English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Redis Master-Slave Implementierung Lese-Schreib-Trennung

Einleitung

Bei der Arbeit könnten Sie solche Anforderungen erleben, dass Redis-Lesen und Schreiben getrennt werden, um den Druck zu verteilen. Nachfolgend werde ich Ihnen zeigen, wie man mit AWS ELB eine Trennung von Lesen und Schreiben implementiert, wobei als Beispiel der Schreibende Primär und der Lesende Sekundär ist.

Umsetzung

Bibliotheksbibliothek referenzieren

  <!-- Redis-Client -->
  <dependency>
   <groupId>redis.clients</groupId>
   <artifactId>jedis</artifactId>
   <version>2.6.2</version>
  </dependency>

Methode 1,unter Zuhilfenahme von Aspekten

JedisPoolSelector

Der Zweck dieses Klassen ist es, unterschiedliche Annotations für Lese- und Schreibvorgänge zu konfigurieren, um zu unterscheiden, ob es sich um primäre oder sekundäre Operationen handelt.

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

Der Zweck dieses Klassen ist es, eine dynamische Poolzuweisung für primäre und sekundäre Annotations zu realisieren, d.h. der Primärverwendung wird der Primärlinkpool zugewiesen, und der Sekundärverwendung wird der Sekundärlinkpool zugewiesen.

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);
      }
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    this.ctx = applicationContext;
  }
}

DynamicJedisPoolHolder

Das Ziel dieser Klasse ist die Speicherung des momentan verwendeten JedisPool, d.h. das Ergebnis der Zuweisung in der obigen Klasse wird gespeichert.

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

Das Ziel dieses Klassen ist die spezifische Anfrage an Redis, wobei angegeben wird, ob die Haupt- oder die Nebenverbindung verwendet wird.

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">
    <!-- Maximum number of links in the pool -->
    <property name="maxTotal" value="100"/>
    <!-- Maximum number of idle links in the pool -->
    <property name="maxIdle" value="50"/>
    <!-- Minimum number of idle links in the pool -->
    <property name="minIdle" value="20"/>
    <!-- When the pool is exhausted, the maximum blocking time for the caller, if exceeding this time, an exception will be thrown. (Unit: milliseconds; default is-1, which means 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 pool and try to continue to acquire. (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 for 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 detect 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"/>
    <!-- Hier die Host-Konfiguration auf die ELB-Adresse einstellen]} -->
    <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"));
  }
}

Methode 2,Abhängigkeitsinjektion

Ähnlich wie Methode 1, aber es muss festgelegt werden, ob der Haupt- oder der Slave-Pool verwendet wird, die Idee ist wie folgt:
Vermeide die Verwendung von Annotations und injiziere die beiden Haupt- und Slave-Pools direkt in die spezifische Implementierungsklasse.

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">
    <!-- Maximum number of links in the pool -->
    <property name="maxTotal" value="100"/>
    <!-- Maximum number of idle links in the pool -->
    <property name="maxIdle" value="50"/>
    <!-- Minimum number of idle links in the pool -->
    <property name="minIdle" value="20"/>
    <!-- When the pool is exhausted, the maximum blocking time for the caller, if exceeding this time, an exception will be thrown. (Unit: milliseconds; default is-1, which means 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 pool and try to continue to acquire. (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 for 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 detect 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>

Das ist der gesamte Inhalt dieses Artikels. Wir hoffen, dass er Ihnen bei Ihrem Lernen hilft und dass Sie unsere Anleitung stark unterstützen.

Erklärung: Der Inhalt dieses Artikels wurde aus dem Internet übernommen und gehört dem jeweiligen Urheber. Der Inhalt wurde von Internetbenutzern selbstständig beigesteuert und hochgeladen. Diese Website besitzt keine Eigentumsrechte und hat den Inhalt nicht manuell bearbeitet. Sie übernimmt keine rechtlichen Verantwortlichkeiten. Falls Sie verdächtige Inhalte entdecken, sind Sie herzlich eingeladen, eine E-Mail an notice#w zu senden und relevante Beweise bereitzustellen.3Erklärung: Der Inhalt dieses Artikels wurde aus dem Internet übernommen und gehört dem jeweiligen Urheber. Der Inhalt wurde von Internetbenutzern selbstständig beigesteuert und hochgeladen. Diese Website besitzt keine Eigentumsrechte und hat den Inhalt nicht manuell bearbeitet. Sie übernimmt keine rechtlichen Verantwortlichkeiten. Falls Sie verdächtige Inhalte entdecken, sind Sie herzlich eingeladen, eine E-Mail an notice#w zu senden und relevante Beweise bereitzustellen. Sobald überprüft, wird dieser Inhalt sofort gelöscht.

Mag sein