【賞碼會】Redis的最佳拍檔:Jedis

Jedis簡介

做爲Redis官方推薦的三個Java Client之一,Jedis推出時間最先,使用最爲普遍(Spring默認使用的Redis Client就是Jedis),同時Star數也遙遙領先於另外兩個。和其餘Redis Client同樣,Jedis經過RESP協議向Redis發送命令請求和解析響應數據。java

源碼賞析

最新版本的Jedis代碼行數超過18K,和Redis自己(20K)處於同一規模。面對如此龐大的項目,分模塊閱讀是必然之選。因爲類的數量太多,本文只在類層面進行簡單解讀,不會涉及具體的源代碼。值得一提的是,雖然Jedis的代碼稱不上規範,好比全局缺註釋、某些類的長度過長,但因爲絕大多數方法都很簡短,加上清晰的命名和完善的單元測試,代碼可讀性並無太大影響。git

Core: 核心模塊,實現RESP協議

  • Jedis/BinaryJedis: 入口類,封裝Redis的各類命令。github

  • Client/BinaryClient/Connection: 與Redis進行具體的交互工做。redis

  • Protocol, RedisInputStream, RedisOutputStream: 實現RESP協議。算法

Sharding: 提供Partitioning支持

  • ShardedJedis/BinaryShardedJedis: 首先對傳入的Key進行Hash計算(默認使用高性能、低碰撞率的MurmurHash算法),而後根據計算結果找到相應的Jedis實例,最後執行命令。apache

Pool: 提供鏈接池和Sentinel支持

  • JedisPool: 基於Apache Commons Pool實現的鏈接池,經過JedisFactory獲取Jedis實例。緩存

  • JedisSentinelPool: 經過偵聽"switch-master"事件,每當master切換時,調用JedisFactory從新初始化master鏈接信息。安全

  • ShardedJedisPool: 與JedisPool相似,經過ShardedJedisFactory獲取ShardedJedis實例。工具

Pipeline: 提供Pipelining事務支持

  • Pipeline: 經過Jedis#pipelined()獲取實例。以類型安全的方式獲取執行結果,經過BuilderFactory將Object類型的Response轉化爲指望的結果類型。性能

    • 非事務模式:構建Response Queue,而後經過Client#getMany()批量獲取結果。

    • 事務模式:經過MultiResponseBuilder緩存Response,而後批量獲取結果。

  • Transaction: 經過Jedis#multi()獲取實例。自然的事務屬性,經過Client#getMany()批量獲取結果,但沒法獲取單條命令的結果,且類型非安全。

  • ShardedJedisPipeline: ShardedJedis#pipelined()獲取實例。不一樣於Pipeline和Transaction,因爲請求可能落到多個Client上,只能經過Client#getOne()挨個獲取結果,類型非安全。

Cluster: 提供Cluster支持

  • JedisCluster/BinaryJedisCluster: 經過JedisClusterConnectionHandler獲取Jedis實例,而後執行命令。

  • JedisClusterConnectionHandler & JedisClusterInfoCache: 經過Collections#shuffle()隨機返回一個Jedis實例。使用ReentrantReadWriteLock保證更新Cluster的Jedis實例列表時的線程安全性。

  • JedisClusterCommand: 經過retry機制獲取有效的Jedis實例,而後再執行命令。

解惑

Q1:爲何有那麼多的Binary*類(BinaryJedis, BinaryClient, BinaryShardedJedis, BinaryJedisCluster),它們看上去跟非Binary的子類差很少啊?

A: Binary的父類與非Binary的子類表面的區別是不論是key,仍是value,只要涉及字符串語義的參數,前者都用byte[]類型傳參,然後者使用String類型。而深層次的緣由,我認爲跟RESP協議有關,RESP協議是面向字節的協議,對於性能要求極高的場景,使用Binary類有助於提升性能(由於減小了一次String到byte[]的轉換)。

Q2:Pipeline, Transaction以及普通的Jedis有何關聯?

A: 簡單來講,Pipeline和Transaction是批處理運行模式,一次獲取多條命令的執行結果,而Jedis只能一條一條獲取。而Pipeline和Transaction的區別主要有兩點:1)Pipeline同時支持事務模式和非事務模式,而Transaction支持事務模式。2)Pipeline類型安全,Transaction類型非安全。

漫談

上面提到Jedis的代碼規模很大,進一步分析排名靠前的幾個大類,能夠發現兩個明顯的特色:

  1. 方法不少,最多的一個類有250+方法,直接結果就是致使類的長度也很長(3000+)

  2. 大多數方法實現不超過5行,而且聽從同一結構

單從縮減代碼行數的角度來看,至少能夠考慮兩種方式:

  1. 使用代碼生成工具自動生成享有同一結構的方法

  2. 使用Java 8引入的Functional Interface簡化代碼

傳送門

相關文章
相關標籤/搜索