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