性能优化是Java进阶岗位必备技能,大厂喜欢研究。今天主要介绍9种性能优化方法@mikechen1。之所以把代码放在第一位,是因为这个最容易被忽略。比如拿到一个性能优化需求之后,一定要调用缓存,异步等等。其实第一步应该是分析相关代码,找出对应的瓶颈,然后再考虑具体的优化策略。有些性能问题完全是由于代码编写不合理造成的。直接修改代码就可以解决问题,比如for循环太多,做了很多不必要的条件判断,同样的逻辑重复了很多次。这样的优化成本是最小的。二、数据库1、SQL优化这里以MySQL为例。最常见的方式是通过内置的慢查询日志或者开源的慢查询系统定位到具体有问题的SQL,然后使用explain、profile等工具逐步Tuning,最后测试上线达到效果.下面举几个优化的例子:1.查询优化优化查询,尽量避免全表扫描,首先考虑对where和orderby涉及的列建立索引。2、避免空判断,尽量避免在where子句中判断字段的空值,否则会导致引擎放弃使用索引,进行全表扫描,如:selectidfromtwherenumisnull3.尽量避免全表扫描避免在where子句中使用!=或<>操作符,否则引擎会放弃使用索引而进行全表扫描。尽量避免在where子句中使用或连接条件。如果一个字段有索引而另一个字段没有,则会导致引擎放弃使用索引而进行全表扫描。in和notin也要慎用,否则会导致全表扫描,如:selectidfromtwherenumin(1,2,3)对于连续值,可以用between代替in:selectidfromtwherenum1到34之间。大数据量查询对于大数据量的多表JOIN,必须先分页再JOIN,否则逻辑读会很高。5、合理使用索引索引不是越多越好。索引可以提高相应select的效率,但同时会降低insert和update的效率,因为insert或update的时候可能会重建索引,所以如何建立索引需要慎重考虑,具体情况具体分析案例基础。一张表中的索引最好不要超过6个。如果过多,则应考虑是否有必要在一些不常用的列上建立索引。6.使用更多的数字字段。尽量使用数字字段。如果只包含数字信息的字段尽量不要设计成字符类型,这样会降低查询和连接的性能,还会增加存储开销。这是因为引擎在处理查询和连接时,会把字符串中的每个字符一个一个地进行比较,但是对于数字类型,只需要一个比较就可以了。7.避免大量。尽量避免向客户端返回大量数据。如果数据量太大,就要考虑相应的要求是否合理。8、避免大事务尽量避免大事务操作,提高系统并发度。更全面深入的MySQL性能优化,请查看《MySQL慢查询优化、索引优化、以及表等优化总结》。2.连接池调优为了实现高效获取数据库连接,限制数据库连接的流量,我们的应用通常采用连接池方案,即每个应用节点管理一个连接池到每个数据库。随着业务访问或数据量的增长,原有的连接池参数可能不能很好地满足需求。这时候就需要结合当前连接池的使用原理、具体的连接池监控数据以及当前的业务量进行综合判断,通过反复调试得到最终的调优参数。3.这类架构层面的优化包括读写分离、多从库负载均衡、横纵分库分表等,一般需要较大的改动,但频率没有那么高SQL调优,一般需要DBA。合作和参与。详细的分库分表,读写分离,请参考《数据库分库分表、读写分离的原理实现,使用场景》3.分布式缓存缓存堪称性能优化的利器。缓存主要用于存储读写比高、很少变化的数据。什么情况适合缓存?考虑以下两种场景:同一数据在短时间内被多次重复查询,且数据更新不频繁。这时候可以选择先从缓存中查询,如果查询不到,再从数据库中加载,重新设置到缓存中。这种场景更适合单机缓存。对于热点数据的高并发查询,后端数据库不堪重负,可以使用缓存来承载。使用缓存需要注意的问题:1、避免缓存失效。将频繁修改的数据放入缓存中,很容易导致数据写入缓存后,应用程序还没来得及读取缓存,数据就失效了,会增加系统的负担。2、缓存热点数据缓存所使用的内存资源是非常宝贵的。只缓存最近访问的数据,历史数据应该从缓存中清除,即为20%的热点数据预留缓存资源。3.数据不一致一般都会给缓存设置一个过期时间。如果过期时间超过过期时间,则必须从数据库中重新加载。因此,应用程序必须忍受一定时间的数据不一致。另一种策略是当数据更新时立即更新缓存,但这也会带来更多的系统开销和事务一致性问题。4、当缓存可用性业务发展到一定阶段后,缓存将承担大部分的数据访问压力。数据库习惯了有缓存的日子,所以当缓存服务器崩溃时,数据库就会宕机,因为它根本承受不了这么大的压力,进而导致整个网站不可用。这种情况称为缓存雪崩。当出现这种故障时,甚至无法简单地重启缓存服务器和数据库服务器来恢复网站访问。解决方案:1)缓存热备(当某台服务器宕机时,将缓存访问切换到热备服务器上;2)缓存服务器集群。5.缓存预热热点数据存放在缓存中,热点数据由缓存系统通过LRU选择,持续访问数据。这个过程需要很长时间。新启动的缓存系统没有任何数据,此时系统性能和数据库负载都不是很好。因此,可以选择在启动缓存时预加载热点数据。6.缓存穿透由于业务不当或恶意攻击,持续高并发访问某个不存在的数据。如果缓存不保存数据,大量的请求压力就会落在数据库上。简单的解决办法就是把请求的不存在的数据放到缓存中,它的值为null。如果你还想全面了解缓存的5大问题,《如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题》有更深入全面的讲解。4、异步的对于一些客户端的请求,服务端可能需要为这些请求做一些辅助的事情。事实上,用户并不关心这些东西或者用户不需要立即得到这些东西的处理结果。这种情况比较适合用异步的方式来处理这些事情。异步的作用:缩短接口响应时间,使用户的请求能够快速返回,用户体验更好。避免长时间运行线程,导致服务线程池可用线程长期不足,导致线程池任务队列长度增加,从而阻塞更多的请求任务,使更多技术上无法处理请求。如果线程长时间运行,还可能导致系统负载、CPU占用率、机器整体性能下降等一系列问题,甚至引发雪崩。异步思想可以在不增加机器和CPU数量的情况下有效解决这个问题。例如:使用消息队列(MQ)中间件服务,MQ天生就是异步的。一些额外的任务可能不需要由我的系统处理,但需要由其他系统处理。这时候就可以打包成消息,扔进消息队列,通过消息中间件的可靠性传递给消息。关心它的系统,然后让系统做相应的处理。再比如C端完成一个提单动作后,其他端可能需要做一系列的事情,但是这些事情的结果不会立即影响到C端用户,所以C端的请求响应-结束订单可以先退货。对于用户来说,在返回之前发送消息给MQ就好了,这些事情不应该是C端的责任,所以这个时候,用MQ来解决这个问题是最合适的。5、Web前端Web前端是指网站业务逻辑之前的部分,包括:浏览器加载网站视图模型、图片服务、CDN服务等。主要的优化方式包括优化浏览器访问,使用反向代理、CDN等1.浏览器访问优化(1)减少http请求HTTP协议是一个无状态的应用层协议,意味着每个HTTP请求都需要一个resume通信链路进行数据传输,在server端,每个HTTP都需要启动独立的线程来处理,这些通信和服务的开销是非常昂贵的,减少HTTP请求的数量可以有效提高访问性能。减少HTTP请求的主要手段有:合并CSS,压缩CSS大小合并JavaScript,压缩JS大小合并图片将浏览器一次访问所需的JavaScript和CSS合并到一个文件中,让浏览器只需要一次请求。将多张图片合并为一张。如果每张图片都有不同的超链接,可以使用CSS偏移响应鼠标点击来构造不同的URL。(2)使用浏览器缓存对于一个网站来说,CSS、JavaScript、Logo、图标等静态资源文件的更新频率比较低,几乎每次HTTP请求都需要这些文件。如果将这些文件缓存在浏览器中,可以大大提高性能。通过在HTTP头中设置Cache-Control和Expires属性,可以设置浏览器缓存,缓存时间可以是几天甚至几个月。有时,静态资源文件的变化需要及时应用到客户端浏览器。这可以通过更改文件名来实现。例如,通常在JavaScript之后添加一个版本号,以使浏览器刷新修改后的文件。(3)启用压缩,在服务器端对文件进行压缩,在浏览器端对文件进行解压,可以有效减少通信传输的数据量。文本文件压缩效率达80%以上。(4)CSS放在页面顶部,JavaScript放在页面底部。浏览器将在下载所有CSS后呈现整个页面。因此,最好的办法就是将CSS放在页面的顶部,让浏览器尽快下载。CSS。JS认为浏览器加载JS后立即执行,可能会阻塞整个页面,导致页面显示缓慢,所以JS最好放在页面底部。(5)减少cookie传输一方面,每次请求和响应中都包含cookie。太大的cookies会严重影响数据传输。因此,哪些数据需要写入cookies需要慎重考虑,尽量减少cookies传输的数据量。另一方面,对于一些静态资源的访问,比如CSS、JS等,发送cookie是没有意义的。可以考虑使用独立域名访问静态资源,避免请求静态资源时发送cookie,减少cookie传输次数。2、CDN加速CDN(ContentDistributeNetwork,内存分发网络)本质上还是一个缓存,将数据缓存在离用户最近的地方,让用户以最快的速度获取数据,这就是所谓的网络访问的第一跳。CDN一般会缓存静态资源,比如图片、文件、CSS、脚本脚本、静态网页等,但是这些文件访问频率很高,将它们缓存在CDN中可以大大提高网页的打开速度。3.反向代理传统代理服务器位于浏览器端,代理浏览器向互联网发送HTTP请求,而反向代理服务器位于网站机房一侧,代理网站Web服务器接收HTTP要求。就像传统代理服务器可以保护浏览器安全一样,反向代理服务器也具有保护网站安全的功能。来自Internet的访问请求必须经过代理服务器,相当于在Web服务器和可能的网络攻击之间建立了一道屏障。除了安全功能,代理服务器还可以通过配置缓存功能来加速web请求。当用户第一次访问静态内容时,将静态内容缓存在反向代理服务器上,这样当其他用户访问静态内容时,可以直接从反向代理服务器返回,加快响应速度Web请求和减少服务器负载。6、服务化做服务化最基本的方式就是按照业务拆分服务,避免业务之间相互影响,同时拆分数据和服务。在同一个业务中,我们也按照计算密集/IO密集服务拆分、C端/B端服务拆分、核心/非核心服务拆分、高频业务单独部署的原则进行拆分。7、硬件升级硬件问题对性能的影响不容忽视。举个例子:DB集群经常出现慢SQL告警。经过业务排查,发现SQL很简单,该做的索引优化也做了。后来由于硬件陈旧,DBA同学帮忙定位问题,将机械硬盘升级为固态硬盘后,告警立即消失,效果立竿见影!8、搜索引擎复杂的查询和一些聚合计算不适合数据库,可以使用搜索引擎来实现。另外,搜索引擎还可以帮助我们解决跨数据库、跨数据源的检索场景。9、产品逻辑优化业务逻辑优化往往容易被忽视,但效果往往比数据库性能优化、JVM调优等更明显。举个例子,在12306春运抢火车票的场景中,由于人流量大,用户点击“查票”后系统会很卡,进度条很慢。作为用户,我们会习惯性地点击“查票”,可能会连续点击几次。假设一个用户平均点击5次,后台系统的负载就会增加5倍!并且80%??的请求是重复请求。这时候,我们可以通过产品逻辑进行优化。比如用户点击查询后,“按钮变灰”,或者通过JS控制xx秒只能提交一个请求等,有效拦截80%的无效流量。.以上作者简介陈睿|mikechen,10年+大工厂架构经验,《BAT架构技术500期》系列文章作者,分享十余年BAT架构经验和面试心得!更多技术文章看mikechen的互联网架构合集JavaConcurrency|JVM|MySQL|Spring|Redis|Distributed|HighConcurrency|架构师关注“mikechen的互联网架构”公众号,回复【架构】领取本人原创《300 期 + BAT 架构技术系列与 1000 + 大厂面试题答案》
