sofastack / sofa-jraft

A production-grade java implementation of RAFT consensus algorithm.
https://www.sofastack.tech/projects/sofa-jraft/
Apache License 2.0
3.58k stars 1.15k forks source link

jraft组成5个节点的raft集群,运行一段时间后,1个节点4个线程池的线程数量缓慢增长 #974

Closed zhipingu closed 1 year ago

zhipingu commented 1 year ago

jraft组成5个节点的raft集群,运行一段时间后,发现2个集群都出现其中1个从节点4个线程池的线程数量缓慢增长达到了1200多,其它节点线程数量正常,只有几十个,这4个线程池名字是:Bolt-heal-connection-thread, Bolt-conn-event-executor, JRaft-RPC-Processor, RpcTaskScannerThread

Environment

fengjiachun commented 1 year ago

怎么使用 jraft 的?是不是进程一直在,然后反复重启 jraft 服务?

zhipingu commented 1 year ago

怎么使用 jraft 的?是不是进程一直在,然后反复重启 jraft 服务?

首先启动时初始化raftGroupService,然后通过raftGroupService.getRaftNode().apply(task)使用的jraft服务,raftGroupServie.start()后没有关过

fengjiachun commented 1 year ago

重复构建 RpcClient 了?我看都是 bolt 相关的线程池

zhipingu commented 1 year ago

重复构建 RpcClient 了?我看都是 bolt 相关的线程池

没有重复构建,每次通过raftGroupService.getRaftNode().getRpcService().getRpcClient()获取的rpcClient

zhipingu commented 1 year ago

RpcClient每次调用后需要close或者shutdown吗

fengjiachun commented 1 year ago

RpcClient每次调用后需要close或者shutdown吗

和调用无关,不需要,请注意我的问题,是否反复构建 RpcClient?看现象是的

zhipingu commented 1 year ago

RpcClient每次调用后需要close或者shutdown吗

和调用无关,不需要,请注意我的问题,是否反复构建 RpcClient?看现象是的

没有重复构建,每次通过raftGroupService.getRaftNode().getRpcService().getRpcClient()获取的rpcClient

fengjiachun commented 1 year ago

RpcClient每次调用后需要close或者shutdown吗

和调用无关,不需要,请注意我的问题,是否反复构建 RpcClient?看现象是的

没有重复构建,每次通过raftGroupService.getRaftNode().getRpcService().getRpcClient()获取的rpcClient

建议查下相关的使用代码,应该没有别的可能性了

fengjiachun commented 1 year ago

这里被调用了多次,可以查一下看看

https://github.com/sofastack/sofa-jraft/blob/master/jraft-core/src/main/java/com/alipay/sofa/jraft/rpc/impl/AbstractClientService.java#L106

zhipingu commented 1 year ago

RpcClient每次调用后需要close或者shutdown吗

和调用无关,不需要,请注意我的问题,是否反复构建 RpcClient?看现象是的

没有重复构建,每次通过raftGroupService.getRaftNode().getRpcService().getRpcClient()获取的rpcClient

建议查下相关的使用代码,应该没有别的可能性了

我查了一下jvm内存,只有3个BoltRpcCLient实例

fengjiachun commented 1 year ago

首先,多于一个就有问题了吧?为什么要3个? 其次,3个是多少线程呢?是昨天你发的有问题节点的内存吗?

zhipingu commented 1 year ago

RpcClient每次调用后需要close或者shutdown吗

和调用无关,不需要,请注意我的问题,是否反复构建 RpcClient?看现象是的

没有重复构建,每次通过raftGroupService.getRaftNode().getRpcService().getRpcClient()获取的rpcClient

建议查下相关的使用代码,应该没有别的可能性了

但是com.alipay.remoting.rpc.RpcClient实例有1200多个

fengjiachun commented 1 year ago

RpcClient实例有1200多个

嗯,但是实例是你在上层创建的呀,所以让你查呀,我上面的那个代码链接,那个方法被调用多次,请查一下原因

zhipingu commented 1 year ago

之所以有3个,是因为我们初始化时创建了3个,即使是3个,也不应该有1200个线程?而且还在增长

fengjiachun commented 1 year ago

参考我上条回复,查下自己代码,为什么 initXXX 那个方法被多次调用

zhipingu commented 1 year ago

RpcClient每次调用后需要close或者shutdown吗

