【面试突击】性能优化面试实战

发布时间:2024年01月23日

🌈🌈🌈🌈🌈🌈🌈🌈
欢迎关注公众号(通过文章导读关注:【11来了】),及时收到 AI 前沿项目工具及新技术的推送!

在我后台回复 「资料」 可领取编程高频电子书
在我后台回复「面试」可领取硬核面试笔记

文章导读地址:点击查看文章导读!

感谢你的关注!

🍁🍁🍁🍁🍁🍁🍁🍁

性能优化面试实战

优化数据库连接池

高并发场景下的数据库连接池应该如何进行优化?

数据库连接池中存放的就是数据库的连接,要对连接池优化,可以从建立连接的超时时间、连接池中的连接数量限制来考虑

简单来说,就是如果建立连接或者发送请求失败,不要一直阻塞等待,设置超时时间,失败了就断开重连就好了!

  1. maxWait 设置

maxWait参数表示从连接池中获取连接时的最大等待时间,单位是毫秒

推荐设置值为 1000,表示等待 1s 之后还没有获取链接,就算等待超时

如果 maxWait 设置为 -1,那么在高并发场景下,瞬间连接池中的连接都被占用了,大量的请求拿不到连接,无限等待,最终导致 Tomcat 服务器中的线程耗尽,无法对外继续提供服务

  1. connectionProperties 设置

可以放 connectionTimeoutsocketTimeout 属性,表示 建立TCP连接的超时时间发送请求后等待响应的超时时间

推荐设置值为:

  • connectionTimeout = 1200
  • socketTimeout = 3000

不设置这两个值的话,如果高并发场景下,万一碰到了网络问题,导致和数据库的 Socket 连接异常无法通信,那么服务端的 Socket 一直阻塞等待响应,其他请求就无法获取这个连接处理自己的任务

通过设置这两个值,保证在一定时间没有处理完,就算超时,断开连接重连

  1. 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

    1. 最大线程数maxThreads

      决定了Web服务器最大同时可以处理多少个请求任务数量

      线程池最大线程数,默认值200

    2. 最大等待数accept-count

      是指队列能够接受的最大等待数,如果等待队列超了请求会被拒绝

      默认值100

    3. 最大连接数MaxConnections

      是指在同一时间,Tomcat能够接受的最大连接数,如果设置为-1,则不限制连接数

      最大连接数和最大等待数关系:当连接数达到最大连接数后还会继续接请求,但不能超过最大等待数,否则拒绝连接

最大线程数的值应该设置多少合适呢?

  • 需要基于业务系统的监控结果来定:RT(响应时间)均值很低不用设置,RT均值很高考虑加线程数
  • 接口响应时间低于100毫秒,足以产生足够的TPS
  • 如果没有证据表明系统瓶颈是线程数,则不建议设置最大线程数
  • 个人经验值:1C2G线程数200,4C8G线程数800

调优结论:在高负载场景下,TPS提升近1倍,RT大幅降低,异常占比降低

注意:配置修改需确认配置生效,否则再苦再累也白搭!

Tomcat 调优配置

  1. 修改配置

在 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 来管理和监听应用程序

  1. 集成 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

  1. 在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>
  1. 导入其他容器的starter
<!--导入undertow容器依赖-->
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
  1. 配置
# 设置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
文章来源:https://blog.csdn.net/qq_45260619/article/details/135766496
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。