redis-cluster
简介
  • redis-cluster是一个分布式、容错的redis实现,redis-cluster通过将各个单独的redis实例通过特定的协议连接到一起实现了分布式、集群化的目标。
  • redis-cluster中不存在中心节点或者代理节点,这样的设计目标是为了实现线性化扩展,也解决了单一中心(或代理)节点带来的性能瓶颈,但是随着集群规模的增大,节点之间通信的开销也会成指数级的增长,这样的机制也反过来限制了redis-cluster的规模无限扩充的可能。
  • redis-cluster的容错性采用的基本的主备(1-N)模式,由主节点提供服务,备节点定期与主节点同步数据,且备节点与主节点采用完全一致的配置,只有在主节点异常的情况下才会切换到备用节点。这种简单主备的模式浪费过多资源,不知道是否考虑过节点互为主备的情况(可以保留几台设备作为备机,当然这种情况只在集群故障率较低的情况下使用)
 
redis-cluster 通信    
  • redis-cluster中的每一个节点都包含以下信息:1、保存k-v信息;2、记录集群中slot到node的映射信息(因为slot是由key根据固定的算法计算出来的,而且slot数量固定为16384,如果保存key-node映射,则需要大量空间存储映射关系);3、通过Gossip协议与cluster中的其他节点进行通信,自动发现其他节点、识别出工作异常的节点(PING-PONG机制)、传播自身以及获取到的其他节点的信息。4、集群间可以通过PUB/SUB进行分发、订阅事件
  • redis-cluster中每个节点都有一个独一无二的ID,这个ID是一个十六进制表示的160位随机数,在节点第一次启动时由/dev/urandom生成。生成的节点ID会保存到配置文件中,只要配置文件存在该节点就会已知沿用这个ID。节点的ip、port都有可能改变,所以用ID来作为集群节点的唯一识别符。当某一结点的ip、port发生变化时,会通过gossip协议将关联信息发送到集群中其他节点:*当前的ip、port;标识(flags);负责处理的hash_slot;最后一次使用集群连接发送PING的时间;最后一次收到PONG的时间;被集群标记为下线状态的时间;如果是从节点,会记录主节点的ID,否则主节点ID这一栏值为0000*。example:```` 3886e65cc906bfd9b1f7e7bde468726a052d1dae 127.0.0.1:6380 master - 1318428930 1318428931 connected 1365-2729````
  • 节点通信:redis-cluster中的节点总是应答来自集群节点的连接请求,并对收到的PING数据包进行回复;对于来自本集群之外的节点的数据包,除了PING之外一概拒绝。这种情况下,集群中添加一个新的节点需要通过以下的步骤:1、新节点向原有节点发送MEET信息,强制接收信息的节点承认该节点是本集群的一份子,但是MEET信息只有在管理员手动执行````CLUSTER MEET ip port````命令时才能发送。2、redis-cluster支持A->B,B->C=A->C,这种传递方式C认识A的方式。 这种添加节点的方式有效防止了多个集群节点的mix,增强了集群的健壮性。
  • MOVED和ASK命令:客户端向Node1请求key,如果key存在于Node1上就会直接返回,如果不在该节点上,就会返回````-MOVED *slot addr:port*````给客户端,告知客户端请求的slot所在的Node,然后客户端会重新向新的Node发送请求同时更新本地的slot-node映射缓存;如果请求的key所在的node正在和另一个node进行slot迁移,如果key仍然在当前node上,node会正常返回;否则会返回一个ASK转向命令,客户端收到这个ASK应答后(这里与MOVED的最大区别就是客户端不会去更新本地的slot-node映射缓存,也就是说客户端下次请求依然会指向原来的node),会向新的node节点先发送一个ASKING命令,node节点收到ASKING命令后会设置一个一次性的flag,使得可以接受一次客户端对该node节点的请求,如果没有收到ASKING命令,node节点是拒绝接收任何客户端请求的。
  • 由于redis-cluster没有中心节点或者代理节点,客户端与redis-cluster通信都是采用与节点直接连接发送消息的方式进行的。redis-cluster中的节点采用ASK、MOVED两种机制来解决客户端请求的key不在当前节点的问题,通常情况下只有在新增、删除、主备切换才会出现slot迁移的情况,此时会用到AKS、MOVED机制。为了使客户端可以尽快的找到目标key所在的节点,通常客户端都会缓存一份slot-node映射关系,根据这个映射关系客户端可以直接访问到目标key所在的节点。
 
集群操作
  • redis-cluster支持在运行过程中进行节点的增加、删除操作,而且还不影响集群的正常工作。redis-cluster整个集群总共有16384(16*1024)个slot,所有的key都会指向一个特定的slot,每个node上可以负责其中的一部分,节点的增删,实际上就是slot迁移的过程。slot迁移除了因为主节点down会自动发生主备切换时是自动发生的,其他情况下都需要人工干预,即通过向集群发送命令来进行节点增删、slot迁移,slot迁移(resharding之后的文章会具体介绍)过程中会涉及到ASK、MOVED命令。
  • 节点失效检测:当一个节点向另一个节点发送PING消息时,目标节点没有在超时时间内返回PONG,当前节点就会将目的节点标记为PFAIL(possible failure);每次当节点对其他节点发送PING命令的时候,都会随机的广播三个它所知道的节点信息,其中包括已经被标记为PFAIL或者FAIL的节点(如果有的话);当一个节点收到广播的信息,会记下被标记为PFAIL和FAIL的节点;如果节点已经将某个节点标记为PFAIL,并根据节点所收到其他节点关于状态的反馈,如果反馈其为PFAIL的节点数过半,就可以将那个节点标记为FAIL;一旦一个节点被标记为FAIL,其为FAIL的状态信息会很快广播到整个集群。在以下两种情况下节点的FAIL状态会被移除:
    1. 如果被标记的时从节点,那么当这个节点重新上线时,FAIL标记就会被移除,保持从节点的FAIL状态没有任何意义,因为不处理任何slot,只会在主节点发生failover时才会影响其是否能够被提升为主节点;
    2. 如果一个主节点被打上FAIL标记后,结果节点的超时时间的4倍再加10秒钟之后,针对这个主节点的故障slot转移操作仍未完成,并且这个主节点重新上线的话,那么就移除这个节点的FAIL标记。
 
  • 节点failover选举:如果一个主节点进入FAIL状态,如果这个主节点有从节点,那么就会将一个从节点设置为主节点,其他从节点(如果有的话)就会开始从这个节点复制数据。从节点变主节点的条件:

    • 必须为已下线主节点的从节点;
    • 原主节点负责的slot数不为0;
    • 从节点数据被认为是可靠的,即主从节点间复制连接的断线时长不得超过  节点超时时限*REDIS_CLUSTER_SLAVE_VALIDITY_MULT  常量的乘积。
 
  • 从节点满足条件后,就会向集群中其他的主节点发送授权请求,询问是否能够转换成新的主节点。集群中主节点审核从节点升级主节点的请求时,考虑一下内容:
    • 发送请求消息的节点目前是从节点状态,其主节点为FAIL状态;
    • 该从节点在原主节点的所有从节点中,ID最小;
    • 该从节点没有被标记PFAIL或者FAIL。
 
一旦一个从节点在一定时间内收到大部分的集群主节点的授权,就会开始故障转移操作:
    • 显式的向集群中所有节点广播一个PONG数据包,表面自身是一个已升级的从节点(promoted slave),目前已经是主节点,接管原有主节点负责处理的所有槽;
    • 原有主节点的slot全部被更新;
    • 已下线主节点其他所有的从节点(有的话)接收到promoted标志,开始从当前新的主节点复制数据;
    • 如果已下线的主节点重新上线,察觉到PROMOTED标志,就会将自身调整为目前主节点的从节点。
 
  • 集群失效检测:每当集群配置发生变化时(slot更新或者slot迁移),集群中的每个节点都会对它所知道的节点进行扫描。配置更新完毕后,集群会根据扫描结果进入不同的状态:

    • FAIL:集群不能正常工作,即对每个请求,集群都会返回错误回复;
    • 集群可以正常工作,负责处理全部16384个槽的节点中,没有一个主节点进入FAIL状态。当集群中的大部分主节点都进入下线状态,即此时大部分为PFAIL,就无法完成FAIL状态确认,因为需要过半数的主节点投票,这种情况下,整个集群就会停止处理客户端的命令请求,并进入到集群FAIL状态。
 
注:部分内容引用于http://redisdoc.com/topic/cluster-spec.html#id4
 

具体操作
 
创建redis运行实例
先修改redis.conf,把其中的cluster-enabled、daemonize选项改成yes,设置maxmemory(单位byte)。然后执行下面脚本
#!/bin/sh
 
port=10000
redis_data="/home/sxhlinux/redis_data"
cd $redis_data
while [ $port -le 10009 ]
do
    mkdir $dir
    cd $dir
    cp /home/sxhlinux/redis/redis.conf .
    sed -i "s/\(port \)[0-9]*/\1${dir}/" redis.conf
    /usr/local/bin/redis-server ./redis.conf
    cd ..
 
    let port+=1
done

  

创建主备1:1的redis cluster集群
#注:参数中的... 表示实例的缩写,这里的10个实例会生成一个5主5从的集群。
$ redis-trib.rb create --replicas 1 127.0.0.1:10000 127.0.0.1:10001 127.0.0.1:10002 ... 127.0.0.1:10009 
 
$ redis-trib.rb check 127.0.0.1:10000 #检查整个集群状态
 
$ redis-cli -c [-h IP_ADDR] -p 10000 cluster nodes  #查看当前端口号为10000的节点所在集群的节点数 -h 选项用于连接远程的redis实例

  

集群中新增一个redis节点
#创建两个redis运行实例10010的过程省略
#将10010两个节点添加到127.0.0.1:10009运行的集群中,默认节点类型为master;
#--slave选项可以将新节点作为slave节点加入到集群中,可以通过--master-id选项指定搭配的主节点,否则集群就会随机分配给一个主节点
$ redis-trib.rb add-node [--slave] [--master-id MASTERID]127.0.0.1:10010 127.0.0.1:10009     #新添加一个节点
 
$ redis-cli -c -p 10001 cluster meet 127.0.0.1 10010     #新添加一个主节点
 
$ redis-cli -c -h [IP_ADDR] -p 10010 cluster replicate MASTER_ID     #将IP_ADDR 10001实例作为MASTER_ID的slave节点

  

集群中删除一个redis节点
$ redis-trib.rb del-node IP:PORT NODE_ID   #将IP:PORT实例删除,并结束掉该实例进程(如果该实例上有slot,需要先执行reshard操作,将slot迁移走)   

#将NODE_ID从IP_ADDR:PORT节点上的集群信息中移除,但是被删除节点的还在其它节点的node.conf中,#由于redis-cluster的gossip协议作用,
#删除的节点信息很快会被加到IP_ADDR:PORT节点的node.conf中。所以想要彻底将一个节点从集群中移除,
#需要使用下面的redis-trib.rb call 命令来对所有的节点执行forget命令
$ redis-cli -c [-h IP_ADDR] -p PORT cluster forget NODE_ID    
 
$ redis-trib.rb call IP:PORT CMD     #对IP:PORT所在集群上所有的节点上执行CMD命令

  

 
集群失败与恢复
$ redis-cli -c [-h IP_ADDR] -p 10001 debug segfault     #手动将10001节点关掉,模拟实例挂掉的情况,测试故障转移

  

slot操作
#将0-5000,6000这5002个slot指派到该节点上
$ redis-cli -c [-h IP_ADDR] -p PORT cluster addslots {0..5000,6000}     
 
#移除指派给当前结点的部分slot
$ redis-cli -c [-h IP_ADDR] -p PORT cluster delslots {0..5000,6000} 
 
#移除指派给当前结点的所有slot
$ redis-cli -c [-h IP_ADDR] -p PORT cluster flushslots
 
#指派slot给NODE_ID代表的节点,如果要指派的节点已经在其它节点,则需要delslots命令先把这些slot从其它节点上删除
$ redis-cli -c [-h IP_ADDR] -p PORT cluster setslot {1..500, 5000} node NODE_ID
 
#将本节点指定的slot迁移到NODE_ID代表的节点
$ redis-cli -c [-h IP_ADDR] -p PORT cluster setslot {1..500, 5000} migrating NODE_ID
 
#从NODE_ID代表的节点中将指定的slot迁移到本节点中
$ redis-cli -c [-h IP_ADDR] -p PORT cluster setslot {1..500, 5000} importing NODE_ID
 
#取消对指定slot的migrating或者importing
$ redis-cli -c [-h IP_ADDR] -p PORT cluster setslot {1..500, 5000} stable
 
#在IP:PORT所在集群进行slot迁移,可以从特定节点(NODE_ID1..)也可以是全部(all)节点迁移NUMS个slot到NODE_ID3(NODE_ID3必须时master节点,否则会失败)上(注:源可以多个,但目的只有一个)
$ redis-trib.rb reshard IP:PORT --from all/NODE_ID1[,NODE_ID2...] --to NODE_ID3 --slots NUMS --yes [--timeout SECS]

  

