redis_集群

1、为什么要弄redis集群

集群技术是构建高性能网站架构的重要手段,试想在网站承受高并发访问压力的同时,还需要从海量数据中查询出满足条件的数据,并快速响应,我们必然想到的是将数据进行切片,把数据根据某种规则放入多个不同的服务器节点,来降低单节点服务器的压力。上篇redis_主从我们讲到了 Redis 的主从复制技术,当实现了多节点的 master-slave 后,我们也可以把它叫做集群,但我们今天要讲的集群主要是利用切片技术来组建的集群。我们最后希望达到的是类似下图:

redis集群拓扑图

2、实现策略

因为从3.0开始以后官方已经支持了 redis cluster,http://redis.io/topics/cluster-tutorial

集群要实现的目的是要将不同的 key 分散放置到不同的 redis 节点,这里我们需要一个规则或者算法,通常的做法是获取 key 的哈希值,然后根据节点数来求模,但这种做法有其明显的弊端,当我们需要增加或减少一个节点时,会造成大量的 key 无法命中,这种比例是相当高的,所以就有人提出了一致性哈希的概念。

由于官方版本是基于哈希槽(hash slot)的概念来实现的,我们还是从其官方介绍中翻译解释一下:

Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value 时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。

使用哈希槽的好处就在于可以方便的添加或移除节点

当需要增加节点时,只需要把其他节点的某些哈希槽挪到新节点就可以了;

当需要移除节点时,只需要把移除节点上的哈希槽挪到其他节点就行了;

3、集群实现

对于我们来说,在新增或移除节点的能做到无缝(即不需要重启集群),这点它做到了。还是来看看具体的实现吧:


新建3个实例

新建redis_cluster文件夹下面新建6000、6100、6200三个文件夹。

把src 目录下面的redis-server、redis.conf这两个文件分别拷贝到这三个目录里面,拷贝完之后就像这样子了:

[mysql@localhost 6000]$ ll

-rw-rw-r--. 1 mysql mysql     116 Aug 21 05:37 redis.conf

-rwxrwxr-x. 1 mysql mysql 7820101 Aug 21 05:29 redis-server

修改每个目录下面的redis.conf文件因为我们启动的端口是不一样的,vi redis.conf删除里面的所有添加如下的:

daemonize yes   //指定以守护进程启动

port 6000     //启动端口

cluster-enabled yes

cluster-config-file nodes.conf

cluster-node-timeout 5000

appendonly yes

依次启动每一个实例文件夹下面的./redis-server ./redis.conf,这样的话3个实例就启动了,但是如何将3个实例维护成一个集群呢,在src目录下面执行:

./redis-trib.rb create --replicas 0 127.0.0.1:6000 127.0.0.1:6100 127.0.0.1:6200

执行以后是不是会发现执行失败提示没有redis-trib.rb文件,好吧我们还忘了装一个,因为我们执行的是ruby命令,所以还需要安装ruby:

https://rubygems.org/gems/redis下载,然后离线安装。sudo gem install redis-3.3.1.gem --local

安装完成以后再src目录下面就有了redis-trib.rb文件。

执行上面的集群命令控制台输出如下:

集群安装

来试试集群的效果吧:

在6000端口实例上测试

[mysql@localhost src]$ ./redis-cli -c -p 6000

127.0.0.1:6000> get name

-> Redirected to slot [5798] located at 127.0.0.1:6100       //发现当没有指定的key的时候会重定向到集群的其它机器去找

127.0.0.1:6100> set aaa 111

OK

127.0.0.1:6100> get aaa

"111"

//如上索性在6100实例的机器上面set aaa的值,然后在6200的机器上面去查

[mysql@localhost src]$ ./redis-cli -c -p 6200

127.0.0.1:6200> get aaa

-> Redirected to slot [10439] located at 127.0.0.1:6100   //发现重定向去6100的端口的实例上找到了结果

"111"

//在6200的机器上面直接重置aaa为1234

127.0.0.1:6200> set aaa 1234

-> Redirected to slot [10439] located at 127.0.0.1:6100  //还是重定向去6100的端口的实例上更新结果

OK

从上面的结果可以看出,集群中的节点是会进行通讯的,从而能找到不同的key在不同实例上,在机器固定的情况下,key唯一时后续对其的所有更新以及查询都会映射到这一台机器上面。

当然我们的集群的节点是不会一成不变的,我们随时有可能扩容、缩容那该怎么来实现呢?下面来讲讲集群节点的变化吧。

4、集群变更

我们先在上面的基础上试试添加端口为6300的实例,重复操作如上:

[mysql@localhost redis_cluster]$ mkdir 6300

[mysql@localhost redis_cluster]$ ll

total 16

drwxrwxr-x. 2 mysql mysql 4096 Aug 21 05:40 6000

drwxrwxr-x. 2 mysql mysql 4096 Aug 21 05:40 6100

drwxrwxr-x. 2 mysql mysql 4096 Aug 21 05:40 6200

drwxrwxr-x. 2 mysql mysql 4096 Aug 21 06:27 6300

[mysql@localhost redis_cluster]$ cp ../redis/redis-3.2.3/src/redis-server ../redis/redis-3.2.3/redis.conf 6300/

不要忘了修改redis.conf,具体配置如上文提到的。

