Redis 非常非常非常重要

Redis 是一个高性能的非关系型数据库,常被用于解决高并发场景下的数据存储和读取问题。在实际的使用中,了解Redis 的高并发原理对于保证数据的一致性、性能的稳定性来说至关重要。

一、Redis 如何实现高并发?
1、Redis 采用单线程机制
  • Redis 采用单线程机制避免了多线程竞争造成数据的不一致性和过多线程上下文切换的开销。在Redis 的内部实现中,采用了事件循环的方式,将事件交给 Bvent Loop 负责,每当有10事件发生时,Event Loop 就会将事件取出并处理。同时,为了提高 Redis 的处理速度,Redis 采用了多路复用技术,以在单线程下处理多个请求。

  • 这种机制避免了多线程竞争造成的数据不一致性等问题,同时也降低了 Redis 的上下文切换开销,提高了 Redis 的处理效率

2、Redis 支持多种数据结构
  • Redis 支持多种数据结构,例如字符串、哈希、列表、集合、有序集合等,不同的数据结构可以对应不同的数据需求场景。

  • 例如,对于高并发场景下经常需要进行排行榜排名的系统,可以使用 Redis 的有序集合来实现,提高了系统的性能,避免了使用关系型数据库的性能瓶颈.

3、Redis 提供多种缓存策略
  • 在高并发场景下,为了避免数据库的连接过多以及频繁的查询操作,我们可以使用 Redis 作为缓存层,将一些常用的数据储存至 Redis 中,并设置合理的缓存时间。

  • 在Redis 中,我们可以使用多种缓存策略,例如 FIFO、LRU、LFU 等,这些策略可以根据数据的热度,将热点数据留在 Redis 中,从而提高系统的性能。同时,我们也可以根据不同的数据需求,灵活配置 Redis 的缓存策略,以达到最优的缓存效果。

4、Redis 支持多个客户端同时访问
  • 在高并发场景下,多个客户端同时访问 Redis 是不可避免的,并发读写操作有可能会导致数据的丟失或不一致。
  • 为了使 Redis 支持多个客户端同时访问,Redis 内部实现了基于时间截的乐观锁机制,以保证数据在多个客户端之间的一致性。
  • 同时,Redis 还提供了事务机制使得多个操作可以一起执行,保证操作的原子性,从而避免数据出现不一致的情况。
二、如何保证 Redis 的高并发?

问题:

  • 单机 Redis 几乎不能说 QPS 超过十万,一般在几万
  • 单机 Redis 易成为高并发的瓶颈

Redis 通过 主从集群架构,实现读写分离,主节点负责写,并将数据同步给其他节点,从节点负责读,从而实现高并发。

Redis replication的核心机制:

  • Redis 采用异步方式复制数据到 slave 节点,不过 Redis 2.8 开始,slave node 会周期性地确认自己每次复制的数据量
  • 一个 master node 是可以配置多个 slave node 的
  • slave node 也可以连接其他的 slave node
  • slave node 做复制的时候,是不会 block master node 的正常工作的
  • slave node 在做复制的时候,也不会 block 对自己的查询操作,它会用旧的数据集来提供服务; 但是复制完成的时候,需要删除旧数据集,加载新数据集,这个时候就会暂停对外服务了
  • slave node 主要用来进行横向扩容,做读写分离,扩容的 slave node 可以提高读的吞吐量,对于高可用性,有很大的关系

master 持久化对于主从架构的安全保障的意义:

  • 如果采用了主从架构,那么建议必须开启 master node 的持久化!
  • 不建议用 slave node 作为 master node 的数据热备,因为,如果你关掉 master 的持久化,可能在 master 宕机重启的时候数据是空的,然后可能一经过复制,salve node 数据也丢了
  • 第二个,master 的各种备份方案,要不要做,万一本地的所有文件丢失了; 从备份中挑选一份 RDB 去恢复 master;这样才能确保 master 启动的时候,是有数据的

