开发者社区> 技术小阿哥> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

redis 单机命令和集群维护 原理 程序开发等

简介:
+关注继续查看

我们可以用redis-trib.rb fix 来修复集群/redis-3.0.1/src/redis-trib.rb fix 127.0.0.1:7000  ,如果还是启动不了的话,可以把相关的cluster-config-file节点同步信息删掉。

节点   

CLUSTER MEET <ip> <port> 将 ip 和 port 所指定的节点添加到集群当中,让它成为集群的一份子。   

CLUSTER FORGET <node_id> 从集群中移除 node_id 指定的节点。   

CLUSTER REPLICATE <node_id> 将当前节点设置为 node_id 指定的节点的从节点。   

CLUSTER SAVECONFIG 将节点的配置文件保存到硬盘里面。   

槽(slot)   

CLUSTER ADDSLOTS <slot> [slot ...] 将一个或多个槽(slot)指派(assign)给当前节点。   

CLUSTER DELSLOTS <slot> [slot ...] 移除一个或多个槽对当前节点的指派。   

CLUSTER FLUSHSLOTS 移除指派给当前节点的所有槽,让当前节点变成一个没有指派任何槽的节点。   

CLUSTER SETSLOT <slot> NODE <node_id> 将槽 slot 指派给 node_id 指定的节点,如果槽已经指派给另一个节点,那么先让另一个节点删除该槽>,然后再进行指派。   

CLUSTER SETSLOT <slot> MIGRATING <node_id> 将本节点的槽 slot 迁移到 node_id 指定的节点中。   

CLUSTER SETSLOT <slot> IMPORTING <node_id> 从 node_id 指定的节点中导入槽 slot 到本节点。   

CLUSTER SETSLOT <slot> STABLE 取消对槽 slot 的导入(import)或者迁移(migrate)。   

键   

CLUSTER KEYSLOT <key> 计算键 key 应该被放置在哪个槽上。   

CLUSTER COUNTKEYSINSLOT <slot> 返回槽 slot 目前包含的键值对数量。   

CLUSTER GETKEYSINSLOT <slot> <count> 返回 count 个 slot 槽中的键。  


单机命令

1. KEYS/RENAME/DEL/EXISTS/MOVE/RENAMENX:

flushdb

set mykey 2

sadd mysetkey 1 2 3

hset mmtest username "stephen"

keys my*

del mykey mykey2

#将当前数据库中的mysetkey键移入到ID为1的数据库中,从结果可以看出已经移动成功

move mysetkey 1

select 1

renamenx oldkey newkey

2. PERSIST/EXPIRE/EXPIREAT/TTL:    

3. TYPE/RANDOMKEY/SORT:



http://blog.csdn.net/u010258235/article/details/50060127


很全面,配置也有提到


键分布模型?

Redis 集群的键空间被分割为 16384 个槽(slot),集群的最大节点数量也是 16384 个。

重配置指的是将某个/某些槽从一个节点移动到另一个节点。


节点握手(已实现)?

MOVED 转向?

如果该命令是集群可以执行的命令,那么节点会查找这个命令所要处理的键所在的槽。

集群在线重配置(live reconfiguration)

Redis 集群支持在集群运行的过程中添加或者移除节点。

实际上,节点的添加操作和节点的删除操作可以抽象成同一个操作,那就是,将哈希槽从一个节点移动到另一个节点:

添加一个新节点到集群,等于将其他已存在节点的槽移动到一个空白的新节点里面。

从集群中移除一个节点,等于将被移除节点的所有槽移动到集群的其他节点上面去。

要理解 Redis 集群如何将槽从一个节点移动到另一个节点,我们需要对 CLUSTER 命令的各个子命令进行介绍,这些命理负责管理集群节点的槽转换表(slots translation table)。

以下是 CLUSTER 命令可用的子命令:

CLUSTER ADDSLOTS slot1 [slot2] ... [slotN]

CLUSTER DELSLOTS slot1 [slot2] ... [slotN]

CLUSTER SETSLOT slot NODE node

CLUSTER SETSLOT slot MIGRATING node

