解决Tomcat启动慢的问题:深入分析随机值阻塞与优化策略

1.tomcat启动缓慢

解决Tomcat启动慢的问题:深入分析随机值阻塞与优化策略

在线上环境中,我们经常会遇到类似的问题,那就是tomcat启动缓慢。检查内存、CPU、io时都正常,但启动很慢,有时长达几分钟。这是什么原因呢?的。

1.1 tomcat获取随机值阻塞

tomcat的启动需要生成session id。这个生成需要通过java.security.SecureRandom生成随机数来实现。随机数算法使用“SHA1PRNG”,但该算法依赖于操作系统提供的随机数据。在Linux系统中,该值取决于/dev/random和/dev/urandom

/dev/random :阻塞型,读取它就会产生随机数据,但该数据取决于熵池噪声,当熵池空了,对/dev/random 的读操作也将会被阻塞。
/dev/urandom: 非阻塞的随机数产生器,它会重复使用熵池中的数据以产生伪随机数据。这表示对/dev/urandom的读取操作不会产生阻塞,但其输出的熵可能小于/dev/random的。它可以作为生成较低强度密码的伪随机数生成器,不建议用于生成高强度长期密码。

我们查看了java.security文件(我的java版本是1.8.0_131),发现它依赖于/dev/random

tomcat启动生成的session ID最终取决于/dev/random,而/dev/random又取决于熵池。

关于熵池,百度百科上写道:

     Linux内核采用熵来描述数据的随机性。熵(entropy)是描述系统混乱无序程度的物理量,一个系统的熵越大则说明该系统的有序性越差,即不确定性越大。在信息学中,熵被用来表征一个符号或系统的不确定性,熵越大,表明系统所含有用信息量越少,不确定度越大。计算机本身是可预测的系统,因此,用计算机算法不可能产生真正的随机数。但是机器的环境中充满了各种各样的噪声,如硬件设备发生中断的时间,用户点击鼠标的时间间隔等是完全随机的,事先无法预测。Linux内核实现的随机数产生器正是利用系统中的这些随机噪声来产生高质量随机数序列。内核维护了一个熵池用来收集来自设备驱动程序和其它来源的环境噪音。理论上,熵池中的数据是完全随机的,可以实现产生真随机数序列。为跟踪熵池中数据的随机性,内核在将数据加入池的时候将估算数据的随机性,这个过程称作熵估算。熵估算值描述池中包含的随机数位数,其值越大表示池中数据的随机性越好。

那么如何查看熵池的大小呢?文件 /proc/sys/kernel/random/entropy_avail 保存熵池的大小。 /proc/sys/kernel/random/poolsize 存储熵池的最大容量,以位为单位。

[root@haha cwd]# cat  /proc/sys/kernel/random/entropy_avail
146

综上所述,tomcat启动缓慢的原因是随机数生成被阻塞,而被阻塞的原因是熵池的大小。

解决方案:

1. 更换产生随机数的源,(也是tomcat的官方文档的启动比较慢的解决办法)
2. 增大熵池 的值

1.改变随机数来源

官方文档链接

因为/dev/urandom是非阻塞的随机数生成器,我们可以从这里获取,但是生成的随机数的随机性比较低。我们可以将其添加到我们的tomcat启动脚本(catalina.sh)中

JAVA_OPTS="$JAVA_OPTS -Djava.security.egd=file:/dev/./urandom"

或者将java的java.security文件改为securerandom.source=file:/dev/random

securerandom.source=file:/dev/./urandom

注意为什么我们这里使用的路径是“/dev/./urandom”而不是“/dev/urandom”。这是因为在Java 8之前的版本中设置了/dev/urandom,但实际上仍然使用/dev/。 random,设置为“/dev/./urandom”即可正常使用“/dev/urandom”。这个bug已经在java8版本中修复了。如果您使用的是java7版本,则需要按照上面进行设置。如果你使用的是java8,则不需要添加“./”。官方错误链接

2.增加熵池的值

要增加熵池的值,您必须首先在您的CPU上支持DRNG功能。如何检查我们的服务器是否支持DRNG功能?

cat /proc/cpuinfo | grep rdrand

如果不支持,那么只能通过上面第一种方法解决。

安装rngd服务(rngd服务介绍)

yum -y install rng-tools
systemctl enable rngd
systemctl start rngd

然后我们检查我们的熵池的值,发现它变大了

 cat  /proc/sys/kernel/random/entropy_avail

那么当我们启动tomcat时,我们会发现启动速度快了很多。

1.2 Tomcat需要部署过多的Web应用

有时候,我们的tomcat启动缓慢的原因是因为它需要部署太多的web应用,但其中有一些是我们不需要的,比如webapps下的doc、example、ROOT等。在发布之前删除必要的 Web 应用程序。这些不必要的webapp不仅会占用我们的资源,还可能成为入侵者的目标。如果我们想要并行启动多个Web应用程序,我们可以将Host属性startStopThreads值设置为大于1,但这也取决于我们的服务器是否是多核的。如果是多核,建议增大startStopThreads的值,但不要超过核心数。

1.3 启动tomcat时内存不足

如果项目比较大,我们用默认参数启动的tomcat很有可能内存不足。我们需要设置 JVM 并调整内存。建议JVM的最大值和最小值不要相差太大(最好一致。)

在启动脚本catalina.sh中添加:

JAVA_OPTS='-server -Xms1024m -Xmx1024m'

具体内存大小根据业务调整。

以上就是解决tomcat启动慢问题的问题及解决方案,可以根据自己的项目情况来使用。稍后也会有关于tomcat调优的文章,请关注。

2 连接器调整

### 2.1  使用arp 连接器

官方文档

Tomcat可以使用Apache Portable Runtime来提供更高性能的服务。 Apache Portable Runtime 是一个高度可移植的库,是 Apache HTTP Server 2.x 的核心。 APR有很多用途,包括高级io功能(sendfile、epoll、Openssl)、系统级功能(生成随机数、系统状态)和进程处理(共享内存、NT管道、unix套接字),它可以使tomcat成为一个万能的Web 服务器使 Java 应用程序更可行地充当完整的 Web 服务器,而不仅仅是作为后端技术。

总结:从系统层面解决异步IO的问题,提高性能。

apr连接器需要手动安装,需要以下组件

2.1 yum安装(推荐)

注意apr安装的版本

yum -y install openssl
yum -y install apr
yum -y install apr-util
yum -y install tomcat-native

2.2 源码安装(yum和源码安装二选一)

apr源码编译安装过程:

安装依赖并下载apr包

下载地址:

yum  -y install make gcc gcc-c++  openssl-devel libtool
cd /tmp && wget http://archive.apache.org/dist/apr/apr-1.6.5.tar.gz

解压apr包

tar -xzf  apr-1.6.5.tar.gz &&  cd apr-1.6.5

预编译、编译、安装

./configure   --prefix=/usr/local/apr  
make
make install

本机安装

解压原生包(原生包在tomcat安装包中的bin下)

cd  tomcat/bin && tar -xzf tomcat-native.tar.gz

预编译、编译、安装

cd tomcat-native*/native &&  ./configure  --with-apr=/usr/local/apr 
make
make install

添加环境变量

vim  + /etc/profile
# 添加环境变量
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/apr/lib

# 加载变量
source /etc/profile

2.3 配置apr连接器

vim  ./conf/server.xml

# 将 Connector 属性protocol 配置成 apr(org.apache.coyote.http11.Http11AprProtocol)
<Connector port="8080" protocol="org.apache.coyote.http11.Http11AprProtocol"
connectionTimeout="20000"
redirectPort="8443" />


默认连接器是 nio,主要有以下三种连接器:

重启tomcat

年利率测试·

Tomcat和jvm使用默认配置进行测试,使用nio连接器总共1000个请求,100个并发请求。

在使用nio连接器时,我多次尝试用150个并发请求,总共1000个请求进行测试,发现始终没有成功,但是当我使用apr连接时,

100个并发

150并发

