redis分布式集群搭建介紹

redis分布式集群搭建介紹

redis集群架構

redis分布式集群搭建介紹

上圖藍色為redis集群的節點。

節點之間通過ping命令來測試連接是否正常,節點之間沒有主區分,連接到任何一個節點進行操作時,都可能會轉發到其他節點。

1、Redis的容錯機制

節點之間會定時的互相發送ping命令,測試節點的健康狀態,當節點接受到ping命令后,會返回一個pong字符串

投票機制:如果一個節點A給節點B發送ping沒有得到pong返回,會通知其他節點再次給B發送ping,如果集群中有超過一半的節點收不B節點的pong。那么就認為B節點掛了。一般會為每個節點提供一個備份節點,如果掛掉會切換到備份節點。

2、Redis集群存儲原理

Redis對于每個存放的key會進行hash操作,生成一個[0-16384]的hash值(先進行

crc?算法再對16384取余)。

集群的情況下,就是把[0-16384]的區間進行拆分,放到不同的redis中。

3、Redis的持久化

Snapshotting:定時的將Redis內存中的數據保存到硬盤中

AOF:將所有的command操作保存到aof中,AOP的同步頻率很高,數據即使丟失,粒度也很小,但會在性能上造成影響。

二、集群環境搭建

redis集群管理工具redis-trib.rb依賴ruby環境,首先需要安裝ruby環境

安裝ruby

yum?install?ruby yum?install?rubygems

安裝ruby和redis的接口程序

拷貝redis-3.0.0.gem至/usr/local下

執行:

gem?install?/usr/local/redis-3.0.0.gem

三、創建Redis集群

在一臺服務器上,可以用不同端口號來表示不同redis服務器。

Redis集群最少需要三臺服務器,而每臺服務器有需要備用服務器,所以最少需要6臺服務器。端口規劃如下:

主服務器:192.168.100.66 :7001 ?:7002 ?:7003

從服務器:192.168.100.66 :7004 ?:7005 ?:7006

在/usr/local?創建文件夾用來存放服務器程序

mkdir 7001 7002 7003 7004 7005 7006

如果想讓redis支持集群需要修改redis.config配置文件的cluster-enabled yes

本例中我們以端口來區別不同的redis服務,所以還需要修改redis.config的port為對應端口

修改完配置文件,將redis安裝目錄的bin復制到上面每個目錄中。

分別進入7001/bin/ 7002/bin …..

啟動服務./redis-server ./redis.conf

查看redis進程:ps -aux|grep redis?如下圖則說明啟動成功

redis分布式集群搭建介紹

創建集群:

將之前解壓的文件夾的redis-3.0.0/src/redis-trib.rb復制到redis-cluster目錄

運行

./redis-trib.rb?create?--replicas?1?192.168.100.66:7001?192.168.100.66:7002?192.168.100.66:7003?192.168.100.66:7004?192.168.100.66:7005??192.168.100.66:7006

如果執行時報如下錯誤:

[ERR]?Node?XXXXXX?is?not?empty.?Either?the?node?already?knows?other?nodes?(check?with?CLUSTER?NODES)?or?contains?some?key?in?database?0

解決方法是刪除生成的配置文件nodes.conf,如果不行則說明現在創建的結點包括了舊集群的結點信息,需要刪除redis的持久化文件后再重啟redis,比如:appendonly.aof、dump.rdb

如果成功最終輸入如下:

redis分布式集群搭建介紹

查詢集群信息:

redis分布式集群搭建介紹

說明:

./redis-cli -c -h 192.168.101.3 -p 7001?,其中-c表示以集群方式連接redis,-h指定ip地址,-p指定端口號

cluster nodes?查詢集群結點信息

cluster info?查詢集群狀態信息

redis分布式集群搭建介紹

hash槽重新分配

第一步:連接上集群

./redis-trib.rb reshard 192.168.101.3:7001(連接集群中任意一個可用結點都行)

第二步:輸入要分配的槽數量

redis分布式集群搭建介紹

輸入?500表示要分配500個槽

第三步:輸入接收槽的結點id

redis分布式集群搭建介紹

這里準備給7007分配槽,通過cluster nodes查看7007結點id為15b809eadae88955e36bcdbb8144f61bbbaf38fb

輸入:15b809eadae88955e36bcdbb8144f61bbbaf38fb?

第四步:輸入源結點id

redis分布式集群搭建介紹

這里輸入all

第五步:輸入yes開始移動槽到目標結點id

redis分布式集群搭建介紹

添加從節點

?

集群創建成功后可以向集群中添加節點,下面是添加一個slave從節點。

添加7008從結點,將7008作為7007的從結點。

./redis-trib.rb add-node –slave?–master-id?主節點id?添加節點的ip和端口?集群中已存在節點ip和端口

執行如下命令:

./redis-trib.rb add-node –slave –master-id cad9f7413ec6842c971dbcc2c48b4ca959eb5db4 ?192.168.101.3:7008?192.168.101.3:7001

cad9f7413ec6842c971dbcc2c48b4ca959eb5db4 ?是7007結點的id,可通過cluster nodes查看。

redis分布式集群搭建介紹

注意:如果原來該結點在集群中的配置信息已經生成cluster-config-file指定的配置文件中(如果cluster-config-file沒有指定則默認為nodes.conf),這時可能會報錯:

[ERR] Node XXXXXX?is not empty. Either the node already knows other nodes (check with CLUSTER NODES) or contains some key in database 0

解決方法是刪除生成的配置文件nodes.conf,刪除后再執行./redis-trib.rb add-node指令

查看集群中的結點,剛添加的7008為7007的從節點:

redis分布式集群搭建介紹

?刪除結點:

./redis-trib.rb?del-node?127.0.0.1:7005?4b45eb75c8b428fbd77ab979b85080146a9bc017

刪除已經占有hash槽的結點會失敗,報錯如下:

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

需要將該結點占用的hash槽分配出去(參考hash槽重新分配章節)。

測試:

Maven: <dependencies> ????<dependency> ????????<groupid>redis.clients</groupid> ????????<artifactid>jedis</artifactid> ????????<version>2.7.0</version> ????</dependency> ????<!-- https://mvnrepository.com/artifact/junit/junit --> ????<dependency> ????????<groupid>junit</groupid> ????????<artifactid>junit</artifactid> ????????<version>4.12</version> ????????<scope>test</scope> ????</dependency> ????<!-- https://mvnrepository.com/artifact/org.springframework/spring-test --> ????<dependency> ????????<groupid>org.springframework</groupid> ????????<artifactid>spring-test</artifactid> ????????<version>4.3.10.RELEASE</version> ????????<scope>test</scope> ????</dependency></dependencies>

普通測試:

@Test public?void?redisClusterTest1(){ ????JedisPoolConfig?config=new?JedisPoolConfig(); ????config.setMaxTotal(30); ????config.setMaxIdle(2);  ????Set<hostandport>?jedisNode=new?HashSet<hostandport>(); ????jedisNode.add(new?HostAndPort("192.168.100.66",7001)); ????jedisNode.add(new?HostAndPort("192.168.100.66",7002)); ????jedisNode.add(new?HostAndPort("192.168.100.66",7003)); ????jedisNode.add(new?HostAndPort("192.168.100.66",7004)); ????jedisNode.add(new?HostAndPort("192.168.100.66",7005)); ????jedisNode.add(new?HostAndPort("192.168.100.66",7006));  ????JedisCluster?jc=new?JedisCluster(jedisNode,config); ????jc.set("name","老王"); ????String?value=jc.get("name"); ????System.out.println(value); }</hostandport></hostandport>

Spring測試:

配置文件:

<?xml  version="1.0" encoding="UTF-8"?><beans> ????<!-- 連接池配置 --> ????<bean> ????????<!-- 最大連接數 --> ????????<property></property> ????????<!-- 最大空閑連接數 --> ????????<property></property> ????????<!-- 每次釋放連接的最大數目 --> ????????<property></property> ????????<!-- 釋放連接的掃描間隔(毫秒) --> ????????<property></property> ????????<!-- 連接最小空閑時間 --> ????????<property></property> ????????<!-- 連接空閑多久后釋放, 當空閑時間>該值 且 空閑連接>最大空閑連接數 時直接釋放 --> ????????<property></property> ????????<!-- 獲取連接時的最大等待毫秒數,小于零:阻塞不確定的時間,默認-1 --> ????????<property></property> ????????<!-- 在獲取連接的時候檢查有效性, 默認false --> ????????<property></property> ????????<!-- 在空閑時檢查有效性, 默認false --> ????????<property></property> ????????<!-- 連接耗盡時是否阻塞, false報異常,ture阻塞直到超時, 默認true --> ????????<property></property> ????</bean> ????<!-- redis集群 --> ????<bean> ????????<constructor-arg> ????????????<set> ????????????????<bean> ????????????????????<constructor-arg></constructor-arg> ????????????????????<constructor-arg></constructor-arg> ????????????????</bean> ????????????????<bean> ????????????????????<constructor-arg></constructor-arg> ????????????????????<constructor-arg></constructor-arg> ????????????????</bean> ????????????????<bean> ????????????????????<constructor-arg></constructor-arg> ????????????????????<constructor-arg></constructor-arg> ????????????????</bean> ????????????????<bean> ????????????????????<constructor-arg></constructor-arg> ????????????????????<constructor-arg></constructor-arg> ????????????????</bean> ????????????????<bean> ????????????????????<constructor-arg></constructor-arg> ????????????????????<constructor-arg></constructor-arg> ????????????????</bean> ????????????????<bean> ????????????????????<constructor-arg></constructor-arg> ????????????????????<constructor-arg></constructor-arg> ????????????????</bean> ????????????</set> ????????</constructor-arg> ????????<constructor-arg></constructor-arg> ????</bean></beans>

測試類:

@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration({"classpath:spring-config.xml"}) public?class?RedisClusterTest?{ ????@Autowired ????private?JedisCluster?jedisCluster; ????@Test ????public?void?redisClusterTest2(){ ????????jedisCluster.set("username","小明啦啦"); ????????String?name=jedisCluster.get("username"); ????????System.out.println(name); ????} }

更多redis知識請關注redis數據庫教程欄目。

以上就是

? 版權聲明
THE END
喜歡就支持一下吧
點贊8 分享