1、概述
Dynomite是Netflix實(shí)現(xiàn)的一個(gè)Redis數(shù)據(jù)庫(kù)同步復(fù)制方案。其思路來(lái)自于亞馬遜的Dynamo的白皮書 Dynamo whitepaper。目前支持Redis和Memcached,Dynomite的最終目標(biāo)是能夠在存儲(chǔ)引擎上實(shí)現(xiàn)高效的,不復(fù)雜的高可用性和跨數(shù)據(jù)中心復(fù)制,即使存儲(chǔ)引擎本身不提供這種功能。
Dynomite有數(shù)據(jù)中心、機(jī)架、節(jié)點(diǎn)的三層概念,數(shù)據(jù)中心可以有多個(gè)機(jī)架,機(jī)架可以有多個(gè)節(jié)點(diǎn)。每個(gè)機(jī)架數(shù)據(jù)是完整的,機(jī)架上的不同節(jié)點(diǎn)各有一部分?jǐn)?shù)據(jù),即是數(shù)據(jù)分片。大體原理可以看下這個(gè)文章關(guān)于Dynomite的部分原理解釋。
2、安裝配置
2.1、編譯
可以通過以下步驟安裝所需工具,使用wget下載特定版本代碼并編譯,目前最新穩(wěn)定版l'l是v0.6
yum install -y git autoconf automake libtool openssl-devel net-tools
wget https://github.com/Netflix/dynomite/archive/v0.6.zip
unzip v0.6.zip
cd dynomite-0.6
autoreconf -fvi
./configure --enable-debug=false
make
src/dynomite -h
在src目錄下的 dynomite 就是編譯結(jié)果
接著建立工作目錄,并移動(dòng)執(zhí)行程序到工作目錄下
mkdir -p /apps/dynomite/bin
mkdir -p /apps/dynomite/conf
cp src/dynomite /apps/dynomite/bin/
2.2、部署
為了方便測(cè)試,我在兩個(gè)云服務(wù)器A、B分別部署兩個(gè)Dynomite節(jié)點(diǎn),A1、A2、B1、B2共四個(gè)節(jié)點(diǎn)構(gòu)成集群。每個(gè)Dynomite代理一個(gè)Redis節(jié)點(diǎn),在Dynomite所在機(jī)器本機(jī)上啟動(dòng)對(duì)應(yīng)Redis即可。
也就是一個(gè)云服務(wù)器模擬一個(gè)數(shù)據(jù)中心,同一個(gè)云服務(wù)上的兩個(gè)Dynomite節(jié)點(diǎn)模擬同一個(gè)機(jī)架上的兩個(gè)節(jié)點(diǎn)。這樣就可以模擬一個(gè)雙數(shù)據(jù)中心集群,一個(gè)數(shù)據(jù)中心有一個(gè)機(jī)架,同機(jī)架的兩個(gè)節(jié)點(diǎn)按數(shù)據(jù)分片規(guī)則保存部分?jǐn)?shù)據(jù)。
首先每個(gè)服務(wù)器上起兩個(gè)redis實(shí)例,分別用6378、6379端口,并打開遠(yuǎn)程連接。打開遠(yuǎn)程主要是為了方便后面進(jìn)行非本機(jī)壓測(cè)性能對(duì)比,實(shí)際使用時(shí)如果Dynomite和Redis在同服務(wù)器可以不開。
6378配置文件redis6378_simple.conf
bind 改為對(duì)應(yīng)ip
protected-mode no
port 6378
6379配置redis6379_simple.conf
bind 改為對(duì)應(yīng)ip
protected-mode no
port 6379
然后使用指令啟動(dòng)兩個(gè)Redis實(shí)例
redis-server /etc/redis6378_simple.conf&
redis-server /etc/redis6379_simple.conf&
接著生成一個(gè)公鑰私鑰對(duì),用下面的指令在 conf目錄生成兩個(gè)秘鑰文件 dynomite.pem 和 dynomite.pem.pub,這兩個(gè)文件后面要寫到配置文件中。
ssh-keygen -t rsa -f conf/dynomite.pem
接著配置Dynomite節(jié)點(diǎn),其主要配置項(xiàng)意義如下
rack 機(jī)架號(hào)
dyn_listen dynomite集群同步數(shù)據(jù)的監(jiān)聽地址和端口
dyn_seeds 集群中其他節(jié)點(diǎn)的信息
data_store 存儲(chǔ)類型 0 代表redis 1 代表memcached
listen 客戶端訪問數(shù)據(jù)的地址和端口
servers 本Dynomite節(jié)點(diǎn)對(duì)接的redis的ip,端口,權(quán)重。這個(gè)字段未來(lái)可能會(huì)支持列表的,即支持一個(gè)Dynomite節(jié)點(diǎn)對(duì)接多個(gè)Redis節(jié)點(diǎn)
tokens 可以認(rèn)為是集群中的唯一編碼,最好是按照一定規(guī)則區(qū)分編碼,避免重復(fù)
secure_server_option 通訊加密方案,可選值'none'、'rack'、'datacenter'、'all',none表示無(wú)加密,rack表示不同機(jī)架間通訊加密,datacenter表示不同數(shù)據(jù)中心間通訊加密,all表示全部通訊加密。
recon_key_file 公鑰文件
recon_iv_file 私鑰文件
max_msgs 緩存的最大消息數(shù),默認(rèn)200000,可以配置大點(diǎn)
將下面實(shí)例的Dynomite節(jié)點(diǎn)的配置文件保存到目錄/apps/dynomite/conf中。
A1對(duì)應(yīng)的dynomite配置
dyn_o_mite:
datacenter: dc1
rack: rack1
dyn_listen: 192.168.1.1:8101
dyn_seeds:
- 192.168.1.1:8201:rack1:dc1:112
- 192.168.1.2:8101:rack1:dc2:211
- 192.168.1.2:8201:rack1:dc2:212
data_store: 0
listen: 192.168.1.1:8102
dyn_seed_provider: simple_provider
servers:
- 192.168.1.1:6378:1
tokens: 111
secure_server_option: none
stats_listen: 127.0.0.1:30001
recon_key_file: conf/dynomite.pem.pub
recon_iv_file: conf/dynomite.pem
max_msgs: 500000
A2對(duì)應(yīng)的dynomite配置
dyn_o_mite:
datacenter: dc1
rack: rack1
dyn_listen: 192.168.1.1:8201
dyn_seeds:
- 192.168.1.1:8101:rack1:dc1:111
- 192.168.1.2:8101:rack1:dc2:211
- 192.168.1.2:8201:rack1:dc2:212
data_store: 0
listen: 192.168.1.1:8202
dyn_seed_provider: simple_provider
servers:
- 192.168.1.1:6379:1
tokens: 112
secure_server_option: none
stats_listen: 127.0.0.1:30002
recon_key_file: conf/dynomite.pem.pub
recon_iv_file: conf/dynomite.pem
max_msgs: 500000
B1對(duì)應(yīng)的dynomite配置
dyn_o_mite:
datacenter: dc2
rack: rack1
dyn_listen: 192.168.1.2:8101
dyn_seeds:
- 192.168.1.2:8201:rack1:dc2:212
- 192.168.1.1:8101:rack1:dc1:111
- 192.168.1.1:8201:rack1:dc1:112
data_store: 0
listen: 192.168.1.2:8102
dyn_seed_provider: simple_provider
servers:
- 192.168.1.2:6378:1
tokens: 211
secure_server_option: none
stats_listen: 127.0.0.1:30001
recon_key_file: conf/dynomite.pem.pub
recon_iv_file: conf/dynomite.pem
max_msgs: 500000
B2對(duì)應(yīng)的dynomite配置
dyn_o_mite:
datacenter: dc2
rack: rack1
dyn_listen: 192.168.1.2:8201
dyn_seeds:
- 192.168.1.2:8101:rack1:dc2:211
- 192.168.1.1:8101:rack1:dc1:111
- 192.168.1.1:8201:rack1:dc1:112
data_store: 0
listen: 192.168.1.2:8202
dyn_seed_provider: simple_provider
servers:
- 192.168.1.2:6379:1
tokens: 212
secure_server_option: none
stats_listen: 127.0.0.1:30002
recon_key_file: conf/dynomite.pem.pub
recon_iv_file: conf/dynomite.pem
max_msgs: 500000
然后使用使用以下指令分別啟動(dòng)dynomit節(jié)點(diǎn),-d 表示后臺(tái)運(yùn)行
./bin/dynomite -c conf/node1.yml -d --output=node1.log
./bin/dynomite -c conf/node2.yml -d --output=node2.log
接著使用redis-cli連接到dynomite的任一個(gè)節(jié)點(diǎn)進(jìn)行測(cè)試,會(huì)發(fā)現(xiàn)任意dynomite節(jié)點(diǎn)修改數(shù)據(jù)后另外一個(gè)dynomite實(shí)例都可以查到。注意keys * 、flushall、del key1 key2 等批量指令不能正常運(yùn)行。
redis-cli -h 更改為你的ip -p port
接著直接連接各個(gè)redis節(jié)點(diǎn)檢查數(shù)據(jù),會(huì)發(fā)現(xiàn)同一個(gè)數(shù)據(jù)中心的一個(gè)機(jī)架包含了完整數(shù)據(jù),而同一個(gè)機(jī)架中的節(jié)點(diǎn)的數(shù)據(jù)不重復(fù)。
redis-cli -h 更改為你的ip -p port
4、性能分析
4.1、Dynomite代理造成的性能損失
每個(gè)Dynomite節(jié)點(diǎn)都會(huì)作為一個(gè)Redis實(shí)例的代理,直接使用壓測(cè)工具 redis-benchmark 測(cè)試連接到Dynomite以及直連Redis的性能表現(xiàn),便可以大體了解代理造成的性能損耗。
我們選取B1、B2兩個(gè)Dynomite以及其代理的Redis來(lái)進(jìn)行壓測(cè)分析。由于實(shí)際使用時(shí)發(fā)現(xiàn)數(shù)據(jù)并不是隨機(jī)或者平均落到B1、B2對(duì)應(yīng)的Redis節(jié)點(diǎn),而是所有數(shù)據(jù)都落到了B1代理的Redis中,數(shù)據(jù)分片的規(guī)則需要再分析。所以對(duì)Dynomite壓測(cè)時(shí),數(shù)據(jù)在本身代理的Redis中比起不在的情況,可能性能有區(qū)別。
所以我們分別在本機(jī)對(duì)B1、B2以及B1代理的Redis進(jìn)行壓測(cè),之后再在服務(wù)器A對(duì)B1、B2進(jìn)行壓測(cè),將得到的五個(gè)壓測(cè)數(shù)據(jù)進(jìn)行對(duì)比。
壓測(cè)的指令參數(shù)如下
redis-benchmark -h ip -p 端口 -r 1000000 -t get,set,lpush,lpop -n 500000 -c 300 -d 1000 -q
壓測(cè)結(jié)果如下
| 壓測(cè)目標(biāo) | 本機(jī)壓測(cè) | 同區(qū)服務(wù)器壓測(cè) |
|---|---|---|
| B1代理的Redis | SET 99265 GET 94607 | SET 50080 GET 47943 |
| B1 | SET 69070 GET 82331 | SET 48642 GET 47888 |
| B2 | SET 69851 GET 79833 | SET 50241 GET 48971 |
可以看出本機(jī)訪問Dynomite比起直接訪問Reids有接近三成的性能損耗;不同Dynomite節(jié)點(diǎn)之間性能差別基本可以忽略;同區(qū)云服務(wù)訪問Dynomite代理的性能和直接訪問Redis相比幾乎沒差別,應(yīng)該是因?yàn)镈ynomite對(duì)Redis的連接使用了 pipelinie 功能。
由于實(shí)際使用時(shí),服務(wù)和Redis一般不在一個(gè)服務(wù)器上,所以Dynomite的性能表現(xiàn)比較理想。
5、對(duì)Redis指令支持度
支持度較高,除了以下情況外未發(fā)現(xiàn)其他不支持的指令
- keys * 、flushall、del key1 key2 等批量執(zhí)行指令實(shí)際上只能處理到Dynomite直接連接的Redis節(jié)點(diǎn)的數(shù)據(jù)。這很好理解,因?yàn)榕恐噶钜蕉鄠€(gè)實(shí)例去執(zhí)行并合并結(jié)果,執(zhí)行時(shí)間會(huì)較長(zhǎng),而且如果執(zhí)行結(jié)果只有部分正常,合并后的執(zhí)行結(jié)果將會(huì)相當(dāng)復(fù)雜。其中keys * 指令會(huì)獲取到Dynomite鏈接的Redis實(shí)例的key列表
- 訂閱發(fā)布指令不支持,估計(jì)也是因?yàn)榧合卤容^難處理
- 不支持 rename 指令
6、優(yōu)缺點(diǎn)及其應(yīng)用于生產(chǎn)環(huán)境的風(fēng)險(xiǎn)評(píng)估
優(yōu)點(diǎn)
- 支持多主集群
- 配置使用相對(duì)較為簡(jiǎn)單直觀
- 比起直連Redis性能折損相當(dāng)少,可以忽略
- 對(duì)Redis的支持度相當(dāng)高,完全足夠平時(shí)開發(fā)使用
缺點(diǎn)
- 集群功能的輔助功能不夠完整,缺少不停機(jī)動(dòng)態(tài)擴(kuò)容功能
- 缺少內(nèi)置的數(shù)據(jù)同步功能,新增節(jié)點(diǎn)
- 缺少內(nèi)置的數(shù)據(jù)同步功能,Dynomite或Redis節(jié)點(diǎn)故障停機(jī)重啟后不會(huì)自動(dòng)從其他節(jié)點(diǎn)同步數(shù)據(jù)
- 高可用功能有一定缺陷,Dynomite節(jié)點(diǎn)對(duì)應(yīng)的Redis掛掉之后,訪問這個(gè)節(jié)點(diǎn)時(shí),如果key是屬于這個(gè)Redis的會(huì)直接報(bào)錯(cuò),不會(huì)到其他數(shù)據(jù)中心拿數(shù)據(jù)
- 文檔比較少特別是中文文檔,不夠詳細(xì),比如各類配置的可選項(xiàng)、各配置的關(guān)聯(lián)互動(dòng)、異常處理說(shuō)明、第三方配合使用工具說(shuō)明很少,
- 社區(qū)不活躍
- 更新有點(diǎn)慢,4-6個(gè)月更新一次代碼
缺點(diǎn)1可以通過Dynomite節(jié)點(diǎn)代理Redis哨兵模式或者Redis-cluster集群解決,但會(huì)帶來(lái)一定性能折損;2可以通過第三方數(shù)據(jù)同步工具做處理如Redis-migrate-tool、Redis-shake;3無(wú)法解決;4可以引入進(jìn)程進(jìn)程存活監(jiān)控,出問題后立刻重啟Redis,但期間丟失的數(shù)據(jù)也即是缺點(diǎn)3無(wú)法解決;其他無(wú)法解決。
其他風(fēng)險(xiǎn),分別用了兩個(gè)分支的最新版本,rel_0.6_prod_safe(2019.9.25更新)和0.6(2019.11.21更新)
- rel_0.6_prod_safe分支 快速壓測(cè)幾百萬(wàn)個(gè)1k大小的數(shù)據(jù)包后,Dynomite服務(wù)掛掉的情況。
- rel_0.6_prod_safe以及0.6分支出現(xiàn)max_msgs超過上限的錯(cuò)誤日志,之后停止壓測(cè)很長(zhǎng)時(shí)間在壓測(cè)仍然會(huì)出現(xiàn),出現(xiàn)這種錯(cuò)誤是會(huì)出現(xiàn)非常高的內(nèi)存占用,在redis只占用了不到3-5g內(nèi)存情況下,Dynomite占用了8-12G內(nèi)存。并且這個(gè)內(nèi)存不會(huì)下降,推測(cè)是未處理的消息堆積導(dǎo)致。
- 0.6分支配置打開enable_gossip時(shí)啟動(dòng)服務(wù)后出現(xiàn)了使用redis-cli連接長(zhǎng)時(shí)間無(wú)響應(yīng)卡住的情況
對(duì)于數(shù)據(jù)庫(kù)集群方案,以下幾點(diǎn)非常重要
- 1、零侵入:業(yè)務(wù)系統(tǒng)不需要做任何改造就能接入
- 2、高吞吐量:基于現(xiàn)有業(yè)務(wù)峰值TPS乘以10,得出TPS要達(dá)到1萬(wàn)
- 3、低延時(shí):我司的多活業(yè)務(wù)不會(huì)出現(xiàn)跨機(jī)房讀取數(shù)據(jù)的情況,所以定的目標(biāo)延時(shí)低于1s。實(shí)際情況延時(shí)在50ms左右
- 4、高堆積能力:基于跨機(jī)房網(wǎng)絡(luò)的不確定性,當(dāng)網(wǎng)絡(luò)閃斷時(shí)能夠保證指令不丟失
- 5、高可用性:當(dāng)網(wǎng)絡(luò)故障或者Redis宕機(jī)恢復(fù)時(shí),同步任務(wù)能自動(dòng)恢復(fù)
- 6、可配置性:業(yè)務(wù)系統(tǒng)可以自由定制需要同步哪些Key
Dynomite在第1、2、3 方面做得比較好,第4支持但是有一定缺陷,第5不夠完善,6不支持。
總的來(lái)說(shuō)Dynomite作為集群方案是功能不夠完善,和Redis Cluster相比多了多主功能,但是缺失動(dòng)態(tài)擴(kuò)容、自動(dòng)同步數(shù)據(jù)等功能;高可用方面也有一定缺陷。社區(qū)活躍度和文檔都比較欠缺,更新較慢。生產(chǎn)環(huán)境使用風(fēng)險(xiǎn)較大。如果實(shí)在要用建議搭配Redis Cluster使用以解決動(dòng)態(tài)擴(kuò)容、新增節(jié)點(diǎn)和故障節(jié)點(diǎn)自動(dòng)同步數(shù)據(jù)等問題,并且應(yīng)該將其當(dāng)做緩存集群,避免當(dāng)做持久化數(shù)據(jù)庫(kù),特別是用戶數(shù)據(jù)等核心數(shù)據(jù)。