zl程序教程

您现在的位置是:首页 >  数据库

当前栏目

Redis 集群模式搭建

2023-04-18 13:10:33 时间

本文为博主原创,未经允许不得转载:

 目录:

  1. 哨兵模式与集群模式对比

  2. Redis 集群架构搭建

  3. 集群原理分析

  4. 集群元数据维护方式对比

  5. redis 分布式寻址

  6. 集群选举过程

  7. spring boot 接入

1. 哨兵模式与集群模式对比

  哨兵模式架构通过哨兵 sentinel 工具来监控master节点的状态,如果master节点异常,则会做主从切换,将某一台slave作为master,哨兵的配置略微复杂,并且性能和高可用性等各方面表现一般,特别是在主从切换的瞬间存在访问瞬断的情况,而且哨兵模式只有一个主节点对外提供服务,没法支持很高的并发,且单个主节点内存也不宜设置得过大,否则会导致持久化文件过大,影响数据恢复或主从同步的效率。

  集群模式:redis集群是一个由多个主从节点群组成的分布式服务器群,它具有复制、高可用和分片特性。Redis集群不需要sentinel哨兵∙也能完成节点移除和故障转移的功能。需要将每个节点设置成集群模式,这种集群模式没有中心节点,可水平扩展,据官方文档称可以线性扩展到上万个节点(官方推荐不超过1000个节点)。redis集群的性能和高可用性均优于之前版本的哨兵模式,且集群配置非常简单。

                    

2. Redis 集群架构搭建:

  redis集群需要至少三个master节点。这里用一台机器搭建三个master节点,并且给每个master再搭建一个slave节点,总共6个redis节点,

  2.1. /usr/local下创建文件夹redis‐cluster,然后在其下面分别创建6个文件夹,以端口进行区分:7001,7002,8001,8002,9001,9002

  2.2. 把之前的redis.conf配置文件copy到8001下,修改如下内容(并配置每个端口文件夹下的配置)

1)daemonize yes
(2)port 8001(分别对每个机器的端口号进行设置)
(3)pidfile /var/run/redis_8001.pid  # 把pid进程号写入pidfile配置的文件
(4)dir /usr/local/redis-cluster/8001/(指定数据文件存放位置,必须要指定不同的目录位置,不然会丢失数据)
(5)cluster-enabled yes(启动集群模式)
(6)cluster-config-file nodes-8001.conf(集群节点信息文件,这里800x最好和port对应上)
(7)cluster-node-timeout 10000
(8)# bind 127.0.0.1(bind绑定的是自己机器网卡的ip,如果有多块网卡可以配多个ip,代表允许客户端通过机器的哪些网卡ip去访问,内网一般可以不配置bind,注释掉即可)
(9)protected-mode  no   (关闭保护模式)
(10)appendonly yes
  如果要设置密码需要增加如下配置:
(11)requirepass test     (设置redis访问密码)
(12)masterauth  test      (设置集群节点间访问密码,跟上面一致)

  2.3. 分别启动每个 redis 实例,并查看是否启动成功:

/usr/local/redis-5.0.3/src/redis-server /usr/local/redis-cluster/700*/redis.conf
/usr/local/redis-5.0.3/src/redis-server /usr/local/redis-cluster/800*/redis.conf
/usr/local/redis-5.0.3/src/redis-server /usr/local/redis-cluster/900*/redis.conf
  ps -ef | grep redis 查看是否启动成功

  2.4.  用redis-cli创建整个redis集群。

    如果redis 实例是在不同的服务器之间,需要关闭防火器,关闭防火墙命令:

# systemctl stop firewalld # 临时关闭防火墙
# systemctl disable firewalld # 禁止开机启动

    创建集群:

/usr/local/redis-5.0.3/src/redis-cli -a test --cluster create --cluster-replicas 1 112.125.26.68:7001 112.125.26.68:7002 112.125.26.68:8001 112.125.26.68:8002 1112.125.26.68:9001 112.125.26.68:9002

  2.5. 集群验证

(1)连接任意一个客户端即可:./redis-cli -c -h -p (-a访问服务端密码,-c表示集群模式,指定ip地址和端口号)
    如:/usr/local/redis-5.0.3/src/redis-cli -a test -c -h 112.125.26.68 -p 800*2)进行验证: cluster info(查看集群信息)、cluster nodes(查看节点列表)
(3)进行数据操作验证
(4)关闭集群则需要逐个进行关闭,使用命令:
/usr/local/redis-5.0.3/src/redis-cli -a zhuge -c -h 112.125.26.68 -p 800* shutdown

3. 集群原理分析:

  Redis Cluster 将所有数据划分为 16384 个 slots(槽位),每个节点负责其中一部分槽位。槽位的信息存储于每个节点中。当 Redis Cluster 的客户端来连接集群时,它也会得到一份集群的槽位配置信息并将其缓存在客户端本地。这样当客户端要查找某个 key 时,可以直接定位到目标节点。同时因为槽位的信息可能会存在客户端与服务器不一致的情况,还需要纠正机制来实现槽位信息的校验调整。
 

4. 集群元数据维护方式对比:

  集群元数据的维护有两种方式:集中式、Gossip 协议。Redis cluster 节点间采用 gossip 协议进行通信。

   集中式是将集群元数据(节点信息、故障等等)集中存储在某个节点上。集中式元数据集中存储的一个典型代表,就是大数据领域的 storm 。它是分布式的大数据实时计算引擎,是集中式的元数据存储的结构,底层基于 zookeeper(分布式协调的中间件)对所有元数据进行存储维护。

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

  Redis 维护集群元数据采用另一个方式, gossip 协议,所有节点都持有一份元数据,不同的节点如果出现了元数据的变更,就不断将元数据发送给其它的节点,让其它节点也进行元数据的变更。

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

5. 分布式寻址算法:

    hash 算法, 一致性hash 算法,hash slot 算法

  redis 集群使用的是 hash slot 算法:Redis cluster 有固定的 16384 个 hash slot,对每个 key 计算 CRC16 值,然后对 16384 取模,可以获取 key 对应的 hash slot。

  Redis cluster 中每个 master 都会持有部分 slot,比如有 3 个 master,那么可能每个 master 持有 5000 多个 hash slot。hash slot 让 node 的增加和移除很简单,增加一个 master,就将其他 master 的 hash slot 移动部分过去,减少一个 master,就将它的 hash slot 移动到其他 master 上去。移动 hash slot 的成本是非常低的。客户端的 api,可以对指定的数据,让他们走同一个 hash slot,通过 hash tag 来实现。

  任何一台机器宕机,另外两个节点,不影响的。因为 key 找的是 hash slot,不是机器。

HASH_SLOT = CRC16(key) mod 16384

6. 集群选举过程:

  每个从节点,都根据自己对 master 复制数据的 offset,来设置一个选举时间,offset 越大(复制数据越多)的从节点,选举时间越靠前,优先进行选举。所有的 master node 开始 slave 选举投票,给要进行选举的 slave 进行投票,如果大部分 master node (N/2 + 1) 都投票给了某个从节点,那么选举通过,那个从节点可以切换成 master。从节点执行主备切换,从节点切换为主节点。

7. spring boot 接入

   7.1 引入pom 依赖:

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<dependency>
   <groupId>org.apache.commons</groupId>
   <artifactId>commons-pool2</artifactId>
</dependency>

  7.2 配置文件

server:
  port: 8080

spring:
  redis:
    database: 0
    timeout: 3000
    password: test
    cluster:
      nodes: 112.125.26.68:7001 112.125.26.68:7002 112.125.26.68:8001 112.125.26.68:8002 1112.125.26.68:9001 112.125.26.68:9002
   lettuce:
      pool:
        max-idle: 50
        min-idle: 10
        max-active: 100
        max-wait: 1000

  7.3 代码实现:

@RestController
public class TestController {

    private static final Logger logger = LoggerFactory.getLogger(TestController.class);

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @RequestMapping("/test_cluster")
    public void testCluster() throws InterruptedException {
       stringRedisTemplate.opsForValue().set("test", "666");
       System.out.println(stringRedisTemplate.opsForValue().get("test"));
    }
}