最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

在Java中整合Redis的詳細步驟

 更新時間:2025年11月06日 09:17:08   作者:祈禱蒼天賜我java之術  
這篇文章詳細介紹了在Java中整合Redis的過程,包括Redis的基礎認知、環(huán)境搭建、Jedis和Redisson客戶端的使用、SpringBoot整合Redis以及Redis的進階知識,感興趣的朋友跟隨小編一起看看吧

一、Redis 基礎認知:為什么選擇 Redis?

1.1 Redis 的核心特性

高性能

  • 內存存儲機制:Redis 將數據完全存儲在內存中,數據讀寫操作直接在內存中進行,避免了磁盤I/O的瓶頸。內存讀寫速度通常是磁盤的100倍以上(內存訪問約100ns,SSD約100μs)。
  • 單線程模型:采用單線程處理命令請求,避免了多線程上下文切換和鎖競爭的開銷,同時通過I/O多路復用技術(如epoll)實現高并發(fā)處理。
  • 性能基準:在標準服務器配置(如8核CPU,16GB內存)下,Redis單節(jié)點可達到:
    • 讀操作(QPS):10萬-15萬次/秒
    • 寫操作(QPS):8萬-12萬次/秒
    • 特別優(yōu)化的場景下甚至可達20萬+ QPS

豐富的數據結構

  • String:最基本類型,最大512MB,常用于緩存簡單數據或計數器
  • Hash:鍵值對集合,適合存儲對象(如用戶信息:user:1001 {name:"張三",age:28})
  • List:雙向鏈表,可實現消息隊列(LPUSH+BRPOP)或最新N條記錄
  • Set:無序集合,支持交并差運算,適合標簽系統(tǒng)
  • Sorted Set:帶權重的有序集合,可用于排行榜(ZADD game:score 100 "player1")
  • Bitmap:位圖操作,適合簽到統(tǒng)計(SETBIT sign:202301 100 1)
  • HyperLogLog:基數統(tǒng)計,誤差率0.81%,適合UV統(tǒng)計(PFADD uv:20230101 "user1")

持久化機制

  • RDB(快照)
    • 定時將內存數據生成二進制快照文件(dump.rdb)
    • 配置示例:save 900 1(900秒內至少1次修改觸發(fā)保存)
    • 優(yōu)點:文件緊湊,恢復速度快
    • 缺點:可能丟失最后一次快照后的數據
  • AOF(Append Only File)
  • 記錄所有寫操作命令(類似MySQL的binlog)
  • 提供三種同步策略:
    • always:每次寫操作都同步
    • everysec:每秒同步(默認)
    • no:由操作系統(tǒng)決定
      • 優(yōu)點:數據安全性高,最多丟失1秒數據
      • 缺點:文件較大,恢復速度較慢
  • 混合模式:Redis 4.0+支持RDB+AOF混合持久化,結合兩者優(yōu)勢

高可用與分布式

  • 主從復制
    • 一個主節(jié)點(Master)可配置多個從節(jié)點(Slave)
    • 從節(jié)點異步復制主節(jié)點數據
    • 讀寫分離:寫操作走主節(jié)點,讀操作可分散到從節(jié)點
  • 哨兵模式(Sentinel)
    • 由2個以上哨兵節(jié)點監(jiān)控Redis集群狀態(tài)
    • 自動故障轉移:主節(jié)點宕機時,自動將從節(jié)點提升為主節(jié)點
    • 提供配置中心和通知機制
  • Redis Cluster
    • 官方分布式解決方案(Redis 3.0+)
    • 數據分片存儲:16384個哈希槽分配到不同節(jié)點
    • 節(jié)點間使用Gossip協(xié)議通信
    • 支持自動故障轉移和請求重定向

多語言支持

  • Java:Jedis、Lettuce、Redisson
  • Python:redis-py
  • Go:go-redis
  • Node.js:ioredis
  • 所有客戶端庫均遵循Redis協(xié)議規(guī)范,支持連接池、管道等高級特性

1.2 Redis 在 Java 項目中的典型應用場景

緩存熱點數據

  • 實現方式
// Spring Cache示例
@Cacheable(value="products", key="#productId")
public Product getProduct(String productId) {
    return productDao.findById(productId); 
}
  • 緩存策略
    • 緩存穿透:布隆過濾器或空值緩存
    • 緩存雪崩:隨機過期時間
    • 緩存擊穿:互斥鎖更新

分布式鎖

  • 原生實現
// SETNX實現
String lockKey = "order_lock_"+orderId;
String clientId = UUID.randomUUID().toString();
try {
    Boolean result = redisTemplate.opsForValue().setIfAbsent(lockKey, clientId, 30, TimeUnit.SECONDS);
    if(result) {
        // 執(zhí)行業(yè)務邏輯
    } else {
        // 獲取鎖失敗
    }
} finally {
    // 使用Lua腳本保證原子性
    String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
    redisTemplate.execute(new DefaultRedisScript<>(script, Long.class), 
                        Collections.singletonList(lockKey), clientId);
}

Redisson實現

RLock lock = redissonClient.getLock("order_lock_"+orderId);
try {
    // 嘗試加鎖,最多等待100秒,上鎖后30秒自動解鎖
    if(lock.tryLock(100, 30, TimeUnit.SECONDS)) {
        // 執(zhí)行業(yè)務邏輯
    }
} finally {
    lock.unlock();
}

計數器與限流

計數器示例

// 文章閱讀量計數
redisTemplate.opsForValue().increment("article:read:count:"+articleId);
// 獲取閱讀量
Long count = redisTemplate.opsForValue().increment("article:read:count:"+articleId, 0);

限流實現(滑動窗口算法):

public boolean isAllowed(String key, int maxCount, int period) {
    long now = System.currentTimeMillis();
    long windowStart = now - period * 1000;
    // 刪除舊時間戳
    redisTemplate.opsForZSet().removeRangeByScore(key, 0, windowStart);
    // 獲取當前請求數
    long count = redisTemplate.opsForZSet().zCard(key);
    if(count < maxCount) {
        // 添加當前請求
        redisTemplate.opsForZSet().add(key, String.valueOf(now), now);
        return true;
    }
    return false;
}

消息隊列

List實現簡單隊列

// 生產者
redisTemplate.opsForList().leftPush("queue:order", orderJson);
// 消費者
String orderJson = redisTemplate.opsForList().rightPop("queue:order", 30, TimeUnit.SECONDS);

Redis Stream實現(Redis 5.0+):

// 創(chuàng)建消費者組
redisTemplate.opsForStream().createGroup("order_stream", "order_group");
// 生產者
Map<String, String> message = new HashMap<>();
message.put("orderId", "1001");
message.put("amount", "99.9");
redisTemplate.opsForStream().add("order_stream", message);
// 消費者
List<MapRecord<String, String, String>> records = redisTemplate.opsForStream()
    .read(Consumer.from("order_group", "consumer1"),
        StreamReadOptions.empty().count(1).block(Duration.ofSeconds(1)),
        StreamOffset.create("order_stream", ReadOffset.lastConsumed()));

分布式Session

Spring Session集成

<!-- pom.xml -->
<dependency>
    <groupId>org.springframework.session</groupId>
    <artifactId>spring-session-data-redis</artifactId>
</dependency>
# application.properties
spring.session.store-type=redis
spring.session.timeout=1800 # 30分鐘
// 自動將Session存儲到Redis
@RestController
@SessionAttributes("user")
public class UserController {
    @PostMapping("/login")
    public String login(@RequestParam String username, Model model) {
        model.addAttribute("user", username);
        return "login success";
    }
}
  • Session共享效果
    • 用戶登錄后,Session信息存儲在Redis
    • 同一用戶的請求可路由到集群中任意節(jié)點
    • 各服務通過統(tǒng)一Session ID獲取用戶狀態(tài)
    • 默認使用Jackson序列化Session對象

二、環(huán)境搭建:Redis 服務與 Java 開發(fā)環(huán)境準備

2.1 Redis 服務端部署(以 Linux 為例)

步驟 1:下載并解壓 Redis

下載 Redis(版本可根據需求選擇,此處以 6.2.6 為例)
# 下載 Redis 源碼包
wget https://download.redis.io/releases/redis-6.2.6.tar.gz
# 驗證下載完整性(可選)
wget https://download.redis.io/releases/redis-6.2.6.tar.gz.asc
gpg --verify redis-6.2.6.tar.gz.asc
# 解壓 Redis 源碼包
tar -zxvf redis-6.2.6.tar.gz
# 進入解壓后的目錄
cd redis-6.2.6
注意事項:
  • 建議使用穩(wěn)定版本(stable)而非開發(fā)版本
  • 下載前可訪問 https://download.redis.io/releases/ 查看最新版本
  • 對于生產環(huán)境,建議使用 Redis 6.x 及以上版本以支持多線程處理

步驟 2:編譯與安裝

# 安裝編譯依賴(CentOS/RHEL)
yum install -y gcc make tcl
# 或 Ubuntu/Debian
apt-get install -y build-essential tcl
# 編譯 Redis(此過程可能需要幾分鐘)
make
# 運行測試(可選,但推薦)
make test
# 安裝 Redis 到系統(tǒng)目錄
make install
安裝結果驗證:
  • 默認安裝路徑:/usr/local/bin
  • 檢查是否安裝成功:
    ls -l /usr/local/bin/redis-*

步驟 3:配置并啟動 Redis

基本配置管理:
# 創(chuàng)建 Redis 配置目錄
mkdir -p /etc/redis
# 復制配置文件模板
cp redis.conf /etc/redis/redis.conf
# 創(chuàng)建數據存儲目錄
mkdir -p /var/lib/redis
關鍵配置文件修改(/etc/redis/redis.conf):
# 使用 vim 或其他編輯器修改配置文件
vim /etc/redis/redis.conf

需要修改的重要配置項:

網絡配置

# 允許遠程訪問(注釋掉或修改為)
# bind 127.0.0.1
bind 0.0.0.0

安全配置

# 關閉保護模式
protected-mode no
# 設置密碼(生產環(huán)境必須)
requirepass your_strong_password

運行模式

# 以守護進程方式運行
daemonize yes

日志配置

# 指定日志文件路徑
logfile "/var/log/redis/redis-server.log"

數據持久化(根據需求配置):

# RDB 持久化配置
save 900 1
save 300 10
save 60 10000
# AOF 持久化配置(可選)
appendonly yes
appendfsync everysec
啟動 Redis 服務:
# 創(chuàng)建日志目錄
mkdir -p /var/log/redis
chown -R redis:redis /var/log/redis
# 啟動 Redis 服務
redis-server /etc/redis/redis.conf
# 驗證服務狀態(tài)
ps aux | grep redis
netstat -tulnp | grep 6379
連接測試:
# 本地連接測試
redis-cli -h 127.0.0.1 -p 6379 -a your_password ping
# 遠程連接測試(從其他服務器)
redis-cli -h your_server_ip -p 6379 -a your_password ping
設置開機自啟(可選):
# 創(chuàng)建 systemd 服務文件
vim /etc/systemd/system/redis.service

添加以下內容:

[Unit]
Description=Redis In-Memory Data Store
After=network.target
[Service]
User=redis
Group=redis
ExecStart=/usr/local/bin/redis-server /etc/redis/redis.conf
ExecStop=/usr/local/bin/redis-cli shutdown
Restart=always
[Install]
WantedBy=multi-user.target

然后執(zhí)行:

# 重新加載 systemd
systemctl daemon-reload
# 啟用開機自啟
systemctl enable redis
# 啟動服務
systemctl start redis
# 檢查狀態(tài)
systemctl status redis

2.2 Java 開發(fā)環(huán)境配置

客戶端選擇說明

Java 操作 Redis 主要有兩種主流客戶端:

  • Jedis
    • 官方推薦的輕量級客戶端
    • 直接操作 Redis 命令
    • 支持連接池
    • 適合簡單場景和性能要求高的場景
  • Redisson
    • 基于 Netty 實現
    • 提供分布式對象和服務
    • 內置分布式鎖、原子操作等高級功能
    • 適合復雜分布式場景

2.2.1 Maven 依賴配置

Jedis 依賴配置(推薦使用連接池):
<!-- Jedis 核心依賴 -->
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>4.3.1</version>
</dependency>
<!-- 連接池依賴(必須) -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.11.1</version>
</dependency>
<!-- 可選:JSON 序列化支持 -->
<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.9.0</version>
</dependency>
Redisson 依賴配置:
<!-- Redisson 核心依賴 -->
<dependency>
    <groupId>org.redisson</groupId>
    <artifactId>redisson</artifactId>
    <version>3.17.6</version>
</dependency>
<!-- 可選:配置支持(如 JSON/YAML 配置文件) -->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.3</version>
</dependency>
版本選擇建議:
  • 生產環(huán)境建議使用穩(wěn)定版本
  • 可訪問 Maven 中央倉庫(https://mvnrepository.com/)查詢最新版本
  • 注意版本兼容性:
    • Jedis 4.x 支持 Redis 6.x
    • Redisson 3.x 支持 Redis 5.x+

開發(fā)環(huán)境驗證

創(chuàng)建簡單的測試類驗證環(huán)境是否配置成功:

import redis.clients.jedis.Jedis;
public class RedisTest {
    public static void main(String[] args) {
        // 創(chuàng)建連接
        Jedis jedis = new Jedis("localhost", 6379);
        jedis.auth("your_password");  // 如果有密碼
        // 測試連接
        System.out.println("連接狀態(tài):" + jedis.ping());
        // 基本操作
        jedis.set("test_key", "Hello Redis");
        System.out.println("獲取值:" + jedis.get("test_key"));
        // 關閉連接
        jedis.close();
    }
}

IDE 配置建議

  • IntelliJ IDEA
    • 確保 Maven 項目正確導入依賴
    • 安裝 Redis 插件(如 "Redis" 插件)方便調試
  • Eclipse
    • 使用 M2Eclipse 插件管理依賴
    • 可安裝 Redis 客戶端插件(如 "RedisClipse")

生產環(huán)境注意事項

  • 連接池配置
    • 必須使用連接池管理連接
    • 推薦配置參數:
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(128);       // 最大連接數
poolConfig.setMaxIdle(32);         // 最大空閑連接
poolConfig.setMinIdle(8);          // 最小空閑連接
poolConfig.setTestOnBorrow(true);  // 獲取連接時測試
  • 安全建議
    • 不要將密碼硬編碼在代碼中
    • 使用配置中心或環(huán)境變量管理敏感信息
    • 啟用 SSL/TLS 加密傳輸(Redis 6+支持)
  • 性能優(yōu)化
    • 批量操作使用 pipeline
    • 大 value 考慮分片存儲
    • 合理選擇序列化方式

三、Jedis 客戶端:Java 操作 Redis 的基礎實現

3.1 基本使用:單實例連接

步驟 1:創(chuàng)建 Jedis 實例并連接 Redis

import redis.clients.jedis.Jedis;
public class JedisBasicDemo {
    public static void main(String[] args) {
        // 1. 創(chuàng)建Jedis實例(參數說明:Redis地址、端口、連接超時時間(毫秒)、密碼)
        // 注意:如果Redis服務器在同一臺機器,地址可以是"localhost"
        Jedis jedis = new Jedis("192.168.1.100", 6379, 5000); 
        try {
            // 2. 驗證密碼(若Redis未設置密碼,可跳過此步驟)
            // 如果密碼錯誤,會拋出redis.clients.jedis.exceptions.JedisDataException
            jedis.auth("your_password");
            // 3. 測試連接
            // ping()返回"PONG"表示連接正常
            System.out.println("Redis連接狀態(tài):" + jedis.ping()); // 期望輸出:PONG
            // 4. 操作String類型數據
            jedis.set("username", "zhangsan"); // 存入數據,默認永不過期
            // 帶過期時間的設置(單位秒)
            jedis.setex("temp_token", 3600, "abcd1234"); 
            String username = jedis.get("username"); // 獲取數據
            System.out.println("獲取到的用戶名:" + username); // 輸出:zhangsan
            // 5. 操作Hash類型數據
            // 存儲用戶信息
            jedis.hset("user:1001", "name", "lisi");
            jedis.hset("user:1001", "age", "25");
            jedis.hset("user:1001", "gender", "male");
            // 獲取Hash中所有字段和值(返回Map<String,String>)
            System.out.println("用戶1001信息:" + jedis.hgetAll("user:1001"));
            // 輸出:{name=lisi, age=25, gender=male}
            // 獲取單個字段
            System.out.println("用戶年齡:" + jedis.hget("user:1001", "age")); // 輸出:25
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 6. 關閉連接(重要!避免連接泄漏)
            if (jedis != null) {
                jedis.close();
            }
        }
    }
}

注意事項

  • 線程安全性
    • Jedis實例是非線程安全的,每個線程應該使用自己的Jedis實例
    • 在高并發(fā)場景中直接使用單例連接會導致線程安全問題
  • 性能考量
    • 每次操作都需要創(chuàng)建和關閉TCP連接,頻繁操作時會產生較大性能開銷
    • 實測表明,在100次連續(xù)操作中,單實例連接方式耗時是連接池方式的10倍以上
  • 實際應用建議
    • 開發(fā)環(huán)境或簡單腳本可以使用單實例連接
    • 生產環(huán)境必須使用連接池(JedisPool)管理連接
    • 對于長時間運行的任務,建議使用try-with-resources確保連接關閉
  • 異常處理
    • 網絡中斷時可能拋出JedisConnectionException
    • 認證失敗拋出JedisDataException
    • 建議對關鍵操作添加重試機制

3.2 進階使用:Jedis 連接池

步驟 1:配置 Jedis 連接池

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
public class JedisPoolDemo {
    // 初始化Jedis連接池(使用靜態(tài)代碼塊確保只初始化一次)
    private static JedisPool jedisPool;
    static {
        // 1. 配置連接池參數
        GenericObjectPoolConfig<Jedis> poolConfig = new GenericObjectPoolConfig<>();
        // 關鍵參數配置(根據實際業(yè)務需求調整)
        poolConfig.setMaxTotal(100);       // 最大連接數(根據Redis服務器配置調整)
        poolConfig.setMaxIdle(20);         // 最大空閑連接數(建議設為MaxTotal的20%-50%)
        poolConfig.setMinIdle(5);          // 最小空閑連接數(保持一定數量的熱連接)
        poolConfig.setBlockWhenExhausted(true); // 連接耗盡時是否阻塞等待(建議true)
        poolConfig.setMaxWaitMillis(3000); // 獲取連接最大等待時間(毫秒)
        poolConfig.setTestOnBorrow(true);  // 獲取連接時是否測試有效性(建議true,但會有性能損耗)
        poolConfig.setTestOnReturn(false); // 歸還連接時是否測試(建議false)
        poolConfig.setTestWhileIdle(true); // 空閑時是否測試(建議true)
        // 2. 初始化連接池
        String redisHost = "192.168.1.100";
        int redisPort = 6379;
        int timeout = 5000; // 連接超時時間(毫秒)
        String password = "your_password";
        jedisPool = new JedisPool(
            poolConfig, 
            redisHost, 
            redisPort, 
            timeout, 
            password
        );
    }
    // 從連接池獲取Jedis實例
    public static Jedis getJedis() {
        return jedisPool.getResource();
    }
    // 測試連接池使用
    public static void main(String[] args) {
        // 使用try-with-resources語法自動管理連接
        try (Jedis jedis = getJedis()) {
            // 1. 操作String類型
            jedis.set("product:1001", "iPhone 13");
            System.out.println("商品1001名稱:" + jedis.get("product:1001"));
            // 2. 操作List類型(模擬消息隊列)
            jedis.lpush("message:queue", "msg1", "msg2", "msg3"); // 左推(入隊)
            // 右拉(出隊),0表示無限期阻塞等待
            String msg = jedis.brpop(0, "message:queue").get(1); 
            System.out.println("消費的消息:" + msg);
            // 3. 批量操作(使用pipeline提升性能)
            long start = System.currentTimeMillis();
            for (int i = 0; i < 1000; i++) {
                jedis.set("key_" + i, "value_" + i);
            }
            long end = System.currentTimeMillis();
            System.out.println("普通操作耗時:" + (end - start) + "ms");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

核心優(yōu)勢

  • 性能優(yōu)化
    • 連接復用減少TCP三次握手開銷
    • 實測在1000次操作中,連接池方式比單實例快8-10倍
    • 支持Pipeline批量操作,進一步提升吞吐量
  • 資源管理
    • 自動維護連接池中的活躍連接數
    • 可配置連接最大存活時間(maxAge)避免長時間使用的連接出現問題
    • 通過evictor線程定期檢測和清理無效連接
  • 生產環(huán)境配置建議
// 典型生產環(huán)境配置
poolConfig.setMaxTotal(200);       // 根據QPS估算,一般(平均QPS*平均耗時(ms))/1000
poolConfig.setMaxIdle(50);         // 根據業(yè)務波動情況調整
poolConfig.setMinIdle(10);         // 保持一定熱連接
poolConfig.setMaxWaitMillis(1000); // 根據系統(tǒng)容忍度設置
poolConfig.setTestOnBorrow(true);  // 確保獲取的連接可用
poolConfig.setTimeBetweenEvictionRunsMillis(30000); // 30秒檢測一次
  • 監(jiān)控指標
    • 可通過JMX監(jiān)控連接池狀態(tài)
    • 關鍵指標:活動連接數、空閑連接數、等待獲取連接的線程數等
  • 最佳實踐
    • 每個應用使用獨立的連接池
    • 根據業(yè)務類型(讀寫比例、命令復雜度)配置不同連接池
    • 定期監(jiān)控連接池狀態(tài),及時調整參數

3.3 Jedis 操作核心數據結構

(1)Set 類型(無序、唯一)

try (Jedis jedis = JedisPoolDemo.getJedis()) {
    // 1. 添加元素(自動去重)
    jedis.sadd("tags:java", "spring", "mybatis", "redis");
    jedis.sadd("tags:java", "spring"); // 重復元素不會被添加
    // 2. 獲取所有元素(無序)
    System.out.println("Java相關標簽:" + jedis.smembers("tags:java")); 
    // 輸出可能是:[redis, spring, mybatis]
    // 3. 判斷元素是否存在
    System.out.println("是否包含spring:" + jedis.sismember("tags:java", "spring")); 
    // 輸出:true
    // 4. 移除元素
    jedis.srem("tags:java", "mybatis");
    // 5. 計算集合大小
    System.out.println("標簽數量:" + jedis.scard("tags:java")); // 輸出:2
    // 6. 集合運算
    jedis.sadd("tags:backend", "spring", "django", "redis");
    // 交集
    System.out.println("交集:" + jedis.sinter("tags:java", "tags:backend"));
    // 輸出:[spring, redis]
    // 并集
    System.out.println("并集:" + jedis.sunion("tags:java", "tags:backend"));
    // 輸出:[spring, redis, django]
    // 差集(tags:java有而tags:backend沒有的)
    System.out.println("差集:" + jedis.sdiff("tags:java", "tags:backend"));
    // 輸出:[]
}

(2)Sorted Set 類型(有序、唯一,基于分數排序)

try (Jedis jedis = JedisPoolDemo.getJedis()) {
    // 1. 添加元素(如果成員已存在,則更新分數)
    jedis.zadd("rank:java", 95, "zhangsan");
    jedis.zadd("rank:java", 88, "lisi");
    jedis.zadd("rank:java", 92, "wangwu");
    jedis.zadd("rank:java", 90, "lisi"); // 更新lisi的分數
    // 2. 按分數升序獲?。?到-1表示全部)
    System.out.println("升序排名:" + jedis.zrange("rank:java", 0, -1));
    // 輸出:[lisi, wangwu, zhangsan]
    // 3. 按分數降序獲取(帶分數)
    Set<Tuple> results = jedis.zrevrangeWithScores("rank:java", 0, -1);
    results.forEach(tuple -> 
        System.out.println(tuple.getElement() + ":" + tuple.getScore())
    );
    // 輸出:
    // zhangsan:95.0
    // wangwu:92.0
    // lisi:90.0
    // 4. 獲取分數
    System.out.println("lisi的分數:" + jedis.zscore("rank:java", "lisi"));
    // 輸出:90.0
    // 5. 獲取排名(從0開始)
    System.out.println("zhangsan的降序排名:" + jedis.zrevrank("rank:java", "zhangsan"));
    // 輸出:0
    // 6. 范圍查詢(80<=score<=90)
    System.out.println("80-90分的學生:" + 
        jedis.zrangeByScoreWithScores("rank:java", 80, 90));
    // 輸出:[lisi:90.0, wangwu:92.0](注意包含邊界)
    // 7. 原子操作:增加分數
    jedis.zincrby("rank:java", 5, "lisi"); // lisi分數+5
    System.out.println("新分數:" + jedis.zscore("rank:java", "lisi"));
    // 輸出:95.0
}

(3)其他數據結構操作

// Geo地理位置操作
try (Jedis jedis = JedisPoolDemo.getJedis()) {
    // 添加地理位置(經度、緯度、名稱)
    jedis.geoadd("cities", 116.404, 39.915, "beijing");
    jedis.geoadd("cities", 121.474, 31.230, "shanghai");
    // 計算兩地距離(單位:km)
    Double dist = jedis.geodist("cities", "beijing", "shanghai", GeoUnit.KM);
    System.out.println("北京到上海距離:" + dist + "km");
    // 查找附近位置
    List<GeoRadiusResponse> nearby = jedis.georadiusByMember(
        "cities", 
        "beijing", 
        1000, 
        GeoUnit.KM
    );
    nearby.forEach(r -> System.out.println(r.getMemberByString()));
}
// HyperLogLog基數統(tǒng)計
try (Jedis jedis = JedisPoolDemo.getJedis()) {
    // 添加元素(用于統(tǒng)計不重復元素數量)
    for (int i = 0; i < 10000; i++) {
        jedis.pfadd("visitors", "user_" + i);
        jedis.pfadd("visitors", "user_" + (i % 5000)); // 50%重復
    }
    // 獲取基數估計值
    System.out.println("獨立訪客數:" + jedis.pfcount("visitors"));
    // 輸出約7500(誤差率約0.81%)
}

四、Redisson 客戶端:Java 操作 Redis 的高級實現

Redisson是基于Jedis的封裝,不僅提供了更簡潔易用的API,還實現了大量Redis官方推薦的分布式特性。相比原生Jedis,Redisson具有以下核心優(yōu)勢:

  1. 線程安全:內置連接池管理,徹底解決Jedis線程安全問題
  2. 豐富特性:支持分布式鎖(可重入鎖、公平鎖、聯(lián)鎖等)、分布式集合(Set、Map、List)、延遲隊列、布隆過濾器等20+種分布式對象
  3. 協(xié)議支持:完整支持Redis 5.0+的所有命令和數據類型
  4. 容錯機制:自動重連、故障轉移、讀寫分離等企業(yè)級特性

4.1 Redisson客戶端初始化

Redisson支持多種Redis部署模式,每種模式的配置方式如下:

單點模式配置示例

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
/**
 * Redisson客戶端工廠類(推薦單例模式)
 * 典型應用場景:Spring Bean管理、靜態(tài)工具類等
 */
public class RedissonClientFactory {
    // 使用volatile保證多線程可見性
    private static volatile RedissonClient redissonClient;
    // 雙重檢查鎖實現線程安全初始化
    public static RedissonClient getRedissonClient() {
        if (redissonClient == null) {
            synchronized (RedissonClientFactory.class) {
                if (redissonClient == null) {
                    // 1. 創(chuàng)建配置構建器
                    Config config = new Config();
                    // 2. 配置單點模式(生產環(huán)境建議使用YAML/JSON配置文件)
                    config.useSingleServer()
                          .setAddress("redis://192.168.1.100:6379") // 支持rediss://協(xié)議(SSL加密)
                          .setPassword("your_password")             // 密碼特殊字符需URL編碼
                          .setDatabase(0)                           // 默認DB索引
                          .setConnectionPoolSize(100)               // 最大連接數(默認64)
                          .setConnectionMinimumIdleSize(10)         // 最小空閑連接(默認10)
                          .setConnectTimeout(5000)                  // 連接超時(毫秒)
                          .setIdleConnectionTimeout(30000)          // 空閑連接超時
                          .setRetryAttempts(3)                      // 命令重試次數
                          .setRetryInterval(1000);                  // 重試間隔
                    // 3. 創(chuàng)建客戶端實例(實際會啟動連接池和定時任務)
                    redissonClient = Redisson.create(config);
                }
            }
        }
        return redissonClient;
    }
    // 優(yōu)雅關閉方法
    public static void shutdown() {
        if (redissonClient != null) {
            redissonClient.shutdown();
        }
    }
}

其他部署模式配置示例

哨兵模式
config.useSentinelServers()
      .addSentinelAddress("redis://sentinel1:26379")
      .addSentinelAddress("redis://sentinel2:26379")
      .setMasterName("mymaster");
集群模式
config.useClusterServers()
      .addNodeAddress("redis://node1:6379")
      .addNodeAddress("redis://node2:6379")
      .setScanInterval(2000); // 集群狀態(tài)掃描間隔

最佳實踐建議

  1. 連接池配置:根據QPS調整連接數(建議公式:最大連接數 = QPS × 平均響應時間(秒))
  2. 超時設置:網絡不穩(wěn)定的環(huán)境適當增大超時時間
  3. 資源釋放:應用關閉時調用shutdown()釋放資源
  4. 配置分離:生產環(huán)境建議使用外部配置文件(JSON/YAML格式)

4.2 Redisson 操作核心數據結構

Redisson 是一個基于 Redis 的 Java 客戶端,它通過 RedissonClient 提供了對應 Redis 數據結構的封裝類,使得操作 Redis 更加面向對象和簡潔。Redisson 支持 Redis 的所有核心數據結構,包括 String、Hash、List、Set 和 Sorted Set 等,每種數據結構都有對應的 Java 接口實現。

(1)String 類型(RBucket)

RBucket 是 Redisson 對 Redis String 類型的封裝,提供了一系列操作字符串的方法。RBucket 支持設置過期時間,適用于緩存場景。

import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
public class RedissonStringDemo {
    public static void main(String[] args) {
        // 獲取 RedissonClient 實例
        RedissonClient redissonClient = RedissonClientFactory.getRedissonClient();
        try {
            // 獲取 RBucket 對象(對應 Redis 的 String 類型)
            RBucket<String> usernameBucket = redissonClient.getBucket("username");
            // 存入數據,并設置過期時間為 3600 秒(1小時)
            usernameBucket.set("zhangsan", 3600);
            // 獲取數據
            String username = usernameBucket.get();
            System.out.println("用戶名:" + username); // 輸出:zhangsan
            // 判斷 key 是否存在
            System.out.println("是否存在:" + usernameBucket.isExists()); // 輸出:true
            // 刪除數據
            usernameBucket.delete();
            System.out.println("刪除后是否存在:" + usernameBucket.isExists()); // 輸出:false
        } finally {
            // 關閉客戶端(若為長期運行的服務,無需頻繁關閉)
            redissonClient.shutdown();
        }
    }
}

(2)Hash 類型(RMap)

RMap 是 Redisson 對 Redis Hash 類型的封裝,提供類似 Java Map 的操作方法,適用于存儲對象或結構化數據。

import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
public class RedissonHashDemo {
    public static void main(String[] args) {
        RedissonClient redissonClient = RedissonClientFactory.getRedissonClient();
        try {
            // 獲取 RMap 對象(對應 Redis 的 Hash 類型)
            RMap<String, String> userMap = redissonClient.getMap("user:1001");
            // 存入數據
            userMap.put("name", "lisi");
            userMap.put("age", "25");
            userMap.put("gender", "male");
            // 獲取數據
            System.out.println("用戶姓名:" + userMap.get("name")); // 輸出:lisi
            System.out.println("用戶所有信息:" + userMap); // 輸出:{name=lisi, age=25, gender=male}
            // 刪除字段
            userMap.remove("gender");
            System.out.println("刪除 gender 后的信息:" + userMap); // 輸出:{name=lisi, age=25}
            // 判斷字段是否存在
            System.out.println("是否包含 age:" + userMap.containsKey("age")); // 輸出:true
        } finally {
            // 關閉客戶端
            redissonClient.shutdown();
        }
    }
}

(3)List 類型(RList)

RList 是 Redisson 對 Redis List 類型的封裝,支持雙向添加、刪除和獲取元素,適用于隊列或棧的場景。

import org.redisson.api.RList;
import org.redisson.api.RedissonClient;
public class RedissonListDemo {
    public static void main(String[] args) {
        RedissonClient redissonClient = RedissonClientFactory.getRedissonClient();
        try {
            // 獲取 RList 對象(對應 Redis 的 List 類型)
            RList<String> messageList = redissonClient.getList("message:queue");
            // 添加元素(右添加,等同于 RPUSH)
            messageList.add("msg1");
            // 左添加(等同于 LPUSH)
            messageList.add(0, "msg0");
            // 獲取指定索引元素
            System.out.println("索引 0 的元素:" + messageList.get(0)); // 輸出:msg0
            // 獲取所有元素
            System.out.println("所有消息:" + messageList); // 輸出:[msg0, msg1]
            // 移除并返回最后一個元素(等同于 RPOP)
            String lastMsg = messageList.remove(messageList.size() - 1);
            System.out.println("移除的最后一條消息:" + lastMsg); // 輸出:msg1
            // 獲取列表長度
            System.out.println("列表長度:" + messageList.size()); // 輸出:1
        } finally {
            redissonClient.shutdown();
        }
    }
}

(4)Set 類型(RSet)

RSet 是 Redisson 對 Redis Set 類型的封裝,支持元素的添加、刪除和集合運算,適用于標簽或唯一值存儲場景。

import org.redisson.api.RSet;
import org.redisson.api.RedissonClient;
public class RedissonSetDemo {
    public static void main(String[] args) {
        RedissonClient redissonClient = RedissonClientFactory.getRedissonClient();
        try {
            // 獲取 RSet 對象(對應 Redis 的 Set 類型)
            RSet<String> tagSet = redissonClient.getSet("tags:java");
            // 添加元素
            tagSet.add("spring");
            tagSet.add("mybatis");
            tagSet.add("redis");
            // 判斷元素是否存在
            System.out.println("是否包含 spring:" + tagSet.contains("spring")); // 輸出:true
            // 獲取所有元素
            System.out.println("Java 標簽集合:" + tagSet); // 輸出:[spring, mybatis, redis]
            // 創(chuàng)建另一個 Set
            RSet<String> backendTagSet = redissonClient.getSet("tags:backend");
            backendTagSet.add("spring");
            backendTagSet.add("django");
            backendTagSet.add("redis");
            // 計算并返回交集
            System.out.println("Java 與 Backend 標簽交集:" + tagSet.retainAll(backendTagSet));
            // 輸出:[spring, redis](retainAll 方法會保留交集元素并返回)
            // 獲取集合大小
            System.out.println("交集大小:" + tagSet.size()); // 輸出:2
        } finally {
            redissonClient.shutdown();
        }
    }
}

(5)Sorted Set 類型(RSortedSet)

RSortedSet 是 Redisson 對 Redis Sorted Set 類型的封裝,支持按分數排序和范圍查詢,適用于排行榜或優(yōu)先級隊列場景。

import org.redisson.api.RSortedSet;
import org.redisson.api.RedissonClient;
import org.redisson.api.ScoredEntry;
import java.util.Collection;
public class RedissonSortedSetDemo {
    public static void main(String[] args) {
        RedissonClient redissonClient = RedissonClientFactory.getRedissonClient();
        try {
            // 獲取 RSortedSet 對象(對應 Redis 的 Sorted Set 類型)
            RSortedSet<String> rankSet = redissonClient.getSortedSet("rank:java");
            // 添加元素(指定分數)
            rankSet.add(95, "zhangsan");
            rankSet.add(88, "lisi");
            rankSet.add(92, "wangwu");
            // 按分數升序獲取元素
            System.out.println("成績升序排名:" + rankSet); // 輸出:[lisi, wangwu, zhangsan]
            // 按分數降序獲取元素(含分數)
            Collection<ScoredEntry<String>> scoredEntries = rankSet.entryRangeReversed(0, -1);
            for (ScoredEntry<String> entry : scoredEntries) {
                System.out.println(entry.getValue() + ":" + entry.getScore());
                // 輸出:
                // zhangsan:95.0
                // wangwu:92.0
                // lisi:88.0
            }
            // 獲取指定元素的排名(降序)
            System.out.println("zhangsan 的排名:" + rankSet.revRank("zhangsan")); // 輸出:0
            // 獲取分數范圍內的元素
            Collection<String> range = rankSet.valueRange(90, true, 95, true);
            System.out.println("分數在 90~95 之間的學生:" + range); // 輸出:[wangwu, zhangsan]
        } finally {
            redissonClient.shutdown();
        }
    }
}

4.3 Redisson 高級特性:分布式鎖與延遲隊列

4.3.1 分布式鎖(RLock)

在分布式系統(tǒng)中,多個服務實例可能同時操作同一資源(如訂單創(chuàng)建、庫存扣減等場景),分布式鎖可避免并發(fā)問題,保證數據一致性。Redisson 的RLock實現了與Java的ReentrantLock類似的可重入鎖特性,且支持自動過期釋放機制,無需手動處理死鎖問題。

核心特性
  1. 可重入性:同一線程可以多次獲取同一把鎖
  2. 自動續(xù)期:通過watchdog機制自動延長鎖持有時間
  3. 公平鎖支持:可配置為公平鎖模式
  4. 鎖等待超時:避免線程無限期等待
  5. 鎖釋放保障:通過finally塊確保鎖釋放
典型應用場景
  • 秒殺系統(tǒng)中的庫存扣減
  • 支付系統(tǒng)中的訂單狀態(tài)變更
  • 分布式定時任務調度
  • 重要數據的并發(fā)修改
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import java.util.concurrent.TimeUnit;
public class RedissonDistributedLockDemo {
    // 鎖的key命名規(guī)范:業(yè)務類型:業(yè)務ID(如訂單創(chuàng)建鎖)
    private static final String LOCK_KEY = "lock:order:create"; 
    public static void createOrder(RedissonClient redissonClient) {
        // 1. 獲取分布式鎖實例(非阻塞)
        RLock lock = redissonClient.getLock(LOCK_KEY);
        try {
            // 2. 嘗試獲取鎖(參數說明)
            // - waitTime: 獲取鎖的最大等待時間(建議設置短于業(yè)務超時時間)
            // - leaseTime: 鎖自動釋放時間(業(yè)務完成前應足夠長)
            // - TimeUnit: 時間單位
            boolean isLocked = lock.tryLock(3, 30, TimeUnit.SECONDS);
            if (isLocked) {
                try {
                    // 3. 加鎖成功,執(zhí)行業(yè)務邏輯
                    System.out.println(Thread.currentThread().getName() + "獲取分布式鎖成功,開始創(chuàng)建訂單...");
                    // 模擬業(yè)務處理耗時(如數據庫操作、遠程調用等)
                    Thread.sleep(5000);
                    System.out.println("訂單創(chuàng)建完成!");
                } finally {
                    // 4. 確保業(yè)務完成后再釋放鎖
                    if (lock.isHeldByCurrentThread()) {
                        lock.unlock();
                        System.out.println("分布式鎖已釋放!");
                    }
                }
            } else {
                // 5. 獲取鎖失敗處理(可記錄日志、返回友好提示或重試)
                System.out.println("獲取分布式鎖失敗,請稍后再試!");
                // 可拋出特定異?;蚍祷劐e誤碼
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            System.err.println("線程被中斷:" + e.getMessage());
        } catch (Exception e) {
            System.err.println("業(yè)務處理異常:" + e.getMessage());
        }
    }
    public static void main(String[] args) {
        RedissonClient redissonClient = RedissonClientFactory.getRedissonClient();
        // 模擬3個并發(fā)線程嘗試獲取鎖
        for (int i = 0; i < 3; i++) {
            new Thread(() -> createOrder(redissonClient), "Thread-"+i).start();
        }
        // 注意:實際應用中RedissonClient應該是單例長期存在
        // redissonClient.shutdown();
    }
}
最佳實踐
  1. 鎖命名規(guī)范:使用業(yè)務相關的有意義的名稱,如lock:order:{orderId}
  2. 鎖超時設置:leaseTime應大于預估的業(yè)務處理時間
  3. 異常處理:確保在finally塊中釋放鎖
  4. 避免長時間持有鎖:鎖持有時間應盡量短
  5. 重試機制:獲取鎖失敗時應有合理的重試策略

4.3.2 延遲隊列(RDelayedQueue)

延遲隊列可實現"消息延遲一段時間后再被消費"的場景,如訂單超時未支付自動取消、定時任務觸發(fā)、預約提醒等。Redisson的RDelayedQueue基于Redis的Sorted Set實現,提供了簡單易用的API,避免了自行實現延遲隊列的復雜性。

核心特性
  1. 精確延時:支持毫秒級延遲精度
  2. 持久化存儲:消息不會因服務重啟而丟失
  3. 高可用:基于Redis集群保證可靠性
  4. 多消費者支持:多個服務實例可以同時消費
  5. 消息順序保障:按延遲時間順序消費消息
典型應用場景
  • 電商訂單超時自動取消(30分鐘未支付)
  • 會議開始前15分鐘提醒
  • 延時任務調度
  • 紅包24小時未領取自動退回
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RedissonClient;
import java.util.concurrent.TimeUnit;
public class RedissonDelayedQueueDemo {
    // 延遲隊列命名規(guī)范:業(yè)務類型:業(yè)務目的
    private static final String DELAY_QUEUE_KEY = "delay:queue:order"; 
    private static final String BLOCKING_QUEUE_KEY = "blocking:queue:order";
    /**
     * 生產者:添加延遲消息
     * @param redissonClient Redisson客戶端
     * @param message 消息內容(建議包含業(yè)務ID)
     * @param delayTime 延遲時間(單位:秒)
     */
    public static void produceDelayMessage(RedissonClient redissonClient, String message, long delayTime) {
        // 1. 獲取阻塞隊列(底層實際存儲結構)
        RBlockingQueue<String> blockingQueue = redissonClient.getBlockingQueue(BLOCKING_QUEUE_KEY);
        // 2. 創(chuàng)建延遲隊列(與阻塞隊列關聯(lián))
        try (RDelayedQueue<String> delayedQueue = redissonClient.getDelayedQueue(blockingQueue)) {
            // 3. 添加延遲消息
            delayedQueue.offer(message, delayTime, TimeUnit.SECONDS);
            System.out.println("[" + System.currentTimeMillis() + "] 添加延遲消息:" + message 
                + ",延遲時間:" + delayTime + "秒");
        } // 自動關閉延遲隊列(Java 7+ try-with-resources)
    }
    /**
     * 消費者:持續(xù)消費延遲消息
     * @param redissonClient Redisson客戶端
     */
    public static void consumeDelayMessage(RedissonClient redissonClient) {
        // 1. 獲取阻塞隊列(與生產者使用的相同)
        RBlockingQueue<String> blockingQueue = redissonClient.getBlockingQueue(BLOCKING_QUEUE_KEY);
        System.out.println("消費者啟動,等待消費延遲消息...");
        while (!Thread.currentThread().isInterrupted()) {
            try {
                // 2. 阻塞獲取消息(當有消息到期時自動喚醒)
                String message = blockingQueue.take();
                // 3. 處理消息
                long currentTime = System.currentTimeMillis();
                System.out.println("[" + currentTime + "] 消費延遲消息:" + message);
                // 根據消息內容處理業(yè)務
                if (message != null && message.startsWith("order:")) {
                    String[] parts = message.split(":");
                    if (parts.length >= 2) {
                        String orderId = parts[1];
                        System.out.println("處理訂單超時:訂單" + orderId + "超時未支付,已自動取消!");
                        // 實際業(yè)務中此處會調用訂單服務取消訂單
                    }
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                System.err.println("消費者線程被中斷");
                break;
            } catch (Exception e) {
                System.err.println("消費消息異常:" + e.getMessage());
                // 可添加重試或錯誤處理邏輯
            }
        }
    }
    public static void main(String[] args) {
        RedissonClient redissonClient = RedissonClientFactory.getRedissonClient();
        // 啟動消費者線程(實際應用中通常是獨立服務)
        Thread consumerThread = new Thread(() -> consumeDelayMessage(redissonClient));
        consumerThread.setDaemon(true);
        consumerThread.start();
        // 模擬生產3個訂單延遲消息
        produceDelayMessage(redissonClient, "order:10001", 5);  // 5秒后超時
        produceDelayMessage(redissonClient, "order:10002", 10); // 10秒后超時
        produceDelayMessage(redissonClient, "order:10003", 15); // 15秒后超時
        // 保持主線程運行(演示用)
        try {
            Thread.sleep(20000);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        // 實際應用中不需要關閉(長期運行的服務)
        // redissonClient.shutdown();
    }
}
最佳實踐
  1. 消息設計:消息內容應包含足夠業(yè)務信息(如訂單ID)
  2. 異常處理:消費者需處理各種異常情況
  3. 冪等性:消息處理應保證冪等,防止重復消費
  4. 監(jiān)控報警:對消費延遲和堆積情況監(jiān)控
  5. 資源釋放:正確關閉延遲隊列實例
性能優(yōu)化建議
  1. 批量消費:可適當批量獲取消息減少網絡開銷
  2. 分區(qū)設計:大流量場景可按業(yè)務ID分多個隊列
  3. 消費并行度:根據業(yè)務需求調整消費者數量
  4. 消息壓縮:大消息可考慮壓縮后再存儲

五、Spring Boot 整合 Redis:企業(yè)級項目實戰(zhàn)

在 Spring Boot 項目中,可通過 spring-boot-starter-data-redis 快速整合 Redis,簡化配置和開發(fā)。該 starter 默認使用 Spring Data Redis 抽象層,支持 Jedis、Lettuce(Spring Boot 2.x 默認客戶端)等底層客戶端。Spring Data Redis 提供了統(tǒng)一的 API 來操作 Redis,支持多種數據結構的操作,包括字符串、哈希、列表、集合等。

5.1 環(huán)境配置

5.1.1 添加 Maven 依賴

pom.xml 中添加以下依賴:

<!-- Spring Boot Redis Starter -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <!-- 排除默認的Lettuce客戶端(若需使用Jedis,可添加此配置) -->
    <!-- <exclusions>
        <exclusion>
            <groupId>io.lettuce</groupId>
            <artifactId>lettuce-core</artifactId>
        </exclusion>
    </exclusions> -->
</dependency>
<!-- 若排除Lettuce后,需添加Jedis依賴 -->
<!-- <dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency> -->
<!-- Spring Boot Web Starter(用于演示接口) -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

說明:

  1. spring-boot-starter-data-redis 是 Spring Boot 提供的 Redis 啟動器,自動配置了 Redis 相關的 Bean。
  2. 默認使用 Lettuce 客戶端,如需切換為 Jedis,需排除 Lettuce 并添加 Jedis 依賴。
  3. spring-boot-starter-web 用于演示 RESTful 接口,實際項目中根據需求添加。
5.1.2 配置 application.yml

src/main/resources/application.yml 中添加 Redis 相關配置:

spring:
  redis:
    host: 192.168.1.100 # Redis服務地址,生產環(huán)境建議使用域名或內網IP
    port: 6379 # Redis端口,默認6379
    password: your_password # Redis密碼(若未設,可省略)
    database: 0 # Redis數據庫索引(0-15),默認0
    timeout: 5000ms # 連接超時時間
    lettuce: # Lettuce客戶端配置(若使用Jedis,需改為jedis配置)
      pool: # 連接池配置
        max-active: 100 # 最大連接數,默認8
        max-idle: 20 # 最大空閑連接數,默認8
        min-idle: 5 # 最小空閑連接數,默認0
        max-wait: 3000ms # 連接池耗盡時的最大等待時間,默認-1(無限等待)

配置項詳解:

  1. hostport:Redis 服務器地址和端口,必填項。
  2. password:如果 Redis 設置了密碼,需配置此項。
  3. database:Redis 默認有 16 個數據庫(0-15),可通過此配置選擇使用的數據庫。
  4. timeout:連接 Redis 的超時時間,建議設置為 5000ms 以上。
  5. lettuce.pool:Lettuce 連接池配置,適用于高并發(fā)場景:
    • max-active:最大連接數,根據業(yè)務量調整。
    • max-idlemin-idle:空閑連接數,避免頻繁創(chuàng)建和銷毀連接。
    • max-wait:獲取連接的最大等待時間,避免長時間阻塞。

Jedis 配置示例(如需切換):

spring:
  redis:
    host: 192.168.1.100
    port: 6379
    jedis:
      pool:
        max-active: 100
        max-idle: 20
        min-idle: 5
        max-wait: 3000ms

生產環(huán)境建議:

  1. 使用連接池以提高性能。
  2. 密碼和敏感信息建議通過環(huán)境變量或配置中心管理。
  3. 對于集群或哨兵模式,需額外配置。

5.2 核心 API:RedisTemplate 與 StringRedisTemplate

Spring Data Redis 提供了兩種主要的模板類用于操作 Redis,它們各自適用于不同的使用場景:

StringRedisTemplate

StringRedisTemplate 是專門用于操作 String 類型數據的模板類,具有以下特點:

  1. 序列化方式:默認使用 StringRedisSerializer,所有鍵和值都以 UTF-8 編碼的字符串形式存儲
  2. 優(yōu)勢
    • 完全避免中文亂碼問題
    • 存儲的數據可直接在 Redis CLI 中查看
    • 性能較高,適用于簡單字符串操作
  3. 限制
    • 只能操作字符串類型的數據
    • 無法直接存儲 Java 對象

RedisTemplate

RedisTemplate 是通用模板類,支持所有 Redis 數據結構,但需要注意:

  1. 默認序列化問題
    • 默認使用 JdkSerializationRedisSerializer
    • 會導致存儲的數據帶有"xac\xed\x00\x05t\x00"等序列化前綴
    • 存儲的數據在 Redis CLI 中不可讀
  2. 適用場景
    • 需要操作復雜數據結構(List, Set, ZSet等)
    • 需要直接存儲 Java 對象
    • 需要自定義序列化方式

5.2.1 配置 RedisTemplate(自定義序列化)

為優(yōu)化 RedisTemplate 的默認行為,推薦配置自定義序列化:

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.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        // 設置連接工廠(必需)
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        // Key序列化配置(String類型)
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        // Value序列化配置(JSON格式)
        GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = 
            new GenericJackson2JsonRedisSerializer();
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
        // 初始化模板(必需)
        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }
}

配置說明:

  1. 鍵序列化使用 StringRedisSerializer,保證鍵的可讀性
  2. 值序列化使用 Jackson,支持復雜對象存儲
  3. 必須調用 afterPropertiesSet() 完成初始化

5.2.2 StringRedisTemplate 使用示例

StringRedisTemplate 的常見操作示例:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@RestController
@RequestMapping("/redis/string")
public class StringRedisController {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    // 存儲String數據(帶過期時間)
    @PostMapping("/set")
    public String setString(@RequestParam String key,
                           @RequestParam String value,
                           @RequestParam(required = false, defaultValue = "3600") long timeout) {
        stringRedisTemplate.opsForValue().set(key, value, timeout, TimeUnit.SECONDS);
        return "存儲成功!Key:" + key + ",Value:" + value;
    }
    // 獲取String數據
    @GetMapping("/get/{key}")
    public String getString(@PathVariable String key) {
        String value = stringRedisTemplate.opsForValue().get(key);
        return "獲取到的數據:Key:" + key + ",Value:" + (value == null ? "無" : value);
    }
    // 存儲Hash數據
    @PostMapping("/hash/set")
    public String setHash(@RequestParam String key,
                        @RequestParam Map<String, String> hashMap) {
        stringRedisTemplate.opsForHash().putAll(key, hashMap);
        return "Hash數據存儲成功!Key:" + key;
    }
    // 獲取Hash數據
    @GetMapping("/hash/get/{key}")
    public Map<Object, Object> getHash(@PathVariable String key) {
        return stringRedisTemplate.opsForHash().entries(key);
    }
    // 設置過期時間
    @PostMapping("/expire")
    public Boolean expireKey(@RequestParam String key, 
                          @RequestParam long timeout) {
        return stringRedisTemplate.expire(key, timeout, TimeUnit.SECONDS);
    }
}

5.2.3 RedisTemplate 使用示例(操作對象)

定義實體類:

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String gender;
}

對象操作示例:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
import java.util.concurrent.TimeUnit;
@RestController
@RequestMapping("/redis/object")
public class ObjectRedisController {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    // 存儲User對象
    @PostMapping("/user/set")
    public String setUser(@RequestBody User user,
                        @RequestParam(required = false, defaultValue = "86400") long timeout) {
        String key = "user:" + user.getId();
        redisTemplate.opsForValue().set(key, user, timeout, TimeUnit.SECONDS);
        return "User對象存儲成功!Key:" + key + ",User:" + user;
    }
    // 獲取User對象
    @GetMapping("/user/get")
    public User getUser(@RequestParam Long userId) {
        String key = "user:" + userId;
        return (User) redisTemplate.opsForValue().get(key);
    }
    // 刪除User對象
    @PostMapping("/user/delete")
    public String deleteUser(@RequestParam Long userId) {
        String key = "user:" + userId;
        Boolean isDeleted = redisTemplate.delete(key);
        return isDeleted ? "User對象刪除成功!Key:" + key : "刪除失敗,Key不存在";
    }
}

操作說明:

  1. 對象存儲會自動使用配置的 Jackson 序列化器
  2. 獲取時會自動反序列化為 Java 對象
  3. 建議使用"類型:id"的鍵命名規(guī)范(如"user:123")

5.3 Spring Boot Redis緩存注解:簡化緩存開發(fā)

Spring Boot提供了@Cacheable、@CachePut、@CacheEvict等緩存注解,通過聲明式的方式快速實現緩存功能,無需手動調用RedisTemplate。這些注解底層基于Spring Cache抽象,可以與多種緩存實現(如Redis、EhCache等)無縫集成,大大簡化了緩存開發(fā)流程。

5.3.1 開啟緩存注解支持

在Spring Boot啟動類上添加@EnableCaching注解:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableCaching // 開啟緩存注解支持,自動配置CacheManager
public class RedisSpringBootApplication {
    public static void main(String[] args) {
        SpringApplication.run(RedisSpringBootApplication.class, args);
    }
}

注意事項

  1. 確保項目中已引入spring-boot-starter-cachespring-boot-starter-data-redis依賴
  2. 在application.properties/yml中配置Redis連接信息
  3. 默認情況下會自動配置RedisCacheManager

5.3.2 常用緩存注解詳解

(1)@Cacheable:查詢緩存

當方法被調用時,先從緩存中查詢數據。若緩存存在,則直接返回緩存數據;若緩存不存在,則執(zhí)行方法邏輯,并將結果存入緩存。

import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
@Service
public class UserService {
    /**
     * 根據用戶ID查詢用戶信息
     * @param userId 用戶ID
     * @return 用戶對象
     * 
     * 緩存配置說明:
     * - value="userCache": 指定緩存名稱(相當于Redis中的key前綴)
     * - key="#userId": 動態(tài)生成緩存key(使用SpEL表達式獲取方法參數)
     * - unless="#result == null": 當方法返回null時不緩存結果
     */
    @Cacheable(value = "userCache", key = "#userId", unless = "#result == null")
    public User getUserById(Long userId) {
        // 模擬從數據庫查詢數據(實際開發(fā)中替換為DAO層調用)
        System.out.println("從數據庫查詢用戶,userId:" + userId);
        return new User(userId, "張三", 25, "男");
    }
}

典型應用場景

  • 高頻訪問但數據變化不頻繁的查詢,如商品詳情、用戶信息等
  • 復雜計算結果的緩存,如報表數據、統(tǒng)計結果等
(2)@CachePut:更新緩存

執(zhí)行方法邏輯后,將結果存入緩存(無論緩存是否存在,都會覆蓋原有緩存),常用于數據新增或更新場景。

import org.springframework.cache.annotation.CachePut;
import org.springframework.stereotype.Service;
@Service
public class UserService {
    /**
     * 保存或更新用戶信息
     * @param user 用戶對象
     * @return 更新后的用戶對象
     * 
     * 緩存配置說明:
     * - value="userCache": 緩存名稱
     * - key="#user.id": 使用用戶ID作為緩存key
     * - unless="#result == null": 更新失敗不緩存
     */
    @CachePut(value = "userCache", key = "#user.id", unless = "#result == null")
    public User saveOrUpdateUser(User user) {
        // 模擬數據庫新增/更新操作
        System.out.println("數據庫新增/更新用戶,user:" + user);
        return user; // 將更新后的用戶對象存入緩存
    }
}

使用建議

  1. 方法返回值必須是需要緩存的對象
  2. 確保key與查詢方法@Cacheable的key一致
  3. 適用于insert和update操作
(3)@CacheEvict:刪除緩存

執(zhí)行方法邏輯后,刪除指定緩存,常用于數據刪除場景。

import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
@Service
public class UserService {
    /**
     * 刪除用戶
     * @param userId 用戶ID
     * 
     * 緩存配置說明:
     * - value="userCache": 緩存名稱
     * - key="#userId": 指定要刪除的緩存key
     * - allEntries=false: 默認只刪除指定key的緩存
     */
    @CacheEvict(value = "userCache", key = "#userId", allEntries = false)
    public void deleteUser(Long userId) {
        // 模擬數據庫刪除操作
        System.out.println("數據庫刪除用戶,userId:" + userId);
    }
    /**
     * 清空用戶緩存
     * 
     * 緩存配置說明:
     * - value="userCache": 緩存名稱
     * - allEntries=true: 刪除該緩存名稱下的所有緩存
     */
    @CacheEvict(value = "userCache", allEntries = true)
    public void clearUserCache() {
        System.out.println("清空用戶緩存");
    }
}

刪除策略選擇

  1. 單條刪除:使用key指定要刪除的緩存項
  2. 批量刪除:設置allEntries=true清空整個緩存區(qū)域
  3. 可在方法執(zhí)行前刪除(beforeInvocation=true)
(4)@Caching:組合緩存注解

當一個方法需要同時使用多個緩存注解(如同時更新和刪除緩存)時,可使用@Caching組合注解。

import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
@Service
public class UserService {
    /**
     * 更新用戶信息并清空用戶列表緩存
     * @param user 用戶對象
     * @return 更新后的用戶對象
     */
    @Caching(
        put = {
            // 更新用戶緩存
            @CachePut(value = "userCache", key = "#user.id")
        },
        evict = {
            // 刪除用戶列表緩存(假設存在用戶列表緩存)
            @CacheEvict(value = "userListCache", allEntries = true)
        }
    )
    public User updateUserAndClearListCache(User user) {
        // 模擬數據庫更新操作
        System.out.println("更新用戶并清空用戶列表緩存,user:" + user);
        return user;
    }
}

適用場景

  1. 需要同時操作多個緩存區(qū)域
  2. 需要同時執(zhí)行put和evict操作
  3. 復雜的緩存策略組合

六、Redis 進階:持久化、高可用與性能優(yōu)化

在實際生產環(huán)境中,僅掌握基礎使用還不夠,還需深入理解 Redis 的持久化機制、高可用架構配置及性能優(yōu)化技巧,確保 Redis 服務穩(wěn)定高效運行。本章將詳細介紹這些關鍵內容。

6.1 Redis 持久化機制

Redis 提供兩種持久化方式,可根據業(yè)務需求選擇單獨使用或組合使用,確保數據安全性和系統(tǒng)可靠性。

6.1.1 RDB(Redis Database):快照持久化

原理:在指定時間間隔內,將 Redis 內存中的數據生成二進制快照文件(.rdb 文件)并保存到磁盤。這種機制類似于數據庫的全量備份。

觸發(fā)方式

  • 手動觸發(fā)
    • save命令:阻塞 Redis 主線程直到快照完成,期間無法處理其他請求(生產環(huán)境不推薦)
    • bgsave命令:Redis 會 fork 一個子進程進行快照操作,主進程繼續(xù)提供服務(推薦方式)
  • 自動觸發(fā)
    • 通過 redis.conf 配置文件中的 save 指令設置觸發(fā)條件
    • 當 Redis 正常關閉時(shutdown命令)也會自動執(zhí)行 RDB 持久化

典型配置示例

# 900秒(15分鐘)內至少1個key變化,觸發(fā)RDB
save 900 1
# 300秒(5分鐘)內至少10個key變化,觸發(fā)RDB
save 300 10
# 60秒內至少10000個key變化,觸發(fā)RDB
save 60 10000
# RDB文件名稱
dbfilename dump.rdb
# 工作目錄(保存RDB文件和AOF文件的目錄)
dir /var/lib/redis

優(yōu)缺點分析

  • 優(yōu)點
    • 快照文件體積小,占用空間少
    • 恢復速度快,特別適合大規(guī)模數據恢復
    • 對 Redis 性能影響小,適合定期備份
  • 缺點
    • 可能丟失最后一次快照后的所有數據(如 Redis 異常崩潰時)
    • 當數據量很大時,fork 子進程的過程可能耗時較長,導致短暫的服務停頓

6.1.2 AOF(Append Only File):日志持久化

原理:將 Redis 的每一條寫命令(如 SET、HSET)以協(xié)議文本格式追加到 AOF 日志文件中,Redis 重啟時通過重新執(zhí)行日志中的命令來重建數據。

AOF 工作流程

  1. 命令執(zhí)行后寫入 AOF 緩沖區(qū)
  2. 根據配置的刷盤策略將緩沖區(qū)內容同步到磁盤
  3. 定期進行 AOF 重寫(rewrite)壓縮文件體積

配置詳解

# 開啟AOF(默認關閉,需手動設置為yes)
appendonly yes
# AOF文件名稱
appendfilename "appendonly.aof"
# AOF刷盤策略(關鍵配置)
# everysec:每秒刷盤一次(推薦,平衡性能和數據安全性)
# always:每執(zhí)行一條命令刷盤一次(數據零丟失,性能較差)
# no:由操作系統(tǒng)決定刷盤時機(性能最好,數據丟失風險最高)
appendfsync everysec
# AOF重寫觸發(fā)條件
# 當前AOF文件大小比起最后一次重寫時的大小增長率達到100%時觸發(fā)
auto-aof-rewrite-percentage 100
# AOF文件最小重寫大小,避免文件很小就重寫
auto-aof-rewrite-min-size 64mb
# 加載AOF時發(fā)現文件末尾不完整時的處理方式
aof-load-truncated yes

AOF 重寫機制

  1. 原理:創(chuàng)建一個新的 AOF 文件,包含重建當前數據集所需的最少命令集
  2. 觸發(fā)方式:
    • 自動觸發(fā):根據 auto-aof-rewrite-percentage 和 auto-aof-rewrite-min-size 配置
    • 手動觸發(fā):執(zhí)行BGREWRITEAOF命令

優(yōu)缺點分析

  • 優(yōu)點
    • 數據安全性高,最多丟失1秒數據(everysec配置下)
    • AOF 文件可讀性強,便于問題排查
    • 通過重寫機制可以壓縮文件大小
  • 缺點
    • AOF 文件通常比 RDB 文件大
    • 恢復速度比 RDB 慢
    • 在高寫入負載下,AOF 可能影響 Redis 性能

6.1.3 RDB 與 AOF 組合使用

生產環(huán)境中推薦同時開啟 RDB 和 AOF,充分發(fā)揮兩者的優(yōu)勢:

  • 數據恢復策略
    • 日常恢復:優(yōu)先使用 AOF 恢復(數據更完整)
    • 大規(guī)模數據恢復:若 AOF 文件過大,先使用 RDB 快速恢復基礎數據,再通過 AOF 補充后續(xù)數據
  • 典型配置組合
    • RDB 配置為每天全量備份一次
    • AOF 配置為每秒刷盤
    • 定期將 RDB 文件和 AOF 文件備份到異地
  • 注意事項
    • Redis 4.0+ 支持混合持久化(aof-use-rdb-preamble),AOF 文件前半部分是 RDB 格式,后半部分是 AOF 格式,可以結合兩者優(yōu)點
    • 需要監(jiān)控磁盤空間使用情況,避免持久化文件占滿磁盤

6.2 Redis 高可用配置

為避免 Redis 單點故障,需搭建高可用架構,確保服務持續(xù)可用。Redis 提供了多種高可用方案,適用于不同場景。

6.2.1 主從復制(Master-Slave)

原理:將一臺 Redis 服務器(Master)的數據同步到多臺 Redis 服務器(Slave),實現數據冗余和讀寫分離。

核心特性

  • 異步復制:Slave 異步從 Master 同步數據
  • 讀寫分離:Master 處理寫請求,Slave 處理讀請求
  • 級聯(lián)復制:Slave 可以作為其他 Slave 的 Master

配置步驟(以 1 主 2 從為例)

  1. 準備 3 臺 Redis 服務器(假設IP為192.168.1.100-102)
  2. 配置 Master(192.168.1.100): 確保 redis.conf 中有以下配置:
    # 如果需要密碼認證
    requirepass your_password
  3. 配置 Slave(192.168.1.101 和 192.168.1.102):
    # 指定Master的地址和端口
    replicaof 192.168.1.100 6379
    # 若Master設置了密碼,需配置認證密碼
    masterauth your_password
    # 可選:設置Slave只讀
    replica-read-only yes
  4. 驗證主從狀態(tài):
    • 在 Master 上執(zhí)行info replication查看 Slave 連接信息
    • 在 Slave 上執(zhí)行info replication查看復制狀態(tài)

主從復制過程

  1. Slave 啟動后向 Master 發(fā)送 SYNC 命令
  2. Master 執(zhí)行 BGSAVE 生成 RDB 文件并發(fā)送給 Slave
  3. Master 將生成 RDB 期間的新命令緩存起來,之后發(fā)送給 Slave
  4. 之后 Master 將所有寫命令異步發(fā)送給 Slave

注意事項

  • 復制延遲問題:網絡延遲或 Slave 負載過高可能導致數據不一致
  • 數據過期問題:Redis 的過期策略在主從模式下有特殊處理
  • 復制中斷處理:可通過replica-serve-stale-data yes配置Slave在斷開連接時是否繼續(xù)提供服務

6.2.2 哨兵模式(Sentinel)

原理:在主從復制的基礎上,增加哨兵進程監(jiān)控節(jié)點狀態(tài),實現自動故障轉移。

哨兵核心功能

  1. 監(jiān)控:持續(xù)檢查 Master 和 Slave 是否正常運行
  2. 通知:當監(jiān)控的 Redis 實例出現問題時,可以通過API通知管理員
  3. 自動故障轉移:當 Master 不可用時,自動選舉新的 Master
  4. 配置提供者:為客戶端提供最新的 Master 地址

配置步驟(3個哨兵節(jié)點)

  1. 準備哨兵配置文件 sentinel.conf:
    port 26379
    sentinel monitor mymaster 192.168.1.100 6379 2
    sentinel auth-pass mymaster your_password
    sentinel down-after-milliseconds mymaster 30000
    sentinel parallel-syncs mymaster 1
    sentinel failover-timeout mymaster 180000
  2. 啟動哨兵:
    redis-sentinel /path/to/sentinel.conf
  3. 驗證哨兵狀態(tài):
    redis-cli -p 26379 info sentinel

故障轉移流程

  1. 哨兵檢測到 Master 不可達(超過 down-after-milliseconds 時間)
  2. 哨兵集群選舉領導者哨兵(需要至少 quorum 數量的哨兵同意)
  3. 領導者哨兵從 Slave 中選擇新的 Master(基于優(yōu)先級、復制偏移量等)
  4. 將其他 Slave 重新配置為復制新的 Master
  5. 通知客戶端配置變更

客戶端訪問哨兵模式的最佳實踐

  1. 客戶端應連接哨兵獲取當前 Master 地址
  2. 客戶端應訂閱哨兵的+switch-master事件處理主從切換
  3. 建議使用支持哨兵的 Redis 客戶端庫(如Jedis、Lettuce)

6.2.3 Redis Cluster(集群)

原理:將數據分片存儲到多個節(jié)點,每個節(jié)點負責一部分哈希槽(共16384個槽),同時每個分片可配置主從復制。

集群特性

  • 數據分片:自動將數據分布到多個節(jié)點
  • 高可用:每個分片可以配置主從復制
  • 線性擴展:可通過增加節(jié)點擴展集群容量和性能
  • 客戶端路由:客戶端可直接連接正確的節(jié)點

配置步驟(3主3從集群)

  1. 準備6臺服務器(192.168.1.100-105),確保端口6379和16379開放
  2. 每個節(jié)點的 redis.conf 配置:
    cluster-enabled yes
    cluster-config-file nodes-6379.conf
    cluster-node-timeout 15000
    cluster-announce-ip 192.168.1.100 # 每臺填寫自己的IP
    cluster-announce-port 6379
    cluster-announce-bus-port 16379
  3. 啟動所有節(jié)點后,創(chuàng)建集群:
    redis-cli --cluster create \
      192.168.1.100:6379 192.168.1.101:6379 192.168.1.102:6379 \
      192.168.1.103:6379 192.168.1.104:6379 192.168.1.105:6379 \
      --cluster-replicas 1
  4. 驗證集群狀態(tài):
    redis-cli -c -h 192.168.1.100 -p 6379 cluster info
    redis-cli -c -h 192.168.1.100 -p 6379 cluster nodes

數據分片原理

  1. Redis 使用 CRC16(key) mod 16384 計算 key 所屬的槽位
  2. 每個節(jié)點負責一部分連續(xù)的槽位
  3. 客戶端可以緩存槽位到節(jié)點的映射關系

集群管理命令

  • cluster meet:將節(jié)點加入集群
  • cluster addslots:分配槽位給節(jié)點
  • cluster replicate:設置節(jié)點為從節(jié)點
  • cluster failover:手動觸發(fā)故障轉移

集群擴展操作

  1. 添加新節(jié)點:
    redis-cli --cluster add-node new_host:new_port existing_host:existing_port
  2. 遷移槽位:
    redis-cli --cluster reshard host:port
  3. 刪除節(jié)點:
    redis-cli --cluster del-node host:port node_id

6.3 Redis 性能優(yōu)化建議

6.3.1 硬件優(yōu)化

內存優(yōu)化

  • 為 Redis 分配足夠的內存,避免頻繁交換
  • 使用maxmemory限制 Redis 最大內存使用量
  • 考慮使用大頁內存(transparent huge pages)

CPU優(yōu)化

  • Redis 6.0+ 支持多線程IO(I/O threading),可配置:
    io-threads 4
    io-threads-do-reads yes
  • 在高并發(fā)場景下,可考慮使用多個 Redis 實例分擔負載

磁盤優(yōu)化

  • 使用 SSD 存儲持久化文件
  • 確保磁盤有足夠的寫入帶寬
  • 對于 AOF,可以考慮使用no-appendfsync-on-rewrite yes減少重寫時的磁盤壓力

6.3.2 配置優(yōu)化

內存管理配置

# 內存淘汰策略(當內存達到maxmemory時)
maxmemory-policy allkeys-lru
# 設置最大內存(例如4GB)
maxmemory 4gb
# 避免內存碎片
activedefrag yes

網絡配置優(yōu)化

# 提高TCP連接隊列大小
tcp-backlog 511
# 客戶端空閑超時時間
timeout 0 # 0表示不超時
# 最大客戶端連接數
maxclients 10000

持久化優(yōu)化

# 禁用持久化(僅用于純緩存場景)
save ""
appendonly no
# 如果使用RDB,適當調整save參數
save 3600 1  # 1小時內至少有1個變化則保存

6.3.3 開發(fā)優(yōu)化

鍵設計原則

  1. 使用簡潔但有意義的鍵名,如user:1000:profile
  2. 避免使用大鍵(如包含百萬元素的hash)
  3. 為鍵設置合理的過期時間

命令優(yōu)化

  1. 使用批量操作命令:
    • MSET替代多個SET
    • HMGET替代多個HGET
  2. 使用管道(pipeline)減少網絡往返:
    pipeline = redis.pipeline()
    pipeline.set('key1', 'value1')
    pipeline.set('key2', 'value2')
    pipeline.execute()
  3. 避免阻塞命令:
    • 避免在生產環(huán)境使用KEYS,改用SCAN
    • 謹慎使用FLUSHALL/FLUSHDB

客戶端優(yōu)化

  1. 使用連接池管理連接
  2. 合理設置連接池大小
  3. 實現客戶端緩存(Redis 6.0+的客戶端緩存功能)

監(jiān)控與調優(yōu)

  1. 定期檢查info命令輸出
  2. 監(jiān)控慢查詢(slowlog get
  3. 使用redis-benchmark進行性能測試
  4. 考慮使用Redis的Lua腳本減少網絡開銷

到此這篇關于在Java中整合Redis的詳細過程的文章就介紹到這了,更多相關java整合redis內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • SpringBoot配置Actuator組件,實現系統(tǒng)監(jiān)控

    SpringBoot配置Actuator組件,實現系統(tǒng)監(jiān)控

    在生產環(huán)境中,需要實時或定期監(jiān)控服務的可用性。Spring Boot的actuator(健康監(jiān)控)功能提供了很多監(jiān)控所需的接口,可以對應用系統(tǒng)進行配置查看、相關功能統(tǒng)計等。
    2021-06-06
  • 教你如何在 javadoc 輸出<> 符號

    教你如何在 javadoc 輸出<> 符號

    在 javadoc 輸出 <> 兩個符號,直接使用會提示錯誤,今天通過本文教大家如何在 javadoc 輸出<> 符號,需要的朋友可以參考下
    2023-05-05
  • 新版IDEA使用Spring Initializr創(chuàng)建工程的兩種方法

    新版IDEA使用Spring Initializr創(chuàng)建工程的兩種方法

    這篇文章主要介紹了新版IDEA使用Spring Initializr創(chuàng)建工程(兩種方法,官方工具和IDEA),文中通過代碼示例和圖文結合的方式給大家講解的非常詳細,具有一定的參考價值,需要的朋友可以參考下
    2024-10-10
  • 在Java中將List轉換為String輸出過程解析

    在Java中將List轉換為String輸出過程解析

    這篇文章主要介紹了在Java中將List轉換為String輸出過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-09-09
  • 使用Jackson 處理 null 或者 空字符串

    使用Jackson 處理 null 或者 空字符串

    這篇文章主要介紹了使用Jackson 處理 null 或者 空字符串,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • Java處理多API請求的方法詳解

    Java處理多API請求的方法詳解

    Java?中的并發(fā)是指語言并行運行多個線程的能力,允許同時執(zhí)行多個任務,
    2023-10-10
  • Java源碼解析HashMap成員變量

    Java源碼解析HashMap成員變量

    今天小編就為大家分享一篇關于Java源碼解析HashMap成員變量,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • 用SpringBoot框架來接收multipart/form-data文件方式

    用SpringBoot框架來接收multipart/form-data文件方式

    這篇文章主要介紹了用SpringBoot框架來接收multipart/form-data文件方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-02-02
  • Java之HashMap.values()轉List時的錯誤和正確演示

    Java之HashMap.values()轉List時的錯誤和正確演示

    這篇文章主要介紹了Java之HashMap.values()轉List時的錯誤和正確演示,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • Springboot 自定義線程池的參數配置最優(yōu)小結

    Springboot 自定義線程池的參數配置最優(yōu)小結

    在SpringBoot中配置自定義線程池時,參數的設置需要根據具體的應用場景、系統(tǒng)資源和業(yè)務需求來調整,本文就來詳細的介紹一下,感興趣的可以了解一下
    2025-10-10

最新評論

佛冈县| 同江市| 凤翔县| 阳谷县| 桓台县| 丰都县| 泸溪县| 远安县| 进贤县| 彭水| 阿拉善左旗| 万源市| 宝兴县| 遂川县| 从化市| 永济市| 五峰| 南华县| 金寨县| 靖远县| 涿鹿县| 汉阴县| 阳信县| 合作市| 胶州市| 长武县| 阿巴嘎旗| 德格县| 灵寿县| 烟台市| 来宾市| 西盟| 南昌县| 凤冈县| 沙湾县| 灌云县| 罗田县| 岳池县| 工布江达县| 金阳县| 贵阳市|