概述
Redis哨兵为Redis提供了高可用性。可以使用哨兵模式创建一个可以不用人为干预而应对各种故障的Redis部署。
哨兵模式还提供了其他的附加功能,如监控,通知,为客户端提供配置。
下面是在宏观层面上哨兵模式的功能列表:
- 监控:哨兵不断的检查master和slave是否正常的运行。
- 通知:当监控的某台Redis实例发生问题时,可以通过API通知系统管理员和其他的应用程序。
- 自动故障转移:如果一个master不正常运行了,哨兵可以启动一个故障转移进程,将一个slave升级成为master,其他的slave被重新配置使用新的master,并且应用程序使用Redis服务端通知的新地址。
- 配置提供者:哨兵作为Redis客户端发现的权威来源:客户端连接到哨兵请求当前可靠的master的地址。如果发生故障,哨兵将报告新地址。
特性
Redis哨兵是一个分布式系统:
哨兵自身设计成和多个哨兵进程一起合作运行。这样做的好处有:
- 当多个哨兵对一个master不再可用达成一致时执行故障检测。这会降低错误判断的概率。
- 只要大多数哨兵正常运行就可以,增强系统健壮性。毕竟在故障系统里单点故障没有什么意义。
哨兵部署和故障转移过程
下面以部署三个哨兵为例(配置quorum = 2):
- Box:代表服务器
- Redis:代表Redis实例
- Sentinel:代表Redis哨兵实例
- Client:代表连接到Redis的客户端
- Redis1:为master
- Redis2和Redis3为Redis1的Slave
- 其中三个哨兵都监控Master1;
下面是Box1主机发生故障之后的转移过程:
- Sentinel2检测到Box1故障,标记状态为SDOWN;
- Sentinel3检测到Box1故障,标记状态为SDOWN;
- 因标记SDOWN状态数量 >= 配置的quorum ,标记Redis实例状态为ODOWN,触发故障转移;
- 通过算法选举出一个Leader(如Sentinel2);
- Sentinel2请求其他Sentinel(Sentinel3)的授权(注意这里需要得到半数以上的哨兵授权);
- Sentinel2得到授权后通过算法选举出合适的Slave(如Slave2)晋升为Master;
- Sentinel更改配置监听新Master,并把其他的Redis配置为新Master的Slave;
- 通知客户端连接新Master。
使用
使用之前需要知道的事情
- 一个健壮的部署至少需要三个哨兵实例
- 三个哨兵实例最好放在三个不同的物理机上
- 使用的客户端必须支持哨兵(一般流行的都支持)
服务端配置(运维部同事需仔细看看)
sentinel.conf(注意所有哨兵配置都相同)
# port <sentinel port>
#
# 哨兵实例运行端口
port 26379
# sentinel monitor <master-
name
> <ip> <redis-port> <quorum>
#
# 配置监控master
#
# <master-
name
>:配置监控master实例名字
# <ip>:Redis master所在IP
# <redis-port>:Redis master运行端口
# <quorum>: 至少<quorum>个同意,master才能进入o_down状态触发故障转移
#
# 示例:
sentinel monitor mymaster 192.168.45.136 6379 2
#
# sentinel auth-pass <master-
name
> <
password
>
# 配置连接master的授权密码
#
# <master-
name
>:配置监控master实例名字
# <
password
>:Redis master密码
#
# 示例:
sentinel auth-pass mymaster 123456
# sentinel down-
after
-milliseconds <master-
name
> <milliseconds>
#
# 配置master被认为是不可用的时间,超过这个时间即标为S_DOWN
#
# <master-
name
>:监控master实例名字
# <milliseconds>:毫秒,默认30秒
#
# 示例:
sentinel down-
after
-milliseconds mymaster 1000
# sentinel failover-timeout <master-
name
> <milliseconds>
#
# 设置故障转移超时时间,默认3分钟
#
# <master-
name
>:master实例名字
# <milliseconds>:毫秒,默认3分钟
#
# 示例:
sentinel failover-timeout mymaster 5000
# sentinel parallel-syncs <master-
name
> <numslaves>
#
# 故障转移的同时,重新配置slave指向的数量。
#
# <master-
name
>:master实例名字
# <numslaves>:Slave数量
#
# 示例:
sentinel parallel-syncs mymaster 1
# sentinel client-reconfig-script <master-
name
> <script-path>
#
# 发生故障转移后执行的脚本
# 输出参数:<master-
name
> <role> <state> <
from
-ip> <
from
-port> <
to
-ip> <
to
-port>
# <master-
name
>:master实例名字
# <script-path>:shell脚本绝对路径
#
# 示例:
sentinel client-reconfig-script mymaster /home/mjw/testfunc.sh
|
redis.conf
//配置master授权密码
masterauth
123456
//配置master密码
requirepass
123456
//配置slave(注意master不用此配置)
slaveof <masterip> <masterport>
|
客户端代码示例
使用哨兵代码非常简单,只需要在客户端改动一下连接方式即可(注意连接的是哨兵的地址)
连接哨兵客户端示例
public
static
void
testSentinel(){
Set<String> sentinels =
new
HashSet<String>();
//注意,这里是哨兵的地址
sentinels.add(
"192.168.45.142:26379"
);
sentinels.add(
"192.168.45.143:26379"
);
sentinels.add(
"192.168.45.144:26379"
);
GenericObjectPoolConfig config =
new
GenericObjectPoolConfig();
config.setMinIdle(
1
);
config.setTestOnBorrow(
true
);
//mymaster:哨兵配置监控的Redis实例名字
//123456:密码
JedisSentinelPool pool =
new
JedisSentinelPool(
"mymaster"
, sentinels,config,
"123456"
);
for
(
int
i =
0
;i <
100000
;i++){
Jedis jedis =
null
;
try
{
Thread.sleep(
1000
);
jedis = pool.getResource();
jedis.set(
"testSentinel"
+ i,
"testSentinelValue"
+ i);
System.out.println(jedis.get(
"testSentinel"
+ i));
}
catch
(Exception e) {
System.out.println(
new
SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss"
).format(
new
Date()));
System.out.println(
"error!"
+ e.getMessage());
}
finally
{
if
(jedis !=
null
) {
try
{
jedis.close();
}
catch
(Exception e) {
e.printStackTrace();
}
}
}
}
}
|