因为Redis出众的性能,其在众多的移动互联网企业中获得普遍的应用。Redis在3.0版本前只支持单实例模式,虽然如今的服务器内存能够到100GB、200GB的规模,可是单实例模式限制了Redis无法知足业务的需求(例如新浪微博就曾经用Redis存储了超过1TB的数据)。Redis的开发者Antirez早在博客上就提出在Redis 3.0版本中加入集群的功能,但3.0版本等到2015年才发布正式版。各大企业在3.0版本还没发布前为了解决Redis的存储瓶颈,纷纷推出了各自的Redis集群方案。这些方案的核心思想是把数据分片(sharding)存储在多个Redis实例中,每一片就是一个Redis实例。算法
下面介绍Redis的集群方案。安全
1.客户端分片服务器
客户端分片是把分片的逻辑放在Redis客户端实现,经过Redis客户端预先定义好的路由规则,把对Key的访问转发到不一样的Redis实例中,最后把返回结果聚集。这种方案的模式如图1所示。架构
图1 客户端分片的模式负载均衡
客户端分片的好处是全部的逻辑都是可控的,不依赖于第三方分布式中间件。开发人员清楚怎么实现分片、路由的规则,不用担忧踩坑。运维
客户端分片方案有下面这些缺点。异步
这是一种静态的分片方案,须要增长或者减小Redis实例的数量,须要手工调整分片的程序。分布式
可运维性差,集群的数据出了任何问题都须要运维人员和开发人员一块儿合做,减缓了解决问题的速度,增长了跨部门沟通的成本。ide
在不一样的客户端程序中,维护相同的分片逻辑成本巨大。例如,系统中有两套业务系统共用一套Redis集群,一套业务系统用Java实现,另外一套业务系统用PHP实现。为了保证分片逻辑的一致性,在Java客户端中实现的分片逻辑也须要在PHP客户端实现一次。相同的逻辑在不一样的系统中分别实现,这种设计原本就很是糟糕,并且须要耗费巨大的开发成本保证两套业务系统分片逻辑的一致性。工具
2.Twemproxy
Twemproxy是由Twitter开源的Redis代理,其基本原理是:Redis客户端把请求发送到Twemproxy,Twemproxy根据路由规则发送到正确的Redis实例,最后Twemproxy把结果聚集返回给客户端。
Twemproxy经过引入一个代理层,将多个Redis实例进行统一管理,使Redis客户端只须要在Twemproxy上进行操做,而不须要关心后面有多少个Redis实例,从而实现了Redis集群。
Twemproxy集群架构如图2所示。
图2Twemproxy集群架构
Twemproxy的优势以下。
客户端像链接Redis实例同样链接Twemproxy,不须要改任何的代码逻辑。
支持无效Redis实例的自动删除。
Twemproxy与Redis实例保持链接,减小了客户端与Redis实例的链接数。
Twemproxy有以下不足。
因为Redis客户端的每一个请求都通过Twemproxy代理才能到达Redis服务器,这个过程当中会产生性能损失。
没有友好的监控管理后台界面,不利于运维监控。
最大的问题是Twemproxy没法平滑地增长Redis实例。对于运维人员来讲,当由于业务须要增长Redis实例时工做量很是大。
Twemproxy做为最被普遍使用、最久经考验、稳定性最高的Redis代理,在业界被普遍使用。
3.Codis
Twemproxy不能平滑增长Redis实例的问题带来了很大的不便,因而豌豆荚自主研发了Codis,一个支持平滑增长Redis实例的Redis代理软件,其基于Go和C语言开发,并于2014年11月在GitHub上开源。
Codis包含下面4个部分。
Codis Proxy:Redis客户端链接到Redis实例的代理,实现了Redis的协议,Redis客户端链接到Codis Proxy进行各类操做。Codis Proxy是无状态的,能够用Keepalived等负载均衡软件部署多个Codis Proxy实现高可用。
CodisRedis:Codis项目维护的Redis分支,添加了slot和原子的数据迁移命令。Codis上层的 Codis Proxy和Codisconfig只有与这个版本的Redis通讯才能正常运行。
Codisconfig:Codis管理工具。能够执行添加删除CodisRedis节点、添加删除Codis Proxy、数据迁移等操做。另外,Codisconfig自带了HTTP server,里面集成了一个管理界面,方便运维人员观察Codis集群的状态和进行相关的操做,极大提升了运维的方便性,弥补了Twemproxy的缺点。
ZooKeeper:分布式的、开源的应用程序协调服务,是Hadoop和Hbase的重要组件,其为分布式应用提供一致性服务,提供的功能包括:配置维护、名字服务、分布式同步、组服务等。Codis依赖于ZooKeeper存储数据路由表的信息和Codis Proxy节点的元信息。另外,Codisconfig发起的命令都会经过ZooKeeper同步到CodisProxy的节点。
Codis的架构如图3所示。
图3Codis的架构图
在图3的Codis的架构图中,Codis引入了Redis Server Group,其经过指定一个主CodisRedis和一个或多个从CodisRedis,实现了Redis集群的高可用。当一个主CodisRedis挂掉时,Codis不会自动把一个从CodisRedis提高为主CodisRedis,这涉及数据的一致性问题(Redis自己的数据同步是采用主从异步复制,当数据在主CodisRedis写入成功时,从CodisRedis是否已读入这个数据是无法保证的),须要管理员在管理界面上手动把从CodisRedis提高为主CodisRedis。
若是以为麻烦,豌豆荚也提供了一个工具Codis-ha,这个工具会在检测到主CodisRedis挂掉的时候将其下线并提高一个从CodisRedis为主CodisRedis。
Codis中采用预分片的形式,启动的时候就建立了1024个slot,1个slot至关于1个箱子,每一个箱子有固定的编号,范围是1~1024。slot这个箱子用做存放Key,至于Key存放到哪一个箱子,能够经过算法“crc32(key)%1024”得到一个数字,这个数字的范围必定是1~1024之间,Key就放到这个数字对应的slot。例如,若是某个Key经过算法“crc32(key)%1024”获得的数字是5,就放到编码为5的slot(箱子)。1个slot只能放1个Redis Server Group,不能把1个slot放到多个Redis Server Group中。1个Redis Server Group最少能够存放1个slot,最大能够存放1024个slot。所以,Codis中最多能够指定1024个Redis Server Group。
Codis最大的优点在于支持平滑增长(减小)Redis Server Group(Redis实例),能安全、透明地迁移数据,这也是Codis 有别于Twemproxy等静态分布式 Redis 解决方案的地方。Codis增长了Redis Server Group后,就牵涉到slot的迁移问题。例如,系统有两个Redis Server Group,Redis Server Group和slot的对应关系以下。
Redis Server Group |
slot |
1 |
1~500 |
2 |
501~1024 |
当增长了一个Redis Server Group,slot就要从新分配了。Codis分配slot有两种方法。
第一种:经过Codis管理工具Codisconfig手动从新分配,指定每一个Redis Server Group所对应的slot的范围,例如能够指定Redis Server Group和slot的新的对应关系以下。
Redis Server Group |
slot |
1 |
1~500 |
2 |
501~700 |
3 |
701~1024 |
第二种:经过Codis管理工具Codisconfig的rebalance功能,会自动根据每一个Redis Server Group的内存对slot进行迁移,以实现数据的均衡。
4.Redis 3.0集群
Redis 3.0集群采用了P2P的模式,彻底去中心化。Redis把全部的Key分红了16384个slot,每一个Redis实例负责其中一部分slot。集群中的全部信息(节点、端口、slot等),都经过节点之间按期的数据交换而更新。
Redis客户端在任意一个Redis实例发出请求,若是所需数据不在该实例中,经过重定向命令引导客户端访问所需的实例。
Redis 3.0集群的工做流程如图4所示。
图4Redis 3.0集群的工做流程图
如图4所示Redis集群内的机器按期交换数据,工做流程以下。
(1) Redis客户端在Redis2实例上访问某个数据。
(2) 在Redis2内发现这个数据是在Redis3这个实例中,给Redis客户端发送一个重定向的命令。
(3) Redis客户端收到重定向命令后,访问Redis3实例获取所需的数据。
Redis 3.0的集群方案有如下两个问题。
一个Redis实例具有了“数据存储”和“路由重定向”,彻底去中心化的设计。这带来的好处是部署很是简单,直接部署Redis就行,不像Codis有那么多的组件和依赖。但带来的问题是很难对业务进行无痛的升级,若是哪天Redis集群出了什么严重的Bug,就只能回滚整个Redis集群。
对协议进行了较大的修改,对应的Redis客户端也须要升级。升级Redis客户端后谁能确保没有Bug?并且对于线上已经大规模运行的业务,升级代码中的Redis客户端也是一个很麻烦的事情。
综合上面所述的两个问题,Redis 3.0集群在业界并无被大规模使用。
5.云服务器上的集群服务
国内的云服务器提供商阿里云、UCloud等均推出了基于Redis的云存储服务。
这个服务的特性以下。
(1)动态扩容
用户能够经过控制面板升级所需的Redis存储空间,扩容的过程当中服务部不须要中断或中止,整个扩容过程对用户透明、无感知,这点是很是实用的,在前面介绍的方案中,解决Redis平滑扩容是个很烦琐的任务,如今按几下鼠标就能搞定,大大减小了运维的负担。
(2)数据多备
数据保存在一主一备两台机器中,其中一台机器宕机了,数据还在另一台机器上有备份。
(3)自动容灾
主机宕机后系统能自动检测并切换到备机上,实现服务的高可用。
(4)实惠
不少状况下为了使Redis的性能更高,须要购买一台专门的服务器用于Redis的存储服务,但这样子CPU、内存等资源就浪费了,购买Redis云存储服务就很好地解决了这个问题。
有了Redis云存储服务,能使App后台开发人员从烦琐运维中解放出来。App后台要搭建一个高可用、高性能的Redis服务,须要投入至关的运维成本和精力。若是使用云存储服务,就不必投入这些成本和精力,可让App后台开发人员更专一于业务。