一个豁达的关键是正确乐观的面对失败的系统。不需要过多的担心,需要一种去说那又怎样的能力。因此架构的设计是如此的重要。许多优秀的系统没有进一步成长的能力,我们应该做的是去使用其他的系统去共同分担工作。

Redis是其中一个吸引我的系统,一个持久性的,键值对 存储内存操作高性能的平台。他是一个优秀的键值对数据库。我已经在使用了。即使AWS最近宣布开始支持ElasticCache的下级缓存。但是一个无主 的redis集群仍然起着重要的作用。我们需要多系统去完成工作。同时,我们能够集合多种组件在一个容错和无主的集群里共同工作么?在这片文章中我将介绍 梦幻般的redis。

一致哈希

构建一个存储数据集群的关键是有一个有效的数据存储和复制机制。我希望通过一个行之有效的方法来说明建造一个数据集群,在这个过程中你可以随意添加或移除一个Redis节点,同时保证你的数据仍然存在,而不会消失。这个方法称为一致哈希。

由于它不是一个很明显的概念,我将用一点时间来解释一下。 为了理解一致哈希,你可以想像有一个函数f(x),对于给定的x总是返回一个1到60(为什么是60?你会知道的,但现在请等等)之间的结果,同样对于一 个唯一的x,f(x)总是返回相同的结果。这些1到60的值按顺时针排成一个环。

现在集群中的每个节点都需要一个唯一的名字,是吧?所以如
果你将这个名字传递给f('<redis_node_name>'),它将返回一个1到60之间的数字(包括1和60),这个数字就是节点在
环上的位置。当然它只是节点的逻辑(记录的)位置。这样,你获得一个节点,将它传给哈希函数,获得结果并将它放到环上。是不是很简单?这样每个节点都在环
上有了它自己的位置。假设这里有5个Redis节点,名字分别为'a','b','c','d','e'。每个节点都传给哈希函数f(x)并且放到了环
上。在这里f('a') = 21, f('b') = 49, f('c') = 11, f('d') = 40, f('e') =
57。一定记得这里位置是逻辑位置。

那么,我们为什么要将节点放在一个环上呢?将节点放到环上
的目的是确定拥有哪些哈希空间。图中的节点'd'拥有的哈希空间就是f('a')到f('d')(其值为40)之间的部分,包括f('d'),即(21,
40]。也就是说节点'd'将拥有键x,如果f(x)的属于区间(21, 40]。比如键‘apple’,其值f('apple') =
35,那么键'apple'将被存在'd'节点。类似的,每个存储在集群上的键都会通过哈希函数,在环上按顺时针方向被恰当地存到最近的节点。

虽然一致哈希讲完了,但应知道,在多数情况下,这种类型的
系统是伴随着高可用性而构建。为了满足数据的高可用性,需要根据一些因子进行复制,
这些因子称为复制因子。假设我们集群的复制因子为2,那么属于'd'节点的数据将会被复制到按顺时针方向与之相隔最近的'b'和'e'节点上。这就保证了
如果从'd'节点获取数据失败,这些数据能够从'b'或'e'节点获取。

不仅仅是键使用一致哈希来存储,也很容易覆盖失败了的节点,并且复制因子依然完好有效。比如'd'节点失败了,'b'节点将获取'd'节点哈希空间的所有权,同时'd'节点的哈希空间能够很容易地复制到'c'节点。

坏事和好事

坏事就是目前这些讨论过的所有概念,复制(冗余),失效处理以及集群规模等,在Redis之外是不可行的。一致哈希仅仅描述了节点在哈希环上的映射以及那些哈希数据的所有权,尽管这样,它仍然是构建一个弹性可扩展系统的极好的开端。

好事就是,也有一些分立的其他工具在Redis集群上实现一致哈希,它们能提醒节点失效和新节点的加入。虽然这个功能不是一个工具的一部分,我们将看到如何用多个系统来使一个理想化的Redis集群运转起来。

Twemproxy aka Nutcracker