CLUSTER SETSLOT slot IMPORTING node

最开头的两条命令 ADDSLOTS 和 DELSLOTS 分别用于向节点指派(assign)或者移除节点,当槽被指派或者移除之后,节点会将这一信息通过 Gossip 协议传播到整个集群。 ADDSLOTS 命令通常在新创建集群时,作为一种快速地将各个槽指派给各个节点的手段来使用。

CLUSTER SETSLOT slot NODE node 子命令可以将指定的槽 slot 指派给节点 node 。

至于 CLUSTER SETSLOT slot MIGRATING node 命令和 CLUSTER SETSLOT slot IMPORTING node 命令,前者用于将给定节点 node 中的槽 slot 迁移出节点,而后者用于将给定槽 slot 导入到节点 node :

当一个槽被设置为 MIGRATING 状态时,原来持有这个槽的节点仍然会继续接受关于这个槽的命令请求,但只有命令所处理的键仍然存在于节点时,节点才会处理这个命令请求。

如果命令所使用的键不存在与该节点,那么节点将向客户端返回一个 -ASK 转向(redirection)错误,告知客户端,要将命令请求发送到槽的迁移目标节点。

当一个槽被设置为 IMPORTING 状态时,节点仅在接收到 ASKING 命令之后,才会接受关于这个槽的命令请求。

如果客户端没有向节点发送 ASKING 命令,那么节点会使用 -MOVED 转向错误将命令请求转向至真正负责处理这个槽的节点。

上面关于 MIGRATING 和 IMPORTING 的说明有些难懂,让我们用一个实际的实例来说明一下。

假设现在,我们有 A 和 B 两个节点,并且我们想将槽 8 从节点 A 移动到节点 B ,于是我们:

向节点 B 发送命令 CLUSTER SETSLOT 8 IMPORTING A

向节点 A 发送命令 CLUSTER SETSLOT 8 MIGRATING B

每当客户端向其他节点发送关于哈希槽 8 的命令请求时,这些节点都会向客户端返回指向节点 A 的转向信息:

如果命令要处理的键已经存在于槽 8 里面,那么这个命令将由节点 A 处理。

如果命令要处理的键未存在于槽 8 里面(比如说,要向槽添加一个新的键),那么这个命令由节点 B 处理。

这种机制将使得节点 A 不再创建关于槽 8 的任何新键。

与此同时,一个特殊的客户端 redis-trib 以及 Redis 集群配置程序(configuration utility)会将节点 A 中槽 8 里面的键移动到节点 B 。

键的移动操作由以下两个命令执行:

CLUSTER GETKEYSINSLOT slot count

上面的命令会让节点返回 count 个 slot 槽中的键,对于命令所返回的每个键, redis-trib 都会向节点 A 发送一条 MIGRATE 命令,该命令会将所指定的键原子地(atomic)从节点 A 移动到节点 B (在移动键期间,两个节点都会处于阻塞状态,以免出现竞争条件)。

以下为 MIGRATE 命令的运作原理:

MIGRATE target_host target_port key target_database id timeout

执行 MIGRATE 命令的节点会连接到 target 节点,并将序列化后的 key 数据发送给 target ,一旦 target 返回 OK ,节点就将自己的 key 从数据库中删除。

从一个外部客户端的视角来看,在某个时间点上,键 key 要么存在于节点 A ,要么存在于节点 B ,但不会同时存在于节点 A 和节点 B 。

因为 Redis 集群只使用 0 号数据库,所以当 MIGRATE 命令被用于执行集群操作时, target_database 的值总是 0 。

target_database 参数的存在是为了让 MIGRATE 命令成为一个通用命令,从而可以作用于集群以外的其他功能。

我们对 MIGRATE 命令做了优化,使得它即使在传输包含多个元素的列表键这样的复杂数据时,也可以保持高效。

不过,尽管 MIGRATE 非常高效,对一个键非常多、并且键的数据量非常大的集群来说,集群重配置还是会占用大量的时间,可能会导致集群没办法适应那些对于响应时间有严格要求的应用程序。

ASK 转向?

在之前介绍 MOVED 转向的时候,我们说除了 MOVED 转向之外,还有另一种 ASK 转向。

当节点需要让一个客户端长期地(permanently)将针对某个槽的命令请求发送至另一个节点时,节点向客户端返回 MOVED 转向。

另一方面,当节点需要让客户端仅仅在下一个命令请求中转向至另一个节点时,节点向客户端返回 ASK 转向。

比如说,在我们上一节列举的槽 8 的例子中,因为槽 8 所包含的各个键分散在节点 A 和节点 B 中,所以当客户端在节点 A 中没找到某个键时,它应该转向到节点 B 中去寻找,但是这种转向应该仅仅影响一次命令查询,而不是让客户端每次都直接去查找节点 B :在节点 A 所持有的属于槽 8 的键没有全部被迁移到节点 B 之前,客户端应该先访问节点 A ,然后再访问节点 B 。

因为这种转向只针对 16384 个槽中的其中一个槽,所以转向对集群造成的性能损耗属于可接受的范围。

因为上述原因,如果我们要在查找节点 A 之后,继续查找节点 B ,那么客户端在向节点 B 发送命令请求之前,应该先发送一个 ASKING 命令,否则这个针对带有 IMPORTING 状态的槽的命令请求将被节点 B 拒绝执行。

接收到客户端 ASKING 命令的节点将为客户端设置一个一次性的标志(flag),使得客户端可以执行一次针对 IMPORTING 状态的槽的命令请求。

从客户端的角度来看, ASK 转向的完整语义(semantics)如下:

如果客户端接收到 ASK 转向,那么将命令请求的发送对象调整为转向所指定的节点。

先发送一个 ASKING 命令,然后再发送真正的命令请求。

不必更新客户端所记录的槽 8 至节点的映射:槽 8 应该仍然映射到节点 A ,而不是节点 B 。

一旦节点 A 针对槽 8 的迁移工作完成,节点 A 在再次收到针对槽 8 的命令请求时,就会向客户端返回 MOVED 转向,将关于槽 8 的命令请求长期地转向到节点 B 。

注意,即使客户端出现 Bug ,过早地将槽 8 映射到了节点 B 上面,但只要这个客户端不发送 ASKING 命令,客户端发送命令请求的时候就会遇上MOVED 错误,并将它转向回节点 A 。

容错?

节点失效检测?

以下是节点失效检查的实现方法:

当一个节点向另一个节点发送 PING 命令,但是目标节点未能在给定的时限内返回 PING 命令的回复时,那么发送命令的节点会将目标节点标记为PFAIL (possible failure,可能已失效)。

等待 PING 命令回复的时限称为“节点超时时限(node timeout)”,是一个节点选项(node-wise setting)。

每次当节点对其他节点发送 PING 命令的时候,它都会随机地广播三个它所知道的节点的信息,这些信息里面的其中一项就是说明节点是否已经被标记为 PFAIL 或者 FAIL 。

当节点接收到其他节点发来的信息时,它会记下那些被其他节点标记为失效的节点。这称为失效报告(failure report)。

如果节点已经将某个节点标记为 PFAIL ,并且根据节点所收到的失效报告显式,集群中的大部分其他主节点也认为那个节点进入了失效状态,那么节点会将那个失效节点的状态标记为 FAIL 。

一旦某个节点被标记为 FAIL ,关于这个节点已失效的信息就会被广播到整个集群,所有接收到这条信息的节点都会将失效节点标记为 FAIL 。

简单来说,一个节点要将另一个节点标记为失效,必须先询问其他节点的意见,并且得到大部分主节点的同意才行。

因为过期的失效报告会被移除,所以主节点要将某个节点标记为 FAIL 的话,必须以最近接收到的失效报告作为根据。

在以下两种情况中,节点的 FAIL 状态会被移除:

如果被标记为 FAIL 的是从节点,那么当这个节点重新上线时, FAIL 标记就会被移除。

保持(retaning)从节点的 FAIL 状态是没有意义的,因为它不处理任何槽,一个从节点是否处于 FAIL 状态,决定了这个从节点在有需要时能否被提升为主节点。

如果一个主节点被打上 FAIL 标记之后,经过了节点超时时限的四倍时间,再加上十秒钟之后,针对这个主节点的槽的故障转移操作仍未完成,并且这个主节点已经重新上线的话,那么移除对这个节点的 FAIL 标记。

在第二种情况中,如果故障转移未能顺利完成,并且主节点重新上线,那么集群就继续使用原来的主节点,从而免去管理员介入的必要。

集群状态检测(已部分实现)?

从节点选举?

发布/订阅(已实现,但仍然需要改善)?

Redis Cluster failover机制

节点心跳

失效检测

从选举与提升

模拟宕机(实现故障转移)


程序开发

429659_14418588970U0K.png

这里我们会先去redis中判断数据是否存在,如果存在,则直接更新对应的数据(这一步会把对应更新过的key记录下来,比如也保存到redis中比如:key为:save_update_keys【用lpush列表记录】),并把更新后的数据返回给页面。而如果不存在的话,就会去先更新数据库中内容,然后把数据保存一份到Redis中。后面的工作:后台会有相关机制把Redis中的save_update_keys存储的key,分别读取出来,找到对应的数据,更新到DB中。
优点:这个流程的主要目的是把Redis当作数据库使用,更新获取数据比DB快。非常适合大数据量的频繁变动(比如微博)。
缺点:对Redis的依赖很大,要做好宕机时的数据保存。(不过可以使用redis的快照AOF,快速恢复的话,应该不会有多大影响,因为就算Redis不工作了,也不会影响后续数据的处理。)
难点:在前期规划key的格式,存储类型很重要,因为这会影响能否把数据同步到DB。


排行榜
游戏服务器中涉及到很多排行信息,比如玩家等级排名、金钱排名、战斗力排名等。
一般情况下仅需要取排名的前N名就可以了,这时可以利用数据库的排序功能,或者自己维护一个元素数量有限的top集合。
但是有时候我们需要每一个玩家的排名,玩家的数量太多,不能利用数据库(全表排序压力太大),自己维护也会比较麻烦。
使用Redis可以很好的解决这个问题。它提供的有序Set,支持每个键值(比如玩家id)拥有一个分数(score),每次往这个set里添加元素,
Redis会对其进行排序,修改某一元素的score后,也会更新排序,在获取数据时,可以指定排序范围。
更重要的是,这个排序结果会被保存起来,不用在服务器启动时重新计算。
通过它,排行榜的实时刷新、全服排行都不再成为麻烦事。


消息队列(可跨服)
Redis提供的List数据类型,可以用来实现一个消息队列。
由于它是独立于游戏服务器的,所以多个游戏服务器可以通过它来交换数据、发送事件。
Redis还提供了发布、订阅的事件模型。
利用这些,我们就不必自己去实现一套服务器间的通信框架,方便地实现服务器组。


数据库缓存
Redis提供了较为丰富数据类型,使我们可以更为容易地将数据对象缓存起来(序列化、protobuffer)。
当需要请求某一数据时,先从Redis中查找,如果没有再查数据库,同时交给Redis缓存起来。
当对数据进行修改时,则先将修改后的数据保存到Redis,然后保存至数据库(2)。
第2步可以有另外的思路:
A不实时保存到数据库,而是交由另外的线程(甚至是专门的程序)去保存,以提高逻辑层的响应速度。
B部分数据交给Redis保存(Reids自身有持久化功能),像玩家已经完成过的任务ID集合,利用Redis的Set类型保存更为合适。
C玩家瞬时变化的数据不见得每次修改都需要保存(比如金钱、经验),但如果游戏服务器自己维护在内存中,出现宕机就会导致回档。
Redis是独立于游戏服务器的,交由它来保存,可以防止宕机回档的问题,也可以减少游戏服务器自己维护数据所占用的内存。

Redis Cluster还具有一些其他方面的不同,譬如它不支持多个数据库,不支持select命令等等,
但其中最大的不同还是Redis Cluster不支持复杂的多主键操作。关于这一点,
Redis Cluster的官方文档有这样一段描述,现摘录如下:
Commands performing complex multi key operations like Set type unions
or intersections are not implemented, and in general all the operations
where in theory keys are not available in the same node are not implemented。
由这段描述可知,在Redis Cluster中任何跨节点的命令都是不允许的,
但是落实到具体的系统实现中,Redis Cluster又是如何去处理这些命令的呢?
我们不妨通过两种典型的命令来验证一下,其中一种是MULTI/EXEC事务命令,
该命令可以将多条Redis命令一次执行,所以这类命令可能同时操作多个主键,
另外一种是本身就支持多主键的命令如mset和mget等。下面,
本博主就在之前搭建的Redis Cluster上,分别尝试了以上两类命令的不同执行场景,
以此来感性地认识Redis Cluster的反应!存在疑问?

情景一:MULTI/EXEC事务中的所有命令均操作相同的主键,且该主键就在当前连接的Redis节点上
情景二:MULTI/EXEC事务中的所有命令均操作相同的主键,但该主键不在当前连接的Redis节点上
情景三:MULTI/EXEC事务中的所有命令操作不同的主键,且某些主键不在当前连接的Redis节点上
redis 127.0.0.1:6379> multi
OK
redis 127.0.0.1:6379> set hello america
QUEUED
redis 127.0.0.1:6379> set foo rab
(error) MOVED 12182 192.168.32.4:6379
redis 127.0.0.1:6379> exec1) 
OK
redis 127.0.0.1:6379> get hello"america"
情景四:MULTI/EXEC事务中的所有命令操作不同的主键,且所有主键均在当前连接的Redis节点上
情景五:Multiple主键命令包含了不同的主键,且所有主键均在当前连接的Redis节点上
情景六:Multiple主键命令包含了多个相同的主键,且该主键在当前连接的Redis节点上
情景七:Multiple主键命令包含了多个相同的主键,但该主键不在当前连接的Redis节点上
基于以上执行结果,我们可以知道对于MULTI/EXEC事务来说,执行效果与逐条处理单个命令一样,
被事务包裹的Redis命令连接节点能够处理就处理,无法处理的就返回MOVED信息。
但是



本文转自 liqius 51CTO博客,原文链接:http://blog.51cto.com/szgb17/1914456,如需转载请自行联系原作者

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
Redis之集群环境搭建
前面文章介绍了Redis的主从复制,虽然该模式能够在一定程度上提高系统的稳定性,但是在数据访问量比较大的情况下,单个master应付起来还是比较吃力的,这时我们可以考虑将redis集群部署,本文就来重点给大家介绍下Redis的集群部署操作。
117 0
Redis集群管理
Redis集群管理1.简介 Redis在生产环境中一般是通过集群的方式进行运行,Redis集群包括主从复制集群和数据分片集群两种类型。 *主从复制集群提供高可用性,而数据分片集群提供负载均衡。 *数据分片集群中能实现主从复制集群的功能。
1753 0
redis集群
redis,集群,cluster
1033 0
那些年用过的Redis集群架构(含面试解析)
Replication+Sentinel这套架构使用的是社区版本推出的原生高可用解决方案! 这里Sentinel的作用有三个: 监控:Sentinel 会不断的检查主服务器和从服务器是否正常运行。 通知:当被监控的某个Redis服务器出现问题,Sentinel通过API脚本向管理员或者其他的应用程序发送通知。
4273 0
Windows下搭建Redis集群
原文:Windows下搭建Redis集群  Redis集群:  如果部署到多台电脑,就跟普通的集群一样;因为Redis是单线程处理的,多核CPU也只能使用一个核, 所以部署在同一台电脑上,通过运行多个Redis实例组成集群,然后能提高CPU的利用率。
1021 0
Redis-4.0.11集群配置
版本:redis-3.0.5 redis-3.2.0  redis-3.2.9  redis-4.0.11 参考:http://redis.io/topics/cluster-tutorial。
2683 0
13688
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载