天天看点

《ZooKeeper:分布式过程协同技术详解》——第1章 简介1.1 ZooKeeper的使命

本节书摘来自华章计算机《zookeeper:分布式过程协同技术详解》一书中的第1章,第1.1节,作者:flavio junqueira, benjamin reed 更多章节内容可以访问云栖社区“华章计算机”公众号查看。

zookeeper的概念和基础

这一部分适合任何对zookeeper感兴趣的读者,该部分介绍zookeeper所处理的问题,以及在zookeeper的设计中的权衡取舍。

在计算机诞生之后很长的一段时间里,一个应用服务是在一个独立的单处理器计算机上运行一段程序。时至今日,应用服务已经发生了很大的变化。在大数据和云计算盛行的今天,应用服务由很多个独立的程序组成,这些独立的程序则运行在形形色色、千变万化的一组计算机上。

相对于开发在一台计算机上运行的单个程序,如何让一个应用中多个独立的程序协同工作是一件非常困难的事情。开发这样的应用,很容易让很多开发人员陷入如何使多个程序协同工作的逻辑中,最后导致没有时间更好地思考和实现他们自己的应用程序逻辑;又或者开发人员对协同逻辑关注不够,只是用很少的时间开发了一个简单脆弱的主协调器,导致不可靠的单一失效点。

zookeeper的设计保证了其健壮性,这就使得应用开发人员可以更多关注应用本身的逻辑,而不是协同工作上。zookeeper从文件系统api得到启发,提供一组简单的api,使得开发人员可以实现通用的协作任务,包括选举主节点、管理组内成员关系、管理元数据等。zookeeper包括一个应用开发库(主要提供java和c两种语言的api)和一个用java实现的服务组件。zookeeper的服务组件运行在一组专用服务器之上,保证了高容错性和可扩展性。

当你决定使用zookeeper来设计应用时,最好将应用数据和协同数据独立开。比如,网络邮箱服务的用户对自己邮箱中的内容感兴趣,但是并不关心由哪台服务器来处理特定邮箱的请求。 在这个例子中,邮箱内容就是应用数据,而从邮箱到某一台邮箱服务器之间的映射关系就是协同数据(或称元数据)。整个zookeeper服务所管理的就是后者。

试着说明zookeeper能为我们做什么,就像解释螺丝能为我们做什么一样。我们可以简单地表述,螺丝刀可以让我们拧动螺丝。但是这种方式并不能完全表达螺丝刀的能力。实际上,螺丝刀还可以让我们组装各种家具和电子设备,甚至在某些情况下你还可以用它把画挂在墙上。就像螺丝刀的例子一样,我们将介绍zookeeper能做什么,虽然未必详尽。

关于zookeeper这样的系统功能的讨论都围绕着一条主线:它可以在分布式系统中协作多个任务。一个协作任务是指一个包含多个进程的任务。这个任务可以是为了协作或者是为了管理竞争。协作意味着多个进程需要一同处理某些事情,一些进程采取某些行动使得其他进程可以继续工作。比如,在典型的主-从(master-worker)工作模式中,从节点处于空闲状态时会通知主节点可以接受工作,于是主节点就会分配任务给从节点。竞争则不同。它指的是两个进程不能同时处理工作的情况,一个进程必须等待另一个进程。同样在主-从工作模式的例子中,我们想有一个主节点,但是很多进程也许都想成为主节点,因此我们需要实现互斥排他锁(mutual exclusion)。实际上,我们可以认为获取主节点身份的过程其实就是获取锁的过程,获得主节点控制权锁的进程即主节点进程。

如果你曾经有过多线程程序开发的经验,就会发现很多类似的问题。实际上,在一台计算机上运行的多个进程和跨计算机运行的多个进程从概念上区别并不大。在多线程情况下有用的同步原语在分布式系统中也同样有效。一个重要的区别在于,在典型的不共享环境下不同的计算机之间不共享除了网络之外的其他任何信息。虽然许多消息传递算法可以实现同步原语,但是使用一个提供某种有序共享存储的组件往往更加简便,这正是zookeeper所采用的方式。

协同并不总是采取像群首选举或者加锁等同步原语的形式。配置元数据也是一个进程通知其他进程需要做什么的一种常用方式。比如,在一个主-从系统中,从节点需要知道任务已经分配到它们。即使在主节点发生崩溃的情况下,这些信息也需要有效。

让我们看一些zookeeper的使用实例,以便更直观地理解其用处:

apache hbase

hbase是一个通常与hadoop一起使用的数据存储仓库。在hbase中,zookeeper用于选举一个集群内的主节点,以便跟踪可用的服务器,并保存集群的元数据。

apache kafka

kafka是一个基于发布-订阅(pub-sub)模型的消息系统。其中zookeeper用于检测崩溃,实现主题(topic)的发现,并保持主题的生产和消费状态。

apache solr

solr是一个企业级的搜索平台。solr的分布式版本命名为solrcloud,它使用zookeeper来存储集群的元数据,并协作更新这些元数据。

yahoo! fetching service

yahoo! fetching service是爬虫实现的一部分,通过缓存内容的方式高效地获取网页信息,同时确保满足网页服务器的管理规则(比如robots.txt文件)。该服务采用zookeeper实现主节点选举、崩溃检测和元数据存储。

facebook messages

facebook推出的这个应用集成了email、短信、facebook聊天和facebook收件箱等通信通道。该应用将zookeeper作为控制器,用来实现数据分片、故障恢复和服务发现等功能。

除了以上介绍的这些应用外,还有很多使用zookeeper的例子。根据这些代表应用,我们可以从更抽象的层次上讨论zookeeper。当开发人员使用zookeeper进行开发时,开发人员设计的那些应用往往可以看成一组连接到zookeeper服务器端的客户端,它们通过zookeeper的客户端api连接到zookeeper服务器端进行相应的操作。zookeep的客户端api功能强大,其中包括:

保障强一致性、有序性和持久性。

实现通用的同步原语的能力。

在实际分布式系统中,并发往往导致不正确的行为。zookeeper提供了一种简单的并发处理机制。

当然,zookeeper也并不是万能的,我们还不能让它解决所有问题。对我们来说,更重要的是要了解zookeeper为我们提供了什么,并知道如何处理其中的一些棘手问题。这本书的目标之一就是讨论如何处理这些问题。我们将介绍zookeeper为开发人员提供的各种功能,也会讨论我们在开发zookeeper应用中遇到的一些问题,带你走入zookeeper的世界。

关于zookeeper名字的来源

zookeeper由雅虎研究院开发。我们小组在进行zookeeper的开发一段时间之后,开始推荐给其他小组,因此我们需要为我们的项目起一个名字。与此同时,小组也一同致力于hadoop项目,参与了很多动物命名的项目,其中有广为人知的apache pig项目。我们在讨论各种各样的名字时,一位团队成员提到我们不能再使用动物的名字了,因为我们的主管觉得这样下去会觉得我们生活在动物园中。大家对此产生了共鸣,分布式系统就像一个动物园,混乱且难以管理,而zookeeper就是将这一切变得可控。

本书封面上的猫也颇有渊源。雅虎研究院早期的一篇关于zookeeper的文章谈到,分布式进程管理就像养一群猫一样,而zookeeper这个名字比catherder更好一些。

1.1.1 zookeeper改变了什么

使用zookeeper是否意味着需要以全新的方式进行应用程序开发?事实并非如此,zookeeper实际上简化了开发流程,提供了更加敏捷健壮的方案。

zookeeper之前的其他一些系统采用分布式锁管理器或者分布式数据库来实现协作。实际上,zookeeper也从这些系统中借鉴了很多概念。但是,zookeeper的设计更专注于任务协作,并不提供任何锁的接口或通用存储数据接口。同时,zookeeper没有给开发人员强加任何特殊的同步原语,使用起来非常灵活。

虽然我们也可以不使用zookeeper来构建分布式系统,但是使用zookeeper可以让开发人员更专注于其应用本身的逻辑而不是神秘的分布式系统概念。所以不使用zookeeper开发分布式系统也并不是不可能,只是难度会比较大。

1.1.2 zookeeper不适用的场景

整个zookeeper的服务器集群管理着应用协作的关键数据。zookeeper不适合用作海量数据存储。对于需要存储海量的应用数据的情况,我们有很多备选方案,比如说数据库和分布式文件系统等。因为不同的应用有不同的需求,如对一致性和持久性的不同需求,所以在设计应用时,最佳实践还是应该将应用数据和协同数据独立开。

zookeeper中实现了一组核心操作,通过这些可以实现很多常见分布式应用的任务。你知道有多少应用服务采用主节点方式或进程响应跟踪方式?虽然zookeeper并没有为你实现这些任务,也没有为应用实现主节点选举,或者进程存活与否的跟踪的功能,但是,zookeeper提供了实现这些任务的工具,对于实现什么样的协同任务,由开发人员自己决定。

1.1.3 关于apache项目

zookeeper是一个托管到apache软件基金会(apache software foundation)的开源项目,apache的项目管理委员会(project management committee,pmc)负责项目管理和监督。只有技术专家可以检查补丁(patch),但是任何开发人员都可以贡献补丁。开发人员为项目做出贡献后也可以成为技术专家。对项目的贡献不仅仅限于贡献补丁,也可以通过其他形式参与项目,与社区成员们互动。我们在邮件列表中进行很多讨论,如新功能特性、用户反馈的新问题等。我们强烈建议开发人员积极参与开发社区,订阅邮件列表,并参与讨论。如果你想通过一些项目与zookeeper社区保持长期关系,你也许会发现成为一名技术专家很有价值。

1.1.4 通过zookeeper构建分布式系统

对分布式系统的定义有很多,但对于本书的目的,我们对分布式系统的定义为:分布式系统是同时跨越多个物理主机,独立运行的多个软件组件所组成的系统。我们采用分布式去设计系统有很多原因,分布式系统能够利用多处理器的运算能力来运行组件,比如并行复制任务。一个系统也许由于战略原因,需要分布在不同地点,比如一个应用由多个不同地点的服务器提供服务。

使用一个独立的协调组件有几个重要的好处:首先,我们可以独立地设计和实现该组件,这样独立的组件可以跨多个应用共享。其次,系统架构师可以简化协作方面的工作,这些并不是琐碎的小事(本书试图说明这些)。最后,系统可以独立地运行和协作这些组件,独立这样的组件,也简化了生产环境中解决实际问题的任务。

软件组件以操作系统的进程方式运行,很多时候还涉及多线程的执行。因此zookeeper的服务端和客户端也是以进程的方式运行,一个单独的物理主机(无论是一个独立主机还是一个虚拟环境中的操作系统)上运行一个单独的应用进程,尽管进程可能采用多线程运行的方式,以便利用现代处理器的多核(multicore)处理能力。

分布式系统中的进程通信有两种选择:直接通过网络进行信息交换,或读写某些共享存储。zookeeper使用共享存储模型来实现应用间的协作和同步原语。对于共享存储本身,又需要在进程和存储间进行网络通信。我们强调网络通信的重要性,因为它是分布式系统中并发设计的基础。

在真实的系统中,我们需要特别注意以下问题:

消息延迟

消息传输可能会发生任意延迟,比如,因为网络拥堵。这种任意延迟可能会导致不可预期的后果。比如,根据基准时钟,进程p先发送了一个消息,之后另一个进程q发送了消息,但是进程q的消息也许会先完成传送。

处理器性能

操作系统的调度和超载也可能导致消息处理的任意延迟。当一个进程向另一个进程发送消息时,整个消息的延时时间约等于发送端消耗的时间、传输时间、接收端的处理时间的总和。如果发送或接收过程需要调度时间进行处理,消息延时会更高

时钟偏移

使用时间概念的系统并不少见,比如,确定某一时间系统中发生了哪些事件。处理器时钟并不可靠,它们之间也会发生任意的偏移。因此,依赖处理器时钟也许会导致错误的决策。

关于这些问题的一个重要结果是,在实际情况中,我们很难判断一个进程是崩溃了还是某些因素导致了延时。没有收到一个进程发送的消息,可能是该进程已经崩溃,或是最新消息发生了网络延迟,或是其他情况导致进程延迟,或者是进程时钟发生了偏移。我们无法确定一个被称为异步(asynchronous)的系统中的这些区别。

数据中心通常使用大量统一的硬件。但即使在数据中心,我们需要发现这些问题对应用服务带来的影响,因为一个应用服务使用了多代的硬件,甚至对于同一批次的硬件也存在微小但显著的性能差异。所有这些事情使分布式系统设计师的生活越来越复杂。

zookeeper的精确设计简化了这些问题的处理,zookeeper并不是完全消除这些问题,而是将这些问题在应用服务层面上完全透明化,使得这些问题更容易处理。zookeeper实现了重要的分布式计算问题的解决方案,直观为开发人员提供某种程度上实现的封装,至少这是我们一直希望的。