MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Bash中的脚本与性能监控

2023-02-132.8k 阅读

Bash脚本基础

脚本结构与语法

Bash脚本是由一系列Bash命令按顺序组成的文本文件。脚本文件通常以#!/bin/bash开头,这一行被称为Shebang,它告诉系统使用/bin/bash来解释执行这个脚本。例如,一个简单的打印“Hello, World!”的Bash脚本如下:

#!/bin/bash
echo "Hello, World!"

在这个脚本中,echo是Bash的内置命令,用于在标准输出上打印文本。

脚本中的变量是非常重要的组成部分。变量名通常由字母、数字和下划线组成,并且不能以数字开头。定义变量不需要特殊的声明关键字,例如:

name="John"
echo "My name is $name"

这里定义了一个名为name的变量,并在echo命令中使用$name来引用它的值。

控制结构

  1. if语句 if语句用于根据条件执行不同的代码块。基本语法如下:
if [ condition ]; then
    commands
elif [ another_condition ]; then
    other_commands
else
    fallback_commands
fi

例如,判断一个文件是否存在:

#!/bin/bash
file="test.txt"
if [ -f $file ]; then
    echo "$file exists."
else
    echo "$file does not exist."
fi

这里[ -f $file ]是条件判断,-f表示判断是否为文件。

  1. for循环 for循环用于对一组值进行迭代。常见的语法有两种:
    • 对列表进行迭代:
for item in apple banana cherry; do
    echo "I like $item"
done
- 基于数字范围的迭代:
for (( i=1; i<=5; i++ )); do
    echo "Number: $i"
done
  1. while循环 while循环在条件为真时持续执行代码块。语法如下:
while [ condition ]; do
    commands
done

例如,当文件不存在时等待:

#!/bin/bash
file="test.txt"
while [ ! -f $file ]; do
    sleep 1
    echo "Waiting for $file to appear..."
done
echo "$file has appeared."

这里[ ! -f $file ]表示文件不存在的条件,sleep 1表示暂停1秒。

函数在Bash脚本中的应用

函数定义与调用

在Bash脚本中,函数是一段可重复使用的代码块。定义函数的基本语法如下:

function_name() {
    commands
    [ return value ]
}

例如,定义一个计算两个数之和的函数:

add_numbers() {
    sum=$(( $1 + $2 ))
    echo $sum
}
result=$(add_numbers 3 5)
echo "The result of addition is: $result"

这里add_numbers是函数名,$1$2是函数的参数,分别表示传入的第一个和第二个数。$(( $1 + $2 ))用于计算两数之和,echo $sum返回计算结果。$(add_numbers 3 5)调用函数并获取返回值。

函数的参数处理

函数可以接受多个参数,通过$1, $2, $3等方式访问。例如,一个打印所有传入参数的函数:

print_args() {
    for arg in "$@"; do
        echo "Argument: $arg"
    done
}
print_args apple banana cherry

这里$@表示所有传入函数的参数,通过for循环遍历并打印每个参数。

性能监控工具基础

系统性能指标概述

  1. CPU使用率 CPU使用率表示CPU在一段时间内忙于处理任务的时间比例。过高的CPU使用率可能意味着系统负载过重,或者某个进程占用了过多的CPU资源。
  2. 内存使用率 内存使用率反映了系统当前已使用的内存占总内存的比例。内存不足可能导致系统性能下降,因为操作系统可能需要频繁地在磁盘和内存之间交换数据。
  3. 磁盘I/O 磁盘I/O性能包括读写速度、I/O请求队列长度等指标。缓慢的磁盘I/O可能会影响应用程序的性能,尤其是对于频繁读写磁盘的程序。
  4. 网络I/O 网络I/O涉及网络带宽的使用、数据包的发送和接收速率等。网络问题可能导致数据传输延迟,影响分布式系统的性能。

常用性能监控工具

  1. top top是一个实时监控系统性能的工具。它可以显示系统的CPU使用率、内存使用率、进程状态等信息。在终端中输入top命令,即可进入top界面。
top

top界面会动态更新,默认按CPU使用率对进程进行排序。一些重要的信息字段包括: - %CPU:进程的CPU使用率。 - %MEM:进程的内存使用率。 - VIRT:进程使用的虚拟内存大小。 - RES:进程使用的物理内存大小。

  1. htop htoptop的增强版本,提供了更直观的界面和更多的功能。它可以通过包管理器安装,例如在Ubuntu上:
