这里我用docker实现:
结构:
[root@14ba6e5d00c2 redis]# ls
redis-3.2.8 redis-6379 redis-6380 redis-6381
#bind 127.0.0.1
bind 0.0.0.0
bind 0.0.0.0
port 6379
daemonize yes
pidfile "/sys/fs/cgroup/redis_6379.pid"
logfile "/sys/fs/cgroup/redis_6379.log"
dbfilename "dump6379.rdb"
dir "/sys/fs/cgroup"
appendonly no
appendfilename "appendonly.aof"
sentinel monitor mymaster 127.0.0.1 6379 1
ps:启动各个redis,和sentinel,记得把 主从关系搭建好!
java:代码 贴一些关键的(读写分离,自动读取或写入 最新的redis,和发现最新的从redis):
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import redis.clients.jedis.JedisPoolConfig;
import cn.com.qiqi.springMvcTest.core.JedisSentinelPoolExt;
import cn.com.qiqi.springMvcTest.core.RedisDataSource;
import cn.com.qiqi.springMvcTest.core.RedisDataSourceImpl;
@Configuration
@PropertySource(value="classpath:/redis.properties")
public class RedisConfig {
@Value("${redis.masterName}")
private String masterName;
@Value("${redis.sentinals}")
private String sentinal_hostAndPorts;
@Bean(name="redisDataSource")
public RedisDataSource redisDataSource(){
JedisPoolConfig poolConfig=new JedisPoolConfig();
poolConfig.setMaxTotal(1000);
poolConfig.setMaxIdle(32);
poolConfig.setTestOnBorrow(true);
poolConfig.setMaxWaitMillis(100*1000);
System.out.println(masterName+":"+sentinal_hostAndPorts);
JedisSentinelPoolExt jedisSentinelPoolExt=new JedisSentinelPoolExt(masterName, sentinal_hostAndPorts, poolConfig, 100, 200, 10, true);
RedisDataSourceImpl dataSourceImpl =new RedisDataSourceImpl();
dataSourceImpl.setJedisSentinelPool(jedisSentinelPoolExt);
return dataSourceImpl;
}
}
#redis
#masterName
redis.masterName=mymaster
#sentinal-HostAndPort
redis.sentinals=192.168.1.107:26379
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPubSub;
import redis.clients.jedis.Protocol;
import redis.clients.jedis.exceptions.JedisConnectionException;
import redis.clients.jedis.exceptions.JedisException;
import redis.clients.util.Pool;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* 高级哨兵池
*/
public class JedisSentinelPoolExt extends Pool {
protected GenericObjectPoolConfig poolConfig;
protected int connectionTimeout = Protocol.DEFAULT_TIMEOUT;
protected int soTimeout = Protocol.DEFAULT_TIMEOUT;
protected String password;
protected int database = Protocol.DEFAULT_DATABASE;
protected String clientName;
protected Set masterListeners = new HashSet();
protected Set slaveDownListeners = new HashSet();
protected Set slaveUpListeners = new HashSet();
protected List readHaps = new ArrayList();
protected List jedisReadPools = new CopyOnWriteArrayList();
protected Set _sentinels = new LinkedHashSet();
protected Map failMap = new ConcurrentHashMap();
private String masterName;
private int failMax;
protected boolean masterWriteOnly;
protected long subscribeRetryWaitTimeMillis = 5000;
protected Logger log = Logger.getLogger(getClass().getName());
private volatile JedisFactory factory;
private volatile HostAndPort currentHostMaster;
public JedisSentinelPoolExt(String masterName, String sentinels, final GenericObjectPoolConfig poolConfig, int connectionTimeout, int soTimeout, int failMax, boolean masterWriteOnly) {
this(masterName, sentinels, poolConfig, null, connectionTimeout, soTimeout, failMax, masterWriteOnly, null);
}
public JedisSentinelPoolExt(String masterName, String sentinels, final GenericObjectPoolConfig poolConfig, int connectionTimeout, int soTimeout, int failMax, boolean masterWriteOnly, String clientName) {
this(masterName, sentinels, poolConfig, null, connectionTimeout, soTimeout, failMax, masterWriteOnly, clientName);
}
public JedisSentinelPoolExt(String masterName, String sentinels, final GenericObjectPoolConfig poolConfig, final String password, int connectionTimeout, int soTimeout, int failMax, boolean masterWriteOnly) {
this(masterName, sentinels, poolConfig, password, connectionTimeout, soTimeout, failMax, masterWriteOnly, null);
}
public JedisSentinelPoolExt(String masterName, String sentinels, final GenericObjectPoolConfig poolConfig, final String password, int connectionTimeout, int soTimeout, int failMax, boolean masterWriteOnly, String clientName) {
String[] strings = sentinels.split(",");
Collections.addAll(_sentinels, strings);
this.poolConfig = poolConfig;
this.connectionTimeout = connectionTimeout;
this.soTimeout = soTimeout;
if (!StringUtils.isBlank(password)) {
this.password = password;
}
this.database = Protocol.DEFAULT_DATABASE;
this.failMax = failMax;
this.masterName = masterName;
this.masterWriteOnly = masterWriteOnly;
if (!StringUtils.isBlank(clientName)) {
this.clientName = clientName;
}
HostAndPort master = initSentinels(_sentinels, masterName);
initPool(master);
initReadPool();
}
private void initReadPool() {
updateReadPools(readHaps);
}
/**
* 获取写实例
* @return
*/
public WriteJedis getWriteResource() {
return new WriteJedis(getResource());
}
/**
* 获取读实例
* @return
*/
public ReadJedis getReadResource() {
if (jedisReadPools.size() == 0) {
throw new RedisException("there is no jedis for read");
}
// 从redis读池中随机获取一个实例
Random rand = new Random();
int randNum = rand.nextInt(jedisReadPools.size());
JedisPoolExt jedisPoolExt = jedisReadPools.get(randNum);
HostAndPort hostAndPort = jedisPoolExt.getHostAndPort();
JedisPool jedisPool = jedisPoolExt.getJedisPool();
ReadJedis readJedis;
try {
Jedis jedis = jedisPool.getResource();
readJedis = new ReadJedis(jedis, jedisPool);
} catch (Throwable e) {
// 添加失败列表
addFailMap(hostAndPort, jedisPool);
// 重试其它连接池
if (jedisReadPools.size() > 1) {
while (true) {
// 随机获取另一个读节点,仍然连接失败就抛异常
int randNum1 = rand.nextInt(jedisReadPools.size());
if (randNum1 != randNum) {
JedisPoolExt jedisPoolExt1 = jedisReadPools.get(randNum1);
JedisPool jedisPool1 = jedisPoolExt1.getJedisPool();
try {
Jedis jedis = jedisPool1.getResource();
readJedis = new ReadJedis(jedis, jedisPool1);
} catch (Exception e1) {
addFailMap(hostAndPort, jedisPool);
throw new RedisException("JedisSentinelPoolExt getReadResource retry error", e1);
}
return readJedis;
}
}
} else {
throw new RedisException(e);
}
}
return readJedis;
}
/**
* 连接失败的实例,放入失败记录列表,超过指定失败次数的实例,会从读节点列表中丢弃
* @param hostAndPort
* @param jedisPool
*/
private void addFailMap(HostAndPort hostAndPort, JedisPool jedisPool) {
if (failMax != 0 && jedisReadPools.size() > 1) {
Integer failTimes = failMap.get(hostAndPort);
if (failTimes == null) {
failTimes = 1;
} else {
failTimes++;
}
if (failTimes >= failMax) {
failMap.remove(hostAndPort);
jedisPool.close();
removeFromReadPool(hostAndPort);
} else {
failMap.put(hostAndPort, failTimes);
}
}
}
public void resetReadPool() {
initSentinels(_sentinels, masterName);
initReadPool();
failMap.clear();
}
public void destroy() {
for (MasterListener m : masterListeners) {
m.shutdown();
}
for (SlaveDownListener m : slaveDownListeners) {
m.shutdown();
}
for (SlaveUpListener m : slaveUpListeners) {
m.shutdown();
}
super.destroy();
}
public HostAndPort getCurrentHostMaster() {
return currentHostMaster;
}
protected void initPool(HostAndPort master) {
if (!master.equals(currentHostMaster)) {
currentHostMaster = master;
if (factory == null) {
factory = new JedisFactory(master.getHost(), master.getPort(), connectionTimeout,
soTimeout, password, database, clientName);
initPool(poolConfig, factory);
} else {
factory.setHostAndPort(currentHostMaster);
// although we clear the pool, we still have to check the
// returned object
// in getResource, this call only clears idle instances, not
// borrowed instances
internalPool.clear();
}
log.info("Created JedisPool to master at " + master);
}
}
protected HostAndPort initSentinels(Set sentinels, final String masterName) {
HostAndPort master = null;
boolean sentinelAvailable = false;
log.info("Trying to find master from available Sentinels...");
for (String sentinel : sentinels) {
final HostAndPort hap = toHostAndPort(Arrays.asList(sentinel.split(":")));
log.fine("Connecting to Sentinel " + hap);
Jedis jedis = null;
try {
jedis = new Jedis(hap.getHost(), hap.getPort());
List masterAddr = jedis.sentinelGetMasterAddrByName(masterName);
// connected to sentinel...
sentinelAvailable = true;
if (masterAddr == null || masterAddr.size() != 2) {
log.warning("Can not get master addr, master name: " + masterName + ". Sentinel: " + hap
+ ".");
continue;
}
master = toHostAndPort(masterAddr);
log.fine("Found Redis master at " + master);
initReadHaps(jedis, masterName, master);
break;
} catch (JedisConnectionException e) {
log.warning("Cannot connect to sentinel running @ " + hap + ". Trying next one.");
} finally {
if (jedis != null) {
jedis.close();
}
}
}
if (master == null) {
if (sentinelAvailable) {
// can connect to sentinel, but master name seems to not
// monitored
throw new JedisException("Can connect to sentinel, but " + masterName
+ " seems to be not monitored...");
} else {
throw new JedisConnectionException("All sentinels down, cannot determine where is "
+ masterName + " master is running...");
}
}
log.info("Redis master running at " + master + ", starting Sentinel listeners...");
for (MasterListener masterListener : masterListeners) {
masterListener.shutdown();
}
masterListeners.clear();
for (SlaveDownListener slaveDownListener : slaveDownListeners) {
slaveDownListener.shutdown();
}
slaveDownListeners.clear();
for (SlaveUpListener slaveUpListener : slaveUpListeners) {
slaveUpListener.shutdown();
}
slaveUpListeners.clear();
for (String sentinel : sentinels) {
final HostAndPort hap = toHostAndPort(Arrays.asList(sentinel.split(":")));
MasterListener masterListener = new MasterListener(masterName, hap.getHost(), hap.getPort());
masterListeners.add(masterListener);
masterListener.start();
SlaveDownListener slaveDownListener = new SlaveDownListener(masterName, hap.getHost(), hap.getPort());
slaveDownListeners.add(slaveDownListener);
slaveDownListener.start();
SlaveUpListener slaveUpListener = new SlaveUpListener(masterName, hap.getHost(), hap.getPort());
slaveUpListeners.add(slaveUpListener);
slaveUpListener.start();
}
return master;
}
private void initReadHaps(Jedis jedis, String masterName, HostAndPort master) {
List
使用:
@Controller
public class HomeController {
@Autowired
private RedisDataSource redisDataSource;
private static int z=1;
@RequestMapping(value = "/setKey", method = RequestMethod.GET)
@ResponseBody
public String setKey() {
z++;
String ss=String.valueOf(z);
redisDataSource.getRedisWriteClient().set(ss, ss);
return ss;
}
@RequestMapping(value = "/getKey", method = RequestMethod.GET)
@ResponseBody
public String getKey(HttpServletRequest request) {
String ss=request.getParameter("key");
return redisDataSource.getRedisReadClient().get(ss);
}