Riak - 背景篇(2)

Dynamo备份思想

因为我们用的PC机器性能不一,质量参差不齐,可能每天都会有机器挂掉或者重启。我们需要保证在某个机器挂掉或者损坏时,保证工作的正常运行。
我们可能最先想到的就是,给每个节点机器加一台备用的节点。这样,在主节点宕机时,备节点就可以顶上去。但是仔细想一下,这个方案是让人不放心的。因为当一主一备中的某一台机器坏掉,另外一台就成了一个单点运行的节点。这个时候另外一个节点一旦发生错误,服务就变得不可用,数据也有可能丢失。在一个要求高可靠性的系统上,这是不可忍受的。
那么,这样,我们就再加一个呗,一主两备。或者说,我们做个集群,集群内有多台,动态选主。但是这么做,无疑增加了成本。而且如果架构设计的不好,宕机重启的工作很麻烦,而且故障排查,也很麻烦。
我们可以抛弃主备的思想,运用无主集群。而且,尽量不添加额外的备用机器。那么,我们可以考虑在现有的机器上多备份几份。一般工业界认为比较安全的备份数应该是3份。好,那么我们看看做这个备份的时候需要注意的问题。

  1. 如何选择备份节点:假设我们简单的让某一段运单的数据备份到环上面顺序后两个节点上。但是,这样有个问题,对于11-20,它会保存到BAB上,而这就相当于只保存在了两个机器上,并不是严格意义的写三份。
    Riak - 背景篇(2)_第1张图片
    所以,我们可以这么规定,某一段运单的数据备份到环上面顺序后不在同一台机器且与本台机器不同的两个节点上。如下图所示:
    Riak - 背景篇(2)_第2张图片
    这时我们发现,有了备份后,某些虚分片上的数据过多。我们可以改进虚分片的分配方式,或者改进备份环算法。但是注意,最好改进虚分片分配方式,备份环算法修改需要考虑不要丢失一致性哈希的思想。

  2. 当一个节点离开系统的时候,比如宕机,这个节点上存储的信息需要继续备份到其它节点上。虽然节点离开了系统,但是因为备份的存在,我们通过其他节点可以恢复出本节点的所有信息,因为该节点的离开,这部分信息的备份数会比要求的备份数少一,所以需要把这部分数据做再备份。假设B这台机器挂了,它对应虚节点环上之后的节点会承担起他的工作,这里是A,但是对于1-10和31-40,我们需要交给C和D,因为我们要保证在不同的机器上写三份。这时,A、C、D对应的那四个虚节点会承担起B的那两个虚节点的所有数据。如下图所示
    Riak - 背景篇(2)_第3张图片

  3. 一个节点如果只是暂时性的不可达,也就是失效一个很短的时间(这种情况是最常发生的),那么需要其他节点暂时接管这个节点的工作,在其可用的时候,把数据增量传送回该节点。比如说B又恢复了,这时,A、C、D需要把工作交回给B,并把对应虚节点的增量更新同步给B。

  4. 同样,当一个节点加入系统,从其他节点偷了数据后,其他节点也需要相应减少备份数。

NWR模型与同步和异步备份

在设计上述节点同步备份方案时,我们还需要搞清楚,各个节点间数据备份是同步还是异步的。
CAP是老生常谈的理论,Dynamo首先保证了P,这时就要在C和A之间取舍。
假设,我们需要强一致性(C),就是读取一定读取到最新更新的数据,就是每次快递员只要成功更新了运单状态,即能立刻看到更新。那么我们就需要同步数据备份。继续沿用上面的例子,我们在更新运单1时,必须保证E,B,A机器上对应的虚节点都更新好,再返回。这样会牺牲一定的写入性能,而且有时写入会失败(多台机器挂掉,无法写三份),但保证了强一致性。
假设,我们要保证高可用性(A),要求写请求总是尽可能的成功,就是无论何时,快递员都可以更新运单状态,那么我们的策略是写任何一个节点成功就认为成功。节点之间的数据通过异步形式达成一致,这个时候读请求可能读不到最新写进去的信息。
Dynamo 的处理方式是把这个选择权交给用户,这就是它的N W R模型。N代表N个备份,W代表要写入至少W份才认为成功,R表示至少读取R个备份。配置的时候要求W+R > N。 因为W+R > N, 所以 R > N-W 这个是什么意思呢?就是读取的份数一定要比总备份数减去确保写成功的倍数的差值要大。
也就是说,每次读取,都至少读取到一个最新的版本。从而不会读到一份旧数据。当我们需要高可写的环境的时候(例如,amazon的购物车的添加请求应该是永远不被拒绝的)我们可以配置W = 1 如果N=3 那么R = 3。 这个时候只要写任何节点成功就认为成功,但是读的时候必须从所有的节点都读出数据。如果我们要求读的高效率,我们可以配置 W=N R=1。这个时候任何一个节点读成功就认为成功,但是写的时候必须写所有三个节点成功才认为成功。
大家注意,一个操作的耗时是几个并行操作中最慢一个的耗时。比如R=3的时候,实际上是向三个节点同时发了读请求,要三个节点都返回结果才能认为成功。假设某个节点的响应很慢,它就会严重拖累一个读操作的响应速度。

<script type="text/javascript"> $(function () { $('pre.prettyprint code').each(function () { var lines = $(this).text().split('\n').length; var $numbering = $('<ul/>').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($('<li/>').text(i)); }; $numbering.fadeIn(1700); }); }); </script>

你可能感兴趣的:(Riak - 背景篇(2))