The Redis client simply encapsulates and integrates Spring. Spring-data-redis is suspected of over-encapsulating Redis, and does not provide Sharding mode, so this paper simply encapsulates Jedis.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="Http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"
default-autowire="byName">
<! -- single instance -->
<bean id="singletonRedisClient" class="com.itlong.whatsmars.redis.client.singleton.SingletonRedisClient">
<property name="host" value="127.0.0.1"/>
<property name="port" value="6379" />
<property name="maxTotal" value="256"/>
<property name="maxIdle" value="8" />
<property name="maxWait" value="3000" />
<property name="timeout" value="3000" />
<property name="minIdle" value="2" />
</bean>
<!-- M-S读写分离 -->
<bean id="readWriteRedisClient" class="com.itlong.whatsmars.redis.client.readwrite.ReadWriteRedisClient">
<property name="hosts" value="127.0.0.1:6379,127.0.0.1:7379"/>
<property name="maxTotal" value="256"/>
<property name="maxIdle" value="8" />
<property name="maxWait" value="3000" />
<property name="timeout" value="3000" />
<property name="minIdle" value="2" />
</bean>
<! -- Cluster mode -->
<bean id="redisClusterClient" class="com.itlong.whatsmars.redis.client.cluster.RedisClusterClient">
<property name="addresses" value="127.0.0.1:6379127.00 01:7 379127.00 0.1:8379"/>
<property name="maxTotal" value="256"/>
<property name="maxIdle" value="8" />
<property name="maxWait" value="3000" />
<property name="timeout" value="3000" />
<property name="minIdle" value="2" />
</bean>
<! -- Client Sharding mode, pending -->
</beans>
Copy the code
package com.itlong.whatsmars.redis.client.singleton;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
/** * Created by javahongxi on 2017/6/22. */
public class SingletonRedisClient implements FactoryBean<JedisPool>,InitializingBean {
private JedisPool jedisPool;
private int maxTotal = 128;
// Maximum number of idle connections
private int maxIdle = 2;
// Minimum number of free connections
private int minIdle = 1;
// If the connection pool is exhausted, the maximum blocking time is 3 seconds by default
private long maxWait = 3000;// in milliseconds
private String host;
private int port;
private int database = 0;// Select the database, default is 0
private int timeout = 3000;//connectionTimeout, soTimeout, the default is 3 seconds
private boolean testOnBorrow = true;
private boolean testOnReturn = true;
private String password;
public void setMaxTotal(int maxTotal) {
this.maxTotal = maxTotal;
}
public void setMaxIdle(int maxIdle) {
this.maxIdle = maxIdle;
}
public void setMinIdle(int minIdle) {
this.minIdle = minIdle;
}
public void setMaxWait(long maxWait) {
this.maxWait = maxWait;
}
public void setHost(String host) {
this.host = host;
}
public void setPort(int port) {
this.port = port;
}
public void setDatabase(int database) {
this.database = database;
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
public void setTestOnBorrow(boolean testOnBorrow) {
this.testOnBorrow = testOnBorrow;
}
public void setTestOnReturn(boolean testOnReturn) {
this.testOnReturn = testOnReturn;
}
public void setPassword(String password) {
this.password = password;
}
protected JedisPoolConfig buildConfig(a) {
JedisPoolConfig config = new JedisPoolConfig();
config.setMinIdle(minIdle);
config.setMaxIdle(maxIdle);
config.setMaxTotal(maxTotal);
config.setTestOnBorrow(testOnBorrow);
config.setTestOnReturn(testOnReturn);
config.setBlockWhenExhausted(true);
config.setMaxWaitMillis(maxWait);
config.setFairness(false);
return config;
}
@Override
public void afterPropertiesSet(a) throws Exception {
JedisPoolConfig config = buildConfig();
jedisPool = new JedisPool(config,host,port,timeout, password, database,null);
}
@Override
public JedisPool getObject(a) throws Exception {
return jedisPool;
}
@Override
publicClass<? > getObjectType() {return JedisPool.class;
}
@Override
public boolean isSingleton(a) {
return true; }}Copy the code
package com.itlong.whatsmars.redis.client.readwrite;
import org.springframework.beans.factory.InitializingBean;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/** * Created by javahongxi on 2017/6/22. */
public class ReadWriteRedisClient implements InitializingBean {
//master:port,slave:port,slave:port...
//master first
private String hosts;
private JedisPool master;
private List<JedisPool> slaves = new ArrayList<JedisPool>();
private int maxTotal = 128;
// Maximum number of idle connections
private int maxIdle = 2;
// Minimum number of free connections
private int minIdle = 1;
// If the connection pool is exhausted, the maximum blocking time is 3 seconds by default
private long maxWait = 3000;// in milliseconds
private int database = 0;// Select the database, default is 0
private int timeout = 3000;//connectionTimeout, soTimeout, the default is 3 seconds
private boolean testOnBorrow = true;
private boolean testOnReturn = true;
private String password;
private Random random = new Random();
public void setMaxTotal(int maxTotal) {
this.maxTotal = maxTotal;
}
public void setMaxIdle(int maxIdle) {
this.maxIdle = maxIdle;
}
public void setMinIdle(int minIdle) {
this.minIdle = minIdle;
}
public void setMaxWait(long maxWait) {
this.maxWait = maxWait;
}
public void setDatabase(int database) {
this.database = database;
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
public void setTestOnBorrow(boolean testOnBorrow) {
this.testOnBorrow = testOnBorrow;
}
public void setTestOnReturn(boolean testOnReturn) {
this.testOnReturn = testOnReturn;
}
public void setPassword(String password) {
this.password = password;
}
public void setHosts(String hosts) {
this.hosts = hosts;
}
protected JedisPoolConfig buildConfig(a) {
JedisPoolConfig config = new JedisPoolConfig();
config.setMinIdle(minIdle);
config.setMaxIdle(maxIdle);
config.setMaxTotal(maxTotal);
config.setTestOnBorrow(testOnBorrow);
config.setTestOnReturn(testOnReturn);
config.setBlockWhenExhausted(true);
config.setMaxWaitMillis(maxWait);
config.setFairness(false);
return config;
}
@Override
public void afterPropertiesSet(a) throws Exception {
JedisPoolConfig config = buildConfig();
String[] hostAndPorts = hosts.split(",");
String masterHP = hostAndPorts[0];
String[] ms = masterHP.split(":");
master = new JedisPool(config,ms[0],Integer.valueOf(ms[1]),timeout, password, database,null);
if(hostAndPorts.length > 1) {
for(int i = 1; i < hostAndPorts.length; i++) {
String[] ss = hostAndPorts[i].split(":");
JedisPool slave = new JedisPool(config,ss[0],Integer.valueOf(ss[1]),timeout, password, database,null);
slaves.add(slave);
}
}
slaves.add(master);
}
public String get(String key) {
Jedis jedis = fetchResource(true);
try {
return jedis.get(key);
} finally{ jedis.close(); }}public List<String> mget(String... keys) {
Jedis jedis = fetchResource(true);
try {
return jedis.mget(keys);
} finally{ jedis.close(); }}public String setex(String key,int seconds,String value) {
Jedis jedis = fetchResource(false);
try {
return jedis.setex(key,seconds,value);
} finally{ jedis.close(); }}public Long setnx(String key,String value) {
Jedis jedis = fetchResource(false);
try {
return jedis.setnx(key,value);
} finally{ jedis.close(); }}public String set(String key,String value) {
Jedis jedis = fetchResource(false);
try {
return jedis.set(key,value);
} finally{ jedis.close(); }}public Long del(String key) {
Jedis jedis = fetchResource(false);
try {
return jedis.del(key);
} finally{ jedis.close(); }}public Long expire(String key,int seconds) {
Jedis jedis = fetchResource(false);
try {
return jedis.expire(key,seconds);
} finally{ jedis.close(); }}public Boolean exists(String key) {
Jedis jedis = fetchResource(false);
try {
return jedis.exists(key);
} finally{ jedis.close(); }}public Long exists(String... keys) {
Jedis jedis = fetchResource(false);
try {
return jedis.exists(keys);
} finally{ jedis.close(); }}private Jedis fetchResource(boolean read) {
if(slaves.isEmpty() || ! read) {return master.getResource();
}
int size = slaves.size();
int i = random.nextInt(size);
return slaves.get(i).getResource();
}
public static void main(String[] args) throws Exception {
String prefix = "_test_";
ReadWriteRedisClient client = new ReadWriteRedisClient();
client.setHosts("127.0.0.1:6379,127.0.0.1:6379");
client.afterPropertiesSet();
client.set(prefix + "10001"."test");
System.out.println(client.get(prefix + "10001")); }}Copy the code
package com.itlong.whatsmars.redis.client.cluster;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPoolConfig;
import java.util.HashSet;
import java.util.Set;
/** * Created by javahongxi on 2017/6/22. */
public class RedisClusterClient implements FactoryBean<JedisCluster>,InitializingBean {
private JedisCluster jedisCluster;
private int maxTotal = 128;
// Maximum number of idle connections
private int maxIdle = 6;
// Minimum number of free connections
private int minIdle = 1;
// If the connection pool is exhausted, the maximum blocking time is 3 seconds by default
private long maxWait = 3000;// in milliseconds
private int timeout = 3000;//connectionTimeout, soTimeout, the default is 3 seconds
private boolean testOnBorrow = true;
private boolean testOnReturn = true;
private String addresses;//ip:port,ip:port
public void setMaxTotal(int maxTotal) {
this.maxTotal = maxTotal;
}
public void setMaxIdle(int maxIdle) {
this.maxIdle = maxIdle;
}
public void setMinIdle(int minIdle) {
this.minIdle = minIdle;
}
public void setMaxWait(long maxWait) {
this.maxWait = maxWait;
}
public void setTimeout(int timeout) {
this.timeout = timeout;
}
public void setTestOnBorrow(boolean testOnBorrow) {
this.testOnBorrow = testOnBorrow;
}
public void setTestOnReturn(boolean testOnReturn) {
this.testOnReturn = testOnReturn;
}
public void setAddresses(String addresses) {
this.addresses = addresses;
}
protected JedisPoolConfig buildConfig(a) {
JedisPoolConfig config = new JedisPoolConfig();
config.setMinIdle(minIdle);
config.setMaxIdle(maxIdle);
config.setMaxTotal(maxTotal);
config.setTestOnBorrow(testOnBorrow);
config.setTestOnReturn(testOnReturn);
config.setBlockWhenExhausted(true);
config.setMaxWaitMillis(maxWait);
config.setFairness(false);
return config;
}
private Set<HostAndPort> buildHostAndPorts(a) {
String[] hostPorts = addresses.split(",");
Set<HostAndPort> hostAndPorts = new HashSet<HostAndPort>();
for(String item : hostPorts) {
String[] hostPort = item.split(":");
HostAndPort hostAndPort = new HostAndPort(hostPort[0],Integer.valueOf(hostPort[1]));
hostAndPorts.add(hostAndPort);
}
return hostAndPorts;
}
@Override
public void afterPropertiesSet(a) throws Exception {
JedisPoolConfig config = buildConfig();
Set<HostAndPort> hostAndPorts = buildHostAndPorts();
jedisCluster = new JedisCluster(hostAndPorts,timeout,config);
}
@Override
public JedisCluster getObject(a) throws Exception {
return jedisCluster;
}
@Override
publicClass<? > getObjectType() {return JedisCluster.class;
}
@Override
public boolean isSingleton(a) {
return true; }}Copy the code
/** * Created by javahongxi on 2017/6/23. */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:spring-redis.xml")
public class Demo {
@Autowired
@Qualifier("singletonRedisClient")
private JedisPool singletonRedisClient;
@Autowired
private ReadWriteRedisClient readWriteRedisClient;
@Autowired
@Qualifier("redisClusterClient")
private JedisCluster jedisCluster;
@Test
public void testSingleton(a) {
Jedis jedis = singletonRedisClient.getResource();
String cacheContent = null;
try {
cacheContent = jedis.get("hello_world");
}finally {
singletonRedisClient.close();
}
// After the redis data is obtained, the connection is immediately released and business processing begins
if(cacheContent == null) {
// DB operation
}
/ /..
}
@Test
public void testReadWrite(a) {
String cacheContent = null;
try {
cacheContent = readWriteRedisClient.get("hello_world");
} catch (Exception e) {
// If there is an exception, you can decide whether to ignore it
}
if(cacheContent == null) {
// If the cache does not exist, or redis is abnormal}}@Test
public void testCluster(a) {
String cacheContent = null;
try {
cacheContent = jedisCluster.get("hello_world");
} catch (Exception e) {
// If there is an exception, you can decide whether to ignore it
}
if(cacheContent == null) {
// If the cache does not exist, or redis is abnormal}}}Copy the code
@ Read/write separation in M-S mode
In general, the Slave serves only as a data backup and does not provide read operations. This consideration is to avoid problems caused by Slave providing stale data. However, in many scenarios, even if the slave data has some latency, we can still be compatible or normal processing. In this case, we can provide read service to the slave and split the read operation in the M-S cluster, and our Redis cluster can support higher QPS. In this example, only the “read/write split” sample is provided, not all redis methods have been rewritten and encapsulated, please continue to add later. In addition, if the slave node is abnormal, we should support failover, which will be extended later.
Code https://github.com/javahongxi/whatsmars/tree/master/whatsmars-redisCopy the code