zookeeper之于分布式系统的意义

分布式系统中普遍存在的问题 

  • 可用性

        现在很多时候我们的服务需要7*24小时工作,假如一台机器挂了,我们希望能有其它机器顶替它继续工作。此类问题现在多采用master-salve模式,也就是常说的主从模式,正常情况下主机提供服务,备机负责监听主机状态,当主机异常时,可以自动切换到备机继续提供服务(这里有点儿类似于数据库主库跟备库,备机正常情况下只监听,不工作),这个切换过程中选出下一个主机的过程就是master选举。

        举个栗子,比如我们利用nginx作为代理服务器,把用户的访问代理到Web服务器上,如下图:

试想,nginx绑定了一个VIP(虚拟IP地址),然后把用户请求代理到Web服务器上,那么如果nginx出现了故障,不能转发客户请求给Web服务器了,于是整个系统就无法对外处理用户的请求了,系统处于一种不可用的状态,这就是称之为单点故障。面临这种单点故障,我们应该怎么解决呢?也就是我们必须对外提供高可用(High Availability)的服务。一种解决办法就是nginx部署多台(例如2台)服务器,当一台故障后另一台对外提供服务,这就是经典的Master-Slave的机制。如下图,他们之间使用一个PING/PONG机制,去探测对方是否存在,如果收不到对方的PING或者PONG信息,那么就认为对端挂掉了,比如Slave收不到PONG消息,则认为对端挂了,此时Slave的nginx则设置VIP,然后对外提供服务,看起来十分完美,但是如果是因为网络问题而收不到PONG消息呢?这个时候Slave也会认为Master断开了,Slave nginx也会自我选举成为一个Master nginx,于是系统中就出现了两个Master同时对外提供服务,这就会乱套了,像这么一个情况,我们称之为脑裂。那如何解决这种脑裂问题呢?其实,上面我们依赖了一种PING/PONG的机制在选举Master,这种选举机制有缺陷,那么比较好的办法就是引入一个第三方,比如zookeeper,去选举Master。那如何利用zookeeper去做呢?预知后事如何,且听下文分解!

  • 服务发现上的负载均衡

        先来看一个例子,比如在我们的一个游戏服务系统是一个分布式的系统,系统结构如下图所示:

        里面的GameServer在处理业务时需要调用DataServer的接口update数据。也就是说GameServer必须知道DataServer的IP地址和端口号,惯用做法把IP、port写入配置文件,比如:

<?xml version="1.0" encoding="UTF-8"?>

<root version="1.0">

  <!--gameserver监听端口-->

    <HostServer type="1" id="1">

      <bind ip="192.168.1.134" port="8500" type="0"/>

      <register ip="192.168.1.134" />

    </HostServer>



  <!--连接datacenter的端口-->

  <DataServer>

    <connect ip="192.168.1.135" port="8600" type="0" />

  </DataServer>

  

  <RecvBuffer>

    <buf msgHeadLen="12" clientBuf="40960" serverBuf="1024000" />

  </RecvBuffer>

</root>

        咋一看,并不会有什么问题,其实这种方式有很大问题:

        问题一:GameServer启动的时候就去连接DataServer,连接并去发送消息可能没有什么问题,如果DataServer启动时端口是监听起来了,可是启动后,发现处理业务消息的某个模块不可用。此时GameServer并不知情这个这个情况,反正已经开始发送业务消息给DataServer了。像这么一种情况,我们可以称之为优雅发布问题

        问题二:游戏服务整体已经可用了,但是研发内部说要整治下服务,需要重新梳理各个系统的IP配置,我们惯用做法还是去更新这个配置文件中的ip的值,然后重启GameServer使之生效,在这个过程中势必导致GameServer的短暂不可用。这样一种情况,我们称之为优雅更新配置问题,当然增加DataServer的部署也会导致这个问题。

        问题三:比如,在游戏过程中,突然DataServer宕机了,或者DataServer应用崩溃了,导致对外不可用,那么GameServer如何感知到,并且不再发送请求到DataServer呢?这个问题其实就是服务健康检查,比如nginx也提供了健康检查。

        上面三个问题我们可以用服务发现的机制去解决的,那么什么叫做服务主动发现以及如何设计并实现呢?而且如果DataServer是一种异构的服务配置,也就是说他们的硬件配置不一样,这样GameServer就必须通过权重配比的方式去发送请求给多个DataServer。那利用zookeeper是怎么做呢?

当然,除了可用性和服务发现问题外,还有自动化配置,数据发布订阅,分布式队列,分布式锁等等,以及zookeeper内部是如何设计,以至于它能解决这些问题。还有zookeeper对外提供可用性,那么它自己又是如何保障可用性的呢,如果是集群的话,那么它们又是如何确保数据的一致性的呢?还有很多分布式常见的问题,就不一一细数了。

