Skip to content

Shutdown ExecutorService(s) in multi node pipelines #3467

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jun 14, 2023

Conversation

sazzad16
Copy link
Contributor

Some discussions can be found in e193365

@sazzad16 sazzad16 added the bug label Jun 13, 2023
@sazzad16 sazzad16 added this to the 4.4.x milestone Jun 13, 2023
@sazzad16 sazzad16 requested a review from yangbodong22011 June 13, 2023 15:04
@sazzad16
Copy link
Contributor Author

Thanks @jslopezgithub for reporting respective issue.

@yangbodong22011
Copy link
Contributor

@sazzad16 The current PR still frequently creates and destroys threads. I strongly insist on making the thread pool static, let's keep working on #3333 .

@sazzad16
Copy link
Contributor Author

The current PR still frequently creates and destroys threads. I strongly insist on making the thread pool static, let's keep working on #3333 .

@yangbodong22011 Yes. But it may take at least a couple of days. A quick fix for the issue is kind of necessary at this moment.

@sazzad16 sazzad16 requested a review from yangbodong22011 June 14, 2023 07:15
@sazzad16 sazzad16 merged commit c33bdf7 into redis:master Jun 14, 2023
@sazzad16 sazzad16 deleted the executor-shutdown branch June 14, 2023 07:47
sazzad16 added a commit that referenced this pull request Jun 14, 2023
* Shutdown ExecutorService(s) in multi node pipelines

* Use only shutdownNow()

* format import
@sazzad16 sazzad16 modified the milestones: 4.4.x, 4.4.3 Mar 24, 2024
@dolavb
Copy link

dolavb commented Nov 4, 2024

We executed load testing with profiling and this change results in 45% of CPU being used for starting thread, incurring a latency cost equivalent to the network wait time for the Redis process to return on the completed command. Overall this change has been detrimental and would probably be better with executing the whole pipeline on a single thread in our case.

@sazzad16
Copy link
Contributor Author

sazzad16 commented Nov 5, 2024

@dolavb I think you actually mean the changes in #3331. Right? If so, have you tried setting MULTI_NODE_PIPELINE_SYNC_WORKERS = 1?

@dolavb
Copy link

dolavb commented Jan 22, 2025

@dolavb I think you actually mean the changes in #3331. Right? If so, have you tried setting MULTI_NODE_PIPELINE_SYNC_WORKERS = 1?

@sazzad16 , sorry for the delay, I wanted to come with a Fix. Even with MULTI_NODE_PIPELINE_SYNC_WORKERS set to 1, this remains a poor experience event with 1:

  • You are creating a thread that you do not need, as 1 would be equivalent as to executing with a single thread.
  • That implementation is sub optimal as well as it can create threads that are not needed when the number of connection is lower than the value of MULTI_NODE_PIPELINE_SYNC_WORKERS.
  • Further, this creates expensive resource as a side effect of the client call, which is overall a bad experience for the callers.

For my usage, this extra CPU will likely translate in large amount of money. I finally had to time to create a PR: 4070. I will move it out of draft in a bit, I want to rerun the profilers and get accurate number, that 40% is out of memory.

@szx1
Copy link

szx1 commented Feb 8, 2025

@sazzad16 I don't understand why a thread pool cannot use a static variable but instead is changed to a local variable with shutdownNow(). The latter has much lower performance compared to the former. What was the author's consideration?

@sazzad16
Copy link
Contributor Author

sazzad16 commented Feb 9, 2025

@szx1 Consideration was performance in terms of data communication.

@dolavb
Copy link

dolavb commented Feb 10, 2025

@szx1 I agree that making this static is not the right approach, this forces the client to use that thread pool which might not be the right approach for that use case. Further, the exposition of a global variable through a static public field in the class to select the thread count of the pool has created a hard dependency on this approach, and broken encapsulation.

However, making the thread pool local is not the solution. As @sazzad16, the consideration here is the closing/syncing of multiple connections once the pipeline is closed/synced. The creation of a thread pool is CPU intensive, this is why we create thread Pool, and not thread Collections. We should not make this in a local variable that client keeps creating and shutting down for every pipeline. This might come with a benefit for people whit high communication cost, but for people who use pipelines and have a short communication time, that benefit is not there, and in fact it becomes detrimental.

I have created a PR 4070 to address this issue by allowing the clients to pass in an Executor service when creating a pipeline. I had to maintain the static one there, since this has now been leaked into a public interface. I believe the ideal situation following this PR would be to to add the ExecutorService as an optional field in the JedisClientConfig, and pass it down when needed. I am not sure if this need be done in the PR I have created.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants