此篇简要介绍一下Redis的集群代理方案:Twemproxy。
背景
Redis单实例内存容量有限,为了提高系统承载能力,就必须使用到Redis集群
根据执行分片的位置,可以分为三种分片方式:
集群技术
1. 客户端分片
- 客户端分片:客户端使用一致性哈希等算法决定应当分布到哪个节点。
- 由业务方的程序代码设置路由规则,直接对多个Redis实例进行分布式访问
- 优点是可以灵活调整路由规则,另外性能比代理方式好一些(少了一个中间分发的环节)
- 缺点是Redis实例数量变化时需要手动调整分片,升级麻烦,可运维性较差
2. 代理分片
- 代理分片:将客户端的请求发送到代理上,由代理转发到正确的节点上。
- 通过增加一个对业务方使用透明的代理层,来执行分片工作
- 增加代理层虽然带来了一些多余的性能损耗,但是可以容忍
- 基于该机制的开源产品Twemproxy
3. 服务器分片:Redis Cluster
- 没有中心节点(和代理模式的重要不同之处)
- Redis Cluster将所有Key映射到多个Slot中,集群中每个Redis实例负责一部分,业务程序通过集成的Redis Cluster客户端进行操作。客户端可以向任一实例发出请求,如果所需数据不在该实例中,则该实例引导客户端自动去对应实例读写数据。
- 缺点是这是一个非常重的方案,Redis Cluster的成员管理(节点名称、IP、端口、状态、角色)等,都通过节点之间两两通讯,定期交换并更新,缺少了Redis单例的“简单、可依赖”的特点
1. Twemproxy
Twemproxy是Twitter公司开发的,代理分片构建Redis集群的一个开源解决方案
优势
- 单线程工作,用C语言开发
- 直接支持大部分Redis指令,对于业务层可以透明使用
- 应用层不必关心连接失败,,由代理负责重连
- 代理后边的升级,前端不关心,解决了HA的问题
- 把Hash算法放到了代理上做,路由策略多样,支持HashTag, 通过HashTag可以自己设定将同一类型的key映射到同一个实例上去
- 减少与redis的直接连接数,保持与redis的长连接,可设置代理与后台每个redis连接的数目
- 自带一致性hash算法,能够将数据自动分片到后端多个redis实例上
- 支持redis pipelining request,将多个连接请求,组成reids pipelining统一向redis请求
高效,对连接的管理采用epoll机制,内部数据传输采用“Zero Copy”技术,以提高运行效率
高可用方案
因为Twemproxy本身是单点,所以需要用Keepalived做高可用方案
Keepalived是一种实现高可用的方案,它的功能主要包括两方面:
- 通过IP漂移,实现服务的高可用:服务器集群共享一个虚拟IP,同一时间只有一个服务器占有虚拟IP并对外提供服务,若该服务器不可用,则虚拟IP漂移(VIP自动切换的过程就称为IP漂移)至另一台服务器并对外提供服务
- 对LVS应用服务层的应用服务器集群进行状态监控:若应用服务器不可用,则keepalived将其从集群中摘除,若应用服务器恢复,则keepalived将其重新加入集群中
性能
经过一层代理后,官方给出的极限情况性能下降20%
2. Codis
Codis是由豌豆荚于2014年11月开源的一种Redis集群解决方案。
组成
Codis是一个代理中间件,使用Go语言开发。其分为四个部分:
1. Codis Proxy (codis-proxy)
2. Codis Dashboard (codis-config)
3. Codis Redis (codis-server)
4. ZooKeeper/Etcd
优劣
Codis和Twemproxy最大的区别有两个:
- Codis支持动态水平扩展,对Client完全透明不影响服务的情况下可以完成增减redis实例的操作
- Codis是用Go语言写的并支持多线程而Twemproxy用C并只用单线程
第2条又意味着:Codis在多核机器上的性能会好于Twemproxy,Codis的最坏响应时间可能会因为GC的STW而变大,不过Go1.5发布后会显著降低STW的时间;如果只用一个CPU的话Go语言的性能不如C,因此在一些短连接而非长连接的场景中,整个系统的瓶颈可能变成Accept新Tcp连接的速度,这时Codis的性能可能会差于Twemproxy。
- 虽然Redis是单线程的,但Codis Proxy是多线程的(严格来说是goroutine), 启动的线程数是CPU的核数,是可以充分利用起多核的性能的
使用注意事项
官方的建议是单个集合的总容量不要超过1M,否则在迁移的时候会有卡顿感
3. Redis Cluster
客户端分片、Redis Cluster属于无中心化的集群方案,Codis、Tweproxy属于中心化的集群方案。
- 采用中间加一层Proxy的中心化模式时,对Proxy的要求很高。因为Proxy一旦出现故障,那么操作这个Proxy的所有客户端都无法处理。要想实现Proxy的高可用,还需要另外的机制来实现,例如Keepalive。
- 另外,增加一层Proxy进行转发,必然会有一定的性能损耗。
- 除了客户端分片和上面提到的中心化的方案之外,还有比较好的解决方案么?Redis官方推出的Redis Cluster另辟蹊径,它没有采用中心化模式的Proxy方案,而是把请求转发逻辑一部分放在客户端,一部分放在了服务端,它们之间互相配合完成请求的处理。
- Redis把请求转发的逻辑放在了Smart Client中,要想使用Redis Cluster,必须升级Client SDK,这个SDK中内置了请求转发的逻辑,所以业务开发人员同样不需要自己编写转发规则,Redis Cluster采用16384个槽位进行路由规则的转发。
- Redis Cluster也提供了在线数据迁移、节点扩容缩容等功能,内部还内置了哨兵完成故障自动恢复功能,可见它是一个集成所有功能于一体的Cluster。因此它在部署时非常简单,不需要部署过多的组件,对于运维极其友好。
- Redis Cluster在节点数据迁移、扩容缩容时,对于客户端的请求处理也做了相应的处理。当客户端访问的数据正好在迁移过程中时,服务端与客户端制定了一些协议,来告知客户端去正确的节点上访问,帮助客户端订正自己的路由规则。
- 虽然Redis Cluster提供了在线数据迁移的功能,但它的迁移性能并不高,迁移过程中遇到大key时还有可能长时间阻塞迁移的两个节点,这个功能相较于Codis来说,Codis数据迁移性能更好。