引言
在當(dāng)今高速發(fā)展的互聯(lián)網(wǎng)應(yīng)用中,數(shù)據(jù)訪(fǎng)問(wèn)性能是決定用戶(hù)體驗(yàn)的關(guān)鍵因素之一。Redis作為一個(gè)開(kāi)源的高性能鍵值內(nèi)存數(shù)據(jù)庫(kù),以其卓越的速度、豐富的數(shù)據(jù)結(jié)構(gòu)和廣泛的適用場(chǎng)景,成為了架構(gòu)師的"瑞士軍刀"。
無(wú)論是作為緩存、會(huì)話(huà)存儲(chǔ)還是消息隊(duì)列,Redis都能大顯身手。本文將帶你全面學(xué)習(xí)如何在Spring Boot中集成Redis,深入理解Redis集群的搭建與原理,并剖析其最核心的三大應(yīng)用場(chǎng)景,讓你真正掌握這把利器。
第一部分:入門(mén)篇 - Spring Boot快速集成Redis
目標(biāo): 在Spring Boot中成功連接Redis并執(zhí)行基本操作。
1. 環(huán)境準(zhǔn)備
- 安裝Redis服務(wù)器??梢詮?a target="_blank" rel="nofollow">官網(wǎng)下載安裝,或使用Docker快速啟動(dòng):
docker run -d --name redis -p 6379:6379 redis:latest - 創(chuàng)建一個(gè)Spring Boot項(xiàng)目。
2. 添加依賴(lài)
在pom.xml中添加Spring Boot Redis Starter依賴(lài)。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 連接池依賴(lài),推薦添加 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
3. 基礎(chǔ)配置
在application.yml中配置Redis連接信息。
spring:
redis:
host: 127.0.0.1
port: 6379
password: # 如果沒(méi)有密碼,可以不填
database: 0 # 默認(rèn)使用0號(hào)數(shù)據(jù)庫(kù)
lettuce:
pool:
max-active: 8 # 連接池最大連接數(shù)
max-idle: 8 # 連接池最大空閑連接數(shù)
min-idle: 0 # 連接池最小空閑連接數(shù)
4. 使用RedisTemplate操作Redis
Spring Data Redis提供了強(qiáng)大的RedisTemplate工具類(lèi)。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.concurrent.TimeUnit;
@Service
public class RedisService {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
// 設(shè)置值
public void setValue(String key, Object value) {
redisTemplate.opsForValue().set(key, value);
}
// 設(shè)置值并指定過(guò)期時(shí)間
public void setValueWithExpire(String key, Object value, long timeout, TimeUnit unit) {
redisTemplate.opsForValue().set(key, value, timeout, unit);
}
// 獲取值
public Object getValue(String key) {
return redisTemplate.opsForValue().get(key);
}
// 刪除鍵
public Boolean deleteKey(String key) {
return redisTemplate.delete(key);
}
// 判斷鍵是否存在
public Boolean hasKey(String key) {
return redisTemplate.hasKey(key);
}
}
5. 測(cè)試
編寫(xiě)一個(gè)Controller進(jìn)行測(cè)試,如果能夠成功存儲(chǔ)和讀取數(shù)據(jù),說(shuō)明集成成功!
@RestController
public class TestController {
@Autowired
private RedisService redisService;
@GetMapping("/test")
public String test() {
redisService.setValueWithExpire("name", "Redis入門(mén)用戶(hù)", 10, TimeUnit.MINUTES);
return "值是: " + redisService.getValue("name");
}
}
第二部分:進(jìn)階篇 - Redis集群模式詳解
單機(jī)Redis存在單點(diǎn)故障和容量瓶頸問(wèn)題,生產(chǎn)環(huán)境必須使用集群。
1. 主從復(fù)制 (Master-Slave)
- 概念: 一個(gè)主節(jié)點(diǎn)(Master)負(fù)責(zé)寫(xiě)操作,多個(gè)從節(jié)點(diǎn)(Slave)負(fù)責(zé)讀操作,并實(shí)時(shí)同步主節(jié)點(diǎn)的數(shù)據(jù)。
- 優(yōu)點(diǎn): 讀寫(xiě)分離,提高讀性能;數(shù)據(jù)備份,提高可靠性。
- 缺點(diǎn): 主節(jié)點(diǎn)宕機(jī)需要手動(dòng)切換,無(wú)法實(shí)現(xiàn)高可用。
2. 哨兵模式 (Sentinel)
- 概念: 在主從復(fù)制基礎(chǔ)上,引入哨兵進(jìn)程來(lái)監(jiān)控所有節(jié)點(diǎn)。當(dāng)主節(jié)點(diǎn)宕機(jī)時(shí),哨兵會(huì)自動(dòng)選舉一個(gè)從節(jié)點(diǎn)升級(jí)為主節(jié)點(diǎn)。
- 優(yōu)點(diǎn): 實(shí)現(xiàn)了高可用,自動(dòng)故障轉(zhuǎn)移。
- 缺點(diǎn): 寫(xiě)操作和存儲(chǔ)能力仍然受單主節(jié)點(diǎn)限制,擴(kuò)容復(fù)雜。
Spring Boot連接哨兵模式配置:
spring:
redis:
sentinel:
master: mymaster # 主節(jié)點(diǎn)名稱(chēng)
nodes: 192.168.1.10:26379,192.168.1.11:26379,192.168.1.12:26379 # 哨兵節(jié)點(diǎn)地址列表
3. 集群模式 (Cluster) - 生產(chǎn)環(huán)境推薦
- 概念: Redis官方提供的分布式解決方案。采用無(wú)中心結(jié)構(gòu),數(shù)據(jù)被分片(sharding)存儲(chǔ)在多個(gè)節(jié)點(diǎn)上(通常16384個(gè)槽位)。每個(gè)節(jié)點(diǎn)負(fù)責(zé)一部分槽位,節(jié)點(diǎn)之間通過(guò)Gossip協(xié)議通信。
-
優(yōu)點(diǎn):
- 高可用: 每個(gè)分片通常都是主從結(jié)構(gòu),支持自動(dòng)故障轉(zhuǎn)移。
- 高擴(kuò)展性: 數(shù)據(jù)分片存儲(chǔ),理論上可以線(xiàn)性擴(kuò)展至1000+節(jié)點(diǎn)。
- 無(wú)中心架構(gòu): 客戶(hù)端直接連接任意節(jié)點(diǎn),節(jié)點(diǎn)間可轉(zhuǎn)發(fā)請(qǐng)求。
-
Spring Boot連接集群模式配置:
spring: redis: cluster: nodes: 192.168.1.10:6379,192.168.1.11:6379,192.168.1.12:6379,192.168.1.13:6379,192.168.1.14:6379,192.168.1.15:6379 max-redirects: 3 # 最大重定向次數(shù) password: your_password
第三部分:精通篇 - Redis三大核心場(chǎng)景剖析
場(chǎng)景一:緩存 - 這是Redis最經(jīng)典的用法
- 目標(biāo): 減輕數(shù)據(jù)庫(kù)壓力,加速讀寫(xiě)。
-
實(shí)現(xiàn)模式:
-
Cache-Aside (旁路緩存):
- 讀: 先讀緩存,命中則返回;未命中則讀數(shù)據(jù)庫(kù),并將結(jié)果寫(xiě)入緩存。
- 寫(xiě): 直接更新數(shù)據(jù)庫(kù),然后刪除緩存(推薦,避免數(shù)據(jù)不一致復(fù)雜性)。
-
代碼示例:
public User getUserById(Long id) { String key = "user:" + id; // 1. 從緩存查詢(xún) User user = (User) redisTemplate.opsForValue().get(key); if (user != null) { return user; } // 2. 緩存沒(méi)有,從數(shù)據(jù)庫(kù)查詢(xún) user = userMapper.selectById(id); if (user != null) { // 3. 將數(shù)據(jù)寫(xiě)入緩存 redisTemplate.opsForValue().set(key, user, 30, TimeUnit.MINUTES); } return user; }
-
Cache-Aside (旁路緩存):
-
常見(jiàn)問(wèn)題:
- 緩存穿透: 查詢(xún)一個(gè)一定不存在的數(shù)據(jù)。解決方案:緩存空對(duì)象、使用布隆過(guò)濾器。
- 緩存擊穿: 某個(gè)熱點(diǎn)key過(guò)期瞬間,大量請(qǐng)求直接打到數(shù)據(jù)庫(kù)。解決方案:設(shè)置熱點(diǎn)key永不過(guò)期、使用互斥鎖。
- 緩存雪崩: 大量key在同一時(shí)間過(guò)期,導(dǎo)致所有請(qǐng)求都打到數(shù)據(jù)庫(kù)。解決方案:設(shè)置不同的過(guò)期時(shí)間、Redis高可用。
場(chǎng)景二:分布式鎖
- 目標(biāo): 在分布式系統(tǒng)中,控制對(duì)共享資源的互斥訪(fǎng)問(wèn)。
-
核心命令:
SET key value [EX seconds] [PX milliseconds] [NX|XX]-
EX設(shè)置過(guò)期時(shí)間,這是防止死鎖的關(guān)鍵! -
NX只在鍵不存在時(shí)設(shè)置,這是實(shí)現(xiàn)互斥性的關(guān)鍵。
-
-
代碼示例:
public boolean tryLock(String lockKey, String requestId, long expireTime) { // requestId用于標(biāo)識(shí)加鎖的客戶(hù)端,解鎖時(shí)可驗(yàn)證,避免解錯(cuò)鎖 Boolean result = redisTemplate.opsForValue() .setIfAbsent(lockKey, requestId, expireTime, TimeUnit.SECONDS); return Boolean.TRUE.equals(result); } public boolean unlock(String lockKey, String requestId) { // 使用Lua腳本保證判斷和刪除的原子性 String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"; Long result = redisTemplate.execute( new DefaultRedisScript<>(script, Long.class), Collections.singletonList(lockKey), requestId ); return Boolean.TRUE.equals(result == 1); }
場(chǎng)景三:計(jì)數(shù)器和排行榜
- 目標(biāo): 利用Redis原子操作實(shí)現(xiàn)高性能的計(jì)數(shù)和排序功能。
-
計(jì)數(shù)器實(shí)現(xiàn):
- 使用
INCR、INCRBY命令,原子性增加,可用于文章閱讀量、用戶(hù)點(diǎn)贊等。 // 文章閱讀量+1 redisTemplate.opsForValue().increment("article:view:123");
- 使用
-
排行榜實(shí)現(xiàn):
- 使用
ZSET(有序集合),成員為item,分?jǐn)?shù)為排序依據(jù)。 // 添加或更新用戶(hù)分?jǐn)?shù) redisTemplate.opsForZSet().add("leaderboard", "userA", 2500); redisTemplate.opsForZSet().add("leaderboard", "userB", 1800); // 獲取Top 10 Set<ZSetOperations.TypedTuple<Object>> top10 = redisTemplate.opsForZSet() .reverseRangeWithScores("leaderboard", 0, 9);
- 使用
總結(jié)
通過(guò)本文的學(xué)習(xí),我們系統(tǒng)地掌握了Redis在Spring Boot中的應(yīng)用:
- 入門(mén): 學(xué)會(huì)了Spring Boot與Redis的單機(jī)集成和基本CRUD操作。
- 進(jìn)階: 理解了主從、哨兵、集群三種模式的演進(jìn)與區(qū)別,并掌握了生產(chǎn)環(huán)境最推薦的集群配置方法。
- 精通: 深度剖析了Redis作為緩存、分布式鎖、計(jì)數(shù)器/排行榜的三大核心場(chǎng)景,并給出了代碼實(shí)現(xiàn)和問(wèn)題解決方案。
Redis的魅力遠(yuǎn)不止于此,它在消息隊(duì)列(Pub/Sub/Stream)、地理位置(GEO)、限流等場(chǎng)景中同樣表現(xiàn)出色。希望這篇文章能成為你Redis之旅的堅(jiān)實(shí)起點(diǎn),在實(shí)踐中不斷探索,讓Redis成為你構(gòu)建高性能、高可用系統(tǒng)的得力助手。