深入了解Redis【二十】缓存和数据库双写一致性问题
引言缓存与数据库双写一致性问题在以前自己做的Go项目《旅行记账》app的时候学习过,也整理了文档:数据库、缓存双写一致性方案简单的介绍了一下Cache Aside Pattern
失效应用程序先从cache中取数据,没有得到(数据带失效时间),则从数据库中取数据,成功后,放入缓存。
命中应用程序从cache中取数据,取到数据后返回。
更新先将数据更新到数据库中,成功后,再将缓存数据清除。
这个套路有个问题:在并发操作的时候,假设缓存刚刚失效。有个线程A,从库中获取到旧的值,并刷缓存;线程B更新值,并清除缓存。这种情况,肯定会出现脏读。
但是数据库的读操作比写操作快的多,即A线程大多数情况下比B线程先操作结束,即先程序写缓存在大多数情况下肯定是优先于B线程删除缓存,最终,缓存中没有数据,其他线程缓存脏读的几率很小。
还有个问题:更新操作,删除缓存那一步失败了,怎么处理,肯定不能等着下一波更新或者缓存超时,应该引入重试机制:如果缓存删除失败,将key放入队列,由专门的线程处理重试。
深入了解Redis【十九】缓存并发之key竞争与缓存穿透、击穿、雪崩问题
引言简单的使用redis的缓存功能是比较容易的,比如计数或者存储个配置信息,但是当并发数上来的时候,就会出现一些列的问题,比如题目中出现的key竞争,缓存穿透、缓存击穿、缓存雪崩,下面分别描述一下,并简答的给出解决方案。
1、key并发竞争1.1、问题描述当多个系统去set同一个key时,可能本来应该先到的值,后到了,导致了数据版本不一致;又或者是多个系统去同时获取一个key,修改值之后再写回redis,只要顺序错了,数据就错了。
1.2、解决办法可以使用时间戳作为版本号,但是这种情况也会有个别机器系统时间回调,时间不确定的问题,也可以使用队列,将并行改为串行。
2、缓存穿透2.1、问题描述大量不存在的key查询,越过缓存,查询数据库,一些恶意攻击等造成大量未命中(缓存和数据库均未命中)。
2.2、解决办法在缓存层之前增加一道过滤屏障,存储所有数据库中目前存在的所有key。可以采用布隆过滤器,虽说会有误报的问题,但也能有很大作用。
3、缓存击穿3.1、问题描述高并发情况下,某一个key失效(缓存时间过期),造成大量的数据库查询操作。
3.2、解决办法热点key永久缓存(不设置缓存过期时 ...
深入了解Redis【十八】一致性Hash算法在Jedis客户端中的应用
引言一致性hash算法用于在集群环境中,使得节点的增加或者减少对于整个集群中的数据来说影响返回达到最小。
一致性hash算法一致性hash算法将整个hash值空间组成一个虚拟的环,整个空间按照顺时针方向组织。算法简答描述:盗图:一致性哈希算法原理假设hash值空间为32位无符号整型,整个hash空间如图:
服务器节点的位置确定将服务器节点通过名称进行hash,这样每台服务器节点都能座落到hash环上(假设4个节点),如图:
数据对象的位置确定如果有数据过来,使用与服务器节点相同的hash算法,将key定位到hash环上,从这个位置沿着hash环顺时针查找,第一个遇到的服务器节点就是其归属服务器。假设有4个数据,经过计算后,在环上的位置如下:
容错性假设其中的一个节点宕机,则受影响的数据仅仅是次服务器到其逆时针查找遇到的第一台服务器之间的数据,其他不受影响,如图:
扩展性假设增加一台服务器,则受影响的仅仅是新加入的服务器到其逆时针查找遇到的第一台服务器之间的数据,其他不受影响,如图:
数据倾斜问题与虚拟节点假设有两个服务器节点,其分布图如下:
当数据分布不均匀时,容易数据倾斜 ...
深入了解Redis【十七】Redisson分布式锁原理与RedLock算法
1、从一个问题开始问题:假设设置失效时间10秒,如果由于某些原因导致10秒还没执行完任务,这时候锁自动失效,导致其他线程也会拿到分布式锁,怎么处理?答:Redisson内部提供了一个监控锁的看门狗,它的作用是在Redisson实例被关闭前,不断的延长锁的有效期。
2、分布式锁的要求
互斥性任意时刻只能有一个客户端拥有锁,不能同时多个客户端获取
安全性锁只能被持有该锁的用户删除,而不能被其他用户删除
死锁获取锁的客户端因为某些原因而宕机,而未能释放锁,其他客户端无法获取此锁,需要有机制来避免该类问题的发生
容错当部分节点宕机,客户端仍能获取锁或者释放锁
3、Redisson实现的分布式锁具体使用可以参考Redisson官方文档这里贴上我简单使用的例子:
3.1、pom我使用的是springboot,所以直接用了redisson提供的集成包。
12345<dependency> <groupId>org.redisson</groupId> <artifactId>redisson-spring-boot-starter< ...
深入了解Redis【十六】集群机制之槽指派、重新分片、故障转移、主节点选举
引言Redis集群通过分片进行数据共享,并且提供复制和故障转移功能。在学习主从复制和哨兵机制的时候,知道他们一个重要的缺点,动态扩容麻烦。Redis集群通过分片可以很轻松解决扩容问题,增加节点的时候,只需重新分片,相关槽转移即可,不影响redis集群对外提供服务。
1、节点节点通过CLUSTER MEET命令加入到集群,并通过Gossip协议传播加入集群的节点的信息,最终所有的节点都保存集群中所有节点的信息。Gossip协议是P2P网络的核心技术,也叫流行病协议,具有扩展性、容错、去中心化、最终一致性、简单等特点。传播过程是由其中一个节点发起,随机选择周围几个节点散播消息,收到消息的节点也重复该过程,最终所有节点都收到消息,适合实时性不高的系统。
2、槽指派Redis集群通过分片的方式保存数据库中的键值对,整个集群被分为16384个槽(slot)。数据通过CRC16计算hash,再对16384取模,获取到当前数据的目标槽,最后定位到负责该槽的节点信息。每个节点都存储了其他节点的槽信息,所以集群模式的时候,只需要连接一个节点即可。当执行命令的时候,如果当前数据正好在此节点上,则执行命令, ...
深入了解Redis【十五】哨兵机制与选举算法
引言哨兵机制是基于主从模式实现,作用有两点:
监控master和slave是否正常运行
master出现故障时,自动将slave升级为master
哨兵的三个定时任务来源于:哨兵机制的原理
任务1每个哨兵节点每10秒会向主节点和从节点发送info命令获取最新的拓扑结构图,哨兵配置时只需要配置对主节点的监控即可,通过向主节点发送info,获取从节点的信息,并当有新的从节点加入时可以马上感知。
任务2每个哨兵节点每隔2秒会向redis数据节点的指定频道上(sentinel:hello)发送该哨兵节点对于主节点的判断以及当前哨兵节点的信息,同时每个哨兵节点也会订阅该频道,来了解其他哨兵节点的信息以及对主节点的判断。其实就是通过publish与subscribe来完成。
任务3每隔1秒每个哨兵会向主节点、从节点、其他哨兵发送ping命令,做心跳检测。
主观下线与客观下线主观下线当任务3心跳时间过长时,哨兵节点认为该节点下线。
客观下线当主观下线的节点时主节点时,该哨兵会联系其他哨兵对此主节点进行判断,大部分哨兵都统一下线时,次主节点为客观下线。
哨兵选举机制当redis主节点下线后,哨兵会 ...
深入了解Redis【十四】多机环境下主从复制、哨兵、集群的优缺点
1、Redis主从复制1.1、原理从服务器向主服务器发送PSYNC命令,主服务器执行命令,生成RDB文件,并用缓冲区记录所有新的写命令。主服务器的BGSAVE执行完成之后,将生成的RDB文件发送给从服务器,从服务器加载RDB文件。最后主服务器将缓冲区中的写命令发送给从服务器,从服务器执行写命令,最终达到数据一致性。
如果同步期间主从断线,从服务器会重连主服务器,并根据偏移量进行增量复制。
1.2、优缺点这部分内容来源于:Redis集群模式
1.2.1、优点
同一个Master可以同步多个Slaves。
Slave同样可以接受其它Slaves的连接和同步请求,这样可以有效的分载Master的同步压力。因此我们可以将Redis的Replication架构视为图结构。
Master Server是以非阻塞的方式为Slaves提供服务。所以在Master-Slave同步期间,客户端仍然可以提交查询或修改请求。
Slave Server同样是以非阻塞的方式完成数据同步。在同步期间,如果有客户端提交查询请求,Redis则返回同步之前的数据
为了分载Master的读操作压力,Slave服务器可以为客 ...
深入了解Redis【十三】客户端与服务端连接事件实例
引言本篇分析redis客户端与服务器进行连接并发送命令的过程。
Redis服务器正在运行,服务器的监听套接字的AE_READABLE事件处于监听状态下,当前所对应的事件处理器为:连接应答处理器。
Redis客户端向服务器发起连接请求,触发连接应答处理器执行。创建客户端套接字以及客户端状态,并将客户端套接字的AE_READABLE事件与命令请求处理器进行关联,使得客户端可以向服务器发送命令请求。
客户端向服务端发送命令请求,触发命令请求处理器,命令请求处理器读取客户端的请求内容,并处理。
服务端将客户端的AE_WRITEABLE事件与命令回复处理器进行关联。
客户端尝试读取命令回复时,触发命令回复处理器,将命令回复写入到套接字。
最后服务器解除客户端套接字的AE_WRITEABLE事件与命令回复处理器之间的关联。
深入了解Redis【十二】Reactor事件模型在Redis中的应用
引言Redis基于Reactor模式开发了自己的网路事件处理器,称为文件事件处理器,其使用I/O多路复用,同时监听多个套接字,根据套接字执行的任务来为套接字关联不同的事件处理器。文件事件处理器以单线程运行,Redis服务器中的其他模块也是单线程方式运行。
1、Redis中的Reactor体现Redis使用了一个称为“A simple event-driven programming library”的自制异步事件库来实现Reactor模型。
1.1、构成分为四个部分:套接字、I/O多路复用程序、文件事件派发器、事件处理器。
I/O多路复用程序会监听多个套接字,并将所有产生事件的套接字放到一个队列中,通过队列,每次一个套接字的方式向文件事件派发器传送套接字,相应的有事件处理器处理这些套接字。当该套接字为事件所关联的事件处理器处理完毕之后,I/O多路复用程序才会继续向文件事件派发器传送下一个套接字。
1.1.1、I/O多路复用程序redis是通过包装select\epoll\evport\kqueue这些I/O多路复用函数库实现的 ...
深入了解Redis【十一】RDB与AOF持久化
引言Redis的持久化分为两种:RDB(redis database)与AOF(Append Only File)。
RDB在指定的时间间隔内将内存中的数据集快照写入磁盘,或者手动执行SAVE\BGSAVE进行持久化操作。
AOF保存Redis服务器所执行的写命令来记录数据库状态。
1、RDB
优点节省磁盘空间,恢复速度快
缺点虽然Redis在fork时使用了写时拷贝技术,但是如果数据庞大时还是比较消耗性能。备份周期在一定间隔时间做一次备份,所以如果Redis意外down掉的话,就会丢失最后一次快照后的所有修改。
2、AOF
优点备份机制更稳健,丢失数据概率更低。可读的日志文本,通过操作AOF文件,可以处理误操作。
缺点比起RDB占用更多的磁盘空间。恢复备份速度要慢。每次读写都同步的话,有一定的性能压力。
3、注意
RDB、AOF文件同时存在时,服务器会根据AOF文件恢复,因为对于服务器来说,AOF的备份数据更完整。(考虑了意外宕机的情况)。
AOF日志sync属性的配置,如果不要求性能,在每条写指令时都sync一下磁盘,就不会丢失数据。但是在高性能的要求下每次都sync是不现 ...