1 編譯安裝
Q1: 支持的系統?
A1: 目前只支持Linux環境,包括Centos,Ubuntu; 不支持Windowns, Mac
Q2: 怎么編譯安裝?
A2: 參考編譯安裝wiki
Q3: Ubuntu編譯偶爾報錯isnan isinf was not declared?
A3: 一些舊版本的pika對Ubuntu環境兼容不好,某些情況下會出現;可以先修改代碼,用std::isnan和std::isinf替代isnan,isinf, 並包含頭文件cmath。 我們會在新版兼容這個。
#include <cmath>
2 設計與實現
Q1: 為什么要開那么多線程?比如purge,搞個定時任務不就好了。難道編程框架不支持定時器?
A1: pika有一些比較耗時的任務,如刪binlog,掃描key,備份,同步數據文件等等,為了不影響正常的用戶請求,這些任務都是放到后台執行的,並且將能並行的都放到不同線程里來最大程度上提升后台任務的執行速度;你說的變成框架是pink嗎?pink是支持定時器的,每一個workerthread只要用戶定義了cronhandle和頻率,就會定時執行要執行的內容,不過這時候worker是被獨占的,響應不了用戶請求,所以占時的任務最好還是單獨開線程去做,redis的bio也是這個原因
Q2: heartbeat讓sender做不就好了?或者說sender有必要那么多線程嗎?
A2: 這主要有兩個原因,第一為了提高同步速度,sender只發不收,receiver只收不發,心跳是又單獨的線程去做,如果心跳又sender來做,那么為了一秒僅有一次的心跳還要去復雜化sender和receiver的邏輯;第二其實前期嘗試過合並在一起來進行連接級別的存活檢測,當寫入壓力過大的時候會心跳包的收發會延后,導致存活檢測被影響,slave誤判master超時而進行不必要的重連
Q3: nemo存儲hash的實際key,第一個字節是?header?一個類型標記?是說他是個hash類型?
A3: 的確是一個header,不過不是為了標記它是hash,因為nemo底下已經將string,hash,list,zset,set這五個數據結構分成的5個庫,互不影響,之所以有header是因為一個hash有一個meta key和一堆field key,meta key對應的value記錄的是這個hash的基礎信息,如hash的size等等,這個header也是區分meta key和field key用的
Q4: list數據結構里面的curr_seq是個什么東西?
A4: list的實現是完全基於kv實現的list,通過seq來實現list類似prev和next指針,cur_seq是在meta信息里的,也就是當前已經用到那個seq了,新來的節點從這個seq開始遞增接着用
Q5: binlog里面存儲的是轉化后的put,delete?還是存儲的原生redis命令?
A5: 存的是redis的命令
Q6: rsync的deamon模式,這個rsync是linux上的rsync命令?
A6: 是的,pika前期為了更快的實現全同步的功能,此處是直接調用rsync命令來完成數據文件的收發,也是由它來進行文件的續傳校驗等
Q7: dump db文件是rocksdb本身就帶的功能?具體怎么搞的?
A7: rocksdb提夠對當前db快照備份的功能,我們基於此,在dump時先對pika阻住用戶的寫,然后記錄當前的binlog偏移量並且調用rocksdb的接口來拿到當前db的元信息,這個時候就可以放開用戶寫,然后基於這個元信息來進行快照數據的后台拷貝,阻寫的時間很短
Q8: 先寫binlog再執行,如果這時候掛了,命令還沒執行,但是寫入到binlog里面了怎么辦?
A8: master是先寫db再寫binlog,之前slave只用一個worker來同步會在master寫入壓力很大的情況下由於slave一個worker寫入太慢而造成同步差距過大,后來我們調整結構,讓slave通過多個worker來寫提高寫入速度,不過這時候有一個問題,為了保證主從binlog順序一致,寫binlog的操作還是只能又一個線程來做,也就是receiver,所以slave這邊是先寫binlog在寫db,所以slave存在寫完binlog掛掉導致丟失數據的問題,不過redis在master寫完db后掛掉同樣會丟失數據,所以redis采用全同步的辦法來解決這一問題,pika同樣,默認使用部分同步來繼續,如果業務對數據十分敏感,此處可以強制slave重啟后進行全同步即可
Q9: BinlogBGWorker線程之間還是要按照binlog順序執行,這塊並發能提高多少性能?
A9: 之前主從同步的差異是由主的多個worker寫入而從只有一個worker寫入帶來的,現在的做法提高了從寫db的速度,不過協議解析還是有一個線程來做,還是有瓶頸,不過這樣的優化主從同步的性能提高了3~5倍左右,如果key很少的話,優化不明顯,因為slave這面是通過key的hash值來sharding到其中一個worker上的
Q10: 秒刪,每次put都要去查詢key的最新版本?也就是說每次寫避免伴隨一次讀?
A10: pika多數據結構的實現主要是“meta key + 普通key”來實現的,所以對於多數據結構的讀寫,肯定都是對rocksdb進行2次及以上的讀寫次數,你說的版本信息我們是存在meta_key中的,和其他meta信息一起被讀出來,其實並沒有因為版本號而額外增加讀寫次數
Q11: 為什么 Pika 使用多線程而不是像 Redis 單線程的結構?
A11: 因為 Redis 所有的操作都是對於內存的操作,因此理論上 Redis 的每次操作很短的。
Q12: 數據分片是在代理層做的?集合操作落在不同的槽,比如 mget,是在代理層聚合的?
A12: 目前沒有對數據進行分片,你可以理解成和單機 Redis 類似,支持 master-slave 的架構,因此單個 pika 實例存儲的大小的限制是磁盤大小的限制。
Q13: pika 支持的客戶端有哪些,是否支持 pipelining?
A13: pika 支持所有的 Redis 客戶端,因為 pika 設計之初就考慮到了用戶的遷移成本,因此各種語言的客戶端都支持。pipelining 是客戶端來做的,因此我們是支持 pipelining 的。
Q14: 為什么不考慮 Redis cluster shard 呢?
A14: 我們開始做 pika 的時候,Redis cluster shard 還不完善,而且 Redis cluster 定位的場景和 pika 還是有區別。目前我們內部還沒大范圍使用 Redis cluster。
Q15: 不理解前面為什么加 LVS?Redis 類服務都是帶狀態,負載反而用吧?
A15: 我們暴露給用戶的 ip 是我們 LVS 的 ip。在 Redis 前面 LVS 是為了方便主從切換,這樣可以做到用戶完全不感知。這里 LVS 下面掛的多個 Redis 實例,都是 master-slave 結構的。
Q16: 有沒有對比過 ssdb,LevelDB?優勢是什么?
A16: 我們公司內部有業務部門用 ssdb,目前除了游戲大部分的 ssdb 已經遷移到 pika上來。我覺得 pika 的優勢在於我們代碼實現的比較細,性能會比較好。
Q17: 存儲引擎為什么沒有選擇 LevelDB 呢,另外市面上有類似的方案如 ssdb,有什么不同之處嗎?
A17: 存儲引擎上我們在 LevelDB,RocksDB 上面做過對比。LevelDB,RocksDB 在數據量比較小的時候性能差異不大,但是在數據量比較大的情況下,比如 200G 的時候,RocksDB 的性能會比 LevelDB 要來得好。但是 RocksDB 也有他的缺點,就是代碼沒有 LevelDB 來的那么優雅,我一直覺得一個好的 c++ 程序員看 LevelDB 代碼和 effective c++ 就好了。
Q18: 若類似於單機 Redis,那么單機性能是個瓶頸吧?大量的客戶端連接,命令處理,以及網卡流量等
A18: 是的。所以目前內部的 pika 的架構是支持一主多從、多機房自洽的方案。目前線上最多一個主 14 個從這樣的結構。DBA 可以很容易的slaveof 給一個主掛上slave,然后進行數據的全同步過程。
Q19: pika 的多線程比 Redis 的全內存,在 get上竟然快兩倍?set 也快,不存在多線程的鎖消耗嗎?
A19: 這里大家可以看到,這個測試結果是 pika work thread 開了 18 個。
在多數據結構的接口里面 kv 的結構的性能是最好的,而多數據結構的接口比如 hash、zset 等等就算開了 18 個線程,性能依然不如 Redis 要來得好。因為 hash、zset 等數據結構需要有搶占多數據結構元數據鎖的開銷,因此性能很容易下來。但是 kv 接口基本沒有鎖的開銷。唯一的鎖開銷就是 RocksDB 為了實現線程安全增加的鎖,因此這個結果也是可以理解了。
Q20: 完全是因為分布式切片不均的緣故,而放棄分布式集群嗎?m-s架構每個節點不都是全量數據,占用更多資源嗎?
A20: 其實我們在 bada 里面增加了多數據結構的接口,並且兼容了 Redis 的協議,但是后來用戶的使用中,發現其實使用多數據結構接口的用戶數據量其實不是特別大。單機 1T 的盤基本都能夠承受下來。但是還是因為 Hash 分布式切片不均衡,導致我們的維護成本增加,因此我們去實現了 m-s 架構方案。
目前 bada 的方案也是和 pika 並存的方案,我們會根據用戶具體的使用場景推薦使用的存儲方案。我一直覺得肯定不是一套存儲方案解決公司內部的所有需求,一定是某一個方案更適用於某一種存儲方案。
Q21: 除了類比為單機 Redis 外,有沒有考慮分布式支持?比如 Redis 的 sentinel 或者支持 Codis 這樣可能其它 Redis 集群可以無縫遷移。
A21: Pika 目前並沒有使用類似 Redis 的 sentinel,pika 前面是掛 LVS 來負責主從切換。目前也沒有使用 Codis 這樣的 proxy 方案。
Q22: 一主 14 個從?主從同步豈不是很慢?另外,從是只讀的吧,讀從的話,從的數據可能是過期的,數據一致性怎么解決?
A22: 一主 14 從的場景是用戶的寫入都是晚上定期的灌數據,讀取的話從各個從庫進行讀取。因此這個數據一致性是用戶可以接受的場景。