Scene
设计一个聊天系统,具备如下功能:
- 两个用户互相发消息
- 群聊
- 用户在线状态
Service
- Message service 存储,读取消息
- Push Service 推送消息
Storage
-
Thread Table 会话表,存储会话基本信息 | column | notes | | --------- | ----------- | | id | primary key | | avatar | 头像| | name | 群聊名称|
-
User Thread Table 用户会话表,存储与用户相关的会话信息 | column | notes | | --------- | ----------- | | id | primary key | | thread_id | 会话id| | unread_cnt | 未读消息数量| | is_muted | 是否免打扰|
-
Message Table 消息表 | column | notes | | --------- | ----------- | | id | primary key | | thread_id | 会话id| | user_id | 用户id| | content | 内容| | publish_at | 消息发送时间|
用户读取Message
select * from message_table
where thread_id = xx
order by publish_at desc
limti 20
消息的发送与消息的读取
- 客户端A请求推送系统地址
- 客户端A与推送吗系统建立连接
- B发送消息给A
- 消息系统存储B的消息后,通知推送系统
- 推送系统推送消息通知(可以直接将消息推送过去或A在收到消息后主动pull数据)
Scale
推送系统优化
当群了人数较多时,如何不向哪些不在线的客户端发推送消息通知。 增加一个channel服务,维护用户的存活信息。
- 每个Thread对应一个Channel
- 用户上线时,订阅相关Channel;如果用户下线,push服务会得知用户掉线,通知channel service将用户从某个channel移除
- Message service收到消息后,通知Channel Service。
- Channel Service 查询某个channel当前订阅用户,将数据推送给push service
- Push service push通知消息
多机登陆限制
在session中记录客户端信息 用户从新的客户端登录时,查询是否有其他设备处于登陆态
- 如果没有,直接创建session
- 如果有,将已存在的session设置为过期或删除,并push消息让已登陆的设备logout
好友在想状态
-
Pull :用户主动告诉服务器是否在想
-
Push :服务器查询用户是否在线
建议使用 Pull ,客户端定期向服务端发送心跳。Pull模型的实现会更加简单。