目录
一、缓存淘汰策略
1.1LRU原理
1.2案例分析
1.3Redis缓存淘汰策略
1.3.1设置最⼤缓存
1.3.2淘汰策略
二、Redis事务
2.1Redis事务典型应⽤—Redis乐观锁
2.2Redis事务介绍
2.3事务命令
2.3.1MULTI
2.3.2EXEC
2.3.3DISCARD
2.3.4WATCH
2.3.5UNWATCH
2.4事务演示
2.5事务失败处理
2.6Redis乐观锁
2.7Redis乐观锁实现秒杀
三、Redis持久化
3.1RDB⽅式(默认)
3.1.1触发快照的时机
3.1.2设置快照规则
3.1.3原理图
3.2AOF⽅式
3.2.1AOF介绍
3.2.2同步磁盘数据
3.2.3AOF重写原理(优化AOF⽂件)
3.2.4AOF⽂件损坏以后如何修复
3.3如何选择RDB和AOF
3.4如何选择RDB和AOF(4.0之前的还需要考虑)
3.5混合持久化⽅式
四、Redis主从复制
4.1什么是主从复制
4.2主从配置
4.2.1主Redis配置
4.2.2从Redis配置
4.2.3实现原理
4.2.4全量同步
4.2.5增量同步
五、Redis哨兵机制
5.1简介
5.2哨兵进程的作用
5.3故障判定原理分析
5.4⾃动故障迁移
5.5案例演示
六、Redis集群
6.1Redis的集群策略
6.2Redis-cluster架构图
6.3Redis-cluster投票:容错
6.4安装RedisCluster
6.5命令客户端连接集群
6.6查看集群的命令
6.7维护节点
6.7.1添加主节点
6.7.2hash槽重新分配(数据迁移)
6.7.3添加从节点
6.7.4删除结点
6.8Jedis连接集群
6.8.1代码实现
6.8.2使⽤spring
一、缓存淘汰策略
1.1LRU原理
LRU ( Least recently used ,最近最少使⽤)算法根据数据的历史访问记录来进⾏淘汰数据,其核⼼思 想是“ 如果数据最近被访问过,那么将来被访问的⼏率也更⾼ ” 。
最常⻅的实现是使⽤⼀个链表保存缓存数据,详细算法实现如下:
1. 新数据插⼊到链表头部; 2. 每当缓存命中(即缓存数据被访问),则将数据移到链表头部; 3. 当链表满的时候,将链表尾部的数据丢弃。
在Java中可以使⽤LinkHashMap去实现LRU利⽤哈希链表实现
1.2案例分析
让我们以⽤户信息的需求为例,来演示⼀下LRU算法的基本思路:
(1)假设我们使⽤哈希链表来缓存⽤户信息,⽬前缓存了4个⽤户,这4个⽤户是按照时间顺序依次从链表右端插⼊的。
(2)此时,业务⽅访问⽤户5,由于哈希链表中没有⽤户5的数据,我们从数据库中读取出来,插⼊到缓存当中。这时候,链表中最右端是最新访问到的⽤户5,最左端是最近最少访问的⽤户1。
(3)接下来,业务⽅访问⽤户2,哈希链表中存在⽤户2的数据,我们怎么做呢?我们把⽤户2从它的前驱节 点和后继节点之间移除,重新插⼊到链表最右端。这时候,链表中最右端变成了最新访问到的⽤户2,最左端仍然是最近最少访问的⽤户1
(4)接下来,业务⽅请求修改⽤户4的信息。同样道理,我们把⽤户4从原来的位置移动到链表最右侧,并把⽤户信息的值更新。这时候,链表中最右端是最新访问到的⽤户4,最左端仍然是最近最少访问的⽤户1
(5)后来业务⽅换⼝味了,访问⽤户6,⽤户6在缓存⾥没有,需要插⼊到哈希链表。假设这时候缓存容量已经达到上限,必须先删除最近最少访问的数据,那么位于哈希链表最左端的⽤户1就会被删除掉,然后再把⽤户6插⼊到最右端。
以上,就是LRU算法的基本思路。
1.3Redis缓存淘汰策略
1.3.1设置最⼤缓存
在 redis 中,允许⽤户设置最⼤使⽤内存⼤⼩ maxmemory ,默认为 0 ,没有指定最⼤缓存,如果 有新的数据添加,超过最⼤内存,则会使redis 崩溃,所以⼀定要设置。
redis 内存数据集⼤⼩上升到⼀定⼤⼩的时候,就会实⾏数据淘汰策略。
1.3.2淘汰策略
redis 淘汰策略配置: maxmemory-policy voltile-lru ,⽀持热配置
redis 提供 6种数据淘汰策略:
1. volatile-lru :从已设置过期时间的数据集( server.db[i].expires )中挑选最近最少使⽤的数据淘汰 2. volatile-ttl :从已设置过期时间的数据集( server.db[i].expires )中挑选将要过期的数据淘汰 3. volatile-random :从已设置过期时间的数据集( server.db[i].expires )中任意选择数据淘汰 4. allkeys-lru :从数据集( server.db[i].dict )中挑选最近最少使⽤的数据淘汰 5. allkeys-random :从数据集( server.db[i].dict )中任意选择数据淘汰 6. no-enviction (驱逐):禁⽌驱逐数据
二、Redis事务
2.1Redis事务典型应⽤—Redis乐观锁
在⽣产环境⾥,经常会利⽤ redis 乐观锁来实现秒杀, Redis 乐观锁是 Redis 事务的经典应⽤。 秒杀场景描述 : 秒杀活动对稀缺或者特价的商品进⾏定时,定量售卖,吸引成⼤量的消费者进⾏抢购,但⼜只有少部分 消费者可以下单成功。因此,秒杀活动将在较短时间内产⽣⽐平时⼤数⼗倍,上百倍的⻚⾯访问流量和 下单请求流量。 由于秒杀只有少部分请求能够成功,⽽⼤量的请求是并发产⽣的,所以如何确定哪个请求成功了,就是 由redis 乐观锁来实现。具体思路如下: 监控 锁定量,如果该值被修改成功则表示该请求被通过,反之表示该请求未通过。 从监控到修改到执⾏都需要在 redis ⾥操作,这样就需要⽤到 Redis 事务。
2.2Redis事务介绍
Redis 的事务是通过 MULTI 、 EXEC 、 DISCARD 和 WATCH 这四个命令来完成的。 Redis 的单个命令都是原⼦性的,所以这⾥需要确保事务性的对象是 命令集合 。 Redis 将命令集合序列化并确保处于同⼀事务的 命令集合连续且不被打断 的执⾏ Redis 不⽀持回滚操作。
2.3事务命令
2.3.1MULTI
⽤于标记事务块的开始。 Redis 会将后续的命令逐个放⼊队列中,然后使⽤ EXEC 命令原⼦化地执⾏这个命令序列。 语法:
multi
2.3.2EXEC
在⼀个事务中执⾏所有先前放⼊队列的命令,然后恢复正常的连接状态 语法:
exec
2.3.3DISCARD
清除所有先前在⼀个事务中放⼊队列的命令,然后恢复正常的连接状态。 语法:
discard
2.3.4WATCH
当某个 [ 事务需要按条件执⾏ ] 时,就要使⽤这个命令将给定的 [ 键设置为受监控 ] 的状态。 语法:
watch key [key…]
注意事项: 使⽤该命令可以实现 Redis 的 乐观锁 。(后⾯实现)
2.3.5UNWATCH
清除所有先前为⼀个事务监控的键。 语法:
unwatch
2.4事务演示
127.0.0.1:6379> multiOK127.0.0.1:6379> set s1 111QUEUED127.0.0.1:6379> hset set1 name zhangsanQUEUED127.0.0.1:6379> exec1) OK2) (integer) 1127.0.0.1:6379> multiOK127.0.0.1:6379> set s2 222QUEUED127.0.0.1:6379> hset set2 age 20QUEUED127.0.0.1:6379> discardOK127.0.0.1:6379> exec(error) ERR EXEC without MULTI127.0.0.1:6379> watch s1 OK127.0.0.1:6379> multiOK127.0.0.1:6379> set s1 555QUEUED127.0.0.1:6379> exec # 此时在没有exec之前,通过另⼀个命令窗⼝对监控的s1字段进⾏修改(nil)127.0.0.1:6379> get s1111
2.5事务失败处理
(1 )Redis 语法错误
整个事务的命令在队列⾥都清除
(2)Redis 运⾏错误
在队列⾥正确的命令可以执⾏ (弱事务性) 弱事务性 : 1 、在队列⾥正确的命令可以执⾏ (⾮原⼦操作) 2 、不⽀持回滚
(3)Redis 不⽀持事务回滚(为什么呢)
1 、⼤多数事务失败是因为 语法错误或者类型错误 ,这两种错误,在开发阶段都是可以预⻅的 2 、 Redis 为了 性能⽅⾯ 就忽略了事务回滚。 (回滚记录历史版本)
2.6Redis乐观锁
乐观锁基于CAS(Compare And Swap)思想(⽐较并替换),是不具有互斥性,不会产⽣锁等待⽽消 耗资源,但是需要反复的重试,但也是因为重试的机制,能⽐较快的响应。因此我们可以利⽤redis来实 现乐观锁。具体思路如下:
1 、利⽤ redis 的 watch 功能,监控这个 redisKey 的状态值 2 、获取 redisKey 的值 3 、创建 redis 事务 4 、给这个 key 的值 +1 5 、然后去执⾏这个事务,如果 key 的值被修改过则回滚, key 不加 1
public void watch() { try { String watchKeys = "watchKeys"; //初始值 value=1 jedis.set(watchKeys, 1); //监听key为watchKeys的值 jedis.watch(watchkeys); //开启事务 Transaction tx = jedis.multi(); //watchKeys⾃增加⼀ tx.incr(watchKeys); //执⾏事务,如果其他线程对watchKeys中的value进⾏修改,则该事务将不会执⾏ //通过redis事务以及watch命令实现乐观锁 List
2.7Redis乐观锁实现秒杀
import redis.clients.jedis.Jedis;import redis.clients.jedis.Transaction;import java.util.List;import java.util.UUID;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class SecKill {public static void main(String[] arg) {// 库存keyString redisKey = "stock";ExecutorService executorService = Executors.newFixedThreadPool(20);try {Jedis jedis = new Jedis("127.0.0.1", 6378);// 可以被秒杀的库存的初始值,库存总共20个jedis.set(redisKey, "0");jedis.close();} catch (Exception e) {e.printStackTrace();}for (int i = 0; i {Jedis jedis1 = new Jedis("127.0.0.1", 6378);try {jedis1.watch(redisKey);String redisValue = jedis1.get(redisKey);int valInteger = Integer.valueOf(redisValue);String userInfo = UUID.randomUUID().toString();// 没有秒完if (valInteger < 20) {Transaction tx = jedis1.multi();tx.incr(redisKey);List
三、Redis持久化
Redis是⼀个内存数据库,为了保证数据的持久性,它提供了两种持久化⽅案:
3.1RDB⽅式(默认)
RDB ⽅式是通过 快照 ( snapshotting )完成的,当 符合⼀定条件 时 Redis 会⾃动将内存中的数据进⾏快 照并持久化到硬盘
3.1.1触发快照的时机
1. 符合⾃定义配置的快照规则 redis.conf 2. 执⾏ save 或者 bgsave 命令 3. 执⾏ flushall 命令 4. 执⾏主从复制操作 ( 第⼀次 )
3.1.2设置快照规则
save 多少秒内 数据变了多少 save “” : 不使⽤ RDB 存储 save 900 1 : 表示 15 分钟( 900 秒钟)内⾄少 1 个键被更改则进⾏快照。 save 300 10 : 表示 5 分钟( 300 秒)内⾄少 10 个键被更改则进⾏快照。 save 60 10000 :表示 1 分钟内⾄少 10000 个键被更改则进⾏快照。 过滤条件是或的关系,⽽且是漏⽃型的过滤顺序。
3.1.3原理图
注意事项!!!
1. Redis 在进⾏快照的过程中不会修改 RDB ⽂件,只有快照操作结束后才会将旧的⽂件替换成新的, 也就是说任何时候 RDB ⽂件都是完整的。 2. 这就使得我们可以通过定时备份 RDB ⽂件来实现 Redis 数据库的备份, RDB ⽂件是 经过压缩的⼆ 进制⽂件 ,占⽤的空间会⼩于内存中的数据,更加利于传输。
RDB优缺点:
缺点: 使⽤ RDB ⽅式实现持久化,⼀旦 Redis 异常退出 ,就会 丢失最后⼀次快照以后更改的所有数 据 。这个时候我们就需要根据具体的应⽤场景,通过组合设置⾃动快照条件的⽅式来将可能发⽣的 数据损失控制在能够接受范围。如果数据相对来说⽐较重要,希望将损失降到最⼩,则可以使 ⽤ AOF ⽅式进⾏持久化 优点: RDB 可以最⼤化 Redis 的性能:⽗进程在保存 RDB ⽂件时唯⼀要做的就是 fork 出⼀个⼦ 进程,然后这个⼦进程就会处理接下来的所有保存⼯作,⽗进程⽆需执⾏任何磁盘 I/O 操作。同时 这个也是⼀个缺点,如果数据集⽐较⼤的时候, fork 可以能⽐较耗时,造成服务器在⼀段时间内 停⽌处理客户端的请求;
3.2AOF⽅式
3.2.1AOF介绍
默认情况下 Redis 没有开启 AOF ( append only file )⽅式的持久化。 开启 AOF 持久化后,每执⾏⼀条会更改 Redis 中的数据的命令, Redis 就会将该命令写⼊硬盘中的 AOF ⽂件,这⼀过程显然会降低 Redis 的性能,但⼤部分情况下这个影响是能够接受的,另外使⽤较快的硬盘可以提⾼ AOF 的性能。
redis.conf :
# 可以通过修改redis.conf配置⽂件中的appendonly参数开启appendonly yes # AOF⽂件的保存位置和RDB⽂件的位置相同,都是通过dir参数设置的。dir ./ # 默认的⽂件名是appendonly.aof,可以通过appendfilename参数修改appendfilename appendonly.aof
⽤SET命令来举例说明RESP协议的格式。
redis> SET mykey "Hello""OK"
实际发送的请求数据:
*3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$5\r\nHello\r\n*3$3SET$5mykey$5Hello
3.2.2同步磁盘数据
Redis 每次更改数据的时候, aof 机制都会将命令记录到 aof ⽂件,但是实际上由于操作系统的 缓存 机制 ,数据并没有实时写⼊到硬盘,⽽是进⼊ 硬盘缓存 。再通过 硬盘缓存机制 去刷新到保存到⽂件。
filesync命令:参数说明:
# 每次执⾏写⼊都会进⾏同步, 这个是最安全但是是效率⽐较低的⽅式appendfsync always # 每⼀秒执⾏(默认)appendfsync everysec # 不主动进⾏同步操作,由操作系统去执⾏,这个是最快但是最不安全的⽅式appendfsync no
3.2.3AOF重写原理(优化AOF⽂件)
set s1 111set s1 222set s1 333set s1 444set s1 444
Redis 可以在 AOF ⽂件体积变得过⼤时,⾃动地在后台对 AOF 进⾏重写。重写后的新 AOF ⽂ 件包含了恢复当前数据集所需的最⼩命令集合。
AOF ⽂件有序地保存了对数据库执⾏的所有写⼊操作, 这些写⼊操作以 Redis 协( RESP )的格式 保存, 因此 AOF ⽂件的内容⾮常容易被⼈读懂, 对⽂件进⾏分析( parse )也很轻松。
AOF重写过程分析(整个重写操作是绝对安全的):
Redis 在创建新 AOF ⽂件的过程中,会继续将命令追加到现有的 AOF ⽂件⾥⾯,即使重写过程中发 ⽣停机,现有的 AOF ⽂件也不会丢失。 ⽽⼀旦新 AOF ⽂件创建完毕, Redis 就会从旧 AOF ⽂件切换 到新 AOF ⽂件,并开始对新 AOF ⽂件进⾏追加操作。
参数说明:
# 表示当前aof⽂件⼤⼩超过上⼀次aof⽂件⼤⼩的百分之多少的时候会进⾏重写。如果之前没有重写过,以启动时aof⽂件⼤⼩为准auto-aof-rewrite-percentage 100# 限制允许重写最⼩aof⽂件⼤⼩,也就是⽂件⼤⼩⼩于64mb的时候,不需要进⾏优化auto-aof-rewrite-min-size 64mb
3.2.4AOF⽂件损坏以后如何修复
问题描述:
服务器可能在程序正在对 AOF ⽂件进⾏写⼊时停机, 如果停机造成了 AOF ⽂件出错 ( corrupt ), 那么 Redis 在重启时会拒绝载⼊这个 AOF ⽂件, 从⽽确保数据的⼀致性不会 被破坏。
当发⽣这种情况时, 可以⽤以下⽅法来修复出错的 AOF ⽂件:
1.为现有的 AOF ⽂件创建⼀个备份。 2.使⽤ Redis 附带的 redis-check-aof 程序,对原来的 AOF ⽂件进⾏修复。
redis-check-aof --fix readonly.aof
3.重启 Redis 服务器,等待服务器载⼊修复后的 AOF ⽂件,并进⾏数据恢复。
3.3如何选择RDB和AOF
⼀般来说,如果对数据的安全性要求⾮常⾼的话,应该同时使⽤两种持久化功能。 如果可以承受数分钟以内的数据丢失,那么可以只使⽤ RDB 持久化。 有很多⽤户都只使⽤ AOF 持久化, 但并不推荐这种⽅式: 因为定时⽣成 RDB 快照( snapshot )⾮常便于进⾏数据库备份, 并且 RDB 恢复数据集的速度也要⽐ AOF 恢复的速度要快 。
# 禁⽌ RDB ⽅式 save “”
两种持久化策略可以同时使⽤,也可以使⽤其中⼀种。如果同时使⽤的话, 那么 Redis 重启时,会优先使⽤ AOF ⽂件来还原数据。
3.4如何选择RDB和AOF(4.0之前的还需要考虑)
内存数据库 rdb ( redis database ) +aof 数据不能丢 缓存服务器 rdb 不建议 只使⽤ aof ( 性能差 ) 恢复时: 先 aof 再 rdb
3.5混合持久化⽅式
Redis 4.0 之后新增的⽅式,混合持久化是结合了 RDB 和 AOF 的优点,在写⼊的时候,先把当前 的数据以 RDB 的形式写⼊⽂件的开头,再将后续的操作命令以 AOF 的格式存⼊⽂件,这样既能保证 Redis 重启时的速度,⼜能减低数据丢失的⻛险。
RDB 和 AOF 持久化各有利弊, RDB 可能会导致⼀定时间内的数据丢失,⽽ AOF 由于⽂件较⼤则会影响 Redis 的启动速度,为了能同时拥有 RDB 和 AOF 的优点, Redis 4.0 之后新增了混合持久化的⽅式,因 此我们在必须要进⾏持久化操作时,应该选择混合持久化的⽅式。
查询是否开启混合持久化可以使⽤ config get aof-use-rdb-preamble 命令,执⾏结果
127.0.0.1:6379> config get aof-use-rdb-preamble1) "aof-use-rdb-preamble"2) "yes"
其中 yes 表示已经开启混合持久化,no 表示关闭,Redis 5.0 默认值为 yes。如果是其他版本的 Redis ⾸先需要检查⼀下,是否已经开启了混合持久化,如果关闭的情况下,可以通过以下两种⽅式开启:
通过命令⾏开启 通过修改 Redis 配置⽂件开启
(1)通过命令⾏开启
使⽤命令 config set aof-use-rdb-preamble yes 命令⾏设置配置的缺点是重启 Redis 服务之后,设置的配置就会失效。
(2)通过修改 Redis 配置⽂件开启
在 Redis 的根路径下找到 redis.conf ⽂件,把配置⽂件中的 aof-use-rdb-preamble no 改为 aof-use-rdb-preamble yes 配置完成之后,需要重启 Redis 服务器,配置才能⽣效,但修改配置⽂件的⽅式,在每次重启 Redis 服务之后,配置信息不会丢失。需要注意的是,在⾮必须进⾏持久化的业务中,可以关闭持久化,这样可以有效的提升 Redis 的运⾏速度,不会出现间歇性卡顿的困扰。 混合持久化 是RDB+指令 如果AOF⽂件过⼤时候,会重写:把当前数据已RDB格式保存,后续指令⽤aof
四、Redis主从复制
4.1什么是主从复制
主对外从对内,主可写从不可写 主挂了,从不可为主
4.2主从配置
4.2.1主Redis配置
⽆需特殊配置
4.2.2从Redis配置
修改从服务器上的 redis.conf ⽂件:
# slaveof # 表示当前【从服务器】对应的【主服务器】的IP是192.168.10.135,端⼝是6379。slaveof 127.0.0.1 6379replicaof
4.2.3实现原理
Redis 的主从同步,分为 全量同步 和 增量同步 。 只有从机第⼀次连接上主机是 全量同步 。 断线重连有可能触发 全量同步 也有可能是 增量同步( master 判断 runid 是否⼀致)。
除此之外的情况都是 增量同步 。
4.2.4全量同步
Redis 的全量同步过程主要分三个阶段:
同步快照阶段: Master 创建并发送 快照 RDB 给 Slave , Slave 载⼊并解析快照。 Master 同时将此阶段所产⽣的新的写命令存储到缓冲区。 同步写缓冲阶段: Master 向 Slave 同步存储在缓冲区的写操作命令。 同步增量阶段: Master 向 Slave 同步写操作命令。
4.2.5增量同步
Redis 增量同步主要指 ** Slave 完成初始化后开始正常⼯作时, Master 发⽣的写操作同步到 Slave` 的过 程** 。 通常情况下, Master 每执⾏⼀个写命令就会向 Slave 发送相同的 写命令 ,然后 Slave 接收并执⾏。
五、Redis哨兵机制
Redis 主从复制的缺点:没有办法对 master 进⾏动态选举(master宕机后,需要重新选举master),需要使⽤ Sentinel机制完成动态选举。
5.1简介
Redis 的哨兵模式到了 2.8 版本之后 Sentinel ( 哨兵 ) 进程是⽤于监控 Redis 集群中 Master 主服务器⼯作的状态 在 Master 主服务器发⽣故障的时候,可以实现 Master 和 Slave 服务器的切换,保证系统的⾼可⽤( HA )
5.2哨兵进程的作用
监控 ( Monitoring ) :哨兵 ( sentinel ) 会不断地检查你的 Master 和 Slave 是否运作正常。 提醒 ( Notification ) : 当被监控的某个 Redis 节点出现问题时 , 哨兵 ( sentinel ) 可以通过 API 向管理员或者其他应⽤程序发送通知。 ⾃动故障迁移 ( Automatic failover ) :当⼀个 Master 不能正常⼯作时,哨兵 ( sentinel ) 会开始⼀次⾃动故障迁移操作
5.3故障判定原理分析
1. 每个 Sentinel (哨兵)进程以 每秒钟⼀次 的频率向整个集群中的 Master 主服务器, Slave 从服务器以及其他 Sentinel (哨兵)进程发送⼀个 PING 命令。 2. 如果⼀个实例( instance )距离最后⼀次有效回复 PING 命令的时间超过 down-after milliseconds 选项所指定的值, 则这个实例会被 Sentinel (哨兵)进程标记为 主观下线 ( SDOWN )。 3. 如果⼀个 Master 主服务器被标记为主观下线( SDOWN ),则正在监视这个 Master 主服务器的 所 有 Sentinel (哨兵) 进程要以每秒⼀次的频率 确认 Master 主服务器 的确 进⼊了主观下线状态 。 4. 当有⾜够数量的 Sentinel (哨兵) 进程(⼤于等于配置⽂件指定的值)在指定的时间范围内确认Master 主服务器进⼊了主观下线状态( SDOWN ), 则 Master 主服务器会被标记为 客观下线 ( ODOWN ) 。 5. 在⼀般情况下, 每个 Sentinel (哨兵)进程会以每 10 秒⼀次的频率向集群中的所有 Master 主服务器、 Slave 从服务器发送 INFO 命令。 6. 当 Master 主服务器被 Sentinel (哨兵)进程标记为 客观下线( ODOWN ) 时, Sentinel (哨兵)进程向下线的 Master 主服务器的所有 Slave 从服务器发送 INFO 命令的频率会从 10 秒⼀次改为每秒⼀次。 7. 若没有⾜够数量的 Sentinel (哨兵)进程同意 Master 主服务器下线, Master 主服务器的客观下线状态就会被移除。若 Master 主服务器重新向 Sentinel (哨兵)进程发送 PING 命令返回有效回复, Master 主服务器的主观下线状态就会被移除。
5.4⾃动故障迁移
1.它会将失效 Master 的其中⼀个 Slave 升级为新的 Master , 并让失效 Master 的其他 Slave 改为复制新的 Master ; 2.当客户端试图连接失效的 Master 时,集群也会向客户端返回新 Master 的地址,使得集群可以使⽤现在的 Master 替换失效 Master 。 3.Master 和 Slave 服务器切换后, Master 的 redis.conf 、 Slave 的 redis.conf 和 sentinel.conf 的配置⽂件的内容都会发⽣相应的改变,即, Master 主服务器的 redis.conf 配置⽂件中会多⼀⾏ slaveof 的配置, sentinel.conf 的监控⽬标会随之调换。
5.5案例演示
(1)修改从机的 sentinel.conf
# 哨兵sentinel监控的redis主节点的 ip port# master-name 可以⾃⼰命名的主节点名字 只能由字⺟A-z、数字0-9 、这三个字符".-_"组成。# quorum 当这些quorum个数sentinel哨兵认为master主节点失联 那么这时 客观上认为主节点失联了# sentinel monitor sentinel monitor mymaster 192.168.10.133 6379 1
(2)其他配置项说明
sentinel.conf
# 哨兵sentinel实例运⾏的端⼝ 默认26379port 26379# 哨兵sentinel的⼯作⽬录dir /tmp# 哨兵sentinel监控的redis主节点的 ip port# master-name 可以⾃⼰命名的主节点名字 只能由字⺟A-z、数字0-9 、这三个字符".-_"组成。# quorum 当这些quorum个数sentinel哨兵认为master主节点失联 那么这时 客观上认为主节点失联了# sentinel monitor sentinel monitor mymaster 127.0.0.1 6379 1# 当在Redis实例中开启了requirepass foobared 授权密码 这样所有连接Redis实例的客户端都要提供密码# 设置哨兵sentinel 连接主从的密码 注意必须为主从设置⼀样的验证密码# sentinel auth-pass sentinel auth-pass mymaster MySUPER--secret-0123passw0rd# 指定多少毫秒之后 主节点没有应答哨兵sentinel 此时 哨兵主观上认为主节点下线 默认30秒# sentinel down-after-milliseconds sentinel down-after-milliseconds mymaster 30000# 这个配置项指定了在发⽣failover主备切换时最多可以有多少个slave同时对新的master进⾏ 同步,这个数字越⼩,完成failover所需的时间就越⻓,但是如果这个数字越⼤,就意味着越 多的slave因为replication⽽不可⽤。可以通过将这个值设为 1 来保证每次只有⼀个slave 处于不能处理命令请求的状态。# sentinel parallel-syncs sentinel parallel-syncs mymaster 1# 故障转移的超时时间 failover-timeout 可以⽤在以下这些⽅⾯:#1. 同⼀个sentinel对同⼀个master两次failover之间的间隔时间。#2. 当⼀个slave从⼀个错误的master那⾥同步数据开始计算时间。直到slave被纠正为向正确的master那⾥同步数据时。#3.当想要取消⼀个正在进⾏的failover所需要的时间。 #4.当进⾏failover时,配置所有slaves指向新的master所需的最⼤时间。不过,即使过了这个超时,slaves依然会被正确配置为指向master,但是就不按parallel-syncs所配置的规则来了# 默认三分钟# sentinel failover-timeout sentinel failover-timeout mymaster 180000# SCRIPTS EXECUTION#配置当某⼀事件发⽣时所需要执⾏的脚本,可以通过脚本来通知管理员,例如当系统运⾏不正常时发邮件通知相关⼈员。#对于脚本的运⾏结果有以下规则:#若脚本执⾏后返回1,那么该脚本稍后将会被再次执⾏,重复次数⽬前默认为10#若脚本执⾏后返回2,或者⽐2更⾼的⼀个返回值,脚本将不会重复执⾏。#如果脚本在执⾏过程中由于收到系统中断信号被终⽌了,则同返回值为1时的⾏为相同。#⼀个脚本的最⼤执⾏时间为60s,如果超过这个时间,脚本将会被⼀个SIGKILL信号终⽌,之后重新执⾏。#通知型脚本:当sentinel有任何警告级别的事件发⽣时(⽐如说redis实例的主观失效和客观失效等等),将会去调⽤这个脚本,这时这个脚本应该通过邮件,SMS等⽅式去通知系统管理员关于系统不正常运⾏的信息。调⽤该脚本时,将传给脚本两个参数,⼀个是事件的类型,⼀个是事件的描述。#如果sentinel.conf配置⽂件中配置了这个脚本路径,那么必须保证这个脚本存在于这个路径,并且是可执⾏的,否则sentinel⽆法正常启动成功。#通知脚本# sentinel notification-script sentinel notification-script mymaster /var/redis/notify.sh# 客户端重新配置主节点参数脚本# 当⼀个master由于failover⽽发⽣改变时,这个脚本将会被调⽤,通知相关的客户端关于master地址已经发⽣改变的信息。# 以下参数将会在调⽤脚本时传给脚本:# # ⽬前总是“failover”,# 是“leader”或者“observer”中的⼀个。# 参数 from-ip, from-port, to-ip, to-port是⽤来和旧的master和新的master(即旧的slave)通信的# 这个脚本应该是通⽤的,能被多次调⽤,不是针对性的。# sentinel client-reconfig-script sentinel client-reconfig-script mymaster /var/redis/reconfig.sh
(3)通过 redis-sentinel 启动哨兵服务
./redis-sentinel sentinel.conf
六、Redis集群
6.1Redis的集群策略
twproxy codis(豌⾖荚) 代理⽅案
6.2Redis-cluster架构图
Redis3以后,官⽅的集群⽅案 Redis-Cluster Redis3 使⽤lua脚本实现 Redis5 直接实现
架构细节:
(1) 所有的 redis 主节点彼此互联 ( PING-PONG 机制 ), 内部使⽤⼆进制协议优化传输速度和带宽 . (2) 节点的 fail 是通过集群中超过半数的节点检测失效时才⽣效 . (3) 客户端与 redis 节点直连 , 不需要中间 proxy 层 . 客户端不需要连接集群所有节点 , 连接集群中任何⼀个可⽤节点即可 (4)redis-cluster 把所有的物理节点映射到 [0-16383] slot 上 ,cluster 负责维护 nodeslotvalue
Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置⼀个 key-value 时, redis 先对key 使⽤ crc16 算法算出⼀个结果,然后把结果对 16384 求余数,这样每个 key 都会对应⼀个编号在 0-16383 之间的哈希槽, redis 会根据节点数量⼤致均等的将哈希槽映射到不同的节点
示例如下:
6.3Redis-cluster投票:容错
1、主节点投票,如果超过半数的主都认为某主down了,则该主就down了(主选择单数) 2、主节点投票,选出挂了的主的从升级为主注:
集群挂了的情况: 1 、半数的主挂了,不能投票⽣效,则集群挂了 2 、挂了的主机的从也挂了,造成 slot 槽分配不连续( 16384 不能完全分配),集群就挂了
6.4安装RedisCluster
Redis 集群最少需要三台主服务器,三台从服务器。 端⼝号分别为: 7001~7006
(1)第⼀步:创建7001实例,并编辑redis.conf⽂件,修改port为7001。
注意:创建实例,即拷⻉单机版安装时,⽣成的bin⽬录,为7001⽬录。
(2)第⼆步:修改redis.conf配置⽂件,打开cluster-enable yes
(3)第三步:复制7001,创建7002~7006实例,注意端⼝修改。
(4)第四步:创建start.sh,启动所有的实例
cd 7001./redis-server redis.confcd ..cd 7002./redis-server redis.confcd ..cd 7003./redis-server redis.confcd ..cd 7004./redis-server redis.confcd ..cd 7005./redis-server redis.confcd ..cd 7006./redis-server redis.confcd ..
chomd u+x start.sh
(5)第五步:创建Redis集群
[root@localhost 7001]# ./redis-cli --cluster create 127.0.0.1:7001127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006--cluster-replicas 1>>> Performing hash slots allocation on 6 nodes...Master[0] -> Slots 0 - 5460Master[1] -> Slots 5461 - 10922Master[2] -> Slots 10923 - 16383Adding replica 127.0.0.1:7005 to 127.0.0.1:7001Adding replica 127.0.0.1:7006 to 127.0.0.1:7002Adding replica 127.0.0.1:7004 to 127.0.0.1:7003>>> Trying to optimize slaves allocation for anti-affinity[WARNING] Some slaves are in the same host as their masterM: af559fc6c82c83dc39d07e2dfe59046d16b6a429 127.0.0.1:7001 slots:[0-5460] (5461 slots) masterM: 068b678923ad0858002e906040b0fef6fff8dda4 127.0.0.1:7002 slots:[5461-10922] (5462 slots) masterM: d277cd2984639747a17ca79428602480b28ef070 127.0.0.1:7003 slots:[10923-16383] (5461 slots) masterS: 51c3ebdd0911dd6564040c7e20b9ae69cabb0425 127.0.0.1:7004 replicates af559fc6c82c83dc39d07e2dfe59046d16b6a429S: e7b1f1962de2a1ffef2bf1ac5d94574b2e4d67d8 127.0.0.1:7005 replicates 068b678923ad0858002e906040b0fef6fff8dda4S: 78dfe773eaa817fb69a405a3863f5b8fcf3e172f 127.0.0.1:7006 replicates d277cd2984639747a17ca79428602480b28ef070Can I set the above configuration" />6.5命令客户端连接集群 命令:./redis-cli -h 127.0.0.1 -p 7001 -c
注意:-c 表示是以redis集群⽅式进⾏连接
[root@localhost redis-cluster]# cd 7001[root@localhost 7001]# ./redis-cli -h 127.0.0.1 -p 7001 -c127.0.0.1:7001> set name1 aaa-> Redirected to slot [12933] located at 127.0.0.1:7003OK127.0.0.1:7003>
6.6查看集群的命令
(1)查看集群状态
127.0.0.1:7003> cluster infocluster_state:okcluster_slots_assigned:16384cluster_slots_ok:16384cluster_slots_pfail:0cluster_slots_fail:0cluster_known_nodes:6cluster_size:3cluster_current_epoch:6cluster_my_epoch:3cluster_stats_messages_sent:926cluster_stats_messages_received:926
(2)查看集群中的节点:
127.0.0.1:7003> cluster nodesd277cd2984639747a17ca79428602480b28ef070 127.0.0.1:7003@17003 myself,master - 01570457306000 3 connected 10923-16383af559fc6c82c83dc39d07e2dfe59046d16b6a429 127.0.0.1:7001@17001 master - 01570457307597 1 connected 0-5460e7b1f1962de2a1ffef2bf1ac5d94574b2e4d67d8 127.0.0.1:7005@17005 slave068b678923ad0858002e906040b0fef6fff8dda4 0 1570457308605 5 connected068b678923ad0858002e906040b0fef6fff8dda4 127.0.0.1:7002@17002 master - 01570457309614 2 connected 5461-1092251c3ebdd0911dd6564040c7e20b9ae69cabb0425 127.0.0.1:7004@17004 slaveaf559fc6c82c83dc39d07e2dfe59046d16b6a429 0 1570457307000 4 connected78dfe773eaa817fb69a405a3863f5b8fcf3e172f 127.0.0.1:7006@17006 slaved277cd2984639747a17ca79428602480b28ef070 0 1570457309000 6 connected127.0.0.1:7003>
6.7维护节点
集群创建成功后可以继续向集群中添加节点
6.7.1添加主节点
先创建 7007 节点 添加 7007 结点作为新节点 , 并启动 执⾏命令:
[root@localhost 7007]# ./redis-cli --cluster add-node 127.0.0.1:7007127.0.0.1:7001>>> Adding node 127.0.0.1:7007 to cluster 127.0.0.1:7001>>> Performing Cluster Check (using node 127.0.0.1:7001)M: af559fc6c82c83dc39d07e2dfe59046d16b6a429 127.0.0.1:7001 slots:[0-5460] (5461 slots) master 1 additional replica(s)M: d277cd2984639747a17ca79428602480b28ef070 127.0.0.1:7003 slots:[10923-16383] (5461 slots) master 1 additional replica(s)S: e7b1f1962de2a1ffef2bf1ac5d94574b2e4d67d8 127.0.0.1:7005 slots: (0 slots) slave replicates 068b678923ad0858002e906040b0fef6fff8dda4M: 068b678923ad0858002e906040b0fef6fff8dda4 127.0.0.1:7002 slots:[5461-10922] (5462 slots) master 1 additional replica(s)S: 51c3ebdd0911dd6564040c7e20b9ae69cabb0425 127.0.0.1:7004 slots: (0 slots) slave replicates af559fc6c82c83dc39d07e2dfe59046d16b6a429S: 78dfe773eaa817fb69a405a3863f5b8fcf3e172f 127.0.0.1:7006slots: (0 slots) slave replicates d277cd2984639747a17ca79428602480b28ef070[OK] All nodes agree about slots configuration.>>> Check for open slots...>>> Check slots coverage...[OK] All 16384 slots covered.>>> Send CLUSTER MEET to node 127.0.0.1:7007 to make it join the cluster.[OK] New node added correctly.
查看集群结点发现7007已添加到集群中
127.0.0.1:7001> cluster nodesd277cd2984639747a17ca79428602480b28ef070 127.0.0.1:7003@17003 master - 01570457568602 3 connected 10923-1638350b073163bc4058e89d285dc5dfc42a0d1a222f2 127.0.0.1:7007@17007 master - 01570457567000 0 connectede7b1f1962de2a1ffef2bf1ac5d94574b2e4d67d8 127.0.0.1:7005@17005 slave068b678923ad0858002e906040b0fef6fff8dda4 0 1570457569609 5 connected068b678923ad0858002e906040b0fef6fff8dda4 127.0.0.1:7002@17002 master - 01570457566000 2 connected 5461-1092251c3ebdd0911dd6564040c7e20b9ae69cabb0425 127.0.0.1:7004@17004 slaveaf559fc6c82c83dc39d07e2dfe59046d16b6a429 0 1570457567000 4 connectedaf559fc6c82c83dc39d07e2dfe59046d16b6a429 127.0.0.1:7001@17001 myself,master - 01570457567000 1 connected 0-546078dfe773eaa817fb69a405a3863f5b8fcf3e172f 127.0.0.1:7006@17006 slaved277cd2984639747a17ca79428602480b28ef070 0 1570457567593 6 connected
6.7.2hash槽重新分配(数据迁移)
添加完主节点需要对主节点进⾏hash槽分配,这样该主节才可以存储数据。查看集群中槽占⽤情况
cluster nodes
redis集群有16384个槽,集群中的每个结点分配⾃已槽,通过查看集群结点可以看到槽占⽤情况。
127.0.0.1:7001> cluster nodesd277cd2984639747a17ca79428602480b28ef070 127.0.0.1:7003@17003 master - 01570457568602 3 connected 10923-1638350b073163bc4058e89d285dc5dfc42a0d1a222f2 127.0.0.1:7007@17007 master - 01570457567000 0 connectede7b1f1962de2a1ffef2bf1ac5d94574b2e4d67d8 127.0.0.1:7005@17005 slave068b678923ad0858002e906040b0fef6fff8dda4 0 1570457569609 5 connected068b678923ad0858002e906040b0fef6fff8dda4 127.0.0.1:7002@17002 master - 01570457566000 2 connected 5461-1092251c3ebdd0911dd6564040c7e20b9ae69cabb0425 127.0.0.1:7004@17004 slaveaf559fc6c82c83dc39d07e2dfe59046d16b6a429 0 1570457567000 4 connectedaf559fc6c82c83dc39d07e2dfe59046d16b6a429 127.0.0.1:7001@17001 myself,master - 01570457567000 1 connected 0-546078dfe773eaa817fb69a405a3863f5b8fcf3e172f 127.0.0.1:7006@17006 slaved277cd2984639747a17ca79428602480b28ef070 0 1570457567593 6 connected
给刚添加的7007结点分配槽 (1)第⼀步:连接上集群(连接集群中任意⼀个可⽤结点都⾏)
[root@localhost 7007]# ./redis-cli --cluster reshard 127.0.0.1:7007>>> Performing Cluster Check (using node 127.0.0.1:7007)M: 50b073163bc4058e89d285dc5dfc42a0d1a222f2 127.0.0.1:7007 slots: (0 slots) masterS: 51c3ebdd0911dd6564040c7e20b9ae69cabb0425 127.0.0.1:7004 slots: (0 slots) slave replicates af559fc6c82c83dc39d07e2dfe59046d16b6a429S: 78dfe773eaa817fb69a405a3863f5b8fcf3e172f 127.0.0.1:7006 slots: (0 slots) slave replicates d277cd2984639747a17ca79428602480b28ef070S: e7b1f1962de2a1ffef2bf1ac5d94574b2e4d67d8 127.0.0.1:7005 slots: (0 slots) slave replicates 068b678923ad0858002e906040b0fef6fff8dda4M: af559fc6c82c83dc39d07e2dfe59046d16b6a429 127.0.0.1:7001 slots:[0-5460] (5461 slots) master 1 additional replica(s)M: 068b678923ad0858002e906040b0fef6fff8dda4 127.0.0.1:7002 slots:[5461-10922] (5462 slots) master 1 additional replica(s)M: d277cd2984639747a17ca79428602480b28ef070 127.0.0.1:7003 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.
(2)第⼆步:输⼊要分配的槽数量
How many slots do you want to move (from 1 to 16384)? 3000
输⼊:3000,表示要给⽬标节点分配3000个槽
(3)第三步:输⼊接收槽的结点id
What is the receiving node ID?
输⼊:50b073163bc4058e89d285dc5dfc42a0d1a222f2
PS:这⾥准备给7007分配槽,通过cluster nodes查看7007结点id为:50b073163bc4058e89d285dc5dfc42a0d1a222f2
(4)第四步:输⼊源结点id
Please enter all the source node IDs. Type 'all' to use all the nodes as source nodes for the hash slots. Type 'done' once you entered all the source nodes IDs.
输⼊:all
(5)第五步:输⼊yes开始移动槽到⽬标结点id
输⼊:yes
Moving slot 11899 from 127.0.0.1:7003 to 127.0.0.1:7007:Moving slot 11900 from 127.0.0.1:7003 to 127.0.0.1:7007:Moving slot 11901 from 127.0.0.1:7003 to 127.0.0.1:7007:Moving slot 11902 from 127.0.0.1:7003 to 127.0.0.1:7007:Moving slot 11903 from 127.0.0.1:7003 to 127.0.0.1:7007:Moving slot 11904 from 127.0.0.1:7003 to 127.0.0.1:7007:Moving slot 11905 from 127.0.0.1:7003 to 127.0.0.1:7007:Moving slot 11906 from 127.0.0.1:7003 to 127.0.0.1:7007:Moving slot 11907 from 127.0.0.1:7003 to 127.0.0.1:7007:Moving slot 11908 from 127.0.0.1:7003 to 127.0.0.1:7007:Moving slot 11909 from 127.0.0.1:7003 to 127.0.0.1:7007:Moving slot 11910 from 127.0.0.1:7003 to 127.0.0.1:7007:Moving slot 11911 from 127.0.0.1:7003 to 127.0.0.1:7007:Moving slot 11912 from 127.0.0.1:7003 to 127.0.0.1:7007:Moving slot 11913 from 127.0.0.1:7003 to 127.0.0.1:7007:Moving slot 11914 from 127.0.0.1:7003 to 127.0.0.1:7007:Moving slot 11915 from 127.0.0.1:7003 to 127.0.0.1:7007:Moving slot 11916 from 127.0.0.1:7003 to 127.0.0.1:7007:Moving slot 11917 from 127.0.0.1:7003 to 127.0.0.1:7007:Moving slot 11918 from 127.0.0.1:7003 to 127.0.0.1:7007:Moving slot 11919 from 127.0.0.1:7003 to 127.0.0.1:7007:Moving slot 11920 from 127.0.0.1:7003 to 127.0.0.1:7007:Moving slot 11921 from 127.0.0.1:7003 to 127.0.0.1:7007:
(6)查看结果
127.0.0.1:7001> cluster nodesd277cd2984639747a17ca79428602480b28ef070 127.0.0.1:7003@17003 master - 01570458285557 3 connected 11922-1638350b073163bc4058e89d285dc5dfc42a0d1a222f2 127.0.0.1:7007@17007 master - 01570458284000 7 connected 0-998 5461-6461 10923-11921e7b1f1962de2a1ffef2bf1ac5d94574b2e4d67d8 127.0.0.1:7005@17005 slave068b678923ad0858002e906040b0fef6fff8dda4 0 1570458283000 5 connected068b678923ad0858002e906040b0fef6fff8dda4 127.0.0.1:7002@17002 master - 01570458284546 2 connected 6462-1092251c3ebdd0911dd6564040c7e20b9ae69cabb0425 127.0.0.1:7004@17004 slaveaf559fc6c82c83dc39d07e2dfe59046d16b6a429 0 1570458283538 4 connectedaf559fc6c82c83dc39d07e2dfe59046d16b6a429 127.0.0.1:7001@17001 myself,master - 01570458283000 1 connected 999-546078dfe773eaa817fb69a405a3863f5b8fcf3e172f 127.0.0.1:7006@17006 slaved277cd2984639747a17ca79428602480b28ef070 0 1570458284000 6 connected
6.7.3添加从节点
添加7008从结点,将7008作为7007的从结点命令:
./redis-cli --cluster add-node 新节点的ip和端⼝ 旧节点ip和端⼝ --cluster-slave --cluster-master-id 主节点id
例如:
./redis-cli --cluster add-node 127.0.0.1:7008 127.0.0.1:7007 --cluster-slave --cluster-master-id 50b073163bc4058e89d285dc5dfc42a0d1a222f2
50b073163bc4058e89d285dc5dfc42a0d1a222f2是7007结点的id,可通过cluster nodes查看。
[root@localhost 7008]# ./redis-cli --cluster add-node 127.0.0.1:7008127.0.0.1:7007 --cluster-slave --cluster-master-id50b073163bc4058e89d285dc5dfc42a0d1a222f2>>> Adding node 127.0.0.1:7008 to cluster 127.0.0.1:7007>>> Performing Cluster Check (using node 127.0.0.1:7007)M: 50b073163bc4058e89d285dc5dfc42a0d1a222f2 127.0.0.1:7007 slots:[0-998],[5461-6461],[10923-11921] (2999 slots) masterS: 51c3ebdd0911dd6564040c7e20b9ae69cabb0425 127.0.0.1:7004 slots: (0 slots) slave replicates af559fc6c82c83dc39d07e2dfe59046d16b6a429S: 78dfe773eaa817fb69a405a3863f5b8fcf3e172f 127.0.0.1:7006 slots: (0 slots) slave replicates d277cd2984639747a17ca79428602480b28ef070S: e7b1f1962de2a1ffef2bf1ac5d94574b2e4d67d8 127.0.0.1:7005 slots: (0 slots) slave replicates 068b678923ad0858002e906040b0fef6fff8dda4M: af559fc6c82c83dc39d07e2dfe59046d16b6a429 127.0.0.1:7001 slots:[999-5460] (4462 slots) master 1 additional replica(s)M: 068b678923ad0858002e906040b0fef6fff8dda4 127.0.0.1:7002 slots:[6462-10922] (4461 slots) master 1 additional replica(s)M: d277cd2984639747a17ca79428602480b28ef070 127.0.0.1:7003 slots:[11922-16383] (4462 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.>>> Send CLUSTER MEET to node 127.0.0.1:7008 to make it join the cluster.Waiting for the cluster to join.....>>> Configure node as replica of 127.0.0.1:7007.[OK] New node added correctly.
注意:如果原来该结点在集群中的配置信息已经⽣成到cluster-config-file指定的配置⽂件中(如果 cluster-config-file没有指定则默认为nodes.conf),这时可能会报错:
[ERR] Node XXXXXX is not empty. Either the node already knows other nodes(check with CLUSTER NODES) or contains some key in database 0
解决⽅法是删除⽣成的配置⽂件nodes.conf,删除后再执⾏./redis-cli --cluster add-node 指令 查看集群中的结点,刚添加的7008为7007的从节点:
[root@localhost 7008]# ./redis-cli -h 127.0.0.1 -p 7001 -c127.0.0.1:7001> cluster nodesd277cd2984639747a17ca79428602480b28ef070 127.0.0.1:7003@17003 master - 01570458650720 3 connected 11922-16383c3272565847bf9be8ae0194f7fb833db40b98ac4 127.0.0.1:7008@17008 slave50b073163bc4058e89d285dc5dfc42a0d1a222f2 0 1570458648710 7 connected50b073163bc4058e89d285dc5dfc42a0d1a222f2 127.0.0.1:7007@17007 master - 01570458649000 7 connected 0-998 5461-6461 10923-11921e7b1f1962de2a1ffef2bf1ac5d94574b2e4d67d8 127.0.0.1:7005@17005 slave068b678923ad0858002e906040b0fef6fff8dda4 0 1570458650000 5 connected068b678923ad0858002e906040b0fef6fff8dda4 127.0.0.1:7002@17002 master - 01570458649715 2 connected 6462-1092251c3ebdd0911dd6564040c7e20b9ae69cabb0425 127.0.0.1:7004@17004 slaveaf559fc6c82c83dc39d07e2dfe59046d16b6a429 0 1570458648000 4 connectedaf559fc6c82c83dc39d07e2dfe59046d16b6a429 127.0.0.1:7001@17001 myself,master - 01570458650000 1 connected 999-546078dfe773eaa817fb69a405a3863f5b8fcf3e172f 127.0.0.1:7006@17006 slaved277cd2984639747a17ca79428602480b28ef070 0 1570458651725 6 connected127.0.0.1:7001>
6.7.4删除结点
命令:
./redis-cli --cluster del-node 127.0.0.1:700841592e62b83a8455f07f7797f1d5c071cffedb50
删除已经占有hash槽的结点会失败,报错如下:
[ERR] Node 127.0.0.1:7008 is not empty! Reshard data away and try again.
需要将该结点占⽤的hash槽分配出去(参考hash槽重新分配章节)。
6.8Jedis连接集群
需要开启防⽕墙,或者直接关闭防⽕墙。
service iptables stop
6.8.1代码实现
创建JedisCluster类连接redis集群
@Testpublic void testJedisCluster() throws Exception { //创建⼀连接,JedisCluster对象,在系统中是单例存在 Set nodes = new HashSet(); nodes.add(new HostAndPort("192.168.10.133", 7001)); nodes.add(new HostAndPort("192.168.10.133", 7002)); nodes.add(new HostAndPort("192.168.10.133", 7003)); nodes.add(new HostAndPort("192.168.10.133", 7004)); nodes.add(new HostAndPort("192.168.10.133", 7005)); nodes.add(new HostAndPort("192.168.10.133", 7006)); JedisCluster cluster = new JedisCluster(nodes); //执⾏JedisCluster对象中的⽅法,⽅法和redis⼀⼀对应。 cluster.set("cluster-test", "my jedis cluster test"); String result = cluster.get("cluster-test"); System.out.println(result); //程序结束时需要关闭JedisCluster对象 cluster.close();}
6.8.2使⽤spring
配置applicationContext.xml
Ø 测试代码
private ApplicationContext applicationContext; @Before public void init() { applicationContext = new ClassPathXmlApplicationContext( "classpath:applicationContext.xml"); } // redis集群 @Test public void testJedisCluster() { JedisCluster jedisCluster = (JedisCluster) applicationContext .getBean("jedisCluster"); jedisCluster.set("name", "zhangsan"); String value = jedisCluster.get("name"); System.out.println(value); }