我们可以对比发现,使用APR连接器在处理高并发请求时具有一定的优势,可以提高Web应用的请求处理能力。

2.2 连接器其他属性调整属性说明推荐设置值

最大线程数

tomcat可以创建处理请求的最大线程数,默认值为200

500

最小处理器数

启动时创建的线程数(最小线程数)

接受计数

指定当用于处理请求的所有可用线程都被使用时可以放入队列中的请求数。超过此数量的请求将拒绝连接。默认值为 100。

500

可压缩Mime类型

该值用于指定可以压缩的文件类型。默认值为:text/html、text/xml、text/plain、text/css、text/javascript、application/javascript

压缩

打开 gzip 压缩。可接受的值有“off”(禁用压缩)、“on”(启用压缩)、“force(强制压缩)”、“1-9”(相当于开启压缩并设置压缩级别)、开启压缩意味着会占用更多的CPU资源。

在

保持活动超时

指连接器的两个HTTP请求之间的直接等待时间。如果在此时间之后仍未收到第二个 HTTP 请求,则连接将被关闭。默认是使用connectionTimeout的值,以毫秒为单位。

30000

处理器缓存

进程缓冲区,默认值为maxThreads的值。正确使用该值可以增加并发请求。

500

以上设置仅供参考。建议根据自己的业务进行设置并测试。

tomcat默认给我设置了很多参数,比如URIEncoding和connectionTimeout。这些值都有默认值。有关详细信息,请参阅文章 tomcat 配置文件 server.xml 以获取 Connector Engine Host Context 的详细说明。

2.3 主机属性调整属性说明推荐配置

启动停止线程

指Host启动Context时使用的线程数。默认值为1,如果有多个核心,建议配置为核心数-1。

解压WAR

默认为 true。如果设置为true,则表示解压Web应用程序war包,false则表示直接从war文件运行。设置为false会对性能有一定的影响

真的

如果我们想要并行启动多个Web应用程序,我们可以将Host属性startStopThreads值设置为大于1,但这也取决于我们的服务器是否是多核的。如果是多核,建议增大startStopThreads的值,但不要超过核心数。

2.3 tomcat线程不能关闭,调优不能丢失(代码层)

如果我们采用自动发布的形式,即替换war包的形式,按照tomcat安装文章中介绍的那样与Jenkins集成,那么很容易出现的一个问题就是最后一个线程没有关闭,又新建了一个线程一个已经开始。版本,那么上一个版本的线程仍然存在并且仍然占用资源。出现这个问题的原因可能是代码问题。我们可以尝试直接使用catalina.sh脚本stop。你会发现,stop掉之后,tomcat的线程依然存在,所以出现这种情况很大一部分原因是java代码中存在非守护线程,即java代码没有设置线程作为守护线程,这就导致了tomcat无法停止线程的原因。那么这种情况可能会导致使用两个Web应用程序(旧版本和新版本),而这个应用程序的定时任务可能会被执行两次,这很容易导致生产事故。

这种问题一方面会占用服务器资源。另一方面,也容易引发生产事故。我们可以使用jstack来分析没有停止的线程,用开发区解决线程没有关闭的问题。

2.4 AJP 连接器禁用

tomcat中AJP协议的作用是将该服务与其他HTTP服务器集成。在我们一般的项目中,不会用到这个连接器,所以我们可以禁用该连接器

3 JVM设置

我们之前谈到启动内存不足。

JAVA_OPTS='-server -Xms1024m -Xmx1024m'

对于其他调整选项,如果您有多个连接器,您还可以通过执行器属性调整它们。

你可能想看:
« 上一篇
下一篇 »

相关推荐

java中什么是冒泡,冒泡算法

2026年09月06日

27阅读

java中冒号,java双冒号

2026年09月06日

26阅读

java中的->,java中的是什么意思

2026年09月06日

24阅读

java中的super用法,Java中super的说明

2026年09月06日

28阅读

java中反射的应用,java中反射的应用场景

2026年09月06日

25阅读

java中开关的定义,Java关键字有哪些

2026年09月06日

25阅读