🌈🌈🌈🌈🌈🌈🌈🌈
欢迎关注公众号(通过文章导读关注:【11来了】),及时收到 AI 前沿项目工具及新技术的推送!在我后台回复 「资料」 可领取
编程高频电子书
!
在我后台回复「面试」可领取硬核面试笔记
!文章导读地址:点击查看文章导读!
感谢你的关注!
🍁🍁🍁🍁🍁🍁🍁🍁
性能优化面试实战
优化数据库连接池
高并发场景下的数据库连接池应该如何进行优化?
数据库连接池中存放的就是数据库的连接,要对连接池优化,可以从建立连接的超时时间、连接池中的连接数量限制来考虑
简单来说,就是如果建立连接或者发送请求失败,不要一直阻塞等待,设置超时时间,失败了就断开重连就好了!
- maxWait 设置
maxWait
参数表示从连接池中获取连接时的最大等待时间,单位是毫秒
推荐设置值为 1000,表示等待 1s 之后还没有获取链接,就算等待超时
如果 maxWait 设置为 -1,那么在高并发场景下,瞬间连接池中的连接都被占用了,大量的请求拿不到连接,无限等待,最终导致 Tomcat 服务器中的线程耗尽,无法对外继续提供服务
- connectionProperties 设置
可以放 connectionTimeout
和 socketTimeout
属性,表示 建立TCP连接的超时时间
和 发送请求后等待响应的超时时间
推荐设置值为:
- connectionTimeout = 1200
- socketTimeout = 3000
不设置这两个值的话,如果高并发场景下,万一碰到了网络问题,导致和数据库的 Socket 连接异常无法通信,那么服务端的 Socket 一直阻塞等待响应,其他请求就无法获取这个连接处理自己的任务
通过设置这两个值,保证在一定时间没有处理完,就算超时,断开连接重连
- maxActive 设置
最大连接池数量,一般建议是设置个20就够了
如果确实有高并发场景,可以适当增加到 3~5 倍,但是不要太多,其实一般这个数字在几十到 100 就很大了,因为这仅仅是你一个服务连接数据库的数量,还有其他的服务,而且数据库整体能承受的连接数量是有限的
连接越多不是越好,数据库连接太多了,会导致 CPU 负载很高,可能反而会导致性能降低的,所以这个参数你一般设置个 20,最多再加几十个就差不多了
优化系统 TPS
如果压测的时候发现系统的 TPS 不达标,此时应该如何优化系统?
这里说一下优化系统的思路,首先,TPS 不达标,一定要去检查 SQL,比如存不存在比较慢的 SQL,比如一个 SQL 执行 500ms 或者 1s,那你线程再多,也处理不了多少的请求,所以要先检查慢 SQL,第一步:对数据库建立索引进行优化
接下来检查有没有耗时较长的接口,比如一个接口耗时 500ms 甚至 1s,不过接口耗时太长一般都是 SQL 太慢,如果 SQL 优化过之后,接口耗时还是很长,第二步:可以考虑异步化或多线程进行优化
还可以对 Tomcat 进行优化,通过修改 Tomcat 的参数,Tomcat 默认最大线程数是 200 个,那么可以扩大至 500 个或者 800 个,并且加大 Tomcat 中等待队列的长度以及连接建立数量的限制,主要是 3 个参数:maxThreads、acceptCount、maxConnections,第三步:对 Tomcat 进行优化
代码方面优化做完了,接下来就可以对机器方面进行优化,比如一台服务单机抗 800 个请求,你需要抗 3000 个请求,那么就再扩充 3 台机器,总共 4 台机器,每秒就可以抗 3200 个请求,第四步:扩充机器
Tomcat 调优
为什么对 SpringBoot 嵌入式的 Web 服务器 Tomcat 进行调优?
-
Tomcat三大配置maxThreads、acceptCount、maxConnections
-
最大线程数maxThreads
决定了Web服务器最大同时可以处理多少个请求任务数量
线程池最大线程数,默认值200
-
最大等待数accept-count
是指队列能够接受的最大等待数,如果等待队列超了请求会被拒绝
默认值100
-
最大连接数MaxConnections
是指在同一时间,Tomcat能够接受的最大连接数,如果设置为-1,则不限制连接数
最大连接数和最大等待数关系:当连接数达到最大连接数后还会继续接请求,但不能超过最大等待数,否则拒绝连接
-
最大线程数的值应该设置多少合适呢?
- 需要基于业务系统的监控结果来定:RT(响应时间)均值很低不用设置,RT均值很高考虑加线程数
- 接口响应时间低于100毫秒,足以产生足够的TPS
- 如果没有证据表明系统瓶颈是线程数,则不建议设置最大线程数
- 个人经验值:1C2G线程数200,4C8G线程数800
调优结论:在高负载场景下,TPS提升近1倍,RT大幅降低,异常占比降低
注意:配置修改需确认配置生效,否则再苦再累也白搭!
Tomcat 调优配置
- 修改配置
在 SpringBoot 项目中的 yml 文件中,对嵌入的 Tomcat 进行如下配置:
# Tomcat的maxConnections、maxThreads、acceptCount三大配置,分别表示最大连接数,最大线程数、最大的等待数,可以通过application.yml配置文件来改变这个三个值,一个标准的示例如下:
server.tomcat.uri-encoding: UTF-8
# 思考问题:一台服务器配置多少线程合适?
server.tomcat.accept-count: 1000 # 等待队列最多允许1000个请求在队列中等待
server.tomcat.max-connections: 20000 # 最大允许20000个链接被建立
## 最大工作线程数,默认200, 4核8g内存,线程数经验值800
server.tomcat.threads.max: 800 # 并发处理创建的最大的线程数量
server.tomcat.threads.min-spare: 100 # 最大空闲连接数,防止突发流量
修改之后,我们使用 SpringBoot Actuator 来管理和监听应用程序
- 集成 Actuator
官方文档:https://docs.spring.io/spring-boot/docs/current/reference/html/actuator.html#actuator.enabling
- 引入依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
- 配置文件暴露监控点
# 暴露所有的监控点
management.endpoints.web.exposure.include: '*'
# 定义Actuator访问路径
management.endpoints.web.base-path: /actuator
# 开启endpoint 关闭服务功能
management.endpoint.shutdown.enabled: true
# 暴露的数据中添加application label
management.metrics.tags.application: hero_mall
访问 http://localhost:8081/actuator 可以查看所有配置
找到configprops,访问链接,搜索tomcat查看是否配置成功
Web 容器优化
将Tomcat容器升级为Undertow
Undertow是一个用Java编写的灵活的高性能Web服务器,提供基于NIO的阻塞和非阻塞API。
- 支持Http协议
- 支持Http2协议
- 支持Web Socket
- 最高支持到Servlet4.0
- 支持嵌入式
SpringBoot的web环境中默认使用Tomcat作为内置服务器,其实SpringBoot提供了另外2种内置的服务器供我们选择,我们可以很方便的进行切换。
- Undertow红帽公司开发的一款基于 NIO 的高性能 Web 嵌入式服务器 。轻量级Servlet服务器,比Tomcat更轻量级没有可视化操作界面,没有其他的类似jsp的功能,只专注于服务器部署,因此undertow服务器性能略好于Tomcat服务器;
- Jetty开源的Servlet容器,它是Java的web容器。为JSP和servlet提供运行环境。Jetty也是使用Java语言编写的。
配置Undertow
- 在spring-boot-starter-web排除tomcat
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
- 导入其他容器的starter
<!--导入undertow容器依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
- 配置
# 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接
server.undertow.threads.io: 800
# 阻塞任务线程池, 当执行类似servlet请求阻塞IO操作, undertow会从这个线程池中取得线
程
# 默认值是IO线程数*8
server.undertow.threads.worker: 8000
# 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内
存管理
# 每块buffer的空间大小越小,空间就被利用的越充分,不要设置太大,以免影响其他应用,合
适即可
server.undertow.buffer-size: 1024
# 每个区分配的buffer数量 , 所以pool的大小是buffer-size * buffers-per-region
# 是否分配的直接内存(NIO直接分配的堆外内存)
server.undertow.direct-buffers: true
小结:
- 更换了服务容器之后,RT更加平稳,TPS的增长趋势更平稳,异常数(超时3s)几乎为0。
- 在低延时情况下,接口通吐量不及Tomcat。
- 稳定压倒一切,如果只是写json接口,且对接口响应稳定性要求高,可以选用Undertow