緩存技術(shù)在分布式中的實踐與原理(二.redis、memcached網(wǎng)絡(luò)IO模型分析)

引言

上一節(jié)簡單介紹了redis的安裝與使用,與redis一樣的緩存組件還有memcached,大體接入方式類似,這里就不重復介紹了,大家可以google具體memcached安裝以及使用方式。那么這一節(jié)將圍繞redis以及memcached兩大分布式最常用的緩存組件,對它們各自使用的網(wǎng)絡(luò)IO模型進行分析。

簡介

本篇博客主要針對redis的單線程模型,epoll事件驅(qū)動。以及memcached多線程模型,libevent事件驅(qū)動進行對比分析,了解他們各自的設(shè)計思想與應(yīng)用層的利弊。

目錄:1.redis的單線程模型

? ? ? ? ? ?2.memcached的多線程模型

正文:?

引用一段CSDN博主對于redis架構(gòu)的描述:

Redis單線程架構(gòu)

1 單線程模型(linux只有輕量級進程,ps命令也會出線程,由于博主不搞底層開發(fā),就把模擬進程稱為線程)

Redis客戶端對服務(wù)端的每次調(diào)用都經(jīng)歷了發(fā)送命令,執(zhí)行命令,返回結(jié)果三個過程。其中執(zhí)行命令階段,由于Redis是單線程來處理命令的,所有每一條到達服務(wù)端的命令不會立刻執(zhí)行,所有的命令都會進入一個隊列中,然后逐個被執(zhí)行。并且多個客戶端發(fā)送的命令的執(zhí)行順序是不確定的。但是可以確定的是不會有兩條命令被同時執(zhí)行,不會產(chǎn)生并發(fā)問題,這就是Redis的單線程基本模型。

2 單線程模型每秒萬級別處理能力的原因

(1)純內(nèi)存訪問。數(shù)據(jù)存放在內(nèi)存中,內(nèi)存的響應(yīng)時間大約是100納秒,這是Redis每秒萬級別訪問的重要基礎(chǔ)。

(2)非阻塞I/O,Redis采用epoll做為I/O多路復用技術(shù)的實現(xiàn),再加上Redis自身的事件處理模型將epoll中的連接,讀寫,關(guān)閉都轉(zhuǎn)換為了時間,不在I/O上浪費過多的時間。

(3)單線程避免了線程切換和競態(tài)產(chǎn)生的消耗。

(4)Redis采用單線程模型,每條命令執(zhí)行如果占用大量時間,會造成其他線程阻塞,對于Redis這種高性能服務(wù)是致命的,所以Redis是面向高速執(zhí)行的數(shù)據(jù)庫。

ok,看完了以上描述,我的總結(jié)是:

總體來說:

1)絕大部分請求是純粹的內(nèi)存操作(非常快速)?

2)采用單線程,避免了不必要的上下文切換和競爭條件?

3)非阻塞IO 、epoll event loop。

Redis的單線程的行為主要是對內(nèi)存的讀寫,這些操作其實用不了多少時間,因此瓶頸在網(wǎng)絡(luò)I/O上面,我們一般提供較好的網(wǎng)絡(luò)環(huán)境就可以提升Redis的吞吐量,比如提高網(wǎng)絡(luò)帶寬,除此之外還可以通過合并命令提交批處理請求(pipeline)來代替單條命令一次次請求從而減少網(wǎng)絡(luò)開銷,提高吞吐量。

我們來進一步研究redis的網(wǎng)絡(luò)模型,redis是封裝了下圖幾種多路復用器實現(xiàn)的EventLoop事件輪訓,redis沒有采用memcached采用的Libevent,Libevent為了迎合通用性造成代碼龐大及犧牲了在特定平臺的不少性能。Redis一直堅持設(shè)計小巧并去依賴庫的思路,提供Socket句柄事件的多路復用器,這部分分別對于不同平臺提供了不同的實現(xiàn),比如epoll和select可以用于linux平臺、kqueue可以用于蘋果平臺、evpoll可以用于Solaris平臺,這里并沒有看到iocp,也就是Redis對于Windows支持并不是很好。


什么是多路I/O復用?

(1) 網(wǎng)絡(luò)IO都是通過Socket實現(xiàn),Server在某一個端口持續(xù)監(jiān)聽,客戶端通過Socket(IP+Port)與服務(wù)器建立連接(ServerSocket.accept),成功建立連接之后,就可以使用Socket中封裝的InputStream和OutputStream進行IO交互了。針對每個客戶端,Server都會創(chuàng)建一個新線程專門用于處理?

