DB缓存一致性

直接硬核干货,去掉前戏。redis

方案大体说明数据库

1:假设对redis中存在一对key,value的对应关系是 key=money,value=666缓存

2:当修改线程修改key时先将key设置成value=666_write,(这里须要说明的是:线上实际应用能够将_wirte改为很是复杂的UUID等字符串,只要保证不要和线上实际set的值冲突便可,例如666_write_@#$%^&*_qwerty服务器

3:当读取时发现key的存在读取标识666_read_@#$%^&*_qwerty,发现有其余读取线程已经在从DB中load数据了,这种状况休眠一下重试就能够了,不须要从DB中load数据,由于这样作会引发大量线程访问数据库引起灾难。若是不存在读取标识则判断一下是否含有写入标识若不存在则直接返回数据便可,若存在读取标识将全部读取标识去掉以后看看是否为空,不为空则返回当前value便可。并发

4:为何一个字符串会出现多个写入标识呢。假设线程A和B对 key=money,value=666的数据进行修改,那么线程A将value变成了value=666_write_@#$%^&*_qwerty,这个时候线程B也来掺和一下,会变成666_write_@#$%^&*_qwerty_write_@#$%^&*_qwerty,这个地方是须要注意的。同时也会出现业务数据被删除了这个时候加上了修改标记,value变成_write_@#$%^&*_qwerty这种只有修改标识可是没有业务数据的的状况。线程

5:还有一个须要特别注意的是setnx在客户端2.8以后 支持超时时间,这块须要设置一个超时的时间处理,防止读取线程setnx以后服务器挂了,引发永远没法同步的问题,至于超时时间设置成多少和实际环境有关。设计

6:同时也会出现_read_@#$%^&*_qwerty_write_@#$%^&*_qwerty这种同时带有read和write的状况,出如今并发读取的场景。对象

7:这种须要DB缓存强一致读写应该在master中进行,不该该在slave中读,颇有可能出现延迟致使问题blog

8:redis主从切换这种极端的场景出如今读取或者修改的状况下也会引发数据不一致的问题,通常上线这种问题的解决方案是跨机房多机缓存或者容许短时间内不一致的job任务定时校验兜底等。字符串

总结起来就是一下几点:

当存在_read_@#$%^&*_qwerty时说明有读取线程正请求DB,重新load对象。

当存在_write_@#$%^&*_qwerty时说明当前key正在被写入。

当存在多个_write_@#$%^&*_qwerty时 存在并发修改。

当有_read_@#$%^&*_qwerty和_write_@#$%^&*_qwerty时 存在读和写的并发。

 

读取详细设计方案

 

 更新时设计方案:

其余问题加群讨论吧 QQ群号:825199617。

相关文章
相关标签/搜索