Learn to monitor disk I/O performance with iostat from the sysstat package. Set up real-time monitoring, identify bottlenecks, and automate disk performance analysis with systemd timers.
Prerequisites
- Root or sudo access
- Basic command line knowledge
What this solves
The iostat command helps you monitor disk I/O performance and identify storage bottlenecks on Linux systems. This tutorial shows you how to install the sysstat package, understand iostat output, and set up automated disk monitoring to catch performance issues before they affect your applications.
Step-by-step installation
Update system packages
Start by updating your package manager to ensure you get the latest versions of system monitoring tools.
sudo apt update && sudo apt upgrade -y
Install sysstat package
The sysstat package contains iostat and other system performance tools. It also includes the sar daemon for historical data collection.
sudo apt install -y sysstat
Enable sysstat data collection
Enable the sysstat service to collect historical performance data automatically. This runs the sadc (system activity data collector) every 10 minutes by default.
sudo systemctl enable --now sysstat
sudo sed -i 's/ENABLED="false"/ENABLED="true"/' /etc/default/sysstat
Understanding iostat output and key metrics
Run basic iostat command
Start with a simple iostat command to see current disk activity. This shows average statistics since system boot.
iostat
The output includes CPU utilization and device statistics. Focus on the device section showing disk I/O metrics.
Analyze key iostat metrics
Understanding these metrics helps identify disk bottlenecks and performance issues.
| Metric | Description | Good Values |
|---|---|---|
| %util | Device utilization percentage | < 80% for good performance |
| await | Average wait time for I/O requests (ms) | < 10ms for SSD, < 20ms for HDD |
| r/s, w/s | Read and write requests per second | Depends on workload and hardware |
| rkB/s, wkB/s | Data read/written per second (KB) | Monitor against disk specifications |
| avgrq-sz | Average request size in sectors | Larger is generally more efficient |
| avgqu-sz | Average queue length | < 2 for most workloads |
View extended statistics
Use the -x flag to see extended disk statistics including service time and queue metrics.
iostat -x 1 5
This shows extended stats every 1 second for 5 intervals. Watch for high %util values and long await times.
Monitor disk performance in real-time
Monitor specific devices
Monitor only the devices you care about to reduce noise in the output.
iostat -x 2 sda sdb
This monitors only /dev/sda and /dev/sdb with 2-second intervals. Replace with your actual device names.
Monitor with human-readable output
Use the -h flag to display sizes in human-readable format (K, M, G).
iostat -xh 5
This makes it easier to spot large data transfers and identify which devices are handling the most traffic.
Monitor partition-level statistics
Use the -p flag to see statistics for individual partitions instead of whole devices.
iostat -xp ALL 3
This shows detailed statistics for all partitions, helping identify which specific partitions are experiencing high I/O.
Identify I/O bottlenecks and high disk usage
Identify saturated disks
Look for disks with consistently high utilization that may be causing performance issues.
iostat -x 1 10 | grep -E "Device|%util.*[8-9][0-9]"
This shows devices with utilization above 80%. High %util combined with high await times indicates disk saturation.
Monitor I/O wait times
High I/O wait times indicate processes are waiting for disk operations to complete.
iostat -c 1 5
Watch the %iowait column in CPU statistics. Values consistently above 10% suggest disk I/O is impacting performance.
Analyze top I/O processes
Combine iostat with other tools to identify which processes are generating high disk I/O.
sudo iotop -o -d 1
If iotop isn't installed, you can also use the process monitoring tools covered in our Linux process monitoring tutorial.
Set up automated disk monitoring with systemd timers
Create monitoring script
Create a script that logs disk performance statistics and alerts on high utilization.
#!/bin/bash
Disk monitoring script
LOG_FILE="/var/log/disk-monitor.log"
ALERT_THRESHOLD=85
EMAIL="admin@example.com"
Get current disk statistics
DATE=$(date '+%Y-%m-%d %H:%M:%S')
STATS=$(iostat -x 1 2 | tail -n +4 | awk 'NF > 0 && !/^avg-cpu/ && !/^$/')
Log all statistics
echo "[$DATE] Disk Statistics:" >> "$LOG_FILE"
echo "$STATS" >> "$LOG_FILE"
echo "" >> "$LOG_FILE"
Check for high utilization
HIGH_UTIL=$(echo "$STATS" | awk -v threshold="$ALERT_THRESHOLD" '$NF > threshold {print $1 ": " $NF "%"}')
if [ -n "$HIGH_UTIL" ]; then
echo "[$DATE] ALERT: High disk utilization detected:" >> "$LOG_FILE"
echo "$HIGH_UTIL" >> "$LOG_FILE"
# Send email alert (requires mail command)
if command -v mail >/dev/null 2>&1; then
echo "High disk utilization detected on $(hostname) at $DATE: $HIGH_UTIL" | mail -s "Disk Alert - $(hostname)" "$EMAIL"
fi
fi
Make script executable
Set proper permissions for the monitoring script and create the log directory.
sudo chmod 755 /usr/local/bin/disk-monitor.sh
sudo mkdir -p /var/log
sudo touch /var/log/disk-monitor.log
Create systemd service
Create a systemd service file for the disk monitoring script.
[Unit]
Description=Disk Performance Monitor
Wants=disk-monitor.timer
[Service]
Type=oneshot
ExecStart=/usr/local/bin/disk-monitor.sh
User=root
[Install]
WantedBy=multi-user.target
Create systemd timer
Create a timer to run the disk monitoring every 5 minutes.
[Unit]
Description=Run disk monitor every 5 minutes
Requires=disk-monitor.service
[Timer]
OnBootSec=5min
OnUnitActiveSec=5min
Unit=disk-monitor.service
[Install]
WantedBy=timers.target
Enable and start the monitoring
Enable the systemd timer to start disk monitoring automatically.
sudo systemctl daemon-reload
sudo systemctl enable --now disk-monitor.timer
sudo systemctl status disk-monitor.timer
Analyze disk performance patterns and trends
View historical data with sar
Use sar (part of sysstat) to analyze historical disk performance data.
# View yesterday's disk activity
sar -d -f /var/log/sysstat/saXX
View specific time range
sar -d -s 09:00:00 -e 17:00:00
Replace XX with yesterday's date (day of month). This shows patterns in disk usage throughout the day.
Generate performance reports
Create a script to generate daily disk performance summaries.
#!/bin/bash
Generate disk performance report
REPORT_DATE=$(date -d yesterday '+%d')
REPORT_FILE="/var/log/disk-report-$(date '+%Y-%m-%d').txt"
echo "Disk Performance Report for $(date -d yesterday '+%Y-%m-%d')" > "$REPORT_FILE"
echo "=========================================" >> "$REPORT_FILE"
echo "" >> "$REPORT_FILE"
Peak utilization times
echo "Peak Disk Utilization:" >> "$REPORT_FILE"
sar -d -f /var/log/sysstat/sa$REPORT_DATE | grep -v "^$" | \
awk 'NR>3 && $NF>80 {print $1 " " $2 ": " $(NF-1) " (" $NF "% util)"}' | \
head -10 >> "$REPORT_FILE"
echo "" >> "$REPORT_FILE"
Average daily statistics
echo "Average Daily Statistics:" >> "$REPORT_FILE"
sar -d -f /var/log/sysstat/sa$REPORT_DATE | grep "Average" >> "$REPORT_FILE"
echo "Report generated: $REPORT_FILE"
Set up log rotation
Configure logrotate to manage disk monitoring logs and prevent them from filling up your disk.
/var/log/disk-monitor.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
create 644 root root
postrotate
/usr/bin/systemctl reload-or-restart rsyslog > /dev/null 2>&1 || true
endscript
}
/var/log/disk-report-*.txt {
weekly
rotate 12
compress
delaycompress
missingok
notifempty
}
Verify your setup
Test your disk monitoring configuration to ensure everything is working correctly.
# Check iostat is working
iostat -x 1 2
Verify sysstat service
sudo systemctl status sysstat
Check monitoring timer
sudo systemctl list-timers disk-monitor.timer
Test monitoring script manually
sudo /usr/local/bin/disk-monitor.sh
tail -20 /var/log/disk-monitor.log
View historical data
sar -d | head -20
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| No historical data in sar | sysstat not enabled or running | sudo systemctl enable --now sysstat |
| iostat command not found | sysstat package not installed | Install sysstat package for your distribution |
| Monitoring script not running | Timer not enabled or service failed | Check sudo systemctl status disk-monitor.timer |
| High %iowait but low disk %util | Network I/O or swap activity | Check network stats and swap usage |
| Permission denied on log files | Incorrect file ownership or permissions | sudo chown root:root /var/log/disk-monitor.log |
| Email alerts not working | Mail command not installed | Install mailx or postfix package |
Next steps
- Configure system performance monitoring with sar and sysstat for comprehensive system metrics
- Benchmark and optimize Linux disk I/O performance with fio testing for detailed I/O analysis
- Configure centralized log management with rsyslog to consolidate monitoring logs
- Set up disk monitoring alerts with Prometheus and Grafana for advanced visualization
- Optimize filesystem performance with mount options and I/O schedulers to improve disk performance
Running this in production?
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Script info
SCRIPT_NAME="iostat-monitoring-installer"
LOG_FILE="/var/log/${SCRIPT_NAME}.log"
# Cleanup function for rollback
cleanup() {
local exit_code=$?
if [ $exit_code -ne 0 ]; then
echo -e "${RED}[ERROR] Installation failed. Check ${LOG_FILE} for details${NC}"
# Rollback actions if needed
if systemctl is-enabled sysstat >/dev/null 2>&1; then
systemctl disable sysstat >/dev/null 2>&1 || true
fi
fi
exit $exit_code
}
trap cleanup ERR
# Logging function
log() {
echo "$(date '+%Y-%m-%d %H:%M:%S'): $1" | tee -a "${LOG_FILE}"
}
# Print colored output
print_status() {
local color=$1
local message=$2
echo -e "${color}${message}${NC}"
log "$message"
}
# Check if running as root or with sudo
check_privileges() {
if [[ $EUID -ne 0 ]] && ! sudo -n true 2>/dev/null; then
print_status "$RED" "[ERROR] This script requires root privileges or sudo access"
exit 1
fi
}
# Auto-detect distribution
detect_distro() {
if [ ! -f /etc/os-release ]; then
print_status "$RED" "[ERROR] Cannot detect Linux distribution"
exit 1
fi
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_UPDATE="apt update"
PKG_UPGRADE="apt upgrade -y"
PKG_INSTALL="apt install -y"
SYSSTAT_CONFIG="/etc/default/sysstat"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_UPDATE="dnf check-update || true"
PKG_UPGRADE="dnf update -y"
PKG_INSTALL="dnf install -y"
SYSSTAT_CONFIG=""
;;
amzn)
PKG_MGR="yum"
PKG_UPDATE="yum check-update || true"
PKG_UPGRADE="yum update -y"
PKG_INSTALL="yum install -y"
SYSSTAT_CONFIG=""
;;
*)
print_status "$RED" "[ERROR] Unsupported distribution: $ID"
exit 1
;;
esac
print_status "$GREEN" "Detected distribution: $PRETTY_NAME"
}
# Update system packages
update_system() {
print_status "$YELLOW" "[1/6] Updating system packages..."
$PKG_UPDATE >> "${LOG_FILE}" 2>&1
$PKG_UPGRADE >> "${LOG_FILE}" 2>&1
print_status "$GREEN" "System packages updated successfully"
}
# Install sysstat package
install_sysstat() {
print_status "$YELLOW" "[2/6] Installing sysstat package..."
if command -v iostat >/dev/null 2>&1; then
print_status "$YELLOW" "sysstat already installed, checking version..."
iostat -V >> "${LOG_FILE}" 2>&1 || true
fi
$PKG_INSTALL sysstat >> "${LOG_FILE}" 2>&1
# Verify installation
if ! command -v iostat >/dev/null 2>&1; then
print_status "$RED" "[ERROR] iostat command not found after installation"
exit 1
fi
print_status "$GREEN" "sysstat package installed successfully"
}
# Configure sysstat service
configure_sysstat() {
print_status "$YELLOW" "[3/6] Configuring sysstat service..."
# Enable data collection for Debian-based systems
if [[ -n "$SYSSTAT_CONFIG" && -f "$SYSSTAT_CONFIG" ]]; then
cp "$SYSSTAT_CONFIG" "${SYSSTAT_CONFIG}.backup"
sed -i 's/ENABLED="false"/ENABLED="true"/' "$SYSSTAT_CONFIG"
print_status "$GREEN" "Enabled sysstat data collection in $SYSSTAT_CONFIG"
fi
# Enable and start sysstat service
systemctl enable sysstat >> "${LOG_FILE}" 2>&1
systemctl start sysstat >> "${LOG_FILE}" 2>&1
print_status "$GREEN" "sysstat service configured and started"
}
# Create monitoring scripts
create_monitoring_scripts() {
print_status "$YELLOW" "[4/6] Creating monitoring scripts..."
# Create monitoring directory
mkdir -p /opt/iostat-monitoring
# Create disk monitoring script
cat > /opt/iostat-monitoring/check-disk-performance.sh << 'EOF'
#!/bin/bash
# Disk performance monitoring script
THRESHOLD_UTIL=80
THRESHOLD_AWAIT=20
LOG_FILE="/var/log/disk-performance.log"
echo "$(date): Checking disk performance..." >> "$LOG_FILE"
# Check for high disk utilization
iostat -x 1 1 | awk -v threshold="$THRESHOLD_UTIL" '
/^[a-z]/ && $10 > threshold {
print "WARNING: Device " $1 " has " $10 "% utilization (threshold: " threshold "%)"
}' >> "$LOG_FILE"
# Check for high await times
iostat -x 1 1 | awk -v threshold="$THRESHOLD_AWAIT" '
/^[a-z]/ && $10 > 50 && $9 > threshold {
print "WARNING: Device " $1 " has " $9 "ms average wait time (threshold: " threshold "ms)"
}' >> "$LOG_FILE"
# Log current I/O wait
IOWAIT=$(iostat -c 1 2 | tail -1 | awk '{print $4}')
if (( $(echo "$IOWAIT > 10" | bc -l) )); then
echo "WARNING: High I/O wait: ${IOWAIT}%" >> "$LOG_FILE"
fi
EOF
chmod 755 /opt/iostat-monitoring/check-disk-performance.sh
chown root:root /opt/iostat-monitoring/check-disk-performance.sh
print_status "$GREEN" "Monitoring scripts created"
}
# Setup systemd timer for automated monitoring
setup_systemd_timer() {
print_status "$YELLOW" "[5/6] Setting up automated monitoring..."
# Create systemd service
cat > /etc/systemd/system/disk-monitoring.service << EOF
[Unit]
Description=Disk Performance Monitoring
After=multi-user.target
[Service]
Type=oneshot
ExecStart=/opt/iostat-monitoring/check-disk-performance.sh
User=root
StandardOutput=journal
StandardError=journal
EOF
# Create systemd timer
cat > /etc/systemd/system/disk-monitoring.timer << EOF
[Unit]
Description=Run disk monitoring every 5 minutes
Requires=disk-monitoring.service
[Timer]
OnCalendar=*:0/5
Persistent=true
[Install]
WantedBy=timers.target
EOF
# Set correct permissions
chmod 644 /etc/systemd/system/disk-monitoring.service
chmod 644 /etc/systemd/system/disk-monitoring.timer
# Reload systemd and enable timer
systemctl daemon-reload >> "${LOG_FILE}" 2>&1
systemctl enable disk-monitoring.timer >> "${LOG_FILE}" 2>&1
systemctl start disk-monitoring.timer >> "${LOG_FILE}" 2>&1
print_status "$GREEN" "Automated monitoring configured"
}
# Verify installation
verify_installation() {
print_status "$YELLOW" "[6/6] Verifying installation..."
# Test iostat command
if ! iostat 1 1 >> "${LOG_FILE}" 2>&1; then
print_status "$RED" "[ERROR] iostat command failed"
exit 1
fi
# Check sysstat service status
if ! systemctl is-active --quiet sysstat; then
print_status "$YELLOW" "[WARNING] sysstat service is not active"
fi
# Check timer status
if ! systemctl is-active --quiet disk-monitoring.timer; then
print_status "$RED" "[ERROR] disk-monitoring timer is not active"
exit 1
fi
# Check if bc is available for monitoring script
if ! command -v bc >/dev/null 2>&1; then
print_status "$YELLOW" "Installing bc for monitoring calculations..."
$PKG_INSTALL bc >> "${LOG_FILE}" 2>&1
fi
print_status "$GREEN" "Installation verified successfully"
}
# Main installation function
main() {
print_status "$GREEN" "Starting iostat monitoring installation..."
check_privileges
detect_distro
update_system
install_sysstat
configure_sysstat
create_monitoring_scripts
setup_systemd_timer
verify_installation
print_status "$GREEN" "Installation completed successfully!"
echo
echo "Usage examples:"
echo " iostat # Show current stats"
echo " iostat -x 1 5 # Extended stats, 1s interval, 5 times"
echo " iostat -xh 2 # Human-readable format, 2s interval"
echo " systemctl status disk-monitoring.timer # Check monitoring status"
echo " tail -f /var/log/disk-performance.log # View monitoring alerts"
}
main "$@"
Review the script before running. Execute with: bash install.sh