sudo apt install htop

htop允许用户通过鼠标操作,并且可以更清晰地显示进程树结构。它还提供了对CPU核心、内存和交换空间的可视化展示。

  1. iostat iostat用于监控系统的磁盘I/O性能。它可以显示磁盘的读写速率、I/O请求队列长度等信息。在大多数系统中,它可以通过安装sysstat包来获取。例如在CentOS上:
sudo yum install sysstat

使用iostat命令:

iostat -d -x 1

这里-d表示仅显示磁盘统计信息,-x表示显示扩展统计信息,1表示每1秒刷新一次。

  1. vmstat vmstat提供了关于系统内存、进程、CPU等方面的统计信息。它可以帮助用户了解系统的内存使用情况、上下文切换次数等。基本使用方法如下:
vmstat 1

这里1表示每1秒刷新一次统计信息。

在Bash脚本中实现性能监控

获取CPU使用率

  1. 使用top命令获取CPU使用率 可以通过top命令结合一些文本处理工具来获取CPU使用率。例如:
cpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{print $2 + $4}')
echo "CPU usage: $cpu_usage%"

这里top -bn1表示以非交互式模式运行一次top命令,grep "Cpu(s)"过滤出包含“Cpu(s)”的行,awk '{print $2 + $4}'计算并打印用户空间和系统空间的CPU使用率之和。

  1. 使用/proc/stat文件获取CPU使用率 /proc/stat文件包含了系统的CPU统计信息。通过读取该文件并进行计算,可以得到CPU使用率。以下是一个示例脚本:
#!/bin/bash
# 读取初始CPU统计信息
prev_total=0
prev_idle=0
cat /proc/stat | grep "^cpu " | while read line; do
    cpu=$(echo $line | awk '{print $1}')
    if [ "$cpu" == "cpu" ]; then
        fields=($line)
        total=0
        for i in $(seq 2 8); do
            total=$(( total + ${fields[$i]} ))
        done
        idle=${fields[5]}
        prev_total=$total
        prev_idle=$idle
    fi
done

# 等待1秒
sleep 1

# 读取新的CPU统计信息
new_total=0
new_idle=0
cat /proc/stat | grep "^cpu " | while read line; do
    cpu=$(echo $line | awk '{print $1}')
    if [ "$cpu" == "cpu" ]; then
        fields=($line)
        total=0
        for i in $(seq 2 8); do
            total=$(( total + ${fields[$i]} ))
        done
        idle=${fields[5]}
        new_total=$total
        new_idle=$idle
    fi
done

# 计算CPU使用率
total_diff=$(( new_total - prev_total ))
idle_diff=$(( new_idle - prev_idle ))
cpu_usage=$(( (total_diff - idle_diff) * 100 / total_diff ))
echo "CPU usage: $cpu_usage%"

这个脚本通过读取/proc/stat文件中的CPU统计信息,在等待1秒前后分别读取一次,然后计算CPU使用率。

获取内存使用率

  1. 使用free命令获取内存使用率 free命令可以显示系统的内存使用情况。通过对其输出进行处理,可以得到内存使用率。例如:
mem_usage=$(free -h | awk '/Mem:/ {print $3/$2 * 100}' | awk -F. '{print $1}')
echo "Memory usage: $mem_usage%"

这里free -h以人类可读的格式显示内存信息,awk '/Mem:/ {print $3/$2 * 100}'计算已使用内存与总内存的比例,awk -F. '{print $1}'去掉小数部分。

  1. 使用/proc/meminfo文件获取内存使用率 /proc/meminfo文件包含了详细的内存信息。以下是通过读取该文件获取内存使用率的脚本:
#!/bin/bash
total_mem=0
free_mem=0
while read line; do
    if [[ $line =~ ^MemTotal: ]]; then
        total_mem=$(echo $line | awk '{print $2}')
    elif [[ $line =~ ^MemFree: ]]; then
        free_mem=$(echo $line | awk '{print $2}')
    fi
done < /proc/meminfo

used_mem=$(( total_mem - free_mem ))
mem_usage=$(( used_mem * 100 / total_mem ))
echo "Memory usage: $mem_usage%"

这个脚本逐行读取/proc/meminfo文件,获取总内存和空闲内存,然后计算内存使用率。

监控磁盘I/O性能

  1. 使用iostat获取磁盘I/O信息 可以通过iostat命令获取磁盘的读写速率等信息。例如,获取设备sda的读写速率:
