Introduce several performance and synchronization enhancements: - Implement `SeqBufferManager` to allow sequence number pre-allocation via Redis Lua scripts, reducing atomic increment overhead. - Add `PushWorker` to handle asynchronous message pushing using Redis Streams. - Implement incremental conversation synchronization via `ConversationVersionLog` to allow clients to fetch only recent changes. - Add support for Gzip compression in WebSocket communications to reduce bandwidth usage. - Update dependency injection and configuration to support these new components.
212 lines
6.7 KiB
Go
212 lines
6.7 KiB
Go
package cache
|
||
|
||
import (
|
||
"fmt"
|
||
)
|
||
|
||
// 缓存键前缀常量
|
||
const (
|
||
// 帖子相关
|
||
PrefixPostList = "posts:list"
|
||
PrefixPost = "posts:detail"
|
||
// HotRankZSet 热门榜(有序集合,member=post_id,score=归一化热度,仅存 TopN)
|
||
HotRankZSet = "posts:hot:zset"
|
||
// HotRankTopIDs 热门榜有序 post_id 列表(JSON []string,供分层缓存本地层命中)
|
||
HotRankTopIDs = "posts:hot:top_ids"
|
||
|
||
// 会话相关
|
||
PrefixConversationList = "conversations:list"
|
||
PrefixConversationDetail = "conversations:detail"
|
||
|
||
// 群组相关
|
||
PrefixGroupMembers = "groups:members"
|
||
PrefixGroupInfo = "groups:info"
|
||
|
||
// 未读数相关
|
||
PrefixUnreadSystem = "unread:system"
|
||
PrefixUnreadConversation = "unread:conversation"
|
||
PrefixUnreadDetail = "unread:detail"
|
||
|
||
// 已读位置相关(OpenIM 风格:缓存 hasReadSeq,用于 O(1) 未读数计算)
|
||
PrefixUserReadSeq = "user_read_seq"
|
||
|
||
// 用户相关
|
||
PrefixUserInfo = "users:info"
|
||
PrefixUserMe = "users:me"
|
||
|
||
// 频道相关(全量列表一条缓存,供 /channels、帖子 channel 填充共用)
|
||
PrefixChannelsAllList = "channels:all_list"
|
||
|
||
// 消息缓存相关
|
||
keyPrefixMsgHash = "msg_hash" // 消息详情 Hash
|
||
keyPrefixMsgIndex = "msg_index" // 消息索引 Sorted Set
|
||
keyPrefixMsgCount = "msg_count" // 消息计数
|
||
keyPrefixMsgSeq = "msg_seq" // Seq 计数器
|
||
keyPrefixMsgPage = "msg_page" // 分页缓存
|
||
keyPrefixMsgIdempotent = "msg_idem" // 消息幂等键
|
||
keyPrefixSeqBuffer = "seq_buf" // Seq 预分配缓冲区 Hash
|
||
)
|
||
|
||
// PostListKey 生成帖子列表缓存键
|
||
// postType: 帖子类型 (hot, follow, latest)
|
||
// page: 页码
|
||
// pageSize: 每页数量
|
||
// userID: 用户维度(仅在个性化列表如 follow 场景使用)
|
||
// HotRankZSetKey 热门榜 Redis ZSET 逻辑键(仅存 TopN,会经 normalizeKey 加前缀)
|
||
func HotRankZSetKey() string {
|
||
return HotRankZSet
|
||
}
|
||
|
||
// HotRankTopIDsKey 热门榜 Top 顺序 ID 列表键(会经 normalizeKey 加前缀)
|
||
func HotRankTopIDsKey() string {
|
||
return HotRankTopIDs
|
||
}
|
||
|
||
func HotRankZSetChannelKey(channelID string) string {
|
||
return fmt.Sprintf("%s:ch:%s", HotRankZSet, channelID)
|
||
}
|
||
|
||
func HotRankTopIDsChannelKey(channelID string) string {
|
||
return fmt.Sprintf("%s:ch:%s", HotRankTopIDs, channelID)
|
||
}
|
||
|
||
func PostListKey(postType string, userID string, page, pageSize int) string {
|
||
if userID == "" {
|
||
return fmt.Sprintf("%s:%s:%d:%d", PrefixPostList, postType, page, pageSize)
|
||
}
|
||
return fmt.Sprintf("%s:%s:%s:%d:%d", PrefixPostList, postType, userID, page, pageSize)
|
||
}
|
||
|
||
// PostDetailKey 生成帖子详情缓存键
|
||
func PostDetailKey(postID string) string {
|
||
return fmt.Sprintf("%s:%s", PrefixPost, postID)
|
||
}
|
||
|
||
// ConversationListKey 生成会话列表缓存键
|
||
func ConversationListKey(userID string, page, pageSize int) string {
|
||
return fmt.Sprintf("%s:%s:%d:%d", PrefixConversationList, userID, page, pageSize)
|
||
}
|
||
|
||
|
||
// GroupMembersKey 生成群组成员缓存键
|
||
func GroupMembersKey(groupID string, page, pageSize int) string {
|
||
return fmt.Sprintf("%s:%s:page:%d:size:%d", PrefixGroupMembers, groupID, page, pageSize)
|
||
}
|
||
|
||
|
||
|
||
// UnreadSystemKey 生成系统消息未读数缓存键
|
||
func UnreadSystemKey(userID string) string {
|
||
return fmt.Sprintf("%s:%s", PrefixUnreadSystem, userID)
|
||
}
|
||
|
||
// UnreadConversationKey 生成会话未读总数缓存键
|
||
func UnreadConversationKey(userID string) string {
|
||
return fmt.Sprintf("%s:%s", PrefixUnreadConversation, userID)
|
||
}
|
||
|
||
// UnreadDetailKey 生成单个会话未读数缓存键
|
||
func UnreadDetailKey(userID, conversationID string) string {
|
||
return fmt.Sprintf("%s:%s:%s", PrefixUnreadDetail, userID, conversationID)
|
||
}
|
||
|
||
|
||
// ChannelsAllListKey 频道全量列表缓存键(含未启用,供 MapByIDs 解析历史帖子 channel)
|
||
func ChannelsAllListKey() string {
|
||
return PrefixChannelsAllList
|
||
}
|
||
|
||
// InvalidateChannelList 失效频道列表缓存(管理端增删改频道后调用)
|
||
func InvalidateChannelList(c Cache) {
|
||
c.Delete(ChannelsAllListKey())
|
||
}
|
||
|
||
// InvalidatePostList 失效帖子列表缓存
|
||
func InvalidatePostList(cache Cache) {
|
||
cache.DeleteByPrefix(PrefixPostList)
|
||
}
|
||
|
||
// InvalidatePostDetail 失效帖子详情缓存
|
||
func InvalidatePostDetail(cache Cache, postID string) {
|
||
cache.Delete(PostDetailKey(postID))
|
||
}
|
||
|
||
// InvalidateConversationList 失效会话列表缓存
|
||
func InvalidateConversationList(cache Cache, userID string) {
|
||
cache.DeleteByPrefix(PrefixConversationList + ":" + userID + ":")
|
||
}
|
||
|
||
|
||
// InvalidateGroupMembers 失效群组成员缓存
|
||
func InvalidateGroupMembers(cache Cache, groupID string) {
|
||
cache.DeleteByPrefix(PrefixGroupMembers + ":" + groupID)
|
||
}
|
||
|
||
|
||
// InvalidateUnreadSystem 失效系统消息未读数缓存
|
||
func InvalidateUnreadSystem(cache Cache, userID string) {
|
||
cache.Delete(UnreadSystemKey(userID))
|
||
}
|
||
|
||
// InvalidateUnreadConversation 失效会话未读数缓存
|
||
func InvalidateUnreadConversation(cache Cache, userID string) {
|
||
cache.Delete(UnreadConversationKey(userID))
|
||
}
|
||
|
||
// InvalidateUnreadDetail 失效单个会话未读数缓存
|
||
func InvalidateUnreadDetail(cache Cache, userID, conversationID string) {
|
||
cache.Delete(UnreadDetailKey(userID, conversationID))
|
||
}
|
||
|
||
|
||
// ============================================================
|
||
// 消息缓存 Key 生成函数
|
||
// ============================================================
|
||
|
||
// MessageHashKey 消息详情 Hash key
|
||
func MessageHashKey(convID string) string {
|
||
return fmt.Sprintf("%s:%s", keyPrefixMsgHash, convID)
|
||
}
|
||
|
||
// MessageIndexKey 消息索引 Sorted Set key
|
||
func MessageIndexKey(convID string) string {
|
||
return fmt.Sprintf("%s:%s", keyPrefixMsgIndex, convID)
|
||
}
|
||
|
||
// MessageCountKey 消息计数 key
|
||
func MessageCountKey(convID string) string {
|
||
return fmt.Sprintf("%s:%s", keyPrefixMsgCount, convID)
|
||
}
|
||
|
||
// MessageSeqKey Seq 计数器 key
|
||
func MessageSeqKey(convID string) string {
|
||
return fmt.Sprintf("%s:%s", keyPrefixMsgSeq, convID)
|
||
}
|
||
|
||
// MessagePageKey 分页缓存 key
|
||
func MessagePageKey(convID string, page, pageSize int) string {
|
||
return fmt.Sprintf("%s:%s:%d:%d", keyPrefixMsgPage, convID, page, pageSize)
|
||
}
|
||
|
||
// InvalidateMessagePages 失效会话消息分页缓存
|
||
func InvalidateMessagePages(cache Cache, conversationID string) {
|
||
cache.DeleteByPrefix(fmt.Sprintf("%s:%s:", keyPrefixMsgPage, conversationID))
|
||
}
|
||
|
||
// MessageIdempotentKey 消息幂等键 (clientMsgID -> server MsgID)
|
||
func MessageIdempotentKey(senderID, clientMsgID string) string {
|
||
return fmt.Sprintf("%s:%s:%s", keyPrefixMsgIdempotent, senderID, clientMsgID)
|
||
}
|
||
|
||
// SeqBufferKey seq 预分配缓冲区 Hash key
|
||
func SeqBufferKey(convID string) string {
|
||
return fmt.Sprintf("%s:%s", keyPrefixSeqBuffer, convID)
|
||
}
|
||
|
||
|
||
// UserReadSeqKey 用户已读位置缓存键(OpenIM 风格 SEQ_USER_READ:{convID}:{userID})
|
||
func UserReadSeqKey(convID, userID string) string {
|
||
return fmt.Sprintf("%s:%s:%s", PrefixUserReadSeq, convID, userID)
|
||
}
|
||
|