Redis Cluster架构优化
Redis Cluster架构优化
在《全面剖析Redis Cluster原理和应用》中,我们已经详细剖析了现阶段Redis Cluster的缺点:
- 无中心化架构
- Gossip消息的开销
- 不停机升级困难
- 无法根据统计区分冷热数据
- 客户端的挑战
- Cluster协议支持
- 连接和路由表的维护开销
- MultiOp和Pipeline支持有限
- Redis实现问题
- 不能自动发现
- 不能自动Resharding
- 无监控管理UI
- 最终一致性和“脑裂”问题
- 数据迁移以Key为单位,速度较慢
- 数据迁移没有保存进度,故障时不能恢复
- Slave“冷备”,不能缓解读压力
当然之前也说过了:“这与Redis的设计初衷有关,毕竟作者都已经说了,最核心的设计目标就是性能、水平伸缩和可用性”。但综合来看,要想在生产环境中使用Redis Cluster,我们还是有一些工作要做的。本文就从宏观层面上,列举一些架构优化的参考方案。
1.P2P架构副作用
1.1 Gossip通信开销
Gossip消息的通信开销是P2P分布式系统带来的第一个副作用。有一篇关于Gossip通俗易懂的文章《Life in a Redis Cluster: Meet and Gossip with your neighbors》。Redis为集群操作的消息通信单独开辟一个TCP通道,交换二进制消息:
- PING/PONG:Cluster的心跳,每个结点每秒随机PING几个结点。结点的选择方法是:超过
cluster-node-timeout
一半的时间还未PING过或未收到PONG的结点,所以这个参数会极大影响集群内部的消息通信量。心跳包除了结点自己的数据外,还包含一些其他结点(集群规模的1/10)的数据,这也是“Gossip流言”的含义。 - MEET/PONG:只有MEET后的受信结点才能加入到上面的PING/PONG通信中。
关于Gossip的问题不可避免,我们只能通过参数调整和优化,在通信效率和开销之间找到一个平衡点。因为笔者还未搭建过大规模的Redis Cluster集群,关于集群的性能和参数调优还不能给出建议,留到积累足够经验再做整理吧。
1.2 不停机升级困难
以Nginx为例,修改配置甚至升级版本都不需要停机,Master会逐一启动新的Worker实例去替代旧的Worker。对于单机版的Redis,我们也可以用类似的方式实现的。但目前不知道Redis Cluster或者其他P2P分布式系统像Cassandra,是否有比较好的方案。
1.3 冷热数据无法区分
由于集群内结点都是对等的,所以像数据热度这种整体的统计数据就无处存放。当内存有限时,要想实现层次化存储,将冷数据Swap到慢存储如磁盘上时,就变得有些棘手了!
解决方法就是计算机界号称万能的“增加中间层”方法。增加一层Proxy,负责做数据统计、Swap甚至L1缓存。关于冷热数据的统计和处理,请参考《微博CacheService架构浅析》
2.客户端的挑战
Redis Cluster的引入会给客户端带来一些挑战。要么“勇敢面对”,通过引入最新的支持Cluster协议的Jedis客户端,再加以改造来应对这些挑战。要么增加Proxy,像防洪堤坝一样将危险隔离在外。
2.1 Cluster协议开发
对于Java,最主流的Jedis客户端已经早早开始支持Cluster协议了,但仔细看了一下,貌似处理集群中结点Failover时有些问题。Slave替换上来了,Jedis的确可以根据”MOVED”消息更新Slot与结点的对应关系,但是:
- 原来Master结点的连接池没有处理
- 结点IP列表没有更新,极端情况下有问题
不知道这算不算Jedis由来已久的问题了。因为之前Jedis就是只支持要么用分片连接池,要么用Sentinel连接池,没有两者的结合!还好有热心的程序员“出手相助”,详见《Jedis分片Sentinel连接池实验》。上面两个问题对应的源码看得不是很细,突然想到的这两个问题,要是说的不对还请指正!
2.2 连接和路由表的维护
为了实现Smart客户端,Jedis要缓存16384个Slot到结点的映射关系。这还不算什么,Jedis还要为每个结点单独开一个连接池。假如你有一台强劲的32核服务器,为了在多核上充分释放Redis的处理能力,可能会起16甚至32个实例,想想会有多少连接建立?如果你有两台应用呢?
这个问题在像Hazelcast或GridGain等其他P2P系统中还不会这么严重。因为这两个产品都是用Java多线程开发的,每台服务器上起一个实例就可以了。这样客户端即便是Smart模式也不会开很多连接到服务器。后面还会讲到,单线程的Redis的运维成本也不小。
2.3 MultiOp和Pipeline支持有限
因为Redis Cluster自动数据Sharding的缘故,MultiOp和Pipeline都被限定在命令中的所有Key必须都在同一Slot内。如果想突破这个限定该怎么办?那扩展Jedis或者在Proxy中实现命令拆分和结果聚合的逻辑。
3.Redis实现问题
关于Redis的具体实现细节问题,主要是Redis简洁的设计、redis-trib等工具的欠缺导致的。我们可以通过Dashboard或Agent组件来解决这些问题。
3.1 不能自动发现
Redis Cluster没有使用传统的Multicast通知自动发现集群结点,我们能做的也只能是像redis-trib那样,在用户指定新结点时帮它执行CLUSTER MEET
命令。
3.2 手动Resharding
手动指的不只是像Codis那样要在控制台上添加完新结点后手动触发Rebalance,而是要我们指定哪些Slot迁移到哪些结点上!就像建立集群时做的那样!如果我们有个统一的Dashboard,实现个简单的根据各个机器和Slot负载进行Resharding的算法,那么就能将这部分工作自动化了。
3.3 无监控管理UI
Redis一直没有官方的监控管理工具,到了Redis Cluster依旧是这个样子。这个问题比较好解决,像Codis那样提供一套漂亮的Dashboard就可以了,底层使用各种CLUSTER
命令完成工作。
3.4 “脑裂”问题
关于“脑裂”(网络分区)问题,只能靠Redis官方提供解决方案了。
3.5 迁移速度较慢
GitHub上有人提了一个Issue “redis-trib: use pipeline to speed up moving slot”,通过Pipeline调用Migrate命令,改善redis-trib的迁移速度。但这样只是治标不治本,毕竟迁移的基本单位还是Key而不是Slot。但因为Redis的save/bgsave都是实例级别,所以要想不改Redis源码就获得Slot的复制或迁移能力,还真不太好办!
看看Codis作者的思路:“在RebornDB中我们会尝试提供基于复制的迁移方式,也就是开始迁移时,记录某slot的操作,然后在后台开始同步到slave,当slave同步完后,开始将记录的操作回放,回放差不多后,将master的写入停止,追平后修改路由表,将需要迁移的slot切换成新的master,主从(半)同步复制,这个之前提到过。”
3.6 迁移故障恢复
由于无中心化的设计,数据迁移的进度等信息无处保存。如果迁移中发生失败,则可能某一个Slot处于迁移中间状态。再加上没有进度信息的话,会给我们的恢复工作带来很大麻烦。可以考虑重新启用ZooKeeper,或者单独使用一个Redis实例做全局信息存储。
3.7 Slave冷备
对于Redis Cluster不会将请求转发给Slave结点,造成Slave冷备的问题,可以靠Proxy做读写分离来解决,当然这样会牺牲一部分的一致性。
4.优化方案总结
4.1 架构变迁
在解决上面各种问题时我们引入了三个组件:Proxy、Dashboard和Agent。这三个组件都担当一定的职责,但这三个组件不一定非要对应部署三个子系统。根据需要,可以选择去掉或合并来简化设计。
4.1.1 Proxy组件
从上面问题解决方案的分析可以看出,Proxy层的保留还是有其必要性的:
- 协议解析
- 实现Cluster协议,屏蔽影响
- 维护到后端的长连接
- 安全过滤
- 命令白名单
- 安全权限过滤
- 负载均衡
- Presharding哈希函数
- 缓存Slot路由表
- 控制Resharding算法和方式
- 结果聚合
- MultiOp支持
- Pipeline支持
- 读写分离
- 读压力分摊,避免Slave“冷备”
- 层次化存储
- 冷数据Swap到慢存储
- L1缓存实现
- 监控管理
- 状态的监控、历史报告
- 阈值的设置、预警
既然保留了Proxy组件,Redis Cluster的优势就不明显了。那为什么后端还要用Redis Cluster而不是单机版的Redis呢?因为Redis Cluster给我们带来几个最大的好处:
- 自动故障转移:不再需要额外的Sentinel集群
- 官方的Slot实现:不修改Redis源码就得到Slot实现及常用操作
- 被动保证Slot一致性:Redis负责访问了旧结点的客户端的重定向
- 迁移中的数据访问:Redis负责访问迁移中数据的客户端的重定向
4.1.2 Dashboard组件
一个美观而实用的Dashboard完全有理由让用户抛弃redis-trib,要是再具有自动部署和Resharding算法那就更完美了!
4.1.3 Agent组件
Agent不仅可以完成运行数据采集,仅仅这样的话Dashboard完全可以自己完成。它还可以完成Redis Cluster的部署工作,这样就能大大降低开发人员的工作量和手工出错的概率。
4.2 ZK去哪了?
Codis完全依赖ZooKeeper,进入到Redis Cluster后,ZooKeeper哪里去了?我们先回忆一下ZooKeeper在其中的角色,详情请参见《豆瓣Redis解决方案Codis源码剖析:Dashboard》:
- 保存Slot和Group映射
- 将Slot和Group的变化通知Proxy
- 迁移时与Proxy进行Pre-migrate确认
- 保存Migrate任务和进度信息
因为Redis Cluster的P2P架构,Slot与结点的映射关系都打散到集群中的各个结点上,所以第一个问题就解决了。又因为当客户端去旧结点请求数据时会收到MOVED或ASK消息进行重定向,就像是LAZY缓存过期策略一样,等访问时再更新或清除,所以第二和第三个问题也解决了。唯一要重点考虑的就是迁移任务这种Redis Cluster并不负责的全局信息的保存。
4.3 运维成本
关于如何降低Redis的运维成本,可以参考AliRedis和Reborndb。
4.3.1 阿里AliRedis
AliRedis是来自阿里巴巴的基于Redis改造的缓存产品,目前还未开源。网上只能搜到这么一篇资料《AliRedis单机180w QPS, 8台服务器构建1000w QPS Cache集群》。
AliRedis采取“多线程Master + N*Worker的工作模式。Master线程负责监听网络事件, 在接收到一个新的连接后, Master会把新的fd注册到Worker的epoll事件中, 交由worker处理这个fd的所有读写事件。这样Master线程就可以完全被释放出来接收更多的连接, 同时又不妨碍worker处理业务逻辑和IO读写。”
AliRedis对Redis架构上非常类似Nginx的Master-Worker架构模式,那Nginx中的Master进程都有哪些作用呢?(《Nginx工作进程模型》)
- 读取和校验配置文件
- 创建、绑定、关闭套接字
- 启动、终止、维护所配置数目的worker进程
- worker进程接受、处理来自客户端的连接
- 不中断服务刷新配置文件
- 不中断服务升级程序
- 反向代理和过滤功能
因此,每台服务器上由一个Master管理这台机器上的所有Redis实例,达到充分利用多核多线程。同时每台服务器只需维护一个AliRedis实例,大大降低运维成本的目的。也可以根据需要,实现类似Nginx中Master的各种功能。
4.3.2 豆瓣Reborndb
Reborndb基本是从Codis衍生出来的,但相比Codis多了一个Agent组件。agent主要是部署在Redis实例的机器上,类似AliRedis的Master,但Agent不负责处理请求。它负责监管Redis实例的生命周期,例如Redis部署、启动、停止、重启以及升级等等。它通过一套RESTFul接口来暴露这些操作。此外,它还担当着Redis高可用性协调者的角色,类似官方HA方案的Sentinel。
4.3.3 Master vs. Proxy
Master与Redis实例在一台机器上,Master负责建立连接,之后的I/O读写都交给Worker进程处理。因此,这与《Netty 4源码解析:请求处理》介绍过的主从Reactor模式里的主Reactor非常像!只不过Netty的模型是在一个进程里通过线程实现的,而AliRedis是类似Nginx用进程实现的。
而Proxy的责任要比Master大得多,它负责请求和响应处理的全过程,而不是建立连接后直接交给后端。所以Proxy的压力也不小,一般与Redis实例不部署在一台机器上。实际上,它与Master并不矛盾。Proxy模式负责解决协议解析、请求的过滤转发、结果聚合等问题,而Master-Worker模式则让Redis享受到多核的速度、不停机程序升级、降低运维成本等。
5.理想中的Redis
5.1 第二代Codis
Codis作者谈到第二代Codis,即Reborndb的发展方向,很值得学习:
“在开源Codis后,我们收到了很多社区的反馈,大多数的意见是集中在Zookeeper的依赖,Redis的修改,还有为啥需要Proxy上面,我们也在思考,这几个东西是不是必须的。当然这几个部件带来的好处毋庸置疑,上面也阐述过了,但是有没有办法能做得更漂亮。于是,我们在下一阶段会再往前走一步,实现以下几个设计:
1)使用proxy内置的Raft来代替外部的Zookeeper,zk对于我们来说,其实只是一个强一致性存储而已,我们其实可以使用Raft来做到同样的事情。将raft嵌入proxy,来同步路由信息。达到减少依赖的效果。
2)抽象存储引擎层,由proxy或者第三方的agent来负责启动和管理存储引擎的生命周期。具体来说,就是现在codis还需要手动的去部署底层的Redis或者qdb,自己配置主从关系什么的,但是未来我们会把这个事情交给一个自动化的agent或者甚至在proxy内部集成存储引擎。这样的好处是我们可以最大程度上的减小Proxy转发的损耗(比如proxy会在本地启动Redis instance)和人工误操作,提升了整个系统的自动化程度。
3)还有replication based migration。众所周知,现在Codis的数据迁移方式是通过修改底层Redis,加入单key的原子迁移命令实现的。这样的好处是实现简单、迁移过程对业务无感知。但是坏处也是很明显,首先就是速度比较慢,而且对Redis有侵入性,还有维护slot信息给Redis带来额外的内存开销。大概对于小key-value为主业务和原生Redis是1:1.5的比例,所以还是比较费内存的。在RebornDB中我们会尝试提供基于复制的迁移方式。
4)QDB:QDB使用LevelDB、RocksDB、GoLevelDB作为后端存储。我们喜欢Redis,并且希望超越它的局限,因此我们创建了一个服务叫做QDB,它兼容Redis,将数据保存在磁盘来越过内存大小的限制并且将热点数据保存在内存中以提高性能。”
除了第三点“基于复制的迁移”,这些改进思路在下面要介绍的Redis商业版(RLEC)中得到了印证。因为RLEC并未透露它的迁移实现方式,所以技术细节我们不得而知。
5.2 Redis商业版
Redis作者Salvatore Sanfilippo所在公司RedisLab提供了企业版的Redis产品——Redis Labs Enterprise Cluster (RLEC)——几乎解决了我们上述的所有问题:对客户端完全透明化,自动集群管理(伸缩、高可用、持久化等),多种监控和预警方式等等。
RLEC支持单结点(单主)、单结点主从(一主一从)、集群(多主)、高可用性的集群(多主多从)。从架构上看,RLEC集群的每个结点由以下组件组成:
- Zero-latency Proxy (Proxy):高性能的Proxy,隐藏后端存储路由和实现
- Cluster Manager (Agent):集群的部署、配置、管理
- Management UI (Dashboard):监控管理页面,提供RESTFul API,Web,CLI等多种管理方式
任意时刻,集群中会有一个结点处于”Master”角色,即这个结点上的Cluster Manager负责整个集群的管理工作,包括集群健康检查、分片迁移、请求监管等。由此能够看出,RLEC本身的结点之前也会互相通信,选举出一个主。
额外地,RLEC还支持一些比较高级的功能,如所有Key和热Value保存在RAM,Swap冷Value到SSD,Rack感知的集群等。RLEC可以免费下载试用,免费版只支持4个分片,而且不能用于生产环境。感兴趣的话,大家可以自己下载试用一下。
除了RLEC软件,RedisLab还提供了RedisCloud云,以公有云、私有云等服务的形式提供缓存服务——Redis as a Service (RaaS)。可以说,RLEC代表了一个比较理想的Redis产品方向。
Redis Cluster架构优化的更多相关文章
- Redis Cluster架构和设计机制简单介绍
之前另一篇文章也介绍了 Redis Cluster (link,在文章的后半部分) 今天看到这一篇,简单说一下(http://hot66hot.iteye.com/blog/2050676) 作者的目 ...
- [转帖]美团在Redis上踩过的一些坑-5.redis cluster遇到的一些问题
美团在Redis上踩过的一些坑-5.redis cluster遇到的一些问题 博客分类: redis 运维 redis clustercluster-node-timeoutfailover 转载请 ...
- Redis Cluster 理论知识
http://www.ttlsa.com/redis/redis-cluster-theoretical-knowledge/ Redis 集群的 TCP 端口(Redis Cluster TCP p ...
- Redis Cluster 实践
一:关于redis cluster 1:redis cluster的现状 reids-cluster计划在redis3.0中推出,可以看作者antirez的声明:http://antirez.com/ ...
- Redis中国用户组|唯品会Redis cluster大规模生产实践
嘉宾:陈群 很高兴有机会在Redis中国用户组给大家分享redis cluster的生产实践.目前在唯品会主要负责redis/hbase的运维和开发支持工作,也参与工具开发工作 Outline 一.生 ...
- redis cluster集群的原理
redis集群的概述: 在以前,如果前几年的时候,一般来说,redis如果要搞几个节点,每个节点存储一部分的数据,得借助一些中间件来实现,比如说有codis,或者twemproxy,都有.有一些red ...
- 关于redis的几件小事(十)redis cluster模式
redis cluster是redis提供的集群模式. 1.redis cluster的架构 ①可以有多个master node,每个master node 都可以挂载多个slave node. ②读 ...
- redis cluster介绍
讲解分布式数据存储的核心算法,数据分布的算法 hash算法 -> 一致性hash算法(memcached) -> redis cluster,hash slot算法 一.概述 1.我们的m ...
- Redis入门到高可用(二十)——Redis Cluster
一.呼唤集群 二.数据分布概论 三.哈希分布 1.节点取余 2.一致性哈希 添加一个node5节点时,只影响n1和n2之间的数据 3.虚拟槽分区 四.基本架构 五.redis clust ...
随机推荐
- TP-LINK | TL-WR842N设置无线转有线
首先点击右上角的"高级设置". 点击左侧的"无线设置"栏,点击"WDS无线桥接",然后一步步设置可以使路由器连接到当前的一个无线网络. 然后 ...
- 福利:100G Java全套学习视频免费送了
嗯 是的 众所周知 java工会自开办以来 一直致力于分享一些 java技术总结 学习方法..等等等 所以 从我做这个公众号以来 我的手机就没有消停过一天 因为 每天都有很多粉丝问我 "您好 ...
- 通过TCP实现显示屏截图请求及回传
在很多业务场景下,需要监视显示屏画面.在实时性要求不高的情况下,可以通过定时对显示屏进行截图及回传实现. 本文通过C#中提供的TCP通信功能,对该功能的实现进行简单描述. 首先,该功能的实现分为客户端 ...
- [C#]使用 Jenkins 为 .Net Core 实现持续集成/部署
在前后端分离开发的项目当中为了避免重复构建发布,我们需要部署一个持续发布环境,而目前的开发环境服务器都是基于 CentOS 的,因此每次在本地发布之后还需要打包,上传,部署,十分繁琐.故这里采用了比较 ...
- JEECG 新版在线文档WIKI正式发布
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/zhangdaiscott/article/details/80 JEECG 新版在线文档WIKI正式 ...
- [LeetCode] Flood Fill 洪水填充
An image is represented by a 2-D array of integers, each integer representing the pixel value of the ...
- webpack构建react项目(一)
前言 下面是我们使用到技术栈: webpack + react + redux + react-router + react-thunk + ES6 + .... 注意事项: 建议使用npm5.X 或 ...
- hdu 5441 (并查集)
题意:给你n个点,m条边构成无向图.q个询问,每次一个值,求有多少条路,路中的边权都小于这个值 a->b 和 b->a算两种 思路:把权值从小到大排序,询问从小到大排序,如果相连则用并查集 ...
- [bzoj4245][ONTAK2015]OR-XOR
来自FallDream的博客,未经允许,请勿转载,谢谢. 给定一个长度为n的序列a[1],a[2],...,a[n],请将它划分为m段连续的区间,设第i段的费用c[i]为该段内所有数字的异或和,则总费 ...
- [Noi2016]优秀的拆分
来自F allDream的博客,未经允许,请勿转载,谢谢. 如果一个字符串可以被拆分为 AABB 的形式,其中 A和 B是任意非空字符串,则我们称该字符串的这种拆分是优秀的. 例如,对于字符串 aab ...