springboot之如何同時連接多個redis
線上服務需要連接三個redis服務器;業(yè)務背景不能介紹,直接上代碼:
技術選型
Springboot連接reids的三個客戶端
Jedis:是Redis的Java實現客戶端,提供了比較全面的Redis命令的支持,復雜的redis操作需要使用它;springboot1.x 默認集成;據說在高并發(fā)下有并發(fā)性問題出現;
Lettuce:高級Redis客戶端,用于線程安全同步,異步和響應使用,支持集群,Sentinel,管道和編碼器,springboot 2.x 默認集成
Redission:Redisson是一個在Redis的基礎上實現的Java駐內存數據網格(In-Memory Data Grid)。它不僅提供了一系列的分布式的Java常用對象,還提供了許多分布式服務。其中包括(BitSet, Set, Multimap, SortedSet, Map, List, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, AtomicLong, CountDownLatch, Publish / Subscribe, Bloom filter, Remote service, Spring cache, Executor service, Live Object service, Scheduler service) Redisson提供了使用Redis的最簡單和最便捷的方法。Redisson的宗旨是促進使用者對Redis的關注分離(Separation of Concern),從而讓使用者能夠將精力更集中地放在處理業(yè)務邏輯上。暫時企業(yè)級開發(fā)感覺只是使用了分布式鎖;
結論:
單個redis隨便使用哪個客戶端都可以,也可以使用 Jedis + Redission 或者 Lettuce + Redission;
由于Jedis使用和研究比較多,此處使用Jedis拋磚引玉,實現三組redis + 分布式鎖;Lettuce版本也可以根據此思路編寫;
代碼部分
maven pom引用
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <exclusions> <!-- 不依賴Redis的異步客戶端lettuce --> <exclusion> <groupId>io.lettuce</groupId> <artifactId>lettuce-core</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> </dependency>
application.yml配置
spring: redis: r1: host: 192.168.1.210 port: 6379 password: #cluster: #nodes: 192.168.1.101:6379,192.168.1.102:6379,192.168.1.103:6379 r2: host: 192.168.1.211 port: 6379 password: #cluster: #nodes: 192.168.1.104:6379,192.168.1.105:6379,192.168.1.106:6379 r3: host: 192.168.1.212 port: 6379 password: #cluster: #nodes: 192.168.1.107:6379,192.168.1.108:6379,192.168.1.109:6379
Configuration代碼
import java.util.HashSet; import java.util.Set; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisClusterConfiguration; import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisNode; import org.springframework.data.redis.connection.RedisPassword; import org.springframework.data.redis.connection.RedisStandaloneConfiguration; import org.springframework.data.redis.connection.jedis.JedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import cn.hutool.core.util.StrUtil; import lombok.extern.slf4j.Slf4j; import redis.clients.jedis.JedisPoolConfig; /** * redis配置 三個redis同時存在 * @author douzi * @date 2021-12-2 09:00:00 */ @Slf4j @Configuration public class RedisJedisConfig2 { // r1 redis 配置信息 @Value("${spring.redis.r1.host:}") private String r1Host; @Value("${spring.redis.r1.port:}") private Integer r1Port; @Value("${spring.redis.r1.password:}") private String r1Password; @Value("${spring.redis.r1.cluster.nodes:}") private String r1Nodes; //r2 redis 配置信息 @Value("${spring.redis.r2.host:}") private String r2Host; @Value("${spring.redis.r2.port:}") private Integer r2Port; @Value("${spring.redis.r2.password:}") private String r2Password; @Value("${spring.redis.r2.cluster.nodes:}") private String r2Nodes; //r3 redis 配置信息 @Value("${spring.redis.r3.host:}") private String r3Host; @Value("${spring.redis.r3.port:}") private Integer r3Port; @Value("${spring.redis.r3.password:}") private String r3Password; @Value("${spring.redis.r3.cluster.nodes:}") private String r3Nodes; /** * connectionFactory 配置工廠 */ public RedisConnectionFactory connectionFactory( RedisStandaloneConfiguration redisStandaloneConfiguration, RedisClusterConfiguration redisClusterConfiguration, JedisPoolConfig jedisPoolConfig) { if (redisStandaloneConfiguration == null && redisClusterConfiguration == null) { log.error("==============請?zhí)砑觬edis配置================"); return null; } JedisConnectionFactory jedisConnectionFactory = null; if (redisStandaloneConfiguration != null) { jedisConnectionFactory = new JedisConnectionFactory(redisStandaloneConfiguration); } else { jedisConnectionFactory = new JedisConnectionFactory(redisClusterConfiguration, jedisPoolConfig); } jedisConnectionFactory.afterPropertiesSet(); // 檢查是否可用 RedisConnection connection = null; try { connection = jedisConnectionFactory.getConnection(); log.info("reids是否可用:" + !connection.isClosed()); } catch(Exception e) { log.error("reids不可用,請檢查組件是否啟動:",e); } finally { connection.close(); } return jedisConnectionFactory; } /** * poolConfig連接池配置 只有集群時使用 直接寫死,不讓外部配置了 * @return */ public JedisPoolConfig poolConfig() { JedisPoolConfig config = new JedisPoolConfig(); config.setMaxTotal(200); config.setMaxIdle(50); config.setMinIdle(8); config.setMaxWaitMillis(10000); // 獲取連接時的最大等待毫秒數(如果設置為阻塞時BlockWhenExhausted),如果超時就拋異常, 小于零:阻塞不確定的時間, 默認-1 config.setTestOnBorrow(true); // 在獲取連接的時候檢查有效性, 默認false config.setTestOnReturn(false); // 調用returnObject方法時,是否進行有效檢查 config.setTestWhileIdle(true); // Idle時進行連接掃描 config.setTimeBetweenEvictionRunsMillis(30000); // 表示idle object evitor兩次掃描之間要sleep的毫秒數 config.setNumTestsPerEvictionRun(10); // 表示idle object evitor每次掃描的最多的對象數 config.setMinEvictableIdleTimeMillis(60000); // 表示一個對象至少停留在idle狀態(tài)的最短時間,然后才能被idle object evitor掃描并驅逐;這一項只有在timeBetweenEvictionRunsMillis大于0時才有意義 return config; } /** * redisStandaloneConfiguration 單機版配置 * @param host * @param port * @param password * @param index * @return */ public RedisStandaloneConfiguration redisStandaloneConfiguration(String host, int port, String password, int index) { RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration(host, port); if (StrUtil.isNotBlank(password)) { redisStandaloneConfiguration.setPassword(password); } if (index != 0) { redisStandaloneConfiguration.setDatabase(index); } return redisStandaloneConfiguration; } /** * redisClusterConfiguration 集群配置 * @param clusterNodes * @param password * @return */ public RedisClusterConfiguration redisClusterConfiguration(String clusterNodes, String password) { RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration(); // Set<RedisNode> clusterNodes String[] serverArray = clusterNodes.split(","); Set<RedisNode> nodes = new HashSet<RedisNode>(); for (String ipPort : serverArray) { String[] ipAndPort = ipPort.split(":"); nodes.add(new RedisNode(ipAndPort[0].trim(), Integer.valueOf(ipAndPort[1]))); } redisClusterConfiguration.setClusterNodes(nodes); redisClusterConfiguration.setMaxRedirects(6); if (StrUtil.isNotBlank(password)) { redisClusterConfiguration.setPassword(RedisPassword.of(password)); } return redisClusterConfiguration; } @Bean(name = "redisR1Template") public RedisTemplate<String, Object> redisR1Template() { RedisTemplate<String, Object> template = new RedisTemplate<>(); RedisStandaloneConfiguration redisStandaloneConfiguration = null; RedisClusterConfiguration redisClusterConfiguration = null; if (StrUtil.isNotBlank(r1Host) && StrUtil.isBlank(r1Nodes)) { redisStandaloneConfiguration = redisStandaloneConfiguration(r1Host, r1Port, r1Password, 0); } else if (StrUtil.isNotBlank(r1Nodes)) { redisClusterConfiguration = redisClusterConfiguration(r1Nodes, r1Password); } log.info("=========================R1 redis信息 開始==============================="); template.setConnectionFactory(connectionFactory(redisStandaloneConfiguration, redisClusterConfiguration, poolConfig())); log.info("=========================R1 redis信息 結束==============================="); return template; } @Bean(name = "redisR2Template") public RedisTemplate<String, Object> redisR2Template() { RedisTemplate<String, Object> template = new RedisTemplate<>(); RedisStandaloneConfiguration redisStandaloneConfiguration = null; RedisClusterConfiguration redisClusterConfiguration = null; if (StrUtil.isNotBlank(r2Host) && StrUtil.isBlank(r2Nodes)) { redisStandaloneConfiguration = redisStandaloneConfiguration(r2Host, r2Port, r2Password, 0); } else if (StrUtil.isNotBlank(r2Nodes)) { redisClusterConfiguration = redisClusterConfiguration(r2Nodes, r2Password); } log.info("=========================R2 redis信息 開始==============================="); template.setConnectionFactory(connectionFactory(redisStandaloneConfiguration, redisClusterConfiguration, poolConfig())); log.info("=========================R2 redis信息 結束==============================="); return template; } @Bean(name = "redisR3Template") public RedisTemplate<String, Object> redisR3Template() { RedisTemplate<String, Object> template = new RedisTemplate<>(); RedisStandaloneConfiguration redisStandaloneConfiguration = null; RedisClusterConfiguration redisClusterConfiguration = null; if (StrUtil.isNotBlank(r3Host) && StrUtil.isBlank(r3Nodes)) { redisStandaloneConfiguration = redisStandaloneConfiguration(r3Host, r3Port, r3Password, 0); } else if (StrUtil.isNotBlank(r3Nodes)) { redisClusterConfiguration = redisClusterConfiguration(r3Nodes, r3Password); } log.info("=========================R3 redis信息 開始==============================="); template.setConnectionFactory(connectionFactory(redisStandaloneConfiguration, redisClusterConfiguration, poolConfig())); log.info("=========================R3 redis信息 結束==============================="); return template; } }
其中在connectionFactory方法中,添加了,自動檢查redis是否連接成功的代碼,在啟動項目時即可判斷是否連接成功。
啟動失敗日志
啟動成功日志
類中使用
@RestController @RequestMapping("/redis") public class TestRedisController { @Autowired RedisTemplate<String, Object> redisR1Template; @Autowired RedisTemplate<String, Object> redisR2Template; @Autowired RedisTemplate<String, Object> redisR3Template; @GetMapping("/cs") public String test() { redisR1Template.opsForValue().get("1"); redisR2Template.opsForValue().get("1"); redisR3Template.opsForValue().get("1"); return "1"; } }
總結
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。