https://blog.csdn.net/panchang199266/article/details/81463026
下文参见Sentinel
(一)Redis Sentinel 模式简介
Redis 的 Sentinel 系统用于管理多个 Redis 服务器(instance), 该系统执行以下三个任务:
Redis Sentinel 是一个分布式系统, 你可以在一个架构中运行多个 Sentinel 进程(progress), 这些进程使用流言协议(gossip protocols)来接收关于主服务器是否下线的信息, 并使用投票协议(agreement protocols)来决定是否执行自动故障迁移, 以及选择哪个从服务器作为新的主服务器。
虽然 Redis Sentinel 释出为一个单独的可执行文件 redis-sentinel , 但实际上它只是一个运行在特殊模式下的 Redis 服务器, 你可以在启动一个普通 Redis 服务器时通过给定 –sentinel 选项来启动 Redis Sentinel 。
(二)启动 Sentinel
对于 redis-sentinel 程序, 你可以用以下命令来启动 Sentinel 系统:
./redis-sentinel /path/to/sentinel.conf
对于 redis-server 程序, 你可以用以下命令来启动一个运行在 Sentinel 模式下的 Redis 服务器:
./redis-server /path/to/sentinel.conf --sentinel
两种方法都可以启动一个 Sentinel 实例。
启动 Sentinel 实例必须指定相应的配置文件, 系统会使用配置文件来保存 Sentinel 的当前状态, 并在 Sentinel 重启时通过载入配置文件来进行状态还原。
如果启动 Sentinel 时没有指定相应的配置文件, 或者指定的配置文件不可写(not writable), 那么 Sentinel 会拒绝启动。
(四)环境准备
1、配置1主2从redis-server
备注:
(1)由于当主节点发生故障时,原本的从节点会提升为主节点,所以从节点也必须能写能读,所以slave-read-only yes
这个选项必须注释掉。否则当从节点提升为主节点时,只能读不能写!
(2)在配置从节点时,记得将slave 127.0.0.1 7000
改为slave 服务器ip 7000
。必须改为真实的服务器ip,否则当客户端远程连接节点时,会将其识别为本机。
2、配置3个redis-sentinel
Redis 源码中包含了一个名为 sentinel.conf 的文件, 这个文件是一个带有详细注释的 Sentinel 配置文件示例。
运行一个 Sentinel 所需的最少配置如下所示:
//守护进程,后台启动
daemonize yes
sentinel monitor mymaster 192.168.10.130 6379 2
sentinel down-after-milliseconds mymaster 60000
sentinel failover-timeout mymaster 180000
sentinel parallel-syncs mymaster 1
sentinel monitor resque 192.168.1.1 6380 4
sentinel down-after-milliseconds resque 10000
sentinel failover-timeout resque 180000
sentinel parallel-syncs resque 5
第一行配置指示 Sentinel 去监视一个名为 mymaster 的主服务器, 这个主服务器的 IP 地址为 192.168.10.130 , 端口号为 6379 , 而将这个主服务器判断为失效至少需要 2 个 Sentinel 同意 (只要同意 Sentinel 的数量不达标,自动故障迁移就不会执行)。
不过要注意, 无论你设置要多少个 Sentinel 同意才能判断一个服务器失效, 一个 Sentinel 都需要获得系统中多数(majority) Sentinel 的支持, 才能发起一次自动故障迁移, 并预留一个给定的配置纪元 (configuration Epoch ,一个配置纪元就是一个新主服务器配置的版本号)。
换句话说, 在只有少数(minority) Sentinel 进程正常运作的情况下, Sentinel 是不能执行自动故障迁移的。
其他选项的基本格式如下:
sentinel <选项的名字> <主服务器的名字> <选项的值>
各个选项的功能如下:
down-after-milliseconds 选项指定了 Sentinel 认为服务器已经断线所需的毫秒数。
如果服务器在给定的毫秒数之内, 没有返回 Sentinel 发送的 PING 命令的回复, 或者返回一个错误, 那么 Sentinel
将这个服务器标记为主观下线(subjectively down,简称 SDOWN )。
不过只有一个 Sentinel 将服务器标记为主观下线并不一定会引起服务器的自动故障迁移: 只有在足够数量的 Sentinel
都将一个服务器标记为主观下线之后, 服务器才会被标记为客观下线(objectively down, 简称 ODOWN ),
这时自动故障迁移才会执行。
将服务器标记为客观下线所需的 Sentinel 数量由对主服务器的配置决定。
parallel-syncs 选项指定了在执行故障转移时, 最多可以有多少个从服务器同时对新的主服务器进行同步, 这个数字越小,
完成故障转移所需的时间就越长。
如果从服务器被设置为允许使用过期数据集(参见对 redis.conf 文件中对 slave-serve-stale-data
选项的说明), 那么你可能不希望所有从服务器都在同一时间向新的主服务器发送同步请求, 因为尽管复制过程的绝大部分步骤都不会阻塞从服务器,
但从服务器在载入主服务器发来的 RDB 文件时, 仍然会造成从服务器在一段时间内不能处理命令请求:
如果全部从服务器一起对新的主服务器进行同步, 那么就可能会造成所有从服务器在短时间内全部不可用的情况出现。
你可以通过将这个值设为 1 来保证每次只有一个从服务器处于不能处理命令请求的状态。
3、开启redis-server和redis-sentinel
//开启redis-server
./redis-server server配置文件
//开启redis-sentinel
./redis-sentinel sentinel配置文件
备注:注意开启redis-server和redis-sentinel的命令不一样
(五)客户端访问
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisSentinelPool;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
* @author 咸鱼
* @date 2018/7/1 22:04
*/
public class RedisTest {
private static final Logger LOGGER = LoggerFactory.getLogger(RedisTest.class);
@Test
public void testRedisSentinel(){
String masterName = "mymaster";
//这里主要是向set集合中增加数据,所有底层用链表效率最高
Set sentinels = new HashSet<>();
//为了redis客户端可以远程连接这些端口,需要在linux服务器上开启这些端口
sentinels.add("192.168.10.130:26379");
sentinels.add("192.168.10.130:26380");
sentinels.add("192.168.10.130:26381");
//创建JedisSentinel线程池
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
poolConfig.setMaxIdle(8);
poolConfig.setMinIdle(0);
poolConfig.setMaxTotal(8);
// JedisSentinelPool pool = new JedisSentinelPool(masterName, sentinels, poolConfig);
//超时时间:毫秒
JedisSentinelPool pool = new JedisSentinelPool(masterName, sentinels, poolConfig, 10000);
int counter = 0;
while (true){
//获取redis客户端
Jedis jedis = null;
try {
jedis = pool.getResource();
int index = new Random().nextInt(10000);
String key = "k-" + index;
String value = "v-" + index;
jedis.set(key, value);
counter++;
if (counter % 100 == 0){
LOGGER.info("{} value is {}", key, jedis.get(key));
}
//休息10秒
TimeUnit.MILLISECONDS.sleep(10);
} catch (Exception e){
LOGGER.error(e.getMessage(), e);
} finally {
if (jedis != null){
jedis.close();
}
}
}
}
}
(六)主观下线和客观下线
前面说过, Redis 的 Sentinel 中关于下线(down)有两个不同的概念:
如果一个服务器没有在 master-down-after-milliseconds 选项所指定的时间内, 对向它发送 PING 命令的 Sentinel 返回一个有效回复(valid reply), 那么 Sentinel 就会将这个服务器标记为主观下线。
服务器对 PING 命令的有效回复可以是以下三种回复的其中一种:
如果服务器返回除以上三种回复之外的其他回复, 又或者在指定时间内没有回复 PING 命令, 那么 Sentinel 认为服务器返回的回复无效(non-valid)。
注意, 一个服务器必须在 master-down-after-milliseconds 毫秒内, 一直返回无效回复才会被 Sentinel 标记为主观下线。
举个例子, 如果 master-down-after-milliseconds 选项的值为 30000 毫秒(30 秒), 那么只要服务器能在每 29 秒之内返回至少一次有效回复, 这个服务器就仍然会被认为是处于正常状态的。
从主观下线状态切换到客观下线状态并没有使用严格的法定人数算法(strong quorum algorithm), 而是使用了流言协议: 如果 Sentinel 在给定的时间范围内, 从其他 Sentinel 那里接收到了足够数量的主服务器下线报告, 那么 Sentinel 就会将主服务器的状态从主观下线改变为客观下线。 如果之后其他 Sentinel 不再报告主服务器已下线, 那么客观下线状态就会被移除。
客观下线条件只适用于主服务器: 对于任何其他类型的 Redis 实例, Sentinel 在将它们判断为下线前不需要进行协商, 所以从服务器或者其他 Sentinel 永远不会达到客观下线条件。
只要一个 Sentinel 发现某个主服务器进入了客观下线状态, 这个 Sentinel 就可能会被其他 Sentinel 推选出, 并对失效的主服务器执行自动故障迁移操作。
(七)每个 Sentinel 都需要定期执行的任务
(八)自动发现 Sentinel 和从服务器
一个 Sentinel 可以与其他多个 Sentinel 进行连接, 各个 Sentinel 之间可以互相检查对方的可用性, 并进行信息交换。
你无须为运行的每个 Sentinel 分别设置其他 Sentinel 的地址, 因为 Sentinel 可以通过发布与订阅功能来自动发现正在监视相同主服务器的其他 Sentinel , 这一功能是通过向频道 sentinel:hello 发送信息来实现的。
与此类似, 你也不必手动列出主服务器属下的所有从服务器, 因为 Sentinel 可以通过询问主服务器来获得所有从服务器的信息。
关于“从slave节点中选出一个“合适的”节点作为新的master节点”中的合适的条件如下: