redis集群篇

时间:2023-03-09 01:38:40
redis集群篇

redis集群的搭建

1.为什么要搭建集群(解决单点问题)

  通过对redis的简单了解,我们知道redis已经有两种持久化方案rdb和aof。在redis出现宕机后,可能会出现部分的数据损失,但是数据还是可以恢复的。但是如果服务器的硬盘出现故障,由于所有的数据都在这一台机器上,就可能会造成很大的损失。

2.redis的主从复制(单点问题解决方案)

复制的目的就是将redis数据库复制多个副本部署在多个机器上,防止其中一台机器硬盘出现损坏而造成的数据损失。复制功能可以实现当其中一台服务器中的数据出现更新后,能够同步到其它的服务器,实现数据的一致性。主从复制就是我们常见的master/slave模式,在这种模式下,一般slave节点只对外提供读服务,而写服务会落到master节点。master节点可以有多个slave节点,master节点会定期同步数据到slave节点。

3.redis中如何搭建master/slave

在redis中搭建master/slave模式很简单,只需要修改slave节点的redis.conf配置文件,而master节点的配置不需要做修改。在每个slave节点的redis.conf配置文件中添加slaveof masterip masterport,并且注释掉bindip(允许所有节点访问),其中masterip就是master的ip,msterport就是master对外提供的端口号。修改配置完成后,依次启动master和slave节点,通过redis-cli连接,使用命令info replication可以查看连接信息。

4.主从复制的原理

4.1全量复制

全量复制发生在slave节点的初始化阶段。首先是连接进来的slave节点发送SYNG的命令到master节点,master收到请求,执行bgsave命令,生成快照发送到slave节点,同时master节点也会在缓存记录在此期间的写命令,并在快照发送完成后,将缓存也发送过去。而slave节点在收到快照和缓存后,会载入数据。完成上述的操作后,slave节点便可以对外部提供服务了。

master/slave的复制采用的是乐观复制,也就是说可以容忍在一段时间内master/slave节点的数据是不同的,但是数据最终会实现同步。具体的说,就是master接收客户端的写操作,在操作完成之后,然后将数据同步给slave节点。这一特定保证了在master/slave模式下,master的性能不受到影响。

由于master节点写完之后才会将数据同步给slave节点,在这期间如果slave节点和master节点之间出现网络问题,会导致数据同步失败。所以为了保证数据实现同步,必须保证在master将数据同步成功给了多少个slave节点之后,才能对外提供写服务。而这个可以在redis.conf中配置,min-slaves-to-write 3 表示只有当3个或以上的节点连接到master节点之后,master节点才是可写的,min-slaves-max-lag 10 表示master允许slave失去的最长连接时间,如果在10秒内没收到slave的响应,则表示该slave已经断开了连接。

4.2增量复制(redis的断点续传)

增量复制的功能是从redis2.8开始的,也就是说在同步数据的过程中,如果网络断开了,重连后下次同步数据会从上一次的位置接着同步,不会重新开始。这个在redis中的实现就是会在mster节点的内存中创建一个backlog,master和slave都会保存一个replica offset还有一个master id,如果网络断掉了,会从上一次的replica接着同步。如果没有找到replica,则会执行全量同步。

4.3无硬盘复制

前面说过,redis复制的工作原理是基于rdb快照的持久化实现的。也就是说master节点在后台保存rdb快照,并将快照传输到slave,slave通过rdb快照载入数据。但是这种方式会存在两个问题。

5.redis的哨兵机制

5.1 哨兵概述:前面已经明确了reids的master/slave模式,这种模式可以实现redis的读写分离和主从复制,但是当master节点挂掉后,就需要一种机制去实现master的选举,这时哨兵机制就出现了。

5.2 什么是哨兵:哨兵的存在有两个作用,第一是监控master和slave节点是否正常运行,第二是当master节点出现故障之后,重新从slave节点中选举出一个master节点。

6.redis-cluster

  即使使用哨兵模式,redis集群中的每个节点还是会保存全量的数据,这个就会导致整个集群的数据总存储量受限于其中内存量最小的节点,形成木桶效应。

  在redis3.0之前,我们是通过在客户端来做分片,通过hash环的方式对key进行分片存储。分片虽然能够解决各个节点的存储压力,但是导致维护成本高,增加和删除节点比较繁琐。因此在redis3.0之后的版本最大的一个好处就是支持集群功能,集群的特点在于拥有和单机实例一样的性能,同时在网络分区以后能够提供一定的可访问性以及对主数据库故障恢复的支持。哨兵和集群是两个独立的功能,当不需要对数据进行分片使用哨兵就够了,如果要进行水平扩容,集群是一个比较好的方式。

  一个Redis Cluster由多个Redis节点构成。不同节点组服务的数据没有交集,也就是每个一节点组对应数据 sharding的一个分片。节点组内部分为主备两类节点,对应master和slave节点。两者数据准实时一致,通过异步 化的主备复制机制来保证。一个节点组有且只有一个master节点,同时可以有0到多个slave节点,在这个节点组中 只有master节点对用户提供些服务,读服务可以由master或者slave提供 。

  redis-cluster是基于gossip协议实现的无中心化节点的集群,因为去中心化的架构不存在统一的配置中心,各个节 点对整个集群状态的认知来自于节点之间的信息交互。在Redis Cluster,这个信息交互是通过Redis Cluster Bus来完成的 。

  redis的数据分区:分布式数据库首要解决把整个数据集按照分区规则映射到多个节点的问题,即把数据集划分到多个节点上,每个节点负责整个数据的一个子集, Redis Cluster采用哈希分区规则,采用虚拟槽分区。虚拟槽分区巧妙地使用了哈希空间,使用分散度良好的哈希函数把所有的数据映射到一个固定范围内的整数集合, 整数定义为槽(slot)。比如Redis Cluster槽的范围是0 ~ 16383。槽是集群内数据管理和迁移的基本单位。采用大范围的槽的主要目的是为了方便数据的拆分和集群的扩展,每个节点负责一定数量的槽。计算公式:slot = CRC16(key)%16383。每一个节点负责维护一部分槽以及槽所映射的键值数据。

  hashtages:通过分片手段,可以将数据合理的划分到不同的节点上,这本来是一件好事。但是有的时候,我们希望对相关联的 业务以原子方式进行操作。举个简单的例子我们在单节点上执行MSET , 它是一个原子性的操作,所有给定的key会在同一时间内被设置,不可能出现某些指定 的key被更新另一些指定的key没有改变的情况。但是在集群环境下,我们仍然可以执行MSET命令,但它的操作不 在是原子操作,会存在某些指定的key被更新,而另外一些指定的key没有改变,原因是多个key可能会被分配到不同的机器上。所以,这里就会存在一个矛盾点,及要求key尽可能的分散在不同机器,又要求某些相关联的key分配到相同机器。 这个也是在面试的时候会容易被问到的内容。怎么解决呢?从前面的分析中我们了解到,分片其实就是一个hash的过程,对key做hash取模然后划分到不同的机器上。所以为了解决这个问题,我们需要考虑如何让相关联的key得到的hash值都相同呢?如果key全部相同是不现实的,所以怎么解决呢?在redis中引入了HashTag的概念,可以使得数据分布算法可以根据key的某一个部分进行计算,然后 让相关的key落到同一个数据分片举个简单的例子,加入对于用户的信息进行存储user:user1:id、user:user1:name/ 那么通过hashtag的方式, user:{user1}:id、user:{user1}.name; 表示 当一个key包含 {} 的时候,就不对整个key做hash,而仅对 {} 包括的字符串做hash。