全部基于一套redis逻辑,数据定时延迟落地
点赞收藏由于有取消和新增,复杂一些,浏览记录存粹新增,简单些
问题1:
取消点赞到全部取消时,会出现两个问题.
一是缓存穿透,由于zset为空时查出来的是null,会穿透缓存查库.
二是数据不一致,假定每日定时持久化时间点为00:00,前一日对一个资源进行了点赞操作,今日取消点赞,此时zset为空,走查库逻辑,但是库中数据又是前一天的数据,今日的取消操作数据还在缓存中未落地,导致查询出来此资源还是已点赞状态.
已解决缓存穿透以及数据不一致问题,第一次查询查库时,放一个空对象,score为0放入zset中,后面每次走缓存查询都删除一次空对象,total数量每次都减1
问题2:
定时持久化,之前采用的是insert on duplicated key插入存在便更新,但是老大提出之前项目遇到过死锁问题不能使用on duplicated key.问题大概是若高并发情况下对同一个唯一键数据进行操作,有回滚的情况下,会造成死锁问题.虽然我这块逻辑上是不会存在此类问题,但不可避免未知错误的发生具体可参考此篇文章
解决方案:采用redis缓存已存储的记录,具体格式为hash(resourceId,userId),判断需要持久化的记录是update还是insert,如果需要保证缓存的已存储记录一致,最好的方式是在持久化前查一遍库(此方案我一直觉得不是很好,但是暂时想不出性能更好的方案)
以点赞为例:
核心:bitmap,持久化缓存队列,zset,分布式锁
一.点赞/取消点赞
1.根据bitmap判断是否点赞
2.取相反状态,设置bitmap
3.存入缓存队列
4.判断查询缓存是否存在,不存在便初始化查询缓存
5.若点赞:zadd,若取消点赞,remove.此处操作的实体要注意不能把时间插进去,要保证相同资源的所有属性一致,才能够remove掉对应的资源
二.查询缓存
1.分页查缓存
2.缓存为空,查库查所有,所有塞缓存,分页
三.定时数据落地
此套方案基本上是基于redis制作,极度依赖redis,必须开启RDB或AOF持久化机制,否则宕机的话会造成大批量数据丢失,特指bitmap(虽然也可以在宕机后跑一边脚本把bitmap设好)