redis 学习笔记——redis集群的更多相关文章

  1. redis 学习笔记-cluster集群搭建

    一.下载最新版redis 编译 目前最新版是3.0.7,下载地址:http://www.redis.io/download 编译很简单,一个make命令即可,不清楚的同学,可参考我之前的笔记: red ...

  2. redis 学习笔记2(集群之哨兵模式的使用)

    redis3.0之前已经有了哨兵模式,3.0之后有了cluster(分片集群),官方不推荐使用!!主要原因是分片后单节点故障后需要实现手动分槽... 集群较为成熟的解决方案codis,公司使用的是哨兵 ...

  3. Quartz学习笔记:集群部署&高可用

    Quartz学习笔记:集群部署&高可用 集群部署 一个Quartz集群中的每个节点是一个独立的Quartz应用,它又管理着其他的节点.这就意味着你必须对每个节点分别启动或停止.Quartz集群 ...

  4. redis相关笔记(二.集群配置及使用)

    redis笔记一 redis笔记二 redis笔记三 1.配置:在原redis-sentinel文件夹中添加{8337,8338,8339,8340}文件夹,且复制原8333中的配置 在上述8333配 ...

  5. Redis学习笔记~Redis主从服务器,读写分离

    回到目录 Redis这个Nosql的存储系统一般会被部署到linux系统中,我们可以把它当成是一个数据服务器,对于并发理大时,我们会使用多台服务器充当Redis服务器,这时,各个Redis之间也是分布 ...

  6. Dubbo -- 系统学习 笔记 -- 示例 -- 集群容错

    Dubbo -- 系统学习 笔记 -- 目录 示例 想完整的运行起来,请参见:快速启动,这里只列出各种场景的配置方式 集群容错 在集群调用失败时,Dubbo提供了多种容错方案,缺省为failover重 ...

  7. NodeJS学习笔记 (17)集群-cluster(ok)

    cluster模块概览 node实例是单线程作业的.在服务端编程中,通常会创建多个node实例来处理客户端的请求,以此提升系统的吞吐率.对这样多个node实例,我们称之为cluster(集群). 借助 ...

  8. MongoDB学习笔记~Mongo集群和副本集

    回到目录 一些概念 对于Mongo在数据容灾上,推荐的模式是使用副本集模式,它有一个对外的主服务器Primary,还有N个副本服务器Secondary(N>=1,当N=1时,需要有一台仲裁服务器 ...

  9. ElasticSearch学习笔记-02集群相关操作_cat参数

    _cat参数允许你查看集群的一些相关信息,如集群是否健康,有哪些节点,以及索引的情况等的. 检测集群是否健康 curl localhost:9200/_cat/health?v 说明: curl 是一 ...

随机推荐

  1. JS获取渲染后的样式

    一般我们利用element.style.属性来获取CSS的样式,而此方法只能获取标签内的样式,无法获取头部或引入的样式,因此,而我们又需要获取其样式,则我们可以使用:(其中element为标签,pro ...

  2. C# 截取图片区域,并返回所截取的图片

    /// <summary> /// 截取图片区域,返回所截取的图片 /// </summary> /// <param name="SrcImage" ...

  3. Scala Sublime text 3 Build 编译

    使用Sublime text 3编译Scala 在sublime工具栏中[tools]->[Build System]->[new Build System]添加如下文本 { " ...

  4. .Net编译之AnyCPU - 进阶者系列 - 学习者系列文章

    Visual Studio是一款非常强大的IDE工具,它为我们提供了强大的编码.调试和测试等工具,为我们编好.NET软件提供了强大的支持. 今天早晨想到了Visual Studio编译模式中的CPU类 ...

  5. 在SQL Server 2008中调用.net,dll

    原文:在SQL Server 2008中调用.net,dll T-SQL的在执行普通的查询的时候是很高效的,但是在执行循环,判断这样的语句的时候效率就不那么的高了.这时可以借助CLR了,我们可以在SQ ...

  6. 你是否应该使用一个Javascript MVC框架?

    你是否应该使用一个Javascript MVC框架?本文摘自smashingmagazine的Journey Through The JavaScript MVC Jungle部分内容,希望对大家有帮 ...

  7. CLR Profiler 性能分析工具

    CLR Profiler 性能分析工具 CLR Profiler 性能分析工具 CLR Profiler 有两个版本,分别用于CLR1.1 和 CLR2.0,至于CLR4试了一些也可以,但不知道是否完 ...

  8. 你的flume-ng的第一篇博客

    我在flume-ng 1.1.0 孵化版的时候就开始接触了,自己也搞了一段时间,没事扯扯心得吧. 先说在前面,flume-ng 后面的版本,我没仔细读change log ,比较农民 , 不知道新添了 ...

  9. ubuntu-使用终端配置网络

    文件说明: IP.网关.掩码的配置文件:/etc/network/interfaces DNS配置文件:/etc/resolv.conf 配置步骤: 1)配置有关IP文件 配置IP.网关.掩码这些信息 ...

  10. Day3:T1数论+高精 T2搜索

    T1:数论+高精(水~) 根据题意可知,从除的数越大越好(在0~9中) 所以我们只要用到高精除然后再模拟一下就可以了 //MARK:但是要注意0-9这个特殊值需要特判,因为题目要求输出的数至少是两位数 ...