Redis原理和高可用场景实践总结(二)

简介: Redis原理和高可用场景实践总结

6.2、解决异步复制和脑裂导致的数据丢失

min-slaves-to-write 1     要求至少有1个slave,数据复制和同步的延迟不能超过10秒
min-slaves-max-lag 10  一旦所有的slave,数据复制和同步的延迟都超过了10秒钟,那么这个时候,master就不会再接收任何请求了

上面两个配置可以减少异步复制和脑裂导致的数据丢失

(1)减少异步复制的数据丢失

有了min-slaves-max-lag这个配置,就可以确保说,一旦slave复制数据和ack延时太长,就认为可能master宕机后损失的数据太多了,那么就拒绝写请求,这样可以把master宕机时由于部分数据未同步到slave导致的数据丢失降低的可控范围内

异步复制导致数据丢失如何降低损失

(2)减少脑裂的数据丢失

如果一个master出现了脑裂,跟其他slave丢了连接,那么上面两个配置可以确保说,如果不能继续给指定数量的slave发送数据,而且slave超过10秒没有给自己ack消息,那么就直接拒绝客户端的写请求,因此在脑裂场景下,最多就丢失10秒的数据

7 redis的集群架构(企业级常用架构)

7.1、什么是redis cluster

1能够自动将数据分散在多个节点上

2当访问的key不在当前分片上时,能够自动将请求转发至正确的分片

3当集群中部分节点失效时仍能提供服务

其中第三点是基于主从复制来实现的,Redis Cluster的每个数据分片都采用了主从复制的结构,原理和前文所述的主从复制完全一致,唯一的区别是省去了Redis Sentinel这一额外的组件,由Redis Cluster负责进行一个分片内部的节点监控和自动failover

在redis cluster架构下,每个redis要放开两个端口号,比如一个是6379,另外一个就是加10000的端口号,比如16379

16379端口号是用来进行节点间通信的,也就是cluster bus的东西,集群总线。cluster bus的通信,用来进行故障检测,配置更新,故障转移授权

cluster bus用了另外一种二进制的协议(gossip协议),主要用于节点间进行高效的数据交换,占用更少的网络带宽和处理时间

7.2、redis cluster vs. replication + sentinal

从各个方面看,Redis Cluster都是优于主从复制的方案

Redis Cluster能够解决单节点上数据量过大的问题

Redis Cluster能够解决单节点访问压力过大的问题

Redis Cluster包含了主从复制的能力

软件架构永远不是越复杂越好,复杂的架构在带来显著好处的同时,一定也会带来相应的弊端。采用Redis Cluster的弊端包括:

维护难度增加

客户端资源消耗增加。

性能优化难度增加

事务和LUA Script的使用成本增加

7.2.1 如果你的数据量很少,主要是承载高并发高性能的场景,比如你的缓存一般就几个G,单机足够了

replication,一个mater,多个slave,要几个slave跟你的要求的读吞吐量有关系,然后自己搭建一个sentinal集群,去保证redis主从架构的高可用性,就可以了

7.2.2 redis cluster,主要是针对海量数据+高并发+高可用的场景,海量数据,如果你的数据量很大,那么建议就用redis cluster

8.redis cluster的hash slot算法

Redis Cluster的Hash slot算法

工作原理如下

1、客户端与Redis节点直连,不需要中间Proxy层,直接连接任意一个Master节点

2、根据公式HASH_SLOT=CRC16(key) mod 16384,计算出映射到哪个分片上,然后Redis会去相应的节点进行操作

具有如下优点:

(1)无需Sentinel哨兵监控,如果Master挂了,Redis Cluster内部自动将Slave切换Master

(2)可以进行水平扩容

(3)支持自动化迁移,当出现某个Slave宕机了,那么就只有Master了,这时候的高可用性就无法很好的保证了,万一Master也宕机了,咋办呢? 针对这种情况,如果说其他Master有多余的Slave ,集群自动把多余的Slave迁移到没有Slave的Master 中。

缺点:

(1)批量操作是个坑