Twemproxy是一个开源工具,它是一个基于memcached和Redis协议的快速、轻量的代理。其本质就是,如果你有一些Redis服务器在运行,同时希望用这些服务器构建集群,你只需要将Twemproxy部署在这些服务器前端,并且让所有Redis流量都通过它。

Twemproxy除了能够代理Redis流量外,在它存储数据在Redis服务器时还能进行一致哈希。这就保证了数据被分布在基于一致哈希的多个不同Redis节点上。

但是Twemproxy并没有为Redis集群建立高可用性支持。最简单的办法是为集群中的每个节点都建立一个从(冗余)服务器,当主服务器失效时将从(冗余)服务器提升为主服务器。为Redis配置一个从服务器是非常简单的。

这种模型的缺点是非常明显的,它需要为Redis集群中的每个节点同时运行两个服务器。但是节点失效也是非常明显,并且更加危险,所以我们怎么知道这些问题并解决。

Gossip on Serf

Gossip是一个标准的机制,通过这个机制集群上的节点可以很清楚的了解成员的最新情况。这样子集群中的每个节点就很清楚集群中节点的变化,如节点的新增和节目的删除。

Serf通过实现Gossip机制提供这样的帮助。Serf是一个基于代理的机制,这个机制实现了Gossip的协议达到节点成员信息交换的目的。Serf是不断运行,除此之外,它还可以生成自定义的事件

现在拿我们的节点集群为例,如果每个节点上也有一个serf代理正在运行,那么节点与节点之间可以进行细节交换.因此,群集中的每个节点都能清楚知道其他节点的存在,也能清楚知道他们的状态。

这还并不够,为了高可靠性我们还需要让twemproxy
知道何时一个节点已经失效,这样的话它就可以据此修改它的配置。像前面提到的Serf,就可以做到这一点,它是基于一些gossip触发的事件,使用自定
义动作实现的。因此只要集群中的一个Redis节点因为一些原因宕掉了,另一个节点就可以发送有成员意外掉线的消息给任何给定的端点,这个端点在我们的案
例中也就是twemproxy服务器。

这还不是全部

现在我们有了Redis集群,基于一致性哈希环,相应的是用twemproxy存储数据(一致性哈希),还有Serf,它用gossip协议来检测Redis集群成员失效,并且向twemproxy发送失效消息;但是我们还没有建立起理想化的Redis集群。

消息侦听器

虽然Serf可以给任何端点发送成员离线或者成员上线消息。然而twemproxy却没有侦听此类事件的机制。因此我们需要自定义一个侦听器,就像Redis-Twenproxy代理,它需要做以下这些事情。

  • 侦听Serf消息
  • 更新nutcraker.yml 以反映新的拓扑
  • 重启twemproxy

这个消息侦听器可以是一个小型的http服务器;它在收到
一批POST数据的时候,为twemproxy做以上列表中的动作。需要记住的是,这种消息应该是一个原子操作;因为当一个节点失效(或者意外离线)的时
候,所有能发消息的活动节点都将发送这个失效事件消息给侦听器;但是侦听器应该只响应一次。

数据复制

在上面的“一致哈希”中,我提到了Redis集群中的复制
因素。同样它也不是Twemproxy的固有特性;Twemproxy只关心使用一致哈希存储一个拷贝。所以在我们追求理想化Redis集群的过程中,我
们还需要给twemproxy或者redis自己创建这种复制的能力。

为了给Twenproxy创建复制能力,需要将复制因子作为一个配置项目,并且将数据保存在集群中相邻的redis节点(根据复制因子)。由于twemproxy知道节点的位置,所以这将给twemproxy增加一个很棒的功能。

由于twemproxy只不过是代理服务器,它的简单功能就是它强大的地方,为它创建复制管理功能将使它臃肿膨胀。

Redis 主从环

在思考这其中的工作机制的时候,我忽然想到,为什么不将每个节点设置成另一个节点的副本,或者说从节点,并由此而形成一个主从环呢?

