分类:
强一致性: 更新完成后,任何多个后续进程或线程读到的都应该是最新的值。常常需要牺牲可用性
弱一致性: 不保证读到最新值,也不承诺多久后可以读到
最终一致性: 弱一致性的特定形式,系统保证没有后续更新的前提下,系统最终返回的是上一次更新操作的值。
在工程实践中,为保证可用性,常常把强一致性需求转换为最终一致性的需求。
1、数据库主从同步问题
同步方式如下图所示:
解决一致性问题的方法:
1、异步复制:客户端提交之后就不用管了,直接返回结果给客户端。这种方法效率高,但是数据一致性却是最弱的
2、半同步复制:客户端提交结果后不直接返回,而是等至少一个从库收到binlog且写入到了中继日志中之后,再回复结果。相对一异步复制来讲,提高了一致性,但是至少增加了一个网络链接的延迟,降低了效率
3、组复制: 多个节点构成一个组,再执行读写操作时,事务提交必须经过大部分节点的同意,才能提交,很好地弥补了前面两种同步方式的不足。
2、Radis 主从节点一致性问题
第一次链接时,利用RDB文件实现全局复制。一旦完成全量复制后,它们之间就会维持一个网络链接,主库会将它接收到的命令同步给从库,从而实现基于长连接的命令传播,可以避免频繁建立连接的开销。主从库断开链接之后,再次连接时,采用增量复制的方式,实现同步。
3、Redis缓存与数据库的一致性问题
-
添加缓存过期时间 : 设置一个过期时间,这个时间段内,只更新数据库,不操作缓存。适用于数据不频繁变更的情况下
-
延时双删 : 为避免更新数据库的时候,其他线程从数据库中读取到旧值更新到缓存中,可以在数据库更新完成后,sleep一段时间,再次删除缓存。(sleep时间大于更新缓存的时间)(为防止删除缓存期间有大量数据去数据库中读取文件,可以使用分布式锁来避免这个问题)。问题:第一次删除缓存有什么作用?似乎作用不是很大?
-
使用消息队列 : 先更新数据库,成功后向消息队列发送消息,消息被消费后,再删除缓存。这种方法问题挺多的,它会使整个流程变得更加复杂,怎么保证消息不会丢失,这就是一个非常麻烦的事情。
-
基于数据库日志(binlog)增量解析、订阅和消费 :通过后台任务使用更新时间戳或者版本作为对比获取数据库的增量数据更新至缓存中,这种方式在小规模数据的场景可以起到一定作用,但其扩展性、稳定性都有所欠缺。(只读版本号的情况下,所需时间是非常短的)。