Redis集群介绍以及搭建

主从:

通过持久化功能,Redis保证了即使在服务器重启的情况下也不会损失(或少量损失)数据,因为持久化会把内存中数据保存到硬盘上,重启会从硬盘上加载数据。 。但是由于数据是存储在一台服务器上的,如果这台服务器出现硬盘故障等问题,也会导致数据丢失。为了避免单点故障,通常的做法是将数据库复制多个副本以部署在不同的服务器上,这样即使有一台服务器出现故障,其他服务器依然可以继续提供服务。为此, Redis 提供了复制(replication)功能,可以实现当一台数据库中的数据更新后,自动将更新的数据同步到其他数据库上。

在复制的概念中,数据库分为两类,一类是主数据库(master),另一类是从数据库[1] (slave)。主数据库可以进行读写操作,当写操作导致数据变化时会自动将数据同步给从数据库。而从数据库一般是只读的,并接受主数据库同步过来的数据。一个主数据库可以拥有多个从数据库,而一个从数据库只能拥有一个主数据库。

哨兵:

当主数据库遇到异常中断服务后,开发者可以通过手动的方式选择一个从数据库来升格为主数据库,以使得系统能够继续提供服务。然而整个过程相对麻烦且需要人工介入,难以实现自动化。 为此,Redis 2.8中提供了哨兵工具来实现自动化的系统监控和故障恢复功能。

哨兵的作用就是监控redis主、从数据库是否正常运行,主出现故障自动将从数据库转换为主数据库。

顾名思义,哨兵的作用就是监控Redis系统的运行状况。它的功能包括以下两个。

    (1)监控主数据库和从数据库是否正常运行。 
    (2)主数据库出现故障时自动将从数据库转换为主数据库。

集群:

 即使使用哨兵,redis每个实例也是全量存储,每个redis存储的内容都是完整的数据,浪费内存且有木桶效应。为了最大化利用内存,可以采用集群,就是分布式存储。即每台redis存储不同的内容,共有16384个slot。每个redis分得一些slot,hash_slot = crc16(key) mod 16384 找到对应slot,键是可用键,如果有{}则取{}内的作为可用键,否则整个键是可用键
集群至少需要3主3从,且每个实例使用不同的配置文件,主从不用配置,集群会自己选。

Redis集群介绍

Redis 集群是一个提供在多个Redis间节点间共享数据的程序集。

Redis集群并不支持处理多个keys的命令,因为这需要在不同的节点间移动数据,从而达不到像Redis那样的性能,在高负载的情况下可能会导致不可预料的错误.

Redis 集群通过分区来提供一定程度的可用性,在实际环境中当某个节点宕机或者不可达的情况下继续处理命令. Redis 集群的优势:

  • 自动分割数据到不同的节点上。
  • 整个集群的部分节点失败或者不可达的情况下能够继续处理命令。

Redis 集群的数据分片

Redis 集群没有使用一致性hash, 而是引入了 哈希槽的概念.

Redis 集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽.集群的每个节点负责一部分hash槽,举个例子,比如当前集群有3个节点,那么:

  • 节点 A 包含 0 到 5500号哈希槽.
  • 节点 B 包含5501 到 11000 号哈希槽.
  • 节点 C 包含11001 到 16384号哈希槽.

这种结构很容易添加或者删除节点. 比如如果我想新添加个节点D, 我需要从节点 A, B, C中得部分槽到D上. 如果我想移除节点A,需要将A中的槽移到B和C节点上,然后将没有任何槽的A节点从集群中移除即可. 由于从一个节点将哈希槽移动到另一个节点并不会停止服务,所以无论添加删除或者改变某个节点的哈希槽的数量都不会造成集群不可用的状态.

Redis 集群的主从复制模型

为了使在部分节点失败或者大部分节点无法通信的情况下集群仍然可用,所以集群使用了主从复制模型,每个节点都会有N-1个复制品.

