Skip to content

[ISSUE #13822]: separation of responsibilities of client executor and login scheduled executor#13878

Merged
shiyiyue1102 merged 2 commits intoalibaba:developfrom
FangYuan33:fix_13822
Oct 14, 2025
Merged

[ISSUE #13822]: separation of responsibilities of client executor and login scheduled executor#13878
shiyiyue1102 merged 2 commits intoalibaba:developfrom
FangYuan33:fix_13822

Conversation

@FangYuan33
Copy link
Contributor

@KomachiSion @shiyiyue1102 二位好,Hi~ o( ̄▽ ̄)ブ

我对这个 ISSUE 的理解:如果只是单纯的解决表面的问题的话,可以直接将 ClientWorker#MIN_THREAD_NUM 字段调整为 3 或更大,但是如果未来出现对 ConfigTransportClient#executor 线程池中再添加一个循环的忙任务,可能还会产生同样的问题,所以我做了以下调整:

  1. 线程池的职责分离:最初 ConfigTransportClient#executor 线程池用在了 ConfigTransportClient#start 定时登录任务、配置监听、模糊配置监听和处理模糊监听请求上(ConfigFuzzyWatchGroupKeyHolder#doExecuteConfigFuzzyListen),除了定时登录任务外,其他几个任务任务都不是定时任务,所以我想为定时登录创建一个线程池大小为 1 的 ScheduledExecutorService 来专门处理它,ConfigTransportClient#executor 线程池用于处理其他非定时任务
  2. 因为 ConfigTransportClient#executor 线程池已经不需要处理定时任务了,所以我修改了它的类型为 ThreadPoolExecutor,用于处理其他三个配置监听的任务,因为配置监听和模糊配置监听需要长期占有 2 个线程,所以我定义了 ClientWorker#LOOP_CONFIG_LISTEN_THREAD_NUM 变量用于标识线程池中循环的忙任务数,并在创建线程池时(ClientWorker#instantiateClientExecutor),对 corePoolSize 和 maximumPoolSize 累加,保证线程池中始终为这两个任务创建专属的线程,剩余的其他线程用于处理其他任务
  3. 创建线程池时指定的 SynchronousQueue 是为了让多提交的任务不在队列中等待,保证任务处理的及时性,当 corePoolSize 线程数不够时,直接创建新的线程来处理任务
  4. CallerRunsPolicy 拒绝策略来保证任务不丢弃

请有时间帮忙 review~ 感谢~ 同时也听听二位的建议~

@github-actions
Copy link

github-actions bot commented Oct 1, 2025

Thanks for your this PR. 🙏
Please check again for your PR changes whether contains any usage/api/configuration change such as Add new API , Add new configuration, Change default value of configuration.
If so, please add or update documents(markdown type) in docs/next/ for repository nacos-group/nacos-group.github.io


感谢您提交的PR。 🙏
请再次查看您的PR内容,确认是否包含任何使用方式/API/配置参数的变更,如:新增API新增配置参数修改默认配置等操作。
如果是,请确保在提交之前,在仓库nacos-group/nacos-group.github.io中的docs/next/目录下添加或更新文档(markdown格式)。

@shiyiyue1102
Copy link
Collaborator

shiyiyue1102 commented Oct 9, 2025

clientworker和fuzzywatcher中的任务是一个后台持续执行的任务,会长时间占用线程,并不适合使用多个线程的线程池。这个bug本质上的问题是创建的线程池和运行任务的场景不适配,在ConfigTransportClient中定义executor时无法感知在子类中如何使用它,因此会比较容易产生bug。 建议将 loginExecutor, listenerExecutor,fuzzyWatcherExecutor定义为3个明确的独立singleExecutor ,并确保在ConfigTransportClient,ClientWorker,ConfigFuzzyWatchGroupKeyHolder的shutdown方法中安全的终止线程。

  1. 移除ConfigTransportClient中的executor,保留loginExecutor(newSingleThreadExecutor)
  2. ClientWorker中的ConfigRpcTransportClient的start方法中新增listenerExecutor(newSingleThreadExecutor)
  3. ConfigFuzzyWatchGroupKeyHolder的start方法中新增fuzzyWatcherExecutor(newSingleThreadExecutor)
  4. 在各自的shutdown方法中确认线程池可终止
  5. 两个while (true) 任务执行前进行线程池状态判断,确保任务可正常退出

@FangYuan33
Copy link
Contributor Author

clientworker和fuzzywatcher中的任务是一个后台持续执行的任务,会长时间占用线程,并不适合使用多个线程的线程池。这个bug本质上的问题是创建的线程池和运行任务的场景不适配,在ConfigTransportClient中定义executor时无法感知在子类中如何使用它,因此会比较容易产生bug。 建议将 loginExecutor, listenerExecutor,fuzzyWatcherExecutor定义为3个明确的独立singleExecutor ,并确保在ConfigTransportClient,ClientWorker,ConfigFuzzyWatchGroupKeyHolder的shutdown方法中安全的终止线程。

  1. 移除ConfigTransportClient中的executor,保留loginExecutor(newSingleThreadExecutor)
  2. ClientWorker中的ConfigRpcTransportClient的start方法中新增listenerExecutor(newSingleThreadExecutor)
  3. ConfigFuzzyWatchGroupKeyHolder的start方法中新增fuzzyWatcherExecutor(newSingleThreadExecutor)
  4. 在各自的shutdown方法中确认线程池可终止
  5. 两个while (true) 任务执行前进行线程池状态判断,确保任务可正常退出

好的,我理解了你的想法,之后我会按照这个方案修改,现在我有一个疑问,在 ConfigFuzzyWatchGroupKeyHolder#doExecuteConfigFuzzyListen 方法中,调用了 ConfigTransportClient#getExecutor 获取线程池然后去执行 ConfigFuzzyWatchGroupKeyHolder#executeFuzzyWatchRequest 方法,这一操作目前依赖的仍然是 ConfigTransportClient#executor 线程池,请问这个线程池需不需要保留?或者我们能不能保留一个多线程的线程池来处理这些非持续运行的任务呢?

@shiyiyue1102
Copy link
Collaborator

shiyiyue1102 commented Oct 9, 2025

,我理解了你的想法,之后我会按照这个方案修改,现在我有一个疑问,在 ConfigFuzzyWatchGroupKeyHolder#doExecuteConfigFuzzyListen 方法中,调用了 ConfigTransportClient#getExecutor 获取线程池然后去执行 ConfigFuzzyWatchGroupKeyHolder#executeFuzzyWatchRequest 方法,这一操作目前依赖的仍然是 ConfigTransportClient#executor 线程池,请问这个线程池需不需要保留?或者我们能不能保留一个多线程的线程池来处理这些非持续运行的任务呢?

在ConfigFuzzyWatchGroupKeyHolder中单独起一个独立的newSingleThreadExecutor来执行fuzzyWatch任务,你说的这个 "保留一个多线程的线程池"当前只服务于login接口,可以保留ConfigTransportClient中的executor(newSingleThreadExecutor)来执行login任务,就是你当前pr里面的executor和loginExecutor合并成一个newSingleThreadExecutor即可,但是这个线程池不向子类暴露

@FangYuan33
Copy link
Contributor Author

,我理解了你的想法,之后我会按照这个方案修改,现在我有一个疑问,在 ConfigFuzzyWatchGroupKeyHolder#doExecuteConfigFuzzyListen 方法中,调用了 ConfigTransportClient#getExecutor 获取线程池然后去执行 ConfigFuzzyWatchGroupKeyHolder#executeFuzzyWatchRequest 方法,这一操作目前依赖的仍然是 ConfigTransportClient#executor 线程池,请问这个线程池需不需要保留?或者我们能不能保留一个多线程的线程池来处理这些非持续运行的任务呢?

在ConfigFuzzyWatchGroupKeyHolder中单独起一个独立的newSingleThreadExecutor来执行fuzzyWatch任务,你说的这个 "保留一个多线程的线程池"当前只服务于login接口,可以保留ConfigTransportClient中的executor(newSingleThreadExecutor)来执行login任务,就是你当前pr里面的executor和loginExecutor合并成一个newSingleThreadExecutor即可,但是这个线程池不向子类暴露

  1. ConfigTransportClient#executor 已删除,相应地也删除了 ClientWorker 构造方法中初始化这个线程池的逻辑,无用的方法 ClientWorker#initWorkerThreadCount 也删除了,相应地 PropertyKeyConst#CLIENT_WORKER_MAX_THREAD_COUNTPropertyKeyConst#CLIENT_WORKER_THREAD_COUNT 配置参数常量也没用了
  2. ConfigTransportClient 中保留了 loginScheduledExecutor,用于定时登录
  3. ConfigRpcTransportClient 中新增了 listenExecutor 用于处理后台持续监听配置变更的任务
  4. ConfigFuzzyWatchGroupKeyHolder 中新增了 fuzzyWatcherExecutor 用于处理后台持续模糊监听的任务
  5. ConfigFuzzyWatchGroupKeyHolder 中新增了 fuzzyWatchTaskExecutor 用于处理 ConfigFuzzyWatchGroupKeyHolder#doExecuteConfigFuzzyListen 方法中 executeFuzzyWatchRequest 的逻辑
  6. shutdown 方法中已确认线程池可终止,两个 while (true) 任务执行前已进行线程池状态判断,确保任务可正常退出

private final long securityInfoRefreshIntervalMills = TimeUnit.SECONDS.toMillis(5);


private ScheduledExecutorService loginScheduledExecutor;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

loginScheduledExecutor 是否可以去掉,使用executor即可?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

loginScheduledExecutor 是否可以去掉,使用executor即可?

O(∩_∩)O,我说说我的想法,看看你的意见:

  1. 我想保留 loginScheduledExecutor 的原因是 loginScheduledExecutor 执行的是 ScheduledExecutorService#scheduleWithFixedDelay 方法,它是一个本地定期执行的定时登录任务,所以我想把它放在一个专用的只有 1 个线程的 ScheduledExecutorService 线程池中去执行,就像上边将 while(true) 的忙任务分离出来一样
  2. ConfigTransportClient#executor 我把它定义的类型是 ThreadPoolExecutor,它没有专有的命名,我觉得定位更像是一个在 Client 中较为通用的线程池,就像它现在已经被用作去处理模糊监听的任务了,之后如果有线程池需要的话,可以通过 ConfigTransportClient#getExecutor 方法获取并复用。如果将 loginScheduledExecutor 去掉的话,那么需要把 ConfigTransportClient#executor 定义成 ScheduledExecutorService 类型,那么它就更像是一个能够执行定时任务的线程池了,但是可能本地启动定时任务的场景好像不是很多

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

loginScheduledExecutor 是否可以去掉,使用executor即可?

O(∩_∩)O,我说说我的想法,看看你的意见:

  1. 我想保留 loginScheduledExecutor 的原因是 loginScheduledExecutor 执行的是 ScheduledExecutorService#scheduleWithFixedDelay 方法,它是一个本地定期执行的定时登录任务,所以我想把它放在一个专用的只有 1 个线程的 ScheduledExecutorService 线程池中去执行,就像上边将 while(true) 的忙任务分离出来一样
  2. ConfigTransportClient#executor 我把它定义的类型是 ThreadPoolExecutor,它没有专有的命名,我觉得定位更像是一个在 Client 中较为通用的线程池,就像它现在已经被用作去处理模糊监听的任务了,之后如果有线程池需要的话,可以通过 ConfigTransportClient#getExecutor 方法获取并复用。如果将 loginScheduledExecutor 去掉的话,那么需要把 ConfigTransportClient#executor 定义成 ScheduledExecutorService 类型,那么它就更像是一个能够执行定时任务的线程池了,但是可能本地启动定时任务的场景好像不是很多

可以,按照你的想法,会清晰明确一些。

@shiyiyue1102 shiyiyue1102 merged commit 39a5548 into alibaba:develop Oct 14, 2025
1 check passed
@FangYuan33 FangYuan33 deleted the fix_13822 branch October 14, 2025 05:25
@KomachiSion KomachiSion added kind/bug Category issues or prs related to bug. area/Client Related to Nacos Client SDK labels Nov 14, 2025
@KomachiSion KomachiSion added this to the 3.1.1 milestone Nov 14, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/Client Related to Nacos Client SDK kind/bug Category issues or prs related to bug.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants