本篇文章主要介紹了 redis 中的主從復(fù)制的基本概念,以及 Java 語(yǔ)言中使用 Lettuce 客戶(hù)端在 Redis 的主從復(fù)制模式下命令執(zhí)行的操作。以下是詳情內(nèi)容,希望對(duì)于大家的學(xué)習(xí)和工作能夠有所幫助!
1 redis主從復(fù)制的概念
多機(jī)環(huán)境下,一個(gè)redis服務(wù)接收寫(xiě)命令,當(dāng)自身數(shù)據(jù)與狀態(tài)發(fā)生變化,將其復(fù)制到一個(gè)或多個(gè)redis。這種模式稱(chēng)為主從復(fù)制。在redis中通過(guò)命令salveof命令讓執(zhí)行該命令的redis復(fù)制另一個(gè)redis數(shù)據(jù)與狀態(tài)。我們將主服務(wù)器稱(chēng)為master,從服務(wù)器稱(chēng)為slave。
主從復(fù)制保證了網(wǎng)絡(luò)異常正常時(shí),網(wǎng)絡(luò)斷開(kāi)重的情況下將數(shù)據(jù)復(fù)制。網(wǎng)絡(luò)正常時(shí)master會(huì)通過(guò)發(fā)送命令保持對(duì)slave更新,更新包括客戶(hù)端的寫(xiě)入,key的過(guò)期或被逐出等網(wǎng)絡(luò)異常,master與slave連接斷開(kāi)一段時(shí)間,slave重連上master后會(huì)嘗試部分重同步,重新獲取連接斷開(kāi)期間丟失的命令。當(dāng)無(wú)法進(jìn)行部分重同步,則會(huì)執(zhí)行全量重同步。
2 為什么需要主從復(fù)制
為了保證數(shù)據(jù)不丟失,有時(shí)會(huì)用到持久化功能。但這樣會(huì)增加磁盤(pán)IO操作。通過(guò)使用主從復(fù)制,可以替代持久化并減少I(mǎi)O操作,降低延遲提高性能。
主從模式下,master負(fù)責(zé)處理寫(xiě),slave負(fù)責(zé)讀。雖然主從同步會(huì)導(dǎo)致在數(shù)據(jù)存在不一致窗口,但可以增加讀操作的吞吐量。主從模式避免了redis單點(diǎn)風(fēng)險(xiǎn)。通過(guò)副本提高系統(tǒng)可用性。當(dāng)master掛掉,從slave中選舉新的機(jī)器作為master保證系統(tǒng)可用。
3 主從復(fù)制配置及原理
主從復(fù)制可以分為三個(gè)階段:初始化、同步、命令傳播。
初始化:從服務(wù)器執(zhí)行完 slaveof 命令后,slave與master建立socket連接。連接建立完畢后通過(guò)ping進(jìn)行心跳檢測(cè),若master正常,則返回響應(yīng)。如果出現(xiàn)故障收不到響應(yīng),那么slave會(huì)重新嘗試連接master。如果master設(shè)置了認(rèn)證信息,則會(huì)再檢查認(rèn)證數(shù)據(jù)是否正確。如果認(rèn)證失敗,則會(huì)報(bào)錯(cuò)。
同步:當(dāng)初始化完畢,master收到slave的數(shù)據(jù)同步命令后,需要判斷是否執(zhí)行全量同步還是部分同步。
命令傳播:同步完成后,master與slave通過(guò)心跳檢測(cè)判斷對(duì)方是否在線。slave同時(shí)向master發(fā)送自己復(fù)制緩沖區(qū)的偏移量。master根據(jù)這些請(qǐng)求,判斷是否向slave同步新產(chǎn)生的命令。slave收到同步的命令后執(zhí)行,最終與master保持同步。
4 使用Lettuce在主從模式下執(zhí)行命令
常用的Java Redis客戶(hù)端有Jedis、Redission、Lettuce。這里將通過(guò)Lettuce來(lái)演示主從模式下的讀寫(xiě)分離命令執(zhí)行。
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
<version>5.1.8.RELEASE</version>
</dependency>
下面通過(guò)
package redis;
import io.lettuce.core.ReadFrom;
import io.lettuce.core.RedisClient;
import io.lettuce.core.RedisURI;
import io.lettuce.core.api.sync.RedisCommands;
import io.lettuce.core.codec.Utf8StringCodec;
import io.lettuce.core.masterslave.MasterSlave;
import io.lettuce.core.masterslave.StatefulRedisMasterSlaveConnection;
import org.assertj.core.util.Lists;
class MainLettuce {
public static void main(String[] args) {
List<RedisURI> nodes = Lists.newArrayList(
RedisURI.create("redis://localhost:7000"),
RedisURI.create("redis://localhost:7001")
);
RedisClient redisClient = RedisClient.create();
StatefulRedisMasterSlaveConnection<String, String> connection = MasterSlave.connect(
redisClient,
new Utf8StringCodec(), nodes);
connection.setReadFrom(ReadFrom.SLAVE);
RedisCommands<String, String> redisCommand = connection.sync();
redisCommand.set("master","master write test2");
String value = redisCommand.get("master");
System.out.println(value);
connection.close();
redisClient.shutdown();
}
}
補(bǔ)充:Redis 客戶(hù)端之Lettuce配置使用(基于Spring Boot 2.x)
開(kāi)發(fā)環(huán)境:使用Intellij IDEA + Maven + Spring Boot 2.x + JDK 8
Spring Boot 從 2.0版本開(kāi)始,將默認(rèn)的Redis客戶(hù)端Jedis替換問(wèn)Lettuce,下面描述Lettuce的配置使用。
1.在項(xiàng)目的pom.xml文件下,引入Redis在Spring Boot 下的相關(guān)Jar包依賴(lài)
<properties>
<redisson.version>3.8.2</redisson.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<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>
</dependencies>
2.在項(xiàng)目的resources目錄下,在application.yml文件里添加lettuce的配置參數(shù)
#Redis配置 spring: redis: database: 6 #Redis索引0~15,默認(rèn)為0 host: 127.0.0.1 port: 6379 password: #密碼(默認(rèn)為空) lettuce: # 這里標(biāo)明使用lettuce配置 pool: max-active: 8 #連接池最大連接數(shù)(使用負(fù)值表示沒(méi)有限制) max-wait: -1ms #連接池最大阻塞等待時(shí)間(使用負(fù)值表示沒(méi)有限制) max-idle: 5 #連接池中的最大空閑連接 min-idle: 0 #連接池中的最小空閑連接 timeout: 10000ms #連接超時(shí)時(shí)間(毫秒)
3.添加Redisson的配置參數(shù)讀取類(lèi)RedisConfig
package com.dbfor.redis.config;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
/**
* RedisTemplate配置
* @param connectionFactory
* @return
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory connectionFactory) {
// 配置redisTemplate
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(connectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer());//key序列化
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());//value序列化
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
4.構(gòu)建Spring Boot的啟動(dòng)類(lèi)RedisApplication
package com.dbfor.redis;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class RedisApplication {
public static void main(String[] args) {
SpringApplication.run(RedisApplication.class);
}
}
5.編寫(xiě)測(cè)試類(lèi)RedisTest
package com.dbfor.redis;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.test.context.junit4.SpringRunner;
@SpringBootTest
@RunWith(SpringRunner.class)
@Component
public class RedisTest {
@Autowired
private RedisTemplate redisTemplate;
@Test
public void set() {
redisTemplate.opsForValue().set("test:set1", "testValue1");
redisTemplate.opsForSet().add("test:set2", "asdf");
redisTemplate.opsForHash().put("hash1", "name1", "lms1");
redisTemplate.opsForHash().put("hash1", "name2", "lms2");
redisTemplate.opsForHash().put("hash1", "name3", "lms3");
System.out.println(redisTemplate.opsForValue().get("test:set"));
System.out.println(redisTemplate.opsForHash().get("hash1", "name1"));
}
}
6.在Redis上查看運(yùn)行結(jié)果
從上圖可以看到,Lettuce配置操作數(shù)據(jù)庫(kù)成功!
以上為關(guān)于 Java 中如何使用 Lettuce 客戶(hù)端在 redis 的主從復(fù)制模式下命令執(zhí)行的操作的詳細(xì)內(nèi)容,希望能給大家一個(gè)參考,也希望大家多多支持W3Cschool。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。