笔者负责的项目最初是由外包团队开发完成,验收阶段没有做过性能方面测试,项目中较复杂的业务性能表现不太理想。 我们技术团队对线上的接口加了监控,监测各个关键接口的健康状况,主要包含接口响应时长。从中发现短视频模块中一个视频排行榜的接口性能非常糟糕,前端经常出现超时(前端设置的超时时间是10s)。针对此问题,笔者梳理业务逻辑,着手解决此接口的性能问题。
定位问题 本项目是部署在阿里云服务器,从mysql实例的慢查询日志中发现多条查询耗时在10s左右的sql语句,对应项目中的sql片段如下 SELECT ID, act_works.MAG_ID, act_works.user_name, act_works. DESCRIBE, act_works.user_icon, `LIKES`, < IF test = "commentMode == 'true'" > ( SELECT count(1) FROM act_comment WHERE WORKS_ID = act_works.ID AND act_comment. STATUS = 1 ) COMMENTS, </ IF > < IF test = "commentMode == 'false'" > ( SELECT count(1) FROM act_comment WHERE WORKS_ID = act_works.ID AND act_comment. STATUS != 2 AND act_comment. STATUS != 3 ) COMMENTS, </ IF > RESOURCE_ID, ( SELECT ifnull(sum(act_works_like. LIKE), 0) FROM act_works_like WHERE act_works_like.WORKS_ID = act_works.ID AND act_works_like. ENABLE = 1 < IF test = "starTime != null and endTime != null" > AND act_works_like.CREATE_TIME >= #{starTime,jdbcType=VARCHAR} AND #{endTime,jdbcType=VARCHAR} >= act_works_like.CREATE_TIME </ IF > ) likesCount, RESOURCE_URL FROM act_works WHERE act_works. STATUS = 1 AND act_works.ACT_ID = #{actId,jdbcType=VARCHAR} < IF test = "starTime != null and endTime != null" > AND act_works.CHECK_TIME >= #{starTime,jdbcType=VARCHAR} AND #{endTime,jdbcType=VARCHAR} >= act_works.CHECK_TIME </ IF > ORDER BY likesCount DESC, act_works.CHECK_TIME DESC 分析问题 分析此sql片段,此sql为查询语句。初步分析此sql存在如下问题: 1、涉及三张表act_works、act_works_like、act_comment的关联查询,三张表的数据量都比较大; 2、每次调用接口都查询数据库,增加了数据库的压力。制定方案 1、把act_works、act_works_like、act_comment三张表的关联查询拆分开来,把数据库中的计算工作转移到服务器内存中计算; 2、使用缓存来分担数据库查询压力; 3、视频排行榜相当于全局数据,可以放在缓存中,并通过定时任务来定期更新。具体实施 加载最近100个挑战活动获得挑战活动列表(加载热点数据); 循环遍历挑战活动列表,根据时间条件查询此活动的周榜、月榜和总榜的排行榜信息,并把查询结果存放到redis缓存; 每查一个活动sleep 500毫秒,避免数据库资源长时间占用。