嘉賓介紹
大家好魂拦,首先自我介紹一下苏携,我是360 web平臺-基礎(chǔ)架構(gòu)組的宋昭做瞪,負(fù)責(zé)大容量類redis存儲pika的和分布式存儲Bada的開發(fā)工作,這是我的github和博客地址右冻,平時歡迎指正交流^^
我的github: https://github.com/KernelMaker
我的博客: http://kernelmaker.github.io
下面是pika的github装蓬,歡迎關(guān)注
https://github.com/Qihoo360/pika
Pika介紹
pika是360 DBA和基礎(chǔ)架構(gòu)組聯(lián)合開發(fā)的類redis存儲系統(tǒng), 使用Redis協(xié)議,兼容redis絕大多數(shù)命令(String纱扭,Hash牍帚,List,ZSet乳蛾,Set)暗赶,用戶不需要修改任何代碼, 就可以將服務(wù)遷移至pika.
pika主要是使用持久化存儲來解決redis在內(nèi)存占用超過50G,80G時遇到的如啟動恢復(fù)時間長肃叶,主從同步代價大蹂随,硬件成本貴等問題,并且在對外用法上盡可能做到與redis一致因惭,用戶基本上對后端是redis或pika無感知
既然pika要做到兼容redis并解決redis在大容量時的各種問題岳锁,那么首先要面對的問題便是如何從redis遷移到pika,畢竟現(xiàn)在redis的使用非常廣泛蹦魔,如果從redis遷移到pika很麻煩激率,那應(yīng)該也不會有多少人用了
-
從redis遷移到pika需要經(jīng)過幾個步驟?
開發(fā)需要做的:
基本不用做任何事情
dba需要做的:
1.dba遷移redis數(shù)據(jù)到pika 2.dba將redis的數(shù)據(jù)實時同步到pika版姑,確保redis與pika的數(shù)據(jù)始終一致 3.dba切換lvs后端ip柱搜,由pika替換redis 注:pika提供redis_to_pika工具,通過aof來將db和實時增量數(shù)據(jù)同步到pika
遷移過程中需要停業(yè)務(wù)/業(yè)務(wù)會受到影響嗎:
不會
-
注
由于pika的數(shù)據(jù)存在硬盤上剥险,故單線程的性能肯定不如redis, 但pika使用多線程來盡可能的彌補數(shù)據(jù)讀寫性能較之redis內(nèi)存讀寫的差異, 線程數(shù)比較多的情況下, 某些數(shù)據(jù)結(jié)構(gòu)的性能會優(yōu)于redis
pika肯定不會是一個完全優(yōu)于redis的方案, 和redis相比也有弊端聪蘸,只是在某些場景下面更適合. 所以目前公司內(nèi)部redis, pika 是共同存在的方案, DBA會根據(jù)業(yè)務(wù)的場景挑選合適的方案
本次分享分成6個部分
- 背景
- 為什么做pika(大容量redis遇到的問題)
- pika架構(gòu)
- pika的創(chuàng)新及優(yōu)化
- pika的優(yōu)勢及不足
- 總結(jié)
背景
redis提供了豐富的多數(shù)據(jù)結(jié)構(gòu)的接口, 在redis之前, 比如memcache,都認(rèn)為后端只需要存儲kv的結(jié)構(gòu)就可以, 不需要感知這個value里面的內(nèi)容, 用戶需要使用的話通過json_encode
, json_decode
等形式進(jìn)行數(shù)據(jù)的讀取就行. 但是其實redis做了一個微創(chuàng)新, 提供了多數(shù)據(jù)結(jié)果的支持, 讓服務(wù)端寫代碼起來更加的方便了
因此redis在公司的使用率也是越來越廣泛, 用戶不知不覺把越來越多的數(shù)據(jù)存儲在redis中, 隨著用戶的使用, DBA發(fā)現(xiàn)有些redis實例的大小也是越來越大, 發(fā)現(xiàn)在redis實例內(nèi)存使用比較大的情況下, 遇到的問題也會越來越多, 因此和我們一起實現(xiàn)了大容量redis的解決方案
最近半年公司每天redis 的訪問情況
redis 架構(gòu)方案
為什么做pika(大容量redis遇到的問題)
- 恢復(fù)時間長
我們線上的redis一般同時開啟rdb和aof. 我們知道aof的作用是實時的記錄用戶的寫入操作, rdb是redis某一時刻數(shù)據(jù)的完整快照. 那么恢復(fù)的時候一般是通過rdb+aof的方式進(jìn)行恢復(fù), 根據(jù)我們線上的情況50G redis恢復(fù)時間需要差不多40~70分鐘(取決于服務(wù)器性能)
- 一主多從, 主從切換代價大
redis在主庫掛掉以后, 從庫升級為新的主庫. 那么切換主庫以后, 所有的從庫都需要跟新主做一次全同步, 代價非常大
- 緩沖區(qū)寫滿問題
為了實現(xiàn)部分同步,redis使用了repl_backlog
來緩存部分同步命令健爬,repl_backlog
默認(rèn)1M控乾。 當(dāng)主從之間網(wǎng)絡(luò)有故障, 同步出現(xiàn)延遲了大于1M以后, slave丟失了master的同步點,就會觸發(fā)全同步的過程. 如果多個從庫同時觸發(fā)全同步的過程, 在全同步的過程中娜遵,redis會將同步點之后的增量請求給每一個slave緩存一份蜕衡,在寫入量大的情況下很容易就將主庫給拖死,當(dāng)然你也可以把repl_backlog
調(diào)大來緩解设拟,比如2G慨仿,不過對全內(nèi)存的redis而言,這2G的內(nèi)存代價也不小
- 內(nèi)存太貴
我們一般線上使用的redis機器是64G, 96G. 我們只會使用80%的空間.
如果一個redis的實例是50G, 那么基本一臺機器只能運行一個redis實例. 因此特別的浪費資源
總結(jié): 可以看到在redis比較小的情況下, 這些問題都不是問題, 但是當(dāng)redis容量上去以后. 很多操作需要的時間也就越來越長了
pika 整體架構(gòu)
主要組成:
1. 網(wǎng)絡(luò)模塊 pink
2. 線程模型
3. 存儲引擎 nemo
4. 日志模塊 binlog
5. 主從同步模塊
pink 網(wǎng)絡(luò)模塊
* 基礎(chǔ)架構(gòu)團(tuán)隊開發(fā)網(wǎng)絡(luò)編程框架, 支持pb, redis等等協(xié)議. 提供了對thread的封裝, 用戶定義不同thread的行為, 使用更加清晰
* 支持單線程模型, 多線程worker模型
* github 地址: https://github.com/baotiao/pink
線程模型
pika使用的是多線程模型纳胧,使用多個工作線程來進(jìn)行讀寫操作镰吆,線程分為11種:
PikaServer:主線程
DispatchThread:監(jiān)聽端口1個端口,接收用戶連接請求
ClientWorker:存在多個(用戶配置)跑慕,每個線程里有若干個用戶客戶端的連接万皿,負(fù)責(zé)接收處理用戶命令并返回結(jié)果,每個線程執(zhí)行寫命令后核行,追加到binlog中
Trysync:嘗試與master建立首次連接牢硅,并在以后出現(xiàn)故障后發(fā)起重連
ReplicaSender:存在多個(動態(tài)創(chuàng)建銷毀,本master節(jié)點掛多少個slave節(jié)點就有多少個)芝雪,每個線程根據(jù)slave節(jié)點發(fā)來的同步偏移量减余,從binlog指定的偏移開始實時同步命令給slave節(jié)點
ReplicaReceiver:存在1個(動態(tài)創(chuàng)建銷毀,一個slave節(jié)點同時只能有一個master)惩系,將用戶指定或當(dāng)前的偏移量發(fā)送給master節(jié)點并開始接收master實時發(fā)來的同步命令佳励,在本地使用和master完全一致的偏移量來追加binlog,然后分發(fā)給多個BinlogBGWorker中的一個來執(zhí)行
BinlogBGWorker:存在多個(用戶配置)蛆挫,ReplicaReceiver將命令按key取hash分配給其中的一個BinlogBGWorker,它負(fù)責(zé)真正執(zhí)行命令
SlavePing:slave用來向master發(fā)送心跳進(jìn)行存活檢測
HeartBeat:master用來接收所有slave發(fā)送來的心跳并回復(fù)進(jìn)行存活檢測
bgsave:后臺dump線程
scan:后臺掃描keyspace線程
purge:后臺刪除binlog線程
存儲引擎 nemo
pika的存儲引擎是基于Rocksdb實現(xiàn)的. 封裝了String妙黍,Hash, List, ZSet, Set等數(shù)據(jù)結(jié)構(gòu)
我們知道redis是需要支持多數(shù)據(jù)結(jié)構(gòu)的, 而rocksdb只是一個kv的接口, 那么我們?nèi)绾螌崿F(xiàn)的呢?
比如對于Hash數(shù)據(jù)結(jié)構(gòu):
對于每一個Hash存儲悴侵,它包括hash鍵(key),hash鍵下的域名(field)和存儲的值 (value).
nemo的存儲方式是將key和field組合成為一個新的key拭嫁,將這個新生成的key與所要存儲的value組成最終落盤的kv鍵值對可免。同時,對于每一個hash鍵做粤,nemo還為它添加了一個存儲元信息的落盤kv浇借,它保存的是對應(yīng)hash鍵下的所有域值對的個數(shù)。
每個hash鍵怕品、field妇垢、value到落盤kv的映射轉(zhuǎn)換
每個hash鍵的元信息的落盤kv的存儲格式
比如對于List 數(shù)據(jù)結(jié)構(gòu):
顧名思義,每個List結(jié)構(gòu)的底層存儲也是采用鏈表結(jié)構(gòu)來完成的。對于每個List鍵闯估,它的每個元素都落盤為一個kv鍵值對灼舍,作為一個鏈表的一個節(jié)點,稱為元素節(jié)點涨薪。和hash一樣骑素,每個List鍵也擁有自己的元信息。
每個元素節(jié)點對應(yīng)的落盤kv存儲格式
每個元信息的落盤kv的存儲格式
其他的數(shù)據(jù)結(jié)構(gòu)實現(xiàn)的方式也類似, 通過將數(shù)據(jù)結(jié)構(gòu)拆分為一個個獨立的KV, 存儲到rocksdb 里面去. 從而實現(xiàn)多數(shù)據(jù)結(jié)構(gòu)的結(jié)構(gòu)
日志模塊 binlog
pika的主從同步是使用Binlog來完成的.
binlog 本質(zhì)是順序?qū)懳募? 通過Index + offset 進(jìn)行同步點檢查.
解決了同步緩沖區(qū)太小的問題
支持全同步 + 增量同步
master執(zhí)行完一條寫命令就將命令追加到Binlog中刚夺,ReplicaSender將這條命令從Binlog中讀出來發(fā)送給slave献丑,slave的ReplicaReceiver收到該命令,執(zhí)行侠姑,并追加到自己的Binlog中.
當(dāng)發(fā)生網(wǎng)絡(luò)閃斷或slave掛掉重啟時, slave僅需要將自己當(dāng)前的Binlog Index + offset 發(fā)送給master创橄,master找到后從該偏移量開始同步后續(xù)命令
為了防止讀文件中寫錯一個字節(jié)則導(dǎo)致整個文件不可用,所以pika采用了類似leveldb log的格式來進(jìn)行存儲结借,具體如下:
主從同步模塊
上圖是一個主從同步的一個過程(即根據(jù)主節(jié)點數(shù)據(jù)庫的操作日志筐摘,將主節(jié)點數(shù)據(jù)庫的改動同步到從節(jié)點的數(shù)據(jù)庫上),從圖中可以看出船老,每一個從節(jié)點在主節(jié)點下都有一個唯一對應(yīng)的BinlogSenderThread
主要模塊:
WorkerThread:接受和處理用戶的命令咖熟;
BinlogSenderThread:負(fù)責(zé)順序地向?qū)?yīng)的從節(jié)點發(fā)送在需要同步的命令;
BinlogReceiverModule: 負(fù)責(zé)接受主節(jié)點發(fā)送過來的同步命令
Binglog:用于順序的記錄需要同步的命令
主要的工作過程:
1.當(dāng)WorkerThread接收到客戶端的命令柳畔,按照執(zhí)行順序馍管,添加到Binlog里;
2.BinglogSenderThread判斷它所負(fù)責(zé)的從節(jié)點在主節(jié)點的Binlog里是否有需要同步的命令薪韩,若有則發(fā)送給從節(jié)點确沸;
3.BinglogReceiverModule模塊則做以下三件事情:
a. 接收主節(jié)點的BinlogSenderThread發(fā)送過來的同步命令;
b. 把接收到的命令應(yīng)用到本地的數(shù)據(jù)上俘陷;
c. 把接收到的命令添加到本地Binlog里
至此罗捎,一條命令從主節(jié)點到從節(jié)點的同步過程完成
BinLogReceiverModule的工作過程:
上圖是BinLogReceiverModule的組成,從圖中可以看出BinlogReceiverModule由一個BinlogReceiverThread和多個BinlogBGWorker組成拉盾。
BinlogReceiverThread:負(fù)責(zé)接受由主節(jié)點傳送過來的命令桨菜,并分發(fā)給各個BinlogBGWorker,若當(dāng)前的節(jié)點是只讀狀態(tài)(不能接受客戶端的同步命令)捉偏,則在這個階段寫B(tài)inlog
BinlogBGWorker:負(fù)責(zé)執(zhí)行同步命令倒得;若該節(jié)點不是只讀狀態(tài)(還能接受客戶端的同步命令),則在這個階段寫B(tài)inlog(在命令執(zhí)行之前寫)
BinlogReceiverThread接收到一個同步命令后夭禽,它會給這個命令賦予一個唯一的序列號(這個序列號是遞增的)霞掺,并把它分發(fā)給一個BinlogBGWorker;而各個BinlogBGWorker則會根據(jù)各個命令的所對應(yīng)的序列號的順序來執(zhí)行各個命令讹躯,這樣也就保證了命令執(zhí)行的順序和主節(jié)點執(zhí)行的順序一致了
之所以這么設(shè)計主要原因是:
配備多個BinlogBGWorker是可以提高主從同步的效率菩彬,減少主從同步的滯后延遲缠劝;
讓BinlogBGWorker在執(zhí)行執(zhí)行之前寫B(tài)inlog可以提高命令執(zhí)行的并行度;
在當(dāng)前節(jié)點是非只讀狀態(tài)挤巡,讓BinglogReceiverThread來寫B(tài)inlog剩彬,是為了讓Binglog里保存的命令順序和命令的執(zhí)行順序保持一致;
綜上所述矿卑,正是因為這樣的架構(gòu)及實現(xiàn)喉恋,pika可以較好的解決上面說到redis在大數(shù)據(jù)量下的不足:
恢復(fù)時間長
pika的存儲引擎是nemo, nemo使用的是rocksdb, rocksdb啟動不需要加載全部數(shù)據(jù), 只需要加載recover log文件就可以啟動, 因此恢復(fù)時間非常快一主多從, 主從切換代價大
在主從切換的時候, 新主確定以后, 從庫會用當(dāng)前的偏移量嘗試與新主做一次部分同步, 如果部分同步不成功才做全同步. 這樣盡可能的減少全同步次數(shù)緩沖區(qū)寫滿問題
pika不是用內(nèi)存buffer進(jìn)行同步數(shù)據(jù)的緩存, 而是記錄在本地的binlog上, binlog的大小可配母廷,遠(yuǎn)遠(yuǎn)大于內(nèi)存可以使用的上限轻黑,因此不會出現(xiàn)把緩沖區(qū)寫滿的問題,減少無用的全同步次數(shù)內(nèi)存昂貴問題
pika的存儲引擎nemo使用的是rocksdb, rocksdb同時使用內(nèi)存和磁盤減少對內(nèi)存的依賴. 同時我們盡可能使用SSD盤來存放數(shù)據(jù), 盡可能跟上redis的性能.
pika的創(chuàng)新及優(yōu)化
多數(shù)據(jù)結(jié)構(gòu)key的快速刪除
以Hash為例琴昆,redis一個Hash key可能包含百萬或者千萬的field氓鄙,對于Hash key的刪除,redis首先從db dict中刪除掉這個key业舍,然后立刻返回抖拦,該key對應(yīng)的hash空間采用惰性的方式來慢慢回收,而我們知道舷暮,pika的是將Hash結(jié)構(gòu)轉(zhuǎn)換成一個個KV來存儲的态罪,刪除一個Hash Key就等于要刪除其對應(yīng)的千萬field,此時用戶的一個del操作等價于引擎千萬次的del操作下面,當(dāng)初做的時候我們有如下考量:
Solution 1:阻塞刪除复颈,這也是目前其他類似Pika項目的主要解決方案,直到把Hash key對應(yīng)的所有field key全部刪除才返回給用戶
優(yōu)點:易實現(xiàn)
缺點:阻塞處理沥割,影響服務(wù)
Solution 2:刪除meta key之后立刻返回耗啦,其他的field key后臺起線程慢慢刪除
優(yōu)點:速度快
缺點:使用場景受限,如果用戶刪除某個Hash key之后又立刻插入這個key机杜,則此時還未刪除的field key會被無當(dāng)做新key的一部分帜讲,出錯
上述兩種方案皆不可行,我們最終在rocksdb上做了改動椒拗,使它支持多數(shù)據(jù)結(jié)構(gòu)版本的概念
最終解決方案:
Hash Key的元信息增加版本舒帮,表示當(dāng)前key的有效版本;
操作:
Put:查詢元信息陡叠,獲得key的最新版本,后綴到val肢执;
Get:查詢元信息枉阵,獲得key的最新版本,過濾低版本的數(shù)據(jù)预茄;
Del:key的元信息版本號+1即可兴溜;
Iterator: 迭代時侦厚,查詢key的版本,過濾舊版本數(shù)據(jù)拙徽;
Compact:數(shù)據(jù)的實際刪除是在Compact過程中刨沦,根據(jù)版本信息過濾;
通過對rocksdb的修改膘怕,pika實現(xiàn)了對多數(shù)據(jù)結(jié)構(gòu)key的秒刪功能想诅,并且將真正的刪除操作交給了compact來減少顯示調(diào)用引擎del造成的多次操作(插入del record及compact)
快照式備份
不同于Redis,Pika的數(shù)據(jù)主要存儲在磁盤中岛心,這就使得其在做數(shù)據(jù)備份時有天然的優(yōu)勢来破,可以直接通過文件拷貝實現(xiàn)
流程:
打快照:阻寫,并在這個過程中或的快照內(nèi)容
異步線程拷貝文件:通過修改Rocksdb提供的BackupEngine拷貝快照中文件忘古,這個過程中會阻止文件的刪除
這樣的備份速度基本等同于cp的速度徘禁,降低了備份的代價
后續(xù)優(yōu)化:不過目前pika正在嘗試使用硬鏈建立checkpoint來實現(xiàn)數(shù)據(jù)的更快備份(秒級),并且減少備份數(shù)據(jù)的空間占用(從之前的2倍優(yōu)化到不到2倍)髓堪,更好的支持超大容量存儲
過期支持
redis的過期是通過將需要過期的key在多存一份送朱,記錄它的過期時間,然后每次讀取時進(jìn)行比較來完成的干旁,這樣的實現(xiàn)簡單驶沼,但基于內(nèi)存的讀寫都很快不會有性能問題,目前其他類似pika的開源項目也采用這樣的方式疤孕,將過期key在db多存一份商乎,不過不同于redis,這些項目的db也是落盤祭阀,采用這樣簡單粗暴的方式無形中又多了一次磁盤讀鹉戚,影響效率,那么pika是如何解決的呢专控?
pika通過給修改rocksdb Set抹凳、Get接口并且新增compact filter,給每個value增加ttl后綴伦腐,并且在Get的時候來進(jìn)行過濾赢底,將真正的過期刪除交給compact(基于ttl來Drop),在磁盤大容量的前提下柏蘑,使用額外空間來減少磁盤讀取次數(shù)幸冻,提高效率
空間回收
rocksdb 默認(rèn)的compact 策略是在寫放大, 讀放大, 空間放大的權(quán)衡. 那么DBA同學(xué)當(dāng)然希望盡可能減少空間的使用, 因此DBA希望能夠隨時觸發(fā)compact, 而又盡可能的不影響線上的使用, 而rocksdb 默認(rèn)的手動compact 策略是最高優(yōu)先級的, 會阻塞線上的正常流程的合并, 因此我們修改了rocksdb compact的部分邏輯,低優(yōu)先級手動compact優(yōu)先級咳焚,使得自動compact可以打斷手動compact洽损,來避免level 0文件數(shù)量過多而造成的rocksdb主動停寫. pika支持DBA隨時compact
方便的運維
pika較之其他類似開源項目,還有一個優(yōu)勢就是它可以方便的運維革半,例如
1. pika的binlog可以配置按個數(shù)或者按天來刪除碑定,提供工具來支持不用再啟實例來進(jìn)行指定節(jié)點binlog的實時備份流码,支持binlog恢復(fù)數(shù)據(jù)到指定某一秒(正在做)
2. 支持info命令來查看后臺任務(wù)的執(zhí)行狀態(tài)(bgsave,purgelogs延刘,keyscan)
3. 支持monitor
4. 支持通過redis aof和monitor來遷移數(shù)據(jù)
5. 支持config set來動態(tài)修改配置項
6. 支持多用戶(admin及普通用戶)及命令黑名單漫试,可以禁止掉不想讓普通用戶使用的命令
7. 支持不活躍客戶端的自動刪除,支持慢日志碘赖,client kill all驾荣,readonly開關(guān)
8. 支持快照式備份及手動compact
9. 等等...
pika在追求盡可能高的性能及穩(wěn)定性的同時,還注重使用者的使用體驗崖疤,一個產(chǎn)品即使擁有再給力的性能如果不可運維我想也不會有人想用秘车,所以pika會不斷發(fā)現(xiàn)并解決使用上的問題,使得它更好用
pika的優(yōu)勢及不足
pika相對于redis劫哼,最大的不同就是pika是持久化存儲叮趴,數(shù)據(jù)存在磁盤上,而redis是內(nèi)存存儲权烧,由此不同也給pika帶來了相對于redis的優(yōu)勢和劣勢
優(yōu)勢:
- 容量大:Pika沒有Redis的內(nèi)存限制, 最大使用空間等于磁盤空間的大小
- 加載db速度快:Pika 在寫入的時候, 數(shù)據(jù)是落盤的, 所以即使節(jié)點掛了, 不需要rdb或者aof眯亦,pika 重啟不用重新加載數(shù)據(jù)到內(nèi)存而是直接使用已經(jīng)持久化在磁盤上的數(shù)據(jù), 不需要任何數(shù)據(jù)回放操作(除去少量rocksdb自身的recover),這大大降低了重啟成本般码。
- 備份速度快:Pika備份的速度大致等同于cp的速度(拷貝數(shù)據(jù)文件后還有一個快照的恢復(fù)過程妻率,會花費一些時間),目前已經(jīng)開發(fā)完更快更省空間的秒級備份板祝,即將投入使用宫静,這樣在對于百G大庫的備份是快捷的,更快的備份速度更好的解決了主從的全同步問題
劣勢:
由于Pika是基于內(nèi)存和文件來存放數(shù)據(jù), 所以性能肯定比Redis低一些, 但是我們一般使用SSD盤來存放數(shù)據(jù), 盡可能跟上Redis的性能券时。
總結(jié)
如果用戶的業(yè)務(wù)場景數(shù)據(jù)比較大孤里,Redis會出現(xiàn)上面說到的那些問題,如果這些問題對用戶來說不可容忍橘洞,那么可以考慮使用pika捌袜。
我們對pika整體進(jìn)行了性能測試,結(jié)果如下:
服務(wù)端配置:
處理器:24核 Intel(R) Xeon(R) CPU E5-2630 v2 @ 2.60GHz
內(nèi)存:165157944 kB
操作系統(tǒng):CentOS release 6.2 (Final)
網(wǎng)卡:Intel Corporation I350 Gigabit Network Connection
客戶端配置:
同服務(wù)端
測試結(jié)果:
pika配置18個worker炸枣,用40個客戶端虏等;
1. 寫性能:
方法:客戶端依次執(zhí)行set、hset适肠、lpush霍衫、zadd、sadd接口寫入數(shù)據(jù)侯养,每個數(shù)據(jù)結(jié)構(gòu)10000個key敦跌;
結(jié)果:qps 110000
2. 讀性能:
方法:客戶端一次執(zhí)行g(shù)et、hget沸毁、lindex峰髓、zscore、smembers息尺,每個數(shù)據(jù)結(jié)構(gòu)5000000個key携兵;
結(jié)果:qps 170000
單數(shù)據(jù)結(jié)構(gòu)性能用戶可以依據(jù)自己的需求來測試,數(shù)據(jù)結(jié)構(gòu)間的性能比較大致是:
String > Hash = Set > ZSet > List
在實際使用中搂誉,大多數(shù)場景下pika的性能大約是Redis的50%~80%徐紧,在某些特定場景下,例如range 500炭懊,pika的性能只有redis的20%并级,針對這些場景我們?nèi)匀辉诟倪M(jìn)
在360內(nèi)部使用情況:
粗略的統(tǒng)計如下:
實例數(shù)160個
當(dāng)前每天承載的總請求量超過100億
當(dāng)前承載的數(shù)據(jù)總量約3TB
wiki
github 地址:
https://github.com/Qihoo360/pika
github wiki:
https://github.com/Qihoo360/pika/wiki/pika介紹
Q&A
Q1:元信息是跟key一起存儲的嗎?
A1:是的
Q2:快照的生成依賴于什么侮腹?會阻塞讀寫嗎嘲碧?
A2:快照是后臺生成的,阻塞的地方只是在最開始取當(dāng)前db狀態(tài)和同步點信息的時候父阻,非常短
Q3:為什么能做到基本上不阻塞愈涩?
A3:因為pika的數(shù)據(jù)本來就是存在磁盤上的,備份就等同于文件拷貝.只要在拷貝前計算一下該拷貝那些文件加矛,然后就可以后臺搞了
Q4:看hashset的實現(xiàn)履婉,只記錄那些信息,是怎么處理hgetall的
A4:比如hash有5個field斟览,那么在pika存儲毁腿,除了元信息之外,真正數(shù)據(jù)是這么存的:key+field1 -> value1苛茂,key+field2-> value2等等已烤,在hgetall的時候,只需要通過rocksdb的iterator味悄,seek到key草戈,然后迭代便可取出所有的field了
Q5:當(dāng)存儲超過SSD空間后,怎么擴容呢?
A5: pika受制于底下引擎的限制注整,不支持?jǐn)U容抛寝,如果連ssd都不夠用了,就只能靠掛lvm來解決了
Q6:那新的數(shù)據(jù)如何融合到db里
A6:只需要給新的實例啟動前费韭,配置文件db路徑為備份的目錄,然后啟動新實例即可
Q7:依賴于rocksdb_backup機制庭瑰?
A7:是的星持,目前是基于rocksdb_backup做的,不過我們最新的秒備份已經(jīng)差不多做完了弹灭,可以直接通過硬鏈接省去文件的拷貝督暂,以達(dá)到更快的備份速度及更少的空間占用
Q8:dispatch 和 clientWorker 這種生產(chǎn)者消費者模型對性能的影響揪垄。
A8:clientworker之間是互不影響的,dispatch在把某個連接分配給其中一個worker時僅與worker有極小概率的沖突(dispatch已分發(fā)完一輪連接逻翁,又回到這個worker饥努,并且該worker此時也在操作自己的任務(wù)隊列),這樣的模型是比較通用的做法(與MC類似)八回,性能瓶頸不會出現(xiàn)在這里
Q9:對hash類型的讀取酷愧、修改、增加缠诅、刪除任意部分field的過程及性能溶浴。
A9:性能比string接口稍有下降,因為多了一個元信息的讀寫管引,過程的話無非就是先讀元信息士败,在讀寫真正的數(shù)據(jù)等等,說起來比較多汉匙,感興趣的話可以下來交流^^
Q10:binlog有對操作做可重入處理嗎
A10:binlog里記錄的就是用戶發(fā)來的redis命令拱烁,所以不是冪等的
Q11:存放元數(shù)據(jù)的那個key如何不成為瓶頸
A11: 這樣的設(shè)計元信息的key的確會成為瓶頸,不過對于比較熱的元數(shù)據(jù)key噩翠,頻繁更新會讓他駐留在rocksdb的memtable中戏自,這樣可以彌補一下讀寫性能
Q12:請問講師使用的是redis cluster嗎?為何只有一個master并且50g那么大伤锚?在截圖那個qps下擅笔,會遇到什么瓶頸?
A12: 目前在公司redis cluster的應(yīng)用不是很廣泛屯援,所以大的業(yè)務(wù)很容易將redis內(nèi)存撐到50G猛们,截圖的qps,根據(jù)上面的介紹狞洋,性能梯度是String>Hash=Set>ZSet>List弯淘,之所以可以到達(dá)10w+的qps,也是因為String吉懊,Hash庐橙,Set這樣的接口操作和redis相比差不多,在worker數(shù)多的情況下借嗽,String甚至還高于redis态鳖,所以整體上看qps還不錯,不過對于List這樣的數(shù)據(jù)結(jié)構(gòu)恶导,實現(xiàn)中就是基于kv來做的list浆竭,所以性能低于前面的數(shù)據(jù)結(jié)構(gòu)
Q13:在多線程情況下,對事務(wù)的處理是怎么實現(xiàn)的
A13:pika上層會對寫操作加行鎖,來確保對同一個key的寫db和寫binlog不被打斷
Q14:hashset每次hset都要讀取count值嗎
A14:是的邦泄,因為版本號的原因删窒,每一次都需要讀取元信息
Q15:binlog可以理解為redis的aof文件么?存儲的都是命令日志記錄顺囊?
A15:是的易稠,和aof差不多,存儲的都是用戶命令包蓝,不過除了做aof的功能,在主從同步中它也承擔(dān)了redis中repl_backlog的功能