前言
最近总算上线了历时半年多的数仓办理文件夹的优化,泪目了家人们,可谓是呕心沥血之精雕细琢之抓耳挠腮之无能狂怒之爱咋咋地的匠心巨著总算上线了,组长为了测验全体重构后的功能专门向运维申请了一台新机器布置重构后的版本代码搭建一套独立的线下集成环境,然后用前史积累下来的数据灌到新服务里看一下全体的体验。
牛逼都吹出去了,原来1s以上的接口呼应悉数优化到500ms以下,代码结构优化后通过中台才能可以半天开发出一套数据办理相关事务。尽管季度会上我没说话,可是听着组长在会上哐哐吹牛逼,我听着腿肚子直转筋,后背呼呼冒冷汗。。。。
之前写的重构的一些思路的文章贴在下面,主要理了一下文件夹相关的一些厌恶的点以及解决方案。
- 【代码结构设计】优化重构文件夹的树状结构
接口调优
由于代码结构变化比较大,根据的表逻辑也发生了一些改动,线下测验的时分是用了一个纯洁的环境去做测验,包括崭新的mysql镜像。这样搞的话线下的数据就远远低于了出产环境下的数据量,这次优化大部分是一些查询类的sql,尽管测验都快完毕了,可是我还是有一点点的虚。
环境一搭建好我就立马进行测验,数据量一大果然露出了马脚,改造后的主页,首先会加载一个平平无奇的类型树接口,点进去页面后loading转了三四圈后才加载出来…..
完了,当时榜首反应是离任散伙饭去哪家吃。。。不可门口那家云南菜吧,刚抢到张50代金券。。。
测验环境里几千条数据毫秒级呼应不在话下,数据量上了十万之后直接干到3s左右了。直接原形毕露,好在组长给了我两天反应时刻。这下得拿点东西出来了家人们!
首先架构现已定了,而且技术评审了好几轮应该没有太大的问题,有也不能全赖我。想到这一点稍微缓和了一下,先剖析日志。咱们的日志都会打出毫秒级的履行时刻,依据接口的trace_id获取所有的请求信息,马上就排查出导致慢的榜首宗罪。
反序列化
由于构建树的时分,一些接口是全量获取,十万等级的单表查询其实是非常快的,顶多损耗个几十毫秒在网络IO上,但我发现在履行SQL到SQL履行完足足用了差不多1s,每一个全量接口都耗费了许多时刻,将sql单独摘出来履行又很快,榜首反应便是反序列化出了问题。
由于咱们运用JPA做数据库层的ORM框架,为了解决原生sql联表查询返回自界说DTO,公共组件里界说了一个用于反序列化的注解@JpaResultDto,这个注解是用aop的方法在服务启动时用反射将DTO类注册一个Converter到Spring默许转换器里。
问题就出在这里,每一条数据从DB反序列化的时分都要通过反射拿到类信息,再通过静态代理的方法将真实的数据写入到对象里。每条数据都这么搞,功能损耗就起来了。当断则断,这帮做中间件的做的什么玩意,差点害我翻大车。。。。
骂骂咧咧的用Object接收,手动反序列化,果然接口成功徘徊到了800ms左右,偶然会抽风到1s,果然高端的食材只需要最简单的烹饪方法。。。尽管离500ms还有一定距离,不过我丝毫不慌,调优三板斧的连招打出榜首招优化了50%。
SQL调优
主页的树接口功能上来了,试一下悉数数据的分页接口,果不其然…..也在1s多,完了完了,呕心沥血的接口居然发挥成这样,反序列化的事现已统一了,内存操作的损耗简直可以疏忽。马上反应过来是SQL的履行问题,翻开一下JPA的慢SQL监控。
jpa:
show-sql: true
properties:
hibernate:
session:
events:
log:
LOG_QUERIES_SLOWER_THAN_MS: 100 # 记录大于100ms的慢查询
翻开后日志里如果有超过了配置的100ms的SQL都会打出来数据库里真正履行的SQL便于剖析,成果翻开后tail -f 监控日志,那个SlowQuery Sql呼呼的打,打的我心都要碎了。。。。
底子原因是当时为了便利后续的调试我把查询条件都整合成了一句SQL,然后用if句子去判断要不要join表查询条件,这样肯定是有一些耗费的,不过这块我留了一手。
按需加载
所谓按需加载便是非常时期用非常手法,这种高功能且经常访问的接口可以疏忽一些代码结构上的不合理,理论上数据库层查询都要把SQL界说在DAO层去履行。可是这样关于多条件查询的分页接口下显得十分不灵活,已然长痛不如短痛,干脆把SQL界说到Service层,咱们在Servcie层根据查询条件按需拼接对应的查询句子。这样的话默许进入页面的时分本质上是一个单表查询,能不起飞吗。
由于当时留了一手,顺带着树接口很快就改造好了,分页接口果然到了200ms左右,全量树到了500ms左右徘徊,ok了ok了,散伙饭看来可以推到拿完年终了。
数据库参数调优
三板斧劈完两板斧之后,接口尽管速度是上来了,可是还很不稳定,隔一段时刻就会有一次较慢的查询,尽管不是特别慢,可是能明显感受到,比方树接口偶然会到1s多。那这肯定不可啊,如果组长演示的时分突然抽筋一下子,那我仕途不是走到头了。
抖动的问题浪费了很久的时刻去剖析原因,一直没有啥条理,偶然一次看日志的时分发现还是sql履行的问题,那么相同的sql相同的机器,会有哪些原因导致履行功能不同呢。SQL实在是优化不动了,于是打起了MySQL的主见,数据库履行查询如果刨去SQL履行的损耗。
那大部分都会耗费在IO上,平常咱们的数据库都进行过参数调优,这台新机器新布置的数据库肯定稍显逊色,于是马上iotop滚动个五分钟调查机器目标。
发现MySQL的io隔一段时刻就干到100%冲到榜首,隔一段时刻就冲上来。那么OK了,跑不了,绝对是磁盘IO导致的。那么怎么规避一下呢。
回忆之前的MySQL八股文,咱们知道MySQL这层是有一层buffer缓存机制的,innodb_buffer_pool_size,缓冲池是数据和索引缓存的地方,它归于MySQL的中心参数,默许为128MB,正常的情况下这个参数设置为物理内存的60%~70%。合理猜测一波,接口呈现抖动是因为缓存到buffer后大部分时刻接口相应是很快的,可是由于buffer_pool大小为128M,满了之后被清掉就会导致重新进行一次磁盘IO导致抖动。
以在my.cnf里加上重启后果然成功稳定在了500ms以下。