feat(core): optimize performance and reliability through batching and redis-backed unread counts
All checks were successful
Build Backend / build (push) Successful in 2m7s
Build Backend / build-docker (push) Successful in 1m51s

This commit introduces several significant architectural improvements to enhance system performance, scalability, and reliability:

- **Performance Optimization (N+1 Problem Resolution)**: Implemented batching mechanisms across `MessageHandler`, `ChatService`, `GroupService`, `MessageService`, and `UserService`. This replaces multiple individual database/cache queries with single batch operations for fetching unread counts, last messages, participants, and user information.
- **Enhanced Unread Count Management**: Migrated unread count tracking to a Redis Hash-based approach (`unread#️⃣{userID}`). This allows for atomic increments/decrements and efficient retrieval of both individual conversation unread counts and total unread counts for a user.
- **Improved Message Sequencing**: Integrated Redis-based sequence (`seq`) pre-allocation for messages to ensure strict ordering and reduce database contention during high-concurrency message creation.
- **Push Service Reliability**: Refactored the push notification system to include persistent `PushRecord` tracking. Added a recovery mechanism (`recoverPendingPushes`) to reload pending notifications from the database upon service startup, ensuring better delivery guarantees.
- **WebSocket Reliability**: Updated the WebSocket hub to move away from in-memory history replay in favor of a client-driven synchronization model (`sync_required` event and `ack` handling), reducing memory overhead and improving connection stability.
- **Cache Layer Enhancements**: Added `HIncrBy` and `IncrBySeq` to the `Cache` interface and its implementations (`RedisCache`, `LayeredCache`) to support the new unread and sequence management logic.
This commit is contained in:
2026-05-04 18:31:03 +08:00
parent ee78071d4d
commit 90c57f1a1c
18 changed files with 752 additions and 218 deletions

View File

@@ -27,6 +27,7 @@ type GroupRepository interface {
UpdateMember(member *model.GroupMember) error
RemoveMember(groupID string, userID string) error
GetMemberCount(groupID string) (int64, error)
GetMemberCountBatch(ctx context.Context, groupIDs []string) (map[string]int64, error)
IsMember(groupID string, userID string) (bool, error)
GetUserGroups(userID string, page, pageSize int) ([]model.Group, int64, error)
@@ -225,6 +226,34 @@ func (r *groupRepository) GetMemberCount(groupID string) (int64, error) {
return count, err
}
// GetMemberCountBatch 批量获取多个群的成员数量
func (r *groupRepository) GetMemberCountBatch(ctx context.Context, groupIDs []string) (map[string]int64, error) {
result := make(map[string]int64, len(groupIDs))
if len(groupIDs) == 0 {
return result, nil
}
type row struct {
GroupID string
Count int64
}
var rows []row
err := r.db.WithContext(ctx).
Model(&model.GroupMember{}).
Select("group_id, COUNT(*) as count").
Where("group_id IN ?", groupIDs).
Group("group_id").
Scan(&rows).Error
if err != nil {
return nil, err
}
for _, r := range rows {
result[r.GroupID] = r.Count
}
return result, nil
}
// IsMember 检查是否是群成员
func (r *groupRepository) IsMember(groupID string, userID string) (bool, error) {
var count int64