一、问题由来
当前参与开发的项目已经上线,并且发布了很多个版本,在服务器上面稳定运行。最近接到通知,需要做服务器迁移,
迁移的东西很多,服务应用需要迁移,数据库需要迁移,redis缓存数据库缓存需要迁移,还有网关服务,配置中心服务等等。
反正一听到这个消息,就知道工作量不小,还好这一块主要是负责人在做,自己作为开发人员也会参与迁移,比如协助测试
人员判断问题是由于业务引起的还是系统迁移导致的。如果在测试过程中发现其他问题,也需要积极的配合解决。
测试环境首先进行迁移后,测试人员正在进行系统功能正确性的验证,测试结果一切正常。然后高级测试人员开始进行系统
性能的测试,立马发现问题,有两个对外提供服务的接口性能不达标,让我们开发去看一下是怎么回事。自己立马找测试人员去
测试,测试的结果确实很慢,好几次请求都需要20s左右才能返回数据,这么慢系统还怎么用呢?
二、问题分析
发现问题后,我立马在原来的测试环境进行验证,并没有复现同样的问题,原来的测试环境请求同样的接口,传递同样的参数
请求时间都正常,1s内能够正常返回数据,那这到底是怎么回事呢?下一步能够想到的办法就是在这两个接口中的关键位置打印日志,
通过打印的日志来判断到底是哪个地方出的问题。自己在最开始开发的时候只打印了少量的日志,还不足以排查目前遇到的问题。添加
日志后,重新部署,发现某一个数据过滤的方法被频繁调用,并且每调用一次就需要从缓存中去取一次数据,负责人初步判断就是由于
这个方法在执行的时候,花的时间太长,导致程序执行慢,让我立马去查看。
三、解决方案
初步找到问题后,自己开始对这个问题进行分析,两个接口里面都处理了同一种类型的数据,那基本可以判断就是在处理这种类型
数据的时候太慢,导致性能出现问题。接口获取数据的方式很简单,先从缓存中获取数据,然后过滤,之后是做计算处理,有的数据不能
直接返回,最后是转换为调用方需要的格式进行返回。问题就出在数据过滤这一步,过滤的方式也很简单,首先循环原有的列表数据,拿到
主键ID,在嵌套循环用户请求时传入的多个编码进行过滤,从缓存中取数据。假设列表数据有100条,用户传入的过滤编码有5个,那么
从缓存中取数据的次数就是100 * 5 = 500次;
按照系统原有的设计,所有编码对应的权限数据,都会存入缓存中,因此优化方案为,先从缓存中根据用户传入的编码,取出当前用户所
具有的权限列表,然后在根据这个权限列表去过滤列表数据。方案敲定之后,自己着手进行代码改造,大致花了一两个小时的时间才改造
完成。还是以上面示例,这时候取缓存的次数变为5次,就将用户传入的编码对应的权限全部取出,取缓存的次数大大地减少。代码修改
完成后,再次部署代码进行测试,发现效率大大提升,单次请求的时间降低到2s左右。性能以肉眼可见的方式大幅度提升。
代码层面做优化后,继续回来分析问题,原有测试环境也是采用同样的处理方式,为什么没有出现这个问题呢?这就让人很疑惑,代码
是有优化的空间,之前生产上面的服务都是正常运行的,也没有出现问题。然后继续分析,生产上面的数据量比较少,只有不到200条的
数据。出问题的新环境,测试数据量在三百多导致请求非常缓慢,原有测试环境数据量也是在三四百的样子却正常。那基本可以判断一点,新
环境的服务器性能比较差。修改完代码重新部署后,性能已经极大的提升,可还是不能满足系统设计的要求。经过负责人的进一步排查,确定是
云redis服务器非常慢导致的一部分原因,原有测试环境redis使用的物理服务器,所以性能很好。新环境使用redis云服务器,网络耗时太久,
导致性能跟不上。自此,总算是搞清楚导致接口查询慢的所有原因,问题解决方案也已经敲定,让自己学习到的最重要的一点就是嵌套循环一定
要慎用,一不留神就会导致效率大大地打折扣,认真吸取这次深刻的到经验教训!