目录
目录
引言
以前只注重“功能的实现”,而不注重代码的质量!这是低级的,经过这么久的摸爬滚打,初窥好代码的门径!
一 :查DB相关的优化
1 代码优化之循环查DB
为什么在for中查DB需要被优化?
简单说如果你的这个for很确定,也很稳定,任何情况下只会循环几次,而且不是大查询,这也无可厚非。
但是,如果一个for会循环几十次呢?那么这个接口调几十次DB,这还是一次接口请求,如果是多次呢,如果是高并发的时候呢?mysql服务器会直接被干挂了吧!所以这些代码要被优化掉,以避免和减少db服务器压力。
解决:
把for循环单独查询的数据改为批量查询-转为map-在for循环中根据key拿到当前循环需要的数据
2 代码优化之循环调Dubbo(或者其他的远程调用)
为什么要被优化?
原因和上面差不多,但是这个更严重一些,我们知道RPC远程调用框架有很多,但是无论哪一种,调用远程接口都是比较耗时的,耗时只会比上面更多,同时也会干挂服务器。
解决:
同上
3 代码优化之重复查询
这个比较简单。
场景:
一段业务逻辑中
//查询id=1的图书
//逻辑处理了一会儿
//又查询id=2的图书
//又过会
//又查询id=3的图书
这不是无谓的IO消耗嘛,干嘛不一次查完
解决:
理清逻辑,接下来会遇使用到哪些需要重复查的数据,比如这里,直接批量查询id in (1,2,3)的图书,后面的直接取数据就好了。一次DB不比3次爽
二 内存、缓存
3 代码优化之内存
看我的这个
项目启动时就加载数据到内存_nurture_的博客-CSDN博客_项目启动就加载
4 代码优化之缓存
以前总以为这个很高大尚,很牛逼,怕不会用!可能刚接触的的同学都是这样吧!
开发中使用的场景:
低频修改,高频访问的数据可以考虑缓存。
缓存的经典使用:先查高速介质,高速介质命中则返回,不存在则查低速介质,返回数据后同时把数据放入高速介质
作用:
减轻DB服务器的压力,提高接口响应速度,进而提升用户体验;高并发。
逻辑处理:
一次请求过来====》拿着约定的key去查redis服务器====》查到了就直接用
====》查不到就查DB,同时存redis
注意:
这里如果是存储的对象会涉及到序列化和反序列话的问题,没啥,很多工具fastJson啥的都可以做到,不多说。
4.1 实际开发中使用
在选课链路中发生DB 请求时 ,原因是未将一些基础信息进行缓存 , 在请求接口时导致每次请求到 DB 上,增加时间耗时,qbs降低 , 而在这次的选课链路中增加了大量的缓存 redis的使用 , 减少了 DB 的次数与耗时 , 很大的减少了请求耗时。
4.2 余量查询接口优化
背景 :
余量接口的请求与刷新是高频的 ,每个学生进入页面会请求每个课程对应班级的余量信息(80+的选修课,每个选修课在 1-2 个班级)
在未做缓存优化时服务器的 rt平均在 3 ,缓存处理之后平均在 1
优化方案 : 余量接口合并请求 + redis 缓存
余量请求接口原逻辑是每一条课程的课时数据就请求一次余量接口 , 导致大量的余量接口请求 , 这次将余量接口合并请求 , 并且余量信息存放缓存 redis 中;
5 代码优化之前置缓存
研究中!...大佬教教我
5.1 开发中实际应用
前置缓存:
前置缓存的优化主要在调用dubbo接口的一些链路上,把调用接口后走缓存的逻辑前置到调用接口之前来减少dubbo的调用。
假设这里UserContextFilter中的doFilter方法为例,doFilter方法中调用了getAndAnalyseUserContext接口,而由于doFilter是一个访问非常高频的一个方法,每一个url进行过滤都要走这里以获取用户的身份信息等,所以会频繁的调用dubbo走到login的服务端。
我们可以看到服务端的逻辑是从redis中获取userContext。
既然userContext缓存到了redis中,而服务端的逻辑也是从redis中获取,那么我们可以在调用dubbo之前就先去查redis,把调用接口后查redis的逻辑拿到接口调用前,这样直接从缓存中获取到之后就不需要调用dubbo,从而减少dubbo和login服务端的压力。
改造之后
我们可以看到原本直接调用dubbo的逻辑变成了先调用getLoginUserContextFromRedis方法,这个方法中的逻辑是先从redis中获取userContext,获取到则直接返回,否则再走dubbo调用接口。前置缓存改造完成。
那么我们可能会产生这样一个疑问,进行前置缓存改造之后,肯定是从缓存中获取不到才会调用接口走dubbo,而调用接口之后在服务端又进行了一次查缓存的操作,这次操作是否是多余的呢?答案当然是否定的,考虑这样一个场景,我们的业务流量非常大,在缓存失效后同时有很多请求走这个链路,它们从缓存中获取不到数据所以都走到了服务端,那么这个时候由于每个请求调用dubbo的耗时长短不一,导致某些耗时短的请求从缓存中获取不到数据而继续执行到了put操作,put操作之后缓存中已经存在数据了,所以那些耗时长一些的请求又可以直接从缓存中获取到数据,而不用再走DB。因此,即使我们进行前置缓存的改造后,服务端也是要再查一次缓存,拦截掉一些到DB的流量。
记录没有截图,简单的文字记录只为了提醒自己。以后会回来完善文章。
三 并行、串行
6 代码优化之串行接口
场景:
多个没有相互依赖关系的接口在逻辑代码中是以串行的方式执行的
解释:
假设一段逻辑是:
//查寻所有用户信息 假设接口耗时100ms
//查寻所有的图书信息 假设接口耗时100ms
//查询所有的阅读记录信息 假设接口耗时100ms
这段逻辑代码走完就是300ms,这是按照逻辑顺序走的,走的是串行。
如果修改为并行,三个接口的耗时就会远远 < 300ms
如何串行改为并行,涉及到JUC的一个包。这里直记录思路。