1、概述
Dynomite是Netflix实现的一个Redis数据库同步复制方案。其思路来自于亚马逊的Dynamo的白皮书 Dynamo whitepaper。目前支持Redis和Memcached,Dynomite的最终目标是能够在存储引擎上实现高效的,不复杂的高可用性和跨数据中心复制,即使存储引擎本身不提供这种功能。
Dynomite有数据中心、机架、节点的三层概念,数据中心可以有多个机架,机架可以有多个节点。每个机架数据是完整的,机架上的不同节点各有一部分数据,即是数据分片。大体原理可以看下这个文章关于Dynomite的部分原理解释。
2、安装配置
2.1、编译
可以通过以下步骤安装所需工具,使用wget下载特定版本代码并编译,目前最新稳定版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 就是编译结果
接着建立工作目录,并移动执行程序到工作目录下
mkdir -p /apps/dynomite/bin
mkdir -p /apps/dynomite/conf
cp src/dynomite /apps/dynomite/bin/
2.2、部署
为了方便测试,我在两个云服务器A、B分别部署两个Dynomite节点,A1、A2、B1、B2共四个节点构成集群。每个Dynomite代理一个Redis节点,在Dynomite所在机器本机上启动对应Redis即可。
也就是一个云服务器模拟一个数据中心,同一个云服务上的两个Dynomite节点模拟同一个机架上的两个节点。这样就可以模拟一个双数据中心集群,一个数据中心有一个机架,同机架的两个节点按数据分片规则保存部分数据。
首先每个服务器上起两个redis实例,分别用6378、6379端口,并打开远程连接。打开远程主要是为了方便后面进行非本机压测性能对比,实际使用时如果Dynomite和Redis在同服务器可以不开。
6378配置文件redis6378_simple.conf
bind 改为对应ip
protected-mode no
port 6378
6379配置redis6379_simple.conf
bind 改为对应ip
protected-mode no
port 6379
然后使用指令启动两个Redis实例
redis-server /etc/redis6378_simple.conf&
redis-server /etc/redis6379_simple.conf&
接着生成一个公钥私钥对,用下面的指令在 conf目录生成两个秘钥文件 dynomite.pem 和 dynomite.pem.pub,这两个文件后面要写到配置文件中。
ssh-keygen -t rsa -f conf/dynomite.pem
接着配置Dynomite节点,其主要配置项意义如下
rack 机架号
dyn_listen dynomite集群同步数据的监听地址和端口
dyn_seeds 集群中其他节点的信息
data_store 存储类型 0 代表redis 1 代表memcached
listen 客户端访问数据的地址和端口
servers 本Dynomite节点对接的redis的ip,端口,权重。这个字段未来可能会支持列表的,即支持一个Dynomite节点对接多个Redis节点
tokens 可以认为是集群中的唯一编码,最好是按照一定规则区分编码,避免重复
secure_server_option 通讯加密方案,可选值'none'、'rack'、'datacenter'、'all',none表示无加密,rack表示不同机架间通讯加密,datacenter表示不同数据中心间通讯加密,all表示全部通讯加密。
recon_key_file 公钥文件
recon_iv_file 私钥文件
max_msgs 缓存的最大消息数,默认200000,可以配置大点
将下面实例的Dynomite节点的配置文件保存到目录/apps/dynomite/conf中。
A1对应的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对应的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对应的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对应的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
然后使用使用以下指令分别启动dynomit节点,-d 表示后台运行
./bin/dynomite -c conf/node1.yml -d --output=node1.log
./bin/dynomite -c conf/node2.yml -d --output=node2.log
接着使用redis-cli连接到dynomite的任一个节点进行测试,会发现任意dynomite节点修改数据后另外一个dynomite实例都可以查到。注意keys * 、flushall、del key1 key2 等批量指令不能正常运行。
redis-cli -h 更改为你的ip -p port
接着直接连接各个redis节点检查数据,会发现同一个数据中心的一个机架包含了完整数据,而同一个机架中的节点的数据不重复。
redis-cli -h 更改为你的ip -p port
4、性能分析
4.1、Dynomite代理造成的性能损失
每个Dynomite节点都会作为一个Redis实例的代理,直接使用压测工具 redis-benchmark 测试连接到Dynomite以及直连Redis的性能表现,便可以大体了解代理造成的性能损耗。
我们选取B1、B2两个Dynomite以及其代理的Redis来进行压测分析。由于实际使用时发现数据并不是随机或者平均落到B1、B2对应的Redis节点,而是所有数据都落到了B1代理的Redis中,数据分片的规则需要再分析。所以对Dynomite压测时,数据在本身代理的Redis中比起不在的情况,可能性能有区别。
所以我们分别在本机对B1、B2以及B1代理的Redis进行压测,之后再在服务器A对B1、B2进行压测,将得到的五个压测数据进行对比。
压测的指令参数如下
redis-benchmark -h ip -p 端口 -r 1000000 -t get,set,lpush,lpop -n 500000 -c 300 -d 1000 -q
压测结果如下
压测目标 | 本机压测 | 同区服务器压测 |
---|---|---|
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 |
可以看出本机访问Dynomite比起直接访问Reids有接近三成的性能损耗;不同Dynomite节点之间性能差别基本可以忽略;同区云服务访问Dynomite代理的性能和直接访问Redis相比几乎没差别,应该是因为Dynomite对Redis的连接使用了 pipelinie 功能。
由于实际使用时,服务和Redis一般不在一个服务器上,所以Dynomite的性能表现比较理想。
5、对Redis指令支持度
支持度较高,除了以下情况外未发现其他不支持的指令
- keys * 、flushall、del key1 key2 等批量执行指令实际上只能处理到Dynomite直接连接的Redis节点的数据。这很好理解,因为批量指令要到多个实例去执行并合并结果,执行时间会较长,而且如果执行结果只有部分正常,合并后的执行结果将会相当复杂。其中keys * 指令会获取到Dynomite链接的Redis实例的key列表
- 订阅发布指令不支持,估计也是因为集群下比较难处理
- 不支持 rename 指令
6、优缺点及其应用于生产环境的风险评估
优点
- 支持多主集群
- 配置使用相对较为简单直观
- 比起直连Redis性能折损相当少,可以忽略
- 对Redis的支持度相当高,完全足够平时开发使用
缺点
- 集群功能的辅助功能不够完整,缺少不停机动态扩容功能
- 缺少内置的数据同步功能,新增节点
- 缺少内置的数据同步功能,Dynomite或Redis节点故障停机重启后不会自动从其他节点同步数据
- 高可用功能有一定缺陷,Dynomite节点对应的Redis挂掉之后,访问这个节点时,如果key是属于这个Redis的会直接报错,不会到其他数据中心拿数据
- 文档比较少特别是中文文档,不够详细,比如各类配置的可选项、各配置的关联互动、异常处理说明、第三方配合使用工具说明很少,
- 社区不活跃
- 更新有点慢,4-6个月更新一次代码
缺点1可以通过Dynomite节点代理Redis哨兵模式或者Redis-cluster集群解决,但会带来一定性能折损;2可以通过第三方数据同步工具做处理如Redis-migrate-tool、Redis-shake;3无法解决;4可以引入进程进程存活监控,出问题后立刻重启Redis,但期间丢失的数据也即是缺点3无法解决;其他无法解决。
其他风险,分别用了两个分支的最新版本,rel_0.6_prod_safe(2019.9.25更新)和0.6(2019.11.21更新)
- rel_0.6_prod_safe分支 快速压测几百万个1k大小的数据包后,Dynomite服务挂掉的情况。
- rel_0.6_prod_safe以及0.6分支出现max_msgs超过上限的错误日志,之后停止压测很长时间在压测仍然会出现,出现这种错误是会出现非常高的内存占用,在redis只占用了不到3-5g内存情况下,Dynomite占用了8-12G内存。并且这个内存不会下降,推测是未处理的消息堆积导致。
- 0.6分支配置打开enable_gossip时启动服务后出现了使用redis-cli连接长时间无响应卡住的情况
对于数据库集群方案,以下几点非常重要
- 1、零侵入:业务系统不需要做任何改造就能接入
- 2、高吞吐量:基于现有业务峰值TPS乘以10,得出TPS要达到1万
- 3、低延时:我司的多活业务不会出现跨机房读取数据的情况,所以定的目标延时低于1s。实际情况延时在50ms左右
- 4、高堆积能力:基于跨机房网络的不确定性,当网络闪断时能够保证指令不丢失
- 5、高可用性:当网络故障或者Redis宕机恢复时,同步任务能自动恢复
- 6、可配置性:业务系统可以自由定制需要同步哪些Key
Dynomite在第1、2、3 方面做得比较好,第4支持但是有一定缺陷,第5不够完善,6不支持。
总的来说Dynomite作为集群方案是功能不够完善,和Redis Cluster相比多了多主功能,但是缺失动态扩容、自动同步数据等功能;高可用方面也有一定缺陷。社区活跃度和文档都比较欠缺,更新较慢。生产环境使用风险较大。如果实在要用建议搭配Redis Cluster使用以解决动态扩容、新增节点和故障节点自动同步数据等问题,并且应该将其当做缓存集群,避免当做持久化数据库,特别是用户数据等核心数据。
参考资料
- Dynomite的Github项目
- Redis高可用第三方开源集群方案介绍
- 较详细的操作指南
- 关于Dynomite的部分原理解释