目录 start
目录 end|2021-01-13 19:47|
设计公告通知未读
需求: 发布一个公告,需要记录用户维度的已读未读,有一键已读,展示首条未读 的功能。
1. 关联表存 已读或未读
存储
- 公告表
- 公告和用户关联表
存已读
- 优点: 新增无需操作关联表,利于统计分析
- 缺点: 一键已读就需要未读的关联数据批量写入,数据量会持续增长,数据不够稀疏不便建立索引
存未读
- 优点: 新增无需操作关联表,利于统计分析
- 缺点:
- 新增公告时,大量数据写入(为每一个用户新增),新注册用户需要补全部数据
- 已读则删除数据(使用物理删除可能存在缺页问题,使用逻辑删除则数据持续增长)
2. Redis Set 存储 未读/已读
存储
- 公告表
- Redis存储 Set key为用户id,value为公告id
存已读
- 优点:
- 新增公告无需操作关联关系
- 用户查询公告未读状态,只需一次请求
- 缺点:
- 全部已读需要查出所有公告id插入Redis Set
- Redis占用的内存会持续增长
存未读
- 优点: 用户查询公告状态,只需一次请求,全部已读也只需一次请求
- 缺点: 新增公告时需要遍历请求所有用户插入公告id
3. Redis bitmap 存储 未读/已读
存储
- 公告表
- Redis存储 key为公告id bitmap存已读的用户id
- 所有公告分页查询时,先得到Mysql分页第一页的公告id,然后遍历查询Redis已读未读状态
- 未读公告的分页,需要查询所有的公告id(组织注册时间后的公告), 遍历请求redis得到 未读的公告id, 再进入Mysql 使用 in 进行分页
- 优点: 新增公告无需维护关联关系
- 缺点:
- 分页查看所有未读的需求会随着公告的增多循环次数会增多
- 全部已读需要遍历所有公告
- 随着用户数增多单个key占用的内存持续增长
可以通过存储用户最后一次 所有公告已读 的时间戳,减少循环次数
扩展: Redis roaring bitmap 降低基数较大时bitmap的存储
4. 客户端存储已读
存储
- 公告表
- 客户端 Cookie 或者 LocalStorage 存储已读的公告id
- 优点: 服务端存储运算压力减轻
- 缺点:
- 查询首条未读的接口需要传入已读的id列表,公告多的时候会导致SQL超长
- 无法多端同步状态(其实也可以做,定时同步已读id列表),全部已读需要写入所有公告id到本地