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

تحقيق الفصل بين القراءة والكتابة في Redis

مقدمة

قد تواجه الجميع احتياجات مثل هذه في العمل، وهي فصل قراءة Redis وكتابة، ويهدف ذلك إلى توزيع الضغط بشكل متساوٍ. سأقوم الآن بشرح كيفية استخدام ELB من AWS لتحقيق فصل القراءة والكتابة، على سبيل المثال، الرئيسي للكتابة والفرعي للقراءة.

تنفيذ

استيراد ملف المكتبة

  <!-- عميل Redis -->
  <dependency>
   <groupId>redis.clients</groupId>
   <artifactId>jedis</artifactId>
   <version>2.6.2</version>
  </dependency>

الطريقة الأولى،باستخدام الجانب

JedisPoolSelector

هدف هذا النوع هو تكوين علامات التوضيح المختلفة للقراءة والكتابة، لتمييز ما إذا كان الرئيسي أم الفرعي.

package com.silence.spring.redis.readwriteseparation;
استيراد java.lang.annotation.ElementType;
استيراد java.lang.annotation.Retention;
استيراد java.lang.annotation.RetentionPolicy;
استيراد java.lang.annotation.Target;
/**
 * Created by keysilence on 16/10/26.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface JedisPoolSelector {
  String value();
}

JedisPoolAspect

هذا النوع من الكائن يهدف إلى التعامل مع التسميات الموجودة على الرئيسي والفرعي، من خلال ربط ديناميكي للخزائن، أي أن الرئيسي يستخدم خزانة الرئيسي، والفرعي يستخدم خزانة الفرعي.

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 هدف = point.getTarget();
    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

هذا الكائن يهدف إلى حفظ JedisPool الحالي المستخدم، أي أن نتائج الت赋صية في الفئة أعلاه يتم حفظها.

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

هذا الكائن يهدف إلى استدعاء Redis المحدد، ويشمل استخدام طريقة الاتصال الرئيسية أو الفرعية.

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">
    <!-- حداکثر عدد از اتصالات در استخر -->
    <property name="maxTotal" value="100"/>
    <!-- عدد الاتصالات العاطلة عن العمل الأقصى في الخزانة -->
    <property name="maxIdle" value="50"/>
    <!-- عدد الاتصالات العاطلة عن العمل الأدنى في الخزانة -->
    <property name="minIdle" value="20"/>
    <!-- عند استنفاد الاتصالات في الخزانة، أقصى وقت التبكير لل مستخدم. إذا تجاوز هذا الوقت، فإنه سيتم إطلاق استثناء. (الوحدة: ميلي ثانية؛ القيمة الافتراضية هي -1، مما يعني عدم الحصول على وقت التبكير) -->
    <property name="maxWaitMillis" value="1000"/>
    <!-- مرجع: http://biasedbit.com/redis-jedispool-configuration/ -->
    <!-- عند الحصول على الاتصال من المستخدم، هل يتم التحقق من صحة الاتصال الحالي. إذا كان غير صالح، يتم إزالته من خزانة الاتصالات ومحاولة الحصول على اتصال آخر. (القيمة الافتراضية هي false) -->
    <property name="testOnBorrow" value="true" />
    <!-- عند إرجاع الاتصال إلى خزانة الاتصالات، هل يتم التحقق من صحة الاتصال. (القيمة الافتراضية هي false) -->
    <property name="testOnReturn" value="true" />
    <!-- عند الحصول على الاتصال من المستخدم، هل يتم التحقق من الإجازة الزمنية العاطلة عن العمل. إذا كان هناك إجازة زمنية، فإنه سيتم إزالته (القيمة الافتراضية هي false) -->
    <property name="testWhileIdle" value="true" />
    <!-- عدد الاتصالات التي يتم التحقق منها في كل تشغيل لسطر التحقق من الاتصالات العاطلة عن العمل -->
    <property name="numTestsPerEvictionRun" value="10" />
    <!-- فترة دوران تشغيل سطر التحقق من الاتصالات العاطلة عن العمل. إذا كان القيمة سالبة، فإن ذلك يعني عدم تشغيل سطر التحقق من الاتصالات العاطلة عن العمل. (الوحدة: ميلي ثانية، القيمة الافتراضية هي -1) -->
    <property name="timeBetweenEvictionRunsMillis" value="60000" />
    <!-- طريقة الحصول على الاتصال. قائمة: false؛ دالة: 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"/>
    <!-- 此处Host配置成ELB地址 -->
    <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"));
  }
}

الطريقة الثانية،حقول تعريف الاعتماد

مثل الطريقة الأولى، ولكن يجب كتابة استخدام خزان الرئيسي أو الخزان الفرعي بشكل دائم، الفكرية كالتالي:
تجاهل استخدام التعليقات، وتقديم رابطين منفصلين للنصب إلى الكلاس المطبق.

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">
    <!-- حداکثر عدد از اتصالات در استخر -->
    <property name="maxTotal" value="100"/>
    <!-- عدد الاتصالات العاطلة عن العمل الأقصى في الخزانة -->
    <property name="maxIdle" value="50"/>
    <!-- عدد الاتصالات العاطلة عن العمل الأدنى في الخزانة -->
    <property name="minIdle" value="20"/>
    <!-- عند استنفاد الاتصالات في الخزانة، أقصى وقت التبكير لل مستخدم. إذا تجاوز هذا الوقت، فإنه سيتم إطلاق استثناء. (الوحدة: ميلي ثانية؛ القيمة الافتراضية هي -1، مما يعني عدم الحصول على وقت التبكير) -->
    <property name="maxWaitMillis" value="1000"/>
    <!-- مرجع: http://biasedbit.com/redis-jedispool-configuration/ -->
    <!-- عند الحصول على الاتصال من المستخدم، هل يتم التحقق من صحة الاتصال الحالي. إذا كان غير صالح، يتم إزالته من خزانة الاتصالات ومحاولة الحصول على اتصال آخر. (القيمة الافتراضية هي false) -->
    <property name="testOnBorrow" value="true" />
    <!-- عند إرجاع الاتصال إلى خزانة الاتصالات، هل يتم التحقق من صحة الاتصال. (القيمة الافتراضية هي false) -->
    <property name="testOnReturn" value="true" />
    <!-- عند الحصول على الاتصال من المستخدم، هل يتم التحقق من الإجازة الزمنية العاطلة عن العمل. إذا كان هناك إجازة زمنية، فإنه سيتم إزالته (القيمة الافتراضية هي false) -->
    <property name="testWhileIdle" value="true" />
    <!-- عدد الاتصالات التي يتم التحقق منها في كل تشغيل لسطر التحقق من الاتصالات العاطلة عن العمل -->
    <property name="numTestsPerEvictionRun" value="10" />
    <!-- فترة دوران تشغيل سطر التحقق من الاتصالات العاطلة عن العمل. إذا كان القيمة سالبة، فإن ذلك يعني عدم تشغيل سطر التحقق من الاتصالات العاطلة عن العمل. (الوحدة: ميلي ثانية، القيمة الافتراضية هي -1) -->
    <property name="timeBetweenEvictionRunsMillis" value="60000" />
    <!-- طريقة الحصول على الاتصال. قائمة: false؛ دالة: 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>

هذا هو محتوى المقال كله، نأمل أن يكون قد ساعد في تعلمكم، ونأمل أن تدعموا دائمًا تعليمات النطق.

البيان: محتويات هذا المقال تم جمعها من الإنترنت، ملكية المحتويات للمالك الأصلي، تم جمع المحتويات من قبل المستخدمين على الإنترنت بتحميلهم بأنفسهم، هذا الموقع لا يمتلك حقوق الملكية، لم يتم تعديل المحتويات بشكل يدوي، ولا يتحمل أي مسؤولية قانونية متعلقة بذلك. إذا كنت قد وجدت محتويات تتضمن حقوق النسخ، فالرجاء إرسال بريد إلكتروني إلى: notice#oldtoolbag.com (عند إرسال البريد الإلكتروني، يرجى استبدال # بـ @) للإبلاغ، وقدم الدليل على الدليل، إذا تم التحقق من ذلك، فإن هذا الموقع سيزيل محتويات التعدين على الفور.

أنت قد تحب