ZooKeeper是什么的简介 

  • ZooKeeper 的由来

        下面这段内容摘自《从Paxos到Zookeeper 》第四章第一节的某段内容,推荐大家阅读以下:

Zookeeper最早起源于雅虎研究院的一个研究小组。在当时,研究人员发现,在雅虎内部很多大型系统基本都需要依赖一个类似的系统来进行分布式协调,但是这些系统往往都存在分布式单点问题。所以,雅虎的开发人员就试图开发一个通用的无单点问题的分布式协调框架,以便让开发人员将精力集中在处理业务逻辑上。

关于“ZooKeeper”这个项目的名字,其实也有一段趣闻。在立项初期,考虑到之前内部很多项目都是使用动物的名字来命名的(例如著名的Pig项目),雅虎的工程师希望给这个项目也取一个动物的名字。时任研究院的首席科学家RaghuRamakrishnan开玩笑地说:“在这样下去,我们这儿就变成动物园了!”此话一出,大家纷纷表示就叫动物园管理员吧一一一因为各个以动物命名的分布式组件放在一起,雅虎的整个分布式系统看上去就像一个大型的动物园了,而Zookeeper正好要用来进行分布式环境的协调一一于是,Zookeeper的名字也就由此诞生了。

  • ZooKeeper是什么

        ZooKeeper 是一个开源的分布式协调服务,ZooKeeper框架最初是在“Yahoo!"上构建的,用于以简单而稳健的方式访问他们的应用程序。 后来,Apache ZooKeeper成为Hadoop,HBase和其他分布式框架使用的有组织服务的标准。 例如,Apache HBase使用ZooKeeper跟踪分布式数据的状态。ZooKeeper 的设计目标是将那些复杂且容易出错的分布式一致性服务封装起来,构成一个高效可靠的原语集,并以一系列简单易用的接口提供给用户使用。

原语: 操作系统或计算机网络用语范畴。是由若干条指令组成的,用于完成一定功能的一个过程。具有不可分割性·即原语的执行必须是连续的,在执行过程中不允许被中断。

        ZooKeeper 是一个典型的分布式数据一致性解决方案,分布式应用程序可以基于 ZooKeeper 实现诸如数据发布/订阅负载均衡服务发现分布式协调/通知集群管理Master 选举分布式锁分布式队列等功能。

        Zookeeper 一个最常用的使用场景就是用于担任服务生产者和服务消费者的注册中心。 服务生产者将自己提供的服务注册到Zookeeper中心,服务的消费者在进行服务调用的时候先到Zookeeper中查找服务,获取到服务生产者的详细信息之后,再去调用服务生产者的内容与数据。如下图所示,使用 Zookeeper 担任了注册中心这一角色。

  • zookeeper内部的数据模型

        在zookeeper内部维护了一个树的结构,如下图所示,跟unix的文件目录类似,但是它的每一个节点下还有很多的属性,这一点在接下来的内容中会分享的。

  • ZooKeeper是集群化部署的

        zookeeper可以单点部署,也可以集群化部署,集群部署后有多个服务对外提供创建、更新和删除节点的服务。

为什么要学习zookeeper? 

  • ZooKeeper的特点

    • 顺序一致性: 从同一客户端发起的事务请求,最终将会严格地按照顺序被应用到 ZooKeeper 中去。

    • 原子性: 所有事务请求的处理结果在整个集群中所有机器上的应用情况是一致的,也就是说,要么整个集群中所有的机器都成功应用了某一个事务,要么都没有应用。

    • 单一系统映像 : 无论客户端连到哪一个 ZooKeeper 服务器上,其看到的服务端数据模型都是一致的。

    • 可靠性: 一旦一次更改请求被应用,更改的结果就会被持久化,直到被下一次更改覆盖,即使在这个过程中,即使有一些zookeeper服务挂掉了。

        我们可以利用这些特点,在系统中提供数据发布/订阅负载均衡服务发现分布式协调/通知集群管理Master 选举分布式锁分布式队列等功能,那么这些功能实现原理是什么,并且如何编码的?

        在使用zookeeper过程中,可能会遇到很多的坑,这些坑又如何避免呢?

        我们很多人可能仅仅把zookeeper当作一个服务组件,仅仅是了解如何使用它,但是这不够,我们更应该了解它的一些机制,不如顺序一致性是怎么做到的?原子性操作又是如何做到的,集群时对外提供了可靠性的服务,那么这种可靠性是怎么实现的呢?如果学习了它的这些处理机制后,我们就可以借它山之石,去攻自己的玉,也就是应用到自己的系统架构设计中。

        大家在阅读这篇文章时,可能会觉得我提了太多问题了,但是会问问题的就是会思考的,希望通过这些问题去意识到zookeeper的重要性。

猜你喜欢

转载自blog.csdn.net/qq_42302962/article/details/98970499