简单公告
简单公告
基于客户端的公告实现
招新平台的公告设计确实简单,除了发布、查询、编辑功能以外,对用户的已读/未读状态维护得并不完整,用户的已读状态在客户端保存,通过轮询发送本地已读公告id请求服务端未读id,如果有新未读id,直接显示。
在赶进度/人手不足状态下是可理解的,因为从业务角度讲,公告的已读状态属于不重要内容,不用担心丢失或被篡改,因此可以选择放在客户端,但问题是用户更换设备登录/更换浏览器登录就需要重新读一遍公告,体验不好,这里先分析一下招新平台现在的实现方式。
根据分析,只需要维护:公告的增删改查、根据已读id查询未读id这两大块功能。
增删改查设计较为简单,不再赘述,唯一需要注意的地方是接口鉴权,一定要验证管理员身份再支持公告的修改,否则会出大问题,具体参考RBAC权限管理。
对于根据已读id查询未读id这个功能,需要注意不必查询全部id后再在业务层做排除,可以直接使用数据库提供的不等于功能快速排除。
正确公告系统的设计
重点在已读/未读状态的维护,个人认为可以分为两种,推和拉。推模式为每个用户维护一个公告已读情况,拉模式为每个公告维护一个已读用户情况,应该根据用户数量和公告数量合理选择。
推模式
Redis bitmap 存储 未读/已读
首先,其实未读已读就是一个0/1的标记而已,可以维护一个Bitmap来实现,0未读,1已读。但是如果公告id使用雪花id来实现的话,会出现id过长的问题,因此需要配套为每个公告设置一个自增id。
然后,每当用户阅读一个公告,就更新bitmap对应位为1,这样可以方便的识别公告的已读未读情况。
放不下了怎么办?位图搞大点吧。。。。例如搞一个25565位的位图怎么都够了吧。
拉模式
Redis bitmap 存储 未读/已读
- Redis存储 key为公告id bitmap存已读的用户id
所有公告分页查询时,先得到Mysql分页第一页的公告id,然后遍历查询Redis已读未读状态
未读公告的分页,需要查询所有的公告id(组织注册时间后的公告), 遍历请求redis得到 未读的公告id, 再进入Mysql 使用 in 进行分页
-
优点: 新增公告无需维护关联关系
-
缺点:
- 分页查看所有未读的需求会随着公告的增多循环次数会增多
- 全部已读需要遍历所有公告
- 随着用户数增多单个key占用的内存持续增长
可以通过存储用户最后一次所有公告已读的时间戳,减少循环次数
扩展: Redis roaring bitmap 降低基数较大时bitmap的存储