和调用无关,不需要,请注意我的问题,是否反复构建 RpcClient?看现象是的

没有重复构建,每次通过raftGroupService.getRaftNode().getRpcService().getRpcClient()获取的rpcClient

建议查下相关的使用代码,应该没有别的可能性了

但是com.alipay.remoting.rpc.RpcClient实例有1200多个 com.alipay.remoting.rpc.RpcClient(和sofa.jraft.rpc.RpcClient不同))这个我们没有直接创建,为什么有1200多个实例,还没找到原因

fengjiachun commented 1 year ago

RpcClient每次调用后需要close或者shutdown吗

和调用无关,不需要,请注意我的问题,是否反复构建 RpcClient?看现象是的

没有重复构建,每次通过raftGroupService.getRaftNode().getRpcService().getRpcClient()获取的rpcClient

建议查下相关的使用代码,应该没有别的可能性了

但是com.alipay.remoting.rpc.RpcClient实例有1200多个

com.alipay.remoting.rpc.RpcClient(和sofa.jraft.rpc.RpcClient不同))这个我们没有直接创建,为什么有1200多个实例,还没找到原因

肯定有重复创建的,我不太了解你们业务测是不是用什么 spring 容器啥的管理实例,我不太了解,得你们自己查下

zhipingu commented 1 year ago

RpcClient每次调用后需要close或者shutdown吗

和调用无关,不需要,请注意我的问题,是否反复构建 RpcClient?看现象是的

没有重复构建,每次通过raftGroupService.getRaftNode().getRpcService().getRpcClient()获取的rpcClient

建议查下相关的使用代码,应该没有别的可能性了

但是com.alipay.remoting.rpc.RpcClient实例有1200多个

com.alipay.remoting.rpc.RpcClient(和sofa.jraft.rpc.RpcClient不同))这个我们没有直接创建,为什么有1200多个实例,还没找到原因

肯定有重复创建的,我不太了解你们业务测是不是用什么 spring 容器啥的管理实例,我不太了解,得你们自己查下

好的,谢谢,我们在查,目前还没查到重复创建的地方,没有用spring,查到了再反馈

fengjiachun commented 1 year ago

好的,我不太懂业务测的一些技术栈不好意思,有结果了可以回来反馈一下

zhipingu commented 1 year ago

好的,我不太懂业务测的一些技术栈不好意思,有结果了可以回来反馈一下

找到原因了,是因为在一个实例方法getLeader()里调用了: CliClientServiceImpl cliClientService = new CliClientServiceImpl(); cliClientService.init(new CliOptions()); 在init()里面分配了jraft-rpc-processor线程池和rpcClient 但是方法退出前没有cliClientService.shutdown() 把它CliClientServiceImpl cliClientService = new CliClientServiceImpl();改成类静态变量了,静态初始化

killme2008 commented 1 year ago

为什么要重复创建 CliClientServiceImpl ? 共用一个就好了。

fengjiachun commented 1 year ago

嗯,修改为静态应该就可以了

fengjiachun commented 1 year ago

那这个 issue 就关闭了

fengjiachun commented 1 year ago

我稍微帮忙复盘一下

上面列出的线程池名字全部是 bolt 相关的(其实已经说明了 bolt 作为 rpc client 被构建多次了), 还有一个是 jraft 的线程池(JRaft-RPC-Processor),只要一搜它在哪里使用了,就可以发现一定是下面这个方法(initRpcClient)被重复多次调用了:

https://github.com/sofastack/sofa-jraft/blob/master/jraft-core/src/main/java/com/alipay/sofa/jraft/rpc/impl/AbstractClientService.java#L118

从 initRpcClient 方法下手,应该可以就能找到哪里的使用出了问题

zhipingu commented 1 year ago

我稍微帮忙复盘一下

上面列出的线程池名字全部是 bolt 相关的(其实已经说明了 bolt 作为 rpc client 被构建多次了), 还有一个是 jraft 的线程池(JRaft-RPC-Processor),只要一搜它在哪里使用了,就可以发现一定是下面这个方法(initRpcClient)被重复多次调用了:

https://github.com/sofastack/sofa-jraft/blob/master/jraft-core/src/main/java/com/alipay/sofa/jraft/rpc/impl/AbstractClientService.java#L118

从 initRpcClient 方法下手,应该可以就能找到哪里的使用出了问题 感谢