日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

springboot+redis主从复制、哨兵、读写分离

發布時間:2023/12/18 编程问答 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 springboot+redis主从复制、哨兵、读写分离 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、redis安裝

# 安裝包存放目錄 cd /opt/software/ # 下載最新穩定版 wget https://download.redis.io/releases/redis-6.2.6.tar.gz # 解壓 tar -zxvf redis-6.2.6.tar.gz # 進入解壓后的目錄 cd /opt/software/redis-6.2.6/ # 編譯 make # 執行 "make install" 默認會安裝到 /usr/local/bin,可通過PREFIX指定安裝路徑 make install PREFIX=/usr/local/redis # 測試是否安裝成功,執行下面命令 /usr/local/redis/bin/redis-server

二、主從及哨兵配置

三個redis實例都運行在192.168.162.10服務器上,端口分別是7001、7002、7003,默認啟動時已7001作為主節點,7002與7003作為從節點,下面是主從與哨兵的配置文件需要修改的地方。

1、redis配置

原始配置文件可在解壓后的源碼文件根目錄中找到,這里以從節點 7002 配置文件為例,其余兩個配置文件幾乎一致。首先將配置文件拷貝到/opt/software/redis-cluster/redis-7002.conf,然后進行下面的修改。

# (1)設置允許外部ip訪問,需要注釋掉bind配置,并關掉保護模式 # bind 127.0.0.1 -::1 protected-mode no# (2)修改端口號 port 7002# (3)修改為以守護進程模式后臺運行 daemonize yes# (4)修改pid文件名,以守護進程運行的時候,會產生pid文件,默認位置為 /run/redis.pid # 因為這里在同一臺機器上運行多個實例,所以需要指定 pidfile /opt/software/redis-cluster/redis_7002.pid# (5)修改日志文件位置 logfile /opt/software/redis-cluster/redis_7002.log# (6)修改rdb快照文件位置 dir /opt/software/redis-cluster dbfilename dump_7002.rdb# (7)修改主節點地址,在部分舊版本中是slaveof命令,主節點7001配置文件中不要加這一行 replicaof 192.168.162.10 7001# (8)aof可按需要開啟 appendonly yes appendfilename appendonly_7002.aof

在上面的配置中,7001文件與7003一致,改一下其中的端口及地址就可以了,其中,7001作為主節點,沒有第(7)點。建議三個實例運行在不同的文件夾下,我為了省去切換文件目錄的時間,都放在一個文件夾下了。

配置完成后,按三個端口號的順序啟動分別啟動三個實例。

/usr/local/redis/bin/redis-server /opt/software/redis-cluster/redis-7001.conf /usr/local/redis/bin/redis-server /opt/software/redis-cluster/redis-7002.conf /usr/local/redis/bin/redis-server /opt/software/redis-cluster/redis-7003.conf

啟動后,產生的文件如下所示

進入主節點,查看實例主從狀況

進入從節點,查看實例主從狀況

測試主從復制,在主節點中添加一個緩存,然后從節點中查詢

至此,主從復制基本上差不多了,接下來就是哨兵的配置了。

2、sentinel配置

共計啟動三個實例,分別運行于27001、27002、27003三個端口,以sentinel-27001.conf為例,配置信息如下,其余兩個配置文件基本上一致,改一下端口以及pidfile、logfile即可。

port 27001 daemonize yes pidfile /opt/software/redis-cluster/sentinel-27001.pid logfile /opt/software/redis-cluster/sentinel-27001.log# 監控192.168.162.10:7001實例,實例取名為mymaster,當有兩個哨兵認為實例下線后,自動進行故障轉移 sentinel monitor mymaster 192.168.162.10 7001 2 # 服務不可達時間,心跳超過這個時間,sentinel將認為節點掛了 sentinel down-after-milliseconds mymaster 5000 sentinel failover-timeout mymaster 60000 sentinel parallel-syncs mymaster 1

分別啟動三個哨兵實例

