当你接手一个老项目,可能发现程序在服务器上运行性能低得可怕,与此同时现网流量还在逐渐增长。也许运用最新框架、微服务容器化、异步协程等方法来次彻底的重构,能够挽狂澜于既倒。可惜时不我待,运维已经在要求加机器了,而坏消息是,原有框架还不支持水平扩展,没法通过堆机器解决。有没有办法在不进行大改的情况下,度过难关呢?
这个时候你需要好好审视下你的服务器上到底发生了什么。否则,即使你重构完,也依然会再度面临这些问题。
你的服务器上CPU使用率如何?使用top
命令观察下。
如果你的工作进程负载很高,进程数量少,但是系统整体空闲,说明你需要提高工作进程的数量了(前提是程序支持多进程,最好有选项配置)。反之,如果工作进程很多,系统整体负载高,单个进程负载低,说明你的工作进程太多了,需要减少进程数量。一般推荐服务器上有多少核,就起多少进程,过少的进程导致浪费硬件资源,过多的进程导致频繁切换调度引起不必要的损耗。对于Nginx等程序,甚至支持绑核,能够进一步减少进程切换引起的损耗。
你的服务器上磁盘使用率如何?使用iostat
命令观察下。
如果磁盘IO等待时间长,读写耗时长,读写量很大甚至接近硬盘读写上限,则需要定位下到底是哪些进程在进行大量磁盘读写。使用iotop -o
命令观察下,可以按<>
按键选定列进行排序。
如果发现有工作进程一直在大量读写,或者周期性地大量读写,可以通过lsof -p 进程号
观察进程在读写哪些文件,注意周期性的读写需要多次执行才可能捕获到。
大量的磁盘写操作可能是进程的日志打印太多了,例如生产环境打印了DEBUG日志,甚至有大量的请求和返回原始数据被写入日志。通常都会允许设置日志级别,建议至少设置为INFO,推荐设置为ERROR级别。
如果你的服务托管在web服务器,例如Apache或者Nginx,要小心是否有额外的日志被打印。例如有问题的Nginx配置将打印完整的请求access log,并且不设置滚动。随着时间推移,甚至可能导致磁盘被耗尽。
你的服务提供的是HTTPS连接,但是工作在内网,又或者并无安全需要,那么可以考虑提供HTTP连接,对于静态资源还能利用CDN进行加速。相比HTTP,HTTPS会耗费较大的连接时间用于SSL握手,并消耗一定的CPU用于对数据加解密,增加响应时延。但是如果你的服务有安全性要求,则务必酌情开启。
如果你的服务提供的是短连接场景,响应延迟较低但吞吐量较高,那么反复的建立并迅速关闭连接也会损耗较大的性能。如果服务本身支持长连接,且没有被不可信任的客户端攻击的风险,则可以酌情考虑开启。注意设置请求次数上限和超时时间自动断开连接。
Linux系统有很多网络参数例如默认最大连接数,以及其他配置例如最大打开的文件句柄数。如果你的服务在响应大量的请求,但是有用户报告经常连接超时,那么需要注意排查下内核参数设置了。使用命令观察丢包数量:netstat -s | egrep "listen|LISTEN"
,例如如下输出表明服务器上出现了大量的SYNC丢包
123456 times the listen queue of a socket overflowed(全连接队列丢包)
132456 SYNs to LISTEN sockets dropped (半连接队列丢包)
原因是TCP在三次握手建立连接的时候,服务器端会维护半连接队列和全连接队列两个队列,如果队列长度过小,则根据其他系统参数可能直接丢弃发送RST给客户端,也可能等待重试此时客户端可能报连接超时。
跟队列长度和行为有关的系统参数如下,可以使用sysctl
命令进行修改,具体数值根据服务QPS设计规格进行调整:
net.core.somaxconn = 4096
net.ipv4.tcp_max_syn_backlog = 4096
net.ipv4.tcp_abort_on_overflow = 1
Nginx配置也需要对应调整,重启生效
listen 80 backlog=4096;
listen 443 backlog=4096;
数据库未必和服务部署在同一个城市,会导致访问延迟加大。如果服务依赖直接读取数据库,可以考虑在服务器所在的地域部署只读从库。如果同时需要读写,但没有强一致的要求,则可以考虑异地双活部署。
以上几点如果都仔细推敲,正确设置,在不修改代码的情况下,也能实现一定程度的性能提升。除此之外,还有其他的方法例如添加缓存等,但可能需要修改代码编译发布,这里就不做展开了。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。