# Inifinichat **Repository Path**: afuna/inifinichat ## Basic Information - **Project Name**: Inifinichat - **Description**: 一个基于golang的即时通讯系统 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-10-15 - **Last Updated**: 2025-05-14 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README - 用户登录/注册:MD5+盐 - 私聊 - 添加好友 - 查询方面引入Bloom Fliter,防止不存在好友ID持续攻击 - 解决缓存穿透:布隆过滤器实现(好友添加那里,将所有合法的friend_id加入布隆过滤器) - 模糊查询 - mysql:like - 消息多选发送:引入客户端管道,减少并发 - 客户端方面:消息塞入管道,由一个goroutine去负责发送给服务端,实现了并发控制,这样每次发送消息就不用每次都创建一个goroutine去发送 - 系统上线:所有userId进入redis - 用户请求共同好友:返回共同好友ID - 未读消息:引入rabbitmq - 广播、群聊 - 群聊创建、邀请、接受 - 共同好友推荐 - 用户登录:friends数据刷新到redis - 用户id=1查询id=2的好友: - 先看看redis中id = 1和id=2的friends是否都存在,不存在去mysql中查 - 返回id = 1 与 id = 2的共同好友 - mysql-redis双写一致性:用户添加好友成功后,先删除redis,再更新mysql,延迟一段时间后再更新redis - 上线通知:rabbitmq消息分发 - 定点消息 [redis延迟队列] 设定三个延迟队列zset分别接收1分钟内的、小于10分钟,大于1hour的消息,1min的队列每隔1s检查一次,大于1min小于10min的每隔1min检查一次,如果在10min的那条队列中出现了在1min内的消息,则加入1min的队列 当用户提交延迟消息时,系统会通过 `PushDelayedMessage` 方法将该消息添加到对应的 Redis 有序集合(ZSET)中,并设置 score 为未来的时间戳。随后,系统中的 `ProcessDelayedMessages` 每秒运行一次,调用 `processMessages` 方法,通过 `ZRANGEBYSCORE` 指令查找所有 score 小于等于当前时间戳的消息。查找到这些到期消息后,系统会通过 `sendMessage` 方法进行转换并发送,最后使用 `ZREM` 从 ZSET 中删除已发送的消息,确保消息不会重复发送。 - 聊天记录:索引优化,对send_time字段添加索引 [读取消息流程] 1. 查 zset:p2pMsg_sid_tid,有数据返回; 这里可以用一个p2pMsg_sid_tid_exist标记是否从mysql中同步过 2. 若 zset nil,则查 MySQL -> 写入 zset -> 标记 set: p2pMsg_sid_tid 同步状态。 [发送消息流程] 1. 消息写入 zset:p2pMsg_sid_tid(score 为 ts); 2. 消息写入之前,需要同步服务器时间写入SendTime 这里有个问题:如果未读消息在redis中不在数据库中,is_read无法准备定位到消息并置为true 解决方案:UUID 3. 加入活跃线程 [守护线程:每1分钟执行] 1. timestamp := now; 2. ZRANGEBYSCORE 获取 <= timestamp 的消息; 3. 过滤 set: p2pMsg_sid_tid 中的(已刷入); 4. 将未刷入的写入 MySQL,写入成功后加入set: p2pMsg_sid_tid 5. 延迟2s后:删除 <= timestamp 的 zset 数据 + hash 清理。 这里需要将exist标记为false 6. 这里刷入成功后需要移除活跃会话, 但是有个问题,当守护线程在写入后,这个zset被从活跃线程中移除了,但又同时有数据写入,这样就会丢失数据 解决:设置一个 “最后活动时间” 哈希(例如 hash:lastActiveTime); 只有当某个 zsetKey 超过一定时间(如 2 分钟)都无新写入,才移除活跃集合。 - 登录/登出(包括异常断开) 通知 - 监视TCP连接 - TCP保活 + 断线重连 - redis分布式锁应用:限制单个客户端登录