master 同步数据给 slave 的过程:

  • 当启动一个 slave node 的时候,它会发送一个 PSYNC 命令给 master node
  • 如果这是 slave node 重新连接 master node,那么 master node 仅仅会复制给 slave node 缺少的数据;如果是 slave node 第一次连接 master node,那么会触发一次 full resynchronization
  • 开始 full resynchronization时,master 会启动一个后台线程,开始生成一份 RDB 快照文件,同时还会将从客户端收到的所有写命令缓存在内存中。
  • RDB文件生成完毕之后,master 会将这个 RDB 发送给 slave,slave 会先写入本地磁盘,然后再从本地磁盘加载到内存中。然后 master 会将内存中缓存的写命令发送给 slave,slave 也会同步这些数据。
  • slave node 如果跟 master node 有网络故障,断开了连接,会自动重连。master 如果发现有多个 slave node 都来重新连接,仅仅会启动一个 RDB save 操作,用一份数据服务所有 slave node。

主从复制的断点续传:

  • 从 redis 2.8开始,就支持主从复制的断点续传,如果主从复制过程中,网络连接断掉了,可以接着上次复制的地方,继续复制下去,而不是从头开始复制一份

  • master node 会在内存中常见一个 backlog,master 和 slave 都会保存一个 replica offse t还有一个 master id,offset 就是保存在 backlog 中的。

  • 如果 master 和 slave 网络连接断掉了,slave 会让 master 从上次的 replica offset 开始继续复制;但是如果没有找到对应的 offset,那么就会执行一次 full resynchronization

1、数据同步相关的核心机制

指的就是第一次 slave 连接 msater 的时候,执行的全量复制,那个过程里面一些细节的机制

(1)master 和 slave 都会维护一个offset

  • master 会在自身不断累加 offset,slave 也会在自身不断累加 offset
  • slave 每秒都会上报自己的 offset 给 master,同时 master 也会保存每个 slave 的 offset
  • 主要是 master 和 slave 都要知道各自的数据的 offset,才能知道互相之间的数据不一致的情况

(2)backlog

  • master node 有一个backlog,默认是1MB大小
  • master node 给slave node复制数据时,也会将数据在 backlog 中同步写一份
  • backlog 主要是用来做全量复制中断时的增量复制

(3)master run id

  • info server,可以看到master run id
  • 如果根据 host+ip 定位 master node,是不靠谱的,如果 master node 重启或者数据出现了变化,那么 slave node 应该根据不同的 run id 区分,run id 不同就做全量复制
  • 如果需要不更改 run id 重启 redis,可以使用 redis-cli debug reload 命令

(4)psync

  • 从节点使用 psync 从 master node 进行复制,psync runid offset
  • master node 会根据自身的情况返回响应信息,可能是 FULLRESYNC runid offset 触发全量复制,可能是 CONTINUE 触发增量复制
2、相关概念

2.1 全量复制

  • master 执行 bgsave,在本地生成一份 RDB 快照文件
  • master node 将 RDB 快照文件发送给 salve node,如果 RDB 复制时间超过 60秒(repl-timeout),那么
  • slave node 就会认为复制失败,可以适当调节大这个参数
  • 对于千兆网卡的机器,一般每秒传输 100MB,6G 文件,很可能超过 60s
  • master node 在生成 RDB 时,会将所有新的写命令缓存在内存中,在 salve node 保存了 RDB 之后,再将新的写命令复制给 salve node
  • client-output-buffer-limit slave 256MB 64MB 60,如果在复制期间,内存缓冲区持续消耗超过 64MB,或者一次性超过256MB,那么停止复制,复制失败
  • slave node 接收到 RDB 之后,清空自己的旧数据,然后重新加载 RDB 到自己的内存中,同时基于旧的数据版本对外提供服务
  • 如果 slave node 开启了AOF,那么会立即执行 BGREWRITEAOF,重写 AOF

2.2 增量复制

  • 如果全量复制过程中,master-slave 网络连接断掉,那么 salve 重新连接 master 时,会触发增量复制
  • master 直接从自己的 backlog 中获取部分丢失的数据,发送给 slave node,默认 backlog 就是1MB
  • msater 就是根据 slave 发送的 psync 中的 offset 来从 backlog 中获取数据的

2.3 heartbeat

  • 主从节点互相都会发送 heartbeat 信息
  • master 默认每隔10秒发送一次 heartbeat,salve node 每隔1秒发送一个 heartbeat

2.4 异步复制

  • master 每次接收到写命令之后,先在内部写入数据,然后异步发送给 slave node
三、如何保证 Redis 的高可用?

高可用:系统可用的时间 / 总的时间 = 高可用性 = 99.99%

  • redis 不可用是什么

    • redis 进程死了
    • redis 进程所在的机器死了
  • 单实例不可用?主从架构不可用?

    • 一个 slave 挂掉了,不会影响可用性的,还有其他的 slave 在提供相同数据下的对外查询服务
    • 如果 master node 死掉,就没法写数据了,slave node 就没有用了,因为没有 master 给他们复制数据了,这时系统相当于就是不可用了
  • 不可用的后果是什么?

    • 高并发高性能的缓存不可用了,超过 mysql 最大承载能力大并发的大流量会涌入 mysq l中,导致 mysql 宕机
1、Redis 怎么才能做到高可用?

Redis 的高可用架构,叫做故障转移 failover,也可以叫做主备切换。

在 master node 故障时,自动检测,并且将某个 slave node 自动切换为 master node 的过程,叫做主备切换。这个过程,实现了 Redis 的主从架构下的高可用性。

一旦 master 故障,在很短的时间内,就会切换到另一个 master 上去,可能就几分钟、几秒钟 Redis 是不可用的。

Redis 高可用,如果是做主从架构部署,那么加上哨兵就可以了,就可以实现,任何一个实例宕机,可以进行主备切换。

2、基于哨兵的高可用

sentinel,中文名是哨兵

  • 哨兵是redis集群架构中非常重要的一个组件,主要功能如下:

(1)集群监控,负责监控 redis master 和 slave 进程是否正常工作

(2)消息通知,如果某个 redis 实例有故障,那么哨兵负责发送消息作为报警通知给管理员

(3)故障转移,如果 master node 挂掉了,会自动转移到 slave node上

(4)配置中心,如果故障转移发生了,通知 client 客户端新的 master ß地址

  • 哨兵本身也是分布式的,作为一个哨兵集群去运行,互相协同工作

(1)故障转移时,判断一个 master node 是宕机了,需要大部分哨兵都同意才行,涉及了分布式选举的问题

(2)即使部分哨兵节点挂掉了,哨兵集群还是能正常工作的,因为如果一个作为高可用机制重要组成部分的故障转移系统本身是单点的,那就很坑了

目前采用的是 sentinel 2 版本,sentinel2 相对于 sentinel1 来说,重写了很多代码,主要是让故障转移的机制和算法变得更加健壮和简单

3、哨兵的核心知识
  • 哨兵至少需要3个实例,来保证自己的健壮性
  • 哨兵 + redis 主从的部署架构,是不会保证数据零丢失的,只能保证 redis 集群的高可用性
  • 对于哨兵 + redis 主从这种复杂的部署架构,尽量在测试环境和生产环境,都进行充足的测试和演练
4、哨兵主备切换的数据丢失问题

4.1 两种数据丢失的情况

(1)异步复制导致的数据丢失

因为 master -> slave 的复制是异步的,所以可能有部分数据还没复制到 slave,master 就宕机了,此时这些部分数据就丢失了

(2)脑裂导致的数据丢失

脑裂(网络分区),也就是说,某个 master 所在机器突然脱离了正常的网络,跟其他 slave 机器不能连接,但是实际上 master 还运行着,此时哨兵可能就会认为 master 宕机了,然后开启选举,将其他 slave 切换成了 master 这个时候,集群里就会有两个 master,也就是所谓的脑裂

此时,虽然某个 slave 被切换成了 master,但是可能 client 还没来得及切换到新的 master,还继续写向旧 master 的数据可能也丢失了

因此,旧 master 再次恢复的时候,会被作为一个 slave 挂到新的 master上去,自己的数据会清空,重新从新的 master 复制数据,导致写向旧 matse r的数据可能也丢失了

4.2 解决上述数据丢失问题

  • min-slaves-to-write 1:要求至少有1个 slave
  • min-slaves-max-lag 10:数据复制和同步的延迟不能超过10秒

如果说一旦所有的 slave,数据复制和同步的延迟都超过了10秒钟,那么 master 就不会再接收任何请求了。上面两个配置可以减少异步复制和脑裂导致的数据丢失

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

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

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

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

四、Redis 的四种模式
1、单机模式

优点:

  • 部署简单,0成本。
  • 成本低,没有备用节点,不需要其他的开支。
  • 高性能,单机不需要同步数据,数据天然一致性。

缺点:

  • 无法高可用:靠性保证不是很好,单节点有宕机的风险。
  • 处理能力有限:单机高性能受限于CPU的处理能力,redis是单线程的。
  • 内存容量有限
2、主从模式

主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。

前者称为主节点(master),后者称为从节点(slave);数据的复制是单向的,只能由主节点到从节点。

主从模式配置很简单,只需要在从节点配置主节点的ip和端口号即可。

启动主从节点的所有服务,查看日志即可以看到主从节点之间的服务连接。

从上面很容易就想到一个问题,既然主从复制,意味着master和slave的数据都是一样的,有数据冗余问题。

在程序设计上,为了高可用性和高性能,是允许有冗余存在的。

主从模式在很多系统设计时都会考虑,一个master挂在多个slave节点,当master服务宕机,会选举产生一个新的master节点,从而保证服务的高可用性。

优点:

  • 一旦 主节点宕机,从节点 作为 主节点 的 备份 可以随时顶上来。
  • 扩展 主节点读能力,分担主节点读压力。
  • 高可用基石:除了上述作用以外,主从复制还是哨兵模式和集群模式能够实施的基础,因此说主从复制是Redis高可用的基石。

缺点:

  • 一旦 主节点宕机从节点 晋升成 主节点,同时需要修改 应用方主节点地址,还需要命令所有 从节点复制 新的主节点,整个过程需要 人工干预
  • 主节点写能力 受到 单机的限制
  • 主节点存储能力 受到 单机的限制
3、哨兵模式

主从模式,当主节点宕机之后,从节点是可以作为主节点顶上来,继续提供服务的。但是有一个问题,主节点的IP已经变动了,此时应用服务还是拿着主节点的地址去访问,这…于是,在Redis 2.8版本开始引入,就有了哨兵这个概念。在复制的基础上,哨兵实现了自动化的故障恢复。

哨兵模式由两部分组成,哨兵节点和数据节点:

  • 哨兵节点:哨兵系统由一个或多个哨兵节点组成,哨兵节点是特殊的redis节点,不存储数据。
  • 数据节点:主节点和从节点都是数据节点。

访问redis集群的数据都是通过哨兵集群的,哨兵监控整个redis集群。一旦发现redis集群出现了问题,比如刚刚说的主节点挂了,从节点会顶上来。但是主节点地址变了,这时候应用服务无感知,也不用更改访问地址,因为哨兵才是和应用服务做交互的。Sentinel 很好的解决了故障转移,在高可用方面又上升了一个台阶,当然Sentinel还有其他功能。比如 主节点存活检测主从运行情况检测主从切换。Redis的Sentinel最小配置是 一主一从

优点:

  • 哨兵模式是基于主从模式的,所有主从的优点,哨兵模式都具有。
  • 主从可以自动切换,系统更健壮,可用性更高。
  • Sentinel 会不断的检查 主服务器 和 从服务器 是否正常运行。当被监控的某个 Redis 服务器出现问题,Sentinel 通过API脚本向管理员或者其他的应用程序发送通知。

缺点:

  • Redis较难支持在线扩容,对于集群,容量达到上限时在线扩容会变得很复杂。
4、集群模式

主从不能解决故障自动恢复问题,哨兵已经可以解决故障自动恢复了,那到底为什么还要集群模式呢?

主从和哨兵都还有另外一些问题没有解决,单个节点的存储能力是有上限,访问能力是有上限的。

Redis Cluster 集群模式具有 高可用可扩展性分布式容错 等特性。

  • Cluster 集群模式的原理

​ 通过数据分片的方式来进行数据共享问题,同时提供数据复制和故障转移功能。

​ 之前的两种模式数据都是在一个节点上的,单个节点存储是存在上限的。集群模式就是把数据进行分片存储,当一个分片数据达到上限的时候,就分成多个分片。

  • 数据分片怎么分?

​ 集群的键空间被分割为16384个slots(即hash槽),通过hash的方式将数据分到不同的分片上的。

  • 数据分片之后怎么查,怎么写?

​ 读请求分配给slave节点,写请求分配给master,数据同步从master到slave节点。读写分离提高并发能力,增加高性能。

  • 如何做到水平扩展?

master节点可以做扩充,数据迁移redis内部自动完成。当你新增一个master节点,需要做数据迁移,redis服务不需要下线。

redis集群的重新分片由redis内部的管理软件redis-trib负责执行。redis提供了进行重新分片的所有命令,redis-trib通过向节点发送命令来进行重新分片。

五、了解一下哨兵的多个底层原理
1、sdown 和 odown 转换机制

sdown 和 odown 是两种失败状态

  • sdown 是主观宕机,就一个哨兵如果自己觉得一个 master 宕机了,那么就是主观宕机
  • odown 是客观宕机,如果 quorum 数量的哨兵都觉得一个 master 宕机了,那么就是客观宕机。
  • sdown 达成的条件很简单,如果一个哨兵 ping 一个 master,超过了 is-master-down-after-milliseconds指定的毫秒数之后,就主观认为 master 宕机
  • sdown 到 odown 转换的条件很简单,如果一个哨兵在指定时间内,收到了quorum 数量的其他哨兵也认为那个 master 是 sdown 了,那么就认为是 odown 了,客观认为 master 宕机
2、哨兵集群的自动发现机制

哨兵互相之间的发现,是通过 redis 的 pub/sub 系统实现的,每个哨兵都会往 sentinel:hello 这个 channel 里发送一个消息,这时候所有其他哨兵都可以消费到这个消息,并感知到其他的哨兵的存在

每隔两秒钟,每个哨兵都会往自己监控的某个 master+slaves 对应的 sentinel:hello channel 里发送一个消息,内容是自己的 host、ip 和 run id 还有对这个 master 的监控配置

每个哨兵也会去监听自己监控的每个 master+slaves 对应的 sentinel:hello channel,然后去感知到同样在监听这个 master+slaves 的其他哨兵的存在

每个哨兵还会跟其他哨兵交换对 master 的监控配置,互相进行监控配置的同步

3、slave 配置的自动纠正

哨兵会负责自动纠正 slave 的一些配置,比如 slave 如果要成为潜在的 master 候选人,哨兵会确保 slave 在复制现有 master 的数据; 如果 slave 连接到了一个错误的 master 上,比如故障转移之后,那么哨兵会确保它们连接到正确的 master 上

4、slave->master 选举算法

如果一个 master 被认为 odown 了,而且 majority 哨兵都允许了主备切换,那么某个哨兵就会执行主备切换操作,此时首先要选举一个 slave 来,会考虑 slave 的一些信息

(1)跟 master 断开连接的时长 (2)slave 优先级 (3)复制 offset (4)run id

如果一个 slave 跟 master 断开连接已经超过了down-after-milliseconds 的10倍,外加 master 宕机的时长,那么 slave 就被认为不适合选举为 master.【(down-after-milliseconds * 10) + milliseconds_since_master_is_in_SDOWN_state】接下来会对slave进行排序

(1)按照 slave 优先级进行排序,slave priority 越低,优先级就越高

(2)如果 slave priority 相同,那么看 replica offset,哪个 slave 复制了越多的数据,offset 越靠后,优先级就越高

(3)如果上面两个条件都相同,那么选择一个 run id 比较小的那个 slave

5、quorum 和 majority

每次一个哨兵要做主备切换,首先需要quorum 数量的哨兵认为 odown,然后选举出一个哨兵来做切换,这个哨兵还得得到 majority 哨兵的授权,才能正式执行切换

如果 quorum < majority,比如5个哨兵,majority 是3,quorum 设置为2,那么就3个哨兵授权就可以执行切换

但是如果 quorum >= majority,那么必须 quorum 数量的哨兵都授权,比如5个哨兵,quorum 是5,那么必须5个哨兵都同意授权,才能执行切换

6、configuration epoch

哨兵会对一套 redis master+slave 进行监控,有相应的监控的配置

执行切换的那个哨兵,会从要切换到的新 master(salve->master)那里得到一个 configuration epoch,这就是一个 version 号,每次切换的 version 号都必须是唯一的

如果第一个选举出的哨兵切换失败了,那么其他哨兵,会等待 failover-timeout 时间,然后接替继续执行切换,此时会重新获取一个新的 configuration epoch,作为新的 version 号

7、configuraiton 传播

哨兵完成切换之后,会在自己本地更新生成最新的 master 配置,然后同步给其他的哨兵,就是通过之前说的 pub/sub 消息机制

这里之前的version 号就很重要了,因为各种消息都是通过一个 channel 去发布和监听的,所以一个哨兵完成一次新的切换之后,新的 master 配置是跟着新的 version 号的

其他的哨兵都是根据版本号的大小来更新自己的 master 配置的

还需要学习的:比如redis的各种数据结构(动态字符串、跳跃表、集合、字典等)、高效的内存分配(jemalloc)、高效的IO模型等。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值