在我们例子中具有A,B,C三个节点的集群,在没有复制模型的情况下,如果节点B失败了,那么整个集群就会以为缺少5501-11000这个范围的槽而不可用.

然而如果在集群创建的时候(或者过一段时间)我们为每个节点添加一个从节点A1,B1,C1,那么整个集群便有三个master节点和三个slave节点组成,这样在节点B失败后,集群便会选举B1为新的主节点继续服务,整个集群便不会因为槽找不到而不可用了

不过当B和B1 都失败后,集群是不可用的.

Redis 一致性保证

Redis 并不能保证数据的强一致性. 这意味这在实际中集群在特定的条件下可能会丢失写操作.

第一个原因是因为集群是用了异步复制. 写操作过程:

  • 客户端向主节点B写入一条命令.
  • 主节点B向客户端回复命令状态.
  • 主节点将写操作复制给他得从节点 B1, B2 和 B3.

主节点对命令的复制工作发生在返回命令回复之后, 因为如果每次处理命令请求都需要等待复制操作完成的话, 那么主节点处理命令请求的速度将极大地降低 —— 我们必须在性能和一致性之间做出权衡。 注意:Redis 集群可能会在将来提供同步写的方法。 Redis 集群另外一种可能会丢失命令的情况是集群出现了网络分区, 并且一个客户端与至少包括一个主节点在内的少数实例被孤立。

举个例子 假设集群包含 A 、 B 、 C 、 A1 、 B1 、 C1 六个节点, 其中 A 、B 、C 为主节点, A1 、B1 、C1 为A,B,C的从节点, 还有一个客户端 Z1 假设集群中发生网络分区,那么集群可能会分为两方,大部分的一方包含节点 A 、C 、A1 、B1 和 C1 ,小部分的一方则包含节点 B 和客户端 Z1 .

Z1仍然能够向主节点B中写入, 如果网络分区发生时间较短,那么集群将会继续正常运作,如果分区的时间足够让大部分的一方将B1选举为新的master,那么Z1写入B中得数据便丢失了.

注意, 在网络分裂出现期间, 客户端 Z1 可以向主节点 B 发送写命令的最大时间是有限制的, 这一时间限制称为节点超时时间(node timeout), 是 Redis 集群的一个重要的配置选项:

搭建并使用Redis集群

