首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Java 操作 Redis 核心 API 實戰:連接池、序列化、管道與 Lua 腳本最佳實踐

     編輯:Java 綜合教學

Java 操作 Redis 核心 API 實戰指南

Redis 作為高性能鍵值存儲,Java 客戶端 Jedis/Lettuce 是後端開發必備技能。本文補全原文缺失內容,系統講解連接池配置、數據結構操作、序列化策略、管道優化、Lua 腳本原子性、集群模式等生產級最佳實踐。

一、客戶端選型與依賴

客戶端特點適用場景
Jedis阻塞 API、功能全、社區成熟傳統同步業務、單機/哨兵模式
Lettuce非阻塞 Netty、線程安全、支援響應式高併發、集群模式、Spring WebFlux
Redisson分布式鎖、對象映射、豐富數據結構分布式協調、複雜業務建模

Maven 依賴(以 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>

二、連接池配置最佳實踐

JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(200);           // 最大連接數
poolConfig.setMaxIdle(50);             // 最大閒置連接
poolConfig.setMinIdle(10);             // 最小閒置連接
poolConfig.setMaxWaitMillis(3000);     // 獲取連接超時
poolConfig.setTestOnBorrow(true);      // 借用時驗證
poolConfig.setTestOnReturn(true);      // 歸還時驗證
poolConfig.setTestWhileIdle(true);     // 空閒驗證
poolConfig.setTimeBetweenEvictionRunsMillis(30000);

JedisPool jedisPool = new JedisPool(poolConfig, "localhost", 6379, 2000, "password", 0);

Spring Boot 自動配置

spring:
  redis:
    host: localhost
    port: 6379
    password: your_password
    database: 0
    lettuce:
      pool:
        max-active: 200
        max-idle: 50
        min-idle: 10
        max-wait: 3000ms
    timeout: 2000ms

三、核心數據結構操作

try (Jedis jedis = jedisPool.getResource()) {
    // String
    jedis.set("user:1001", "{\"name\":\"Tom\",\"age\":28}");
    String json = jedis.get("user:1001");
    
    // Hash(對象映射首選)
    jedis.hset("user:1001", "name", "Tom");
    jedis.hset("user:1001", "age", "28");
    Map<String, String> user = jedis.hgetAll("user:1001");
    
    // List(隊列/棧)
    jedis.lpush("task:queue", "task1", "task2");
    String task = jedis.rpop("task:queue");
    
    // Set(去重/標籤)
    jedis.sadd("tags:java", "backend", "jvm", "spring");
    Set<String> tags = jedis.smembers("tags:java");
    
    // Sorted Set(排行榜/延遲隊列)
    jedis.zadd("rank:score", 95.5, "userA");
    jedis.zadd("rank:score", 88.0, "userB");
    Set<Tuple> top10 = jedis.zrevrangeWithScores("rank:score", 0, 9);
    
    // 過期時間
    jedis.expire("session:abc", 1800);  // 30分鐘
    long ttl = jedis.ttl("session:abc");
}

四、序列化策略對比

方案優點缺點適用場景
JDK 原生無依賴、支援任意對象體積大、不可讀、版本敏感簡單臨時數據
JSON (Jackson/Gson)可讀、跨語言、版本兼容體積中等、反序列化較慢通用業務數據、API 緩存
Protobuf/MessagePack體積極小、速度快、Schema 演進需定義 .proto、學習成本高性能、大對象、跨服務調用
Kryo/FSTJava 專用、極快、無需接口跨語言差、版本遷移複雜高頻緩存、會話存儲

Jackson 整合範例

ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

String json = mapper.writeValueAsString(user);
User u = mapper.readValue(json, User.class);

五、管道技術優化批量操作

管道將多條命令打包發送,減少網絡 RTT,非事務性(不保證原子性)。

// 批量寫入 10萬條用戶緩存
try (Jedis jedis = jedisPool.getResource()) {
    Pipeline pipeline = jedis.pipelined();
    for (int i = 0; i < 100000; i++) {
        pipeline.set("user:" + i, "data" + i);
        if (i % 1000 == 0) pipeline.sync();  // 定期刷新防止客戶端緩衝區 OOM
    }
    pipeline.sync();
}

// 批量讀取
List<Object> results = jedis.pipelined(pipe -> {
    for (String key : keys) pipe.get(key);
}).syncAndReturnAll();

六、Lua 腳本保證原子性

Redis 單線程執行 Lua 腳本,天然原子,替代分布式鎖實現「檢查-設置」模式。

限流腳本(令牌桶)

-- limit.lua
local key = KEYS[1]
local limit = tonumber(ARGV[1])
local window = tonumber(ARGV[2])
local current = redis.call('GET', key)
if current and tonumber(current) >= limit then
    return redis.call('TTL', key)
end
local incr = redis.call('INCR', key)
if incr == 1 then
    redis.call('EXPIRE', key, window)
end
return 0

Java 調用

String script = new String(Files.readAllBytes(Paths.get("limit.lua")));
DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>(script, Long.class);

try (Jedis jedis = jedisPool.getResource()) {
    Long ttl = (Long) jedis.eval(redisScript.getScriptAsString(), 
        Collections.singletonList("rate:limit:user:1001"), "100", "60");
    if (ttl > 0) throw new RateLimitException("請求過於頻繁," + ttl + "秒後重試");
}

七、Redis 集群模式與分片

// JedisCluster 最少 3 主 3 從
Set<HostAndPort> nodes = new HashSet<>();
nodes.add(new HostAndPort("192.168.1.10", 7001));
nodes.add(new HostAndPort("192.168.1.11", 7001));
nodes.add(new HostAndPort("192.168.1.12", 7001));

JedisCluster cluster = new JedisCluster(nodes, 3000, 3000, 3, "password", poolConfig);

// 只能操作單鍵或同槽位鍵
cluster.set("user:1001", "data");
// cluster.mget("a", "b") // 報錯:CROSSSLOT Keys don't hash to same slot

// 強制同槽位:Hash Tags
cluster.set("{user:1001}:profile", "...");
cluster.set("{user:1001}:settings", "...");

八、常見坑與優化清單

  1. 大 Key 拆分: String > 10KB、Hash/Set/ZSet 成員 > 5000 時拆分
  2. 禁用 KEYS *: 生產環境使用 SCAN 游標迭代
  3. 合理設置 TTL: 避免永久 Key 佔用內存,使用隨機過期時間防止雪崩
  4. 連接池洩漏: 必須 try-with-resources 或 finally 歸還
  5. 監控指標: 命中率、QPS、慢查詢、內存碎片率、連接數
  6. 熱 Key 發現: redis-cli --hotkeys 或 Proxy 層統計
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved