本文转载自微信公众号《猿世界》,作者尹继焕。转载本文请联系元天地公众号。面试过程中经常被问到:你做过性能优化吗?你优化了哪些方面?你是如何优化它的?优化的效果如何?.对于没有真正做过优化的小白来说,肯定受不了这一系列的质疑,最终只能以面试失败告终。那么性能优化到底在优化什么呢?下面我们来盘点一些常用的优化方法。SQL优化当你开发的接口响应时间超过200ms,你就得优化了。当然200ms不是绝对值,要看应用场景。以App为例,如果将5个接口调用到一个页面中(题外话:也可以做聚合),那么总时间是1s,对用户来说体验还不错,当然响应越快越好.界面耗时200ms,大部分时间是对数据库的操作,一个界面会有N个数据库操作。因此,优化SQL的速度优先级最高,大量的慢SQL会拖累整个系统。SQL的优化不是本文的重点。大部分慢SQL与你平时的开发习惯有关。大多在写SQL的时候不怎么考虑性能,只要写出来,join就可以随便做,查询字段不整理,不加索引。刚开始上线没问题,等并发量和数据量增加。是时候冷静下来了。关于数据库的使用规范可以参考下面这篇文章:老板让我整理一下公司内部的mysql使用规范分享给大家。数据量大的时候,一定要做读写分离,分库分表,这也是优化。唯一的办法。读写分离数据库和表分离,减少重复调用性能差的另一个致命问题是重复调用。同一个逻辑在不同的方法中重复查询数据库,重复调用RPC服务等等。例如下面的代码:skuDao.querySkus(productId).stream().map(sku->{skuDao.getById(sku.getId());})再根据ID查询,数量越多,浪费的时间越多。这里只是一个例子。相信在实际项目中有很多重复的查询。之前写过一篇文章来说明如何解决这个重复查询的问题。有兴趣的可以看看这篇文章:操作简单,ThreadLocal也可以作为缓存,按需查询很多业务逻辑不复杂的函数,但是响应很慢。经常在写代码的时候,不加思索,随便调用一些已有的方法,导致整体响应变慢。总结一下:大部分的性能问题都是代码写的。说一个场景,想必大家都见过。参数为商品ID,作用为商品上架。需要判断状态,满足条件才能上架。这种场景下,只需要获取商品的状态即可判断。有时候你看到的代码往往是这样的:GoodsDetailgoods=goodsService.detail(id);if(goods.getStatus()==GoodsStatusEnum.XXXX){}detail中有很多逻辑,除了基本的商品信息,还有还有很多其他内容,这就是为什么它很慢。并行调用是针对一个接口的。如果设计了多个内部RPC服务或者多个外部接口,并且接口之间没有关联,我们可以使用并行调用来提高性能。CompletableFuture非常适合并行调用的场景。CompletableFuture的使用本文不做详细介绍,做Java的一定知道怎么用。除了CompletableFuture之外,还可以使用parallelStream实现集合类处理的并行调用。在微服务中,有一个专门用于聚合API的层。聚合层非常适合并行调用。一个功能或者一个页面展示都会涉及到多个界面。汇聚层将接口和后端的数据进行聚合,一起响应。到前端。上层缓存缓存也是优化中最常用的,效果提升最明显,成本也不大。对于缓存,不要滥用它。并不是所有的场景都可以依靠堆缓存来提升性能。首先,对于实时性要求不高的业务场景,可以优先使用缓存,更新问题不用考虑太多,自然过期即可。对于实时性要求高的业务场景,缓存的使用必须有完善的缓存更新机制,否则容易造成业务数据和缓存数据不一致。推荐的方式是订阅binlog,统一更新缓存。不要在代码中更新或使缓存失效。简单的场景还好,入口也很少,问题不大。有些数据在多个场景中使用,需要更新的条目太多。异步处理中有一些逻辑。如果不需要实时反馈给用户,可以在后台异步处理。异步处理最常见的方式是将任务添加到线程池中进行处理。线程池需要考虑容量和一些指标的监控。相关文章可以查看我的文章:一时之痒,一个动态线程池,源码在Github上。除了一些指标的监控,使用线程池还有一个需要注意的问题就是任务持久化。如果你的数据已经存好了,通过线程池读出来执行是没有问题的。如果不持久化直接扔进线程池执行,可能会丢失,比如服务重启等场景。关于持久化,无论是线程池还是EventBus,都会遇到,所以对于异步场景,建议大家使用消息队列。消息队列可以存储任务信息,并保证不会丢失。对单独消费队列的消息进行逻辑处理。如果想提高消费速度,也可以使用队列消费端的线程池进行多线程消费。多线程消费也要避免消息丢失。你可以查看我的文章:嘘!这样使用异步事件真的好吗?JVM参数调整JVM参数调整,一般情况下我们不需要调整。偶尔有些代码写的不好,导致内存溢出。这个时候会做一些调整和代码优化。参数调整主要是为了减少GC带来的暂停问题。如果你的程序一直在GC,停顿,你的界面自然会很慢。只要不频繁的FullGC,这个JVM的参数调整可以在最后进行优化,应该优先考虑SQL的优化。加机加机,才是终极杀招。当并发量增加时,如何优化单机、单库的抗并发能力也受到限制。这时候只能横向扩展。如果是创业初期,正在快速发展,加机器是最直接的优化方法。虽然成本增加了,但是开发资源也是成本,节省下来可以实现更多的业务需求。等中期稳定后再考虑架构和性能的整体优化重构。就像玩游戏一样,只有有装备的玩家才能期待。后端应用,高端机器,高端数据库配置,高端缓存等等也是如此。公众号猿人世界。原文链接:http://cxytiandi.com/blog/user/1
