场景
- 客户端为app,登录这个app的用户每天都会收到10条系统消息(有重要消息和普通消息分类),当用户点击具体某一条消息时,这条消息在未读记录里面消失。
- 现在使用这个app的人有100万,每天登录在线的人员有50多万。
- 后台有个发布系统消息的功能,请设计这个功能。
目标实现:后台发布消息成功后,客户端能及时收到消息记录,并且用户切换手机登录,未读的重要消息不会丢失。
提示:从数据库,核心逻辑上去设计。
这是最近遇到的一个面试题,当时答的并不好。回头想想,还是感觉当时太紧张。晚上吃饭的时候,稍微思考了下,感觉自己还是太笨。现在把经验分享给大家:
数据库设计:
注意:这里不考虑数据库,表设计的优化方案。只考虑关键字段
用户表 user
-
user_id
用户id(主键) -
name
用户昵称 -
msg_version
消息版本,存储最新消息ID 默认为0
...
消息表
-
id
消息ID (自增主键) -
info
消息内容 -
create_time
发布时间 -
type
消息类型 1 普通消息,可丢失 2重要消息,不能丢失,(用户未读的情况下,重要消息不能丢失)
用户登录获取列表
当用户第一次登陆app的时候,检测用户表
msg_version
字段 如果为0,则获取最新的10条消息,并且将msg_version
字段更新为 最新那条消息的id。当用户非第一次登录,则获取大于msg_version 所有未读日志。如果考虑用户已经很久没有登录,可以限制最新n条数据给这个用户。
将上述描述中的消息读取后,存储到本地。
如果是重要消息,每次获取到的未读的重要消息要同时加入redis集合(集合key设计:no_read_msg_{user_id},值为 [msg_id1,msg_id1...])。
使用集合目的是防止重要消息重复加入到里面。也可以用散列,string来存储。但是尽量不要用关系型数据库。
读取消息
当用户点击了某条消息后,从本地存储中删除这条消息。如果这条消息为重要消息,同时操作redis集合,将该值删除。
有新消息
获取msg_id大于msg_version 的所有新消息,更新msg_version 字段,并且将新消息存储到本地,把重要消息存储到集合。
切换手机
获取msg_id大于msg_version 的所有新消息+存储到集合中未读的重要消息。更新msg_version 字段,并且重要消息写入到集合。