-
Notifications
You must be signed in to change notification settings - Fork 38.5k
Thread BLOCKED issues of DestinationCache in DefaultSubscriptionRegistry #24395
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
Comments
Thanks for report. The use of
That said I am curious how is your implementation different? |
@rstoyanchev |
We observed the same. The CPU was BLOCKED on synchronized blocks in DefaultSubscriptionRegistry causing a bottleneck. We were lucky, that we had no subscription pattern matching so we was able to solve it by reimplemeting DefaultSubscriptionRegistry. We used two concurrentMaps and it's.computeX() methods:
And registered it like this:
It more than doubled the performance of a simple broker. |
@liheyuan, #25298 is now scheduled for 5.3 and should be a significant improvement. It not only avoids pattern matching for non-pattern destinations which was your main concern I believe but also reduces locking contention. If you are able to, once the PR is processed, it would be very helpful to hear if it works for you. |
* DestinationCache is now synchronized on multiple 'destination' locks (previously a single shared lock) * DestinationCache keeps destinations without any subscriptions (previously such destinations were recomputed over and over) * SessionSubscriptionRegistry is now a 'sessionId -> subscriptionId -> (destination,selector)' map for faster lookups (previously 'sessionId -> destination -> set of (subscriptionId,selector)') closes spring-projectsgh-24395
The part that I could optimize the most was cache recalculations for destinations without any subscribers on it. |
* DestinationCache is now synchronized on multiple 'destination' locks (previously a single shared lock) * DestinationCache keeps destinations without any subscriptions (previously such destinations were recomputed over and over) * SessionSubscriptionRegistry is now a 'sessionId -> subscriptionId -> (destination,selector)' map for faster lookups (previously 'sessionId -> destination -> set of (subscriptionId,selector)') closes gh-24395
Apparently you can have mutliple subscriptions with the same subscription-id and this change breaks that requirement. Specifically UserDestinationMessageHandler will reuse the same topic subscription message to create the session specific subscription to that topic, which means that according to which thread gets to insert the subscription first wins. |
We are using the spring-messaging to implement a STOMP server (using SimpleBrokerMessageHandler).
The Client will subscribe on 5 channel and everything is ok when there are only a few users.
However, when the online user is above ~ 700, the websocket channel is "out of response".
After analysis, I found many other thread has been "BLOCKED" by DestinationCache, as follows:
And part of the code are as follows:
As you can see, the code inside synchronized will traverse all subscription, which will cost too much time and block other Thread.
Also, the accessCache / updateCache is not works if the client has not success make the subscription, which will make the situation worse.
We try to increase the cache limit and it does't work for our case.
To solve the problem, we remove the DestinationCache and
reimplement an Map -> <sessionId -> subsId> inside SessionSubscriptionRegistry.
(in our own codebase of course)
After theses change, the server can handle more than 5K online users with no problem.
Meanwhile, I noticed that DefaultSubscriptionRegistry and DestinationCache has been there for many years.
So, I just wonder is it ok to make a pr?
Or the existing DestinationCache is good for some other reason?
The text was updated successfully, but these errors were encountered: