English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Preface
Everyone may encounter such a demand in their work, that is, Redis read-write separation, the purpose of which is to distribute the pressure. Below, I will introduce how to implement read-write separation with AWS ELB, taking the master as write and the slave as read as an example.
implementation
reference library file
<!-- redis client --> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.6.2</version> </dependency>
Method 1,With aspect
JedisPoolSelector
The purpose of this class is to configure different annotations for read and write separately, used to distinguish between master and slave.
package com.silence.spring.redis.readwriteseparation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * Created by keysilence on 16/10/26. */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface JedisPoolSelector { String value(); }
JedisPoolAspect
The purpose of this class is to dynamically allocate connection pools for master and slave annotations, that is, the master uses the master connection pool, and the slave uses the slave connection pool.
package com.silence.spring.redis.readwriteseparation; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import redis.clients.jedis.JedisPool; import javax.annotation.PostConstruct; import java.lang.reflect.Method; import java.util.Date; /** * Created by keysilence on 16/10/26. */ @Aspect public class JedisPoolAspect implements ApplicationContextAware { private ApplicationContext ctx; @PostConstruct public void init() { System.out.println("jedis pool aspectj started @" + new Date()); } @Pointcut("execution(* com.silence.spring.redis.readwriteseparation.util.*.*(..))") private void allMethod() { } @Before("allMethod()") public void before(JoinPoint point) { Object target = point.getTarget(); String method = point.getSignature().getName(); Class classz = target.getClass(); Class<?>[] parameterTypes = ((MethodSignature) point.getSignature()) .getMethod().getParameterTypes(); try { Method m = classz.getMethod(method, parameterTypes); if (m != null && m.isAnnotationPresent(JedisPoolSelector.class)) { JedisPoolSelector data = m .getAnnotation(JedisPoolSelector.class); JedisPool jedisPool = (JedisPool) ctx.getBean(data.value()); DynamicJedisPoolHolder.putJedisPool(jedisPool); } } e.printStackTrace(); } } public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.ctx = applicationContext; } }
DynamicJedisPoolHolder
The purpose of this class is to store the current JedisPool being used, i.e., the result saved after the class is assigned above.
package com.silence.spring.redis.readwriteseparation; import redis.clients.jedis.JedisPool; /** * Created by keysilence on 16/10/26. */ public class DynamicJedisPoolHolder { public static final ThreadLocal<JedisPool> holder = new ThreadLocal<JedisPool>(); public static void putJedisPool(JedisPool jedisPool) { holder.set(jedisPool); } public static JedisPool getJedisPool() { return holder.get(); } }
RedisUtils
The purpose of this class is to make specific calls to Redis, including calling with either the master or slave method.
package com.silence.spring.redis.readwriteseparation.util; import com.silence.spring.redis.readwriteseparation.DynamicJedisPoolHolder; import com.silence.spring.redis.readwriteseparation.JedisPoolSelector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Created by keysilence on 16/10/26. */ public class RedisUtils { private static Logger logger = LoggerFactory.getLogger(RedisUtils.class); @JedisPoolSelector("master") public String setString(final String key, final String value) { String ret = DynamicJedisPoolHolder.getJedisPool().getResource().set(key, value); System.out.println("key:" + key + ",value:" + value + ",ret:" + ret); return ret; } @JedisPoolSelector("slave") public String get(final String key) { String ret = DynamicJedisPoolHolder.getJedisPool().getResource().get(key); System.out.println("key:" + key + ",ret:" + ret); return ret; } }
spring-datasource.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"> <!-- The maximum number of links in the pool --> <property name="maxTotal" value="100"/> <!-- The maximum number of idle links in the pool --> <property name="maxIdle" value="50"/> <!-- The minimum number of idle links in the pool --> <property name="minIdle" value="20"/> <!-- When the links in the pool are exhausted, the maximum blocking time for the caller. If this time is exceeded, an exception will be thrown. (Unit: milliseconds; default is-1, indicating never timeout) --> <property name="maxWaitMillis" value="1000"/> <!-- Reference: http://biasedbit.com/redis-jedispool-configuration/ --> <!-- Whether to check the validity of the current link when the caller acquires a link. If invalid, it will be removed from the link pool and try to continue to get it. (Default is false) --> <property name="testOnBorrow" value="true" /> <!-- Whether to check the validity of the link when returning the link to the pool. (Default is false) --> <property name="testOnReturn" value="true" /> <!-- Whether to check idle timeout when the caller acquires a link. If a timeout occurs, it will be removed (default is false) --> <property name="testWhileIdle" value="true" /> <!-- Idle link detection thread runs once to check how many links --> <property name="numTestsPerEvictionRun" value="10" /> <!-- Idle link detection thread detection cycle. If negative, it means that the detection thread does not run. (Unit: milliseconds, default is-1) --> <property name="timeBetweenEvictionRunsMillis" value="60000" /> <!-- Link acquisition method. Queue: false; Stack: true --> <!--<property name="lifo" value="false" />--> </bean> <bean id="master" class="redis.clients.jedis.JedisPool"> <constructor-arg index="0" ref="poolConfig"/> <constructor-arg index="1" value="192.168.100.110" type="java.lang.String"/> <constructor-arg index="2" value="6379" type="int"/> </bean> <bean id="slave" class="redis.clients.jedis.JedisPool"> <constructor-arg index="0" ref="poolConfig"/> <!-- Here, the Host configuration is set to the ELB address --> <constructor-arg index="1" value="192.168.100.110" type="java.lang.String"/> <constructor-arg index="2" value="6380" type="int"/> </bean> <bean id="redisUtils" class="com.silence.spring.redis.readwriteseparation.util.RedisUtils"> </bean> <bean id="jedisPoolAspect" class="com.silence.spring.redis.readwriteseparation.JedisPoolAspect" /> <aop:aspectj-autoproxy proxy-target-class="true"/> </beans>
Test
package com.silence.spring.redis.readwriteseparation; import com.silence.spring.redis.readwriteseparation.util.RedisUtils; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * Created by keysilence on 16/10/26. */ public class Test { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-datasource.xml"); System.out.println(ctx); RedisUtils redisUtils = (RedisUtils) ctx.getBean("redisUtils"); redisUtils.setString("aaa", "111"); System.out.println(redisUtils.get("aaa")); } }
Method two,Dependency injection
Similar to method one, but it is necessary to hardcode whether to use the master's pool or the slave's pool, the idea is as follows:
Abandon the way of annotation and directly inject the master and slave connection pools into the specific implementation class.
RedisUtils
package com.silence.spring.redis.readwriteseparation.util; import com.silence.spring.redis.readwriteseparation.DynamicJedisPoolHolder; import com.silence.spring.redis.readwriteseparation.JedisPoolSelector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import redis.clients.jedis.JedisPool; /** * Created by keysilence on 16/10/26. */ public class RedisUtils { private static Logger logger = LoggerFactory.getLogger(RedisUtils.class); private JedisPool masterJedisPool; private JedisPool slaveJedisPool; public void setMasterJedisPool(JedisPool masterJedisPool) { this.masterJedisPool = masterJedisPool; } public void setSlaveJedisPool(JedisPool slaveJedisPool) { this.slaveJedisPool = slaveJedisPool; } public String setString(final String key, final String value) { String ret = masterJedisPool.getResource().set(key, value); System.out.println("key:" + key + ",value:" + value + ",ret:" + ret); return ret; } public String get(final String key) { String ret = slaveJedisPool.getResource().get(key); System.out.println("key:" + key + ",ret:" + ret); return ret; } }
spring-datasource.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"> <!-- The maximum number of links in the pool --> <property name="maxTotal" value="100"/> <!-- The maximum number of idle links in the pool --> <property name="maxIdle" value="50"/> <!-- The minimum number of idle links in the pool --> <property name="minIdle" value="20"/> <!-- When the links in the pool are exhausted, the maximum blocking time for the caller. If this time is exceeded, an exception will be thrown. (Unit: milliseconds; default is-1, indicating never timeout) --> <property name="maxWaitMillis" value="1000"/> <!-- Reference: http://biasedbit.com/redis-jedispool-configuration/ --> <!-- Whether to check the validity of the current link when the caller acquires a link. If invalid, it will be removed from the link pool and try to continue to get it. (Default is false) --> <property name="testOnBorrow" value="true" /> <!-- Whether to check the validity of the link when returning the link to the pool. (Default is false) --> <property name="testOnReturn" value="true" /> <!-- Whether to check idle timeout when the caller acquires a link. If a timeout occurs, it will be removed (default is false) --> <property name="testWhileIdle" value="true" /> <!-- Idle link detection thread runs once to check how many links --> <property name="numTestsPerEvictionRun" value="10" /> <!-- Idle link detection thread detection cycle. If negative, it means that the detection thread does not run. (Unit: milliseconds, default is-1) --> <property name="timeBetweenEvictionRunsMillis" value="60000" /> <!-- Link acquisition method. Queue: false; Stack: true --> <!--<property name="lifo" value="false" />--> </bean> <bean id="masterJedisPool" class="redis.clients.jedis.JedisPool"> <constructor-arg index="0" ref="poolConfig"/> <constructor-arg index="1" value="192.168.100.110" type="java.lang.String"/> <constructor-arg index="2" value="6379" type="int"/> </bean> <bean id="slaveJedisPool" class="redis.clients.jedis.JedisPool"> <constructor-arg index="0" ref="poolConfig"/> <constructor-arg index="1" value="192.168.100.110" type="java.lang.String"/> <constructor-arg index="2" value="6380" type="int"/> </bean> <bean id="redisUtils" class="com.silence.spring.redis.readwriteseparation.util.RedisUtils"> <property name="masterJedisPool" ref="masterJedisPool"/> <property name="slaveJedisPool" ref="slaveJedisPool"/> </bean> </beans>
That's all for this article. I hope it will be helpful to everyone's learning and that everyone will support the Yell Tutorial more.
Statement: The content of this article is from the Internet, and the copyright belongs to the original author. The content is contributed and uploaded by Internet users spontaneously. This website does not own the copyright, has not been edited by humans, and does not assume relevant legal liabilities. If you find any content suspected of copyright infringement, please send an email to: notice#oldtoolbag.com (When sending an email, please replace # with @ to report abuse, and provide relevant evidence. Once verified, this site will immediately delete the content suspected of infringement.)