Linux调优
Linux作为服务器针对使用场景, 有许多需要调优的地方, 本文记录常用优化项.
核心参数调优
通常涉及到/etc/sysctl.conf和/etc/security/limits.conf配置文件的修改.
也可使用命令修改,使用sysctl -p 以立即生效(不必重启).
内核参数设置
sysctl命令可以用来实时的读取/修改内核参数
# 显示所有可用内核参数
sysctl -a
# 加载/etc/sysctl.conf的参数
sysctl -p
提高文件描述符限制
默认的1024偏小.
如果使用默认值,压测时在Nginx错误日志/var/log/nginx/error.log通常可以发现大量以下类似错误:
socket() failed (24: Too many open files) while connecting to upstream,
常用的命令:
# 查看系统当前设置
ulimit -n
# 查看当前进程的限制
cat /proc/$(pgrep java)/limits
# 查看当前进程句柄数
lsof -p $(pgrep java)|wc -l
## 或者使用
ls /proc/$(pgrep java)/fd|wc -l
soft limit类似于warning, hard limit是真实的最大值限制.
有两种方式修改:
临时设置
# 临时增加,重启后失效
ulimit -n 655350
# 单个进程的限制为soft limit
# hard limit应小于当前系统打开的文件描述符
CentOS7/Ubuntu设置
在CentOS7使用SystemD启动的服务不同于CentOS6, 对/etc/security/limits.conf的设置不会生效.
需要同时修改/etc/systemd/system.conf 和 /etc/systemd/user.conf。 或具体的服务 /etc/systemd/system.conf.d/tomcat.conf,之后重启机器生效.
# 对应下面几项
DefaultLimitCORE=infinity
DefaultLimitNOFILE=102400
DefaultLimitNPROC=102400
# Ubuntu用户 需要同时修改
sudo vi /etc/pam.d/common-session
# 并增加
session required pam_limits.so
CentOS6设置
修改 /etc/security/limits.conf,重启以生效.
* soft nofile 655350
* hard nofile 655350
root soft nofile 655350
root hard nofile 655350
# 系统级内核句柄限制
fs.file-max = 1000000
其他设置及命令
# 默认通常够用
# 相应增加nr_open
echo 2000000 > /proc/sys/fs/nr_open
# 系统级限制, 上限为nr_open
echo 1000000 > /proc/sys/fs/file-max
# 列出打开/占用的文件描述符
cat /proc/sys/fs/file-nr
# 三个值分别代表 占用/未使用/最大可用值
# 注: lsof只会列出进程占用
lsof | wc -l
# 要得到线程占用,需要使用
ps -eLf
增加可用端口数
如果是压测工具端,报错:connect: cannot assign requested address.
IPv4端口可用数:端口号是16位无符号整数,即65535
# 查看当前端口范围,默认28000
cat /proc/sys/net/ipv4/ip_local_port_range
# 实时生效
echo 1024 65000 > /proc/sys/net/ipv4/ip_local_port_range
# 永久生效
vi /etc/sysctl.conf
net.ipv4.ip_local_port_range = 1024 65000
# 重新加载
sysctl -p /etc/sysctl.conf
可选:最大线程数
一般不需要设置
# 默认31299
echo 100000 > /proc/sys/kernel/threads-max
查看当前线程数:
- top, then hit H to view threads
- top -H
- htop
内存调优
实际上不需要调优.
free -m
# cache和buffers被包含在used,但是当新进程需要而没有free内存时,kernel会回收(写到硬盘)以释放
# 每隔1分钟记录一次,共记录100次
vmstat -SM 60 100 > memoryusage.out &
fdisk -l
swap检查/配置
# 启用 swap
swapon -a
# 检查
swapon -s # swap未开启则返回空
free -h # swap未开启则total为0
# 创建
fallocate -l 4G /swapfile # 等价于 dd if=/dev/zero of=/swapfile count=4096 bs=1MiB
ls -lh /swapfile
chmod 600 /swapfile # 安全加固
mkswap /swapfile
swapon /swapfile
# 永久生效
vi /etc/fstab # 添加
/swapfile swap swap defaults 0 0
# 禁用
swapoff -v /swapfile
/etc/fstab # 去掉 /swapfile swap swap defaults 0 0
rm /swapfile
OOM Killer
Linux允许程序申请内存的overcommitment(Linux的malloc分配内存,先承诺,实际用到时再去系统分配),实际使用时可能内存不足,从而触发OOM-Killer的自我保护机制。 即当系统分配不出内存时触发,由操作系统在已有进程中挑选一个占用内存最大的进程kill掉来释放内存.
- 日志通常位于: /var/log/kern.log 或 /var/log/dmesg 或 /var/log/messages
- /proc//oom_score 可查看进程得分(0~1000)
- choom -p 用命令查看/调整得分
调整参数(-1000~1000),实际得分会累加:
choom -p 123
# 调整
choom -p 123 -n -30
# 或直接修改
sudo echo -30 > /proc/<pid>/oom_score_adj
调整Service:
[Service]
OOMScoreAdjust=-30
查询所有进程得分并排序:
#!/bin/bash
while read -r pid comm
do
printf '%d\t%d\t%s\n' "$pid" "$(cat /proc/$pid/oom_score)" "$comm"
done < <(ps -e -o pid= -o comm=) | sort -k2 -n
相关日志演示:
# oom-killer
May 13 09:46:36 moon kernel: dockerd invoked oom-killer: gfp_mask=0x201da, order=0, oom_score_adj=-500
May 13 09:46:36 moon kernel: dockerd cpuset=/ mems_allowed=0
# 如果kernel的 free 内存小于 min,会触发杀掉进程
May 13 09:46:36 moon kernel: Node 0 Normal free:42856kB min:42980kB
# java分数及当时内存占用
May 13 09:46:36 moon kernel: Out of memory: Kill process 17965 (java) score 424 or sacrifice child
May 13 09:46:36 moon kernel: Killed process 17965 (java) total-vm:10461800kB, anon-rss:3390232kB, file-rss:0kB, shmem-rss:0kB
# total-vm 虚拟内存(可忽略该字段,实际意义不大),包含申请的 + 真实使用的
# rss是真实使用的
# 注: 如果page size是4k的话,计算大小要 x4
# anon-rss 虚拟内存页, anonymous memory,RSS映射到真实内存
# file-rss 打开大文件时占用的内存页, RSS映射到文件或设备
一些其他参数:
# 0意味着启发式策略,允许OverCommit,默认设置
cat /proc/sys/vm/overcommit_memory
# 不要在生产环境完全关闭OOM Killer,即
# echo "vm.overcommit_memory=2" >> /etc/sysctl.conf
cat /proc/pagetypeinfo
网络调优
通用网络参数
/etc/sysctl.conf
# 系统网络设置
# 生效值取系统和下面TCP设置值的最大值
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
TCP/IP调优
Backlog Queue
最大连接数队列. 可选, 查看kernel日志决定是否需要调整
net.core.somaxconn
net.core.netdev_max_backlog = 300000
网络缓冲区大小
# TCP读取缓冲区
# 格式: 最小值/默认值/最大值 字节数
# cat /proc/sys/net/ipv4/tcp_rmem
net.ipv4.tcp_rmem = 4096 87380 16777216
# 发送缓冲区
net.ipv4.tcp_wmem = 4096 65536 16777216
# TCP内存, 对应 low/pressure/high 页大小(4K)
net.ipv4.tcp_mem = 786432 2097152 3145728
UDP调优
默认比较受限
#改成8M
sysctl -w net.core.rmem_max=8388608
主要参数
Receive-Side Scaling (RSS)
即multi-queue receive, 在基于硬件的多个接受队列间分发网络接受的数据,可以被多核CPU处理以提高性能.
cat /sys/class/net/eth1/queues/<rx-0>/
ethtool --show-rxfh-indir eth1
CLOSE_WAIT 和 TIME_WAIT 解释
- CLOSE_WAIT:被动关闭,表示远程端 (连接的另一端) 已经关闭连接。
- TIME_WAIT:主动关闭, 表示本地端 (这边) 已经关闭连接,即主动关闭连接的一方保持的状态。 连接会被保持一会儿,以保证该连接上延迟的数据包可以被正确匹配处理。当超时4分钟后连接会被移除。
netstat -nalp | grep -E ‘:80 |:443 ’ | awk ‘{print $6}’ | sort | uniq -c
TCP是全双工的,任何一端可以是source或destination. 在TCP/IP工作时,连接并不会被立即关闭. 在连接被关闭后,数据包也可能乱序或被重传。
- 注1: TIME_WAIT太多的问题可以通过优化服务器参数解决(开启keepalive)
- 注2: 但CLOSE_WAIT太多通常是程序的问题,需要代码判断(释放连接)或优化Nginx参数。
- 注3: MSL一般设置为30秒、1分钟,2分钟(RFC标准),主动关闭方会保持状态2MSL后彻底回收资源。
tcp_tw_reuse和tcp_tw_recycle
tcp_tw_reuse仅对outgoing有效(连接有incoming和outgoing之分).
设计协议时,尽量不要让客户端先关闭连接,应该让服务端控制.
不用开启 net.ipv4.tcp_tw_recycle, 最新内核4.12已结去掉该参数.
TCP/UDP参数
- Socket receive buffer size: Socket send and receive sizes are dynamically adjusted, so they rarely need to be manually edited.
- rmem_default : A kernel parameter that controls the default size of receive buffers used by sockets.
调优常用指标
- Ping 100以下
- 网络延迟50ms以下
- Dns解析尽量快
- 尽量少丢包
- 反向代理优化
调优辅助工具
perf-tools
开源的性能分析工具,基于perf和ftrace.
sysdig
sysdig: Troubleshooting 工具,支持容器
SystemTap
- SystemTap[官方网站][1]
- CentOS[有用的脚本][2]
扩展阅读
- [Linux性能资源大全][3]
- [RedHat官方系统调优指南][4]
- Linux Memory Overcommitment and the OOM Killer
- [TCP的那些事儿][5] : TCP协议特点汇总
- [Linux TCP/IP 协议栈调][6]
- [tcp_tw_reuse和tcp_tw_recycle调整对于过多TIME_WAIT的调研][7]
- centos7-systemd-conf-limits
- Linux free shows high memory usage but top does not:关于内存使用的解释
- What is cache in “free -m” output and why is memory utilization high for cache?:官方详细解释
- Red Hat Enterprise Linux: 没有可以创建一个账号
- Jira Data Center size profiles [1]: https://sourceware.org/systemtap/ [2]: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/systemtap_beginners_guide/useful-systemtap-scripts [3]: http://www.brendangregg.com/linuxperf.html [4]: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/performance_tuning_guide/index [5]: http://coolshell.cn/articles/11564.html [6]: http://colobu.com/2014/09/18/linux-tcpip-tuning/ [7]: https://vincent.bernat.im/en/blog/2014-tcp-time-wait-state-linux