当前位置: 首页 > 后端技术 > Java

生产环境性能优化案例-Oracle

时间:2023-04-01 21:09:49 Java

随着公司交易量的增加,应用端TPS下降,接口耗时变长,甚至在业务高峰期请求超时。但是应用服务器的CPU不到50%,内存占用40%(4C8G配置),loadaverage:0.43,0.45,0.49;负载很低。数据库为ORACLE11G,CPU:128C,内存:512G??,存储:14T。在业务高峰期,60%的CPU被使用,45%的IO空闲。主界面平均耗时统计为每分钟一点。从下图可以看出,在业务量不大的情况下,平均耗时在25毫秒左右。一旦到了业务高峰期,最大平均耗时突然上升到120毫秒。数据库监控图:高峰期CPU和IO占用率非常高。情况发生后,立即成立了一个研究小组。毕竟距离五一假期只有一周的时间,五一假期成交量至少会增加30%。经过第一阶段的分析,制定了以下改进方案:1、修改应用Druid连接池的初始连接数。从Druid监控来看,高峰期最大连接数为27,可能是瞬时交易量激增,连接数不够。以往的经验告诉我们,创建一个新的数据库连接需要很长时间,这会导致瞬时请求排队等待获取连接。因此,决定将初始值从20改为30。2.由于会计数据库(Oracle)采用两主一从的高可用部署(A、B为主节点,C为从节点node),应用系统当前配置的所有主节点都是A,从节点都是B,决定将部分应用主节点调整为B,以减轻A节点的压力。3.会计幂等表改造。现在幂等表已经分了4张表(单表4亿条数据),但是从整个记账请求的耗时分析来看,幂等表和记账流表的查询和插入操作是耗时的-消费。因此,决定将幂等表扩大到64个(为什么是64个,是科学计算出来的,具体计算过程保密不能说)。4、MQ接管,因为临近5月1日,各方压力都很大。如果以上优化点都失败了,最坏的方案就是使用MQ的异步接管机制。但是这种方案会影响业务,除非万不得已,否则不会使用。装修方案确定后,便开启了加班模式,兄弟们夜以继日地工作,迅速完成装修并投产。但上线后的效果与预期相去甚远。方案一:投产后发现,高峰时段计费耗时问题还是比较严重的。调整druid连接池不仅没有效果,反而增加了数据库连接数,浪费资源,回滚。方案二:主备节点调换后,数据库资源争用严重,频繁GC导致CPU占用率反而上升,回退。方案三:幂等表分成64块后,新表的读写速度非常快,平均0.7毫秒,旧幂等表的平均读写速度为4.7毫秒。但是由于旧幂等表数据量大,没有re-hash洗数据,所以代码层也需要兼容旧幂等表的查询,并没有提升整体效率.第一阶段总结:除了方案3长期有效,其他两个方案都没有解决问题。经过反思,我们觉得自己的方向不对,还是没有对症下药。于是大家又回去求医。经过第二阶段的分析,制定了以下两个方案:1、这时候DBA发现了一个新的问题。业务高峰期,计费流量计和计费流量计存在指标拆分问题。初步怀疑是序号采用了Incremental方式(按序生成,且为索引列)。PS:索引分裂主要是因为在比它大的值前面插入了一个较小的序号,当前索引块空间不够,需要替换掉原来的索引。块(IndexBlock)被一分为二,保证较小的值可以插在最前面。这就带来了一个问题,旧块的部分数据需要放到新开的索引块中。频繁的索引拆分绝对不是什么好事。所以我决定把序列号的生成方式改成snow算法。2、目前流量计采用按日期划分5天,保留2个月的数据。经过讨论,决定改为每天一个分区,只保留最近10天的数据。为什么不分表,因为流表涉及到数据同步,很多业务线都用到这个表。表的改造无法在短时间内完成,分区对应用系统是透明的。PS:索引拆分可以参考这个帖子:http://blog.itpub.net/2673616...,我们遇到的这种情况属于9-1拆分,不管是什么类型的索引拆分,都必须是系统问题不是什么好事。和第一阶段一样,加时模式再次开启。但是最后制作出来之后,效果和第一阶段一样,浪费时间。高峰期数据库压力还是很大的,高峰期平均计费时间依然超过100ms。这一刻,心态炸裂了。毕竟大家都加班了一个星期,身心都已经疲惫不堪了。但问题还是要解决,不然五一黄金周就没有假期了。..第三阶段开始,所谓一命二,二生三,三生万物,万物变化,九十九八十一之后,循环再归一。在第一阶段的优化中提到,从整个记账请求的耗时分析来看,幂等表和记账流表的查询和插入操作是比较耗时的。这时候幂等表已经分表了,那么如果插入流操作改成异步插入呢?没错,首先pipeline的异步插入不会影响业务,其次改成异步后可以减少整个事务周期,事务耗时更少,资源释放更快。最后就算没有效果,异步写入也能达到削峰的目的。通过MQbacklog,降低数据库写入速度,保护数据库。PS:因为流量计每天都在写几十亿的流量,所以数据量还是比较大的。修改后,我们很快就上线了。毕竟,时间是宝贵的。正如预期的那样,它是有效的。上图中灰色部分是我们将pipeline改成异步插入后的耗时曲线,和之前相比效果非常明显。即使在高峰时段,耗时也只有30毫秒。再看看数据库监控图,和之前相比,压力明显下降了,总算是松了一口气。image.png优化第四阶段:但是作为技术人员,你不应该满足于这个时候。回头想想索引拆分确实是科学的,不应该改成没有效果。整理后发现开发小伙伴使用的snowification算法是变异算法。说白了,只能保证全局散列(在分布上),但是局部还是连续的(在单机上)。如果直接换成uuid,抱着试一试的想法,又进行了一轮改造。果然,这个想法得到了验证。投产之后,数据库的压力下降了很多。下面三张图展示了优化前的优化、应用优化、索引拆分优化的效果。