StackExchange / StackExchange/StackExchange.Redis
How to limit memory usage and number of threads of pub sub at 15k QPS?
Nobody has claimed this yet.
- Dominant language
- C#
- Stars
- 6.2k
- Forks
- 1.6k
- Avg merge
- 1d 15h
- Merged PRs (30d)
- 43
Description
Background
- Problem: Memory usage keeps increasing when a client has subscribed to too many channels.
- Scale:
- Subscriptions: 3691 channels
- Message frequency: 0 to 4 messages per second per channel
- Peak network download rate: ~400 Mbps
- Estimated 99th percentile latency of callback: ~100 microseconds
- Environment:
- .NET 6.0
- StackExchange.Redis 2.7.33
ConnectionMultiplexerconfiguration:- ClientName
- ReconnectRetryPolicy
- SyncTimeout
- AsyncTimeout
Attempted Solutions and Findings
-
Garbage Collection: Forcing GC provides temporary relief but doesn't solve the issue.
-
Memory Profiling: Survived objects are primarily
Byte[]inChannelMessageQueue. -
Redis Server Queue Limit: Configuring a max size for the queue at the Redis Server doesn't help.
-
Source Code Digging: I see that ChannelMessageQueue creates an unbounded channel here. So we believe the SE Redis client is fetching from the server faster than our callbacks can process, thus accumulating a backlog on the client side.
-
Upvoting a similar question on Stack Overflow.
-
Process Splitting: The more processes we run for the same amount of subscriptions, the less combined memory usage and the higher CPU utilization rate.
Here are some numbers at 80% of the scale mentioned above.
As for the row for 4 processes, the memory growth only stops because the server queue has filled up and the server starts to disconnect the client.Number of Processes Peak Combined Memory (GB) Peak Thread Count 4 37 302 5 19 337 8 13.3 507 10 12.7 614 40 12.2 2184 ... ... ...
Questions and Considerations
- Memory Usage Limitation: What strategies can we employ to limit memory usage effectively? We prefer the client does not fetch items from the server fast enough and the server disconnects the client after the queue at the server exceeds a pre-configured size.
- Thread Count Optimization: How can we minimize the number of threads while maintaining performance?
- Allocation Optimization:
- Current: StackExchange.Redis allocates memory on the heap for new payloads.
- Hypothesis: Processing could be faster by reducing/eliminating heap allocation.
- Potential approach: Direct processing of messages from OS socket without an intermediate queue buffer.
We appreciate any insights or recommendations to address these challenges. Thank you for your assistance!
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with src/StackExchange.Redis/ChannelMessageQueue.cs at line 96 and investigate the reported ChannelMessageQueue Byte[] backlog under the .NET 6 and StackExchange.Redis 2.7.33 workload. The issue provides measurements and hypotheses but no concrete code change or acceptance condition, so the expected definition of done would need to be established first.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp, redis
- Domain
- backend, performance
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 20/100