搭建集群的第一件事情我们需要一些运行在 集群模式的Redis实例. 这意味这集群并不是由一些普通的Redis实例组成的,集群模式需要通过配置启用,开启集群模式后的Redis实例便可以使用集群特有的命令和特性了.

  1. cd /usr/local/

  2. mkdir cluster-test

  3. tar -zxvf  redis-3.2.9.tar.gz -C /usr/local/cluster-test/

  4. 配置redis.conf,给redis设置密码

    1. 
      masterauth 123456
      requirepass 123456
  5. 多实例测试redis集群,6个redis节点

    1. redis7000.conf、redis7001.conf、redis7002.conf、redis7003.conf、redis7004.conf、redis7005.conf

      1. cd /usr/local/cluster-test

      2. mkdir other        #该文件的作用是,我把所有redis生成的文件都放在该文件中了

      3. 这个就是启动所有redis生成的文件都在这里,后面会提到

      4. vim redis7000.conf

      5. include /usr/local/cluster-test/redis-3.2.9/redis.conf
        port 7000
        pidfile /usr/local/cluster-test/other/redis_7000.pid
        logfile /usr/local/cluster-test/other/7000.logdb
        
        dbfilename dump_7000.rdb
        dir /usr/local/cluster-test/other
        
        cluster-enabled yes
        cluster-config-file nodes_7000.conf
        cluster-node-timeout 5000
        appendonly no
        
      6. 配置项说明

      7. include : 包含原来的配置文件内容。/usr/local/redis-3.2.9/redis.conf 按照自己的目录设置。

      8.  

        port : 自定义的端口号

      9. pidfile : 自定义的文件,表示当前程序的 pid ,进程 id。关闭redis服务自动删除

      10. logfile:日志文件名

      11. dbfilename:持久化的 rdb 文件名

      12. dir 持久化的 rdb 文件路径

      13. cluster-enabled 选项用于开实例的集群模式

      14. cluster-conf-file 选项则设定了保存节点配置文件的路径,同一服务器上该文件名不能相同

      15. cluster-node-timeout 在网络分裂出现期间, 客户端可以向主节点发送写命令的最大时间,集群超时时间,节点超过这个时间没反应就断定是宕机

      16. daemonize:yes 后台启动应用,相当于 ./redis-server & , &的作用。我没有使用

    2. 其他5个配置文件同理,只需要把配置文件中的7000相关数据换成相应数字就行了,例如:7001.7002,7003,7004.7005

    3. 实例太多新建脚本启动和关闭redis服务

      1. cd /usr/local/cluster-test/redis-3.2.9/src

      2. 启动脚本

        1. vim startAllRedis.sh

        2. ./redis-server ../redis7000.conf &
          ./redis-server ../redis7001.conf &
          ./redis-server ../redis7002.conf &
          ./redis-server ../redis7003.conf &
          ./redis-server ../redis7004.conf &
          ./redis-server ../redis7005.conf &
          sleep 0.5
          echo "redis进程"
          ps -ef|grep redis
        3. chmod 777 startAllRedis.sh

      3. 停止脚本

        1. vim shutdownAllRedis.sh

        2. ./redis-cli -p 7000 -a 123456 shutdown
          ./redis-cli -p 7001 -a 123456 shutdown
          ./redis-cli -p 7002 -a 123456 shutdown
          ./redis-cli -p 7003 -a 123456 shutdown
          ./redis-cli -p 7004 -a 123456 shutdown
          ./redis-cli -p 7005 -a 123456 shutdown
          echo "redis进程"
          ps -ef|grep redis
          
        3. chmod 777 shutdownAllRedis.sh

      4. 直接执行./startAllRedis.sh,停止服务同理

    4. 到此所有的redis服务实例都以经安装完成,接下来就开始搭建集群

    5. 官方提供了一个工具:redis-trib.rb在redis服务的src目录下,运行它需要ruby环境的支持,所有安装ruby环境

      1. yum install ruby
        //ruby 2.x已经安装了rubygems
        yum install rubygems
        //安装ruby和redis的接口程序
        // 安装指定版本的gem包
        gem install [gemname] --version=[ver]
        gem install redis --version=3.3.0
        
      2. Ruby--gem包管理命令

      3. 安装的时候会出现如下错误

      4. [root@localhost src]# gem install redis --version=3.3.0
        ERROR:  Could not find a valid gem 'redis' (>= 0), here is why:
                  Unable to download data from https://rubygems.org/ - Errno::ENETUNREACH: Network is unreachable - connect(2) (https://rubygems.org/latest_specs.4.8.gz)

      5. 替换gem源,由于网络环境的问题,访问官方源非常慢

      6. gem sources -l

      7. gem sources --remove https://rubygems.org/

      8. gem sources --add https://gems.ruby-china.com/

      9. gem sources -l

    6. 安装完成之后,由于我们的redis设置了密码,需要./redis-trib.rb没办法带参数密码,所以我们需要修改client.rb文件

      1. find / -name 'client.rb'

      2. 我的在该路径下: /usr/local/share/gems/gems/redis-3.3.0/lib/redis/client.rb

      3. 修改为你的redis密码就行了

    7. 之后在redis的src目录下执行该命令

      1. ./redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 \
        127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
      2. 在配置集群的时候不要使用127.0.0.1,不然客户端放入数据的时候会报错,地址跳转错误

      3. ./redis-trib.rb create --replicas 1 192.168.184.133:7000 192.168.184.133:7001 \
        192.168.184.133:7002 192.168.184.133:7003 192.168.184.133:7004 192.168.184.133:7005
      4. 这个命令在这里用于创建一个新的集群, 选项–replicas 1 表示我们希望为集群中的每个主节点创建一个从节点。

        之后跟着的其他参数则是这个集群实例的地址列表,3个master3个slave redis-trib 会打印出一份预想中的配置给你看, 如果你觉得没问题的话, 就可以输入 yes , redis-trib 就会将这份配置应用到集群当中,让各个节点开始互相通讯,最后可以得到如下信息:

      5. [root@localhost src]# ./redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 \
        > 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
        >>> Creating cluster
        >>> Performing hash slots allocation on 6 nodes...
        Using 3 masters:
        127.0.0.1:7000
        127.0.0.1:7001
        127.0.0.1:7002
        Adding replica 127.0.0.1:7003 to 127.0.0.1:7000
        Adding replica 127.0.0.1:7004 to 127.0.0.1:7001
        Adding replica 127.0.0.1:7005 to 127.0.0.1:7002
        M: ee8bc9e3178ae25d3b99a4e8463d39f64a569ba7 127.0.0.1:7000
           slots:0-5460 (5461 slots) master
        M: 059d2ae92557541734b8ee9f7b26b0b872ca9812 127.0.0.1:7001
           slots:5461-10922 (5462 slots) master
        M: 7aae6be7a203e82f4b1c78e12969f94b1497bbfd 127.0.0.1:7002
           slots:10923-16383 (5461 slots) master
        S: c2753e00ca54ced0c0cfe5e767a5e019f6e865e9 127.0.0.1:7003
           replicates ee8bc9e3178ae25d3b99a4e8463d39f64a569ba7
        S: ddf00139bd9bc770459194ce2a68b3963738e572 127.0.0.1:7004
           replicates 059d2ae92557541734b8ee9f7b26b0b872ca9812
        S: f6c3dcef64964114dad441748056e93183e2554d 127.0.0.1:7005
           replicates 7aae6be7a203e82f4b1c78e12969f94b1497bbfd
        Can I set the above configuration? (type 'yes' to accept): yes
        >>> Nodes configuration updated
        >>> Assign a different config epoch to each node
        5425:M 11 Apr 13:52:11.497 # configEpoch set to 1 via CLUSTER SET-CONFIG-EPOCH
        5426:M 11 Apr 13:52:11.498 # configEpoch set to 2 via CLUSTER SET-CONFIG-EPOCH
        5427:M 11 Apr 13:52:11.499 # configEpoch set to 3 via CLUSTER SET-CONFIG-EPOCH
        5428:M 11 Apr 13:52:11.501 # configEpoch set to 4 via CLUSTER SET-CONFIG-EPOCH
        5429:M 11 Apr 13:52:11.506 # configEpoch set to 5 via CLUSTER SET-CONFIG-EPOCH
        5430:M 11 Apr 13:52:11.508 # configEpoch set to 6 via CLUSTER SET-CONFIG-EPOCH
        >>> Sending CLUSTER MEET messages to join the cluster
        5425:M 11 Apr 13:52:11.522 # IP address for this node updated to 127.0.0.1
        5430:M 11 Apr 13:52:11.623 # IP address for this node updated to 127.0.0.1
        5429:M 11 Apr 13:52:11.625 # IP address for this node updated to 127.0.0.1
        5427:M 11 Apr 13:52:11.626 # IP address for this node updated to 127.0.0.1
        5428:M 11 Apr 13:52:11.628 # IP address for this node updated to 127.0.0.1
        5426:M 11 Apr 13:52:11.630 # IP address for this node updated to 127.0.0.1
        Waiting for the cluster to join...
        5428:S 11 Apr 13:52:15.546 # Cluster state changed: ok
        5429:S 11 Apr 13:52:15.549 # Cluster state changed: ok
        5430:S 11 Apr 13:52:15.553 # Cluster state changed: ok
        >>> Performing Cluster Check (using node 127.0.0.1:7000)
        M: ee8bc9e3178ae25d3b99a4e8463d39f64a569ba7 127.0.0.1:7000
           slots:0-5460 (5461 slots) master
           1 additional replica(s)
        M: 059d2ae92557541734b8ee9f7b26b0b872ca9812 127.0.0.1:7001
           slots:5461-10922 (5462 slots) master
           1 additional replica(s)
        S: ddf00139bd9bc770459194ce2a68b3963738e572 127.0.0.1:7004
           slots: (0 slots) slave
           replicates 059d2ae92557541734b8ee9f7b26b0b872ca9812
        S: f6c3dcef64964114dad441748056e93183e2554d 127.0.0.1:7005
           slots: (0 slots) slave
           replicates 7aae6be7a203e82f4b1c78e12969f94b1497bbfd
        S: c2753e00ca54ced0c0cfe5e767a5e019f6e865e9 127.0.0.1:7003
           slots: (0 slots) slave
           replicates ee8bc9e3178ae25d3b99a4e8463d39f64a569ba7
        M: 7aae6be7a203e82f4b1c78e12969f94b1497bbfd 127.0.0.1:7002
           slots:10923-16383 (5461 slots) master
           1 additional replica(s)
        [OK] All nodes agree about slots configuration.
        >>> Check for open slots...
        >>> Check slots coverage...
        [OK] All 16384 slots covered.
      6. 这表示集群中的 16384 个槽都有至少一个主节点在处理, 集群运作正常。

      7. 最后一段文字,显示了每个节点所分配的slots(哈希槽),这里总共6个节点,其中3个是从节点,所以3个主节点分别映射了0-5460、5461-10922、10923-16383solts。  

    8. 如果需要手动分配哈希槽以及主从关系,可以参考狗胖虎的博客:Mac系统搭建Redis集群模式 

    9. 使用create-cluster脚本创建一个Redis集群

      如果您不希望通过如上所述手动配置和执行单个实例来创建一个Redis集群,那么有一个简单得多的系统(但是您不会学到相同数量的操作细节)。

      只需检查Redis发行版中的utils/create-cluster目录。其中有一个名为create-cluster的脚本(与包含它的目录同名),它是一个简单的bash脚本。要启动一个包含3个主节点和3个从节点的6个节点集群,只需输入以下命令:

      create-cluster start

      create-cluster create

      当redis-trib实用程序希望您接受集群布局时,在步骤2中回答yes。

      您现在可以与集群交互,默认情况下,第一个节点将从端口30001开始。当您完成时,使用以下命令停止集群:

      create-cluster stop

      有关如何运行脚本的更多信息,请阅读此目录中的自述。

    10. /redis-cli -c -p 7000 -a 123456

    11. 一定要加上-c,不然节点之间是无法自动跳转的!如下图可以看到,存储的数据(key-value)是均匀分配到不同的节点的

    12. 到此redis集群搭建完毕

    13. 附上集群基本命令

    14. 查看当前集群信息:cluster info

    15. 查看集群里有多少个节点: cluster nodes

    16. 注意: 如果你是使用脚本创建的集群节点,那么默认端口可能是从30001开始。

      redis-cli 对集群的支持是非常基本的, 所以它总是依靠 Redis 集群节点来将它转向(redirect)至正确的节点。如果你不加-c,他就不会转向到正确的节点,他就直接抛给客户端,该key该在哪个节点上。一个真正的(serious)集群客户端应该做得比这更好: 它应该用缓存记录起哈希槽与节点地址之间的映射(map), 从而直接将命令发送到正确的节点上面。这种映射只会在集群的配置出现某些修改时变化, 比如说, 在一次故障转移(failover)之后, 或者系统管理员通过添加节点或移除节点来修改了集群的布局(layout)之后, 诸如此类。

参考:

redis中文网

关于redis的主从、哨兵、集群

提高redis cluster集群的安全性,增加密码验证

猜你喜欢

转载自blog.csdn.net/qq_39669058/article/details/89209789