[mysql@localhost 6300]$  ./redis-server ./redis.conf

[mysql@localhost 6300]$ netstat -an | grep 6300

tcp        0      0 0.0.0.0:16300               0.0.0.0:*                   LISTEN

tcp        0      0 0.0.0.0:6300                0.0.0.0:*                   LISTEN

tcp        0      0 :::16300                    :::*                        LISTEN

tcp        0      0 :::6300                     :::*                        LISTEN

新的redis实例已经启动好了,然后需要把它加到已有的集群啦:

./redis-trib.rb add-node 127.0.0.1:6300 127.0.0.1:6000

新的集群实例图

如上已经能查看到新的实例啦,为什么6300这个新的实例的connected后面没有分配hash槽呢,别慌我们还没有reshard

执行命令:./redis-trib.rb reshard 127.0.0.1:6300 

我们想从6000节点中分配1000个hash槽位出来:

摘自重新分配的一段操作日志

这样有hash槽了,当crc16(key) / 16384 的结果在该节点的所在区间时,数据就放在该节点上。

redis 采用的crc16算法详见:http://blog.csdn.net/guodongxiaren/article/details/44706613

如果后续有时间的话我也会找一个java版的crc16 demo.

如何为每一个主节点增加从节点呢?

好吧,先创建6400端口实例看看,具体新建文件夹以及配置和重启实例我就不再讲了,上面以及有了。

./redis-trib.rb add-node --slave 127.0.0.1:6400 127.0.0.1:6000

为集群的节点添加从节点

我们也可以试试在从节点6400上面做set操作:

127.0.0.1:6400> set da87

(error) ERR wrong number of arguments for 'set' command

127.0.0.1:6400> set da

(error) ERR wrong number of arguments for 'set' command

很不幸,确实不能做set操作会报错,从节点只能用于做读工作。

我们如何来删除一个节点呢:

[mysql@localhost src]$ ./redis-trib.rb del-node 127.0.0.1:6000 'eb868ce2c102b897ee0a48cd8893288c36bacf5c'

>>> Removing node eb868ce2c102b897ee0a48cd8893288c36bacf5c from cluster 127.0.0.1:6000

[ERR] Node 127.0.0.1:6000 is not empty! Reshard data away and try again.

[mysql@localhost src]$

我们发现删除6000端口的实例失败了,应该是上面还有一些数据如果直接删除就有数据丢失,我们应该把数据移到别的节点去:

./redis-trib.rb reshard 127.0.0.1:6000  //移除6000实例的数据

然后输出了很多信息,很多数值和ID都可以从这段信息中找到。

How many slots do you want to move (from 1 to 16384)? 5461

会问你要移动多少个哈希槽,我们把 6000上的所有哈希槽都移走,5461 这个数字可以从终端上看到,或许你的实际情况不是这个数字。

What is the receiving node ID? d4467ece7cca245345b71cc1f639508f4f7831c4  //选定移动到6300端口的实例上面,实例ID

Please enter all the source node IDs.

Type 'all' to use all the nodes as source nodes for the hash slots.

Type 'done' once you entered all the source nodes IDs.

Source node #1:eb868ce2c102b897ee0a48cd8893288c36bacf5c //选定移除掉6000端口的实例上面,实例ID

Source node #2:done

之后,redis 列出了重新分片计划,最后问你

Do you want to proceed with the proposed reshard plan (yes/no)? yes

中间有一些重新分配的刷屏信息省略。

[mysql@localhost src]$ ./redis-cli -p 6300

127.0.0.1:6300> keys *

1) "aaa"

127.0.0.1:6300>

数据移到6300实例上面啦,我们再来试试删除6000端口实例吧:

[mysql@localhost src]$ ./redis-trib.rb del-node 127.0.0.1:6000 'eb868ce2c102b897ee0a48cd8893288c36bacf5c'

>>> Removing node eb868ce2c102b897ee0a48cd8893288c36bacf5c from cluster 127.0.0.1:6000

>>> Sending CLUSTER FORGET messages to the cluster...

>>> SHUTDOWN the node.

[mysql@localhost src]$ ./redis-cli -c -p 6000

Could not connect to Redis at 127.0.0.1:6000: Connection refused

Could not connect to Redis at 127.0.0.1:6000: Connection refused

最终我们还是删除成功啦!维护一个redis集群就是这么简单。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351

推荐阅读更多精彩内容

  • 本文档翻译自 http://redis.io/topics/cluster-tutorial 。 本文档是 Red...
    会跳舞的机器人阅读 66,924评论 2 21
  • 前言 Redis 是我们目前大规模使用的缓存中间件,由于它强大高效而又便捷的功能,得到了广泛的使用。单节点的Red...
    Kevin_ZGJ阅读 11,675评论 19 133
  • 转自:https://www.zybuluo.com/phper/note/195558 前言 redis 是我们...
    yannhuang阅读 1,680评论 0 2
  • 开始部署之前,务必先看最后一条 从官网下载和编译redis安装包 配置redis创建redis.conf, 内容如...
    yandaren阅读 3,341评论 0 3
  • 日更第十二天 爱上写作,好像有二十余年了。 在那青葱年少轻狂的学生时期,好像就有这个想法和行动了,但没有持续,或者...
    白丰阁阅读 315评论 0 1