当今是个分布式、集群、云计算等名词满天飞的时代。形成这种局面的一个重要因素就是,单一机器的处理能力已经不能知足咱们的需求,不得不采用由多台机器组成的服务集群。
服务集群对外提供服务的过程当中,能够分解处理压力,在必定程度上打破性能瓶颈,并提升服务的可用性(不会由于一台机器宕机而形成服务不可用)。html
(2)若是有一台机器挂掉了,其余机器如何感知到这一变化并接管任务?若是用户激增,须要增长机器来缓解压力,如何作到不重启集群而完成机器的添加?java
(3)用户数量增长或者减小,会出现有的机器资源使用率繁忙,有的却空闲,如何让每台机器感知到其余机器的负载状态从而实现负载均衡?linux
(4)在一台机器上要多个进程或者多个线程操做同一资源比较简单,由于能够有大量的状态信息或者日志信息提供保证,好比两个A和B进程同时写一个文件,加锁就能够实现。可是分布式系统怎么办?须要一个三方的分配锁的机制,几百台worker都对同一个网络中的文件写操做,怎么协同?还有怎么保证高效的运行?数据库
分布式系统的不少难题,都是因为缺乏协调机制形成的。编程
目前,在分布式协调技术方面作得比较好的就是Google的Chubby还有Apache的ZooKeeper。 有人会问既然有了Chubby为何还要弄一个ZooKeeper,难道Chubby作得不够好吗?主要是Chubby是非开源的,Google自家用。后来雅虎模仿Chubby开发出了ZooKeeper,也实现了相似的分布式锁的功能,而且将ZooKeeper做为一种开源的程序捐献给了Apache,那么这样就可使用ZooKeeper所提供锁服务。bash
至于这个神器为何叫ZooKeeper,与外国人一向的幽默精神有关。众所周知,外国人喜欢给用一个动物做为吉祥物,在IT界也不例外。好比:服务器
负责大数据工做的Hadoop是一个黄色的大象 网络
随着大数据的火热,Hxx(根据MapReduce,因而咱们有了Hadoop;根据GFS,因而咱们有了HDFS;根据BigTable,因而咱们有了HBase)们已经变得耳熟能详,如今做为一个开发人员若是都不知道这几个名词出门都好像很差意思跟人打招呼。架构
但实际上对咱们这些非大数据开发人员而言,Zookeeper是比Hxx们可能接触到更多的一个基础服务。可是,无奈的是它一直默默的位于二线,历来没有Hxx们那么耀眼。那么到底什么是Zookeeper呢?Zookeeper能够用来干什么?咱们将如何使用Zookeeper?Zookeeper又是怎么实现的?并发
伴随着Zookeeper有两篇论文:一篇是Zab,就是介绍Zookeeper背后使用的一致性协议的(Zookeeper atomic broadcast protocol),还有一篇就是介绍Zookeeper自己的。在这两篇论文里都提到Zookeeper是一个分布式协调服务(a service for coordinating processes of distributed applications)。那分布式协调服务又是个什么东西呢?首先咱们来看“协调”是什么意思。
说到协调,我首先想到的是北京不少十字路口的交通协管,他们手握小红旗,指挥车辆和行人是否是能够通行。若是咱们把车辆和行人比喻成运行在计算机中的单元(线程),那么这个协管是干什么的?不少人都会想到,这不就是锁么?对,在一个并发的环境里,咱们为了不多个运行单元对共享数据同时进行修改,形成数据损坏的状况出现,咱们就必须依赖像锁这样的协调机制,让有的线程能够先操做这些资源,而后其余线程等待。对于进程内的锁来说,咱们使用的各类语言平台都已经给咱们准备不少种选择。就拿Java来讲,有最普通不过的同步方法或同步块:
public synchronized void sharedMethod(){
//对共享数据进行操做
}
复制代码
使用了这种方式后,多个线程对sharedMethod进行操做的时候,就会协调好步骤,不会对sharedMethod里的资源进行破坏,产生不一致的状况。
这是最简单的协调方法,但有的时候咱们可能须要更复杂的协调。好比咱们经常为了提升性能,咱们使用读写锁。由于大部分时候咱们对资源是读多写少,而若是无论三七二十一所有使用排他的写锁,那么性能有可能就会受到影响。仍是用java举例:
public class SharedSource{
private ReadWriteLock rwlock = new ReentrantReadWriteLock();
private Lock rlock = rwlock.readLock();
private Lock wlock = rwlock.writeLock();
public void read(){
rlock.lock();
try{
//读取资源
}finally{
rlock.unlock();
}
}
public void write(){
wlock.lock();
try{
//写资源
}finally{
wlock.unlock();
}
}
}
复制代码
咱们在进程内还有各类各样的协调机制(通常咱们称之为同步机制)。如今咱们大概了解了什么是协调了,可是上面介绍的协调都是在进程内进行协调。在进程内进行协调咱们可使用语言,平台,操做系统等为咱们提供的机制。那么若是咱们在一个分布式环境中呢?也就是咱们的程序运行在不一样的机器上,这些机器可能位于同一个机架,同一个机房又或不一样的数据中心。在这样的环境中,咱们要实现协调该怎么办?那么这就是分布式协调服务要干的事情。
ok,可能有人会讲,这个好像也不难。无非是将原来在同一个进程内的一些原语经过网络实如今分布式环境中。是的,表面上是能够这么说。但分布式系统中,说每每比作容易得多。在分布式系统中,全部同一个进程内的任何假设都不存在:由于网络是不可靠的。
好比,在同一个进程内,你对一个方法的调用若是成功,那就是成功(固然,若是你的代码有bug那就另说了),若是调用失败,好比抛出异常那就是调用失败。在同一个进程内,若是这个方法先调用先执行,那就是先执行。可是在分布式环境中呢?
因为网络的不可靠,你对一个服务的调用失败了并不表示必定是失败的,多是执行成功了,可是响应返回的时候失败了。还有,A和B都去调用C服务,在时间上A还先调用一些,B后调用,那么最后的结果是否是必定A的请求就先于B到达呢? 这些原本在同一个进程内的种种假设咱们都要从新思考,咱们还要思考这些问题给咱们的设计和编码带来了哪些影响。还有,在分布式环境中为了提高可靠性,咱们每每会部署多套服务,可是如何在多套服务中达到一致性,这在同一个进程内很容易解决的问题,但在分布式环境中确实一个大难题。
因此分布式协调远远比同一个进程里的协调复杂得多,因此相似Zookeeper这类基础服务就应运而生。这些系统都在各个系统久经考验,它的可靠性,可用性都是通过理论和实践的验证的。因此咱们在构建一些分布式系统的时候,就能够以这类系统为起点来构建咱们的系统,这将节省很多成本,并且bug也将更少。
上述试图从外围介绍一下Zookeeper是一个什么样子的服务和咱们为何须要这样一种服务。接下来会介绍Zookeeper到底能干些什么。
在Zookeeper的官网上有这么一句话:ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services.
这大概描述了Zookeeper主要能够干哪些事情:配置管理
、名字服务
、分布式同步
以及集群管理
。那这些服务又究竟是什么呢?咱们为何须要这样的服务?咱们又为何要使用Zookeeper来实现呢,使用Zookeeper有什么优点?接下来我会挨个介绍这些究竟是什么,以及有哪些开源系统中使用了。
配置管理
在咱们的应用中除了代码外,还有一些就是各类配置。好比数据库链接等。通常咱们都是使用配置文件的方式,在代码中引入这些配置文件。当咱们只有一种配置、一台服务器,而且不常常修改的时候,使用配置文件是一个很好的作法,可是若是咱们配置很是多,有不少服务器都须要这个配置,并且还多是动态的话使用配置文件就不是个好主意了。这个时候每每须要寻找一种集中管理配置的方法,咱们在这个集中的地方修改了配置,全部对这个配置感兴趣的均可以得到变动。
好比把这公用的配置文件提取出来放到一个地方,对这个地方(目录节点)进行监听,一旦配置信息发生变化,每一个应用程序就会收到Zookeeper的通知,而后从Zookeeper获取新的配置信息应用到系统中。可是,由于不少服务的正常运行都很是依赖这个配置,因此须要这个集中提供配置服务的服务具有很高的可靠性。通常咱们能够用一个集群来提供这个配置服务,可是用集群提高可靠性,那如何保证配置在集群中的一致性呢?
这个时候就须要使用一种实现了一致性协议的服务了。Zookeeper就是这种服务,它使用Zab这种一致性协议来提供一致性。如今有不少开源项目使用Zookeeper来维护配置,好比,在开源的消息队列Kafka中,也使用Zookeeper来维护broker的信息;在Alibaba开源的SOA框架Dubbo中也普遍的使用Zookeeper管理一些配置来实现服务治理;在HBase中,客户端就是链接一个Zookeeper,得到必要的HBase集群的配置信息,而后才能够进一步操做。
命名服务
命名服务这个就很好理解了。好比为了经过网络访问一个系统,咱们得知道对方的IP地址,可是IP地址对人很是不友好,这个时候咱们就须要使用域名来访问。可是计算机是不能识别域名的。怎么办呢?若是咱们每台机器里都有一份域名到IP地址的映射,这个却是能解决一部分问题,可是若是域名对应的IP发生变化了又该怎么办呢?
因而咱们有了DNS这个东西。咱们只须要访问一个你们熟知的(known)的点,它就会告诉你这个域名对应的IP是什么。在咱们的应用中也会存在不少这类问题,特别是在咱们的服务特别多的时候,若是咱们在本地保存服务的地址将很是不方便,可是若是咱们只须要访问一个你们都熟知的访问点,这里提供统一的入口,那么维护起来将方便多了。
好比,用过Duboo+Zookeeper整合的系统的人也能知道,正是由于这个命名服务,才方便了分布式中各个项目之间的联系.在SOA(Service-Oriented Architecture)框架里面,RMI(Remote Method Invoke)框架就是经过某个服务器上的URL来获取远程服务器上的对象来调用服务,但到集群和分布式环境下,如何作到子项目之间调用的关系不会很复杂,不会到时候出现问题都不知道哪一个服务调用的哪一个,因此这里就须要一个服务器专门替咱们管理这些服务,这样咱们就能够集中精力在业务处理上。Zookeeper的命名功能就是这么一个服务器。在集群中,相同的一个服务有不少个提供者,这些提供者启动时,提供者的相关信息(服务接口,地址,端口等)注册到Zookeeper中,当消费者要消费某服务的时候,从Zookeeper中获取该服务的全部提供者的信息目录,再根据Dubbo的负载均衡机制选择一个提供者。
其实从配置管理、命名服务的做用中能够看出,Zookeeper至关于一个文件系统(相似与linux文件系统),换句话说,zookeeper是分布式中的大脑。
分布式锁
分布式锁,又叫分布式的同步。好比,上文中提到了Zookeeper是一个分布式协调服务,这样咱们就能够利用Zookeeper来协调多个分布式进程之间的活动。
好比在一个分布式环境里,为了提升可靠性,咱们的集群中每台服务器上都部署着一样的服务。可是,一件事情若是集群中的每一个服务器都进行的话,那相互之间就要协调,编程起来将很是复杂。而若是咱们只让一个服务进行操做,那又存在单点。一般还有一种作法就是使用分布式锁,在某个时刻只让一个服务去干活,当这台服务出问题的时候锁释放,当即fail over到另外的服务。
不少分布式系统都是这么作的,这种设计有一个更好听的名字叫Leader Election(leader选举)。好比HBase的Master就是采用这种机制。
但要注意的是分布式锁跟同一个进程的锁仍是有区别的,因此使用的时候要比同一个进程里的锁更谨慎的使用。
集群管理
在分布式的集群中,常常会因为各类缘由,好比硬件故障,软件故障,网络问题,有些节点会进进出出。有新的节点加入进来,也有老的节点退出集群。这个时候,集群中其余机器须要感知到这种变化,而后根据这种变化作出对应的决策。
好比在一个分布式存储系统中,有一个中央控制节点负责存储的分配,当有新的存储进来的时候咱们要根据如今集群目前的状态来分配存储节点。这个时候咱们就须要动态感知到集群目前的状态。
还有,好比一个分布式的SOA架构中,服务是一个集群提供的,当消费者访问某个服务时,就须要采用某种机制发现 如今有哪些节点能够提供该服务(这也称之为服务发现,好比Alibaba开源的SOA框架Dubbo,就采用了Zookeeper做为服务发现的底层机制)。还有开源的Kafka队列就采用了Zookeeper做为Cosnumer的上下线管理。
推荐阅读:
参考文档:
ZooKeeper之(一)ZooKeeper是什么
Zookeeper--Zookeeper是什么
Zookeeper-Zookeeper能够干什么