·设为首页收藏本站📧邮箱修改🎁免费下载专区💎积分购买✅卡密充值📒收藏夹🎖️众筹悬赏👽聊天室
返回列表 发布新帖

记一次性能调优

267 0
发表于 2023-4-21 16:10:59 | 查看全部 阅读模式

马上注册,免费下载更多dz插件网资源。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
面对性能调优问题,很多人往往只是单纯的套用既往的经验:先试试一个,不行再试试另一个。面对简单的问题,如此通常能事半功倍;但是当面对复杂问题的时候,单凭经验往往并不能达到立竿见影的效果,此时我们需要更精准的判断性能短板在哪里。
一个 openresty 项目,不了解 openresty 的可以参考我以前的文章,从 top 运行结果看,软中断 si 分配不均,绝大部分压在了 CPU5 上,导致 CPU5 的空闲 id 接近于零,最终的结果是其它 CPU 虽然还有空闲 id,但是却碍于 CPU5 的限制而使不上劲儿:
记一次性能调优 一次,一次性,性能,性能调优,面对 top 显示 si 不均衡
既然知道了软中断是系统的性能短板,那么让我们看看软中断都消耗在哪:
  1. shell> watch -d -n 1 'cat /proc/softirqs'
复制代码
记一次性能调优 一次,一次性,性能,性能调优,面对 watch 显示软中断集中在 NET_RX
通过 watch 命令,我们可以确认 CPU5 的软中断接种在 NET_RX 上,也就是网卡上,除了 CPU5,其它 CPU 的 NET_RX 普遍低了一个数量级,由此可以判断,此网卡工作在单队列模式上,我们不妨通过 ethtool 命令来确认一下:
  1. shell> ethtool -l eth0
  2. Channel parameters for eth0:
  3. Pre-set maximums:
  4. RX: 0
  5. TX: 0
  6. Other: 0
  7. Combined: 8
  8. Current hardware settings:
  9. RX: 0
  10. TX: 0
  11. Other: 0
  12. Combined: 1
复制代码
主要留意结果中的 Combined 即可,其中 Channel parameters 里的 Combined 表示硬件支持的最大队列数,而 Current hardware settings 里的 Combined 表示当前值。如果硬件只支持单队列,那么可以通过 RPS 之类的方式来模拟多队列;如果硬件支持多队列,那么激活它就行了。结果显示:本例中的网卡支持 8 个队列,当前开启了 1 个队列,激活网卡的多队列功能后再观察 top 运行结果会发现 si 均衡了,其它 CPU 也能使上劲儿了:
  1. shell> ethtool -L eth0 combined 8
复制代码
记一次性能调优 一次,一次性,性能,性能调优,面对 top 显示 si 均衡了
至此我们搞定了网卡多队列功能,其实说白了这是一个资源分配不均衡的问题,那么除了网卡多队列以外,还有其它资源分配不均衡的问题么,让我们继续看 top 运行结果:
记一次性能调优 一次,一次性,性能,性能调优,面对 top 显示 nginx 的 time 不均衡
如上所示,会发现 nginx 多进程间的 time 分配并不均衡(此 time 是 cpu time),有的干活多,有的干活少,相关问题在「Why does one NGINX worker take all the load?」一文中有相关描述:在原本的nginx 模型中,一个 socket 接收所有的请求,不同的 worker 按照 accet_mutext 的设置来争抢请求,不过因为 Linux 的 epoll-and-accept 负载均衡算法采取了类似 LIFO 的行为,结果导致请求在不同进程间的分配变得十分不均衡:
记一次性能调优 一次,一次性,性能,性能调优,面对 使用 reuseport 前
为了解决此类问题,nginx 实现了 reuseport 指令,每个进程都有对应自己的 socket:
记一次性能调优 一次,一次性,性能,性能调优,面对 使用 reuseport 后
激活了 reuseport 指令后,我们通过 top 命令观察会发现 time 分配变得均衡了:
  1. http {
  2.     server {
  3.         listen 80 reuseport;
  4.         ...
  5.     }
  6. }
