|
|
|||
|
||||
2.2 Basics of Performance Analysis
4 Performance Measurement Using NetApp Open Interfaces
5 Appendix 1 - Performance Counters in Data ONTAP 7.1
| 1 Purpose and Scope | [top] |
This document provides detailed guidelines on how to do Performance Measurement for NetApp devices using below mentioned Open Interfaces:
| 2 Introduction | [top] |
Performance measurement is important in understanding the usage patterns of storage which can help in catching the performance problems before they start impacting the users and applications.
Performance Measurement is useful in the following areas:
One of the fundamental theories used for Performance Analysis is Little’s Law. Following is the mathematical representation of Little’s Law:
Queue-Length = Throughput x Latency
Throughput – The rate at which any request coming into the system is served
Latency – The time taken to service a request coming into the system
Queue-Length – Average number of pending requests in the system at any given time
Little’s Law can be used to analyze the performance of any system that can be modeled as queues. For example, to analyze how efficiently a Bank is servicing its customers, we need to calculate at what rate the customers are entering the bank for a service (Throughput measurement) and how much time the teller at the counter takes to service each customer (Latency measurement). Once we get Throughput and Latency data, we can calculate the average length of the customer queue which is a direct measure of how efficiently the bank is servicing its customers and this data can be used to take a decision whether the bank needs to open one more counter or the employee at the counter needs to be made more efficient.
Little’s Law can be used to understand the performance of any storage component in the customer environment. For each component in the storage system, the queue-length data can be calculated using the I/O rate to the component (gives throughput measurement) and the I/O latency of the component. For each environment, the queue-length numbers need to be monitored and the average queue-length should be bench-marked. The performance hot-spots can be identified in the specific storage environment by tracking the consistent periodic peaks in the queue-length numbers observed over a period of time.
The following figure shows the overall infrastructure that is available for the applications to monitor the performance statistics of the NetApp storage systems.

At the base of the performance infrastructure there is a set of performance counters which are accessible through existing performance commands. Above the set of these performance counters, there is a thin layer of abstraction called Counter Manager (CM).
Counter Manager provides
The following are the different channels through which performance monitoring applications can access the API set of the CM:
One of the things that are going to be added in the future is something called Filer Data Archives. Today, when you get to the performance counters you get a real-time view of these counters. If you want to save them, you can save them but that responsibility is up to the host or the administrator. With Filer Data Archives, the storage system keeps historical versions of performance counters so that it's easy to do trending and analysis without the host having to save all that information.
Performance counters are grouped in an object-instance-counter hierarchy. Each object could have many instances of it but the object will have a set of well defined counters. So each instance of the object will have its own corresponding values for this well defined counter set. For example, 'Volume' is an Object type. In a particular storage system, there could be many two volumes 'vol0' and "vol1". Each of these volumes will be an instance of the "Volume' object. The "Volume" object has well defined counter set like "read_ops', "read_latency" etc. So the instances of the 'Volume" object in this storage system viz. "vol0' and "vol1' will have their own values for the counters "read_ops", "read_latency" etc. The example is illustrated below:

