目录
说明
由于个人水平有限,总结归纳的时候可能存在错误,还望指出。
前言
后台故障是一个很宽泛的概念,本文有些标题党了,本文只是针对如下几点简单分析- 日志规范
- tcp短连接使用过多
- io频繁
程序逻辑错误或是发布变更引起的故障之类的不在讨论范围内。后台服务出现故障时大多数情况下都会伴随着cpu爆满,或者内存不足,或者网卡塞满,io频繁等情况,故障的定位少不了神兵利器,这里有一篇linux下常用工具的介绍:后台故障&性能分析常用工具。
常规错误
这里把能通过日志定位到的错误视为常规错误。比如说某个调用失败会导致该次请求失败,我们可以通过写日志,将关键信息都记录下来,方便之后的问题定位。写日志其实也有一些要注意的点- 避免无效的信息,控制好日志的量和级别,日志写多了影响性能
- 关键信息要记录全,如某个调用失败了,不能只打印一句 xxx Fail,而是要把对应的错误码,错误信息,该调用的关键参数打印出来,方便后续问题定位。
短连接之祸
tcp连接在关闭的时候,主动关闭的一方将会经历time_wait状态,一旦端口消耗速度持续大于端口回收速度,自然会造成端口不够用。但是话说回来,端口不够用这种情况只会出现在主动发起连接的那一端,因为listen -> accept 并不需要分配端口。
定位方法
使用 ss -s 命令,查看各状态的tcp连接数,如果time_wait状态过多且端口消耗速度持续增长,就得留点神了
另外对于服务端来说,有时我们会想要定位连接主要来自哪些ip,可以通过ss配合awk及uniq,sort等命令得到结论,如:
ss -n |grep ESTAB | awk \'{ print $5 }\' | awk -F: \'{ print $1 }\' | sort | uniq -c | sort -rn
可以得到每个ip的连接数的排序
应对方案
- 1 放开port range,既然端口不够用,那么我们就加大端口数,使用如下命令可以得到当前系统向外建立连接时可用的端口范围
cat /proc/sys/net/ipv4/ip_local_port_range
通过如下指令可以设置端口范围,如
echo "1024 61000" > /proc/sys/net/ipv4/ip_local_port_range
但是调整port range后可能会出现某些服务无法重启,这是因为range调大之后,原先的服务监听的端口被系统分配出去了,这个时候可以把相关服务所绑定的端口设置到保留端口中,如
echo "10000,20000" > /proc/sys/net/ipv4/ip_local_reserved_ports
- 2 加快time_wait回收速度
通过如下命令可以打开time_wait快速回收,recycle需要配合timestapms一起使用,不过timestamps是默认就打开的,开启后在3.5*RTO时间内回收
echo "1" > /proc/sys/net/ipv4/tcp_tw_recycle
若timestapms关闭了,则将其打开
echo "1" > /proc/sys/net/ipv4/tcp_timestamps
- 3 可以打开tcp_tw_resue选项,reuse也需要配合timestapms一起使用,开启后在1s内回收
echo "1" > /proc/sys/net/ipv4/tcp_tw_reuse
注意: 以上的修改都是临时的,一旦系统重启又将恢复为默认值,可以通过将这些参数添加到/etc/sysctl.conf文件中,并使用sysctl –p命令使之生效。相关阅读Linux之TCPIP内核参数优化,TCP连接的状态与关闭方式,及其对Server与Client的影响,另外nat网络下,打开tw_recycle将可能导致tcp连接建立错误,详见链接tcp_tw_recycle和tcp_timestamps导致connect失败问题 ,不过同idc内的服务器之间不存在这个问题,但是还有一个问题,timewait的存在帮我们规避掉了旧连接对新连接的影响,关闭之后,是可能导致旧连接的数据包或fin包到达新连接,或者主动关闭方发送的ack丢包,导致对端仍旧处于last_ack状态,而主动关闭方快速回收了该socket,且新建连接时,该port被重用,发送syn过去时,将被回复rst,不过同idc内的网络环境应该是非常良好的,dog微笑脸。最后还可以通过设置SO_LINGER选项,在关闭socket时会非常粗暴的直接发送一个rst报文给对端,从而避免掉timewait状态。
- 4 使用长连接+连接池,引入长连接也有一些点需要注意,主要是以下三点
- 一是对底层服务的负载控制,短连接模式下可以很轻松的实现对底层服务的负载控制,长连接情况要麻烦一点
- 二是底层服务扩容时,连接池需要感知并调整
- 三是长连接+连接池技术 如果实现的不好的话本身也可能成为性能瓶颈,最好是能根据请求量动态的调整连接数,少了容易成为性能瓶颈,多了浪费端口,不过一般情况下端口肯定是够用的。
IO之祸
这个没什么好说的,io多了必然给磁盘带来压力,由此带来的io等待时间必然上涨,对于我们的后台服务而言,io过多基本是由于写日志导致。 #### 定位方法 使用vmstat 命令查看当前系统io情况,以及cpu的wa(cpu空转等待io就绪)所占时间比例。如 ``` vmstat 2 ``` 重点观察bi,bo以及wa项。分别代表块读入速度和块写入速度以及io等待时间比例。 #### 应对方法 通过/dev/null文件快速关闭日志,如 ``` ln -s /dev/null xxx.log ``` 关于/dev/null和/dev/zero文件的介绍可以查看链接,[/dev/null 和 /dev/zero 简介及对比][5],关闭日志只是紧急处理方法,后续还是要优化好写日志的逻辑,控制好量和级别。总结
后台服务出现性能故障时,可以遵循以下思路去定位(以下内容参考自客厅后台开发群熊哥的聊天内容)- 1 先看vmstat,看io是否高,如是,可关闭日志,快速方法:ln -s /dev/null xxx.log
- 2 io不高,再看cpu消耗在用户态还是内核态,如果是用户态,通常是触发了程序bug,可用ltrace定位,快速方法:重启服务
- 3 如果内核态cpu高,对tcp类网络服务,80%原因就是端口耗尽,通过ss -s看端口和time_wait等各个状态,快速方法:加大port range,打开tw_recycle和tw_reuse
感谢运维们。