Massive Group Chat Technical Solution: Breaking the Group Member Count Limit
Deep dive into JuggleIM's group design: how it supports 100,000-person super groups
Introduction
In IM systems, group chat is one of the most technically demanding scenarios.
A two-person private chat has simple, direct message-distribution logic. But when the group size grows to 1,000, 10,000, or even 100,000 members, the complexity grows geometrically:
- Sending a single message means "replicating" it to every group member
- Querying and maintaining the group member list becomes a performance bottleneck
- Message-ordering consistency is challenged
- Features like read receipts become much harder to implement
Today, let's dive into JuggleIM's group design and see how it solves these challenges at the architectural level, supporting massive groups and even larger.
1. The Essential Difference Between Group Chat and Private Chat
Before exploring the technical solution, we need to understand how group chat and private chat differ in essence.
Difference 1: Message Fan-out
Private chat is one-to-one: sending a message only needs to deliver it to one person.
Group chat is one-to-many: sending a message means delivering it to N people, where N can be dozens, hundreds, or even tens of thousands.
This is the so-called message fan-out problem. The larger the fan-out factor, the more system pressure.
Difference 2: Member Dynamics
The two sides of a private chat are fixed.
The members of a group chat are dynamic — people can join or leave at any time. This raises a question: when a message is sent, who should receive it? The members at send time, or the members at receive time?
Difference 3: State Maintenance
Private chat mainly maintains conversation state and message state.
Group chat additionally needs to maintain:
- Group basic info (name, avatar, announcement)
- Member list and roles (owner, admin, regular member)
- Member permissions (mute, blacklist)
- Group settings (whole-group mute, join verification)
The more complex the state, the harder it is to maintain consistency.
2. JuggleIM's Group Architecture
JuggleIM's group functionality is handled by the Group service, which works with the Message, Conversation, and other services to deliver the complete group chat feature set.
Core Module Division
The Group service internally contains over a dozen Actors, each with a specific responsibility:
Group Management
- DissolveGroupActor: dissolves a group
- UpdGroupInfoActor: updates group info
Member Management
- AddMemberActor: adds a group member
- DelMemberActor: removes a group member
- QryGroupMembersActor: queries the group member list
- CheckGroupMemberActor: verifies group membership
Permission Management
- GroupMuteActor: group-mute settings
- GroupMemberMuteActor: per-member mute
- GroupMemberAllowActor: member whitelist
Message Processing
- GroupMsgActor: group message processing
- ImportGroupHisMsgActor: imports history messages
Data Model Design
Group Basic Info Table
Stores the group's basic attributes, one record per group:
| Field | Description |
|---|---|
| group_id | Group ID |
| group_name | Group name |
| group_portrait | Group avatar |
| is_mute | Whether the whole group is muted |
| created_time | Creation time |
| updated_time | Update time |
| app_key | App identifier |
Index design: (app_key, group_id) unique index.
Group Member Table
Stores group-member relationships, one record per member:
| Field | Description |
|---|---|
| group_id | Group ID |
| member_id | Member ID |
| member_type | Member type (owner / admin / regular) |
| is_mute | Whether muted |
| is_allow | Whether on the whitelist |
| mute_end_at | Mute end time |
| created_time | Join time |
Index design:
- (app_key, group_id, member_id) unique index
- (app_key, member_id, group_id) auxiliary index for querying which groups a user has joined
This design makes both "list the groups a user has joined" and "list the members of a group" efficient.
3. The Complete Pipeline of Sending a Group Message
What happens inside the system when a user sends a message in a group?
Step 1: Message Receipt and Validation
The message sent by the user reaches the ConnectManager, which routes it to GroupMsgActor.
Validation 1: Member Validation
- Verify that the sender is still a group member
- If already kicked out, reject the send
Validation 2: Mute Validation
- Check whether the whole group is muted
- If so, check whether the sender is on the whitelist
- Check whether the sender is individually muted
If validation fails, the corresponding error code is returned, and the client can prompt the user.
Step 2: Message Storage
Once validation passes, the message is persisted:
Store in the history message table
- Write to the
g_hismsgstable (group-chat history messages) - Generate a globally unique message ID
- Record send time, message type, and content
Record a group member snapshot
- Associate the message with the group member list at send time
- This ensures there is a reliable record for "who should have received this message"
Step 3: Conversation Update
Update the sender's conversation list:
- Update the latest message
- Update the conversation time
- Ensure the group conversation appears at the top of the list
Step 4: Message Distribution
This is the most critical step for group messages — delivering the message to all group members.
Get the member list
- Query the member table for all current group members
Filter online members
- Query the connection manager to see which members are online
- Distinguish online from offline members
Online push
- Construct a push message for each online member
- Deliver directly via the long connection
Offline handling
- Write to the inbox, waiting for the user to come online and pull
- Trigger a push notification
Step 5: Return Confirmation
Return a success ACK to the sender, containing:
- The server-generated message ID
- The server timestamp
4. Performance Optimizations for Large-Group Scenarios
The above flow is fine for small groups, but when the group size reaches tens of thousands, every step can become a bottleneck. JuggleIM has done many optimizations.
Optimization 1: Paged Member Query
For a 10,000-person group, returning the entire member list at once puts a lot of pressure on the database and network.
JuggleIM uses paged queries:
- The client passes paging parameters when requesting
- The server returns members page by page
- Supports filtering by member type (e.g. admins only)
This way, the client can load on demand, improving the experience while reducing server pressure.
Optimization 2: Batch Writes
Group message distribution involves a lot of database writes (one record per member's inbox).
JuggleIM uses a batch write strategy:
- Combine multiple records into a single SQL execution
- Reduce database connection overhead
- Significantly improve write throughput
Optimization 3: Async Distribution
For large groups, synchronously waiting for all members to be delivered causes send timeouts.
JuggleIM uses async distribution:
- The ACK is returned immediately after the message is stored
- Distribution happens asynchronously
- Failed deliveries are guaranteed via a retry mechanism
This way, the sender's perceived latency is very low, and the user experience is good.
Optimization 4: Push Aggregation
Group messages can trigger many push notifications. If a group has multiple messages in a short time, users would get a "spam flood" of notifications.
JuggleIM supports push aggregation:
- Multiple messages within a certain time window are merged into one push
- The push text shows "N new messages in the group"
- Reduces disturbance to the user
Optimization 5: Group Member Caching
Frequently querying the database for the group member list is expensive.
JuggleIM uses caching to speed it up:
- Member lists of hot groups are cached in memory
- The cache is updated on member changes
- Periodically refreshed to ensure consistency
5. Group Snapshot Mechanism
Group members are dynamic, which raises a question: who should historical messages be shown to?
Consider this scenario:
- Xiao Ming sends a message in the group
- 1 minute later, Xiao Hong joins the group
- Should Xiao Hong see the message Xiao Ming just sent?
Different IM products have different strategies. JuggleIM uses the group snapshot mechanism to record the group member state at the time a message is sent.
Purpose of Snapshots
The snapshot records the group member list at the instant a message is sent. This enables:
- Precisely knowing who should have received the message
- Accurate "denominator" for read-receipt calculation
- A basis for message audit and traceability
Snapshot Storage
JuggleIM uses the grpsnapshots table to store group snapshots:
| Field | Description |
|---|---|
| group_id | Group ID |
| created_time | Snapshot creation time |
| snapshot | Snapshot content (member list) |
The snapshot content is stored as binary data and compressed to take up less space.
When Snapshots Are Generated
Not every message needs to generate a snapshot (that would be too storage-expensive). JuggleIM's strategy:
- The message record references the snapshot's timestamp
- When querying which members correspond to a message, find the nearest snapshot
- Important messages (e.g. with read-receipt requirements) can trigger a new snapshot
6. Group Read-Receipt Design
In enterprise scenarios, group read receipts are a must-have — senders need to know who has read the message.
Design Challenges
Read receipts in large groups are challenging:
- A 10,000-person group, with one read record per person, creates huge data volume
- Real-time querying of the read count must be efficient
- Detailed read-status queries (who read, who didn't) need to be supported
JuggleIM's Solution
Read-record table design
readinfos table:
- msg_id: message ID
- group_id: group ID
- member_id: member ID
- created_time: read time
Index design supports:
- Query the list of members who have read a given message
- Query the list of messages a given member has read
Read-count optimization
The history message table has a read_count field, which caches the current read count.
- The count is incremented on each read report
- Queries return this value directly, no need for real-time aggregation
Batch reporting
Instead of reporting each read individually, the client reports in batches:
- Reports all messages read up to a given time point
- The server processes them in batches, reducing request count
7. Group Message Ordering Consistency
In a distributed system, ensuring message ordering is a challenge.
Problem Scenario
Consider this scenario:
- A and B send messages in the group almost simultaneously
- A's message reaches the server first, getting timestamp T1
- B's message reaches the server later, getting timestamp T2 (T2 > T1)
- But during network transmission, B's message reaches C's client first
C sees the order B→A, but the actual order should be A→B.
JuggleIM's Guarantees
JuggleIM ensures ordering through these mechanisms:
Server-side sorting
- Messages are sorted by server timestamp
- All clients sort messages by timestamp when pulling
Client-side local sorting
- The client re-sorts messages by timestamp after receiving them
- Even if the arrival order is wrong, the displayed order is correct
Message sequence number
- In addition to timestamps, messages have an auto-incrementing sequence number
- Sequence numbers within a group strictly increase
- Clients can detect missing messages
8. Other Advanced Group Features
In addition to core messaging, JuggleIM's groups support many advanced capabilities.
Group Management
- Group info update: modify group name, avatar, announcement
- Group dissolution: the owner can dissolve the group, cleaning up related data
- Member settings: each member can set a group nickname, do-not-disturb
Permission Control
- Member roles: owner > admin > regular member
- Mute functions: whole-group mute, individual mute, timed mute
- Whitelist: when muted, allow specific members to speak
Member Extended Info
The groupmemberexts table can store extended attributes for members:
- Group nickname
- Join method (invite / scan / search)
- Custom tags
9. Extreme Scenario: 100,000-Person Groups
When a group reaches 100,000 members or more, additional considerations are required:
Adjusted Message Distribution Strategy
- Consider using message queues for async processing
- Sharded distribution, parallel processing across multiple nodes
- Differentiated delivery, VIP users first
Storage Optimization
- Consider sharding the member table (by group_id hash)
- Consider hot/cold separation for history messages
- Consider incremental storage for snapshots instead of full snapshots
Business-Level Constraints
- Limit message-send frequency
- Simplify message types (e.g. text-only)
- Read receipts may need to be downgraded or disabled
Super-large group scenarios are relatively special and usually require custom optimization based on specific business needs.
Project URL: https://github.com/juggleim/im-server