代做毕业设计网站现成,江西省城乡建设厅网站,广州网站开发哪家好,品牌建设目标包括哪些方面背景介绍
某日下午大约四点多#xff0c;接到合作方消息#xff0c;线上环境#xff0c;我这边维护的某http服务突然大量超时#xff08;对方超时时间设置为300ms#xff09;#xff0c;我迅速到鹰眼平台开启采样#xff0c;发现该服务平均QPS到了120左右#xff0c;平…背景介绍
某日下午大约四点多接到合作方消息线上环境我这边维护的某http服务突然大量超时对方超时时间设置为300ms我迅速到鹰眼平台开启采样发现该服务平均QPS到了120左右平均RT在2秒多到3秒部分毛刺高达5到6秒正常时候在60ms左右。
qps情况 rt情况
问题解决
该服务是一个对内的运营平台服务只部署了两台docker预期qps个位数近期没做过任何的线上发布核心操作是整合查询数据库一次请求最多涉及40次左右的DB查询最终查询结果为一个多层树形结构一个响应体大约50K。之前口头跟调用方约定要做缓存现在看到QPS在120左右QPS证明没有做缓存遂要求对方做缓存降低QPS。后QPS降到80以内rt恢复正常平均60ms最终QPS一直降到40后续需要推动调用方上缓存保证QPS在个位数。
问题定位
由于该服务核心操作是查询数据库且一次请求有40次DB query遂首先排查是否慢sql导致查看db性能监控发现db 平均rt在0.3ms以内可以算出来DB整体耗时在12ms左右排除慢sql导致RT变高。
开始怀疑是否DB连接池在高并发下出现排队tddl默认的连接池大小是10.一查监控整个占用的连接数从来没有超过7个排除连接池不足的问题。
至此造成RT高的原因在数据库层面被排除。
接着开始查采样到的服务调用链上的每一个执行点看看到底是调用链上的那部分耗时最多。发现里面很多执行点都有一个特点就是本地调用耗时特别长几百毫秒但是真正的服务调用比如db查询动作时间却很短(0ms代表执行时间小于1ms也间接印证之前db的平均RT在0.3ms以内)
本地调用耗时: 267ms
客户端发送请求: 0ms
服务端处理请求: 0ms
客户端收到响应: 1ms
总耗时: 1ms
这时候问题逐渐清晰问题出现在本地方法执行的耗时过长可是再次检查该服务所有代码并没有需要长耗时的本地执行逻辑那么继续看CPU的load情况。 load长时间在4左右徘徊我们的docker部署在4c8G的宿主机上但是我们不能独占这个4C的持续这么高的load已经不正常了。
继续追查cpu load飙高的原因接着去看GC日志发现大量的Allocation Failure然后ParNew次数在每分钟100次以上明显异常见下GC日志例子
2020-03-25T16:16:18.3900800:1294233.934: [GC (Allocation Failure)2020-03-25T16:16:18.3910800:1294233.935: [ParNew:1770060K-25950K(1922432K),0.0317141secs]2105763K-361653K(4019584K),0.0323010secs] [Times: user0.12sys0.00, real0.04secs]
每次占用cpu的时间在0.04s左右但是由于ParNew GC太过频繁每分钟最高100次以上整体占用cpu时间还是很可观。 看了下jvm内存参数 年轻代分配了2G内存其中eden区约1.7G
使用jmap查看年轻代对象占用空间情况,排名靠前的有多个org.apache.tomcat.util.buf包下的对象比如ByteChunk、CharChunk、MessageBytes等以及响应涉及的一些临时对象列表。其中ByteChunk等即tomcat响应输出相关类
至此问题明确超大响应包50K在发送到网卡的过程中需要经过从用户态user space拷贝到内核态 kernel space然后在拷贝到网卡进行发送像netty等的零拷贝针对的就是这种拷贝加上响应体查询过程中涉及的大量临时对象list在高并发场景下就导致年轻代内存占满然后频繁gc后续在合适的时间会压测该接口这里还有一个点很多人以为ParNewGC不会stop the world其实是会的。频繁ParNewGC造成用户线程进入阻塞状态让出CPU时间片最终导致连接处理等待接口的RT变高。整个排查过程鹰眼idb性能监控等可视化监控平台帮助真的很大否则到处去查日志得查的晕头转向了。
经验总结 接口设计需要避免超大响应体出现分而治之将一个大接口拆分为多个小接口。
缓存设计像这个服务一样一个请求带来将近40次DB查询的需要考虑在服务端进行缓存当时偷懒了要求调用方去做缓存。
性能设计要对自己负责系统的性能了如指掌可以通过压测等手段得到自己系统的天花板否则某一个接口hang住会导致整个应用的可用性出现问题。
流量隔离内部应用和外部流量之间需要进行流量隔离即使通过缓存也有缓存击穿的问题。
口头说的东西都不靠谱要落在文档上还需要检查执行情况。