生产厂家上什么网站做推广好,flash网站设计教程,京东网站内容建设,微信的网址链接前言
日常开发中设计接口#xff0c;响应时间是衡量一个接口质量的重要指标。
接口响应时间这里粗糙地分为三种#xff1a;
即时响应#xff1a;毫秒级#xff0c;小于500毫秒快速响应#xff1a;秒级#xff0c;大于500毫秒且小于2秒长时间操作#xff1a;大于2秒响应时间是衡量一个接口质量的重要指标。
接口响应时间这里粗糙地分为三种
即时响应毫秒级小于500毫秒快速响应秒级大于500毫秒且小于2秒长时间操作大于2秒甚至是分钟级别的操作
一般接口都是需要快速响应的在不考虑任何优化策略的情况下如果整个业务逻辑走下来响应时间大于了2秒那么就应该考虑对这个接口进行性能优化了以免影响了用户的体验。
优化思路
缓存
毫无疑问使用缓存是对性能提升最明显的方法。
若是缓存中存在直接返回结果否则再走接口逻辑最后将结果放入缓存中以便下次查询时使用。
缓存还可以分为本地缓存和分布式缓存
本地缓存
由于数据是在本地内存它的访问速度是最快的同时它的容量也受限于运行本地内存以及在分布式系统中本地缓存的数据很可能和其他节点的数据不一致。所以本地缓存一般用来存储一些系统级别上基本上不会改变的内容。
在 Java 实现中最简单的本地缓存其实可以用一个 ConcurrentHashMap 来实现不过在实际开发中有更好的选择可以选择 Caffeine 来做本地缓存性能更好。
分布式缓存
分布式缓存相对本地缓存多了一次网络交互所以速度会慢一些但是大小则不会受制于本地服务机器内存了内存不够用了还可以通过水平扩容来解决而且在分布式系统中 数据的一致性能够得以保证。
常用的分布式缓存为 Redis 和 MemCachedMemCached 更加轻量级一些纯粹的缓存中间件Redis 不仅仅可以作为缓存它还支持更多的功能分布式锁分布式限流地理位置应用布隆过滤器等等
异步
如果是单线程执行业务逻辑那么可以考虑对业务逻辑进行拆分将其中能够并行执行的部分分解出来然后使用多线程的方式去同时运行理论上能够将该部分的运行性能提升提升的大小取决于能够同时运行的线程数
Java 中可以使用线程池 ThreadPool 来并发执行任务进阶一点还可以使用 CompletableFuture 来编排异步任务。
合并
合并其实是指将批量操作将多个操作合并成一个去执行
例如数据库中的批量插入同一个表的多条插入语句其实可以优化成一个插入语句这样可以减少数据库的交互避免重复地创建数据库连接。Mybatis 中的 BatchExecutor 就是这个思路将相同的 sql 语句添加到同一个 Satement 对象中等待执行可以有效地减少 PrepareStatement 地编译操作
Redis 的 Pipeline 也是将多个请求合并最后一起发送这样可以将多次网络交互优化成一次网络交互减少网络交互的时间从而提升性能。
拆分
拆分其实是针对多线程编程中对共享资源的一个拆分避免因为竞争激烈导致多线程并发执行性能反而比单线程还慢了
代码中如果使用到了锁可以从两方面考虑
减少锁的持有时间将不必要的操作尽可能地放到锁外面去执行避免其他线程等待锁的释放时间过长
减少锁的粒度参考JUC下并发类的设计
ConcurrentHashMap是一个线程安全的Map虽然可以直接通过synchronized修饰 put 和 get 方法来得到一个线程安全的HashMap但是这样显然十分影响性能。
在JDK 1.7中ConcurrentHashMap采用了分段锁Segment Lock的机制来提高并发性能。这种设计将整个哈希表分割成多个段Segment每个段都维护着自己独立的锁。这样当多个线程并发访问ConcurrentHashMap时它们可以并行地访问不同的段从而减少了锁的竞争。
在JDK 1.8中ConcurrentHashMap的锁机制发生了重大变化它放弃了JDK 1.7中的分段锁设计转而采用了一种基于CASCompare-And-Swap操作synchronized锁的细粒度锁机制。
除了ConcurrentHashMap在 JUC 包下还有许多 Adder 类IntegerAdderLongAdder 等等当线程竞争不激烈时直接采用CAS来实现数量的原子递增如果竞争激励则使用数组来维护元素个数将单个资源的竞争拆分成多个先从数组中随机选择一个再通过CAS实现原子递增最后再一起汇总。
单例
单例其实也可以看作是缓存的一种实现方式本质是避免重复创建对象直接服用现有的对象从而减少重复创建对象的时间提升性能。
在 spring 框架下开发依赖注入默认就是单例的
压缩
接口的响应时间除了接口本身执行业务逻辑的时间还有网络传输的时间。在其他条件都不变的情况下减少网络传输内容的大小也可以提升接口的性能。
如果接口的返回数据字段很多可以考虑压缩字段的大小比如说将返回的json中的有实际意思的单词字段名直接改成简单的f1f2f3这样在返回数据量大的情况下也可以减少网络传输的内容大小。