本文介绍如何排查Nacos线程数过多的问题。
问题现象
通过监控系统或其他手段,观察到应用的线程数过多,且大部分线程名中带有nacos等字样。
可能原因
-
系统环境问题。程序读取到的CPU数量错误,导致线程池核心大小和最大大小过大。
-
应用中创建过多Nacos-Client实例, 例如NacosNamingService或NacosConfigService。
-
应用中存在错误使用方式,连续创建Nacos-Client实例,但新创建的Nacos-Client实例替换旧的Nacos-Client实例时未使用shutdown方法关闭线程池。
解决方案
本文以Java应用为例,其他语言应用可使用对应开发语言的相似命令执行。
-
首先确认是否创建过多Nacos-Client实例,使用
jmap -histo ${pid} > histo.log
命令,将应用中的内存实例对象记录在日志文件中,随后对日志文件进行过滤统计,并记录Nacos-Client的数量。# Nacos-Client注册中心客户端数量,正常情况下应该不超过3个。 grep "NacosNamingService" histo.log | awk '{print $2,$4}' # Nacos-Client配置中心客户端数量,正常情况下应该不超过3个。 grep "NacosConfigService" histo.log | awk '{print $2,$4}'
-
如果Nacos-Client实例数存在过多,例如10个以上,则原因可能为应用中创建了过多Nacos-Client实例。请排查应用中使用Nacos-Client的代码,是否未复用Nacos-Client实例而是每次都创建不同的Nacos-Client实例。更多信息,请参见Dubbo框架在2.7.8版本中的Bug。
-
-
如果Nacos-Client实例数量正常,请确认线程数是否符合预期。
-
使用
jstack ${pid} > jstack.log
命令,将当前线程信息打印到日志文件中,随后对日志文件进行过滤统计。# Nacos-Client所使用的线程池数量,其数量不应该超过Nacos-Client数量 * cpu数 * 8。 grep "nacos-grpc-client-executor" jstack.log | wc -l # Nacos-Client内部事件通知机制所使用的线程池,其总数不应超过5个 grep "nacos.publisher-" jstack.log | wc -l # Nacos-Client用于断线重连及发送pingpong心跳的线程,其总数不应超过Nacos-Client数量 * 2。 grep "com.alibaba.nacos.client.remote.worker" jstack.log | wc -l # Nacos-Client注册中心更新缓存所使用的线程池,其总数不应超过NacosNamingService数量 * (cpu数 / 2)。 grep "com.alibaba.nacos.client.naming.updater" jstack.log | wc -l # Nacos-Client注册中心接收UDP推送数据所使用的线程池,其总数不应超过NacosNamingService数量。 grep "com.alibaba.nacos.naming.push.receiver" jstack.log | wc -l # Nacos-Client注册中心在断线重连后,补偿非持久化服务数据的线程,其总数不应超过NacosNamingService数量。 grep "com.alibaba.nacos.client.naming.grpc.redo" jstack.log | wc -l # Nacos-Client配置中心监听配置所使用的线程池,其总数不应超过NacosConfigService数量。 grep "com.alibaba.nacos.client.Worker" jstack.log | wc -l # Nacos-Client配置中心用于回调监听者Listener的线程池,其总数不应超过NacosConfigService数量 * 5。 grep "nacos.client.config.listener.task" jstack.log | wc -l
-
如果上述线程数均超过了预期,则原因可能为连续创建Nacos-Client实例,但新创建的Nacos-Client实例替换旧的Nacos-Client实例时未使用shutdown方法关闭线程池,导致旧线程池未被关闭。更多信息,请参见Sentinel框架在旧版本中的Bug。
-
如果上述线程数仅有nacos-grpc-client-executor、com.alibaba.nacos.client.naming.updater等与CPU数量有关的线程数超过预期,则原因可能为应用读取的当前节点的CPU数量不正确,该情况多出现于容器化的场景中。可通过调用Runtime.getRuntime().availableProcessors()查看应用读取到的CPU数量,确认读取数量过大时,可通过更换正确的环境进行修复,或使用参数
-Dnacos.common.processors=
或环境变量NACOS_COMMON_PROCESSORS=
进行强制指定。 -
如果上述线程均符合预期,说明线程池并没有泄漏,没有线程数过多的风险。如需降低线程数,可通过参数
-Dnacos.remote.client.grpc.pool.core.size=
和-Dnacos.remote.client.grpc.pool.max.size=
来设置nacos-grpc-client-executor线程池的数量。-
参数
-Dnacos.remote.client.grpc.pool.core.size=
和-Dnacos.remote.client.grpc.pool.max.size=
需要Nacos-Client版本为2.1.1及以上版本生效。 -
nacos-grpc-client-executor线程池存在回收机制,客户端在长时间无请求时,会自动回收多余线程至最小值(默认为CPU数量 * 2)。在大量请求时,会自动扩充线程数至最大值(默认为CPU数量 * 8)。因此部分监控系统中会看到该线程名的线程ID会呈现增长趋势,该现象为正常现象,并非Nacos线程数过多的问题。
-
-
https://help.aliyun.com/zh/mse/support/what-do-i-do-if-the-number-of-nacos-threads-is-excessively-large
升级引擎版本
升级过程中的常见问题
-
问:升级到专业版Nacos 2.0.0后,能否支持旧版本客户端?
答:配置中心兼容并支持Nacos Client 1.0.0之后的所有客户端版本,服务发现兼容Nacos Client 1.2.0之后的所有客户端版本。 但Nacos Client 1.x.x的客户端版本不具有长连接能力,因此建议使用Nacos Client 2.0.0之后的客户端版本。
-
问:我使用的是Spring Cloud Alibaba或Dubbo,如何升级客户端?
答:对于Spring Cloud Alibaba,可通过指定Nacos Client的方式,升级Nacos Client版本。例如:
<dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> <version>2.1.1.RELEASE</version> <exclusions> <exclusion> <groupId>com.alibaba.nacos</groupId> <artifactId>nacos-client</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>com.alibaba.nacos</groupId> <artifactId>nacos-client</artifactId> <version>2.2.1</version> </dependency>
客户端nacos-client升级
nacos-client从2.2.1版本开始支持TLS传输链路加密。
-
升级至nacos-client 2.2.1版本。相关代码如下所示。
<dependency> <groupId>com.alibaba.nacos</groupId> <artifactId>nacos-client</artifactId> <version>2.2.1</version> </dependency>
https://help.aliyun.com/zh/mse/user-guide/enable-tls-for-mse-nacos-instances
spring-cloud-alibaba和nacos client版本关系可以参考spring-cloud-alibaba社区的文档说明
组件版本关系
每个 Spring Cloud Alibaba 版本及其自身所适配的各组件对应版本如下表所示(注意,Spring Cloud Dubbo 从 2021.0.1.0 起已被移除出主干,不再随主干演进):
Spring Cloud Alibaba Version | Sentinel Version | Nacos Version | RocketMQ Version | Dubbo Version | Seata Version |
---|---|---|---|---|---|
2022.0.0.0 |
1.8.6 |
2.2.1 |
4.9.4 |
~ |
1.7.0 |
2022.0.0.0-RC2 |
1.8.6 |
2.2.1 |
4.9.4 |
~ |
1.7.0-native-rc2 |
2021.0.5.0 |
1.8.6 |
2.2.0 |
4.9.4 |
~ |
1.6.1 |
2.2.10-RC1 |
1.8.6 |
2.2.0 |
4.9.4 |
~ |
1.6.1 |
2022.0.0.0-RC1 |
1.8.6 |
2.2.1-RC |
4.9.4 |
~ |
1.6.1 |
2.2.9.RELEASE |
1.8.5 |
2.1.0 |
4.9.4 |
~ |
1.5.2 |
2021.0.4.0 |
1.8.5 |
2.0.4 |
4.9.4 |
~ |
1.5.2 |
2.2.8.RELEASE |
1.8.4 |
2.1.0 |
4.9.3 |
~ |
1.5.1 |
2021.0.1.0 |
1.8.3 |
1.4.2 |
4.9.2 |
~ |
1.4.2 |
2.2.7.RELEASE |
1.8.1 |
2.0.3 |
4.6.1 |
2.7.13 |
1.3.0 |
2.2.6.RELEASE |
1.8.1 |
1.4.2 |
4.4.0 |
2.7.8 |
1.3.0 |
2021.1 or 2.2.5.RELEASE or 2.1.4.RELEASE or 2.0.4.RELEASE |
1.8.0 |
1.4.1 |
4.4.0 |
2.7.8 |
1.3.0 |
2.2.3.RELEASE or 2.1.3.RELEASE or 2.0.3.RELEASE |
1.8.0 |
1.3.3 |
4.4.0 |
2.7.8 |
1.3.0 |
2.2.1.RELEASE or 2.1.2.RELEASE or 2.0.2.RELEASE |
1.7.1 |
1.2.1 |
4.4.0 |
2.7.6 |
1.2.0 |
2.2.0.RELEASE |
1.7.1 |
1.1.4 |
4.4.0 |
2.7.4.1 |
1.0.0 |
2.1.1.RELEASE or 2.0.1.RELEASE or 1.5.1.RELEASE |
1.7.0 |
1.1.4 |
4.4.0 |
2.7.3 |
0.9.0 |
2.1.0.RELEASE or 2.0.0.RELEASE or 1.5.0.RELEASE |
1.6.3 |
1.1.1 |
4.4.0 |
2.7.3 |
0.7.1 |
https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E