read_rate=$(iostat -d -x | grep sda | awk '{print $5}')
write_rate=$(iostat -d -x | grep sda | awk '{print $6}')
echo "Read rate: $read_rate KB/s, Write rate: $write_rate KB/s"

这里iostat -d -x获取扩展的磁盘统计信息,grep sda过滤出设备sda的信息,awk '{print $5}'awk '{print $6}'分别获取读速率和写速率。

  1. 通过/proc/diskstats监控磁盘I/O /proc/diskstats文件包含了每个块设备的I/O统计信息。以下是一个示例脚本,用于获取设备sda的I/O请求数:
#!/bin/bash
prev_read_requests=0
prev_write_requests=0
cat /proc/diskstats | grep sda | while read line; do
    fields=($line)
    prev_read_requests=${fields[3]}
    prev_write_requests=${fields[7]}
done

# 等待1秒
sleep 1

new_read_requests=0
new_write_requests=0
cat /proc/diskstats | grep sda | while read line; do
    fields=($line)
    new_read_requests=${fields[3]}
    new_write_requests=${fields[7]}
done

read_requests_diff=$(( new_read_requests - prev_read_requests ))
write_requests_diff=$(( new_write_requests - prev_write_requests ))
echo "Read requests per second: $read_requests_diff, Write requests per second: $write_requests_diff"

这个脚本在等待1秒前后分别读取/proc/diskstats文件中设备sda的读请求数和写请求数,然后计算每秒的请求数差值。

监控网络I/O性能

  1. 使用ifstat监控网络接口速率 ifstat可以显示网络接口的发送和接收速率。可以通过包管理器安装,例如在Ubuntu上:
sudo apt install ifstat

使用ifstat获取网络接口eth0的速率:

rx_rate=$(ifstat -i eth0 1 1 | awk 'NR==3 {print $2}')
tx_rate=$(ifstat -i eth0 1 1 | awk 'NR==3 {print $3}')
echo "Receive rate: $rx_rate KB/s, Transmit rate: $tx_rate KB/s"

这里ifstat -i eth0 1 1表示监控eth0接口,持续1秒,执行1次。awk 'NR==3 {print $2}'awk 'NR==3 {print $3}'分别获取接收速率和发送速率。

  1. 通过/proc/net/dev监控网络I/O /proc/net/dev文件包含了网络接口的详细统计信息。以下是一个示例脚本,用于获取网络接口eth0的接收和发送字节数:
#!/bin/bash
prev_rx_bytes=0
prev_tx_bytes=0
while read line; do
    if [[ $line =~ ^eth0: ]]; then
        fields=($line)
        prev_rx_bytes=${fields[1]}
        prev_tx_bytes=${fields[9]}
    fi
done < /proc/net/dev

# 等待1秒
sleep 1

new_rx_bytes=0
new_tx_bytes=0
while read line; do
    if [[ $line =~ ^eth0: ]]; then
        fields=($line)
        new_rx_bytes=${fields[1]}
        new_tx_bytes=${fields[9]}
    fi
done < /proc/net/dev

rx_bytes_diff=$(( new_rx_bytes - prev_rx_bytes ))
tx_bytes_diff=$(( new_tx_bytes - prev_tx_bytes ))
echo "Received bytes per second: $rx_bytes_diff, Transmitted bytes per second: $tx_bytes_diff"

这个脚本在等待1秒前后分别读取/proc/net/dev文件中网络接口eth0的接收和发送字节数,然后计算每秒的字节数差值。

性能监控数据的记录与分析

记录性能监控数据到文件

  1. 记录CPU使用率到文件 可以将获取到的CPU使用率记录到文件中,以便后续分析。例如:
while true; do
    cpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{print $2 + $4}')
    echo "$(date +%Y-%m-%d\ %H:%M:%S),$cpu_usage" >> cpu_usage.log
    sleep 10
done

这个脚本会每隔10秒获取一次CPU使用率,并将时间和使用率记录到cpu_usage.log文件中。格式为“YYYY - MM - DD HH:MM:SS,CPU使用率”。

  1. 记录内存使用率到文件 类似地,记录内存使用率:
while true; do
    mem_usage=$(free -h | awk '/Mem:/ {print $3/$2 * 100}' | awk -F. '{print $1}')
    echo "$(date +%Y-%m-%d\ %H:%M:%S),$mem_usage" >> mem_usage.log
    sleep 10
done

此脚本每隔10秒获取内存使用率并记录到mem_usage.log文件。

