乐趣区

关于java:9大性能优化经验总结强烈建议收藏

性能优化属于 Java 高级岗的必备技能,而且大厂特地喜爱考查,明天次要给大家介绍 9 种性能优化的办法 @mikechen

1. 代码

之所以把代码放到第一位,是因为这一点最容易引漠视,比方拿到一个性能优化的需要当前,言必称缓存、异步等。

实际上,第一步就应该是剖析相干的代码,找出相应的瓶颈,再来思考具体的优化策略。

有一些性能问题,齐全是因为代码写的不合理,通过间接批改一下代码就能解决问题的,比方 for 循环次数过多、作了很多无谓的条件判断、雷同逻辑反复屡次等,这样的优化老本是最低的。

 

2. 数据库

1.SQL 优化

这里以 MySQL 为例,最常见的形式是,由自带的慢查问日志或者开源的慢查问零碎定位到具体的出问题的 SQL,而后应用 explain、profile 等工具来逐渐调优,最初通过测试达到成果后上线。

这里举几个优化的例子:

1. 查问优化

对查问进行优化,要尽量避免全表扫描,首先应思考在 where 及 order by 波及的列上建设索引。

2. 防止 null 判断

应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃应用索引而进行全表扫描,如:

select id from t where num is null

3. 防止全表扫描

应尽量避免在 where 子句中应用 != 或 <> 操作符,否则将引擎放弃应用索引而进行全表扫描。

应尽量避免在 where 子句中应用 or 来连贯条件,如果一个字段有索引,一个字段没有索引,将导致引擎放弃应用索引而进行全表扫描。

in 和 not in 也要慎用,否则会导致全表扫描,如:

select id from t where num in(1,2,3)

对于间断的数值,能用 between 就不要用 in 了:

select id from t where num between 1 and 3

4. 大数据量查问

对于多张大数据量的表 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. 缓存穿透

因为不失当的业务或歹意攻打,继续高并发地拜访某一个不存在的数据,如果缓存不保留该数据,就会有大量的申请压力落在数据库上。

简略的解决形式是把申请的不存在的数据也放进缓存,其 value 是 null。

如果还想全面理解缓存的 5 大难题,《如何解决 Redis 缓存雪崩、缓存穿透、缓存并发等 5 大难题》有更加深刻全面的解说。

 

4. 异步化

针对某些客户端的申请,在服务端可能须要针对这些申请做一些从属的事件,这些事件其实用户并不关怀或者用户不须要立刻拿到这些事件的处理结果,这种状况就比拟适宜用异步的形式解决这些事件。

异步化的作用:

  •  缩短接口响应工夫,使用户的申请疾速返回,用户体验更好。
  •  防止线程长时间处于运行状态,这样会引起服务线程池的可用线程长时间不够用,进而引起线程池工作队列长度增大,从而阻塞更多申请工作,使得更多申请得不到技术解决。
  •  线程长时间处于运行状态,可能还会引起零碎 Load、CPU 使用率、机器整体性能降落等一系列问题,甚至引发雪崩。异步的思路能够在不减少机器数和 CPU 数的状况下,无效解决这个问题。

比方:应用音讯队列(MQ)中间件服务,MQ 天生就是异步的。

一些额定的工作,可能不须要我这个零碎来解决,然而须要其余零碎来解决,这个时候能够先把它封装成一个音讯,扔到音讯队列外面,通过消息中间件的可靠性保障把音讯投递到关怀它的零碎,而后让这个零碎来做相应的解决。

再比方 C 端在实现一个提单动作当前,可能须要其它端做一系列的事件,然而这些事件的后果不会立即对 C 端用户产生影响,那么就能够先把 C 端下单的申请响应先返回给用户,返回之返回 MQ 中发一个音讯即可,而且这些事件理当不是 C 端的负责范畴,所以这个时候用 MQ 的形式,来解决这个问题最合适。

 

5.Web 前段

Web 前端指网站业务逻辑之前的局部,包含:

  • 浏览器加载
  • 网站视图模型
  • 图片服务
  • CDN 服务等

次要优化伎俩有优化浏览器拜访,应用反向代理,CDN 等。

1. 浏览器拜访优化

(1) 缩小 http 申请

HTTP 协定是无状态的应用层协定,意味着每次 HTTP 申请都须要简历通信链路,进行数据传输,而在服务器端,每个 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 蕴含在每次申请和响应中,太大的 Cookie 会重大影响数据传输,因而哪些数据须要写入 Cookie 须要慎重考虑,尽量减少 Cookie 中传输的数据量。另一方面,对于某些动态资源的拜访,如 CSS,JS 等,发送 Cookie 没有意义,能够思考动态资源应用独立域名拜访,防止申请动态资源时发送 Cookie,缩小 Cookie 传输的次数。

2.CDN 减速

CDN(Content Distribute Network, 内存散发网络) 的实质上依然是一个缓存,而且将数据缓存在离用户最近的中央,是用户以最快速度获取数据,即所谓网络拜访第一跳。

CDN 个别缓存的是动态资源,如图片,文件,CSS,Script 脚本,动态网页等,然而这些文件拜访频率很高,将其缓存在 CDN 可极大改善网页的关上速度。

3. 反向代理

传统代理服务器位于浏览器一侧,代理浏览器将 HTTP 申请发送到互联网上,而反向代理服务器位于网站机房一侧,代理网站 Web 服务器接管 HTTP 申请。

和传统代理服务器能够爱护浏览器平安一样,反向代理服务器也具备爱护网站平安的作用,来自互联网的拜访申请必须通过代理服务器,相当于在 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 的互联网架构更多技术文章合集

Java 并发 |JVM|MySQL|Spring|Redis| 分布式 | 高并发 | 架构师

关注「mikechen 的互联网架构」公众号,回复 【架构】 支付我原创的《300 期 + BAT 架构技术系列与 1000 + 大厂面试题答案》

退出移动版