Yarn是MapReduce引入的资源管理器,它的出现为集群在资源利用率、资源统一管理和数据共享等方面带来了巨大好处。ZooKeeper是一个分布式的、开源的协调服务框架,ZooKeeper出现就是为例减轻分布式应用实现协调服务的负担。
在早期的Hadoop中,MRv1采用Master/Slave(M/S)框架,主要包括Client、JobTracker、TaskTracker和Task几个部分。其中JobTarcker负责整个系统的作业调度和资源管理,TaskTracker负责将本节点上资源的使用情况、节点健康状态和任务的运行进度汇报给JobTracker,同时接受JobTracker发送过来的命令并执行相应操作。
M/S架构的设计具有一定的缺陷,MRv1中存在的问题如下。
Yarn体系结构
Yarn体系结构,Yarn同样采用Master/Slave结构,主要由ResourceManager(简称RM)、NodeManager(简称NM)、ApplicationMaster(简称AM)和Container等几部分组成。ResourceManager负责资源管理,ApplicationMaster负责任务监控和调度,NodeManager负责执行原TaskTracker的任务。
一个集群中通常有一个ResourceManager和多个NodeManager。
在Yarn中,任何两个需要相互通信的组件之间都需要RPC协议,并且有且仅有一个。Yarn采用的是拉式(pull - based)通信模型,因为对于任何一个RPC协议,Clien总是主动连接Server。
第一阶段:提交作业
由于集群资源的有限性,Yarn应用发出的资源请求经常需要等待一段时间,才能得到需要的资源,资源调度器作为Yarn的核心组件,可根据特定的资源调度策略为应用合理分配资源。Yarn中的调度器是可插拔的,用户可根据需要自定义调度器,实现特定的资源调度策略。管理者可通过参数yarn.resourcemanager.scheduler.class设置资源调度器的主类,默认为org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler
另外,对于所有的资源调度器,均需要实现以下接口:org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler。
另外,对于所有的资源调度器,均需要实现以下接口:org.apache.hadoop.yarn.server.resourcemanager.scheduler.ResourceScheduler。该接口的定义如下
package org.apache.hadoop.yarn.server.resourcemanager.scheduler;
import java.io.IOException;
import java.util.List;
import org.apache.hadoop.classification.InterfaceAudience.LimitedPrivate;
import org.apache.hadoop.classification.InterfaceStability.Evolving;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.yarn.api.records.NodeId;
import org.apache.hadoop.yarn.api.records.SchedulingRequest;
import org.apache.hadoop.yarn.server.resourcemanager.RMContext;
import org.apache.hadoop.yarn.server.resourcemanager.recovery.Recoverable;
@LimitedPrivate({"yarn"})
@Evolving
public interface ResourceScheduler extends YarnScheduler, Recoverable {
void setRMContext(RMContext var1);
void reinitialize(Configuration var1, RMContext var2) throws IOException;
List<NodeId> getNodeIds(String var1);
boolean attemptAllocationOnNode(SchedulerApplicationAttempt var1, SchedulingRequest var2, SchedulerNode var3);
void resetSchedulerMetrics();
}
Yarn采用的是双层资源调度模型;首先,ResourceManager中的资源调度器将资源分配给各个Application,然后,ApplicationMaster再进一步将资源分配给它内部的任务。这里主要介绍第一层的调度问题。
Yarn中有三种常见的调度策略:FIFO Scheduler(先进先出调度器)、Capacity Scheduler(容器调度器)和Fair Scheduler(公平调度器)。
FIFO Scheduler
FIFO(先进先出)调度器将应用放置到一个队伍中,按照应用提交的顺序为其分配资源。典型情况下,每个应用会使用整个集群,并且每个应用必须等待前一个应用执行完毕才会开始运行。由于大的应用可能会占用所有集群资源,因此,使用FIFO调度器,可能会出现小作业一直被阻塞的状态。FIFO调度器后来增加了设置作业优先级的功能(可通过参数设置),在选择要运行的下一个作业时,优先考虑作业优先级高的作业,但是优先级并不支持抢占,优先级高的作业仍然需要等到已经开始的优先级低的作业完成。该调度器简单易懂,不需要任何配置,但是不适合共享集群,在一个共享集群中,更适合使用容量调度器和公平调度器,这两种调度器都可以保证长时间运行的作业可以及时完成。
Capacity Scheduler
容器调度器是雅虎公司开发的多用户调度器,运行多个组织共享一个Hadoop集群,每个组织被配置为一个队列,调度器以队列为单位划分资源,每个队列可分配到全部集群资源的一部分。队列可进一步按照用户划分,队列中的不同用户共享该队列中的资源,此时每个用户也可称为一个队列。队列中的应用以FIFO方式调度,另外,为了避免队列过多地占用空闲资源,每个队列可设定资源的最低保证和最大使用上限,队列中的每个用户也可设定资源的使用上限。当一个队列的资源空闲时,可暂时将剩余资源共享给其他资源不够用的队列,这称为"弹性队列"。
Fair Scheduler
公平调度器旨在为所有运行的应用公平地分配资源。当只有一个大地作业运行时,该作业将会获取集群地全部资源,当第二个小作业提交后,Fair调度器会将一半地资源分享给小作业,两个作业可以公平地共享集群资源。
公平调度器是Facebook开发地多用户调度器,它和Capacity Scheduler相似,也是以队列为单位进行资源划分,每个队列可设定最低保证和最高使用上限,当某个队列有空闲资源时,可共享给其他队列使用。但是,Fair Scheduler和Capacity Scheduler也存在不同之处,主要体现在以下几个方面
1)队列内支持多种调度策略:在每个队列中,Fair Scheduler可选择FIFO、Fair或DRF策略为应用程序程序分配资源。
2)资源公平共享:按照队列中同时运行的作业的数量n,为每个作业分配1/n的资源。
3)负载均衡:Fair Scheduler提供了一个基于任务数目的负载机制,该机制尽可能将系统中的任务均匀分配给各个节点。
4)提高小应用程序响应时间:在FIFO策略中,若大作业先执行,小作业必须等到大作业完成才能执行。而Fair策略由于采用了最大最小公平算法,小作业也可以快速获取资源避免了饿死的状况。
其他调度器
Yarn中还包括自适应调度器、自学习调度器和动态优先级调度器等。
ZooKeeper是一个开放源码的分布式应用程序协调服务,是谷歌公司的Chubby一个开源的实现,是Hadoop和HBase的重要组队。它是一个为分布式应用提供一致性服务的软件,提供的功能包括配置维护、域名服务、分布式同步、组服务等。
ZooKeeper是一个分布式的、开源的协调服务框架,服务于分布式应用程序。它提供一组简单的原语,使得分布式应用可以在此基础上构建更高级别的服务,例如,命名服务、配置管理、分布式同步和组服务等,既可以直接运用它去实现一致性、组管理、Leader选举和已存在的协议,也可以在此基础上建立自己特定的需求。ZooKeeper的数据结构类似文件系统目录数结构,易于编程且同时支持Java编程语言和C语言。
众所周知,不出错地实现协调服务是件很困难的事。它们特别容易出现竞争、死锁这样的错误,ZooKeeper的出现就是为了减轻分布式应用实现协调服务的负担。由于部分失败是分布式系统固有的特征,ZooKeeper并不能避免出现部分失败,因此ZooKeeper提供了一组工具,用来对构建分布式应用时部分失败的情况作出正确处理。另外,ZooKeeper注重高性能、高可靠性和严格的顺序访问,高性能使得ZooKeeper可以应用在大规模的分布式系统中,高可靠性可以避免发生单点故障,严格的顺序访问使得复杂的同步原语可以在客户端实现。另外,ZooKeeper的读写操作也十分快速,而且读要比写速度更快,比率大约为10:1,原因在于,在读的情况下,ZooKeeper可以提供给用户较旧的数据。
ZooKeeper具有以下特点
下面将分别介绍命名空间、znode、Watcher、Session,了解ZooKeeper数据模型。
分层命名空间
ZooKeeper可以看作是一个具有高可用性的文件系统,在这个文件系统中,没有文件和目录,而是统一使用"节点"的概念,称为znode。znode作为一个层次化的命名空间,既可以保存与之相关的数据,也可以保存其子znode的相关信息。
znode
在ZooKeeper的命名空间里,每个znode只有一个唯一的路径标识,且每个节点都由三个部分组成,分别是stat、data、children。stat为znode的状态信息,包括描述该znode的版本、权限等信息。data为与znode关联的数据。children为znode下的子节点信息。由于ZooKeeper是被设计用来实现协调服务,而不是用来大容量数据存储,因此一个znode能存储的数据被限制在1MB以内。
每个znode存储的数据都可以被进行读写操作。但是值得注意的是,由于ZooKeeper具有原子性特点,当对一个znode进行读写操作时,将得到它存储的所有数据;当对其进行写操作时,将替换掉它存储的所有数据。每个znode都有一个ACL来限制访问限制。
znode中的数据具有版本号。每当znode的数据发生变化,版本号就会增加。当客户端检索数据时会同时得到数据的版本号。当客户端执行一个更新或者删除操作时必须提供被修改节点数据的版本号。如果提供的版本号错误,则更新操作失败。
znode类型分为持久节点(persistent)、临时节点(ephemeral)和顺序节点(sequential)。所谓的持久节点是指一旦这个znode创建成功,除非主动进行znode的移除操作,否则节点会一直保存在ZooKeeper上;临时节点的生命周期是跟客户端的会话相关联的,一旦客户端会话失效,这个会话上的所有临时节点都会被自动移除,需要注意的是,临时节点不允许有子节点;而顺序节点是指名称中包含Zookeeper顺序号的znode,顺序号是一个单调递增的计数器,顺序节点通常与持久节点搭配使用,生成持久顺序节点。创建持久顺序节点时,用户需要请求ZooKeeper在节点路径末尾添加一个单调递增计数,这个计数对此父节点来说是唯一的。在分布式系统中,所有的事件可通过该顺序号进行全局排序,客户端便可以通过顺序号推断事件的顺序。
Watcher
客户端可以对znode设置监视点(Watcher)。znode的改变会触发Watcher,当Watcher被触发,ZooKeeper会向客户端发送一个通知。触发Watcher的事件包括节点数据改变、子节点改变、节点被删除和连接超时等。一个Watcher只能被触发一次。如果客户端在接收到一次监听事件后,还想继续接受节点发生改变的通知,需要重新设置Watcher。
Session
Session(会话)是客户端与ZooKeeper服务器端之间的通信通道。客户端与服务端之间的任何交互操作都与会话息息相关,如临时节点的生命周期、客户端请求的顺序执行、Watcher通知机制等。在ZooKeeper客户端与服务器端成功连接创建后,就创建了一个会话。
ZooKeeper服务通常由奇数个服务器构成。因为只要大多数服务器可用,ZooKeeper就是可用的。
客户端(Client)连接到单个服务器上。客户端和ZooKeeper服务器之间保持着一个TCP连接,通过该连接客户端可以发送请求、接收响应、接受监听事件及发送心跳等。如果TCP连接被中断了,客户端就会与另一台ZooKeeper服务器进行连接。
在ZooKeeper中,是有角色概念的。ZooKeeper集群中,分别有Leader(领导者)、Follower(跟随者)和Observer(观察者)三种类型的服务器角色。其中Follower和Observer同属于Learner(学习者)。
略
详情可以参考
https://blog.csdn.net/shi_zi_183/article/details/115299001
https://blog.csdn.net/shi_zi_183/article/details/115628310
https://blog.csdn.net/shi_zi_183/article/details/116202903
ZooKeeper支持Java编程语言和C语言,本节只介绍Java语言的ZooKeeper API使用方法。ZooKeeper API共包含5个包。
<dependency>
<groupId>org.apache.zookeepergroupId>
<artifactId>zookeeperartifactId>
<version>3.6.2version>
dependency>
版本与自己集群zookeeper版本相同。
ZooKeeper类是编程时最经常使用的类文件,存放在包org.apache.zookeeper中。如果使用ZooKeeper服务,应用程序需要创建一个ZooKeeper实例。当客户端和ZooKeeper服务器建立连接,ZooKeeper系统将会分配给该连接会话一个ID值,并且客户端会周期性地向服务器发送心跳信息,维持该会话地连接,这样客户端便可调用ZooKeeper API对节点作为相应地处理。
以下的Java API均属于org.apache.zookeeper.ZooKeeper类,主要提供的常用的功能如下。
create
create(String path, byte[] data, List<ACL> acl, CreateMode createMode)
创建一个znode。各参数的含义:path为节点的路径,data为节点的初始数据,acl为节点控制访问列表,createMode为节点的类型。该方法最终的返回值是创建的节点的实际路径。
delete
delete(String path, int version)
删除给定路径节点的特定版本。给参数的含义:path为要删除节点的路径,version为节点的版本,当version为-1时,则匹配节点的任意版本。
exists
判断某一位置是否存在节点。若节点不存在,返回null;若节点存在且函数执行成功,则在该节点上创建一个watcher。
get data
getData(String path, boolean watch, Stat stat)
返回给路径节点的状态和数据。各参数含义:path为节点路径,watch取值为true且该函数执行成功,则在该节点上创建一个watcher,stat为节点的状态。
set data
public Stat setData(String path,byte[] data,int version)
为执行路径节点的特定版本设置数据。当version为-1时,则匹配节点的任意版本。若函数执行成功,则会触发getData函数在该节点创建的watcher。
get children
public List<String> getChildren(String path, Watcher watcher)
检索指定节点的子节点序列。若watch取值true且该函数执行成功,则在该节点上创建一个watcher。返回的子节点序列是无序的。
sync
public void sync(String path, VoidCallback cb, Object ctx)
等待数据被传播以实现同步数据。各参数含义:path为节点路径,cb为需要回调的程序,ctx为提供给回调的上下文。
单个节点的创建、查询、修改及删除
此类包含两个主要的ZooKeeper函数,分别为createZKInstance()和ZKOperations()。其中createZKInstance()函数负责对ZooKeeper实例zk进行初始化。ZKOperations()函数是所定义的对节点的一系列操作,包括对ZooKeeper节点的创建、删除和修改。
package org.shizi;
import org.apache.zookeeper.*;
import java.io.IOException;
public class Zoo {
private static final int SESSION_TIMEOUT=30000;
private ZooKeeper zk;
private Watcher wt=new Watcher() {
public void process(WatchedEvent event) {
System.out.println(event.toString());
}
};
public void createZKInstance() throws IOException{
//在zookeeper目录下使用bin/zkServer.sh status命令,查看leader的服务器的ip作为LeaderIP
zk=new ZooKeeper("slave1:2181", SESSION_TIMEOUT,this.wt);
}
public void ZKOperations() throws KeeperException, InterruptedException {
zk.create("/znode1","MyZnode1".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
System.out.println("查看新创建节点znode1的数据:");
System.out.println(new String(zk.getData("/znode1", false, null)));
System.out.println("修改节点数据");
zk.setData("/znode1","a new data".getBytes(),-1);
System.out.println("节点znode1的新数据:");
System.out.println(new String(zk.getData("/znode1", false, null)));
System.out.println("删除节点znode1:");
zk.delete("/znode1",-1);
System.out.println("查看节点是否被删除:");
System.out.println("节点状态[" + zk.exists("/znode1", false) + "]" + "节点已经被删除");
}
public void ZKclose() throws InterruptedException {
zk.close();
}
}
package org.shizi;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooKeeper;
import org.junit.Test;
import java.io.IOException;
public class zookeeperTest {
@Test
public void ZooTest() throws IOException, KeeperException, InterruptedException {
Zoo zoo=new Zoo();
zoo.createZKInstance();
zoo.ZKOperations();
zoo.ZKclose();
}
}
package org.shizi;
import org.apache.zookeeper.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class SecondZK {
private static final int SESSION_TIMEOUT=30000;
private ZooKeeper zk;
private Watcher wt=new Watcher() {
public void process(WatchedEvent event) {
System.out.println(event.toString());
}
};
public void createZKInstance() throws IOException {
zk=new ZooKeeper("master:2181,slave1:2181,slave2:2181",SESSION_TIMEOUT,this.wt);
}
public void ZKOpertions() throws KeeperException, InterruptedException {
zk.create("/child1","I am the first son".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
zk.create("/child2","I am the second son".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
zk.create("/child3","I am the third son".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL);
}
public void ZKList(){
String zPath="/";
List<String>zooChildren=new ArrayList<String>();
try{
zooChildren=zk.getChildren(zPath,false);
System.out.println("Znodes of /:");
for (String zooChild:zooChildren){
System.out.println(zooChild);
}
} catch (InterruptedException e) {
e.printStackTrace();
} catch (KeeperException e) {
e.printStackTrace();
}
}
public void ZKclose() throws InterruptedException {
zk.close();
}
}
@Test
public void SecondZKTest() throws IOException, KeeperException, InterruptedException {
SecondZK zoo = new SecondZK();
zoo.createZKInstance();
zoo.ZKOpertions();
zoo.ZKList();
zoo.ZKclose();
}