(2) 默認情況下,網(wǎng)絡(luò)IO是阻塞模式,即服務(wù)器線程在數(shù)據(jù)到來之前處于【阻塞】狀態(tài),等到數(shù)據(jù)到達,會自動喚醒服務(wù)器線程,著手進行處理。阻塞模式下,一個線程只能處理一個流的IO事件?

(3) 為了提升服務(wù)器線程處理效率,有以下三種思路

(1)非阻塞【忙輪詢】:采用死循環(huán)方式輪詢每一個流,如果有IO事件就處理,這樣可以使得一個線程可以處理多個流,但是效率不高,容易導致CPU空轉(zhuǎn)

(2)Select代理(無差別輪詢):可以觀察多個流的IO事件,如果所有流都沒有IO事件,則將線程進入阻塞狀態(tài),如果有一個或多個發(fā)生了IO事件,則喚醒線程去處理。但是還是得遍歷所有的流,才能找出哪些流需要處理。

(3)Epoll代理:Select代理有一個缺點,線程在被喚醒后輪詢所有的Stream,還是存在無效操作。 Epoll會哪個流發(fā)生了怎樣的I/O事件通知處理線程,因此對這些流的操作都是有意義的。

Linux下epoll屬于IO多路復用,但他實際應(yīng)用必須搭配no-blocking io ,執(zhí)行epoll和具體業(yè)務(wù)都是在同個主進程中執(zhí)行。雖然純內(nèi)存的業(yè)務(wù)操作很快,但在執(zhí)行業(yè)務(wù)時,有新的請求到來那么kernel中發(fā)現(xiàn)readylist正在被使用時,會把就緒事件放在ovflist中當處理完readylist后,會檢查ovflist是否有事件。

首先,Redis服務(wù)器中有兩類事件,文件事件和時間事件。

文件事件(file event):Redis客戶端通過socket與Redis服務(wù)器連接,而文件事件就是服務(wù)器對套接字操作的抽象。例如,客戶端發(fā)了一個GET命令請求,對于Redis服務(wù)器來說就是一個文件事件。

時間事件(time event):服務(wù)器定時或周期性執(zhí)行的事件。例如,定期執(zhí)行RDB持久化。

在這里我們主要關(guān)注Redis處理文件事件的模型:Reactor模型


Handles?:表示操作系統(tǒng)管理的資源,我們可以理解為fd。

Synchronous Event Demultiplexer?:同步事件分離器,阻塞等待Handles中的事件發(fā)生。

Initiation Dispatcher?:初始分派器,作用為添加Event handler(事件處理器)、刪除Event handler以及分派事件給Event handler。也就是說,Synchronous Event Demultiplexer負責等待新事件發(fā)生,事件發(fā)生時通知Initiation Dispatcher,然后Initiation Dispatcher調(diào)用event handler處理事件。

Event Handler?:事件處理器的接口

Concrete Event Handler?:事件處理器的實際實現(xiàn),而且綁定了一個Handle。因為在實際情況中,我們往往不止一種事件處理器,因此這里將事件處理器接口和實現(xiàn)分開,與C++、Java這些高級語言中的多態(tài)類似。


2.memcached網(wǎng)絡(luò)IO模型


Memcached是多線程,非阻塞IO復用的網(wǎng)絡(luò)模型,分為監(jiān)聽主線程和worker子線程,監(jiān)聽線程監(jiān)聽網(wǎng)絡(luò)連接,接受請求后,將連接描述字pipe 傳遞給worker線程,進行讀寫IO, 網(wǎng)絡(luò)層使用libevent封裝的事件庫,多線程模型可以發(fā)揮多核作用,但是引入了cache coherency和鎖的問題,比如,Memcached最常用的stats 命令,實際Memcached所有操作都要對這個全局變量加鎖,進行計數(shù)等工作,帶來了性能損耗。

Libevent應(yīng)該算是包含了上述一些功能,總體來說也是走事件驅(qū)動+no blocking io。會有一個fd和event的mapping關(guān)系,至于linux內(nèi)核對于喚醒的細節(jié)就沒有多研究了,那總體對比下來,io層面的話,redis有單線程的優(yōu)勢、批量pipeline的優(yōu)勢,memcached有多核優(yōu)勢,但是多了一些同步的損耗,但是在內(nèi)存管理方面以及集群方面,redis是動態(tài)分配,memcached是分配比較固定的chunk,那對于某些字節(jié)比chunk小的情況,就有浪費的空間,集群方面memcached服務(wù)端是沒有分布式的,redis在3.0提供了cluster,這個后續(xù)討論,具體性能對比還需要區(qū)分數(shù)據(jù)量 數(shù)據(jù)格式 集群方案等,下篇文章主要分析兩者在內(nèi)存管理上的區(qū)別。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容