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

Spring 整合 Jedis 實現 Redis 分片集群客戶端完整實戰

     編輯:Java 綜合教學

Spring 整合 Jedis 實現 Redis 分片集群客戶端完整實戰

1. 依賴準備

引入核心 Jar 包 (Maven 坐標示例):

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.4.2</version> <!-- 建議升級至 3.x/4.x 版本 -->
</dependency>
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.0</version>
</dependency>

2. Spring XML 配置分片連接池

配置 ShardedJedisPool,支援主從架構,透過 JedisPoolConfig 精細調優連接池參數。

<bean id="shardedJedisPool" class="redis.clients.jedis.ShardedJedisPool">
    <constructor-arg index="0" ref="jedisPoolConfig"/>
    <constructor-arg index="1">
        <list>
            <bean name="master" class="redis.clients.jedis.JedisShardInfo">
                <constructor-arg index="0" value="${redis.master.host}"/>
                <constructor-arg index="1" value="${redis.master.port}" type="int"/>
            </bean>
            <bean name="slaver" class="redis.clients.jedis.JedisShardInfo">
                <constructor-arg index="0" value="${redis.slaver.host}"/>
                <constructor-arg index="1" value="${redis.slaver.port}" type="int"/>
            </bean>
        </list>
    </constructor-arg>
</bean>

<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
    <property name="maxTotal" value="2048"/>            <!-- 最大連接數 -->
    <property name="maxIdle" value="200"/>              <!-- 最大閒置連接 -->
    <property name="minIdle" value="50"/>               <!-- 最小閒置連接 -->
    <property name="maxWaitMillis" value="1500"/>       <!-- 獲取連接最大等待時間(ms) -->
    <property name="testOnBorrow" value="true"/>        <!-- 借出時驗證有效性 -->
    <property name="testWhileIdle" value="true"/>       <!-- 閒置驗證 -->
    <property name="testOnReturn" value="false"/>       <!-- 歸還時驗證 (通常關閉) -->
    <property name="timeBetweenEvictionRunsMillis" value="30000"/>
    <property name="numTestsPerEvictionRun" value="1024"/>
    <property name="minEvictableIdleTimeMillis" value="60000"/>
    <property name="softMinEvictableIdleTimeMillis" value="10000"/>
    <property name="blockWhenExhausted" value="false"/>  <!-- 連接耗盡時不阻塞,直接拋異常 -->
    <property name="jmxEnabled" value="true"/>
    <property name="jmxNamePrefix" value="myapp"/>
</bean>

屬性檔 redis.properties 中定義 redis.master.host、redis.master.port 等佔位符值。

3. 封裝通用 Redis 操作服務類

注入 ShardedJedisPool,封裝 Key 過期、String、List、Set、Hash、SortedSet (ZSet) 等核心資料結構操作,**統一資源獲取/歸還/異常處理邏輯**,保證連接池不洩漏。

@Service
public class RedisService {
    @Resource private ShardedJedisPool shardedJedisPool;
    private static final Logger logger = LoggerFactory.getLogger(RedisService.class);

    // 通用資源處理模板
    private ShardedJedis getResource() { return shardedJedisPool.getResource(); }
    private void returnResource(ShardedJedis jedis) {
        if (jedis != null) shardedJedisPool.returnResource(jedis);
    }
    private void returnBroken(ShardedJedis jedis) {
        if (jedis != null) shardedJedisPool.returnBrokenResource(jedis);
    }

    // --- Key 過期 ---
    public long expire(String key, int seconds) {
        if (key == null || key.isEmpty()) return 0;
        ShardedJedis jedis = null;
        try {
            jedis = getResource();
            return jedis.expire(key, seconds);
        } catch (Exception e) {
            logger.error("EXPIRE error[key={}, seconds={}]", key, seconds, e);
            returnBroken(jedis); return 0;
        } finally { returnResource(jedis); }
    }

    // --- String 操作 ---
    public boolean set(String key, String value) { /* 同模板 */ }
    public boolean set(String key, String value, int seconds) { /* setex */ }
    public String get(String key, String defVal) { /* 同模板 */ }
    public boolean del(String key) { /* 同模板 */ }
    public long incr(String key) { /* 同模板 */ }
    public long decr(String key) { /* 同模板 */ }

    // --- List 操作 (LPUSH/LRANGE/LTRIM/LLEN/LREM) ---
    public boolean addList(String key, String... values) { /* lpush */ }
    public boolean addList(String key, int seconds, String... values) { /* add + expire */ }
    public List<String> getList(String key) { /* lrange 0 -1 */ }
    public List<String> rangeList(String key, long start, long end) { /* lrange */ }
    public long countList(String key) { /* llen */ }
    public String trimList(String key, long start, long end) { /* ltrim */ }
    public int removeListValue(String key, long count, String value) { /* lrem */ }

    // --- Set 操作 (SADD/SREM/SISMEMBER/SMEMBERS/SCARD) ---
    public boolean addSet(String key, String... values) { /* sadd */ }
    public boolean addSet(String key, int seconds, String... values) { /* add + expire */ }
    public boolean removeSetValue(String key, String... values) { /* srem */ }
    public boolean containsInSet(String key, String value) { /* sismember */ }
    public Set<String> getSet(String key) { /* smembers */ }
    public long countSet(String key) { /* scard */ }

    // --- Hash 操作 (HSET/HGET/HDEL/HEXISTS/HKEYS/HVALS/HLEN/HSCAN) ---
    public boolean setHSet(String domain, String key, String value) { /* hset */ }
    public String getHSet(String domain, String key) { /* hget */ }
    public long delHSet(String domain, String... keys) { /* hdel */ }
    public boolean existsHSet(String domain, String key) { /* hexists */ }
    public List<Map.Entry<String,String>> scanHSet(String domain, String match) { /* hscan 迭代 */ }
    public List<String> hvals(String domain) { /* hvals */ }
    public Set<String> hkeys(String domain) { /* hkeys */ }
    public long lenHset(String domain) { /* hlen */ }

    // --- SortedSet (ZSet) 操作 (ZADD/ZRANGE/ZREVRANGE/ZRANGEBYSCORE/ZCOUNT/ZREM/ZSCORE) ---
    public boolean setSortedSet(String key, long score, String value) { /* zadd */ }
    public Set<String> getSoredSet(String key, long startScore, long endScore, boolean desc) { /* zrangeByScore */ }
    public Set<String> getSoredSetByRange(String key, int start, int end, boolean desc) { /* zrange/zrevrange */ }
    public long countSoredSet(String key, long startScore, long endScore) { /* zcount */ }
    public boolean delSortedSet(String key, String value) { /* zrem */ }
    public Double getScore(String key, String member) { /* zscore */ }
}

4. 關鍵最佳實踐總結

  • 資源管理鐵律:try { jedis = pool.getResource(); ... } catch { returnBroken(jedis); } finally { returnResource(jedis); } —— 異常時歸還「壞連接」,正常歸還「好連接」,防止連接池耗盡。
  • 分片邏輯:ShardedJedis 客戶端按 Key 一致性哈希路由至對應分片,適合海量 Key、單機記憶體不足場景。注意:跨分片操作 (如 KEYS *, FLUSHALL, 事務、Lua 腳本) 不支援或行為異常。
  • 連接池調優:maxTotal 擬設為 (業務峰值 QPS × 平均處理時間 ms / 1000) + 閒置緩衝;testOnBorrow=true 確保借出連接可用;啟用 testWhileIdle 定期清理殭屍連接。
  • 版本建議:生產環境強烈建議升級至 Jedis 3.x/4.x + Commons Pool 2.6+,修復大量 Bug、支援 Redis Cluster 模式、效能大幅提升。Spring Boot 2.x+ 可直接使用 spring-boot-starter-data-redis (底層默認 Lettuce,可切換 Jedis)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved