Redis 集群应用学习.docx
《Redis 集群应用学习.docx》由会员分享,可在线阅读,更多相关《Redis 集群应用学习.docx(15页珍藏版)》请在冰豆网上搜索。
![Redis 集群应用学习.docx](https://file1.bdocx.com/fileroot1/2023-1/6/6cbce05d-5a6c-4708-99c6-00fbbe1747d2/6cbce05d-5a6c-4708-99c6-00fbbe1747d21.gif)
Redis集群应用学习
集群技术是构建高性能网站架构的重要手段,试想在网站承受高并发访问压力的同时,还需要从海量数据中查询出满足条件的数据,并快速响应,我们必然想到的是将数据进行切片,把数据根据某种规则放入多个不同的服务器节点,来降低单节点服务器的压力。
上一篇我们讲到了Redis的主从复制技术,当实现了多节点的master-slave后,我们也可以把它叫做集群,但我们今天要讲的集群主要是利用切片技术来组建的集群。
集群要实现的目的是要将不同的key分散放置到不同的redis节点,这里我们需要一个规则或者算法,通常的做法是获取key的哈希值,然后根据节点数来求模,但这种做法有其明显的弊端,当我们需要增加或减少一个节点时,会造成大量的key无法命中,这种比例是相当高的,所以就有人提出了一致性哈希的概念。
一致性哈希有四个重要特征:
均衡性:
也有人把它定义为平衡性,是指哈希的结果能够尽可能分布到所有的节点中去,这样可以有效的利用每个节点上的资源。
单调性:
对于单调性有很多翻译让我非常的不解,而我想要的是当节点数量变化时哈希的结果应尽可能的保护已分配的内容不会被重新分派到新的节点。
分散性和负载:
这两个其实是差不多的意思,就是要求一致性哈希算法对key哈希应尽可能的避免重复。
但一致性哈希不是我们今天要介绍的重点,因为Redis引入另一种哈希槽(hashslot)的概念。
Redis集群中内置了16384个哈希槽,当需要在Redis集群中放置一个key-value时,redis先对key使用crc16算法算出一个结果,然后把结果对16384求余数,这样每个key都会对应一个编号在0-16383之间的哈希槽,redis会根据节点数量大致均等的将哈希槽映射到不同的节点。
使用哈希槽的好处就在于可以方便的添加或移除节点。
当需要增加节点时,只需要把其他节点的某些哈希槽挪到新节点就可以了;
当需要移除节点时,只需要把移除节点上的哈希槽挪到其他节点就行了;
内部机制,与我何干,对于我们来说,在新增或移除节点的时候不要让我们先停掉所有的redis服务我就谢天谢地了,这点它做到了。
下面我们就开始动手搭建一个redis集群来体验一下。
因为我们要启动多个redis实例,虽然我们可以直接通过命令行来启动,但始终是不怎么方便的,所以我们先来新建三个实例目录,分别是9001,9002,9003,目录名就是redis实例的端口号。
我这里已经建好了目录,然后我们把以前编译过和修改过的redis-server、redis.conf这两个文件分别拷贝到这三个目录里面,拷贝完之后就像这样子了:
我们打开redis.conf文件,为了简单起见,我们只保留下面几个配置项:
daemonizeyes
port9001
cluster-enabledyes
cluster-config-filenodes.conf
cluster-node-timeout5000
appendonlyyes
注意:
port要修改成对应目录的名字,也就是每个实例要有不同的端口。
下面我们分别启动这三个实例:
zhaoguihuadediannao:
~zhaogh$cdapplications/dev/redis-cluster
zhaoguihuadediannao:
redis-clusterzhaogh$cd9001
zhaoguihuadediannao:
9001zhaogh$./redis-server./redis.conf
zhaoguihuadediannao:
9003zhaogh$cd../9002
zhaoguihuadediannao:
9002zhaogh$./redis-server./redis.conf
zhaoguihuadediannao:
9002zhaogh$cd../9003
zhaoguihuadediannao:
9003zhaogh$./redis-server./redis.conf
zhaoguihuadediannao:
9003zhaogh$
接下来我们来创建集群,让三个实例互相通讯:
zhaoguihuadediannao:
srczhaogh$./redis-trib.rbcreate--replicas0127.0.0.1:
9001127.0.0.1:
9002127.0.0.1:
9003
>>>Creatingcluster
Connectingtonode127.0.0.1:
9001:
OK
Connectingtonode127.0.0.1:
9002:
OK
Connectingtonode127.0.0.1:
9003:
OK
>>>Performinghashslotsallocationon3nodes...
Using3masters:
127.0.0.1:
9001
127.0.0.1:
9002
127.0.0.1:
9003
M:
92c9912cb1ccf657c886ecd839dd32c66efd8762127.0.0.1:
9001
slots:
0-5460(5461slots)master
M:
b6d46fcb8b0e6ee373b09a4f2cbcec744d1a259b127.0.0.1:
9002
slots:
5461-10922(5462slots)master
M:
44ab30c7c589ffb15b9b04dd827c72cfaeedacb2127.0.0.1:
9003
slots:
10923-16383(5461slots)master
CanIsettheaboveconfiguration?
(type'yes'toaccept):
yes
>>>Nodesconfigurationupdated
>>>Assignadifferentconfigepochtoeachnode
>>>SendingCLUSTERMEETmessagestojointhecluster
Waitingfortheclustertojoin..
>>>PerformingClusterCheck(usingnode127.0.0.1:
9001)
M:
92c9912cb1ccf657c886ecd839dd32c66efd8762127.0.0.1:
9001
slots:
0-5460(5461slots)master
M:
b6d46fcb8b0e6ee373b09a4f2cbcec744d1a259b127.0.0.1:
9002
slots:
5461-10922(5462slots)master
M:
44ab30c7c589ffb15b9b04dd827c72cfaeedacb2127.0.0.1:
9003
slots:
10923-16383(5461slots)master
[OK]Allnodesagreeaboutslotsconfiguration.
>>>Checkforopenslots...
>>>Checkslotscoverage...
[OK]All16384slotscovered.
zhaoguihuadediannao:
srczhaogh$
需要注意的是执行 redis-trib.rb命令需要ruby的支持,如果你没有安装可以先到 https:
//rubygems.org/gems/redis 下载,然后离线安装。
sudogeminstallredis-3.0.7.gem--local
下面我们用redis自带的客户端测试一下:
zhaoguihuadediannao:
srczhaogh$./redis-cli-c-p9001
127.0.0.1:
9001>gettestkey001
->Redirectedtoslot[12786]locatedat127.0.0.1:
9003
(nil)
127.0.0.1:
9003>settestkey002testvalue002
->Redirectedtoslot[401]locatedat127.0.0.1:
9001
OK
127.0.0.1:
9001>gettestkey002
"testvalue002"
127.0.0.1:
9001>settestkey003testvalue003
OK
127.0.0.1:
9001>
可以看到,虽然我们第一次连接的是9001端口,当我们去获取testkey001的时候,rediscluster自动帮我们重定向到9003。
当我们在9003设置testkey002时,rediscluster又重定向到9001。
总的来说,redis集群部署起来还是非常方便的,遗憾的是,目前几乎还没有c#的客户端能很好的支持redis集群,真是非常的悲哀,我们期待他们的更新。
下一遍中,我们继续讨论redis集群,比如,如何增加节点,移除节点,重新切片等,敬请期待。
Redis集群(中)
昨天晚上钓鱼回来,大发神经,写了篇概括程序员生活现状的文章,没想到招来众多人的口诛笔伐,大有上升到政治层面的趋势。
我也许不会再发表任何冲击心灵的文章,我希望给大家带来更多的正能量,所以那篇文章已被我删除。
我的本意只是想让各位看过文章之后能冷静地思考自己的程序人生,不管是对是错,人都有选择的权力,走好自己的路。
我没有你们想象中那么悲观,我也在不懈的努力,哪怕一时的跌倒,我也要重新站起。
生活无时无刻不是压力,让我们背起行囊,迈出踏实的一步,走起!
我们继续我们的redis缓存之旅。
前一篇我们实现了一个简单的redis集群,redis也为了让我们方便的维护集群提供了非常好的工具。
首先请大家参照我的上一篇文章,把集群环境搭建起来。
OK,我用了分分钟的时间已经搭建好了。
[OK]All16384slotscovered.
zhaoguihuadediannao:
srczhaogh$./redis-cli-c-p9001
127.0.0.1:
9001>gettestkey001
->Redirectedtoslot[12786]locatedat127.0.0.1:
9003
(nil)
127.0.0.1:
9003>
如何增加节点:
首先我们创建一个叫做9004的目录:
zhaoguihuadediannao:
redis-clusterzhaogh$mkdir9004
zhaoguihuadediannao:
redis-clusterzhaogh$
接着我们将9001目录下的redis-server、redis.conf两个文件拷贝到9004目录:
zhaoguihuadediannao:
redis-clusterzhaogh$cp9001/redis-server9004
zhaoguihuadediannao:
redis-clusterzhaogh$cp9001/redis.conf9004
然后我们打开redis.conf文件修改里面的端口配置项,将其改为9004。
启动9004实例:
zhaoguihuadediannao:
redis-clusterzhaogh$cd9004
zhaoguihuadediannao:
9004zhaogh$./redis-server./redis.conf
zhaoguihuadediannao:
9004zhaogh$
想要把这个实例加入到集群,我们只需要执行redis-trib.rb命令:
zhaoguihuadediannao:
srczhaogh$./redis-trib.rbadd-node127.0.0.1:
9004127.0.0.1:
9001
第一个参数是我们刚才启动的新实例,第二个参数是集群中已有的节点。
检查一下新节点是否已经加入:
zhaoguihuadediannao:
srczhaogh$./redis-cli-c-p9001
127.0.0.1:
9001>clusternodes
0e8f980bfe7a682e3d71b15523a41293535b8ccd:
0myself,master-001connected0-5460
cbb01bdfdc265b190496956354d84aaae6e7d54d127.0.0.1:
9004master-014019523163460connected
708e6e14474e3a99677b05ff89bd857375884437127.0.0.1:
9002master-014019523143252connected5461-10922
a7f9d3c64540cc3fc8cd3072e573bb8ab0bf1e6f127.0.0.1:
9003master-014019523153343connected10923-16383
127.0.0.1:
9001>
我们可以发现9004并不包含任何哈希槽,因为它还没有数据。
我们还可以为集群中的主节点增加从节点用于只读查询。
如何增加从节点:
我们还是要创建目录,拷贝那两个文件,修改配置,然后启动实例:
zhaoguihuadediannao:
redis-clusterzhaogh$mkdir9005
zhaoguihuadediannao:
redis-clusterzhaogh$cp9001/redis-server9005
zhaoguihuadediannao:
redis-clusterzhaogh$cp9001/redis.conf9005
修改port为9005
zhaoguihuadediannao:
redis-clusterzhaogh$cd9005
zhaoguihuadediannao:
9005zhaogh$./redis-server./redis.conf
zhaoguihuadediannao:
9005zhaogh$
执行下面的命令,增加从节点:
zhaoguihuadediannao:
srczhaogh$./redis-trib.rbadd-node--slave127.0.0.1:
9005127.0.0.1:
9001
第一个参数为从节点,第二个参数为主节点。
如何删除一个节点:
zhaoguihuadediannao:
srczhaogh$./redis-trib.rbdel-node127.0.0.1:
9001'cbb01bdfdc265b190496956354d84aaae6e7d54d'
这里要注意一下,第一个参数是集群中的任何一个主节点地址,而第二个参数是要删除节点的ID,这个ID如果你不知道的话,可以通过clusternodes命令查看。
还有一点就是要删除的节点必须是空的,也就是不能缓存任何数据,否则会删除不成功。
对于非空节点,在删除之前需要重新分片,将缓存的数据转移到别的节点。
如何重新分片:
我们先给某个节点做点数据:
zhaoguihuadediannao:
srczhaogh$./redis-cli-c-p9001
127.0.0.1:
9001>settestkey001testvalue001
->Redirectedtoslot[12786]locatedat127.0.0.1:
9003
OK
127.0.0.1:
9003>
现在9003上已经有数据了,我们尝试删除一下:
zhaoguihuadediannao:
srczhaogh$./redis-trib.rbdel-node127.0.0.1:
9001'78ec1fd6647b79627d7c29bb2b22d04a4a6c43b3'
>>>Removingnode78ec1fd6647b79627d7c29bb2b22d04a4a6c43b3fromcluster127.0.0.1:
9001
Connectingtonode127.0.0.1:
9001:
OK
Connectingtonode127.0.0.1:
9002:
OK
Connectingtonode127.0.0.1:
9003:
OK
[ERR]Node127.0.0.1:
9003isnotempty!
Resharddataawayandtryagain.
zhaoguihuadediannao:
srczhaogh$
没有删除成功,我们来重新分片,把9003上的数据转移:
zhaoguihuadediannao:
srczhaogh$./redis-trib.rbreshard127.0.0.1:
9003
然后输出了很多信息,很多数值和ID都可以从这段信息中找到。
Howmanyslotsdoyouwanttomove(from1to16384)?
5461
会问你要移动多少个哈希槽,我们把9003上的所有哈希槽都移走,5461这个数字可以从终端上看到,或许你的实际情况不是这个数字。
WhatisthereceivingnodeID?
4d2e0a8360795ce7ce8381c68746034aeba3c9b9
然后问你你要把这些哈希槽移到哪儿去,我指定了9001的节点ID。
PleaseenterallthesourcenodeIDs.
Type'all'touseallthenodesassourcenodesforthehashslots.
Type'done'onceyouenteredallthesourcenodesIDs.
Sourcenode#1:
78ec1fd6647b79627d7c29bb2b22d04a4a6c43b3
Sourcenode#2:
done
之后,redis列出了重新分片计划,最后问你
Doyouwanttoproceedwiththeproposedreshardplan(yes/no)?
yes
执行完成后,我们看看9003上还有没有key:
zhaoguihuadediannao:
srczhaogh$./redis-cli-p9003
127.0.0.1:
9003>keys*
(emptylistorset)
127.0.0.1:
9003>
再看看9001上是不是有这个key了
zhaoguihuadediannao:
srczhaogh$./redis-cli-p9001
127.0.0.1:
9001>keys*
1)"testkey001"
127.0.0.1:
9001>
没错,果然转移过来了。
最后我们试试能不能把9003删除:
zhaoguihuadediannao:
srczhaogh$./redis-trib.rbdel-node127.0.0.1:
9001'78ec1fd6647b79627d7c29bb2b22d04a4a6c43b3'
>>>Removingnode78ec1fd6647b79627d7c29bb2b22d04a4a6c43b3fromcluster127.0.0.1:
9001
Connectingtonode127.0.0.1:
9001:
OK
Connectingtonode127.0.0.1:
9002:
OK
Connectingtonode127.0.0.1:
9003:
OK
>>>SendingCLUSTERFORGETmessagestothecluster...
>>>SHUTDOWNthenode.
zhaoguihuadediannao:
srczhaogh$./redis-cli-p9003
CouldnotconnecttoRedisat127.0.0.1:
9003:
Connectionrefused
notconnected>
非常好,it’sverygood.
Redis主从复制
Redis的主从复制配置非常容易,但我们先来了解一下它的一些特性。
1.redis使用异步复制。
从redis2.8开始,slave也会周期性的告诉master现在的数据量。
可能只是个机制,用途应该不大。
2.一个master可以拥有多个slave,废话,这也是业界的标配吧。
3.slave可以接收来自其他slave的连接。
意思是不是就是说slave在接收其他的slave的连接之后成为master?
等下我们来验证。
4.redis复制在master这一端是非阻塞的,也就是说在和slave同步数据的时候,master仍然可以执行客户端的操作命令而不受其影响。
这点都不能保证,要你干嘛?
5.redis复制在slave这一端也是非阻塞的。
在配置文件里面有slave-serve-stale-data这一项,如果它为yes,slave在执行同步时,它可以使用老版本的数据来处理查询请求,如果是no,slave将返回一个错误。
在完成同步后,slave需要删除老数据,加载新数据,在这个阶段,slave会阻止连接进来。
6.Replicationcanbeusedbothforscalability,inordertohavemultipleslavesforread-onlyqueries(forexample,heavy SORT operationscanbeoffloadedtoslaves),orsimplyfordataredundancy.这句话我也没理解什么意思。
7.使用复制可以避免master因为需要把全部的数据集写入磁盘而造成的开销,因此可以把master中save配置项全部注释掉,不让它进行保存,然后配置slave,让slave保存。
虽然有这个特性,但是我们好像一般不这么做。
好吧,我们做几个例子练习一下。
先打开三个终端,然后起三个实例,分别用三个client去连接它们:
zhaoguihuadediannao:
srczhaogh$./redis-server--port10000--daemonizeyes
zhaoguihuadediannao:
srczhaogh$
zhaoguihuadediannao:
srczhaogh$./redis-cli-p10000
端口10000的做master。
slave01:
zhaoguihuadedia