HTML5技术

游戏服务端究竟解决了什么问题? - fingerpass(11)

字号+ 作者:H5之家 来源:H5之家 2016-02-02 09:51 我要评论( )

上一节末提到过,要想最小化数据迁移成本可以采用两段映射或一致性哈希。这时还有另一种可以扩展的思路,如果采用两段映射,那么我们可以动态下发第二段的配置数据;如果采用一致性哈希,那么我们可以动态下发分片

  上一节末提到过,要想最小化数据迁移成本可以采用两段映射或一致性哈希。这时还有另一种可以扩展的思路,如果采用两段映射,那么我们可以动态下发第二段的配置数据;如果采用一致性哈希,那么我们可以动态下发分片的连接信息。这其中的动态,就可以基于新的符合Phial规范的服务来做。而这个通知机制,就非常适合采用Phial中的Notify pattern实现。而且redis sentinel的实现难度比较低,我们完全可以以较低的成本实现一个扩展性更强,定制性更强,还能额外支持分片服务的部分在线数据迁移机制的服务。
  同时,有一部分我在这篇文章里也没提过,那就是落地服务所依赖的mysql的可用性保障机制。相比于再开一个额外的mysql高可用组件,倒不如整合到同样的一个数据服务监控服务中。

  这个监控服务就是watcher。由于原理类似,接下来的讨论就不再涉及对mysql的监控部分,只针对redis的。

watcher解决了什么问题?
  • 要能够监控redis的生存状态。这一点实现起来很简单,定期的PING redis实例即可。需要的信息以及做出客观下线和主观下线的判断依据都可以直接照搬sentinel实现。
  • 要做到自主服务发现,包括其他watcher的发现与所监控的master-slave组中的新节点的发现。前者基于MQ定期Notify通知,后者定期INFO 监控的master实例即可。
  • 要在发现master客观下线的时候选出leader进行后续的故障转移流程。这部分实现起来算是最复杂的部分,接下来会集中讨论。
  • 选出leader之后将一个最合适的slave提升为master,然后等老的master再上线了就把它降级为新master的slave。
  •   解决这些问题,watcher的职责就已经达成,我们的数据服务也就更加健壮,可用程度更高。

    引入新的问题

      但是,如果我们引入了新的服务,那就引入了新的不确定性。如果引入这个服务的同时还要保证数据服务具有可用性,那我们就还得保证这个服务本身是可用的。

      先简单介绍一下redis sentinel的可用性是如何做到的。同时监控同一组主从的sentinel可以有多个,master挂掉的时候,这些sentinel会根据一种raft算法的工业级实现选举出leader,算法流程也不是特别复杂,至少比paxos简单多了。所有sentinel都是follower,判断出master客观下线的sentinel会升级成candidate同时向其他follower拉票,所有follower同一epoch内只能投给第一个向自己拉票的candidate。在具体表现中,通常一两个epoch就能保证形成多数派,选出leader。有了leader,后面再对redis做SLAVEOF的时候就容易多了。


      如果想用watcher取代sentinel,最复杂的实现细节可能就是这部分逻辑了。
      这部分逻辑说白了就是要在分布式系统中维护一个一致状态,举个例子,可以将“谁是leader”这个概念当作一个状态量,由分布式系统中的身份相等的几个节点共同维护,既然谁都有可能修改这个变量,那究竟谁的修改才奏效呢?


      幸好,针对这种常见的问题情景,我们有现成的基础设施抽象可以解决。

      这种基础设施就是分布式系统的协调器组件(coordinator),老牌的有zookeeper(zab),新一点的有etcd(raft)。这种组件通常没有重复开发的必要,像paxos这种算法理解起来都得老半天,实现起来的细节数量级更是难以想象。因此很多现成的开源项目都是依赖这两者实现高可用的,比如codis就是用的zk。

    zk解决了什么问题?

      就我们的游戏服务端需求来说,zk可以用来选leader,还可以用来维护dbClient的配置数据——dbClient直接去找zk要数据就行了。

      zk的具体原理我就不再介绍了,具体的可以参考lamport的paxos paper,没时间没精力的话搜一下看看zk实现原理的博客就行了。

     

      简单介绍下如何基于zk实现leader election。zk提供了一个类似于os文件系统的目录结构,目录结构上的每个节点都有类型的概念同时可以存储一些数据。zk还提供了一次性触发的watch机制。leader election就是基于这几点概念实现的。

      假设有某个目录节点/election,watcher1启动的时候在这个节点下面创建一个子节点,节点类型是临时顺序节点,也就是说这个节点会随创建者挂掉而挂掉,顺序的意思就是会在节点的名字后面加个数字后缀,唯一标识这个节点在/election的子节点中的id。

      一个简单的方案是我们可以每个watcher都watch /election的所有子节点,然后看自己的id是否是最小的,如果是就说明自己是leader,然后告诉应用层自己是leader,让应用层进行后续操作就行了。但是这样会产生惊群效应,因为一个子节点删除,每个watcher都会收到通知,但是至多一个watcher会从follower变为leader。

      优化一些的方案是每个节点都关注比自己小一个排位的节点。这样如果id最小的节点挂掉之后,id次小的节点会收到通知然后了解到自己成为了leader,避免了惊群效应。

      还有一点需要注意的是,临时顺序节点的临时性体现在一次session而不是一次连接的终止。例如watcher1每次申请节点都叫watcher1,第一次它申请成功的节点全名假设是watcher10002(后面的是zk自动加的序列号),然后下线,watcher10002节点还会存在一段时间,如果这段时间内watcher1再上线,再尝试创建watcher1就会失败,然后之前的节点过一会儿就因为session超时而销毁,这样就相当于这个watcher1消失了。解决方案有两个,可以创建节点前先显式delete一次,也可以通过其他机制保证每次创建节点的名字不同,比如guid。

     

      至于配置下发,就更简单了。配置变更时直接更新节点数据,就能借助zk通知到关注的dbClient,这种事件通知机制相比于轮询请求sentinel要配置数据的机制更加优雅。

     

      我在实现中将zk作为路由协议的一种整合进了Phial规范,这样基于zk的消息通知可以直接走Phial的RPC协议。

      有兴趣的同学可以看下我实现的zkAdaptor,leader election的功能作为zkAdaptor的特殊API,watcherService会直接调用。而配置下发直接走了RPC协议,集成在统一的Phial.RPC规范中。zkAdaptor仅支持Phial.RPC中的Notify pattern。

     

      watcher的实现在这里。

     

    5.总结目前形成的架构以及能做什么

     

     

    1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

    相关文章
    • 网页版扫雷游戏 - 季末的寂寞

      网页版扫雷游戏 - 季末的寂寞

      2017-04-21 13:00

    • net.sz.framework 框架 登录服务器架构 单服2 万 TPS(QPS) - 失足程序员

      net.sz.framework 框架 登录服务器架构 单服2 万 TPS(QPS) - 失足

      2017-04-13 11:05

    • 面向个人的技术咨询服务 - 思想瞭望者

      面向个人的技术咨询服务 - 思想瞭望者

      2017-04-05 12:07

    • net.sz.framework 框架 轻松搭建服务---让你更专注逻辑功能---初探 - 失足程序员

      net.sz.framework 框架 轻松搭建服务---让你更专注逻辑功能---初探 -

      2017-04-02 10:11

    网友点评
    o