SSDB數據庫
SSDB是一套基於LevelDB存儲引擎的非關系型數據庫(NOSQL),可用於取代Redis,更適合海量數據的存儲。
另外,rocksdb是FB在LevelDB的二次開發版本,因此也存在使用RocksDB作為存儲引擎的SSDB版本,可以參考這里。
編譯和安裝
wget --no-check-certificate https://github.com/ideawu/ssdb/archive/master.zip unzip master cd ssdb-master make # 將安裝在 /usr/local/ssdb 目錄下 sudo make install
啟動服務
# 啟動主庫 ./ssdb-server ssdb.conf # 或者啟動為后台進程 ./ssdb-server -d ssdb.conf # 啟動 ssdb 命令行客戶端 ./tools/ssdb-cli -p 8888 # 停止 ssdb-server ./ssdb-server ssdb.conf -s stop # 對於舊版本 kill `cat ./var/ssdb.pid`
配置文件
ssdb.conf:
work_dir = ./var
pidfile = ./var/ssdb.pid
server:
ip: 127.0.0.1
port: 8888
# bind to public ip
#ip: 0.0.0.0
# format: allow|deny: all|ip_prefix
# multiple allows or denys is supported
#deny: all
#allow: 127.0.0.1
#allow: 192.168
# auth password must be at least 32 characters
#auth: very-strong-password
replication:
binlog: yes
# Limit sync speed to *MB/s, -1: no limit
sync_speed: -1
slaveof:
# to identify a master even if it moved(ip, port changed)
# if set to empty or not defined, ip:port will be used.
#id: svc_2
# sync|mirror, default is sync
#type: sync
#ip: 127.0.0.1
#port: 8889
logger:
level: debug
# 支持的日志級別有: debug, warn, error, fatal
.
output: log.txt
rotate:
size: 1000000000
leveldb:
# in MB
cache_size: 500
# in KB
block_size: 32
# in MB
write_buffer_size: 64
# in MB
compaction_speed: 1000
# yes|no
compression: yes
一個 ssdb-server 實例占用的內存瞬時(有可能, 而且即使達到, 也只是持續短時間)最高達到(MB):
cache_size + write_buffer_size * 66 + 32
這是對於壓縮選項沒有開啟的情況, 如果 compression: yes, 計算公式是:
cache_size + 10 * write_buffer_size * 66 + 32
你可以調整配置參數, 限制 ssdb-server 的內存占用.
SSDB命令
與Redis類似,SSDB也支持多種數據結構(KV list, hash, soreted set),下面列出了常用命令:
dbsize # 返回數據庫占用空間,以字節為單位
flushdb # 清空數據庫
info # 返回服務器信息
auth password # 驗證訪問密碼
KV結構
set key value
setx key value ttl # 設置key的同時設置ttl
setnx key value # 若key已存在,則不設置
multi_set key1 value1 key2 value2 ...
exists key
get key
getset key value # 更新key,並返回舊value
multi_get key1 key2 ...
keys key_start key_end limit # 返回指定范圍內的key,左開右閉區間(SSDB的key有序存儲)
rkeys key_start key_end limit
scan key_start key_end limit
rscan key_start key_end limit
expire key ttl
ttl key
del key
multi_del key1 key2 ...
substr key start size # 返回子串
strlen key
incr key [num]
getbit key offset
setbit key offset val
bitcount key [start] [end]
countbit key start size
hashmap結構
hset name key value
multi_hset name key1 value1 key2 value2 ...
hget name key
multi_hget name key1 key2 ...
hgetall name
hkeys name key_start key_end
hscan key_start key_end limit
hrscan key_start key_end limit
hdel name key # 刪除一個字段
hclear name # 刪除所有字符
multi_hdel name key1 key2 ...
hexists name key
hsize name
hincr name key [num]
hlist name_start name_end limit # 列出指定范圍的所有hash表
hrlist name_start name_end limit
list結構
qpush_front name item1 item2 ... # 往隊頭插入新元素
qpush_back name item1 item2 ... # 往隊尾插入新元素
qpop_front name size # 從隊頭彈出若干個元素
qpop_back name size # 從隊尾彈出若干個元素
qtrim_front name size # 從隊頭移除多個元素
qtrim_back name size # 從隊尾移除多個元素
qfront name # 返回隊頭
qback name # 返回隊尾
qsize name # 返回隊長
qget name index # 返回指定位置元素
qset name index val
qrange name offset limit # 返回一個切片
qslice name begine end # 返回一個切片
qclear name
qlist name_start name_end limit
qrlist name_start name_end limit
sorted set結構
zset name key socre
zget name key
zdel name key
zexists name key
zsize name
zincr name key num
導出/導入
SSDB才有LSM模型,也就是說它的key是有序存儲的,因此,我們可以導出所有key的數據,也可以導出指定范圍內key的數據。
1、使用ssdb-cli 命令行客戶端
導出整個數據庫:
# backup current database into file backup.ssdb ssdb 127.0.0.1:8888> export backup.ssdb
按照 Key 區間導出數據庫(交互模式)
ssdb 127.0.0.1:8888> export -i backup.ssdb input KV range[start, end]: start(inclusive, default none): a end(inclusive, default none): z input HASH range: start(inclusive, default none): end(inclusive, default none): input ZSET range: start(inclusive, default none): end(inclusive, default none): input QUEUE range: start(inclusive, default none): end(inclusive, default none):
命令 export -i backup.ssdb 將導出區間 [a, z] 內的 KV, 所有的 HASH, ZSET, QUEUE.
導入命令:
# import backup.ssdb into current database ssdb 127.0.0.1:8888> import backup.ssdb
import 命令會把數據庫中的相同 key 給替換。
2、SSDB 另一個專門用於導出工具是 ssdb-dump,用法如下:
./tools/ssdb-dump ip port output_folder
目錄 output_folder 必須不存在, 因為 ssdb-dump 會創建這個目錄. 導出之后, 這個目錄里將有兩個子目錄, data 目錄里包含着數據, 還有一個空的 meta 目錄.
如果想從導出的目錄恢復數據,可以將 output_folder 目錄拷貝到你的服務器上面,然后修改你的 ssdb.conf 配置文件, 將 work_dir 指向 output_folder 目錄, 然后重啟 ssdb-server。
限制
最大 Key 長度 200 字節
最大 Value 長度 31MB
最大請求或響應長度 31MB
單個 HASH 中的元素數量 9,223,372,036,854,775,807
單個 ZSET 中的元素數量 9,223,372,036,854,775,807
單個 QUEUE 中的元素數量 9,223,372,036,854,775,807
命令最多參數個數 所有參數加起來體積不超過 31MB 大小
Replication
Redis的主從復制在主庫掛了的時候就無法再寫入數據了,而SSDB不但支持主-從結構,還支持多主結構。
主-從配置
#server1:
replication:
slaveof:
#server2:
replication:
slaveof:
id: svc_1
# sync|mirror, default is sync
type: sync
ip: 127.0.0.1
port: 8888
主-主配置
#server1:
replication:
slaveof:
id: svc_2
# sync|mirror, default is sync
type: mirror
ip: 127.0.0.1
port: 8889
#server2:
replication:
slaveof:
id: svc_1
# sync|mirror, default is sync
type: mirror
ip: 127.0.0.1
port: 8888
多主配置
在一組一共包含 n 個實例的 SSDB 實例群中, 每一個實例必須 slaveof 其余的 n-1 個實例.
replication:
slaveof:
id: svc_1
# sync|mirror, default is sync
type: mirror
ip: 127.0.0.1
port: 8888
slaveof:
id: svc_2
# sync|mirror, default is sync
type: mirror
ip: 127.0.0.1
port: 8889
# ... more slaveof
監控
info命令可以返回SSDB服務狀態:
ssdb 127.0.0.1:8899> info
binlogs
capacity : 10000000
min_seq : 1
max_seq : 74
replication
client 127.0.0.1:55479
type : sync
status : SYNC
last_seq : 73
replication
slaveof 127.0.0.1:8888
id : svc_2
type : sync
status : SYNC
last_seq : 73
copy_count : 0
sync_count : 44
binlogs,當前實例的寫操作狀態:
- capacity: binlog 隊列的最大長度
- min_seq: 當前隊列中的最小 binlog 序號
- max_seq: 當前隊列中的最大 binlog 序號
replication,可以有多條 replication 記錄. 每一條表示一個連接進來的 slave(client), 或者一個當前服務器所連接的 master(slaveof).
- slaveof|client ip:port, 遠端 master/slave 的 ip:port
- type: 類型, sync|mirror
- status: 當前同步狀態, DISCONNECTED|INIT|OUT_OF_SYNC|COPY|SYNC,見下面的解釋
- last_seq: 上一條發送或者收到的 binlog 的序號
- slaveof.id: master 的 id(這是從 slave's 角度來看的, 你永遠不需要在 master 上配置它自己的 id)
- slaveof.copy_count: 在全量同步時, 已經復制的 key 的數量
- slaveof.sync_count: 發送或者收到的 binlog 的數量.
關於 status:
- DISCONNECTED: 與 master 斷開了連接, 一般是網絡中斷
- INIT: 初始化狀態
- OUT_OF_SYNC: 由於短時間內在 master 有大量寫操作, 導致 binlog 隊列淘汰, slave 丟失同步點, 只好重新復制全部的數據
- COPY: 正在復制基准數據的過程中, 新的寫操作可能無法及時地同步
- SYNC: 同步狀態是健康的
判斷同步狀態
binlogs.max_seq 是指當前實例上的最新一次的寫(寫/更新/刪除)操作的序號;
replication.client.last_seq 是指已發送給 slave 的最新一條 binlog 的序號;
所以, 如果你想判斷主從同步是否已經同步到位(實時更新), 那么就判斷 binlogs.max_seq 和 replication.client.last_seq 是否相等。
SSDB協議
SSDB協議與Redis的文本協議也類似:
SSDB數據包的結構:
Packet := Block+ '\n'
Block := Size '\n' Data '\n'
Size := literal_integer
Data := size_bytes_of_data
請求:
Request := Cmd Blocks*
Cmd := Block
請求命令包括: get, set, del, ...
響應:
Response := Status Block*
Status := Block
響應狀態碼包括: ok, not_found, error, fail, client_error
示例:
用 telnet 或者 nc 命令連接到 SSDB 服務器, 然后輸入下面的代碼(用最后一行空行結束):
3
get
3
key
你將看到類似這樣的響應:
2
ok
3
val
SSDB 協議解析器的C實現:
#include <stdlib.h> #include <string.h> int len = buffer->size(); char *ptr = buffer->data(); while(len > 0){ char *data = (char *)memchr(ptr, '\n', len); if(data == NULL){ break; } data += 1; int num = data - ptr; if(num == 1 || (num == 2 && ptr[0] == '\r')){ // Packet received. return OK; } // Size received int size = (int)strtol(ptr, NULL, 10); len -= num + size; ptr += num + size; if(len >= 1 && ptr[0] = '\n'){ len -= 1; ptr += 1; }else if(len >= 2 && ptr[0] == '\r' && ptr[1] == '\n'){ len -= 2; ptr += 2; }else{ break; } // Data received }