ledisdb是一個參考ssdb,採用go實現,底層基於leveldb,相似redis的高性能nosql數據庫,提供了kv,list,hash以及zset數據結構的支持。c++
咱們如今的應用極大的依賴redis,但隨着咱們用戶量愈來愈大,redis的內存愈來愈不夠用,而且replication可能還會致使超時問題。雖而後續咱們能夠經過添加多臺機器來解決,可是在現有機器配置下面,咱們仍但願單臺機器承載更多的用戶。另外,由於業務的特性,咱們其實並不須要將全部的數據放到內存,只須要存放當前活躍用戶。git
通過咱們的調研,發現ssdb已經很好的幫咱們解決了這個問題,它提供了跟redis一致的接口(固然有些地方仍是稍微不一樣),可是底層採用leveldb進行存儲。根據其官網的描述,性能已經接近甚至超越了redis。github
本着造輪子的精神,我決定用go實現一個相似的db,取名爲ledisdb,也就是level-redis-db,爲啥不用現成的ssdb,我以爲有以下幾個緣由:redis
go語言開發的快速,這點毋庸置疑,雖然性能上面鐵定離c++的代碼有差距,可是我可以快速的進行原型搭建並實驗。實際上,我在很短的時間裏面就開發出了ledisdb,讓我後續繼續開發有了信心。sql
leveldb的研究,我一直很想將leveldb應用到咱們的項目中,做爲本機熱點數據的首選數據存儲方式,經過ledisdb,讓我對leveldb的使用有了不少經驗。數據庫
redis的熟悉,雖然我用了好久的redis,可是不少redis的命令仍然須要去查手冊,經過實現ledisdb,我更加熟悉了redis的命令,同時,由於要了解這個命令redis如何實現,對redis內部又從新來了一次剖析。json
在準備開發ledisdb的時候,我就在思索一個問題,我需不須要開發另外一個redis?其實這是一個很明確的問題,我不須要另外一個redis。ledisdb雖然參考了redis,但爲了實現簡單,有時候我作了不少減法或者變動,譬如對於zset這種數據結構,我就只支持int64類型的score,而redis的score是double類型的,具體緣由後續講解zset的時候詳細說明。數據結構
因此,咱們能夠認爲,ledisdb是一個基於redis通訊協議,提供了多種高級數據結構的nosql數據庫,它並非另外一個redis。nosql
由於ledisdb是用go寫的,因此首先須要安裝go以及配置GOROOT,GOPATH。性能
mkdir $WORKSPACE cd $WORKSPACE git clone git@github.com:siddontang/ledisdb.git src/github.com/siddontang/ledisdb cd src/github.com/siddontang/ledisdb #構建leveldb,若是已經安裝了,可忽略 ./build_leveldb.sh #安裝ledisdb go依賴 . ./bootstap.sh #配置GOPATH等環境變量 . ./dev.sh go install ./...
具體的安裝說明,能夠查看代碼目錄下面的readme。
使用ledisdb很簡單,只須要運行:
./ledis-server -config=/etc/ledis.json
ledisdb的配置文件採用json格式,爲啥選用json,我在使用json做爲主要的配置格式裏面有過說明。
咱們可使用任何redis客戶端鏈接ledisdb,譬如redis-cli,以下:
127.0.0.1:6380> set a 1 OK 127.0.0.1:6380> get a "1" 127.0.0.1:6380> incr a (integer) 2 127.0.0.1:6380> mset b 2 c 3 OK 127.0.0.1:6380> mget a b c 1) "2" 2) "2" 3) "3"
由於leveldb是c++寫的,因此在go裏面須要使用,cgo是一種很好的方式。這裏,我直接使用了levigo這個庫,並在上面進行了封裝,詳見這裏。雖然有一個go-leveldb,無奈仍不能用。
cgo的性能開銷仍是有的,這點在我作benchmark的時候就明顯感受出來,不事後續優化的空間很大,譬如將多個leveldb的調用邏輯該用c重寫,這樣只須要一次cgo就能夠了。不過這個後續在考慮。
leveldb的一些參數在構建編譯的時候是須要調整的,這點我沒啥經驗,只能google和參考ssdb。譬以下面這幾個:
+ db/dbformat.h // static const int kL0_SlowdownWritesTrigger = 8; static const int kL0_SlowdownWritesTrigger = 16; // static const int kL0_StopWritesTrigger = 12; static const int kL0_StopWritesTrigger = 64; + db/version_set.cc //static const int kTargetFileSize = 2 * 1048576; static const int kTargetFileSize = 32 * 1048576; //static const int64_t kMaxGrandParentOverlapBytes = 10 * kTargetFileSize; static const int64_t kMaxGrandParentOverlapBytes = 20 * kTargetFileSize;
相關參數的調優,只能等我後續深刻研究leveldb了在好好考慮。
任何一個服務端服務沒有性能測試報告那就是耍流氓,我如今只是簡單的用了redis_benchmark進行測試,測試環境爲一臺快兩年的老爺mac air機器。
測試語句:
redis-benchmark -n 10000 -t set,incr,get,lpush,lpop,lrange,mset -q
redis-benchmark默認沒有hash以及zset的測試,後續我在本身加入。
leveldb配置:
compression = false block_size = 32KB write_buffer_size = 64MB cache_size = 500MB
SET: 42735.04 requests per second GET: 45871.56 requests per second INCR: 45248.87 requests per second LPUSH: 45045.04 requests per second LPOP: 43103.45 requests per second LPUSH (needed to benchmark LRANGE): 44843.05 requests per second LRANGE_100 (first 100 elements): 14727.54 requests per second LRANGE_300 (first 300 elements): 6915.63 requests per second LRANGE_500 (first 450 elements): 5042.86 requests per second LRANGE_600 (first 600 elements): 3960.40 requests per second MSET (10 keys): 33003.30 requests per second
SET: 35971.22 requests per second GET: 47393.37 requests per second INCR: 36630.04 requests per second LPUSH: 37174.72 requests per second LPOP: 38167.94 requests per second LPUSH (needed to benchmark LRANGE): 37593.98 requests per second LRANGE_100 (first 100 elements): 905.55 requests per second LRANGE_300 (first 300 elements): 327.78 requests per second LRANGE_500 (first 450 elements): 222.36 requests per second LRANGE_600 (first 600 elements): 165.30 requests per second MSET (10 keys): 33112.59 requests per second
SET: 38759.69 requests per second GET: 40160.64 requests per second INCR: 36101.08 requests per second LPUSH: 33003.30 requests per second LPOP: 27624.31 requests per second LPUSH (needed to benchmark LRANGE): 32894.74 requests per second LRANGE_100 (first 100 elements): 7352.94 requests per second LRANGE_300 (first 300 elements): 2867.79 requests per second LRANGE_500 (first 450 elements): 1778.41 requests per second LRANGE_600 (first 600 elements): 1590.33 requests per second MSET (10 keys): 21881.84 requests per second
能夠看到,ledisdb的性能趕redis以及ssdb仍是有差距的,但也不至於不可用,有些差異並不大。至於爲啥lrange比ssdb高,我比較困惑。
後續的測試報告,我會不斷在benchmark文件裏面更新。
ledisdb仍是一個很是新的項目,比起ssdb已經在生產環境中用了好久,還有不少路要走,還有一些重要的功能須要實現,譬如replication等。
歡迎有興趣的童鞋一塊兒參與進來,在漫漫程序開發路上有一些好基友但是很幸運的。