系统优化复盘一二三

2024-03-07 00:32

本文主要是介绍系统优化复盘一二三,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

背景

2020年下半年的某个周五下午,作为主开发的我请假出去摸鱼了,然后下午四点左右突然的服务器报警不约而至,各个应用大量报错显示网络超时。人在外,只能拜托其他同事帮忙排查问题了,同事排查后发现是Nginx服务器的CPU满载导致的服务不可用,并于半小时后恢复正常。

在这里插入图片描述

回到公司后自己排查发现,确实是Nginx服务器故障了,故障期间Nginx服务器的带宽几乎打满,CPU长达半小时的时间内100%荷载。为了进一步分析问题原因,就把故障期间的Nginx日志扒下来解析分析统计,发现是大量的前端请求营销活动的H5页面,下载静态资源文件占用了故障期间的90%以上的带宽。至于为什么各个后端应用也报错网络超时,则是我们项目架构不合理的原因。如下图,如果前端请求A应用,A应用再请求B应用,其网络调用链路应该如下图。

在这里插入图片描述

但实际上我们项目的架构如下图,因为没有引入注册中心,所以后端应用之间的调用是通过Nginx做负载均衡,且该Nginx与前端Nginx为同一个Nginx。这也就导致了当前端的静态资源流量把Nginx服务器打满后,后端应用之间的网络服务调用也受到了影响,从而大面积报错服务调用网络超时。

在这里插入图片描述

初步分析

后来通过同事了解到,有个大商户通过微信公众号推送了我们项目的营销活动H5领券页面,再加上该商户拥有2000万的公众号粉丝和1600万的注册会员,所以导致H5资源访问打垮了Nginx服务器。

问题似乎一下清晰了,把Nginx的访问日志以及分析结果绘成的流量占用图扔给了项目组长以及前端同事,然后就由前端同事接走了锅负责问题的修复。

解决方案也非常简单,就是把前端的所有静态资源文件全部上传到CDN,Nginx服务器尽可能不处理静态资源的访问。

第二次事故

第一次事故发生后的第二个月,引发该事故的商户提前跟我们组打招呼说下午4点再来一次营销推送,还跟上次一样通过微信公众号给2000万粉丝推送营销活动H5领券页面。这次我们拍着胸脯说肯定没问题,已经做了对应的优化了,然后就被啪啪打脸了。

下午4点商户准时推送了微信公众号,然后我们眼睁睁地看着Nginx服务器的CPU荷载100%打满。Nginx服务器坚持的时长比第一次久一些,但最终还是带宽打满CPU满载,并和上次一样后端应用之间的服务调用大面积报错网络超时。

连续两次营销活动推送故障并影响到了其他的正常主业务,多个商户表示不满,我们项目组则暂缓手头目前的需求任务,把系统优化作为接下来一个月的主要工作。

再次分析

再一次扒Nginx日志解析分析统计,发现这次的Nginx流量占比中静态资源占小部分,绝大部分都是后端服务之间调用占用的。主要分析如下:

  1. 上次前端静态资源上传CDN的改造覆盖面不完整,还有部分静态资源遗漏
  2. 后端服务之间调用返回报文中无用字段过长导致报文臃肿,甚至出现一个返回报文长达几十KB而实际有效字段仅十几个字节
  3. 后端服务之间的服务调用使用了HTTPS,且部分应用使用的HTTP短连接,导致Nginx处理高频率HTTPS的TLS握手浪费了大量的CPU性能
  4. 应用对几乎不变的数据没有加缓存,重复调用其他应用服务导致网络IO浪费

初步方案

针对分析结果,这次故障的主要原因就是报文的无用字段太长报文臃肿,以及后端服务之间的网络调用没有使用直连的方式。因此第一步的主要改造点如下:

  1. 注册中心搭建,后端服务之间的服务发现通过注册中心实现,后端的网络调用不再通过Nginx,各个后端应用之间使用HTTP直连,降低Nginx的负载
  2. 对臃肿报文进行裁剪,只返回调用方需要的关键字段,从而降低网络IO和各个应用的GC
  3. 对于几乎不变的服务调用结果做缓存,降低网络IO
  4. Nginx做限流,营销活动这种容忍失败且优先级低于主业务的场景,针对几个突发流量高的接口做限流处理,避免影响到主业务
  5. 前端遗漏的静态资源上传到CDN

第二次分析

以上方案匆匆忙忙改造完成后,用测试环境进行了一波压测,虽然测试环境配置远低于生产,但压测数据并不是很理想。压测过程中Nginx服务器的带宽压力和CPU荷载不高,因此改造确实没有问题,但还有额外的优化空间。

进一步优化则需要对后端应用进行分析,常用的方式有On-CPU火焰图分析CPU使用分布、时钟火焰图和链路追踪埋点分析各个线程执行耗时时间的分布等。借助于arthas工具的火焰图事件采集对几个压测系统进行性能分析,得出以下信息:

  1. 用户每次与营销系统交互,营销系统都通过Cookie向SSO系统查询用户ID,虽然耗时不长,当该流程可以优化
  2. 营销系统打印了大量的无用日志,压测期间日志打印占用的CPU荷载和耗时较大
  3. 压测期间营销系统和券系统高频率访问的mysql数据虽然使用了redis缓存,但作为热点数据,访问redis缓存的网络耗时消耗可观
  4. 券系统发券前对领券活动的用户合计领取/每日领取张数限制逻辑实现不合理
  5. GC频繁

第二次方案

会话登录优化

大量登录用户请求营销系统时,即使营销系统对用户会话做缓存,但对于营销活动用户抢券这种低频率场景,用户会话缓存的命中率并不高,因此我们从其他方面着手改造。

当前营销系统对于用户会话只需要获取用户ID,其他信息都不必要,因此改造SSO的Cookie生成逻辑,Cookie的值为加密的JSON,其中包含了用户ID和Cookie的过期时间。从而营销系统接收到用户请求后不再需要额外请求SSO系统,直接按预定义的算法从Cookie中解密出用户ID。

日志打印优化

无用日志打印的问题很好解决,挨个排查日志打印的代码,仅打印关键信息日志即可。

热点数据优化

热点数据为活动配置和券配置信息,都是更新频率极低且容忍数据短时间不一致的场景。因此对于这两种热点数据采用堆内缓存+redis缓存的双重缓存方案,具体实现逻辑如下图。

在这里插入图片描述

热点发现

暂定QPS超过200的记录就记为热点数据,由于生产环境当前只有4个节点,为了降低热点数据计数消耗,只要一个节点在内存中计数发现活动配置/券配置的某条记录当前节点的每秒访问次数超过50次,则标记该记录为热点数据。

热点上报/失效上报

热点数据信息会通过kafka推送到该服务的所有节点,且同一条记录短时间内最多推送一次,避免不必要的网络IO消耗。默认对于非热点数据只启用redis缓存读写,当应用节点收到热点数据通知后,记录该热点数据ID,对于热点数据启用堆内缓存+redis缓存。

另外为了能够通过人工提前对热点数据预热,我们也实现了通过配置中心将预热的热点数据key推送到集群各个节点,从而实现热点数据的预热。

对于热点数据更新发生的热点失效问题,直接同步更新redis缓存,然后通过kafka上报热点失效,通知该服务的所有节点失效该记录的堆内缓存,保证缓存数据最终一致性。以及为了防止出现缓存击穿的问题,各节点定时刷新和续期热点数据的堆内缓存,另外主节点还额外负责定时刷新和续期热点数据的redis缓存。

热点key持久化

每当有热点上报或失效上报时,主节点额外负责将当前热点key持久化到数据库中,保证应用节点重启后能及时从数据库获取当前的热点key,从而不会出现由于没有命中热点缓存导致缓存击穿的问题。

发券限制实现优化

业务代码优化,原先发券流程中对于用户每日领券数量控制的实现方式是从mysql的用户券码表实时查询用户当日已发券数量,但营销活动短时间爆发大量用户领券的场景下,该方案令mysql的压力较大。

因此优化实现方式,通过redis计数累计用户的每日领券数量,降低mysql的查询压力提高接口的响应速度。

GC优化

压测期间营销系统的GC日志显示yong gc频繁但没出现过full gc,配合JVM堆内存监控发现新生代Eden区使用内存增长很快,而Survivor区使用内存增长浮动很小,另外老生代使用内存几乎没有浮动,说明压测期间有大量的对象创建但存活时长短暂,大多数对象都存活不到Survivor区,且几乎没有对象能够长时间存活而晋升到老生代。

GC时长消耗分两部分:对象扫描、存活对象移动,且前者的消耗很小,因此GC的时长取决于每次垃圾回收后存活的对象数量和大小,垃圾回收后存活的对象越多内存越大则GC耗时越久。对于我们这个绝大多数对象都存活不到Survivor区的场景,只需要简单地调整XX:NewSizeXX:NewRatio参数降低老生代大小增加Eden区大小,就可以在单次GC时长几乎不变的前提下延长GC间隔,从而整体降低GC时长的占比。

另外通过arthas工具的alloc事件采集,对几个压测系统压测过程中的内存分配分析发现,主要的内存分配消耗在日志打印、应用服务HTTP调用和redis网络调用上。以上几个优化实现后GC频率进一步下降,剩余几个内存分配较高的代码逻辑由于时间所限暂时忽略。

分库分表

券系统券码单表膨胀到了20G,因此对券码表以用户维度进行水平拆分,通过开源中间件Sharding-Proxy将券码表进行查分。

但由于Sharding-Proxy对于分布式事务支持不够完善,local本地事务不适用于分库分表场景,2PC分布式事务性能影响较大,柔性事务Sharding-Proxy还不支持,因此对于券码表的操作直接放弃数据库事务,通过业务代码实现补偿机制。

分库分表修改面较大,包括分表后sql的修改优化,包括数据统计逻辑的重构等过程,完全可以新开一个篇幅专门记录其中的问题分析、问题解决的过程,因此此处略过。

网关优化

现状

当前的负载均衡逻辑为Nginx做负载均衡,服务发版时通过动态模板解析实现:Jenkins自动化脚本修改Nginx的upstream文件实现。例如对某服务的a、b两节点发版时具体逻辑如下:

  1. 先修改Nginx的upstream脚本摘除该服务的a节点,执行reload命令
  2. 等待Nginx不再有请求路由到a节点后,正常关闭a节点
  3. 发布a节点的新版本并启动
  4. 最后再修改Nginx的upstream脚本重新添加a节点,执行reload命令
  5. 接着同样的逻辑操作b节点

问题

在这里插入图片描述

  1. Nginx执行reload后会提前主动关闭HTTP长连接,导致调用方对Nginx的请求网络错误,流程如上图
  2. Nginx的worker进程数量一般配置为CPU核数或CPU核数x2,但reload会造成一段时间内worker进程数量翻倍,导致进程发生CPU争抢,从而降低了Nginx的性能

方案

Kong网关是基于openresty+lua的开源网关,其提供了内部管理API接口,可以通过这些开放的API接口来管理Kong内部的各个对象,例如上线/下线节点target,详见官方文档admin-api/add-target。通过这种方式修改Nginx的转发逻辑避免了reload命令,不会出现服务端提前主动关闭HTTP长连接以及性能下降的问题。

# 节点上线
curl -X POST http://127.0.0.1:8001/upstreams/test-upstream/targets \
--data "target=172.17.0.1:8080" \
--data "weight=100"# 节点下线
curl -X POST http://127.0.0.1:8001/upstreams/test-upstream/targets \
--data "target=172.17.0.1:8080" \
--data "weight=0"

在这里插入图片描述

因此可以搭建如上图的架构方案,自行代码实现一个节点监听服务,通过对接注册中心的API来实时监听各个服务节点的状态。当某服务节点上下线后,注册中心将节点上下线事件推送给监听服务,然后监听服务通过Kong的开放API修改该节点对应的Kong中的target对象状态。

通过上述方案从而实现一个注册中心同时管理微服务之间的服务发现和网关到服务的服务发现。此时应用发布流程例如对某服务的a、b两节点发版时具体逻辑如下:

  1. 请求注册中心下线该服务的a节点
  2. 监听服务监听到a节点下线后自动将Kong中的a节点下线
  3. 等待a节点无流量请求后发布重启a节点的新版本
  4. a节点启动成功后自动将自己重新注册到注册中心
  5. 监听服务监听到a节点上线后自动将Kong中的a节点上线
  6. 接着同样的逻辑操作b节点

这篇关于系统优化复盘一二三的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/781872

相关文章

一二三应用开发平台应用开发示例(4)——视图类型介绍以及新增、修改、查看视图配置

调整上级属性类型 前面为了快速展示平台的低代码配置功能,将实体文件夹的数据模型上级属性的数据类型暂时配置为文本类型,现在我们调整下,将其数据类型调整为实体,如下图所示: 数据类型需要选择实体,并在实体选择框中选择自身“文件夹” 这时候,再点击生成代码,平台会报错,提示“实体【文件夹】未设置主参照视图”。这是因为文件夹选择的功能页面,同样是基于配置产生的,因为视图我们还没有配置,所以会报错。

个人成长的利器:复盘教你如何避免重蹈覆辙

前言  📫 大家好,我是南木元元,热爱技术和分享,欢迎大家交流,一起学习进步!  🍅 个人主页:南木元元 最近忙着学习和工作,更新比较少,期间一直在思考如何才能快速成长,这几天刚看完了《复盘》这本书,感触颇深,在此记录一下自己的收获。 人学习有三种途径: 从书本上学前人的知识; 从身边的人身上学其先进之处;向自己过去的经验和教训学习 其中最重要的学习途径就是向自己学习,

linux面试题(系统管理类——系统优化)

如何进行linux系统优化 禁用不需要的服务(ntsysv命令最为方便)避免直接使用root用户,普通用户通过sudo授权操作通过chattr锁定重要系统文件(/etc/passed,/etc/shadow/etc/group,/etc/gshadow,/etc/inittab)配置国内源,加快下载速度配置系统同时打开最大文件数(vi /etc/profile,ulimit -SHn 65535

文章解读与仿真程序复现思路——电力系统自动化EI\CSCD\北大核心《基于IGDT-效用熵的园区综合能源系统优化配置方法》

本专栏栏目提供文章与程序复现思路,具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源程序擅长文章解读,论文与完整源程序,等方面的知识,电网论文源程序关注python

每日复盘-202406020

今日关注: 20240620 六日涨幅最大: ------1--------300462--------- 华铭智能 五日涨幅最大: ------1--------300462--------- 华铭智能 四日涨幅最大: ------1--------300462--------- 华铭智能 三日涨幅最大: ------1--------300462--------- 华铭智能 二日涨幅最大: -

程序员做电子书产品变现的复盘(10)

前面提到了我对竞争对手发起的投诉,没想到这竟然引发了一场规模庞大的战争,意外地促进了我国版权合规化的进步 。 以前,每当收到版权方的通知,无论APP有多受欢迎,我都会立即下架,一方面是为了避免法律风险,另一方面也是基于互联网从业者的基本道德。 但这场混战的爆发,让每个参与者似乎都变成了版权方,一个月内收到的侵权投诉多达几十封,让人难以辨别真假。 混战的爆发 这场战争起始于一些玩家无差别的攻

【报告分享】2021年618全面复盘报告-魔镜市场情报(附下载)

摘要:对于新锐品牌来说,618是品牌获得更多流量、提升用户体验的购物节点,也为下半年备战提供了诸多素材;在大环境下品牌们从以“货”驱动,关注促销品类、单品的惯性下,逐渐转变为以“人”为驱动,在购物体验、需求上做升级,再满足普遍需求的前提下,开始强调品牌价值、社会价值、情感认同和精神附加。 来源:魔镜市场情报

【报告分享】2021美妆品牌营销战果复盘-解数咨询(附下载)

摘要:当下的化妆品产业,正从营销时代迈入品牌时代。站在这一全新的周期节点上,品牌成长的路径以及对应的营销模式、渠道和产品策略,均急剧变化。面对流量红利的消失,长期主义成为时代的主旋律。报告聚焦美妆品牌社媒营销,总结2021年社交营销思维和模式的变化,为品牌提供2022年营销策略参考。 来源:解数咨询 ​ 如需查看完整报告和报告下载或了解更多,公众号

【报告分享】复盘2021瞭望2022美妆新风口-解数咨询(附下载)

摘要:在全球消费市场萎靡的大环境下,中国美业的蓬勃发展着实引人注目,线上线下的深度融合、KOL和品牌的科普教育、数字化手段的推波助澜,让整个美业从C端到B端都涌现出了新生势力和需求。从整体的化妆品竞争市场来看,虽然国际品牌一直遥遥领先,但也已经可以明显看到,国货的奋起直追,其通过不断深研科技和数字化转型形成自身独有的竞争优势,在行业掀起了一股“新国货美妆”风潮。 来源:解数咨询 ​

每日复盘-202406019

今日关注: 20240619 六日涨幅最大: ------1--------300868--------- 杰美特 五日涨幅最大: ------1--------300462--------- 华铭智能 四日涨幅最大: ------1--------300462--------- 华铭智能 三日涨幅最大: ------1--------300462--------- 华铭智能 二日涨幅最大: --