Each counter has a type, unit and priority associated with it. See ‘Appendix 1 - Performance counters in Data ONTAP 7.1’ for the description of the various objects supported in Data ONTAP 7.1, the description of the different types and priorities of the counters.
The ONTAPI interface is a set of foundational APIs for managing NetApp Storage Systems. This is a proprietary interface developed by NetApp for advance management of NetApp Storage Systems. ONTAPI includes APIs for qtrees, quotas, volumes, luns, snapshots, snapmirror, vfilers, and numerous other features.
ONTAPI interfaces use XML as a format and may be configured to use either HTTP or DCE/RPC as the transport mechanism. HTTP is important when managing devices which may be outside of the corporate firewall, and locked down so that only port 80 is available, and is the default transport configuration. Security for HTTP can be provided by using SSL.
ONTAPI is implemented as a small set of primitives that marshal and un-marshal arguments onto and from the wire, using XML as the description language. At present, bindings for C/C++, Perl and Java are provided. Development of bindings for other languages will be driven primarily by developer demand.
SNMP (Simple Network Management Protocol) is a well-known standard for network management. NetApp storage systems support SNMP V1. NetApp only supports monitoring using SNMP which means that SNMP SET operations are not permitted.
If SNMP is enabled in Data ONTAP, SNMP managers can query your storage system's SNMP agent for information (specified in your storage system's MIBs or the MIB-II specification). In response, the SNMP agent gathers information and forwards it to the SNMP managers using the SNMP protocol. The SNMP agent also generates trap notifications whenever specific events occur and sends these traps to the SNMP managers. The SNMP managers can then carry out actions based on information received in the trap notifications.
The latest versions of the Data ONTAP MIBs files are available online on the NetApp on the Web (NOW) site at http://now.netapp.com/NOW/download/tools/mib/filer.shtml
Among the open interfaces, currently only ManageONTAP APIs provide the interface for getting the performance related data. The following sections describe how the performance counters of some of the performance objects can be used in various scenarios that would need performance measurements.
Consider the scenario wherein the application needs to know if more disks need to be added to the aggregate to improve the application performance. For this the application needs to do the following:
The following table provides details on API calls to get the above data:
| Operation | Command Details( Manage ONTAP API) | Comments |
| Get the number of disks in the aggregate | aggr-list-info | API returns aggr_info[] array. The disk-count attribute in the array provides the number of disks in the aggregate. |
| Get the Total IOP rate and average block transfer rate | perf-object-get-instances The input to this command is to be set as below: Object Name : aggregate Instance Name : aggregate name of interest Counter Info : Fill three elements of type ‘counter_info’ with the counter names as ‘total_transfers’, ‘user_read_blocks’ and ‘user_write_blocks’ respectively |
Get the data at two intervals of time t1 and t2 |
Assuming that the data in the aggregate are striped across all the disks equally and that the benchmark numbers for the FC disks are:
Throughput: 30 – 50 MB/sec, and IOPS: 200 – 400
Also assume that the application is using 64K size blocks for read/write operations.
Total_transfers = (total_transfers at t2 - total_transfers at t1)/ (t2 – t1)
Total bytes of read/write data = ((user_read_blocks + user_write_blocks at t2) – (user_read_blocks + user_write_blocks at t1))*64*1024/ (t2 – t1)
IOPS per disk = (total_transfers)/(disk_count)
Throughput per disk = (Total bytes of read/write data) / (disk_count)
If the IOPS or the throughput per disk are not in the range as mentioned above then additional disks should be added to the aggregate to improve the performance of application that is doing IOs to that particular aggregate.
Consider the scenario wherein an application is sending I/O packets to a LUN and the response time of the I/O is poor. This could be because of one or more of the following reasons:
If the application concurrency is taken care with good multi-threaded design then the bottle-neck is most probably at the LUN.
The following table provides details on API calls to get the above data:
| Operation | Command Details (Manage ONTAP API) | Comments |
| Get the Lun counters 'avg_latency' and 'queue_full' | perf-object-get-instances The input to this command is to be set as below: Object Name : lun Instance Name : LUN name of interest Counter Info : Fill two elements of type ' counter_info' with the counter names as 'avg_latency' and 'queue_full' respectively |
Get the data at two intervals of time t1 and t2 |
Queuefull/sec = (queuefull rate at time t2 - queuefull rate at t1) / (t2 – t1)
avg_latency = (avg_latency at time t2 - avg_latency at time t1)
From the above calculations, the application can determine if the queuefull rate and average latency are in the acceptable range.
If the queue full rate is not in the acceptable range then the LUN is really busy, so add more LUNs and distribute the I/O on different LUNs.
If the average latency is not in the acceptable range, then the LUN is slow so move the LUN to the volume which is based on a faster disk. If the latency at the server is much more compared to the average latency of the LUN then increase the queue-depth settings of the SCSI/FC driver on the host.
Consider the scenario of an application reading data from NFS/CIFS share is facing timeouts or disconnects. The problem could be due to network latency or the storage system latency. Following are the steps to debug this issue:
| Operation | Command Details (ManageONTAP API) | Comments |
| Get the nfsv3 counters ‘nfsv3_read_latency’ and ‘nfsv3_avg_read_latency_base’ | perf-object-get-instances The input to this command is to be set as below: Object Name : nfsv3 Instance Name : NFS share name of interest Counter Info : Fill two elements of type ‘counter_info’ with the counter names as ‘nfsv3_read_latency’ and ‘nfsv3_avg_read_latency_base’ respectively |
Get the data at two intervals of time t1 and t2 |
| Get the cifs counters ‘cifs_latency’ and ‘cifs_latency_base’ | perf-object-get-instances The input to this command is to be set as below: Object Name : cifs Instance Name : CIFS share name of interest Counter Info : Fill two elements of type ‘counter_info’ with the counter names as ‘cifs_latency’ and ‘cifs_latency_base’ respectively |
Get the data at two intervals of time t1 and t2 |
Calculation of the Latencies for NFS and CIFS shares:
NFS read latency = (nfsv3_read_latency at time t2 - nfsv3_read_latency at time t1) / (nfsv3_avg_read_latency_base at time t2 - nfsv3_avg_read_latency_base at time t1)
CIFS latency = (cifs_latency at time t2 - cifs_latency at time t1) / (cifs_latency_base at time t2 - cifs_latency_base at time t1)
The maximum acceptable Latencies :
If the latencies calculated above are higher than the maximum acceptable latencies, then the problem lies with the storage system.
If storage system doesn’t show high latencies, probably it is a network issue. Compare host view of latencies versus storage system view of latencies. If different, probably it is network or host I/O driver issue.
One of the unique features of NetApp storage systems is, unlike other vendor storage systems, NetApp storage systems have an OS and File System. So CPU of the storage box could also be one of the potential candidates for bottlenecks in the I/O path.
Consider the scenario where there is high latency and application sluggishness. Assume that there are no disk bottlenecks or application concurrency problems. Then the problem could be with the utilization of the CPUs on the storage system. Following are the steps to diagnose the CPU bottleneck problems:
The CPU and domain utilizations can be calculated as described below. The following table shows how to use APIs to get the required counters to calculate these values:
| Operation | Command Details (ManageONTAP API) | Comments |
| Get the System object counters total_processor_busy, cpu_elapsed_time | perf-object-get-instances The input to this command is to be set as below: Object Name : system Instance Name : system Counter Info : Fill two elements of type ‘counter_info’ with the counter names as ‘total_processor_busy’ and ‘cpu_elapsed_time’ respectively |
Get the data at two intervals of time t1 and t2 |
| Get the Processor object counters ‘domain’ and ‘processor_elapsed_time’ for each of the processor instance | perf-object-get-instances The input to this command is to be set as below: Object Name : processor Instance Name : (keeping this empty will result in getting the counter values for all of the processors in the system in one shot) Counter Info : Fill two elements of type ‘counter_info’ with the counter names as ‘processor_elapsed_time’and ‘domain’ respectively |
Get the data at two intervals of time t1 and t2 The domain counter will result in multiple arrays of processor time spent in various domains. The number of arrays is equal to the number CPUs in the storage system |
% CPU utilization = (total_processor_busy at time t2 - total_processor_busy at time t1) / (cpu_elapsed_time at time t2 - cpu_elapsed_time at time t1)
Domain utilization:
For each processor instance, the domain utilization is derived as below:
% domain utilization = (domain[cpu-number][domain element] at time t2) – (domain[cpu-number][domain element] at time t1) / (processor_elapsed_time at time t2 - processor_elapsed_time at time t1)
The possible values obtained from the above equation are:
| Idle | Kah | Net | Stor | Exem | Rais | Targ | Netc | Netc2 | |
| Processor 0: | 20% | 34% | 20% | 10% | 6% | 10% | 0% | 0% | 0% |
| Processor 1: | 23% | 60% | 10% | 5% | 1% | 1% | 0% | 0% | 0% |
| Total | 43% | 94% | 30% | 15% | 7% | 11% | 0% | 0% | 0% |
The total domain utilization is calculated by adding the corresponding elements in the above arrays.
Once the % CPU utilization and % domain utilization is calculated as above, the solution for the problem could be decided as below:
| 5 Appendix 1 - Performance counters in Data ONTAP 7.1 | [top] |
| Type | Description |
| RAW | Means that the counter being exported has no math associated with it. | RATE | Means that two samples of this counter (say C1 and C2) have to be taken at two different points in time (say t1 and t2) and the following math needs to be worked out: (C2 - C1) / (t2 – t1) |
| DELTA | Means that two samples of this counter (say C1 and C2) have to be taken at two different points in time (say t1 and t2) and the following math needs to be worked out: (C2 - C1) |
| AVERAGE | Means that two samples of this counter (say C1 and C2) and two samples of the base counter (say b1 and b2) have to be taken at two different points in time (say t1 and t2) and the following math needs to be worked out: (C2 - C1)/(b2-b1) |
| PERCENT | Means that two samples of this counter (say C1 and C2) and two samples of the base counter (say b1 and b2) have to be taken at two different points in time (say t1 and t2) and the following math needs to be worked out: 100 * (C2 - C1)/(b2-b1) |
| TEXT | Means that this counter is a string |
| NODISP | Typically a base counter that is needed for math associated with other counters. These counters are never exported or displayed |
| Level | Meaning |
| BASIC | Essential counters for problem diagnosis |
| ADMIN | Counters for administrative purposes |
| ADVANCED | Advanced counters – Need not be customer visible |
| DIAG | Counters that used for diagnosis purposes. Some of these counters can report incorrect data too! |
| Object Name | No. of Instances | Priority | Contains |
| system | 1 | Basic | Summary of general performance health of the system. |
| disk | 1 - N | Basic | Per disk statistics |
| processor | 1 - 4 | Basic | Per processor stats |
| ifnet | 1 – Max networking cards | Basic | Stats on various network interface cards in the system. It is possible that a system can have all target cards and no interface cards |
| vfiler | 0 - N | Basic | Virtual filer stats |
| target | 0 – Max target cards | Basic | Stats on various target cards in the system |
| lun | 0 - N | Basic | LUN stats |
| qtree | 0 - N | Basic | qtree stats |
| volume | 1 - N | Basic | Volume stats |
| aggregate | 1 - N | Basic | Aggregate stats |
| nfsv3 | 0 or 1 | Basic | NFS stats if NFS is licensed in the system |
| cifs | 0 or 1 | Basic | CIFS stats if CIFS is licensed |
| fcp | 0 or 1 | Basic | FCP stats if FCP is licensed |
| iscsi | 0 or 1 | Basic | iSCSI stats if iSCSI is licensed |
system object |
||||
| Counter Name | Type | Priority | Units | Description |
| nfs_ops | rate | Basic | Per second | NFS operations per second |
| cifs_ops | rate | Basic | Per second | CIFS operations per second |
| http_ops | rate | Basic | Per second | HTTP operations per second |
| dafs_ops | rate | Basic | Per second | DAFS operations per second |
| fcp_ops | rate | Basic | Per second | FCP operations per second |
| iscsi_ops | rate | Basic | Per second | iSCSI operations per second |
| net_data_recv | rate | Basic | KB per second | Network KB received per second |
| net_data_sent | rate | Basic | KB per second | Network KB sent per second |
| disk_data_read | rate | Basic | KB per second | Disk KB read per second |
| disk_data_written | rate | Basic | KB per second | Disk KB written per second |
| cpu_busy | percent | Basic | % | Percentage of time one or more processors is busy in the system |
| avg_processor_busy | percent | Admin | % | Average processor utilization across all processors in the system |
| total_processor_busy | percent | Admin | % | Total processor utilization of all processors in the system |
| num_processors | raw | Admin | No Units | Number of active processors in the system |
| cpu_elapsed_time | no display | Basic | No Units | Elapsed time since boot |
disk object
|
||||
| Counter Name | Type | Priority | Units | Description |
| total_transfers | rate | Basic | Per second | Total number of disk operations involving data transfer initiated per second |
| user_reads | rate | Basic | Per second | Number of disk read operations initiated each second for retrieving data or metadata associated with user requests |
| user_writes | rate | Basic | Per second | Number of disk write operations initiated each second for storing data or metadata associated with user requests |
| cp_reads | rate | Basic | Per second | Number of disk read operations initiated each second for consistency point processing |
| guaranteed_reads | rate | Basic | Per second | Number of disk read operations initiated each second for raid reconstruct and scrubbing activities |
| guaranteed_writes | rate | Basic | Per second | Number of write operations initiated each second for raid reconstruct or scrubbing activities |
| user_read_chain | average | Basic | No Units | Average number of blocks transferred in each user read operation |
| user_write_chain | average | Basic | No Units | Average number of blocks transferred in each user write operation |
| cp_read_chain | average | Basic | No Units | Average number of blocks transferred in each consistency point read operation during a CP |
| guaranteed_read_chain | average | Basic | No Units | Average number of blocks transferred in each guaranteed read operation |
| guaranteed_write_chain | average | Basic | No Units | Average number of blocks transferred in eacj guaranteed write operation |
| user_read_blocks | rate | Basic | Per second | Number of blocks transferred for user read operations per second |
| user_write_blocks | rate | Basic | Per second | Number of blocks transferred for user write operations per second |
| cp_read_blocks | rate | Basic | Per second | Number of blocks transferred for consistency point read operations per second |
| guaranteed_read_blocks | rate | Basic | Per second | Number of blocks transferred for guaranteed read operations per second |
| guaranteed_write_blocks | rate | Basic | Per second | Number of blocks transferred for guaranteed write operations per second |
| user_read_latency | average | Basic | Microseconds | Average latency per block in microseconds for user read operations |
| user_write_latency | average | Basic | Microseconds | Average latency per block in microseconds for user write operations |
| cp_read_latency | average | Basic | Microseconds | Average latency per block in microseconds for consistency point read operations |
| guaranteed_read_latency | average | Basic | Microseconds | Average latency per block in microseconds for guaranteed read operations |
| guaranteed_write_latency | average | Basic | Microseconds | Average latency per block in microseconds for guaranteed write operations |
| base_for_disk_busy | no display | Basic | No Units | Time base for disk_busy calculation |
| disk_busy | percent | Basic | % | Percentage of time there was at least one outstanding request to the disk |
| processor object | ||||
| Counter Name | Type | Priority | Units | Description |
| sk_switches | delta | Admin | No Units | Number of sk switches |
| hard_switches | delta | Admin | No Units | Number of context switches |
| domain_busy | percent | Advanced | % | Array of processor time in percentage spent in various domains |
| processor_busy | percent | Basic | % | Percentage of elapsed time that the processor is executing non-idle processes |
| processor_elapsed_time | no display | Basic | No Units | Wall-clock time since boot, used for calculating processor utilization |
| ifnet object | ||||
| Counter Name | Type | Priority | Units | Description |
| recv_packets | rate | Basic | Per second | Packets received per second |
| recv_errors | rate | Basic | Per second | Errors per second while receiving packets |
| send_packets | rate | Basic | Per second | Packets sent per second |
| send_errors | rate | Basic | Per second | Errors per second while sending packets |
| Collisions | rate | Basic | Per second | Collisions per second on CSMA interfaces |
| recv_data | rate | Basic | Byter per second | Total bytes received per second |
| send_data | rate | Basic | Bytes per second | Total bytes sent per second |
| recv_mcasts | rate | Basic | Per second | Packets received per second via multicast |
| send_mcasts | rate | Basic | Per second | Packets sent per second via multicast |
| recv_drop_packets | rate | Basic | Per second | Receive packets dropped per second |
| nfsv3 object | ||||
| Counter Name | Type | Priority | Units | Description |
| nfsv3_ops | delta | Basic | No Units | Total number of NFSv3 operations |
| nfsv3_read_latency | average | Basic | Milliseconds | Average latency for NFS v3 read operations in milliseconds |
| nfsv3_read_ops | delta | Basic | No Units | Total observed NFS v3 read operations |
| nfsv3_write_latency | average | Basic | Milliseconds | Average latency for NFS v3 write operations in milliseconds |
| nfsv3_write_ops | delta | Basic | No Units | Total observed NFS v3 write operations |
| target object | ||||
| Counter Name | Type | Priority | Units | Description |
| read_ops | rate | Basic | Per Second | Read operations per second |
| write_ops | rate | Basic | Per Second | Write operations per second |
| other_ops | rate | Basic | Per Second | Other operations per second |
| read_data | rate | Basic | Bytes per second | Read bytes per second |
| write_data | rate | Basic | Bytes per second | Write bytes per second |
| queue_full | rate | Basic | Per Second | SCSI queue full responses per second |
| lun object | ||||
| Counter Name | Type | Priority | Units | Description |
| read_ops | rate | Basic | Per second | Read operations per second |
| write_ops | rate | Basic | Per second | Write operations per second |
| other_ops | rate | Basic | Per second | Other operations per second |
| read_data | rate | Basic | Bytes per second | Read bytes per second |
| write_data | rate | Basic | Bytes per second | Write bytes per second |
| queue_full | rate | Basic | Per second | Queue full responses per second |
| total_ops | delta | Basic | No Units | Total number of operations on the LUN |
| avg_latency | average | Basic | Milliseconds | Average latency in milliseconds for all operations on the lun |
| volume object | ||||
| Counter Name | Type | Priority | Units | Description |
| total_ops | rate | Basic | Per second | Number of operations per second serviced by the volume |
| avg_latency | rate | Basic | Milliseconds | Average latency in milliseconds for all operations on the volume |
| read_ops | rate | Basic | Per second | Number of reads per second to the volume |
| read_data | rate | Basic | Bytes per second | Bytes read per second from the volume |
| read_latency | average | Basic | Milliseconds | Average times for reads to the volume |
| write_ops | rate | Basic | Per second | Number of writes per second to the volume |
| write_data | rate | Basic | Bytes per second | Bytes written per second to the volume |
| write_latency | average | Basic | Milliseconds | Average time for writes to the volume |
| other_ops | rate | Basic | Per second | Number of other operations per second to the volume |
| other_latency | average | Basic | Milliseconds | Average time for other operations to the volume |
| cifs object | ||||
| Counter Name | Type | Priority | Units | Description |
| cifs_ops | rate | Basic | No Units | Total number of CIFS operations |
| cifs_latency | average | Basic | Milliseconds | Average latency for CIFS operations in milliseconds |
| cifs_latency_base | delta | Basic | No Units | Total observed CIFS operations to be used as a base counter for CIFS average latency calculation |
| fcp object | ||||
| Counter Name | Type | Priority | Units | Description |
| fcp_ops | rate | Basic | Per Second | FCP operations per second |
| fcp_write_data | rate | Basic | Bytes per second | FCP bytes written per second |
| fcp_read_data | rate | Basic | Bytes per second | FCP bytes read per second |
| iSCSI object | ||||
| Counter Name | Type | Priority | Units | Description |
| iscsi_ops | rate | Basic | Per Second | iSCSI operations per second |
| iscsi_write_data | rate | Basic | Bytes per second | iSCSI bytes written per second |
| iscsi_read_data | rate | Basic | Bytes per second | iSCSI bytes read per second |