分析性能监控数据

  1. 使用gnuplot进行数据可视化 gnuplot是一个用于绘制数据图表的工具。假设我们已经记录了CPU使用率到cpu_usage.log文件,以下是使用gnuplot绘制CPU使用率随时间变化图表的步骤:
    • 安装gnuplot,例如在Ubuntu上:
sudo apt install gnuplot
- 创建一个`gnuplot`脚本文件,例如`plot_cpu_usage.plt`:
set title "CPU Usage Over Time"
set xlabel "Time"
set ylabel "CPU Usage (%)"
set datafile separator ","
set timefmt "%Y-%m-%d %H:%M:%S"
set xdata time
plot "cpu_usage.log" using 1:2 with lines
- 运行`gnuplot`脚本:
gnuplot plot_cpu_usage.plt

这样就可以生成一个CPU使用率随时间变化的图表,帮助我们直观地分析CPU使用率的趋势。

  1. 使用awksed进行数据分析 可以使用awksed等工具对性能监控数据进行简单的分析。例如,计算cpu_usage.log文件中CPU使用率的平均值:
average_cpu_usage=$(awk -F, '{sum+=$2; count++} END {if (count>0) print sum/count}' cpu_usage.log)
echo "Average CPU usage: $average_cpu_usage%"

这里awk -F, '{sum+=$2; count++} END {if (count>0) print sum/count}'以逗号为分隔符,累加CPU使用率并统计行数,最后计算平均值。

性能优化与脚本改进

优化Bash脚本性能

  1. 减少子进程创建 在Bash脚本中,每次执行外部命令都会创建一个子进程,这会带来一定的性能开销。例如,尽量避免在循环中频繁执行外部命令。对比以下两种方式:
    • 不好的方式:
for i in $(seq 1 1000); do
    result=$(ls -l)
    echo $result
done
- 好的方式:
ls_result=$(ls -l)
for i in $(seq 1 1000); do
    echo "$ls_result"
done

在好的方式中,只创建一次子进程获取ls -l的结果,然后在循环中重复使用。

  1. 使用数组而不是字符串拼接 如果需要处理一系列相关的数据,使用数组比字符串拼接更高效。例如,存储多个文件名:
    • 不好的方式:
file_list=""
for file in *; do
    file_list="$file_list $file"
done
- 好的方式:
file_array=()
for file in *; do
    file_array+=("$file")
done

数组操作更灵活,并且在内存管理上更高效。

基于性能监控的系统优化

  1. 优化CPU性能 如果性能监控发现CPU使用率过高,可以采取以下措施:
    • 优化脚本或程序:检查脚本或程序中是否有不必要的计算或循环,尽量简化算法。例如,减少嵌套循环的深度,优化条件判断。
    • 调整进程优先级:使用nicerenice命令调整进程的优先级,让重要的进程获得更多的CPU资源。例如,将某个进程的优先级降低:
nice -n 10 command

这里nice -n 10表示将command命令对应的进程优先级降低10,值越大优先级越低。

  1. 优化内存性能 当内存使用率过高时:
    • 释放缓存:在Linux系统中,可以通过修改/proc/sys/vm/drop_caches文件来释放缓存。例如,释放页面缓存、inode和dentry缓存:
sudo sh -c 'echo 3 > /proc/sys/vm/drop_caches'
- **优化脚本内存使用**:避免在脚本中创建大量不必要的变量,及时释放不再使用的变量。例如,使用完数组后,可以使用`unset`命令删除数组:
my_array=()
# 使用数组
unset my_array
  1. 优化磁盘I/O性能 对于磁盘I/O性能问题:

    • 使用缓存机制:如果脚本频繁读写磁盘文件,可以考虑使用内存缓存。例如,对于一些不经常变化的配置文件,可以在脚本启动时读取到内存变量中,避免重复读取磁盘。
    • 优化磁盘I/O操作:尽量批量处理磁盘读写,而不是单个字节或小块数据的读写。例如,在写入文件时,使用缓冲区,减少写入次数。
  2. 优化网络I/O性能 当网络I/O性能不佳时:

    • 检查网络配置:确保网络接口的配置正确,例如MTU(最大传输单元)设置合理。可以通过ifconfigip link命令查看和修改网络接口配置。
    • 优化网络请求:在脚本中,如果有网络请求操作,尽量合并请求,减少网络连接的建立和断开次数。例如,对于多次向同一服务器的请求,可以复用一个网络连接。