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);
    }
}

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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM