一. Redis集群cluster

Redis cluster主要是为了保证Redis的高可用而设计的,仅仅使用主从复制来说。只能保证master不可用后,通过哨兵自动将salve切换为主机。但是在切换的过程中,Redis是不可工作的。但是不能保证写入操作的高可用,或者说通过负载均衡完成写入操作。不能够支持海量数据的存储。

此时就需要搭建Redis的集群,能够实现海量数据的存储,并且达到写入操作的负载均衡。达到完善的高可用Redis

1. Redis cluster模式图以及工作原理

工作原理:将多个主从复制的哨兵模式组合成一起,形成Redis集群模式,将Redis集群分为多个内存槽块(将数据进行分片存储),存储数据时,根据CRC16算法,得到key的hash值。对Redis集群的所有槽位取模后,按照槽位区间进行存储。

单个哨兵组的槽位区间可以不是连续的,但是必须要保证所有的槽位加起来等于总槽位,否则会导致数据丢失无法存储的问题。

redis联锁 redis锁 集群_Redis

2. 搭建Redis Cluster

cluster帮助文档:./redis-cli --cluster help

  • 修改配置文件,将Redis的集群模式开启    REDIS CLUSTER

cluster-enabled yes     :表示开启集群,否则会以单实例启动

cluster-config-file nodes-6379.conf     集群配置文件:该文件列出了群集中其他节点,它们的状态,持久变量

cluster-node-timeout 15000              集群超时时间(毫秒)

cluster-require-full-coverage yes                     默认为yes,表示只有所有哈希槽有主节点管理的时候,集群才可以接受查询

cluster-migration-barrier 1

cluster-replica-validity-factor 10

  • 配置9台Redis实例,无需设置主从复制模式(三个master,每个master对一个两个slave),启动实例
  • 创建集群(将这9台实例创建成为一个集群),为cluster分配槽位,并且设置主从模式:
#create         host1:port1 ... hostN:portN
                 --cluster-replicas <arg>
./redis-cli --cluster create 192.168.101.1:7000  192.168.101.1:7000  192.168.101.1:7000  192.168.101.1:7000  --cluster-replicas 1

这条指令的意思是:将这些IP地址的Redis实例组成一个集群。并且设置主从复制。复制因子是1(代表每个master有1个slave),例如一共6台服务器,则每个master有一个salve,就一共有三组哨兵。

  • 创建集群时,要保证Redis服务的端口是开启的,并且16379总线端口也要开启
  • 此时Redis的启动需要添加 -c 
  • 查看集群节点信息cluster nodes

此时,Redis的集群就搭建好了。

3. Redis集群的扩容

当Redis需要横向扩容时,就需要对Redis集群进行扩容

  add-node       new_host:new_port existing_host:existing_port
                 --cluster-slave
                 --cluster-master-id <arg>

  • 创建两个Redis实例,配置文件开启cluster,并且启动。
  • 通过cluster的命令,在任意一台的Redis-cli执行均可:
./redis-cli --cluster add-node 192.168.101.10:7000 192.168.101.1:7000

该指令的意思是:将192.168.101.10:7000的Redis实例添加到.1(集群中的任意一个节点)的集群中,默认是添加了master节点。

如果要为该master节点,添加slave集群节点的话:需要指定该master节点的ID

./redis-cli --cluster add-node 192.168.101.10:7000 192.168.101.1:7000 --cluster-slave --cluster-master-id asdf4asf2345dfg3t3

此时,集群中这两个节点就被加入了。但是还没有分配槽位,不能使用

  • 分配槽位

 reshard        host:port

为我们新添加的master分配槽位:

./redis-cli --cluster reshard 192.168.101.10:7000

执行后,按照脚本指令指定分配多少槽位、给哪个节点ID分配槽位、从哪些节点拿出槽位进行分配(all:将其他节点平均分配给新节点,或者输入需要拿出槽位的多个master节点ID,DONE执行),即可完成分配。同时,迁移过去的槽位的数据同样也会被迁移过去。

4. Redis的缩容

当Redis不需要这么多集群时,可以将某一组哨兵下线。先释放槽位,然后下线Redis实例。

  • 释放槽位:

reshard        host:port     集群环境中的任意一个节点地址
                 --cluster-from <arg>   需要释放的master节点ID
                 --cluster-to <arg> 需要迁移到那个master节点ID

                 --cluster-slots <arg> 需要释放多少槽位

./redis-cli --cluster reshard 192.168.101.10:7000 --cluster-from c12f3345565ac345dfq34qasdfq3 --cluster-to 2834anf345kasdf34nifasd --cluster-slots 2000
  • 删除Redis实例节点

del-node       host:port node_id

./redis-cli --cluster del-node 192.168.101.10:7000 asdfaw34aifqi34inrmas

指向集群环境中的任意一个节点地址,指定删除的node——id即可完成删除。

此时,Redis集群完成缩容

 

二. Redis的分布式锁

1. 通过SETNX实现分布式锁

通过setNX实现分布式锁是可以的, 但是需要考虑的东西是比较多的,例如:

  1. 锁是否是可重入的(controller获取了一次锁,调用service时,还需要再次获取一次锁)
  2. 锁是否不被释放,导致死锁
  3. 在锁可重入的情况下,是否存在提前释放锁的问题(service释放了锁,但controller还有一些业务逻辑要处理)
  4. 设置的锁失效时间,是否一定会保证大于业务逻辑的执行时间
  5. 当某个线程占有锁时,其他线程在进行自旋获取锁(死循环时)的时候,如何将CPU资源释放出来实现阻塞还要保证时效性呢

2. redisson分布式锁解决方案

Redisson的实现思路:

某个线程获取锁成功后,会执行后台线程一直检查锁是否还持有,持有的话会把超时时间延长三分之一。

其他线程在获取锁失败时,会while循环自旋一直等待获取锁。