-
Notifications
You must be signed in to change notification settings - Fork 3.6k
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
[Broker] Use shared executors for broker and geo-replication clients #13839
[Broker] Use shared executors for broker and geo-replication clients #13839
Conversation
doc = "Number of shared threads to use for broker clients." | ||
+ " Default is set to `2 * Runtime.getRuntime().availableProcessors()`" | ||
) | ||
private int brokerClientNumIOThreads = 2 * Runtime.getRuntime().availableProcessors(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd say that we should prob reuse the broker IO threads here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem is that broker IO threads is a EventLoopGroup
instance which is already used in the Pulsar Client.
pulsar/pulsar-broker/src/main/java/org/apache/pulsar/broker/PulsarService.java
Lines 319 to 320 in 9032a9a
this.ioEventLoopGroup = EventLoopUtil.newEventLoopGroup(config.getNumIOThreads(), config.isEnableBusyWait(), | |
new DefaultThreadFactory("pulsar-io")); |
The Pulsar Client has this internal/IO and external/listener executors in addition to the eventLoopGroup
.
pulsar/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PulsarClientImpl.java
Lines 182 to 185 in 4591a21
this.externalExecutorProvider = externalExecutorProvider != null ? externalExecutorProvider : | |
new ExecutorProvider(conf.getNumListenerThreads(), "pulsar-external-listener"); | |
this.internalExecutorProvider = internalExecutorProvider != null ? internalExecutorProvider : | |
new ExecutorProvider(conf.getNumIoThreads(), "pulsar-client-internal"); |
It might be a risky change in Pulsar Client to replace the internal executor to delegate directly to eventLoopGroup
.
This is the reason why I think it's necessary to have a separate setting to control the amount of threads used to run the Pulsar Client internal executors. Before this PR each client has had a single threaded internal executor for each client instance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I think the confusion comes from the name brokerClientNumIOThreads
, since it's client internal executor and not the client event loop which is already shared.
Additionally, the client internal executor shouldn't really be used a lot in broker, since it's used mainly for dispatching the partitioned/multi topic consumers, so we could just default to 1 thread instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I think the confusion comes from the name brokerClientNumIOThreads, since it's client internal executor and not the client event loop which is already shared.
That's true. The Pulsar Client uses the numIOThreads
parameter for configuring the number of threads for the eventLoopGroup
and also for the internal/IO executor.
pulsar/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PulsarClientImpl.java
Line 979 in 4591a21
return EventLoopUtil.newEventLoopGroup(conf.getNumIoThreads(), conf.isEnableBusyWait(), threadFactory); |
pulsar/pulsar-client/src/main/java/org/apache/pulsar/client/impl/PulsarClientImpl.java
Lines 184 to 185 in 4591a21
this.internalExecutorProvider = internalExecutorProvider != null ? internalExecutorProvider : | |
new ExecutorProvider(conf.getNumIoThreads(), "pulsar-client-internal"); |
This is confusing. The internal executor was introduced in #8208 and that change uses numIOThreads
parameter also for configuring the number of threads for the internal executor. @merlimat I wonder what would be a way to improve this situation?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Additionally, the client internal executor shouldn't really be used a lot in broker, since it's used mainly for dispatching the partitioned/multi topic consumers, so we could just default to 1 thread instead.
yes, that is true. I wonder if the value needs to be configurable at all? I'll remove brokerClientNumIOThreads key and just use the value 1 as I did for the external executor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made the changes now. @merlimat PTAL
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
- don't ever make it a daemon thread
// the external executor is not used in the broker client or replication clients since this executor is | ||
// used for consumer listeners. | ||
// since an instance is required, a single threaded shared instance is used for all broker client instances |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't this hint at a problem in the java client? It looks like a listener is declared on consumer initialization. We could change the behavior so that it only gets a thread when there is a listener.
We'll still have the issue of creating an ExecutorProvider
per client, so this change still makes sense, but it'd be cheaper for end users to avoid the thread creation for consumers that lack listeners.
I am going to open a PR to update the Java Consumer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't this hint at a problem in the java client? It looks like a listener is declared on consumer initialization. We could change the behavior so that it only gets a thread when there is a listener.
Yes the client isn't optimal, but I doubt that it causes an actual measurable overhead. I think that the thread is just pinned out of the single shared thread and nothing will get run on it (in the current usage patterns when client is used in the broker).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes the client isn't optimal, but I doubt that it causes an actual measurable overhead. I think that the thread is just pinned out of the single shared thread and nothing will get run on it (in the current usage patterns when client is used in the broker).
I was thinking about user applications that have many consumers. I just looked a bit closer, and the upper limit here is NumListenerThreads
in the client configuration. That is the max number of threads a client will spawn for consumer listeners. Was this a problem in the broker because we have many clients?
Motivation
Modifications