缓存充当数据库

比如说Session这种访问非常频繁的数据,就适合采用这种方案;当然了,既然没有涉及到数据库,那么也就不会存在一致性问题;

缓存充当数据库热点缓存

读操作

目前的读操作有个固定的套路,如下:

客户端请求服务器的时候,发现如果服务器的缓存中存在,则直接取服务器的;

如果缓存中不存在,则去请求数据库,并且将数据库计算出来的数据回填给缓存;

返回数据给客户端;

写操作

各种情况会导致数据库和缓存出现不一致的情况,这就是缓存和数据库的双写一致性问题;

目前缓存存在三种策略,分别是

Cache Aside 更新策略:同时更新缓存和数据库;

Read/Write Through 更新策略:先更新缓存,缓存负责同步更新数据库;

Write Behind Caching 更新策略:先更新缓存,缓存定时异步更新数据库;

三种策略各有优缺点,可以根据业务场景使用;

Cache Aside 更新策略

该策略大概的流程就是请求过来时先从缓存中取,如果命中缓存的话,则直接返回读取的数据;相反如果没有命中的话,接着会从数据库中成功获取到数据后,再去清除缓存中的数据;具体流程图如下:

但是以上在某些特殊的情况下是存在问题:

问题1:先更新数据库,后更新缓存

两个线程在高并发的情况下就会可能出现数据脏读的情况:

线程A执行写操作,成功更新数据库;

线程B同样执行和线程A一样的操作,但是在线程A执行更新缓存的过程中,线程B更新了新的数据库数据到缓存中;

线程A在线程B全部操作完成以后才将相对老的数据又更新到了缓存中;

问题2:先删除缓存,后更新数据库

同样的,在高并发场景下同样会出现脏读的情况:

线程A成功删除了缓存,等待更新数据库;

线程B进行读操作,由于此时缓存已经被删除了,因此线程B重新从数据库中获取老的数据并且更新到了缓存中;

线程A在线程B完成了整个的读操作以后,才更新数据库,此时缓存中的数据依旧是老的数据;

Redis和数据库 数据同步问题的解决

问题3:先更新数据库,后删除缓存

目前这是比较普遍的操作,即使它还是有可能会出现脏读的情况:

线程A进行读操作,此时正好没有命中缓存,接着请求数据库;

线程B进行写操作,在线程A没有从数据库中获取到数据之前,把数据写入到数据库中,并且还成功删除了缓存;

线程A在线程B完成了整个的写操作以后,才将相对老的数据更新到缓存中;

但是以上的情况比较不会出现,这是因为上述情况需要满足线程A的读操作要慢于线程B的写操作,但是在现实过程中,读操作通常都是要快于写操作得多的,但是为了避免发生以上的情况,通常都是要给缓存加上一个过期的时间;

但是设想一下,如果上面的删除缓存失败了怎么办呢,这样显然会导致数据脏读的情况,我觉得方案如下:

设置缓存的过期时间(必须要做);

提供一个保障重试机制,将哪些删除失败的key提供给消息队列去消费;

从消息队列取出这些key再次进行删除,失败再次加入到消息队列中,超过一定次数以上则人工介入;

Redis和数据库 数据同步问题的解决

但是以上情况需要在业务代码中进行操作,显然得需要进行解耦;

目前我们公司就是使用该方案,具体过程为在更新数据库数据的时候,数据库会以binlog日志的形式保存下来,通过canal开源软件将binlog解析成程序语言可以解析的地步,接着订阅程序获取到这些数据以后,尝试删除缓存操作,如果操作失败的话,则将其加入到消息队列中,重复消费,当删除操作的失败次数到达一定的次数以后,还是得人工介入。

Read/Write Through 更新策略

该模式下,程序只需要维护缓存即可,数据库的同步工作交由缓存来同步更新;

该策略具体又分为两种:

Read Through:在查询的过程中更新缓存;

Write Through:在写操作的过程中如果命中缓存,则直接更新缓存,数据库则由缓存自己同步去更新;

Write Behind Caching 更新策略

该策略只更新缓存,不会立马更新数据库,只会在一定的时间异步的批量去操作数据库;这样的好处在于直接操作缓存,效率极高,并且操作数据是异步的,还可以将多次的操作数据库语句合并到一个事务中一起提交,因此效率很客观;

但是,该策略没有办法做到数据强一致性,并且实现逻辑相对是比较复杂的,因为它需要确认哪些是需要更新到数据库的,哪些是仅仅想要存储在缓存中的;

比较

目前通常使用的是第一种策略中的先更新数据库,后更新缓存;其他的相较比起来实现都比较复杂;

最后想说的是,缓存本来就是为了牺牲强一致性来提高性能的,所以肯定会存在一定的延迟时间,我们只需要保证最终的数据一致性即可;

补充:redis数据的同步问题

修改redis.conf配置文件

vi redis.conf

在编辑模式下 输入 /slaveof 来搜索

Redis和数据库 数据同步问题的解决

将slaveof启用 即 将#删除

依次配置所有 slave 并将进程 kill 掉 重启

Redis和数据库 数据同步问题的解决

Redis和数据库 数据同步问题的解决

查看主从信息

Redis和数据库 数据同步问题的解决

Redis和数据库 数据同步问题的解决

redis 集群主从同步的简单原理

Redis的复制功能是基于内存快照的持久化策略基础上的,也就是说无论你的持久化策略选择的是什么,只要用到了Redis的复制功能,就一定会有内存快照发生。

当Slave启动并连接到Master之后,它将主动发送一个SYNC命令( 首先Master会启动一个后台进程,将数据快照保存到文件中[rdb文件] Master 会给Slave 发送一个

Ping命令来判断Slave的存活状态 当存活时 Master会将数据文件发送给Slave 并将所有写命令发送到Slave )。

Slave首先会将数据文件保存到本地 之后再将 数据 加载到内存中。当第一次链接 或者是 故障后 重新连接 都会先判断Slave的存活状态 在做全部数据的同步 , 之后只会同步Master的写操作(将命令发送给Slave)

问题:

当 Master 同步数据时 若数据量较大 而Master本身只会启用一个后台进程 来对多个Slave进行同步 , 这样Master就会压力过大 , 而且Slave 恢复的时间也会很慢!

redis 主从复制的优点:

(1)在一个Redis集群中,master负责写请求,slave负责读请求,这么做一方面通过将读请求分散到其他机器从而大大减少了master服务器的压力,另一方面slave专注于提供读服务从而提高了响应和读取速度。

(2)在一个Redis集群中,如果master宕机,slave可以介入并取代master的位置,因此对于整个Redis服务来说不至于提供不了服务,这样使得整个Redis服务足够安全。

(3)水平增加Slave机器可以提高性能

Slave 默认是只读的更改:

Master 可以 读写(Write and Read) 而 Slave只可以读(read only默认情况)也可以更改 {但是开启后Slave数据不会向上同步}

Redis和数据库 数据同步问题的解决

Redis的主从架构的两种方式:

1.主从架构:

Redis和数据库 数据同步问题的解决

2.主从从架构:

Redis和数据库 数据同步问题的解决

备注:

因为Slave断连,重连后仍然会全部同步数据,所以redis2.8版本后,增加了增量复制来解决宕机后重新链接仍然会全部同步!

Master会维护一个环形队列:

队列内存储:

1》:slave连接master的id值 2》:slave上一次同步的最后一个命令这样当断开重连后就不会全部同步,而只会在最后一个命令同步数据!

当你看到这些感到redis很好,有一点你要你记住,redis是基于内存的,内存是很珍贵的,公司不会花费大量的资源只为了让你玩这个架构,同时推荐memcached,这个成本就比较低了,因为它是基于磁盘的,当然效率就会比基于内存的redis低,同时也有和redis同样设计风格的非关系型数据库SSDB就比较友善了。 

SSDB和Redis的优缺点比较:

redis是内存数据库,ssdb是面向硬盘的存储,二者在存储格式和读写方式上有着根本的不同。前面回答里提到的zrevrange 和 zrevrangebyscore慢,而zrange 和 zrangebyscore 还能接受,其实就是说逆序遍历比顺序遍历慢得多,其根本原因就在于逆序遍历的时候,会多一个“记录头部”定位的过程,需要不断尝试去定位到两条记录的“分界点”,而顺序遍历的时候则不需要,因为读完一条记录直接就到了下一条记录的“分界点”,并且像rocksdb之类的存储引擎都会把数据长度保存在记录的元信息里,只需要按长度读取数据就可以了。

redis则不存在类似问题,因为它是完全基于指针和偏移量在内存中进行寻址来读取数据的,寻址效率高了好多个数量级。

ssdb貌似就是一个个人项目,但代码质量还是不错的,整个设计思想比较简洁。ssdb的主从复制效率很低。

binlog和数据是分开存储的,日志冗余较多,由于ssdb本身要在多线程条件下才能发挥出更好的性能,为了使多个线程在写入binlog时能保证操作顺序和原子性,ssdb的binlog数据结构上用了一把全局锁,可想而知,这里的锁竞争会很影响性能。另外,ssdb默认也没有集群管理的支持。

ssdb的好处,和swapdb一样,都可以省钱。如果有需要,可以尝试swapdb,它结合了redis和ssdb的优点,实现了基于LFU的热度统计和冷热交换,做到了低成本和高性能的高平衡。redis的好处,那就多了。

缺点就是纯内存,比用SSD花钱。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。如有错误或未考虑完全的地方,望不吝赐教。

标签:
Redis,数据库,数据同步

免责声明:本站文章均来自网站采集或用户投稿,网站不提供任何软件下载或自行开发的软件! 如有用户或公司发现本站内容信息存在侵权行为,请邮件告知! 858582#qq.com
白云城资源网 Copyright www.dyhadc.com

评论“Redis和数据库 数据同步问题的解决”

暂无“Redis和数据库 数据同步问题的解决”评论...

稳了!魔兽国服回归的3条重磅消息!官宣时间再确认!

昨天有一位朋友在大神群里分享,自己亚服账号被封号之后居然弹出了国服的封号信息对话框。

这里面让他访问的是一个国服的战网网址,com.cn和后面的zh都非常明白地表明这就是国服战网。

而他在复制这个网址并且进行登录之后,确实是网易的网址,也就是我们熟悉的停服之后国服发布的暴雪游戏产品运营到期开放退款的说明。这是一件比较奇怪的事情,因为以前都没有出现这样的情况,现在突然提示跳转到国服战网的网址,是不是说明了简体中文客户端已经开始进行更新了呢?