复制代码
记一次性能调优 一次,一次性,性能,性能调优,面对 top 显示 nginx 的 time 均衡了
虽然我们没有改动一行代码,但是仅仅通过激活网卡多队列和 nginx reuseport,就提升了性能,但是如果想更进一步提升性能,必须深入代码层面才行,下面让我们看看如何发现代码层面的短板在哪里,是时候请出火焰图了,关于火焰图的概念可以参考我以前的文章,如下是一个 on-CPU (sample-bt)的火焰图,同时采样用户态和内核态数据:
记一次性能调优 一次,一次性,性能,性能调优,面对 火焰图显示 cjson 吃掉了大量 cpu
如图所示,cjson 吃掉了大量 cpu,同时发现宽大的火苗基本都是用户态行为,于是我们去掉采样内核态数据,从而降低噪音,重新绘制用户态 on-CPU 火焰图:
记一次性能调优 一次,一次性,性能,性能调优,面对 火焰图显示 cjson 吃掉了大量 cpu
说明:不了解火焰图用法的话,可以参考 iresty 示例,另外,本例中因为服务器缺少 luajit debug symbol,采样的是 C 语言数据,而不是 Lua 语言数据,结果可能有失精准。
如图所示,确实 cjson 吃掉了大量 CPU。对照代码,发现存在若干次解码 json 数据的操作,于是我们可以判断 CPU 是被 cjson.decode 吃掉的,这也正常,不管是什么语言,高效解码 json 数据都是一个让人头疼的问题,群里问问别人有什么银弹可用,结果有人推荐了 lua-resty-json,从官网说明看,相对于 cjson,它把解码 json 数据的性能提升了 10%~50%,实际具体大小取决于数据的复杂程度,使用上也很简单:
  1. shell> cd /path/to/lua-resty-json/
  2. shell> make
  3. shell> cp json_decoder.lua /usr/local/openresty/lualib/
  4. shell> cp libljson.so /usr/local/openresty/lualib/
复制代码
剩下的具体用法参考测试用例就可以了,需要说明的是 lua-resty-json 只实现了解码。
不过我并没有采用把 cjson 替换为 lua-resty-json 的方法来提升性能,这是因为通过数据分析,我发现在本例中,存在明显的热数据,如果把这些热数据直接缓存在进程中,那么对热数据而言,就完全不需要解码 json 数据了,可以利用 lua-resty-mlcache 来实现:
记一次性能调优 一次,一次性,性能,性能调优,面对 mlcache 的多级缓存结构
至此,本次性能调优告一段落,实际上这并不是一次严谨的性能调优,我只是利用一些项目的间歇期偶尔搞一下,不过最终我们把服务器数量降低了一半以上。

原文地址:https://huoding.com/2020/09/12/850
我要说一句 收起回复

回复

 懒得打字嘛,点击右侧快捷回复【查看最新发布】   【应用商城享更多资源】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

创宇盾启航版免费网站防御网站加速服务
投诉/建议联系

discuzaddons@vip.qq.com

未经授权禁止转载,复制和建立镜像,
如有违反,按照公告处理!!!
  • 联系QQ客服
  • 添加微信客服

联系DZ插件网微信客服|最近更新|Archiver|手机版|小黑屋|DZ插件网! ( 鄂ICP备20010621号-1 )|网站地图 知道创宇云防御

您的IP:3.144.230.166,GMT+8, 2024-9-17 03:25 , Processed in 0.212668 second(s), 78 queries , Gzip On, Redis On.

Powered by Discuz! X5.0 Licensed

© 2001-2024 Discuz! Team.

关灯 在本版发帖
扫一扫添加微信客服
QQ客服返回顶部
快速回复 返回顶部 返回列表