Redis集群方案

前段时间搞了搞Redis集群,想用做推荐系统的线上存储,说来挺有趣,这边基础架构不太完善,因此需要我们做推荐系统的自己来搭这个存储环境,就自己折腾了折腾。公司所给机器的单机性能其实挺给力,已经可以满足目前的业务需求,想做redis集群主要有以下几点考虑:

    1、扩展性,scale-out,以后数据量变得很大之后,不至于推到重来,redis虽然可以开启虚拟内存功能,单机也能提供超过物理内存上限的容量,但频繁在内存和硬盘间swap页会大大降低其性能,有点儿违背redis的设计初衷。

    2、redis是一个单线程io复用的结构,无法有效利用服务器的多核结构,如果能在一台多核机器起多个redis进程,共同提供服务,效率会更高一些。

    3、主从,数据备份和容灾。。

因此计划做的redis集群希望可以实现以下功能:

    1、data sharding,支持数据切片。

    2、主从备份,主节点写数据,主和从都提供读请求服务,并且支持主从自动切换。

    3、读请求做负载均衡。

    4、更好地,支持节点failover,数据自动迁移。

下面是前后经历的一个过程:

【第一步】尝试官方方案

   肯定想去查看一下redis的官方集群方案,但是很遗憾,官方对cluster的声明如下:

Unfortunately Redis Cluster is currently not production ready, however you can get more information about it reading the specification or checking the partial implementation in the unstable branch of the Redis GitHub repositoriy.

Once Redis Cluster will be available, and if a Redis Cluster complaint client is available for your language, Redis Cluster will be the de facto standard for Redis partitioning.

Redis Cluster is a mix between query routing and client side partitioning.

  由于这边想做生产环境部署,unstable branch目前还是不敢用,在官方目前的版本上做提前开发又没有资源和时间,因此就放弃了。

【第二步】初步设想的方案

   舍弃了官方的方案后,就想能不能自己搭一个,当时初步的想法是:用lvs做读请求的负载均衡,在客户端代码里自己写一个一致性hash算法做数据切片,配置redis主从,并且配置keepalived做主从自动切换。这个方案应该可以施行的,但当时自己遇到一些细节方面的问题,就在stackoverflow上问了一下,问题如下:

Since the redis cluster is still a work in progress, I want to build a simplied>Redis集群方案

图中画的挺明白了,就不再多解释了。

twemproxy是twitter开源的一个数据库代理服务,可以用于memcached和redis的sharding,兼容二者的标准接口,但是对于redis的keys,dbsize等命令不支持,这个其实想一下也就明白了,这种pool内跨机做统计的命令proxy一般不会支持的。另外,twemproxy在自身与后台redis之间使用pipeline发送命令,因此性能损失比较小。但是,twemproxy对于每一个客户端连接开启的mbuf有限,最大可以设置为64k,如果在客户端代理层与twemproxy之间也使用pipeline,这个pipeline不能太深,而且不支持pipeline的原子性(transaction),其实,这个时候,相当于客户端连接与redis数据库之间存在两层pipeline,分别是客户端到twemproxy的pipeline,和twemproy到后台redis服务器的pipeline,由于二者buffer深度不一致,因此不支持pipeline的transaction也就好理解了。。在引入了twemproxy,插入大规模数据的时候,有时候确实挺耗时,而且pipeline不保证原子性,丢数据时的恢复问题在客户端需要进行额外关注。对于非transaction的pipeline总丢数据,或者对于数据量比较大的key一次性取数据失败等问题,后来经查是twemproxy端timeou值设置过小,按照官方示例设置400ms,会在一次性操作大数据量的时候返回timeout失败,这个数值需要慎重根据业务(具体的,就是客户端单次命令操作的数据量)进行设置,一般2000ms差不多就够用了(可以支持一次操作接近百万的数据)。

上面的结构,将读操作的负载均衡放到了客户端代码来做,写操作控制也在客户端层的代码里,另外,对于twemproy单点、主从之间可以引入keepalived来消除单点和故障恢复。

Redis集群方案

扫一扫手机访问