目录 start

  1. 设计公告通知未读
    1. 1. 关联表存 已读或未读
    2. 2. Redis Set 存储 未读/已读
    3. 3. Redis bitmap 存储 未读/已读
    4. 4. 客户端存储已读

目录 end|2021-01-15 21:26|


设计公告通知未读

需求: 发布公告,用户维度的已读未读,有一键已读功能,首条未读需求

1. 关联表存 已读或未读

存储

  • 公告表
  • 公告和用户关联表

存已读

  1. 优点: 新增无需操作关联表,利于统计分析
  2. 缺点: 一键已读就需要未读的关联数据批量写入,数据量会持续增长,数据不够稀疏不便建立索引

存未读

  1. 优点: 新增无需操作关联表,利于统计分析
  2. 缺点:
    • 新增公告时,大量数据写入(为每一个用户新增),新注册用户需要补全部数据
    • 已读则删除数据(使用物理删除可能存在缺页问题,使用逻辑删除则数据持续增长)

2. Redis Set 存储 未读/已读

存储

  • 公告表
  • Redis存储 Set key为用户id,value为公告id

存已读

  1. 优点:
    • 新增公告无需操作关联关系
    • 用户查询公告未读状态,只需一次请求
  2. 缺点:
    • 全部已读需要查出所有公告id插入Redis Set
    • Redis占用的内存会持续增长

存未读

  1. 优点: 用户查询公告状态,只需一次请求,全部已读也只需一次请求
  2. 缺点: 新增公告时需要遍历请求所有用户插入公告id

3. Redis bitmap 存储 未读/已读

存储

  • 公告表
  • Redis存储 key为公告id bitmap存已读的用户id
  • 所有公告分页查询时,先得到Mysql分页第一页的公告id,然后遍历查询Redis已读未读状态
  • 未读公告的分页,需要查询所有的公告id(组织注册时间后的公告), 遍历请求redis得到 未读的公告id, 再进入Mysql 使用 in 进行分页
  1. 优点: 新增公告无需维护关联关系
  2. 缺点:
    • 分页查看所有未读的需求会随着公告的增多循环次数会增多
    • 全部已读需要遍历所有公告
    • 随着用户数增多单个key占用的内存持续增长

可以通过存储用户最后一次 所有公告已读 的时间戳,减少循环次数


4. 客户端存储已读

存储

  • 公告表
  • 客户端 Cookie 或者 LocalStorage 存储已读的公告id
  1. 优点: 服务端存储运算压力减轻
  2. 缺点:
    • 首条未读查询接口需要传入已读的id列表,公告多的时候会导致SQL超长
    • 无法多端同步状态(其实也可以做,定时同步已读id列表),全部已读需要写入所有公告id到本地