(2)资源隔离性较差,容易出现相互影响的情况

9.Redis节点间的内部通信机制

9.1、基础通信原理

(1)redis cluster节点间采取gossip协议进行通信(必须基于redis3

跟集中式不同,不是将集群元数据(节点信息,故障,等等)集中存储在某个节点上,而是互相之间不断通信,保持整个集群所有节点的数据是完整的

维护集群的元数据一种叫做集中式,一种叫做gossip

集中式:好处在于,元数据的更新和读取,时效性非常好,一旦元数据出现了变更,立即就更新到集中式的存储中,其他节点读取的时候立即就可以感知到; 不好在于,所有的元数据的跟新压力全部集中在一个地方,可能会导致元数据的存储有压力

集中式的集群元数据存储和维护

gossip:好处在于,元数据的更新比较分散,不是集中在一个地方,更新请求会陆陆续续,打到所有节点上去更新,有一定的延时,降低了压力; 缺点,元数据更新有延时,可能导致集群的一些操作会有一些滞后

gossip协议维护集群元数据

(2)10000端口

每个节点都有一个专门用于节点间通信的端口,就是自己提供服务的端口号+10000,比如7001,那么用于节点间通信的就是17001端口

每隔节点每隔一段时间都会往另外几个节点发送ping消息,同时其他几点接收到ping之后返回pong

(3)交换的信息

故障信息,节点的增加和移除,hash slot信息,等等

9.2、gossip协议

gossip协议包含多种消息,包括ping,pong,meet,fail,等等

meet: 某个节点发送meet给新加入的节点,让新节点加入集群中,然后新节点就会开始与其他节点进行通信

redis-trib.rb add-node

其实内部就是发送了一个gossip meet消息,给新加入的节点,通知那个节点去加入我们的集群

ping: 每个节点都会频繁给其他节点发送ping,其中包含自己的状态还有自己维护的集群元数据,互相通过ping交换元数据

每个节点每秒都会频繁发送ping给其他的集群,ping,频繁的互相之间交换数据,互相进行元数据的更新

pong: 返回ping和meet,包含自己的状态和其他信息,也可以用于信息广播和更新

fail: 某个节点判断另一个节点fail之后,就发送fail给其他节点,通知其他节点,指定的节点宕机了

9.3、ping消息深入

ping很频繁,而且要携带一些元数据,所以可能会加重网络负担

每个节点每秒会执行10次ping,每次会选择5个最久没有通信的其他节点

当然如果发现某个节点通信延时达到了cluster_node_timeout / 2,那么立即发送ping,避免数据交换延时过长,落后的时间太长了

比如说,两个节点之间都10分钟没有交换数据了,那么整个集群处于严重的元数据不一致的情况,就会有问题

所以cluster_node_timeout可以调节,如果调节比较大,那么会降低发送的频率

每次ping,一个是带上自己节点的信息,还有就是带上1/10其他节点的信息,发送出去,进行数据交换

至少包含3个其他节点的信息,最多包含总节点-2个其他节点的信息

10.高可用性与主备切换原理

redis cluster的高可用的原理,几乎跟哨兵是类似的

10.1、判断节点宕机

如果一个节点认为另外一个节点宕机,那么就是pfail,主观宕机

如果多个节点都认为另外一个节点宕机了,那么就是fail,客观宕机,跟哨兵的原理几乎一样,sdown,odown

在cluster-node-timeout内,某个节点一直没有返回pong,那么就被认为pfail

如果一个节点认为某个节点pfail了,那么会在gossip ping消息中,ping给其他节点,如果超过半数的节点都认为pfail了,那么就会变成fail

10.2、从节点过滤

对宕机的master node,从其所有的slave node中,选择一个切换成master node

检查每个slave node与master node断开连接的时间,如果超过了cluster-node-timeout * cluster-slave-validity-factor,那么就没有资格切换成master

这个也是跟哨兵是一样的,从节点超时过滤的步骤

10.3、从节点选举

哨兵:对所有从节点进行排序,slave priority,offset,run id

每个从节点,都根据自己对master复制数据的offset,来设置一个选举时间,offset越大(复制数据越多)的从节点,选举时间越靠前,优先进行选举

所有的master node开始slave选举投票,给要进行选举的slave进行投票,如果大部分master node(N/2 + 1)都投票给了某个从节点,那么选举通过,那个从节点可以切换成master

从节点执行主备切换,从节点切换为主节点

10.4、与哨兵比较

整个流程跟哨兵相比,非常类似,所以说,redis cluster功能强大,直接集成了replication和sentinal的功能

11 .jedis cluster api与redis cluster集群交互的一些基本原理

11.1、基于重定向的客户端

redis-cli -c,自动重定向

(1)请求重定向

(2)计算hash slot

(3)hash slot查找

11.2、smart jedis

(1)什么是smart jedis

基于重定向的客户端,很消耗网络IO,因为大部分情况下,可能都会出现一次请求重定向,才能找到正确的节点

所以大部分的客户端,比如java redis客户端,就是jedis,都是smart的

本地维护一份hashslot -> node的映射表,缓存,大部分情况下,直接走本地缓存就可以找到hashslot -> node,不需要通过节点进行moved重定向

(2)JedisCluster的工作原理

在JedisCluster初始化的时候,就会随机选择一个node,初始化hashslot -> node映射表,同时为每个节点创建一个JedisPool连接池

每次基于JedisCluster执行操作,首先JedisCluster都会在本地计算key的hashslot,然后在本地映射表找到对应的节点

如果那个node正好还是持有那个hashslot,那么就ok; 如果说进行了reshard这样的操作,可能hashslot已经不在那个node上了,就会返回moved, 如果JedisCluter API发现对应的节点返回moved,那么利用该节点的元数据,更新本地的hashslot -> node映射表缓存

重复上面几个步骤,直到找到对应的节点,如果重试超过5次,那么就报错,JedisClusterMaxRedirectionException

12.redis在实践中的一些常见问题以及优化思路

12.1、fork耗时导致高并发请求延时

RDB和AOF的时候,其实会有生成RDB快照,AOF rewrite,耗费磁盘IO的过程,主进程fork子进程

fork的时候,子进程是需要拷贝父进程的空间内存页表的,也是会耗费一定的时间的

一般来说,如果父进程内存有1个G的数据,那么fork可能会耗费在20ms左右,如果是10G~30G,那么就会耗费20 * 10,甚至20 * 30,也就是几百毫秒的时间

info stats中的latest_fork_usec,可以看到最近一次form的时长

redis单机QPS一般在几万,fork可能一下子就会拖慢几万条操作的请求时长,从几毫秒变成1秒

优化思路

fork耗时跟redis主进程的内存有关系,一般控制redis的内存在10GB以内,slave -> master,全量复制

12.2、AOF的阻塞问题

redis将数据写入AOF缓冲区,单独开一个现场做fsync操作,每秒一次

但是redis主线程会检查两次fsync的时间,如果距离上次fsync时间超过了2秒,那么写请求就会阻塞

everysec,最多丢失2秒的数据

一旦fsync超过2秒的延时,整个redis就被拖慢

优化思路

优化硬盘写入速度,建议采用SSD,不要用普通的机械硬盘,SSD,大幅度提升磁盘读写的速度

12.3、主从复制延迟问题

主从复制可能会超时严重,这个时候需要良好的监控和报警机制

在info replication中,可以看到master和slave复制的offset,做一个差值就可以看到对应的延迟量

如果延迟过多,那么就进行报警

12.4、主从复制风暴问题

如果一下子让多个slave从master去执行全量复制,一份大的rdb同时发送到多个slave,会导致网络带宽被严重占用

如果一个master真的要挂载多个slave,那尽量用树状结构,不要用星型结构

12.5、vm.overcommit_memory

0: 检查有没有足够内存,没有的话申请内存失败(默认)

1: 允许使用内存直到用完为止

2: 内存地址空间不能超过swap + 50%

如果是0的话,可能导致类似fork等操作执行失败,申请不到足够的内存空间

cat /proc/sys/vm/overcommit_memory
echo "vm.overcommit_memory=1" >> /etc/sysctl.conf
sysctl vm.overcommit_memory=1

12.6、swapiness

cat /proc/version,查看linux内核版本

如果linux内核版本<3.5,那么swapiness设置为0,这样系统宁愿swap也不会oom killer(杀掉进程)
如果linux内核版本>=3.5,那么swapiness设置为1,这样系统宁愿swap也不会oom killer

保证redis不会在内存不充足时被杀掉

echo 0 > /proc/sys/vm/swappiness

echo vm.swapiness=0 >> /etc/sysctl.conf

12.7、最大打开文件句柄

ulimit -n 10032 10032

自己去上网搜一下,不同的操作系统,版本,设置的方式都不太一样

12.8、tcp backlog

cat /proc/sys/net/core/somaxconn

echo 511 > /proc/sys/net/core/somaxconn

12.9、长耗时命令

Redis提供了Slow Log功能,可以自动记录耗时较长的命令。相关的配置参数有两个:

slowlog-log-slower-than xxxms  #执行时间慢于xxx毫秒的命令计入Slow Log

slowlog-max-len xxx  #Slow Log的长度,即最大纪录多少条Slow Log

使用SLOWLOG GET [number]命令,可以输出最近进入Slow Log的number条命令。

使用SLOWLOG RESET命令,可以重置Slow Log

避免在使用这些O(N)命令时发生问题主要有几个办法:

1、不要把List当做列表使用,仅当做队列来使用

2、通过机制严格控制Hash、Set、Sorted Set的大小

3、可能的话,将排序、并集、交集等操作放在客户端执行

4、绝对禁止使用KEYS命令

5、避免一次性遍历集合类型的所有成员,而应使用SCAN类的命令进行分批的,游标式的遍历

Redis提供了SCAN命令,可以对Redis中存储的所有key进行游标式的遍历,避免使用KEYS命令带来的性能问题。同时还有SSCAN/HSCAN/ZSCAN等命令,分别用于对Set/Hash/Sorted Set中的元素进行游标式遍历。SCAN类命令的使用请参考官方文档:https://redis.io/commands/scan

 

13.redis的雪崩和穿透

13.1缓存雪崩

缓存雪崩现象

如何解决缓存雪崩

 

   事前:redis高可用,主从+哨兵,redis cluster,避免全盘崩溃
   事中:本地ehcache缓存 + hystrix限流&降级,避免MySQL被打死
   事后:redis持久化,快速恢复缓存数据

13.2缓存穿透

缓存穿透现象以及解决方案

解决方案:每次从数据库里没查到数据,就写一个空值到缓存里 (或则利用布隆过滤器判断key是否存在)

注:缓存穿透要么是自己系统出bug,要么就是被黑客攻击

14、Redis的并发竞争问题该如何解决

这个也是线上非常常见的一个问题,就是多客户端同时并发写一个key,可能本来应该先到的数据后到了,导致数据版本错了。或者是多客户端同时获取一个key,修改值之后再写回去,只要顺序错了,数据就错了。

Redis有一系列的命令,特点是以NX结尾,NX是Not Exists的缩写,如SETNX命令就应该理解为:SET if Not Exists。这系列的命令非常有用,可以使用SETNX来实现分布式锁。

如果在公司里落地生产环境用分布式锁的时候,一定是会用开源类库的,比如Redis分布式锁,一般就是用Redisson框架就好了,非常的简便易用。


目录
相关文章
|
存储 缓存 NoSQL
Redis 服务器全方位介绍:从入门到核心原理
Redis是一款高性能内存键值数据库,支持字符串、哈希、列表等多种数据结构,广泛用于缓存、会话存储、排行榜及消息队列。其单线程事件循环架构保障高并发与低延迟,结合RDB和AOF持久化机制兼顾性能与数据安全。通过主从复制、哨兵及集群模式实现高可用与横向扩展,适用于现代应用的多样化场景。合理配置与优化可显著提升系统性能与稳定性。
538 0
|
4月前
|
消息中间件 缓存 NoSQL
Redis各类数据结构详细介绍及其在Go语言Gin框架下实践应用
这只是利用Go语言和Gin框架与Redis交互最基础部分展示;根据具体业务需求可能需要更复杂查询、事务处理或订阅发布功能实现更多高级特性应用场景。
321 86
|
4月前
|
存储 监控 NoSQL
Redis高可用架构全解析:从主从复制到集群方案
Redis高可用确保服务持续稳定,避免单点故障导致数据丢失或业务中断。通过主从复制实现数据冗余,哨兵模式支持自动故障转移,Cluster集群则提供分布式数据分片与水平扩展,三者层层递进,保障读写分离、容灾切换与大规模数据存储,构建高性能、高可靠的Redis架构体系。
|
4月前
|
存储 缓存 监控
Redis分区的核心原理与应用实践
Redis分区通过将数据分散存储于多个节点,提升系统处理高并发与大规模数据的能力。本文详解分区原理、策略及应用实践,涵盖哈希、范围、一致性哈希等分片方式,分析其适用场景与性能优势,并探讨电商秒杀、物联网等典型用例,为构建高性能、可扩展的Redis集群提供参考。
241 0
|
6月前
|
存储 缓存 NoSQL
Redis 核心知识与项目实践解析
本文围绕 Redis 展开,涵盖其在项目中的应用(热点数据缓存、存储业务数据、实现分布式锁)、基础数据类型(string 等 5 种)、持久化策略(RDB、AOF 及混合持久化)、过期策略(惰性 + 定期删除)、淘汰策略(8 种分类)。 还介绍了集群方案(主从复制、哨兵、Cluster 分片)及主从同步机制,分片集群数据存储的哈希槽算法。对比了 Redis 与 Memcached 的区别,说明了内存用完的情况及与 MySQL 数据一致性的保证方案。 此外,详解了缓存穿透、击穿、雪崩的概念及解决办法,如何保证 Redis 中是热点数据,Redis 分布式锁的实现及问题解决,以及项目中分布式锁
177 1
|
8月前
|
缓存 NoSQL Java
Redis:现代服务端开发的缓存基石与电商实践-优雅草卓伊凡
Redis:现代服务端开发的缓存基石与电商实践-优雅草卓伊凡
222 5
Redis:现代服务端开发的缓存基石与电商实践-优雅草卓伊凡
|
8月前
|
NoSQL 算法 安全
redis分布式锁在高并发场景下的方案设计与性能提升
本文探讨了Redis分布式锁在主从架构下失效的问题及其解决方案。首先通过CAP理论分析,Redis遵循AP原则,导致锁可能失效。针对此问题,提出两种解决方案:Zookeeper分布式锁(追求CP一致性)和Redlock算法(基于多个Redis实例提升可靠性)。文章还讨论了可能遇到的“坑”,如加从节点引发超卖问题、建议Redis节点数为奇数以及持久化策略对锁的影响。最后,从性能优化角度出发,介绍了减少锁粒度和分段锁的策略,并结合实际场景(如下单重复提交、支付与取消订单冲突)展示了分布式锁的应用方法。
618 3
|
8月前
|
存储 NoSQL Java
从扣减库存场景来讲讲redis分布式锁中的那些“坑”
本文从一个简单的库存扣减场景出发,深入分析了高并发下的超卖问题,并逐步优化解决方案。首先通过本地锁解决单机并发问题,但集群环境下失效;接着引入Redis分布式锁,利用SETNX命令实现加锁,但仍存在死锁、锁过期等隐患。文章详细探讨了通过设置唯一标识、续命机制等方法完善锁的可靠性,并最终引出Redisson工具,其内置的锁续命和原子性操作极大简化了分布式锁的实现。最后,作者剖析了Redisson源码,揭示其实现原理,并预告后续关于主从架构下分布式锁的应用与性能优化内容。
403 0
|
8月前
|
缓存 NoSQL 关系型数据库
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?