zoukankan      html  css  js  c++  java
  • Redis——SpringBoot项目使用Lettuce和Jedis接入Redis集群

    Jedis连接Redis:

    非线程安全

    如果是多线程环境下共用一个Jedis连接池,会产生线程安全问题,可以通过创建多个Jedis实例来解决,但是创建许多socket会影响性能,因此好一点的方法是使用JedisPool

    https://blog.csdn.net/lihao21/article/details/46830553

    https://www.jianshu.com/p/5e4a1f92c88f

    为什么 jedis不是线程安全的,可以通过一个demo来说明:

    public class BadConcurrentJedisTest {
    
        private static final ExecutorService pool = Executors.newFixedThreadPool(20);
    
        private static final Jedis jedis = new Jedis("127.0.0.1", 6379);
    
    
        public static void main(String[] args) {
            for(int i=0;i<20;i++){
                pool.execute(new RedisSet());
            }
        }
    
        static class RedisSet implements Runnable{
    
            @Override
            public void run() {
                while(true){
                    jedis.set("hello", "world");
                }
            }
    
        }

    这时候后台报错:

    redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketException: Socket Closed

    主要的原因就在于jedis实例中的两个成员变量:RedisInputStream和RedisOutputStream

    jedis在执行每一个命令之前都会先执行connect方法,socket是一个共享变量,在多线程的情况下可能存在:线程1执行到:

    outputStream = new RedisOutputStream(socket.getOutputStream());
    inputStream = new RedisInputStream(socket.getInputStream());

    线程2执行到:

    socket = new Socket();
    socket.connect(new InetSocketAddress(host, port), connectionTimeout);
    因为线程2重新初始化了socket但是还没有执行connect,所以线程1执行socket.getOutputStream()或者socket.getInputStream()就会抛出java.net.SocketException: Socket is not connected。
    Jedis解决线程安全的方式就是使用连接池:
    每个线程去连接池中获取一个Jedis实例,这样就在有限个socket的情况下保证了线程安全

    Lettuce连接Redis:

    线程安全

    Lettuce是基于netty的,性能比较好。

    多线程使用同一连接实例时,是线程安全的。

    application-test.yml

    redis:
      nodes:
        - host1:port1
        - host2:port2

    -----------------------------------------------------------------Lettuce-----------------------------------------------------------------

    导入依赖:

        //Redis
        compile 'org.springframework.boot:spring-boot-starter-data-redis-reactive'

    配置类:

    import io.lettuce.core.RedisURI;
    import io.lettuce.core.cluster.RedisClusterClient;
    import io.lettuce.core.cluster.api.StatefulRedisClusterConnection;
    import io.lettuce.core.cluster.api.sync.RedisClusterCommands;
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import java.util.ArrayList;
    import java.util.List;
    
    @Configuration
    @ConfigurationProperties(prefix = "redis")
    public class LettuceConfig {
        private List<String> nodes;
    
        public List<String> getNodes() {
            return nodes;
        }
    
        public void setNodes(List<String> nodes) {
            this.nodes = nodes;
        }
    
        @Bean
        RedisClusterCommands<String, String> redisCommands() {
            List<RedisURI> uriList = new ArrayList<>();
            nodes.forEach(node -> {
                String[] addrStr = node.split(":");
                String host = addrStr[0];
                int port = Integer.parseInt(addrStr[1]);
    
                RedisURI redisUri = RedisURI.Builder.redis(host).withPort(port).build();
                uriList.add(redisUri);
            });
            RedisClusterClient redisClient = RedisClusterClient.create(uriList);
            StatefulRedisClusterConnection<String, String> connection = redisClient.connect();
            RedisClusterCommands<String, String> syncCommands = connection.sync();
    
            return syncCommands;
        }
    
    }

    -----------------------------------------------------------------Jedis-----------------------------------------------------------------

    导入依赖:

    compile group: 'redis.clients', name: 'jedis', version: '2.9.0'

    配置类:

    package com.youdao.outfox.interflow.config;
    
    import org.springframework.boot.context.properties.ConfigurationProperties;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Profile;
    import redis.clients.jedis.HostAndPort;
    import redis.clients.jedis.JedisCluster;
    
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    
    @Configuration
    @ConfigurationProperties(prefix = "redis")
    public class JedisClusterConfig {
    
        private List<String> nodes;
    
        public List<String> getNodes() {
            return nodes;
        }
    
        public void setNodes(List<String> nodes) {
            this.nodes = nodes;
        }
    
        @Bean
        public JedisCluster jedisCluster() {
            Set<HostAndPort> jedisClusterNodes = new HashSet<>();
            nodes.forEach(node -> {
                String[] addrStr = node.split(":");
                String host = addrStr[0];
                int port = Integer.parseInt(addrStr[1]);
                jedisClusterNodes.add(new HostAndPort(host, port));
            });
            return new JedisCluster(jedisClusterNodes, 5, 2);
        }
    }

     --------------------------------更新-------------------------------------

  • 相关阅读:
    数组中出现次数超过一半的数字
    Trie字典树算法
    字符串匹配算法 之 基于DFA(确定性有限自动机)
    实现栈最小元素的min函数
    有关有环链表的问题
    浅谈C中的malloc和free
    undefined reference to 'pthread_create'问题解决
    用两个栈实现队列
    resf规范
    单例模式
  • 原文地址:https://www.cnblogs.com/gaoquanquan/p/11278333.html
Copyright © 2011-2022 走看看