Redis阻塞操作實現原理(轉)


原文:https://www.jianshu.com/p/xsMzfn

作者:Haiger

最近一位朋友問到:既然Redis是單線程的工作模式,那像BLPOP這樣的阻塞操作又是然后實現的呢?

接下來分別從服務端和客戶端來闡述這一邏輯的實現原理。

Redis Server:
redis實現了一套事件觸發模型,主要處理兩種事件:I/O事件(文件事件)和定時事件。而處理它們的就靠一個EventLoop線程。同時redis還提供了豐富的數據結構,今天我們要分析的主要是List數據結構中的阻塞命令。
先來看看BLPOP的源碼(做了精簡,只看主要的部分,詳細的可以看文尾提供的參考鏈接):
t_list.c

 

上面代碼表明:如果客戶端發來一個blpop key命令,redis先找到對應的key的list,如果list不為空則pop一個數據返回給客戶端;如果對應的list不存在或者里面沒有數據,就將該key添加到一個blockling_keys的字典中,value就是想訂閱該key的client鏈表。此時對應的client的為block狀態,且i/o channel里面沒有寫入數據。

 

既然是list數據結構,當然有push數據的操作:
同樣是t_list.c

 

 

 

上面代碼表明:如果客戶端發來一個rpush key value命令,先從blocking_keys中查找是否存在對應的key,如果存在就往ready_keys這個鏈表中添加該key;同時將value插入到對應的list中,並響應客戶端。

從上面的分析來看,主要是blocking_keys和ready_keys的作用,那何時才會處理它們呢? 我們知道redis全靠EventLoop來處理所以的I/O事件,我們來看看所以命令的處理入口:
redis.c

 

 

 

上面代碼表明:每次處理完客戶端命令后都會遍歷ready_keys,並通過blocking_keys找到對應的client,依次將對應list的數據pop出來並響應對應的client;同時檢查是否需要再次block。

 

這樣一來整個流程就清晰了。redis就是通過blocking_keys和ready_keys兩個數據結構來實現的阻塞操作。但整個阻塞並沒有阻塞EventLoop本身,從而實現命令的快速響應。算是一個典型的空間換時間的設計思路。

 

接下來再看看客戶端如何實現一個阻塞的I/O請求。
Client:
這里我們分兩種I/O模型來闡述:阻塞I/O(BIO)和非阻塞I/O(NIO)。
BIO,以Jedis為例。
BinaryJedis.java

 

可以看出一個blpop請求會向redis發起兩次I/O請求,一次向redis發送BLPOP key命令,一次從對應的鏈接管道(channel)中讀取數據。由於BIO的特性當channel中沒有數據時會一直阻塞,直到有新數據為止。這樣就實現了客戶端的阻塞效果。
注意:這里的鏈接是被獨享的,不然會有數據干擾。

 

NIO的實現就稍微復雜一些,這里分兩種情況(以netty為例):
不帶RquestID的實現方式
偽代碼如下:

 

 

由於NIO的特性read和write是兩個I/O事件,要分別等待selector來觸發,所以不能像BIO那樣連續發起兩次I/O操作。再加上沒有requesID,當read到數據時無法找到之前對應的發起者,所以這里的鏈接也必須是獨享的,同時由一個只能包含一個元素的阻塞隊列LinkedBlockingQueue來實現阻塞的效果。

帶RequestID的實現方式
偽代碼如下:

 

這里因為reqeust和response數據結構里都有帶上了requestId,並且在鏈接對象上緩存了requestId和響應future的對應關系,因此鏈接可以不用獨享。

到處,整個阻塞的實現原理分析完畢。

參考鏈接:
帶注解的redis源碼:
https://github.com/huangz1990/annotated_redis_source/blob/unstable/src/t_list.c https://github.com/huangz1990/annotated_redis_source/blob/unstable/src/redis.c
IO - 同步,異步,阻塞,非阻塞 (亡羊補牢篇)
http://blog.csdn.net/historyasamirror/article/details/5778378


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM