比Redis還快5倍的中間件,為啥這么快?

今天給大家介紹的是KeyDB幢踏,KeyDB項(xiàng)目是從redis fork出來(lái)的分支。眾所周知redis是一個(gè)單線程的kv內(nèi)存存儲(chǔ)系統(tǒng)许师,而KeyDB在100%兼容redis API的情況下將redis改造成多線程房蝉。

線程模型

KeyDB將redis原來(lái)的主線程拆分成了主線程和worker線程。每個(gè)worker線程都是io線程微渠,負(fù)責(zé)監(jiān)聽(tīng)端口搭幻,accept請(qǐng)求,讀取數(shù)據(jù)和解析協(xié)議逞盆。如圖所示:

img

KeyDB使用了SO_REUSEPORT特性檀蹋,多個(gè)線程可以綁定監(jiān)聽(tīng)同個(gè)端口。

每個(gè)worker線程做了cpu綁核云芦,讀取數(shù)據(jù)也使用了SO_INCOMING_CPU特性俯逾,指定cpu接收數(shù)據(jù)。解析協(xié)議之后每個(gè)線程都會(huì)去操作內(nèi)存中的數(shù)據(jù)舅逸,由一把全局鎖來(lái)控制多線程訪問(wèn)內(nèi)存數(shù)據(jù)桌肴。主線程其實(shí)也是一個(gè)worker線程,包括了worker線程的工作內(nèi)容琉历,同時(shí)也包括只有主線程才可以完成的工作內(nèi)容识脆。在worker線程數(shù)組中下標(biāo)為0的就是主線程。

主線程的主要工作在實(shí)現(xiàn)serverCron善已,包括:

  • 處理統(tǒng)計(jì)

  • 客戶端鏈接管理

  • db數(shù)據(jù)的resize和reshard

  • 處理aof

  • replication主備同步

  • cluster模式下的任務(wù)

鏈接管理

在redis中所有鏈接管理都是在一個(gè)線程中完成的灼捂。在KeyDB的設(shè)計(jì)中,每個(gè)worker線程負(fù)責(zé)一組鏈接换团,所有的鏈接插入到本線程的鏈接列表中維護(hù)悉稠。鏈接的產(chǎn)生、工作艘包、銷(xiāo)毀必須在同個(gè)線程中的猛。每個(gè)鏈接新增一個(gè)字段

int iel; /* the event loop index we're registered with */

用來(lái)表示鏈接屬于哪個(gè)線程接管耀盗。

KeyDB維護(hù)了三個(gè)關(guān)鍵的數(shù)據(jù)結(jié)構(gòu)做鏈接管理:

  • clients_pending_write:線程專屬的鏈表,維護(hù)同步給客戶鏈接發(fā)送數(shù)據(jù)的隊(duì)列

  • clients_pending_asyncwrite:線程專屬的鏈表卦尊,維護(hù)異步給客戶鏈接發(fā)送數(shù)據(jù)的隊(duì)列

  • clients_to_close:全局鏈表叛拷,維護(hù)需要異步關(guān)閉的客戶鏈接

分成同步和異步兩個(gè)隊(duì)列,是因?yàn)閞edis有些聯(lián)動(dòng)api岂却,比如pub/sub忿薇,pub之后需要給sub的客戶端發(fā)送消息,pub執(zhí)行的線程和sub的客戶端所在線程不是同一個(gè)線程躏哩,為了處理這種情況署浩,KeyDB將需要給非本線程的客戶端發(fā)送數(shù)據(jù)維護(hù)在異步隊(duì)列中。

同步發(fā)送的邏輯比較簡(jiǎn)單扫尺,都是在本線程中完成筋栋,以下圖來(lái)說(shuō)明如何同步給客戶端發(fā)送數(shù)據(jù):

img

如上文所提到的,一個(gè)鏈接的創(chuàng)建正驻、接收數(shù)據(jù)弊攘、發(fā)送數(shù)據(jù)、釋放鏈接都必須在同個(gè)線程執(zhí)行姑曙。異步發(fā)送涉及到兩個(gè)線程之間的交互襟交。KeyDB通過(guò)管道在兩個(gè)線程中傳遞消息:

int fdCmdWrite; //寫(xiě)管道
int fdCmdRead; //讀管道

本地線程需要異步發(fā)送數(shù)據(jù)時(shí),先檢查client是否屬于本地線程渣磷,非本地線程獲取到client專屬的線程ID,之后給專屬的線程管到發(fā)送AE_ASYNC_OP::CreateFileEvent的操作授瘦,要求添加寫(xiě)socket事件醋界。專屬線程在處理管道消息時(shí)將對(duì)應(yīng)的請(qǐng)求添加到寫(xiě)事件中,如圖所示:

img

redis有些關(guān)閉客戶端的請(qǐng)求并非完全是在鏈接所在的線程執(zhí)行關(guān)閉提完,所以在這里維護(hù)了一個(gè)全局的異步關(guān)閉鏈表形纺。

img

鎖機(jī)制

KeyDB實(shí)現(xiàn)了一套類似spinlock的鎖機(jī)制,稱之為fastlock徒欣。

fastlock的主要數(shù)據(jù)結(jié)構(gòu)有:

struct ticket
 {
  uint16_t m_active; //解鎖+1
  uint16_t m_avail; //加鎖+1
 };
 struct fastlock
 {
  volatile struct ticket m_ticket;
  volatile int m_pidOwner; //當(dāng)前解鎖的線程id
  volatile int m_depth; //當(dāng)前線程重復(fù)加鎖的次數(shù)
 };

使用原子操作atomic_load_2逐样,atomic_fetch_add,__atomic_compare_exchange來(lái)通過(guò)比較m_active=m_avail判斷是否可以獲取鎖打肝。

fastlock提供了兩種獲取鎖的方式:

  • try_lock:一次獲取失敗脂新,直接返回

  • lock:忙等,每1024 * 1024次忙等后使用sched_yield 主動(dòng)交出cpu粗梭,挪到cpu的任務(wù)末尾等待執(zhí)行争便。

在KeyDB中將try_lock和事件結(jié)合起來(lái),來(lái)避免忙等的情況發(fā)生断医。每個(gè)客戶端有一個(gè)專屬的lock滞乙,在讀取客戶端數(shù)據(jù)之前會(huì)先嘗試加鎖奏纪,如果失敗,則退出斩启,因?yàn)閿?shù)據(jù)還未讀取序调,所以在下個(gè)epoll_wait處理事件循環(huán)中可以再次處理。

img

Active-Replica

KeyDB實(shí)現(xiàn)了多活的機(jī)制兔簇,每個(gè)replica可設(shè)置成可寫(xiě)非只讀发绢,replica之間互相同步數(shù)據(jù)。主要特性有:

  • 每個(gè)replica有個(gè)uuid標(biāo)志,用來(lái)去除環(huán)形復(fù)制

  • 新增加rreplay API织鲸,將增量命令打包成rreplay命令诬烹,帶上本地的uuid

  • key,value加上時(shí)間戳版本號(hào)甚纲,作為沖突校驗(yàn),如果本地有相同的key且時(shí)間戳版本號(hào)大于同步過(guò)來(lái)的數(shù)據(jù)朦前,新寫(xiě)入失敗介杆。采用當(dāng)前時(shí)間戳向左移20位,再加上后44位自增的方式來(lái)獲取key的時(shí)間戳版本號(hào)韭寸。

小編還為大家準(zhǔn)備了一套最新的零基礎(chǔ)學(xué)前端資料春哨,需要的無(wú)償自取

1、點(diǎn)贊+評(píng)論(勾選“同時(shí)轉(zhuǎn)發(fā)”)恩伺,沒(méi)有點(diǎn)贊也可以獲取哦赴背,看我的文章的都是朋友

2、給個(gè)關(guān)注不迷路晶渠。獲取方式:https://shimo.im/docs/JPRdJDVHxKJ3yQGY/ 凰荚,部分資料如下

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市褒脯,隨后出現(xiàn)的幾起案子便瑟,更是在濱河造成了極大的恐慌,老刑警劉巖番川,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件到涂,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡颁督,警方通過(guò)查閱死者的電腦和手機(jī)践啄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)沉御,“玉大人往核,你說(shuō)我怎么就攤上這事∪陆冢” “怎么了聂儒?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵虎锚,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我衩婚,道長(zhǎng)窜护,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任非春,我火速辦了婚禮柱徙,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘奇昙。我一直安慰自己护侮,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布储耐。 她就那樣靜靜地躺著羊初,像睡著了一般。 火紅的嫁衣襯著肌膚如雪什湘。 梳的紋絲不亂的頭發(fā)上长赞,一...
    開(kāi)封第一講書(shū)人閱讀 49,046評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音闽撤,去河邊找鬼得哆。 笑死,一個(gè)胖子當(dāng)著我的面吹牛哟旗,可吹牛的內(nèi)容都是我干的贩据。 我是一名探鬼主播,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼闸餐,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼饱亮!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起绎巨,我...
    開(kāi)封第一講書(shū)人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤近尚,失蹤者是張志新(化名)和其女友劉穎蠕啄,沒(méi)想到半個(gè)月后场勤,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡歼跟,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年和媳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哈街。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡留瞳,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出骚秦,到底是詐尸還是另有隱情她倘,我是刑警寧澤璧微,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站硬梁,受9級(jí)特大地震影響前硫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜荧止,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一屹电、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧跃巡,春花似錦危号、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至娘香,卻和暖如春苍狰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背烘绽。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工淋昭, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人安接。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓翔忽,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親盏檐。 傳聞我的和親對(duì)象是個(gè)殘疾皇子歇式,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345