这样的话如果一个节点失效了,失效节点的数据在这个环上相
邻的节点上仍然可以获得。而那个具有该数据副本的节点,将作为该节点的从节点,并提供保存数据副本的服务。这是一个既是主节点也是从节点的环。Serf仍
像通常一样作为散布节点失效消息的代理。但是这一回,我们twenproxy上的的客户端,即侦听器,将不仅仅只更新twenproxy上的失效信息,还
要调整redis服务器群集来适应这个变化。

在这个环中有一个明显的,同样也是技术方面的缺陷。这个明显的缺陷是,这个环会坏掉,因为从节点的从节点无法判别哪一个是它的主节点的数据,哪一个是它的主节点的主节点的数据。这样的话就会循环的传送所有的数据。

同样技术性的问题是,一旦redis将主节点的数据同步给
从节点,它就会将从节点的数据擦除干净;这样就将曾经写到从节点的所有数据删除了。这种主从环显然不能实际应用,除非修改主从环的复制机制以适应我们的需
求。这样的话每个从节点就不会将它的主节点的数据同步给它的从节点。要想实现这一点,必须的条件是每个节点都可以区分出自己的密钥空间,以及它的主节点的
密钥空间;这样的话它就不会将主节点的数据传送给它的从节点。

那么这样一来,当一个节点失效时,就需要执行四个动作。一,将失效节点的从节点作为它的密钥空间的所有者。二,将这些密钥散布给失效节点从节点的从节点,以便进行复制。三,将失效节点的从节点作为失效节点的主节点的从节点。最后,在新的拓扑上复位twemproxy。

如何理想化?

事实上并没有这样的Redis集群,它可以具有一致性的哈希,高可靠性以及分区容错性。因此最后一幅图片描绘了一种理想化的Redis集群;但这并不是不可能的。接下来将罗列一下需要哪些条件才能使之成为一个实实在在的产品。

透明的Twenproxy

有必要部署一个Twenproxy,这会使得Hash散列中Redis各节点的位置都是透明的。每个Redis节点都可以知道自己以及其相邻节点的位置,这些信息对于节点的主从复制以及失败节点的修复是有必要的。自从Twenproxy开源之后,节点的位置信息可以被修改、以及扩展。

Redis的数据拥有权

这是比较困难的部分的,每个Redis节点都应该记录自身拥有的数据,以及哪些是主节点的数据。当前这样的隔离是不可能的。这也需要修改Redis的基础代码,这样节点才知道何时与从节点同步,什么时候不需要。

综上所述,我们的理想化的Redis集群变成现实需要修改这样的两个组件。一直以来,它们都是非常大的工业级别,使用在生产环境中。这已经值得任何人去实现(这个集群了)。

本文转自:开源中国社区 [http://www.oschina.net]
本文标题:理想化的 Redis 集群
本文地址:http://www.oschina.net/translate/utopian-redis-cluster
参与翻译:晴风晓月, super0555, wobuzhidao_, Longears, JAVA草根

英文原文:Utopian Redis Cluster

(转)理想化的 Redis 集群的更多相关文章

  1. Redis集群案例与场景分析

    1.背景 Redis的出现确实大大地提高系统大并发能力支撑的可能性,转眼间Redis的最新版本已经是3.X版本了,但我们的系统依然继续跑着2.8,并很好地支撑着我们当前每天5亿访问量的应用系统.想当年 ...

  2. Java Spring mvc 操作 Redis 及 Redis 集群

    本文原创,转载请注明:http://www.cnblogs.com/fengzheng/p/5941953.html 关于 Redis 集群搭建可以参考我的另一篇文章 Redis集群搭建与简单使用 R ...

  3. Redis集群搭建与简单使用

    介绍安装环境与版本 用两台虚拟机模拟6个节点,一台机器3个节点,创建出3 master.3 salve 环境. redis 采用 redis-3.2.4 版本. 两台虚拟机都是 CentOS ,一台 ...

  4. window下使用Redis Cluster部署Redis集群

    日常的项目很多时候都需要用到缓存.redis算是一个比较好的选择.一般情况下做一个主从就可以满足一些比较小的项目需要.在一些并发量比较大的项目可能就需要用到集群了,redis在Windows下做集群可 ...

  5. Redis集群~windows下搭建Sentinel环境及它对主从模式的实际意义

    回到目录 关于redis-sentinel出现的原因 Redis集群的主从模式有个最大的弊端,就是当主master挂了之前,它的slave从服务器无法提升为主,而在redis-sentinel出现之后 ...

  6. [个人翻译]Redis 集群教程(中)

    上一篇:http://www.cnblogs.com/li-peng/p/6143709.html 官方原文地址:https://redis.io/topics/cluster-tutorial  水 ...

  7. [个人翻译]Redis 集群教程(上)

    官方原文地址:https://redis.io/topics/cluster-tutorial  水平有限,如果您在阅读过程中发现有翻译的不合理的地方,请留言,我会尽快修改,谢谢.        这是 ...

  8. Redis集群(九):Redis Sharding集群Redis节点主从切换后客户端自动重新连接

    上文介绍了Redis Sharding集群的使用,点击阅读 本文介绍当某个Redis节点的Master节点发生问题,发生主从切换时,Jedis怎样自动重连新的Master节点 ​一.步骤如下: 1.配 ...

  9. Redis集群(八):Redis Sharding集群

    一.Redis目前的集群方案主要有两种:Redis Sharding和Redis Cluster 1.Redis Sharding:3.0以前基本上使用分片实现集群,目前主流方案,客户端实现 2.Re ...

随机推荐

  1. C++11新特性(3) lambda表达式(1)

    C++11加入了一项名为lambda表达式的新功能.通过这项功能能编写内嵌的匿名函数,而不必编写独立函数或函数对象,使得代码更加理解. lambda表达式包括下面部分. [capture_block] ...

  2. Codeforces Round #Pi (Div. 2) D. One-Dimensional Battle Ships set区间分解

    D. One-Dimensional Battle ShipsTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/co ...

  3. Python的包管理工具Pip

    接触了Ruby,发现它有个包管理工具RubyGem非常好用,而且有非常完备的文档系统http://rdoc.info 发现Python下也有相同的工具,包含easy_install和Pip.只是,我没 ...

  4. 归并排序的C语言实现

    归并排序的核心思想是 Divide-and-Conquer 算法,即将要解决的size为n的问题,分成a个size为n/b的子问题,这些子问题的结果经过O(n^d)的时间复杂度合并,即可解决最初的问题 ...

  5. iOS开发——Swift篇&文件,文件夹操作

    文件,文件夹操作   ios开发经常会遇到读文件,写文件等,对文件和文件夹的操作,这时就可以使用NSFileManager,NSFileHandle等类来实现. 下面总结了各种常用的操作:   1,遍 ...

  6. Nhibernate中 Many-To-One 中lazy="proxy" 延迟不起作用的原因

    2010-07-15 12:10 by 彭白洋, 322 阅读, 0 评论, 收藏, 编辑 NHibernate中 Many-To-One 中lazy="proxy" 延迟不起作用 ...

  7. android138 360 小火箭

    package com.itheima52.rocket; import android.app.Service; import android.content.Context; import and ...

  8. leetcode -- Search for a Range (TODO)

    Given a sorted array of integers, find the starting and ending position of a given target value. You ...

  9. kafka彻底删除topic

    如果只是用kafka-topics.sh的delete命令删除topic,会有两种情况: 如果当前topic没有使用过即没有传输过信息:可以彻底删除 如果当前topic有使用过即有过传输过信息:并没有 ...

  10. RabbitMQ+PHP 消息队列环境配置

    参考文档:http://www.cnblogs.com/phpinfo/p/4104551...http://blog.csdn.net/historyasamirror/ar... 依赖包安装 yu ...