隨意連接一個哨兵,查看哨兵監控信息

查看哨兵日志

關閉主節點,再看哨兵日志

從上面的日志文件中,我們可以看到哨兵投票選舉leader以及切換主節點的大概過程,這時候,主節點已經切換到7003節點了。

這時候,再重新啟動7001節點,也就是之前的主節點,這個節點會被哨兵自動加入到集群中作為從節點,sentinel會打印如下日志

+convert-to-slave slave 192.168.162.10:7001 192.168.162.10 7001 @ mymaster 192.168.162.10 7003

至此,哨兵集群也OK了。接下來就是springboot中配置哨兵集群了。

三、springboot配置哨兵集群及讀寫分離

創建springboot測試項目,pom.xml如下所示

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.6.3</version><relativePath/> <!-- lookup parent from repository --></parent><groupId>com.example</groupId><artifactId>sentinel-cluster</artifactId><version>0.0.1-SNAPSHOT</version><name>spring-boot-sentinel-cluster</name><description>spring-boot-sentinel-cluster</description><properties><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-json</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><configuration><excludes><exclude><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></exclude></excludes></configuration></plugin></plugins></build></project>

配置文件application.yml如下

spring:redis:sentinel:master: mymasternodes:- 192.168.162.10:27001- 192.168.162.10:27002- 192.168.162.10:27003 logging:pattern:console: '%date{yyyy-MM-dd HH:mm:ss.SSS} | %highlight(%5level) [%green(%16.16thread)] %clr(%-50.50logger{49}){cyan} %4line -| %highlight(%msg%n)'level:root: info

創建配置類,配置RedisTemplate

package com.example.config;import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.MapperFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer;import java.text.SimpleDateFormat; import java.util.TimeZone;/*** @author ygr* @date 2022-02-15 16:30*/ @Slf4j @Configuration public class RedisConfig {public ObjectMapper objectMapper() {ObjectMapper objectMapper = new ObjectMapper();objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);return objectMapper;}@Bean@ConditionalOnMissingBeanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {// 創建RedisTemplate<String, Object>對象RedisTemplate<String, Object> template = new RedisTemplate<>();template.setConnectionFactory(factory);// 定義Jackson2JsonRedisSerializer序列化對象Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);jackson2JsonRedisSerializer.setObjectMapper(objectMapper());StringRedisSerializer stringSerial = new StringRedisSerializer();// redis key 序列化方式使用stringSerialtemplate.setKeySerializer(stringSerial);// redis value 序列化方式使用jacksontemplate.setValueSerializer(jackson2JsonRedisSerializer);// redis hash key 序列化方式使用stringSerialtemplate.setHashKeySerializer(stringSerial);// redis hash value 序列化方式使用jacksontemplate.setHashValueSerializer(jackson2JsonRedisSerializer);template.afterPropertiesSet();return template;} }

新建一個RedisInit類來進行測試,該類實現了ApplicationRunner接口,在應用啟動后自動運行

package com.example.init;import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component;import java.util.concurrent.TimeUnit;/*** @author ygr* @date 2022-02-15 16:32*/ @Slf4j @RequiredArgsConstructor @Component public class RedisInit implements ApplicationRunner {private final RedisTemplate<String, Object> redisTemplate;@Overridepublic void run(ApplicationArguments args) throws Exception {for (int i = 0; i < 300; i++) {try {redisTemplate.opsForValue().set("k" + i, "v" + i);log.info("set value success: {}", i);Object val = redisTemplate.opsForValue().get("k" + i);log.info("get value success: {}", val);TimeUnit.SECONDS.sleep(1);} catch (Exception e) {log.error("error: {}", e.getMessage());}}log.info("finished...");} }

項目結構特別簡單

啟動項目,查看日志,可以看到讀寫一切正常。

途中嘗試將主節點干掉,接著看日志,從日志中可以看到,主從切換過來后,一切ok

但從info級別日志中,我們是看不出具體的讀寫連接信息的。將剛剛干掉的主節點重新啟動起來,保持一主二從的模式,并修改一下部分包的日志級別為debug,然后再次啟動看日志

logging:pattern:console: '%date{yyyy-MM-dd HH:mm:ss.SSS} | %highlight(%5level) [%green(%16.16thread)] %clr(%-50.50logger{49}){cyan} %4line -| %highlight(%msg%n)'level:root: infoio.lettuce.core: debugorg.springframework.data.redis: debug

這部分日志有點長,我直接截取了一次讀寫的日志,如下

2022-02-28 15:43:04.962 | DEBUG [ main] o.s.data.redis.core.RedisConnectionUtils 143 -| Fetching Redis Connection from RedisConnectionFactory 2022-02-28 15:43:04.962 | DEBUG [ main] io.lettuce.core.RedisChannelHandler 175 -| dispatching command AsyncCommand [type=SET, output=StatusOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command] 2022-02-28 15:43:04.962 | DEBUG [ main] io.lettuce.core.protocol.DefaultEndpoint 430 -| [channel=0x72e65475, /192.168.162.1:61674 -> /192.168.162.10:7001, epid=0x1] write() writeAndFlush command AsyncCommand [type=SET, output=StatusOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command] 2022-02-28 15:43:04.962 | DEBUG [ main] io.lettuce.core.protocol.DefaultEndpoint 207 -| [channel=0x72e65475, /192.168.162.1:61674 -> /192.168.162.10:7001, epid=0x1] write() done 2022-02-28 15:43:04.963 | DEBUG [nioEventLoop-6-2] io.lettuce.core.protocol.CommandHandler 383 -| [channel=0x72e65475, /192.168.162.1:61674 -> /192.168.162.10:7001, epid=0x1, chid=0x2] write(ctx, AsyncCommand [type=SET, output=StatusOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command], promise) 2022-02-28 15:43:04.963 | DEBUG [nioEventLoop-6-2] io.lettuce.core.protocol.CommandEncoder 101 -| [channel=0x72e65475, /192.168.162.1:61674 -> /192.168.162.10:7001] writing command AsyncCommand [type=SET, output=StatusOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command] 2022-02-28 15:43:04.964 | DEBUG [nioEventLoop-6-2] io.lettuce.core.protocol.CommandHandler 577 -| [channel=0x72e65475, /192.168.162.1:61674 -> /192.168.162.10:7001, epid=0x1, chid=0x2] Received: 5 bytes, 1 commands in the stack 2022-02-28 15:43:04.964 | DEBUG [nioEventLoop-6-2] io.lettuce.core.protocol.CommandHandler 651 -| [channel=0x72e65475, /192.168.162.1:61674 -> /192.168.162.10:7001, epid=0x1, chid=0x2] Stack contains: 1 commands 2022-02-28 15:43:04.964 | DEBUG [nioEventLoop-6-2] io.lettuce.core.protocol.RedisStateMachine 298 -| Decode done, empty stack: true 2022-02-28 15:43:04.964 | DEBUG [nioEventLoop-6-2] io.lettuce.core.protocol.CommandHandler 679 -| [channel=0x72e65475, /192.168.162.1:61674 -> /192.168.162.10:7001, epid=0x1, chid=0x2] Completing command AsyncCommand [type=SET, output=StatusOutput [output=OK, error='null'], commandType=io.lettuce.core.protocol.Command] 2022-02-28 15:43:04.964 | DEBUG [ main] o.s.data.redis.core.RedisConnectionUtils 389 -| Closing Redis Connection. 2022-02-28 15:43:04.965 | INFO [ main] com.example.init.RedisInit 28 -| set value success: 4 2022-02-28 15:43:04.965 | DEBUG [ main] o.s.data.redis.core.RedisConnectionUtils 143 -| Fetching Redis Connection from RedisConnectionFactory 2022-02-28 15:43:04.965 | DEBUG [ main] io.lettuce.core.RedisChannelHandler 175 -| dispatching command AsyncCommand [type=GET, output=ValueOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command] 2022-02-28 15:43:04.965 | DEBUG [ main] io.lettuce.core.protocol.DefaultEndpoint 430 -| [channel=0x72e65475, /192.168.162.1:61674 -> /192.168.162.10:7001, epid=0x1] write() writeAndFlush command AsyncCommand [type=GET, output=ValueOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command] 2022-02-28 15:43:04.965 | DEBUG [ main] io.lettuce.core.protocol.DefaultEndpoint 207 -| [channel=0x72e65475, /192.168.162.1:61674 -> /192.168.162.10:7001, epid=0x1] write() done 2022-02-28 15:43:04.965 | DEBUG [nioEventLoop-6-2] io.lettuce.core.protocol.CommandHandler 383 -| [channel=0x72e65475, /192.168.162.1:61674 -> /192.168.162.10:7001, epid=0x1, chid=0x2] write(ctx, AsyncCommand [type=GET, output=ValueOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command], promise) 2022-02-28 15:43:04.966 | DEBUG [nioEventLoop-6-2] io.lettuce.core.protocol.CommandEncoder 101 -| [channel=0x72e65475, /192.168.162.1:61674 -> /192.168.162.10:7001] writing command AsyncCommand [type=GET, output=ValueOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command] 2022-02-28 15:43:04.966 | DEBUG [nioEventLoop-6-2] io.lettuce.core.protocol.CommandHandler 577 -| [channel=0x72e65475, /192.168.162.1:61674 -> /192.168.162.10:7001, epid=0x1, chid=0x2] Received: 10 bytes, 1 commands in the stack 2022-02-28 15:43:04.966 | DEBUG [nioEventLoop-6-2] io.lettuce.core.protocol.CommandHandler 651 -| [channel=0x72e65475, /192.168.162.1:61674 -> /192.168.162.10:7001, epid=0x1, chid=0x2] Stack contains: 1 commands 2022-02-28 15:43:04.966 | DEBUG [nioEventLoop-6-2] io.lettuce.core.protocol.RedisStateMachine 298 -| Decode done, empty stack: true 2022-02-28 15:43:04.966 | DEBUG [nioEventLoop-6-2] io.lettuce.core.protocol.CommandHandler 679 -| [channel=0x72e65475, /192.168.162.1:61674 -> /192.168.162.10:7001, epid=0x1, chid=0x2] Completing command AsyncCommand [type=GET, output=ValueOutput [output=[B@393ff2f4, error='null'], commandType=io.lettuce.core.protocol.Command] 2022-02-28 15:43:04.967 | DEBUG [ main] o.s.data.redis.core.RedisConnectionUtils 389 -| Closing Redis Connection. 2022-02-28 15:43:04.967 | INFO [ main] com.example.init.RedisInit 31 -| get value success: v4

從日志中可以看到,讀與寫都是走的主節點(目前7001是主)。

如果想做讀寫分離,也很簡單,修改RedisConfig類,加入如下Bean的配置代碼

@Bean public RedisConnectionFactory lettuceConnectionFactory(RedisProperties redisProperties) {RedisSentinelConfiguration redisSentinelConfiguration = new RedisSentinelConfiguration(redisProperties.getSentinel().getMaster(), new HashSet<>(redisProperties.getSentinel().getNodes()));LettucePoolingClientConfiguration lettuceClientConfiguration = LettucePoolingClientConfiguration.builder()// 讀寫分離,若主節點能抗住讀寫并發,則不需要設置,全都走主節點即可.readFrom(ReadFrom.ANY_REPLICA).build();return new LettuceConnectionFactory(redisSentinelConfiguration, lettuceClientConfiguration); }

ReadFrom的取值及讀取方式的對應關系如下,其中,REPLICA會一直讀取的同一個從節點,ANY_REPLICA則會隨機選擇

ReadFrom讀取方式
MASTER / UPSTREAM僅讀取主節點
MASTER_PREFERRED / UPSTREAM_PREFERRED優先讀取主節點,如果主節點不可用,則讀取從節點
REPLICA/ SLAVE(已廢棄)僅讀取從節點
REPLICA_PREFERRED / SLAVE_PREFERRED(已廢棄)優先讀取從節點,如果從節點不可用,則讀取主節點
NEAREST從最近節點讀取
ANY從任何節點讀取
ANY_REPLICA從任意一個從節點讀取

再重啟查看日志

2022-02-28 15:40:58.971 | DEBUG [ main] o.s.data.redis.core.RedisConnectionUtils 143 -| Fetching Redis Connection from RedisConnectionFactory 2022-02-28 15:40:58.971 | DEBUG [ main] io.lettuce.core.RedisChannelHandler 175 -| dispatching command AsyncCommand [type=SET, output=StatusOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command] 2022-02-28 15:40:58.971 | DEBUG [ main] i.l.c.m.MasterReplicaConnectionProvider 112 -| getConnectionAsync(WRITE) 2022-02-28 15:40:58.971 | DEBUG [ main] io.lettuce.core.RedisChannelHandler 175 -| dispatching command AsyncCommand [type=SET, output=StatusOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command] 2022-02-28 15:40:58.971 | DEBUG [ main] io.lettuce.core.protocol.DefaultEndpoint 430 -| [channel=0x4c2f55eb, /192.168.162.1:61317 -> /192.168.162.10:7001, epid=0x7] write() writeAndFlush command AsyncCommand [type=SET, output=StatusOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command] 2022-02-28 15:40:58.972 | DEBUG [nioEventLoop-6-7] io.lettuce.core.protocol.CommandHandler 383 -| [channel=0x4c2f55eb, /192.168.162.1:61317 -> /192.168.162.10:7001, epid=0x7, chid=0x7] write(ctx, AsyncCommand [type=SET, output=StatusOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command], promise) 2022-02-28 15:40:58.972 | DEBUG [ main] io.lettuce.core.protocol.DefaultEndpoint 207 -| [channel=0x4c2f55eb, /192.168.162.1:61317 -> /192.168.162.10:7001, epid=0x7] write() done 2022-02-28 15:40:58.973 | DEBUG [nioEventLoop-6-7] io.lettuce.core.protocol.CommandEncoder 101 -| [channel=0x4c2f55eb, /192.168.162.1:61317 -> /192.168.162.10:7001] writing command AsyncCommand [type=SET, output=StatusOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command] 2022-02-28 15:40:58.974 | DEBUG [nioEventLoop-6-7] io.lettuce.core.protocol.CommandHandler 577 -| [channel=0x4c2f55eb, /192.168.162.1:61317 -> /192.168.162.10:7001, epid=0x7, chid=0x7] Received: 5 bytes, 1 commands in the stack 2022-02-28 15:40:58.974 | DEBUG [nioEventLoop-6-7] io.lettuce.core.protocol.CommandHandler 651 -| [channel=0x4c2f55eb, /192.168.162.1:61317 -> /192.168.162.10:7001, epid=0x7, chid=0x7] Stack contains: 1 commands 2022-02-28 15:40:58.974 | DEBUG [nioEventLoop-6-7] io.lettuce.core.protocol.RedisStateMachine 298 -| Decode done, empty stack: true 2022-02-28 15:40:58.974 | DEBUG [nioEventLoop-6-7] io.lettuce.core.protocol.CommandHandler 679 -| [channel=0x4c2f55eb, /192.168.162.1:61317 -> /192.168.162.10:7001, epid=0x7, chid=0x7] Completing command AsyncCommand [type=SET, output=StatusOutput [output=OK, error='null'], commandType=io.lettuce.core.protocol.Command] 2022-02-28 15:40:58.974 | DEBUG [ main] o.s.data.redis.core.RedisConnectionUtils 389 -| Closing Redis Connection. 2022-02-28 15:40:58.974 | INFO [ main] com.example.init.RedisInit 28 -| set value success: 4 2022-02-28 15:40:58.974 | DEBUG [ main] o.s.data.redis.core.RedisConnectionUtils 143 -| Fetching Redis Connection from RedisConnectionFactory 2022-02-28 15:40:58.975 | DEBUG [ main] io.lettuce.core.RedisChannelHandler 175 -| dispatching command AsyncCommand [type=GET, output=ValueOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command] 2022-02-28 15:40:58.975 | DEBUG [ main] i.l.c.m.MasterReplicaConnectionProvider 112 -| getConnectionAsync(READ) 2022-02-28 15:40:58.975 | DEBUG [ main] io.lettuce.core.RedisChannelHandler 175 -| dispatching command AsyncCommand [type=GET, output=ValueOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command] 2022-02-28 15:40:58.975 | DEBUG [ main] io.lettuce.core.protocol.DefaultEndpoint 430 -| [channel=0x83e97184, /192.168.162.1:61318 -> /192.168.162.10:7002, epid=0x8] write() writeAndFlush command AsyncCommand [type=GET, output=ValueOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command] 2022-02-28 15:40:58.975 | DEBUG [nioEventLoop-6-8] io.lettuce.core.protocol.CommandHandler 383 -| [channel=0x83e97184, /192.168.162.1:61318 -> /192.168.162.10:7002, epid=0x8, chid=0x8] write(ctx, AsyncCommand [type=GET, output=ValueOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command], promise) 2022-02-28 15:40:58.975 | DEBUG [ main] io.lettuce.core.protocol.DefaultEndpoint 207 -| [channel=0x83e97184, /192.168.162.1:61318 -> /192.168.162.10:7002, epid=0x8] write() done 2022-02-28 15:40:58.976 | DEBUG [nioEventLoop-6-8] io.lettuce.core.protocol.CommandEncoder 101 -| [channel=0x83e97184, /192.168.162.1:61318 -> /192.168.162.10:7002] writing command AsyncCommand [type=GET, output=ValueOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command] 2022-02-28 15:40:58.976 | DEBUG [nioEventLoop-6-8] io.lettuce.core.protocol.CommandHandler 577 -| [channel=0x83e97184, /192.168.162.1:61318 -> /192.168.162.10:7002, epid=0x8, chid=0x8] Received: 10 bytes, 1 commands in the stack 2022-02-28 15:40:58.976 | DEBUG [nioEventLoop-6-8] io.lettuce.core.protocol.CommandHandler 651 -| [channel=0x83e97184, /192.168.162.1:61318 -> /192.168.162.10:7002, epid=0x8, chid=0x8] Stack contains: 1 commands 2022-02-28 15:40:58.977 | DEBUG [nioEventLoop-6-8] io.lettuce.core.protocol.RedisStateMachine 298 -| Decode done, empty stack: true 2022-02-28 15:40:58.977 | DEBUG [nioEventLoop-6-8] io.lettuce.core.protocol.CommandHandler 679 -| [channel=0x83e97184, /192.168.162.1:61318 -> /192.168.162.10:7002, epid=0x8, chid=0x8] Completing command AsyncCommand [type=GET, output=ValueOutput [output=[B@75c09ac4, error='null'], commandType=io.lettuce.core.protocol.Command] 2022-02-28 15:40:58.977 | DEBUG [ main] o.s.data.redis.core.RedisConnectionUtils 389 -| Closing Redis Connection. 2022-02-28 15:40:58.977 | INFO [ main] com.example.init.RedisInit 31 -| get value success: v4

從日志中可以看到,寫操作走的是主節點(7001),讀操作走的是從節點(7002),日志太長,沒有粘貼其他的,從完整的日志中可以看到,從節點其實是一直隨機選擇的。

總結

以上是生活随笔為你收集整理的springboot+redis主从复制、哨兵、读写分离的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。