想成为一名顶尖Java开发工程师?这些优化手段一定要掌握!(一)

本文涉及的产品
容器服务 Serverless 版 ACK Serverless,317元额度 多规格
容器服务 Serverless 版 ACK Serverless,952元额度 多规格
简介: 想成为一名顶尖Java开发工程师?这些优化手段一定要掌握!

🌟 服务器配置

🍊 文件系统参数、TCP网络层参数等系统参数

CentOS 7上,可以使用以下命令来配置参数:

  1. 打开配置文件/etc/sysctl.conf:
sudo vi /etc/sysctl.conf
• 1
  1. 添加或编辑以下参数:
# 设置虚拟内存超配值为 1,可以允许分配比实际物理内存更多的内存空间,从而提高应用程序性能,但可能导致 OOM 错误。为 0 时表示内存空间不足时直接拒绝申请
vm.overcommit_memory = 1
# 设置系统脏页(未写入磁盘的页面)达到多少字节时可以开始写入磁盘
vm.dirty_background_bytes = 8388608 
# 设置系统脏页达到多少字节时必须写入磁盘
vm.dirty_bytes = 25165824
# 设置可以在后台写入磁盘的脏页占总脏页的比例(即总脏页数的2%)
vm.dirty_background_ratio = 2
# 设置当系统脏页占总内存的比例超过5%时,系统必须开始写入磁盘
vm.dirty_ratio = 5
# 设置系统判定一个脏页需要写入磁盘的时间,单位为centisecond,即2000分之一秒
vm.dirty_expire_centisecs = 2000
# 设置最小内存分配单位(单位为KB)
vm.min_free_kbytes = 8192 
# 将虚拟内存的 overcommit 比率设置为80%
vm.overcommit_ratio = 80
# 设置堆内存溢出处理方式(0表示不紧急内存压缩,1表示紧急内存压缩,2表示杀死进程)
vm.panic_on_oom = 2
# 设置发送方socket buffer大小的最大值为16MB
net.core.wmem_max = 16777216 
# 设置接收方socket buffer大小的最大值为16MB
net.core.rmem_max = 16777216 
# 当TCP流量控制窗口溢出时,中止连接
net.ipv4.tcp_abort_on_overflow = 1
# 对于高延迟、高带宽的网络,开启窗口缩放
net.ipv4.tcp_adv_win_scale = 1
# 允许使用的TCP拥塞控制算法,可以使用cubic和reno算法
net.ipv4.tcp_allowed_congestion_control = cubic reno
# 应用程序socket buffer的大小,单位为Kbyte
net.ipv4.tcp_app_win = 31
# TCP发送数据时,自动开启corking模式
net.ipv4.tcp_autocorking = 1
# 允许使用的TCP拥塞控制算法,可以使用cubic和reno算法
net.ipv4.tcp_available_congestion_control = cubic reno
# 设置TCP数据包的最小大小,单位为byte
net.ipv4.tcp_base_mss = 512
# 发送方最多允许发送多少个SYN报文段作为challenge ack防范syn flood攻击
net.ipv4.tcp_challenge_ack_limit = 1000
# TCP使用的拥塞控制算法,可以使用cubic算法
net.ipv4.tcp_congestion_control = cubic 
# 开启对方乱序数据的确认,以降低网络延迟
net.ipv4.tcp_dsack = 1
# 当检测到丢包时,提前触发重传
net.ipv4.tcp_early_retrans = 3
# 开启ECN(Explicit Congestion Notification)拥塞控制算法
net.ipv4.tcp_ecn = 2
# 使用FACK(Forward Acknowledgment)作为拥塞控制算法的一部分
net.ipv4.tcp_fack = 1
# 开启TCP Fast Open,以加快连接速度
net.ipv4.tcp_fastopen = 3
# 设置TCP Fast Open使用的密钥,可以使用随机数生成器生成
net.ipv4.tcp_fastopen_key = 6d0c41a3-123fdf85-a7f901e8-59fea180
# TCP连接关闭的超时时间,单位为秒
net.ipv4.tcp_fin_timeout = 10
# 开启TCP Fast Recovery防止网络拥塞
net.ipv4.tcp_frto = 2
# 设置TCP连接每秒允许的最大无效数据包数,超过该值则降低发送速度
net.ipv4.tcp_invalid_ratelimit = 500
# TCP保持连接的时间间隔,单位为秒
net.ipv4.tcp_keepalive_intvl = 15
# 发送TCP保持连接探测报文的次数
net.ipv4.tcp_keepalive_probes = 3
# TCP保持连接的时间,单位为秒
net.ipv4.tcp_keepalive_time = 600
# 限制发送缓存的最大空间,单位为byte
net.ipv4.tcp_limit_output_bytes = 262144
# 开启TCP低延迟模式
net.ipv4.tcp_low_latency = 0
# 操作系统允许的最大TCP半连接数
net.ipv4.tcp_max_orphans = 16384
# TCP拥塞窗口增长算法的阈值,一般设为0不使用该功能
net.ipv4.tcp_max_ssthresh = 0
# 等待建立连接请求的最大个数
net.ipv4.tcp_max_syn_backlog = 262144
# 每秒最多处理的TCP连接数,越高则占用CPU时间越多
net.ipv4.tcp_max_tw_buckets = 5000
# 设置TCP Mem,包括min、default、max三个参数,单位为page数量
net.ipv4.tcp_mem = 88053  117407  176106
# 设置发送方socket buffer大小的最小值,单位为byte
net.ipv4.tcp_min_snd_mss = 48
# 设置TCP使用的最小TSO分段数目(只有在开启TSO时生效)
net.ipv4.tcp_min_tso_segs = 2
# 开启TCP自适应窗口大小控制
net.ipv4.tcp_moderate_rcvbuf = 1
# 开启TCP MTU探测,以避免网络分片
net.ipv4.tcp_mtu_probing = 1
# 禁止保存TCP延迟测量得到的数据
net.ipv4.tcp_no_metrics_save = 1
# 无需等待发送缓存为空,就可以发送数据
net.ipv4.tcp_notsent_lowat = -1
# TCP重传数据包的最大次数
net.ipv4.tcp_orphan_retries = 0
# TCP重传数据包后允许接收的最大乱序数据包个数
net.ipv4.tcp_reordering = 3
# 启用TCP Fast Retransmit和Fast Recovery算法
net.ipv4.tcp_retrans_collapse = 1
# 第一次重传TCP数据包的次数
net.ipv4.tcp_retries1 = 3
# 第二次重传TCP数据包的次数
net.ipv4.tcp_retries2 = 15
# 拒绝与RFC1337不兼容的数据包
net.ipv4.tcp_rfc1337 = 1
# 设置TCP接收缓存大小,包括min、default、max三个参数,单位为byte
net.ipv4.tcp_rmem = 4096  87380 33554432
# 开启TCP SACK(Selective Acknowledgments)支持
net.ipv4.tcp_sack = 1
# 关闭TCP连接空闲一段时间后再次发送数据包
net.ipv4.tcp_slow_start_after_idle = 0
# 禁用TCP Socket Urgent功能
net.ipv4.tcp_stdurg = 0
# TCP SYN请求重试的最大次数
net.ipv4.tcp_syn_retries = 1
# TCP SYN/ACK请求重试的最大次数
net.ipv4.tcp_synack_retries = 1
# 开启TCP SYN Cookie防止syn flood攻击
net.ipv4.tcp_syncookies = 1
# 关闭TCP Thin Dupack
net.ipv4.tcp_thin_dupack = 0
# 关闭TCP Thin Linear Timeouts
net.ipv4.tcp_thin_linear_timeouts = 0
# 开启TCP时间戳
net.ipv4.tcp_timestamps = 1
# 设置TCP TSO窗口大小的除数,只有在开启TSO时生效
net.ipv4.tcp_tso_win_divisor = 3
# 开启TCP TIME_WAIT Socket重用机制
net.ipv4.tcp_tw_recycle = 1
# 允许将TIME_WAIT Socket重用于新的TCP连接
net.ipv4.tcp_tw_reuse = 1
# 开启TCP窗口缩放
net.ipv4.tcp_window_scaling = 1
# 设置发送方socket buffer大小,包括min、default、max三个参数,单位为byte
net.ipv4.tcp_wmem = 4096  16384 33554432
# 关闭TCP workaround signed windows(https://tools.ietf.org/html/rfc7323)
net.ipv4.tcp_workaround_signed_windows = 0
# 当使用conntrack跟踪TCP连接时,设置是否采用liberal模式
net.netfilter.nf_conntrack_tcp_be_liberal = 0
# 当使用conntrack跟踪TCP连接时,设置是否采用loose模式
net.netfilter.nf_conntrack_tcp_loose = 1
# TCP连接最大重传次数
net.netfilter.nf_conntrack_tcp_max_retrans = 3
# TCP连接关闭后,等待fin结束的时间,单位为秒
net.netfilter.nf_conntrack_tcp_timeout_close = 10
# TCP连接关闭后,进入CLOSE_WAIT状态的时间,单位为秒
net.netfilter.nf_conntrack_tcp_timeout_close_wait = 60
# TCP连接已经建立时,如果长期没有数据传输,连接最长保持时间,单位为秒
net.netfilter.nf_conntrack_tcp_timeout_established = 432000
# 当关闭TCP连接时,TCP_FIN等待ACK的超时时间,单位为秒
net.netfilter.nf_conntrack_tcp_timeout_fin_wait = 120
# 当关闭TCP连接时,ACK等待FIN的超时时间,单位为秒
net.netfilter.nf_conntrack_tcp_timeout_last_ack = 30
# TCP连接最大重传次数,以及TCP RTO
net.netfilter.nf_conntrack_tcp_timeout_max_retrans = 300
# 设置 TCP SYN_RECV 状态的超时时间为 60 秒
net.netfilter.nf_conntrack_tcp_timeout_syn_recv = 60
# 设置 TCP SYN_SENT 状态的超时时间为 120 秒
net.netfilter.nf_conntrack_tcp_timeout_syn_sent = 120
# 设置 TCP TIME_WAIT 状态的超时时间为 120 秒
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 120
# 设置 TCP 未确认连接的超时时间为 300 秒
net.netfilter.nf_conntrack_tcp_timeout_unacknowledged = 300
# 设置 sunrpc 协议的 FIN 超时时间为 15 秒
sunrpc.tcp_fin_timeout = 15
# 设置 sunrpc 协议的最大槽位表项数为 65536
sunrpc.tcp_max_slot_table_entries = 65536
# 设置 sunrpc 协议的槽位表项数为 2
sunrpc.tcp_slot_table_entries = 2
# 设置 sunrpc 协议的传输层为 TCP,缓存区大小为 1048576 字节
sunrpc.transports = tcp 1048576
# 设置系统最大连接数为 65535
net.core.somaxconn = 65535
# 设置网络设备缓存队列最大值为 65535
net.core.netdev_max_backlog = 65535
# 设置系统的最大文件句柄数为 65535
fs.file-max = 65535
# 增加文件描述符限制
fs.nr_open = 1000000
# 设置同时为当前用户打开的 inotify 实例的最大数目为 1024
fs.inotify.max_user_instances = 1024 
# 设置当前用户为每个 inotify 实例可同时监视的文件和目录数目上限为 65536
fs.inotify.max_user_watches = 65536 
# 设置 inotify 实例中等待处理的事件队列的最大(未处理)长度为 16384
fs.inotify.max_queued_events = 16384
# 调整文件系统缓存参数
vfs_cache_pressure = 50
# 设置进程ID的最大值为131072
kernel.pid_max = 131072 
# 设置系统支持的最大进程ID值为131072
kernel.max_pid = 131072
# 设置系统的信号量的参数,分别是512个信号量集、每个信号量集的最大值为65535、每个进程最多可以持有的信号量数量为1024、最大的信号量值为2048
kernel.sem = 512 65535 1024 2048
  1. 保存文件并退出。
  2. 使用以下命令使新配置生效:
sudo sysctl -p
  1. 使用命令行工具查看TCP网络参数的值,例如使用命令:
sysctl -a | grep tcp

可以查看到当前TCP网络参数的值,确认修改是否生效。

🍊 修改文件描述符大小

  1. 打开命令行终端,输入以下命令:
sudo vi /etc/security/limits.conf
  1. 在打开的配置文件中添加以下代码:
*    soft    nofile    65535
*    hard    nofile    65535
  1. 保存文件并关闭。
  2. 输入以下命令,使配置修改生效:
ulimit -n 65535

注意:此配置只对当前用户有效,如果要对所有用户生效,需要重启系统。

以上配置仅供参考,具体的参数设置应根据实际情况进行调整。在更改任何系统参数之前,请确保了解所需的配置和可能的影响。

🌟 SpringBoot的配置

Tomcat是Spring Boot默认的Web容器,它的配置也需要进行优化,以提高性能。

🍊 1. 配置HTTP协议下的数据压缩

Spring Boot使用内嵌的Tomcat作为其默认的Web容器,支持HTTP协议下的数据压缩。

要启用数据压缩,需要在application.properties文件中添加以下配置:

server.compression.enabled=true
server.compression.mime-types=application/json,application/xml,text/html,text/xml,text/plain
server.compression.min-response-size=2048

解释一下每一个配置项的含义:

  • server.compression.enabled:启用数据压缩,默认为false。
  • server.compression.mime-types:需要压缩的数据类型列表,支持多个值,用逗号分隔。
  • server.compression.min-response-size:响应数据的最小大小(字节),只有响应数据大小超过该值才会进行压缩。

配置完成后,当客户端请求的Accept-Encoding头中包含“gzip”或“deflate”时,Tomcat会自动压缩响应数据并返回。

需要注意的是,如果使用了反向代理服务器(如Nginx),则需要确保代理服务器不会重复压缩响应数据,否则可能会导致网页无法正确加载。可以通过设置代理服务器的“proxy_set_header Accept-Encoding ”和“proxy_set_header TE ”选项来解决该问题。

🍊 2. 配置静态资源缓存

Spring Boot的默认配置会自动将静态资源缓存一段时间,并指定缓存路径。默认情况下,静态资源的缓存时间是1小时(3600秒),缓存路径为“/static/”和“/public/” 。

如果需要自定义静态资源的缓存配置,可以在application.properties中添加如下配置:

# 配置静态资源缓存时间为10分钟
spring.resources.cache.cachecontrol.max-age=600 
# 配置缓存路径
spring.resources.static-locations=classpath:/static/,classpath:/public/

在上述配置中,通过spring.resources.cache.cachecontrol.max-age可以配置缓存时间,单位为秒;通过spring.resources.static-locations可以配置缓存路径。在配置路径时,需要指定静态资源存放的位置,多个位置可以使用逗号分隔。

需要注意的是,如果静态资源名带有版本号或者时间戳等动态变化的参数,那么缓存路径需要指定到该参数前面的部分,否则可能会导致缓存无效。

🍊 3.Tomcat线程池配置

在高并发场景下,线程池的配置也是非常重要的,可以大大提高系统的并发处理能力。

Spring Boot默认使用Tomcat线程池,它提供了以下参数可以进行调整:

(1)最大工作线程数(maxThreads):表示Tomcat可以处理的并发请求数量,超过最大线程数的请求将会被拒绝。可以根据预期并发请求量进行调整,建议设置为CPU核心数量的2~4倍。

(2)最小工作线程数(minSpareThreads):表示Tomcat最少保持的空闲工作线程。可以根据预期并发请求量进行调整,建议设置为CPU核心数量。

(3)最大连接数(maxConnections):表示Tomcat可以处理的最大请求数量,超过最大连接数的请求将会被放入等待队列。可以根据预期并发请求量进行调整,建议设置为maxThreads的2~4倍。

(4)等待队列长度(acceptCount):表示Tomcat等待队列的长度,超过等待队列长度的请求将会被拒绝。可以根据预期并发请求量进行调整,建议设置为maxConnections的2~4倍。

假设某场景2万用户30秒内处理每个用户5次请求,那么QPS为20000*5/30=3333.3,那么对应的配置如下:

# 🌟 server配置
server:
  compression:
    # 启用数据压缩,默认为false。配置完成后,当客户端请求的Accept-Encoding头中包含“gzip”或“deflate”时,Tomcat会自动压缩响应数据并返回。
    enabled: true
    # 需要压缩的数据类型列表,支持多个值,用逗号分隔。
    mime-types: application/json,application/xml,text/html,text/xml,text/plain
    # 响应数据的最小大小(字节),只有响应数据大小超过该值才会进行压缩。
    min-response-size: 2048
  # 服务端口
  port: 8097
  tomcat:
    # 1核2g内存为200,线程数经验值200左右;4核8g内存,线程数经验值800左右,16核32G内存,线程数经验值3200左右,以此类推,对应的服务器配置也需要跟着调整。这里有二种方式:第一种直接上对应的高配服务器,第二种搭建集群,通过弹性伸缩(需要配置报警任务触发扩容)+负载均衡(需要监听服务端口)+云服务器。
    threads:
      # 最多的工作线程数,默认大小是200。该参数相当于临时工,如果并发请求的数量在10到200之间,就会使用这些临时工线程进行处理。建议设置为 2 倍到 4 倍的 QPS
      max: 6667
      # 最少的工作线程数,默认大小是10。该参数相当于长期工,如果并发请求的数量达不到10,就会依次使用这几个线程去处理请求。如果min-spare设置得太低,那么当应用程序接收到高并发请求时,线程池将无法满足服务要求而导致请求失败。较高的min-spare值可能会导致系统响应时间变慢,因为它会创建大量线程来处理请求,这可能会占用过多的CPU和内存资源。如果将min-spare值设置得太低,则线程池可能无法及时响应请求。当系统负载较高时,有些请求可能会被暂时挂起,等待线程变得可用。如果没有足够的空闲线程,则请求将会等待更长时间。设置较高的min-spare值会占用更多的内存资源。如果线程池中的线程数超出了系统的实际需求,则会浪费内存资源。因此,将min-spare值设置为10至20是一种平衡内存和线程利用率的方式。
      min-spare: 20
      # 最大连接数,默认大小是8192。表示Tomcat可以处理的最大请求数量,超过8192的请求就会被放入到等待队列。如果设置为-1,则禁用maxconnections功能,表示不限制tomcat容器的连接数。建议设置为 2 倍到 4 倍的 QPS。如果设置的值太低,将会限制服务器处理客户端请求的能力,从而可能导致应用程序出现性能问题。如果设置的值太高,则会浪费服务器资源,因为服务器的处理能力可能不足以处理所有的连接。通过经验和测试,2到4倍的QPS值通常会在服务器处理客户端请求时提供最佳性能和稳定性。这个范围也会提供一定的缓冲以应对突发流量,从而在服务器资源短缺时避免过载。
    max-connections: 6667
    # 等待队列的长度,默认大小是100。建议设置为 2 至 5 倍的 max-connections。将accept-count设置为2至5倍的max-connections可以确保Tomcat能够处理足够的连接请求,同时避免因过多排队连接导致的性能问题。但是,设置过高的accept-count会增加系统负担和内存压力,同时也可能会引起其他问题,如拒绝服务攻击等。至于为什么建议不超过5倍,是因为实际上超过这个范围的设置已经很少能带来明显的性能提升,反而会增加系统负担。同时,设置过高的accept-count还可能会导致频繁的连接请求失败和性能下降,甚至可能会导致Tomcat崩溃。
    accept-count: 13334


相关实践学习
通过Ingress进行灰度发布
本场景您将运行一个简单的应用,部署一个新的应用用于新的发布,并通过Ingress能力实现灰度发布。
容器应用与集群管理
欢迎来到《容器应用与集群管理》课程,本课程是“云原生容器Clouder认证“系列中的第二阶段。课程将向您介绍与容器集群相关的概念和技术,这些概念和技术可以帮助您了解阿里云容器服务ACK/ACK Serverless的使用。同时,本课程也会向您介绍可以采取的工具、方法和可操作步骤,以帮助您了解如何基于容器服务ACK Serverless构建和管理企业级应用。 学习完本课程后,您将能够: 掌握容器集群、容器编排的基本概念 掌握Kubernetes的基础概念及核心思想 掌握阿里云容器服务ACK/ACK Serverless概念及使用方法 基于容器服务ACK Serverless搭建和管理企业级网站应用
相关文章
|
6天前
|
Java API Maven
如何使用Java开发抖音API接口?
在数字化时代,社交媒体平台如抖音成为生活的重要部分。本文详细介绍了如何用Java开发抖音API接口,从创建开发者账号、申请API权限、准备开发环境,到编写代码、测试运行及注意事项,全面覆盖了整个开发流程。
46 10
|
12天前
|
缓存 算法 Java
本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制
在现代软件开发中,性能优化至关重要。本文聚焦于Java内存管理与调优,介绍Java内存模型、内存泄漏检测与预防、高效字符串拼接、数据结构优化及垃圾回收机制。通过调整垃圾回收器参数、优化堆大小与布局、使用对象池和缓存技术,开发者可显著提升应用性能和稳定性。
35 6
|
13天前
|
SQL 安全 Java
安全问题已经成为软件开发中不可忽视的重要议题。对于使用Java语言开发的应用程序来说,安全性更是至关重要
在当今网络环境下,Java应用的安全性至关重要。本文深入探讨了Java安全编程的最佳实践,包括代码审查、输入验证、输出编码、访问控制和加密技术等,帮助开发者构建安全可靠的应用。通过掌握相关技术和工具,开发者可以有效防范安全威胁,确保应用的安全性。
26 4
|
14天前
|
缓存 监控 Java
如何运用JAVA开发API接口?
本文详细介绍了如何使用Java开发API接口,涵盖创建、实现、测试和部署接口的关键步骤。同时,讨论了接口的安全性设计和设计原则,帮助开发者构建高效、安全、易于维护的API接口。
40 4
|
19天前
|
SQL Java 程序员
倍增 Java 程序员的开发效率
应用计算困境:Java 作为主流开发语言,在数据处理方面存在复杂度高的问题,而 SQL 虽然简洁但受限于数据库架构。SPL(Structured Process Language)是一种纯 Java 开发的数据处理语言,结合了 Java 的架构灵活性和 SQL 的简洁性。SPL 提供简洁的语法、完善的计算能力、高效的 IDE、大数据支持、与 Java 应用无缝集成以及开放性和热切换特性,能够大幅提升开发效率和性能。
|
20天前
|
存储 Java 关系型数据库
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践,包括连接创建、分配、复用和释放等操作,并通过电商应用实例展示了如何选择合适的连接池库(如HikariCP)和配置参数,实现高效、稳定的数据库连接管理。
39 2
|
20天前
|
存储 Java 开发者
成功优化!Java 基础 Docker 镜像从 674MB 缩减到 58MB 的经验分享
本文分享了如何通过 jlink 和 jdeps 工具将 Java 基础 Docker 镜像从 674MB 优化至 58MB 的经验。首先介绍了选择合适的基础镜像的重要性,然后详细讲解了使用 jlink 构建自定义 JRE 镜像的方法,并通过 jdeps 自动化模块依赖分析,最终实现了镜像的大幅缩减。此外,文章还提供了实用的 .dockerignore 文件技巧和选择安全、兼容的基础镜像的建议,帮助开发者提升镜像优化的效果。
|
14天前
|
安全 Java 测试技术
Java开发必读,谈谈对Spring IOC与AOP的理解
Spring的IOC和AOP机制通过依赖注入和横切关注点的分离,大大提高了代码的模块化和可维护性。IOC使得对象的创建和管理变得灵活可控,降低了对象之间的耦合度;AOP则通过动态代理机制实现了横切关注点的集中管理,减少了重复代码。理解和掌握这两个核心概念,是高效使用Spring框架的关键。希望本文对你深入理解Spring的IOC和AOP有所帮助。
28 0
|
14天前
|
Java API Android开发
kotlin和java开发优缺点
kotlin和java开发优缺点
29 0
WK
|
19天前
|
开发框架 移动开发 Java
C++和Java哪个更适合开发移动应用
本文对比了C++和Java在移动应用开发中的优劣,从市场需求、学习难度、开发效率、跨平台性和应用领域等方面进行了详细分析。Java在Android开发中占据优势,而C++则适合对性能要求较高的场景。选择应根据具体需求和个人偏好综合考虑。
WK
38 0
下一篇
无影云桌面