接口慢的解决方法
1.首先查看接口代码逻辑上是否有可以优化的(比如说查询Mysql 能一次磁盘IO就不要多次IO)
eg.
方式一: deviceList.foreach(deviceId->{
deviceMapper.getDevice(deviceId);
}
方式二: deviceMapper.getDeviceList(deviceIds);
2.类似第一点,rpc调用是否过多,比如能否进行一次rpc调用就完成数据获取,而不需要进行多次
两个rpc接口,当需要获取设备列表的时候尽量调用获取列表的,这样可以大大减少rpc调用时间
方式一:deviceApiService.getDevice(deviceId)
方式二:deviceApiService.getDeviceList(deviceIds)
3.如果io很少,rpc调用很少但是整个接口仍然时间很长,考虑多线程(线程池)的方式执行任务(多线程执行任务必须考虑线程同步以及如何对任务拆分的问题)
线程同步(countDownLatch CyclicBarrior synchorinized......)
3.1 当线程之间访问的资源没有任何交集(不会产生并发修改问题的时候),我们只需要考虑线程与主线程之间的关系,比如需要在每个线程执行完之后才进行主线程的执行,那这个时候countDownLatch CyclicBarrior就派上用场
3.2 当线程直线访问的资源有交集(可能会产生并发修改问题的时候),synchorinized 基于CAS的操作就派上了用场
当需要处理任务结果时
3.3 当处理任务结果之间没有特定排序问题的时候(也就是先处理哪个任务都不影响结果的时候)使用CompletionService可以优先处理先执行完的任务,这样避免某些大的线程没有执行完成导致处理结果的时候阻塞其它线程进而影响到吞吐量
3.4 当处理任务结果之间有特定排序问题的时候(也就是处理任务结果必须按照特定排序的时候)使用ExectorService直接执行任务即可,处理任务结果的时候由于必须进行特定排序,那么只能按顺序处理结果,进而有些大任务可能导致阻塞降低吞吐量
4. 如果在线程池仍然解决不了的情况下,采用缓存
4.1spring容器内的缓存,在某些调用功能完全一样且返回基本一样的场景下,考虑在javabean初始化的时候只获取一次,然后缓存在spring容器中(实现InitializingBean的afterPropertiesSet方法,@Postconstruct)
4.2redis等分布式缓存,将某些高频出现的数据缓存在redis中,获取的时候无需从数据库进行获取,这样减少io更快速
5.sql问题,当某些请求穿透缓存到达数据库时,发现数据库查询很慢
5.1首先看有没有使用上索引,再看使用上了什么索引,虽然使用上了索引,但是是否将查询,排序,分组都用上了索引,能否进一步优化
5.2小表驱动大表,大表使用上索引
..........
6.通过上面方法肯定会提升执行效率,但是在数据量真的很大的时候我们可以将接口异步去执行任务,然后前端轮询请求接口,当任务执行完后返回结果,这样用户在执行某个任务的时候仍可以进行其他操作,提升了用户体验