Redis cluster tutorial Redis集群教程 官方教程 翻译 (一)
官方教程原地址:
http://redis.io/topics/cluster-tutorial
这篇文档是一个总体介绍,不使用复杂的分布式概念.本文介绍如何建立一个集群,测试和使用,详细说明请参看RedisClusterspecification
注意,如果你打算实际使用Redis集群,推荐看正式的规范文档.
Redis集群现在还在alpha测试,请加入Redis邮件列表,或Githubrepository的讨论组.
*Redis集群101
Redis集群实现了数据自动分片于多个节点.
Redis集群不支持处理多个key,因为这可能需要在多个节点间移动数据,这样会使得性能下降.
Redis集群拥有一定程度的可用性,当一个节点挂掉或者不可访问时,集群可继续提供正确的服务.
所以在实际应用上,Redis集群可提供:
@自动分割数据集合在多个节点上;
@当某个节点挂掉或者不可访问时,集群继续正确地提供服务.
*Redis集群TCP端口
每个节点需要使用两个TCP端口.一个普通端口给客户端使用,比如6379,另外个则在这个数字上加1000,本例中也就是16379.
后者这个高位端口是作为集群总线用的,是节点对节点的二进制数据通信频道.集群总线用作节点间的宕机侦测,配置变更,故障转移认证等等.客户端应该不使用集群总线端口,而应该使用那个普通端口.确保这两个端口都没被防火墙禁掉,否则Redis集群会工作不正常.
普通端口和集群总线端口之间的差值固定是1000.
要使集群工作正常,注意以下两点:
1.普通端口(通常为6379)要对所有需要连接的客户端开放,也要对其他节点开放,为了key的迁移.
2.集群总线端口(普通端口+1000)必须对其他节点开放.
*Redis集群数据分片
Redis集群没使用一致性哈希,而用的是不同的分片方式,每个key都是hashslot的逻辑组成部分.
Redis集群有16384个hashslot,计算一个给定key的hashslot,则是把该key的CRC16值对16384取模.
集群中的每个节点覆盖hashslot的一部分,比如一个集群有3个节点,则:
@节点A覆盖0到5500;
@节点B覆盖5501到11000;
@节点C覆盖11001到16384.
这样使得添加和删除节点很容易.比如我想添加一个新节点D,则只要把一些hashslot从ABC挪到D.类似的,我想移除节点A,我只要把A下的slothash移到B和C,当节点A空了我就可以把A完全移除掉了.
因为移动hashsolt不需要停止节点的运行,所以添加删除节点,或者改变节点持有的hashslot百分比,都不会有什么宕机时间.
*Redis集群主从模式
当一个节点挂掉或者不可访问时,为了保证可用性,Redis集群使用了主从模式,一个主节点对应一个或多个从节点.
上面那个例子里,集群有ABC三个节点,如果B挂掉了,我们就没法访问5501到11000的hashslot了.
如果在集群建立的时候(或者建完后),我们为每个主节点都添加了从节点,比如像这样,集群包含主节点ABC,以及从节点A1B1C1,那么即使B挂掉系统也可以继续正确工作.
B1节点替代了B节点,所以Redis集群将会选择B1节点作为新的主节点,集群将会继续正确地提供服务。
不过需要注意,如果节点B和B1同时挂了,Redis集群就无法继续正确地提供服务了。
*Redis集群一致性保证
Redis集群无法保证强一致性。实际情况下这意味着,某些情况下Redis集群有可能会忘记一个已被系统接受的写操作。
Redis集群会丢失写操作的一个原因是它使用异步复制.这表示写操作包含以下几个步骤:
@客户端写数据到主节点B.
@主节点B回复客户端OK.
@主节点B传播本次写操作给它的从节点B1,B2和B3.
你可以发现,节点B并没有在回复客户端之前等待B1,B2和B3的接受,因为这将会造成很大的延迟.所以当客户端写入数据到B中,B接受了数据,但是在传播给它的从节点之前就挂了,那么被提升为主节点的某个从节点将会永久丢失这个写操作.
这很类似于数据库每时每刻刷新配置到磁盘,所以这种情况你应该已经了解,因为传统数据库系统并不涉及分布式.同样的,为了提高一致性,你可以在回复客户端之前强制刷新数据到磁盘,但是这通常会降低性能.
基本上,在一致性和性能之间,都需要权衡一下.
注意:Redis集群会在将来允许用户配置同步写操作,如果确实需要的话.
*创建和使用Redis集群
首先我们需要几个运行在集群模式下的Redis实例,最简单的配置文件包含以下几项:
port7000
cluster-enabledyes
cluster-config-filenodes.conf
cluster-node-timeout5000
appendonlyyes
可以看到启用集群主要依靠cluster-enabled配置项.每个Redis实例都包含一个文件,默认为nodes.conf.这个文件用户不用管,它是在Redis集群每个实例启动的时候自动生成的,以及在需要的时候自动更新的.
注意,最小的Redis集群需要包含至少3个主节点.头次试验,强烈建议创建6个节点,3个主节点,3个从节点.
如下步骤实现以上操作:进入一个新目录,然后创建以Redis实例端口号命名的目录,用以运行每一个Redis实例.
命令如下:
mkdircluster-test
cdcluster-test
mkdir700070017002700370047005
每个目录中都创建一个redis.conf文件.注意修改文件中的端口号.
现在把redis-server的可执行文件复制到cluster-test目录,然后打开6个shell终端.
启动每个实例,命令如下:
cd7000
../redis-server./redis.conf
你可以从每个实例的日志中看到,由于一开始没nodes.conf文件,所以每个节点分配了一个新ID.
[82462]26Nov11:56:55.329*Noclusterconfigurationfound,I'm97a3a64667477371c4479320d683e4c8db5858b1
以后每个实例就一直用自己头一次生成的ID了,每个节点都是通过ID来记住其他节点,而不是IP或端口号.IP地址和端口号会改变,但是ID是唯一的,不变的.这个叫做NodeID.
*创建集群
现在我们有了一些Redis实例在运行了,我们需要创建我们的Redis集群,通过对节点写入配置项来实现.
这很容易搞定,因为有个叫redis-trib的Redis集群命令行工具来帮忙,它是个Ruby程序,用来在Redis实例中执行特殊命令,比如创建一个集群,修改已存在的集群等等.
redis-trib工具在Redis的src目录中.以下命令用以创建Redis集群:
./redis-trib.rbcreate--replicas1127.0.0.1:7000127.0.0.1:7001\
127.0.0.1:7002127.0.0.1:7003127.0.0.1:7004127.0.0.1:7005
因为我们要新建集群,所以这里使用create命令.--replicas1参数表示为每个主节点创建一个从节点.其他参数是实例的地址集合.
很明显,我们的需求只是设置一个拥有3个主节点,3个从节点的集群.
Redis-trib会提示你做了什么配置,输入yes接受.集群就被配置和加入了,意思是,实例会经过互相交流后启动.一切都OK的话最终你会看到个信息类似于:
[OK]All16384slotscovered
这表示至少一个主节点覆盖到了全部16384个slot.
*使用集群
此时Redis集群的一个问题是客户端库的缺乏.
我知道的有以下几个客户端库实现:
@redis-rb-cluster,我(@antirez)用Ruby写的,作为一个其他语言的参考.它是原始redis-rb的简单包装,实现使用集群的最小功能.
@redis-py-cluster,
@流行的Predis支持Redis集群,这功能刚被开发.
@Java使用最多的Jedis最近开始支持Redis集群,请查看JedisCluster的README.
@redis-cli工具实现了一个基本的集群支持,启动时加上-c参数.
使用redis-cli方式,举个例子:
$redis-cli-c-p7000
redis127.0.0.1:7000>setfoobar
->Redirectedtoslot[12182]locatedat127.0.0.1:7002
OK
redis127.0.0.1:7002>sethelloworld
->Redirectedtoslot[866]locatedat127.0.0.1:7000
OK
redis127.0.0.1:7000>getfoo
->Redirectedtoslot[12182]locatedat127.0.0.1:7002
"bar"
redis127.0.0.1:7000>gethello
->Redirectedtoslot[866]locatedat127.0.0.1:7000
"world"
redis-cli仅支持最基础的功能,所以它一般只用来测试集群节点是否被正确地导向.一个严谨的客户端能更好地实现此功能,还能缓存hashslots和节点地址的映射,能把连接正确地导向到节点.这个映射只会在集群配置有变动时刷新,比如某节点挂掉,或者管理员添加删除了节点.
*使用redis-rb-cluster写一个示例程序
(待续)