单机模式 和 主备模式其实差不多,
哨兵模式的服务架构: master 一个,多个 slave, 多个哨兵。
部署好了redis 后,开启master
./redis-4.0/src/redis-server …/conf/redis-master-6379.conf
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#绑定的ip 地址,可多个
bind 192.168.23.11 127.0.0.1
#端口号
port 6379
tcp-backlog 511
timeout 0
tcp-keepalive 300
# 守护进程运行
daemonize yes
#pid存放路径
pidfile "/var/run/redis_6379.pid"
loglevel notice
#日志存放路径
logfile "/home/smkapp/redislog/log6379.log"
#数据库开启数量
databases 2
always-show-logo yes
开启slave
./redis-4.0/src/redis-server …/conf/redis-slave-6380.conf
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#绑定的ip 地址,可多个
bind 192.168.23.11 127.0.0.1
#端口号
port 6380
tcp-backlog 511
timeout 0
tcp-keepalive 300
# 守护进程运行
daemonize yes
#pid存放路径
pidfile "/var/run/redis_6380.pid"
loglevel notice
#日志存放路径
logfile "/home/smkapp/redislog/log6380.log"
#数据库开启数量
databases 2
slaveof 192.168.23.11 6379
always-show-logo yes
开启 哨兵
./redis-4.0/src/redis-sentinel …/conf/redis-sentinel-26379.conf
#绑定的ip 地址,可多个
bind 192.168.23.11 127.0.0.1
#端口号
port 26380
tcp-backlog 511
timeout 0
tcp-keepalive 300
# 守护进程运行
daemonize yes
#pid存放路径
pidfile "/var/run/redis_6380.pid"
loglevel notice
#日志存放路径
logfile "/home/smkapp/redislog/log6380.log"
#监控master
sentinel monitor luoyangmaster 192.168.23.11 6381 1
#指定超时时间 5秒
sentinel down-after-milliseconds luoyangmaster 5000
网上找了好些 哨兵模式的 JAVA客户端,没找到合适的。
自己写了一个样例,算是基本可以跑,在切换master 的时候,还是有有一定量的请求报错
package com.redis;
import java.util.HashSet;
import java.util.Set;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.JedisSentinelPool;
public class RedisClientSentinel {
public static final int default_seconds = 300;
private static RedisClientSentinel client = null;
private JedisSentinelPool poolConfig = null;
private RedisClientSentinel() {
try {
getPool();
} catch (Exception e) {
e.printStackTrace();
}
}
public static synchronized RedisClientSentinel getInstance() {
if (null == client) {
client = new RedisClientSentinel();
}
return client;
}
/**
* 单例模式
*
* @return
*/
private JedisSentinelPool getPool() {
if (poolConfig == null || poolConfig.isClosed()) {
Set sentinels = new HashSet<>();
sentinels.add("192.168.23.11:26379");
sentinels.add("192.168.23.11:26380");
JedisPoolConfig ab = new JedisPoolConfig();
ab.setMinIdle(Integer.parseInt("5"));
ab.setMaxTotal(5);
ab.setMaxIdle(5);
poolConfig = new JedisSentinelPool("luoyangmaster", sentinels, ab);
}
return poolConfig;
}
private Jedis getJedis() {
//查看当前获得的 master 的ip和 端口
System.out.println(poolConfig.getCurrentHostMaster());
// 从哨兵里面 获取链接
return getPool().getResource();
}
/**
* 返回值
*
* @param key
* @return
*/
public String getStringValue(String key) {
Jedis j = getJedis();
String d = null;
try {
d = j.get(key);
// 连接是OK的 返回到连接池里面
poolConfig.returnResourceObject(j);
} catch (Exception e) {
//链接出现异常
System.out.println("异常");
//异常要关闭
j.close();
}
// j.close();
return d;
}
public static void main(String[] args) {
new Thread(new Tre()).start();
new Thread(new Tre()).start();
new Thread(new Tre()).start();
new Thread(new Tre()).start();
new Thread(new Tre()).start();
new Thread(new Tre()).start();
}
public static int i = 0;
public synchronized static void add() {
i++;
}
}
class Tre implements Runnable{
@Override
public void run() {
RedisClientSentinel s = RedisClientSentinel.getInstance();
while (true) {
try {
String d = s.getStringValue("username");
if(d == null) {
RedisClientSentinel.add();
}
System.out.println(RedisClientSentinel.i);
} catch (Exception e) {
e.printStackTrace();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
在哨兵模式里面,获取的连接客户端 Jedis ,这个客户端连接是对接的master,
但是如果这个master 宕机了,哨兵会选举一个新的master 出来。这个时候原来的 jedis 客户端就不可用了。
针对这种情况,JAVA客户端要获取新的master 来链接。
所以在每次使用的时候,都需要从 哨兵连接池里面获取新的 客户端getPool().getResource();
在使用的时候,如果报错,就需要关闭客户端jedis.close();
连接池里面的客户端是有数量限制的,如果取出来了不还回去,那么就只能操作几次,后续都操作都阻塞了。
所以每次使用了 jedis 客户端之后,如果连接正常,就需要将连接客户端还回去poolConfig.returnResourceObject(jedis);
我这是大致研究了一下这个哨兵模式的用法,但是总觉得还有更优秀的使用方式,如有说的不对的地方,欢迎拍砖