您的位置:首页 > 运维架构

Hadoop详解(五)——ZooKeeper详解,ZooKeeper伪分布搭建和集群搭建,Hadoop集群搭建,sqoop工具的使用

2017-09-04 11:24 701 查看

ZooKeeper简介

什么是ZooKeeper?

ZooKeeper是Google的Chubby一个开源的实现,是Hadoop分布式协调服务。它包含了一个简单的原语集,分布式应用程序可以基于它实现同步服务,配置维护和命令服务等。它的结构图如下:


ZooKeeper集群搭建的要求:必须要有奇数台。如果想让ZooKeeper既具有高效性,又能正常工作,只要需要3台的ZooKeeper集群。ZooKeeper允许一般以上的机器不宕机,就能正常启动ZooKeeper服务。(3台ZooKeeper集群允许1台服务器宕机,5台集群允许2台,7台集群允许3台)ZooKeeper集群的数量不需要很大,最大的7台集群的ZooKeeper足够

为什么使用ZooKeeper?

大部分分布式应用需要一个主控、协调器或控制器来管理物理分布的子进程(如资源,任务分配等)。目前大部分应用需要开发私有的协调程序,缺乏一个通用的机制。协调程序的反复编写造成很大浪费,且难以形成通用、伸缩性好的协调器。ZooKeeper:提供通用的分布式锁服务,用以协调分布式应用。

ZooKeeper能做哪些工作?

Hadoop2.0以后,使用ZooKeeper的事件处理可以确保整个集群只有一个活跃的NameNode,存储配置信息等。HBASE,使用ZooKeeper的事件处理确保整个集群中只有一个活跃的HMaster,觉察HRegionServer联机和宕机,存储访问控制列表。

ZooKeeper特性

ZooKeeper特性:① 简单② 富有表现力③ 具有高可用性④ 采用松耦合的交互方式⑤ ZooKeeper是一个资源库

ZooKeeper的数据模型

① 层次化的目录结构,命名符合常规文件系统规范。② 每个节点在ZooKeeper中叫做znode,并且有一个唯一的路径标识。③ 节点Znode可以包含数据和子节点,但是EPHEMERAL (中文翻译为短暂的)类型的节点不能有子节点。④ Znode 中的数据可以有多个版本,比如某一路径下存有多个数据版本,那么查询这个路径下的数据就需要带上版本。⑤ 客户端应用可以在节点上设置监视器。⑥ 节点不支持部分读写,而是一次性完整读写。注意:znode可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是ZooKeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的集中管理,集群管理,分布式锁等等。

ZooKeeper的节点

① Znode有两种类型,短暂的(ephemeral)和持久的(persistent)。② Znode的类型在创建时确定并且之后不能再修改。③ 短暂Znode的客户端会话结束时,ZooKeeper会将短暂znode删除,短暂znode不可以有子节点。④ 持久znode不依赖于客户端会话,只有当客户端明确要删除该持久znode时才会被删除。⑤ Znode有四种形式的目录节点,PERSISTENT、PERSISTENT_SEQUENTIAL、EPHEMERAL、EPHEMERAL_SEQUENTIAL注意:PERSISTENT-持久化节点:创建这个节点的客户端在与zookeeper服务的连接断开后,这个节点也不会被删除(除非您使用API强制删除)。PERSISTENT_SEQUENTIAL-持久化顺序编号节点:当客户端请求创建这个节点A后,zookeeper会根据parent-znode的zxid状态,为这个A节点编写一个全目录唯一的编号(这个编号只会一直增长)。当客户端与zookeeper服务的连接断开后,这个节点也不会被删除。EPHEMERAL-临时目录节点:创建这个节点的客户端在与zookeeper服务的连接断开后,这个节点(还有涉及到的子节点)就会被删除。EPHEMERAL_SEQUENTIAL-临时顺序编号目录节点:当客户端请求创建这个节点A后,zookeeper会根据parent-znode的zxid状态,为这个A节点编写一个全目录唯一的编号(这个编号只会一直增长)。当创建这个节点的客户端与zookeeper服务的连接断开后,这个节点被删除。另外,无论是EPHEMERAL还是EPHEMERAL_SEQUENTIAL节点类型,在zookeeper的client异常终止后,节点也会被删除。

ZooKeeper的角色

① 领导者(Leader) ,负责进行投票的发起和决议,更新系统状态。② 学习者(learned),包括跟随者(follower)和观察者(observer),follower用于接收客户端请求并向客户端返回结果,在选主过程中参与投票。③ Observer可以接受客户端连接,将写请求转发给Leader,但是Observer不参与投票过程,只同步Leader的状态,Observer的目的是为了扩展系统,提高读取速度。④ 客户端(Client),请求发起方。

ZooKeeper的顺序号

① 创建znode时设置顺序标识,znode名称后会附加一个值。② 顺序号是一个单调递增的计数器,由父节点维护。③ 在分布式系统中,顺序号可以被用于为所有的事件进行全局排序,这样客户端可以通过顺序号推断事件的顺序。

ZooKeeper的读写机制

① ZooKeeper是一个由多个Server组成的集群。② 一个Leader,多个Follower。③ 每个Server保存一份数据副本。④ 全局数据一致。⑤ 分布式读写。⑥ 更新请求转发由Leader实施。

ZooKeeper的保证

① 更新请求顺序进行,来自同一个Client的更新请求按照其发送顺序依次执行。② 数据更新原子性,一次数据更新要么成功,要么失败。③ 全局唯一数据视图,Client无论连接到哪个Server,数据视图都是一致的。④ 实时性,在一定的事件范围内,Client能读到最新的数据。

ZooKeeper的API接口

① String create(String path, byte[] data, List<ACL> acl, CreateMode createMode) 创建一个指定的目录节点path,并给它设置数据;
② Stat exists(String path, boolean watch) 判断某个path是否存在,并设置是否监控这个目录节点,这里的watcher是在创建ZooKeeper实例时指定的watcher,exists方法还有一个重载方法,可以指定特定的watcher;
③ void delete(String path, int version) 删除path对应的目录节点,version为-1可以匹配任何版本,也就删除了这个目录的所有数据;
④ List<String> getChildren(String path, boolean watch) 获取指定path下的所有子目录节点。watch表示是否使用初始时的watcher监控子目录。
⑤ List<String> getChildren(String path, Watcher watcher) 
同样getChildren方法也有一个重载订单可以设置特定的watcher来监控子节点状态。⑥ Stat setData(String path, byte[] data, int version) 为path设置数据,可以指定这个数据的版本号,如果version为-1 可以匹配任何版本。
⑦ byte[] getData(String path, boolean watch, Stat stat) 获取这个path对应的目录节点存储的数据,数据的版本信息可以通过stat指定,同时还可以设置是否监控这个目录节点数据的状态;
⑧ void addAuthInfo(String scheme, byte[] auth) 客户端将自己的授权信息提交给服务器,服务器根据这个授权信息验证客户端的访问权限。
⑨ Stat setACL(String path, List<ACL> acl, int version) 给某个目录节点重新设置访问权限,需要注意的是 Zookeeper 中的目录节点权限不具有传递性,父目录节点的权限不能传递给子目录节点。目录节点 ACL 由两部分组成:perms 和 id。Perms 有 ALL、READ、WRITE、CREATE、DELETE、ADMIN 几种 而 id 标识了访问目录节点的身份列表,默认情况下有以下两种:ANYONE_ID_UNSAFE = new Id(“world”, “anyone”) 和 AUTH_IDS = new Id(“auth”, “”) 分别表示任何人都可以访问和创建者拥有访问权限;
⑩ List<ACL> getACL(String path, Stat stat) 
获取某个目录节点的访问权限列表

Watcher

① Watcher在ZooKeeper是一个核心功能,watcher可以监控目录节点的数据变化以及子目录的变化,一旦这些状态发生变化,服务器就会通知所有设置在这个目录节点上的Watcher,从而每个客户端都很快知道它所关注的目录节点的状态发生变化,而做出相应的反向。② 可以设置观察的操作:exists、getChildren,getData③ 可以触发观察的操作:create、delete、setData注意:znode以某种方式发生变化时,“观察”(watch)机制可以让客户端得到通知。可以针对ZooKeeper服务的“操作”来设置观察,该服务的其他 操作可以触发观察。比如,客户端可以对某个客户端调用exists操作,同时在它上面设置一个观察,如果此时这个znode不存在,则exists返回 false,如果一段时间之后,这个znode被其他客户端创建,则这个观察会被触发,之前的那个客户端就会得到通知。
(1) 写操作与ZooKeeper内部事件之间的对应关系



(2) ZooKeeper内部事件与watcher的对应关系


(3) 写操作与watcher的对应关系


NodeCreated:节点创建事件。NodeDeleted:节点被删除事件。NodeDataChanged:节点数据改变事件。NodeChildrenChanged:节点的子节点改变事件。(4) 每个znode被创建时都会带有一个ACL列表,用于决定谁可以对它执行何种操作。


ACL

身份验证模式有三种:
① digest:用户名,密码
② host:通过客户端的主机名来识别客户端
③ ip: 通过客户端的ip来识别客户端
new ACL(Perms.READ,new Id("host","example.com"));
这个ACL对应的身份验证模式是host,符合该模式的身份是example.com,权限的组合是:READ
(每个ACL都是身份验证模式、符合该模式的一个身份和一组权限的组合)

Znode的节点状态



ZooKeeper工作原理

① ZooKeeper的核心是原子广播,这个机制保证了各个Server之间的同步。实现这个机制的协议叫做Zab协议。Zab协议有两种模式,它们分别是恢复模式和广播模式。当服务器启动或者领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数Server完成了和Leader的状态同步以后,恢复模式就结束了。状态同步保证了Leader和Server具有相同的系统状态。② 一旦leader已经和多数的follower进行了状态同步后,他就可以开始广播消息了,即进入广播状态。这时候当一个server加入zookeeper服务中,它会在恢复模式下启动,发现leader,并和leader进行状态同步。待到同步结束,它也参与消息广播。Zookeeper服务一直维持在Broadcast状态,直到leader崩溃了或者leader失去了大部分的followers支持。③ 广播模式需要保证proposal被按顺序处理,因此zk采用了递增的事务id号(zxid)来保证。所有的提议(proposal)都在被提出的时候加上了zxid。实现中zxid是一个64为的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch。低32位是个递增计数。
④ 当leader崩溃或者leader失去大多数的follower,这时候zk进入恢复模式,恢复模式需要重新选举出一个新的leader,让所有的server都恢复到一个正确的状态。

Leader选举

① 每个Server启动以后都询问其它的Server它要投票给谁。
② 对于其他server的询问,server每次根据自己的状态都回复自己推荐的leader的id和上一次处理事务的zxid(系统启动时每个server都会推荐自己)
③ 收到所有Server回复以后,就计算出zxid最大的哪个Server,并将这个Server相关信息设置成下一次要投票的Server。
④ 计算这过程中获得票数最多的的sever为获胜者,如果获胜者的票数超过半数,则改server被选为leader。否则,继续这个过程,直到leader被选举出来。
⑤ leader就会开始等待server连接
⑥ Follower连接leader,将最大的zxid发送给leader
⑦ Leader根据follower的zxid确定同步点
⑧ 完成同步后通知follower 已经成为uptodate状态
⑨ Follower收到uptodate消息后,又可以重新接受client的请求进行服务了
选举的过程,zk的实现中用了基于paxos算法(主要是fastpaxos)的实现。具体如下;此外恢复模式下,如果是重新刚从崩溃状态恢复的或者刚启动的的server还会从磁盘快照中恢复数据和会话信息。(zk会记录事务日志并定期进行快照,方便在恢复时进行状态恢复)



Observing: 观察状态,这时候observer会观察leader是否有改变,然后同步leader的状态;Following:  跟随状态,接收leader的proposal ,进行投票。并和leader进行状态同步



ZooKeeper应用场景

场景一:统一命名服务

① 分布式应用中,通常需要有一套完整的命名规则,既能够产生唯一的名称又便于人识别和记住,通常情况下用树形的名称结构是一个理想的选择,树形的名称结构是一个有层次的目录结构,既对人友好又不会重复。
② Name Service 是 Zookeeper 内置的功能,只要调用 Zookeeper 的 API 就能实现

场景二:配置管理

① 配置的管理在分布式应用环境中很常见,例如同一个应用系统需要多台 PC Server 运行,但是它们运行的应用系统的某些配置项是相同的,如果要修改这些相同的配置项,那么就必须同时修改每台运行这个应用系统的 PC Server,这样非常麻烦而且容易出错。
② 将配置信息保存在 Zookeeper 的某个目录节点中,然后将所有需要修改的应用机器监控配置信息的状态,一旦配置信息发生变化,每台应用机器就会收到 Zookeeper 的通知,然后从 Zookeeper 获取新的配置信息应用到系统中。
举例:Zookeeper很容易实现这种集中式的配置管理,比如将APP1的所有配置配置到/APP1 znode下,APP1所有机器一启动就对/APP1这个节点进行监控(zk.exist(“/APP1″,true)),并且实现回调方法 Watcher,那么在zookeeper上/APP1 znode节点下数据发生变化的时候,每个机器都会收到通知,Watcher方法将会被执行,那么应用再取下数据即可 (zk.getData(“/APP1″,false,null));



场景三:集群管理

① Zookeeper 能够很容易的实现集群管理的功能,如有多台 Server 组成一个服务集群,那么必须要一个“总管”知道当前集群中每台机器的服务状态,一旦有机器不能提供服务,集群中其它集群必须知道,从而做出调整重新分配服务策略。同样当增加集群的服务能力时,就会增加一台或多台 Server,同样也必须让“总管”知道。
② Zookeeper 不仅能够维护当前的集群中机器的服务状态,而且能够选出一个“总管”,让这个总管来管理集群,这就是 Zookeeper 的另一个功能 Leader Election。
③ 规定编号最小的为master,所以当我们对SERVERS节点做监控的时候,得到服务器列表,只要所有集群机器逻辑认为最小编号节点为master,那么master就被选出,而这个master宕机的时候,相应的znode会消失,然后新的服务器列表就被推送到客户端,然后每个节点逻辑认为最小编号节点为master,这样就做到动态master选举。
举例:应用集群中,我们常常需要让每一个机器知道集群中(或依赖的其他某一个集群)哪些机器是活着的,并且在集群机器因为宕机,网络断链等原因能够不在人工介入的情况下迅速通知到每一个机器。Zookeeper同样很容易实现这个功能,比如我在zookeeper服务器端有一个znode叫/APP1SERVERS,那么集群中每一个机器启动 的时候都去这个节点下创建一个EPHEMERAL类型的节点,比如server1创建/APP1SERVERS/SERVER1(可以使用ip,保证不重 复),server2创建/APP1SERVERS/SERVER2,然后SERVER1和SERVER2都watch /APP1SERVERS这个父节点,那么也就是这个父节点下数据或者子节点变化都会通知对该节点进行watch的客户端。因为EPHEMERAL类型节 点有一个很重要的特性,就是客户端和服务器端连接断掉或者session过期就会使节点消失,那么在某一个机器挂掉或者断链的时候,其对应的节点就会消失,然后集群中所有对/APP1SERVERS进行watch的客户端都会收到通知,然后取得最新列表即可。

场景四:共享锁

共享锁在同一个进程中很容易实现,但是在跨进程或者在不同 Server 之间就不好实现了。Zookeeper 却很容易实现这个功能,实现方式也是需要获得锁的 Server 创建一个 EPHEMERAL_SEQUENTIAL 目录节点,然后调用 getChildren方法获取当前的目录节点列表中最小的目录节点是不是就是自己创建的目录节点,如果正是自己创建的,那么它就获得了这个锁,如果不是那么它就调用 exists(String path, boolean watch) 方法并监控 Zookeeper 上目录节点列表的变化,一直到自己创建的节点是列表中最小编号的目录节点,从而获得锁,释放锁很简单,只要删除前面它自己所创建的目录节点就行了。



场景5:队列管理

① Zookeeper 可以处理两种类型的队列:当一个队列的成员都聚齐时,这个队列才可用,否则一直等待所有成员到达,这种是同步队列;队列按照 FIFO 方式进行入队和出队操作,例如实现生产者和消费者模型
② 创建一个父目录 /synchronizing,每个成员都监控目录 /synchronizing/start 是否存在,然后每个成员都加入这个队列(创建 /synchronizing/member_i 的临时目录节点),然后每个成员获取 / synchronizing 目录的所有目录节点,判断 i 的值是否已经是成员的个数,如果小于成员个数等待 /synchronizing/start 的出现,如果已经相等就创建 /synchronizing/start。
总结:Zookeeper 作为 Hadoop 项目中的一个子项目,是 Hadoop 集群管理的一个必不可少的模块,它主要用来控制集群中的数据,如它管理 Hadoop 集群中的 NameNode,还有 Hbase 中 Master Election、Server 之间状态同步等。

ZooKeeper的安装和配置

ZooKeeper的配置选项

zookeeper的默认配置文件为zookeeper/conf/zoo_sample.cfg,需要将其修改为zoo.cfg。其中各配置项的含义,解释如下:
① tickTime:CS通信心跳时间
Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个 tickTime 时间就会发送一个心跳。tickTime以毫秒为单位。
tickTime=2000  
② initLimit:LF初始通信时限
集群中的follower服务器(F)与leader服务器(L)之间初始连接时能容忍的最多心跳数(tickTime的数量)。
initLimit=5  
③ syncLimit:LF同步通信时限
集群中的follower服务器与leader服务器之间请求和应答之间能容忍的最多心跳数(tickTime的数量)。
syncLimit=2   
④ dataDir:数据文件目录
Zookeeper保存数据的目录,默认情况下,Zookeeper将写数据的日志文件也保存在这个目录里。
dataDir=/home/michael/opt/zookeeper/data  
⑤ clientPort:客户端连接端口
客户端连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求。
clientPort=2181 
⑥ 服务器名称与地址:集群信息(服务器编号,服务器地址,LF通信端口,选举端口)
这个配置项的书写格式比较特殊,规则如下:
server.N=YYY:A:B 
server.1=hadoop4:2888:3888
server.2=hadoop5:2888:3888
server.3=hadoop6:2888:3888配置说明:initLimit:这个配置项是用来配置 Zookeeper 接受客户端(这里所说的客户端不是用户连接 Zookeeper 服务器的客户端,而是 Zookeeper 服务器集群中连接到 Leader 的 Follower 服务器)初始化连接时最长能忍受多少个心跳时间间隔数。当已经超过 10 个心跳的时间(也就是 tickTime)长度后 Zookeeper 服务器还没有收到客户端的返回信息,那么表明这个客户端连接失败。总的时间长度就是 5*2000=10 秒syncLimit:这个配置项标识 Leader 与 Follower 之间发送消息,请求和应答时间长度,最长不能超过多少个 tickTime 的时间长度,总的时间长度就是 2*2000=4 秒
server.A=B:C:D   其中 A 是一个数字,表示这个是第几号服务器;B 是这个服务器的 ip 地址;C 表示的是这个服务器与集群中的 Leader 服务器交换信息的端口;D 表示的是万一集群中的 Leader 服务器挂了,需要一个端口来重新进行选举,选出一个新的 Leader,而这个端口就是用来执行选举时服务器相互通信的端口。如果是伪集群的配置方式,由于 B 都是一样,所以不同的 Zookeeper 实例通信端口号不能一样,所以要给它们分配不同的端口号。除了修改 zoo.cfg 配置文件,集群模式下还要配置一个文件 myid,这个文件在 dataDir 目录下,这个文件里面就有一个数据就是 A 的值,Zookeeper 启动时会读取这个文件,拿到里面的数据与 zoo.cfg 里面的配置信息比较从而判断到底是那个 server。分别在3台机器上启动ZooKeeper的Server:sh bin/zkServer.sh start;运行于一个集群上,适合生产环境,这个计算机集群被称为一个“集合体”(ensemble)

ZooKeeper单机模式安装

只运行在一台服务器上适用于测试环境。① 下载ZooKeeper 地址:http://archive.apache.org/dist/zookeeper/zookeeper-3.4.5/zookeeper-3.4.5.tar.gz② 解压到指定目录  tar zxvf zookeeper-3.4.3.tar.gz -C /cloud/③ 在conf目录下创建一个配置文件zoo.cfg,tickTime=2000dataDir=/cloud/zookeeper/datadataLogDir=/cloud/zookeeper/dataLog         clientPort=2181
启动ZooKeeper的Server:sh bin/zkServer.sh start, 如果想要关闭,输入:zkServer.sh stop

ZooKeeper集群模式安装

在dataDir目录中创建myid文件,server1机器的内容为:1,server2机器的内容为:2,server3机器的内容为:3
在conf目录下创建一个配置文件zoo.cfg,
tickTime=2000dataDir=/cloud/zookeeper/datadataLogDir=/cloud/zookeeper/dataLog         clientPort=2181        initLimit=5     
syncLimit=2         
server.1=server1:2888:3888              
server.2=server2:2888:3888                
server.3=server3:2888:3888

ZooKeeper伪集群安装

① 建立3个文件夹,server1 server2 server3,然后每个文件夹里面解压一个zookeeper的下载包
② 进入data目录,创建一个myid的文件,里面写入一个数字,server1,就写一个1,server2对应myid文件就写入2,server3对应myid文件就写个3
③ 在conf目录下创建一个配置文件zoo.cfg,
tickTime=2000dataDir=/cloud/zookeeper/datadataLogDir=/cloud/zookeeper/dataLog         
clientPort=2181                  
initLimit=5      
syncLimit=2         
server.1=server1:2888:3888                   
server.2=server2:2888:3888                          
server.3=server3:2888:3888
注意事项:在一台机器上部署了3个server;需要注意的是clientPort这个端口如果在1台机器上部署多个server,那么每台机器都要不同的clientPort,比如 server1是2181,server2是2182,server3是2183,dataDir和dataLogDir也需要区分下。
分别进入三个文件夹 分别启动查看即可 ./bin/zkServer.sh status  查看当前节点的状态

ZooKeeper接口

package hadoop.zookeeper.test;

import java.io.IOException;

import org.apache.hadoop.ha.ClientBaseWithFixes;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;

public class ZookeeperDemo {
public static void main(String[] args) throws Exception {
// 创建一个与服务器的连接
ZooKeeper zk = new ZooKeeper("hadoop0:2181", ClientBaseWithFixes.CONNECTION_TIMEOUT, new Watcher() {
// 监控所有触发的事情
@Override
public void process(WatchedEvent event) {
System.out.println("已经触发了"+event.getType()+"事件!");
}
});
// 创建一个目录节点
zk.create("/testRootPath", "testRootData".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
// 创建一个子目录节点
zk.create("/testRootPath/testChildPathOne", "testChildOneData".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
System.out.println(new String(zk.getData("/testRootPath", false, null)));
// 取出子目录节点列表
System.out.println(zk.getChildren("/testRootPath", true));
// 修改子目录节点数据
zk.setData("/testRootPath/testChildPathOne", "modifyChildOneData".getBytes(), -1);
System.out.println("目录节点状态:["+zk.exists("/testRootPath", true)+"]");
// 创建另外一个子目录节点
zk.create("/testRootPath/testChildPathTwo", "testChildTwoData".getBytes(), Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
System.out.println(new String(zk.getData("/testRootPath/testChildPathTwo", true, null)));
// 删除子目录节点
zk.delete("/testRootPath/testChildPathTwo", -1);
zk.delete("/testRootPath/testChildPathOne", -1);
// 删除父目录节点
zk.delete("/testRootPath", -1);
// 关闭连接
zk.close();

}
}
运行结果:已经触发了None事件!
testRootData
[testChildPathOne]
目录节点状态:[4294967298,4294967298,1504285237971,1504285237971,0,1,0,0,12,1,4294967299
]
已经触发了NodeChildrenChanged事件!
testChildTwoData
已经触发了NodeDeleted事件!
已经触发了NodeDeleted事件!

运行时注意事项:如果不导入测试包会导致异常java.lang.NoClassDefFoundError: org/apache/zookeeper/ZKTestCase导入 zookeeper-x.x.x-test.jar即可

Hadoop高可靠性HD的原理

在Hadoop2.0之前NameNode只有一个。如果NameNode宕机了,整个集群就不可用了。在Hadoop2.0之后。对NameNode进行了一次抽象,将NameNode抽象成了一个NameService。一个NameService中有两个NameNode,有了两个NameNode共存,需要进行协调,否则在启动时它们的状态都是Active(主)或者standby(备)。这个协调工作就交给了ZooKeeper,ZooKeeper中有一个master-selection选举机制,它确保任何时候NameService中只有一个活跃的NameNode,当NameService中处于Active状态的NameNode宕机后,处于standby状态的备机NameNode会被自动切换成Active状态,保证NameNode永远处于正常的工作状态。原理图如下:


如上图所示是两台NM(NameNode),主机和备机它们之间的协调依赖于ZooKeeper和ZKFC(ZKFailoverController)。每一个NameNode所在的机器节点都有一个ZKFC,ZKFC用于向NameNode发送指令来切换NameNode的状态,并对NameNode的状态进行监控,一旦NameNode程序挂掉了,ZKFC就和对应的NameNode失去了联系,就会将其信息发送给ZK (ZooKeeper)。ZK和ZKFC通讯依赖于心跳机制(即每隔一段时间ZKFC将它监控的NameNode信息发送给ZK)。由于ZooKeeper集群中每台信息是同步的,别的处于Follower状态的ZK(ZooKeeper中的节点)得到处于active状态的NameNode挂掉的信息,就会通过心跳机制和复负责监控NameNode备机的ZKFC进行通讯,处于Standby状态的ZKFC就会发送指令将它所监控的NameNode备机切换成active状态。
已知Hadoop1.0 中NameNode会不断的将元数据信息写入edits和fsimage文件中。在Hadoop2.0之后就不再使用这种方式。如上图所示,处于Active活跃状态的NameNode会实时的将eidts文件存入到专门存放edits文件的介质中(JournalNode,它依赖于ZooKeeper),处于standby状态的NameNode会实时的将介质中的数据同步下来,从而完成active状态的NameNode和standby状态的NameNode中数据的实时同步。
隔离机制:第一种是sshfence 当处于active状态的NM出现了问题但是此进程没有死掉,通过通讯,处于standby状态的NM得到了此信息,但是不能启动两个active状态的NM,standby状态的NM就会首先通过sshfence隔离机制发送命令kill掉出问题的active状态的NM,然后自己转为active状态。第二种就是shell(/bin/true) 隔离机制,在处于active状态的NM所在机器宕机后,同时与它在同一台机器的ZKFC也会死掉,当standby状态的NM发现长时间没有收到active状态的NM的信息,就会任务它已经宕机了,然后就会执行shell脚本,只要返回true,它就会切换为active状态。

Hadoop集群搭建

hadoop集群搭建 根据版本的阶段分为三种安装方式 2.0之前 ——都是单节点2.0以后2.4.1之前 ——NameNode 实现了NameService 主机和备机2.4.1之后—— NameNode和ResourceManager均实现的主机和备机

Hadoop2.2.0集群搭建说明书

hadoop2.0已经发布了稳定版本了,增加了很多特性,比如HDFS HA、YARN等。
1.修改Linux主机名
2.修改IP
3.修改主机名和IP的映射关系
######注意######如果公司是租用的服务器或是使用的云主机(如华为用主机、阿里云主机等)
/etc/hosts里面要配置的是内网IP地址和主机名的映射关系
4.关闭防火墙
5.ssh免登陆
6.安装JDK,配置环境变量等

集群规划:
主机名		IP				安装的软件					运行的进程
hadoop1	192.168.0.10	jdk、hadoop					NameNode、DFSZKFailoverController
hadoop2	192.168.0.20	jdk、hadoop					NameNode、DFSZKFailoverController
hadoop3	192.168.0.30	jdk、hadoop					ResourceManager
hadoop4	192.168.0.40	jdk、hadoop、zookeeper		DataNode、NodeManager、JournalNode、QuorumPeerMain
hadoop5	192.168.0.50	jdk、hadoop、zookeeper		DataNode、NodeManager、JournalNode、QuorumPeerMain
hadoop6	192.168.0.60	jdk、hadoop、zookeeper		DataNode、NodeManager、JournalNode、QuorumPeerMain

说明:
在hadoop2.0中通常由两个NameNode组成,一个处于active状态,另一个处于standby状态。Active NameNode对外提供服务,而Standby NameNode则不对外提供服务,仅同步active namenode的状态,以便能够在它失败时快速进行切换。
hadoop2.0官方提供了两种HDFS HA的解决方案,一种是NFS,另一种是QJM。这里我们使用简单的QJM。在该方案中,主备NameNode之间通过一组JournalNode同步元数据信息,一条数据只要成功写入多数JournalNode即认为写入成功。通常配置奇数个JournalNode
这里还配置了一个zookeeper集群,用于ZKFC(DFSZKFailoverController)故障转移,当Active NameNode挂掉了,会自动切换Standby NameNode为standby状态

安装步骤:
1.安装配置zooekeeper集群
1.1解压
tar -zxvf zookeeper-3.4.5.tar.gz -C /cloud/
1.2修改配置
cd /cloud/zookeeper-3.4.5/conf/
cp zoo_sample.cfg zoo.cfg
vim zoo.cfg
修改:dataDir=/cloud/zookeeper-3.4.5/tmp
在最后添加:
server.1=hadoop4:2888:3888
server.2=hadoop5:2888:3888
server.3=hadoop6:2888:3888
保存退出
然后创建一个tmp文件夹
mkdir /cloud/zookeeper-3.4.5/tmp
再创建一个空文件
touch /cloud/zookeeper-3.4.5/tmp/myid
最后向该文件写入ID
echo 1 > /cloud/zookeeper-3.4.5/tmp/myid
1.3将配置好的zookeeper拷贝到其他节点(首先分别在hadoop5、hadoop6根目录下创建一个cloud目录:mkdir /cloud)
scp -r /cloud/zookeeper-3.4.5/ hadoop5:/cloud/
scp -r /cloud/zookeeper-3.4.5/ hadoop6:/cloud/

注意:修改hadoop5、hadoop6对应/cloud/zookeeper-3.4.5/tmp/myid内容
hadoop5:
echo 2 > /cloud/zookeeper-3.4.5/tmp/myid
hadoop6:
echo 3 > /cloud/zookeeper-3.4.5/tmp/myid

2.安装配置hadoop集群
2.1解压
tar -zxvf hadoop-2.2.0.tar.gz -C /cloud/
2.2配置HDFS(hadoop2.0所有的配置文件都在$HADOOP_HOME/etc/hadoop目录下)
#将hadoop添加到环境变量中
vim /etc/profile
export JAVA_HOME=/usr/java/jdk1.7.0_55
export HADOOP_HOME=/cloud/hadoop-2.2.0
export PATH=$PATH:$JAVA_HOME/bin:$HADOOP_HOME/bin

#hadoop2.0的配置文件全部在$HADOOP_HOME/etc/hadoop下
cd /cloud/hadoop-2.2.0/etc/hadoop

2.2.1修改hadoo-env.sh
export JAVA_HOME=/usr/java/jdk1.7.0_55

2.2.2修改core-site.xml
<configuration>
<!-- 指定hdfs的nameservice为ns1 -->
<property>
<name>fs.defaultFS</name>
<value>hdfs://ns1</value>
</property>
<!-- 指定hadoop临时目录 -->
<property>
<name>hadoop.tmp.dir</name>
<value>/cloud/hadoop-2.2.0/tmp</value>
</property>
<!-- 指定zookeeper地址 -->
<property>
<name>ha.zookeeper.quorum</name>
<value>hadoop4:2181,hadoop5:2181,hadoop6:2181</value>
</property>
</configuration>

2.2.3修改hdfs-site.xml
<configuration>
<!--指定hdfs的nameservice为ns1,需要和core-site.xml中的保持一致 -->
<property>
<name>dfs.nameservices</name>
<value>ns1</value>
</property>
<!-- ns1下面有两个NameNode,分别是nn1,nn2 -->
<property>
<name>dfs.ha.namenodes.ns1</name>
<value>nn1,nn2</value>
</property>
<!-- nn1的RPC通信地址 -->
<property>
<name>dfs.namenode.rpc-address.ns1.nn1</name>
<value>hadoop1:9000</value>
</property>
<!-- nn1的http通信地址 -->
<property>
<name>dfs.namenode.http-address.ns1.nn1</name>
<value>hadoop1:50070</value>
</property>
<!-- nn2的RPC通信地址 -->
<property>
<name>dfs.namenode.rpc-address.ns1.nn2</name>
<value>hadoop2:9000</value>
</property>
<!-- nn2的http通信地址 -->
<property>
<name>dfs.namenode.http-address.ns1.nn2</name>
<value>hadoop2:50070</value>
</property>
<!-- 指定NameNode的元数据在JournalNode上的存放位置 -->
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://hadoop4:8485;hadoop5:8485;hadoop6:8485/ns1</value>
</property>
<!-- 指定JournalNode在本地磁盘存放数据的位置 -->
<property>
<name>dfs.journalnode.edits.dir</name>
<value>/cloud/hadoop-2.2.0/journal</value>
</property>
<!-- 开启NameNode失败自动切换 -->
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
<!-- 配置失败自动切换实现方式 -->
<property>
<name>dfs.client.failover.proxy.provider.ns1</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>
<!-- 配置隔离机制方法,多个机制用换行分割,即每个机制暂用一行-->
<property>
<name>dfs.ha.fencing.methods</name>
<value>
sshfence
shell(/bin/true)
</value>
</property>
<!-- 使用sshfence隔离机制时需要ssh免登陆 -->
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/root/.ssh/id_rsa</value>
</property>
<!-- 配置sshfence隔离机制超时时间 -->
<property>
<name>dfs.ha.fencing.ssh.connect-timeout</name>
<value>30000</value>
</property>
</configuration>

2.2.4修改mapred-site.xml
<configuration>
<!-- 指定mr框架为yarn方式 -->
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
</configuration>

2.2.5修改yarn-site.xml
<configuration>
<!-- 指定resourcemanager地址 -->
<property>
<name>yarn.resourcemanager.hostname</name>
<value>hadoop3</value>
</property>
<!-- 指定nodemanager启动时加载server的方式为shuffle server -->
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
</configuration>

2.2.6修改slaves(slaves是指定子节点的位置,因为要在hadoop1上启动HDFS、在hadoop3启动yarn,所以hadoop1上的slaves文件指定的是datanode的位置,hadoop3上的slaves文件指定的是nodemanager的位置)
hadoop4
hadoop5
hadoop6

2.2.7配置免密码登陆
#首先要配置hadoop1到hadoop2、hadoop3、hadoop4、hadoop5、hadoop6的免密码登陆
#在hadoop1上生产一对钥匙
ssh-keygen -t rsa
#将公钥拷贝到其他节点,包括自己
ssh-coyp-id hadoop1
ssh-coyp-id hadoop2
ssh-coyp-id hadoop3
ssh-coyp-id hadoop4
ssh-coyp-id hadoop5
ssh-coyp-id hadoop6

#配置hadoop3到hadoop4、hadoop5、hadoop6的免密码登陆
#在hadoop3上生产一对钥匙
ssh-keygen -t rsa
#将公钥拷贝到其他节点
ssh-coyp-id hadoop4
ssh-coyp-id hadoop5
ssh-coyp-id hadoop6

#注意:两个namenode之间要配置ssh免密码登陆,别忘了配置hadoop2到hadoop1的免登陆
在hadoop2上生产一对钥匙
ssh-keygen -t rsa
ssh-coyp-id -i hadoop1

2.4将配置好的hadoop拷贝到其他节点
scp -r /cloud/ hadoop2:/
scp -r /cloud/ hadoop3:/
scp -r /cloud/hadoop-2.2.0/ root@hadoop4:/cloud/
scp -r /cloud/hadoop-2.2.0/ root@hadoop5:/cloud/
scp -r /cloud/hadoop-2.2.0/ root@hadoop6:/cloud/

###注意:严格按照下面的步骤
2.5启动zookeeper集群(分别在hadoop4、hadoop5、hadoop6上启动zk)
cd /cloud/zookeeper-3.4.5/bin/
./zkServer.sh start
#查看状态:一个leader,两个follower
./zkServer.sh status

2.6启动journalnode(在hadoop1上启动所有journalnode,注意:是调用的hadoop-daemons.sh这个脚本,注意是复数s的那个脚本)
cd /cloud/hadoop-2.2.0
sbin/hadoop-daemons.sh start journalnode
#运行jps命令检验,hadoop4、hadoop5、hadoop6上多了JournalNode进程

2.7格式化HDFS
#在hadoop1上执行命令:
hdfs namenode -format
#格式化后会在根据core-site.xml中的hadoop.tmp.dir配置生成个文件,这里我配置的是/cloud/hadoop-2.2.0/tmp,然后将/cloud/hadoop-2.2.0/tmp拷贝到hadoop2的/cloud/hadoop-2.2.0/下。
scp -r tmp/ hadoop2:/cloud/hadoop-2.2.0/

2.8格式化ZK(在hadoop1上执行即可)
hdfs zkfc -formatZK

2.9启动HDFS(在hadoop1上执行)
sbin/start-dfs.sh

2.10启动YARN(#####注意#####:是在hadoop3上执行start-yarn.sh,把namenode和resourcemanager分开是因为性能问题,因为他们都要占用大量资源,所以把他们分开了,他们分开了就要分别在不同的机器上启动)
sbin/start-yarn.sh

到此,hadoop2.2.0配置完毕,可以统计浏览器访问: http://192.168.0.10:50070 NameNode 'hadoop1:9000' (active) http://192.168.0.20:50070 NameNode 'hadoop2:9000' (standby)

验证HDFS HA
首先向hdfs上传一个文件
hadoop fs -put /etc/profile /profile
hadoop fs -ls /
然后再kill掉active的NameNode
kill -9 <pid of NN>
通过浏览器访问:http://192.168.0.20:50070
NameNode 'hadoop2:9000' (active)
这个时候hadoop2上的NameNode变成了active
在执行命令:
hadoop fs -ls /
-rw-r--r--   3 root supergroup       1926 2014-02-06 15:36 /profile
刚才上传的文件依然存在!!!
手动启动那个挂掉的NameNode
sbin/hadoop-daemon.sh start namenode
通过浏览器访问:http://192.168.0.10:50070
NameNode 'hadoop1:9000' (standby)

验证YARN:
运行一下hadoop提供的demo中的WordCount程序:
hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.2.0.jar wordcount /profile /out

OK,大功告成!!!

Hadoop2.4.1集群搭建说明

hadoop2.0已经发布了稳定版本了,增加了很多特性,比如HDFS HA、YARN等。最新的hadoop-2.4.1又增加了YARN HA
1.修改Linux主机名
2.修改IP
3.修改主机名和IP的映射关系
######注意######如果你们公司是租用的服务器或是使用的云主机(如华为用主机、阿里云主机等)
/etc/hosts里面要配置的是内网IP地址和主机名的映射关系
4.关闭防火墙
5.ssh免登陆
6.安装JDK,配置环境变量等

集群规划:
主机名		IP				安装的软件					运行的进程
hadoop1	192.168.0.10	jdk、hadoop					NameNode、DFSZKFailoverController(zkfc)
hadoop2	192.168.0.20	jdk、hadoop					NameNode、DFSZKFailoverController(zkfc)
hadoop3	192.168.0.30	jdk、hadoop					ResourceManager
hadoop4	192.168.0.40	jdk、hadoop					ResourceManager
hadoop5	192.168.0.50	jdk、hadoop、zookeeper		DataNode、NodeManager、JournalNode、QuorumPeerMain
hadoop6	192.168.0.60	jdk、hadoop、zookeeper		DataNode、NodeManager、JournalNode、QuorumPeerMain
hadoop7	192.168.0.70	jdk、hadoop、zookeeper		DataNode、NodeManager、JournalNode、QuorumPeerMain

说明:
1.在hadoop2.0中通常由两个NameNode组成,一个处于active状态,另一个处于standby状态。Active NameNode对外提供服务,而Standby NameNode则不对外提供服务,仅同步active namenode的状态,以便能够在它失败时快速进行切换。
hadoop2.0官方提供了两种HDFS HA的解决方案,一种是NFS,另一种是QJM。这里我们使用简单的QJM。在该方案中,主备NameNode之间通过一组JournalNode同步元数据信息,一条数据只要成功写入多数JournalNode即认为写入成功。通常配置奇数个JournalNode
这里还配置了一个zookeeper集群,用于ZKFC(DFSZKFailoverController)故障转移,当Active NameNode挂掉了,会自动切换Standby NameNode为standby状态
2.hadoop-2.2.0中依然存在一个问题,就是ResourceManager只有一个,存在单点故障,hadoop-2.4.1解决了这个问题,有两个ResourceManager,一个是Active,一个是Standby,状态由zookeeper进行协调
安装步骤:
1.安装配置zooekeeper集群(在hadoop5上)
1.1解压
tar -zxvf zookeeper-3.4.5.tar.gz -C /cloud/
1.2修改配置
cd /cloud/zookeeper-3.4.5/conf/
cp zoo_sample.cfg zoo.cfg
vim zoo.cfg
修改:dataDir=/cloud/zookeeper-3.4.5/tmp
在最后添加:
server.1=hadoop5:2888:3888
server.2=hadoop6:2888:3888
server.3=hadoop7:2888:3888
保存退出
然后创建一个tmp文件夹
mkdir /cloud/zookeeper-3.4.5/tmp
再创建一个空文件
touch /cloud/zookeeper-3.4.5/tmp/myid
最后向该文件写入ID
echo 1 > /cloud/zookeeper-3.4.5/tmp/myid
1.3将配置好的zookeeper拷贝到其他节点(首先分别在hadoop6、hadoop7根目录下创建一个cloud目录:mkdir /cloud)
scp -r /cloud/zookeeper-3.4.5/ hadoop6:/cloud/
scp -r /cloud/zookeeper-3.4.5/ hadoop7:/cloud/

注意:修改hadoop6、hadoop7对应/cloud/zookeeper-3.4.5/tmp/myid内容
hadoop6:
echo 2 > /cloud/zookeeper-3.4.5/tmp/myid
hadoop7:
echo 3 > /cloud/zookeeper-3.4.5/tmp/myid

2.安装配置hadoop集群(在hadoop1上操作)
2.1解压
tar -zxvf hadoop-2.4.1.tar.gz -C /cloud/
2.2配置HDFS(hadoop2.0所有的配置文件都在$HADOOP_HOME/etc/hadoop目录下)
#将hadoop添加到环境变量中
vim /etc/profile
export JAVA_HOME=/usr/java/jdk1.7.0_55
export HADOOP_HOME=/cloud/hadoop-2.4.1
export PATH=$PATH:$JAVA_HOME/bin:$HADOOP_HOME/bin

#hadoop2.0的配置文件全部在$HADOOP_HOME/etc/hadoop下
cd /cloud/hadoop-2.4.1/etc/hadoop

2.2.1修改hadoo-env.sh
export JAVA_HOME=/usr/java/jdk1.7.0_55

2.2.2修改core-site.xml
<configuration>
<!-- 指定hdfs的nameservice为ns1 -->
<property>
<name>fs.defaultFS</name>
<value>hdfs://ns1</value>
</property>
<!-- 指定hadoop临时目录 -->
<property>
<name>hadoop.tmp.dir</name>
<value>/cloud/hadoop-2.4.1/tmp</value>
</property>
<!-- 指定zookeeper地址 -->
<property>
<name>ha.zookeeper.quorum</name>
<value>hadoop5:2181,hadoop6:2181,hadoop7:2181</value>
</property>
</configuration>

2.2.3修改hdfs-site.xml
<configuration>
<!--指定hdfs的nameservice为ns1,需要和core-site.xml中的保持一致 -->
<property>
<name>dfs.nameservices</name>
<value>ns1</value>
</property>
<!-- ns1下面有两个NameNode,分别是nn1,nn2 -->
<property>
<name>dfs.ha.namenodes.ns1</name>
<value>nn1,nn2</value>
</property>
<!-- nn1的RPC通信地址 -->
<property>
<name>dfs.namenode.rpc-address.ns1.nn1</name>
<value>hadoop1:9000</value>
</property>
<!-- nn1的http通信地址 -->
<property>
<name>dfs.namenode.http-address.ns1.nn1</name>
<value>hadoop1:50070</value>
</property>
<!-- nn2的RPC通信地址 -->
<property>
<name>dfs.namenode.rpc-address.ns1.nn2</name>
<value>hadoop2:9000</value>
</property>
<!-- nn2的http通信地址 -->
<property>
<name>dfs.namenode.http-address.ns1.nn2</name>
<value>hadoop2:50070</value>
</property>
<!-- 指定NameNode的元数据在JournalNode上的存放位置 -->
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://hadoop5:8485;hadoop6:8485;hadoop7:8485/ns1</value>
</property>
<!-- 指定JournalNode在本地磁盘存放数据的位置 -->
<property>
<name>dfs.journalnode.edits.dir</name>
<value>/cloud/hadoop-2.4.1/journal</value>
</property>
<!-- 开启NameNode失败自动切换 -->
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
<!-- 配置失败自动切换实现方式 -->
<property>
<name>dfs.client.failover.proxy.provider.ns1</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>
<!-- 配置隔离机制方法,多个机制用换行分割,即每个机制暂用一行-->
<property>
<name>dfs.ha.fencing.methods</name>
<value>
sshfence
shell(/bin/true)
</value>
</property>
<!-- 使用sshfence隔离机制时需要ssh免登陆 -->
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/home/hadoop/.ssh/id_rsa</value>
</property>
<!-- 配置sshfence隔离机制超时时间 -->
<property>
<name>dfs.ha.fencing.ssh.connect-timeout</name>
<value>30000</value>
</property>
</configuration>

2.2.4修改mapred-site.xml
<configuration>
<!-- 指定mr框架为yarn方式 -->
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
</configuration>

2.2.5修改yarn-site.xml
<configuration>
<!-- 开启RM高可靠 -->
<property>
<name>yarn.resourcemanager.ha.enabled</name>
<value>true</value>
</property>
<!-- 指定RM的cluster id -->
<property>
<name>yarn.resourcemanager.cluster-id</name>
<value>yrc</value>
</property>
<!-- 指定RM的名字 -->
<property>
<name>yarn.resourcemanager.ha.rm-ids</name>
<value>rm1,rm2</value>
</property>
<!-- 分别指定RM的地址 -->
<property>
<name>yarn.resourcemanager.hostname.rm1</name>
<value>hadoop3</value>
</property>
<property>
<name>yarn.resourcemanager.hostname.rm2</name>
<value>hadoop4</value>
</property>
<!-- 指定zk集群地址 -->
<property>
<name>yarn.resourcemanager.zk-address</name>
<value>hadoop5:2181,hadoop6:2181,hadoop7:2181</value>
</property>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
</configuration>

2.2.6修改slaves(slaves是指定子节点的位置,因为要在hadoop1上启动HDFS、在hadoop3启动yarn,所以hadoop1上的slaves文件指定的是datanode的位置,hadoop3上的slaves文件指定的是nodemanager的位置)
hadoop5
hadoop6
hadoop7

2.2.7配置免密码登陆
#首先要配置hadoop1到hadoop2、hadoop3、hadoop4、hadoop5、hadoop6、hadoop7的免密码登陆
#在hadoop1上生产一对钥匙
ssh-keygen -t rsa
#将公钥拷贝到其他节点,包括自己
ssh-coyp-id hadoop1
ssh-coyp-id hadoop2
ssh-coyp-id hadoop3
ssh-coyp-id hadoop4
ssh-coyp-id hadoop5
ssh-coyp-id hadoop6
ssh-coyp-id hadoop7
#配置hadoop3到hadoop4、hadoop5、hadoop6、hadoop7的免密码登陆
#在hadoop3上生产一对钥匙
ssh-keygen -t rsa
#将公钥拷贝到其他节点
ssh-coyp-id hadoop4
ssh-coyp-id hadoop5
ssh-coyp-id hadoop6
ssh-coyp-id hadoop7
#注意:两个namenode之间要配置ssh免密码登陆,别忘了配置hadoop2到hadoop1的免登陆
在hadoop2上生产一对钥匙
ssh-keygen -t rsa
ssh-coyp-id -i hadoop1

2.4将配置好的hadoop拷贝到其他节点
scp -r /cloud/ hadoop2:/
scp -r /cloud/ hadoop3:/
scp -r /cloud/hadoop-2.4.1/ root@hadoop4:/cloud/
scp -r /cloud/hadoop-2.4.1/ root@hadoop5:/cloud/
scp -r /cloud/hadoop-2.4.1/ root@hadoop6:/cloud/
scp -r /cloud/hadoop-2.4.1/ root@hadoop7:/cloud/
###注意:严格按照下面的步骤
2.5启动zookeeper集群(分别在hadoop5、hadoop6、tcast07上启动zk)
cd /cloud/zookeeper-3.4.5/bin/
./zkServer.sh start
#查看状态:一个leader,两个follower
./zkServer.sh status

2.6启动journalnode(分别在在hadoop5、hadoop6、tcast07上执行)
cd /cloud/hadoop-2.4.1
sbin/hadoop-daemon.sh start journalnode
#运行jps命令检验,hadoop5、hadoop6、hadoop7上多了JournalNode进程

2.7格式化HDFS
#在hadoop1上执行命令:
hdfs namenode -format
#格式化后会在根据core-site.xml中的hadoop.tmp.dir配置生成个文件,这里我配置的是/cloud/hadoop-2.4.1/tmp,然后将/cloud/hadoop-2.4.1/tmp拷贝到hadoop2的/cloud/hadoop-2.4.1/下。
scp -r tmp/ hadoop2:/cloud/hadoop-2.4.1/

2.8格式化ZK(在hadoop1上执行即可)
hdfs zkfc -formatZK

2.9启动HDFS(在hadoop1上执行)
sbin/start-dfs.sh

2.10启动YARN(#####注意#####:是在hadoop3上执行start-yarn.sh,把namenode和resourcemanager分开是因为性能问题,因为他们都要占用大量资源,所以把他们分开了,他们分开了就要分别在不同的机器上启动)
sbin/start-yarn.sh

到此,hadoop-2.4.1配置完毕,可以统计浏览器访问: http://192.168.0.10:50070 NameNode 'hadoop1:9000' (active) http://192.168.0.20:50070 NameNode 'hadoop2:9000' (standby)

验证HDFS HA
首先向hdfs上传一个文件
hadoop fs -put /etc/profile /profile
hadoop fs -ls /
然后再kill掉active的NameNode
kill -9 <pid of NN>
通过浏览器访问:http://192.168.0.20:50070
NameNode 'hadoop2:9000' (active)
这个时候hadoop2上的NameNode变成了active
在执行命令:
hadoop fs -ls /
-rw-r--r--   3 root supergroup       1926 2014-02-06 15:36 /profile
刚才上传的文件依然存在!!!
手动启动那个挂掉的NameNode
sbin/hadoop-daemon.sh start namenode
通过浏览器访问:http://192.168.0.10:50070
NameNode 'hadoop1:9000' (standby)

验证YARN:
运行一下hadoop提供的demo中的WordCount程序:
hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-2.4.1.jar wordcount /profile /out

配置成功!!!
我使用的Hadoop版本是2.7.4 ,由于嫌麻烦,就按照2.2.0的方式进行配置的。查看启动和停止信息在hadoop1上停止HDFS 



在hadoop3上停止Yarn



再次在hadoop1上启动HDFS 查看启动顺序



启动HDFS文件系统时,在hadoop1中读取$HADOOP_HOME/etc/hadoop/目录中的hdfs-site.xml信息启动NameNode,根据slaves配置文件通过ssh协议启动DataNodes,然后根据hdfs-site.xml中的信息通过ssh协议启动JournalNodes 至于最后启动的ZKFC 是和每台NameNode连在一块的。NameNodes—>DataNodes—>JournalNodes—>ZKFCs
需要注意的是:在安装格式化的时候,需要启动JournalNode,在安装完成后启动HDFS或YARN前只需要启动ZooKeeper集群即可
再次在hadoop3上启动yarn 查看启动顺序

在启动yarn的时候,首先启动ResourceManager 因为在本地的yarn-site.xml中配置的ResourceManager所在主机是hadoop3 所以会在本地启动,然后读取本地的slaves配置文件 通过ssh协议将slaves文件中指定的所有的主机上启动NodeManager。注意:启动时都是读取本地的配置文件,在hadoop3上启动yarn 会根据本地的slaves中的配置决定在哪些台机器上启动NodeManager,而在hadoop1上启动HDFS会根据它本地的slaves配置 确定在哪些台机器上启动DataNode,一般情况下建议它们的slaves配置文件保持一致,不过不一致也可,如果不一致意味着NodeManager和DataNode不完全在同样的机器中启动。

Hadoop集群下Java操作方式

package liuxun.hadoop.ha.hdfs;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;

import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IOUtils;

public class HDFSDemo_HA {
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
conf.set("dfs.nameservices", "ns1");
conf.set("dfs.ha.namenodes.ns1", "nn1,nn2");
conf.set("dfs.namenode.rpc-address.ns1.nn1", "hadoop1:9000");
conf.set("dfs.namenode.rpc-address.ns1.nn2", "hadoop2:9000");
conf.set("dfs.client.failover.proxy.provider.ns1",
"org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider");
// FileSystem fs = FileSystem.get(new URI("hdfs://ns1"), conf);
// 测试下载
// InputStream in = fs.open(new Path("/profile"));
// OutputStream out = new FileOutputStream("/Users/liuxun/Downloads/p.txt");
// IOUtils.copyBytes(in, out, 4096, true);

// 测试上传
FileSystem fs = FileSystem.get(new URI("hdfs://ns1"), conf,"root");
InputStream in = new FileInputStream("/Users/liuxun/Downloads/a.txt");
OutputStream out = fs.create(new Path("/a"));
IOUtils.copyBytes(in, out, 4096, true);

}
}

Sqoop

Sqoop是一个用来将Hadoop和关系型数据库中的数据相互转移的工具,可以将一个关系型数据库(例如 : MySQL ,Oracle ,Postgres等)中的数据导进到Hadoop的HDFS中,也可以将HDFS的数据导进到关系型数据库中。sqoop
数据迁移工具——主要用于HDFS和关系型数据库之间数据的相互迁移
例如可以将关系型数据库中的历史数据迁移到HDFS上,运行MapReduce计算分析结果输出到HDFS上,再将结果迁移到关系型数据库中。而sqoop有自己独特的语法,底层采用MapReducer实现,可它以启动多个并行的MapReducer.它依赖于yarn和HDFS。
注意:sqoop不需要搭建集群,它可以安装在任意一台机器上

首先下载sqoop  http://archive.apache.org/dist/sqoop/1.4.4/



我的安装位置是放在hadoop3上
上传安装包,解压到/cloud/下
tar -zxvf sqoop-1.4.4.bin__hadoop-2.0.4-alpha.tar.gz -C /cloud/
发现名称过长 进行重命名
mv sqoop-1.4.4.bin__hadoop-2.0.4-alpha/ sqoop-1.4.4
配置:如果安装配置了Hadoop 则不需要对sqoop的配置文件做任何配置,实际上它会查找环境变量$HADOOP_HOME  找到Hadoop的配置文件 然后就可以查找到ResourceManager和NameNode的位置。
(1) 首选将sqoop添加到环境变量
vim /etc/profile 修改成如下配置
export JAVA_HOME=/usr/java/jdk1.8.0_144
export HADOOP_HOME=/cloud/hadoop-2.7.4
export SQOOP_HOME=/cloud/sqoop-1.4.4
export PATH=$PATH:$JAVA_HOME/bin:$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$SQOOP_HOME/bi
n
使其生效:source /etc/profile
(2)将数据库连接驱动拷贝到$SQOOP_HOME/lib里
(3)将数据库开启远程连接
在使用之前首先保证要操作的数据库开启远程连接 MySQL开启远程连接的方法如下
GRANT ALL PRIVILEGES ON myshop.* TO 'root'@'192.168.0.30’ IDENTIFIED BY ‘root’ WITH GRANT OPTION;
FLUSH PRIVILEGES; 
GRANT ALL PRIVILEGES ON *.* TO 'root'@'%' IDENTIFIED BY ‘root’ WITH GRANT OPTION;
FLUSH PRIVILEGES
注意:*.* 所有数据库所有表  'root'@'%'  允许任意主机以root用户身份连接 IDENTIFIED BY 表示连接时的密码
(4)使用(可以查看安装包中的文档)



第一类:数据库中的数据导入到HDFS上
① 指定输出哪些列
 sqoop import --connect jdbc:mysql://192.168.0.103:3306/myshop --username root --password root --table product --columns 'pid,pname,market_price,shop_price'
② 指定输出路径、指定数据分隔符
 sqoop import --connect jdbc:mysql://192.168.0.103:3306/myshop --username root --password root --table product --columns 'pid,pname,market_price,shop_price' --target-dir '/sqoop/td1' --fields-terminated-by '\t'
③ 指定Map数量 -m 
sqoop import --connect jdbc:mysql://192.168.0.103:3306/myshop --username root --password root --table product --columns 'pid,pname,market_price,shop_price' --target-dir '/sqoop/td2' --fields-terminated-by '\t' -m 2
(只会生成两个part文件 part-m-00000和part-m-00001  说明sqoop底层只是使用了map没有使用reducer)
④ 增加where条件, 注意:条件必须用引号引起来
sqoop import --connect jdbc:mysql://192.168.0.103:3306/myshop --username root --password root --table product --columns 'pid,pname,market_price,shop_price' --where 'pid>4 and  pname like "%装%"'  --target-dir '/sqoop/td3' --fields-terminated-by '\t' -m 2
⑤ 增加query语句(使用 \ 将语句换行)
 sqoop import --connect jdbc:mysql://192.168.0.103:3306/myshop --username root --password root --query 'select * from product where pid > 6 and pname like "%套%" and $CONDITIONS' --split-by product.pid  --target-dir '/sqoop/td4' --fields-terminated-by '\t' -m 3
注意:如果使用--query这个命令的时候,需要注意的是where后面的参数,AND $CONDITIONS这个参数必须加上
而且存在单引号与双引号的区别,如果--query后面使用的是双引号,那么需要在$CONDITIONS前加上\即\$CONDITIONS
如果设置map数量为1个时即-m 1,不用加上--split-by ${tablename.column},否则需要加上
第二类:将HDFS上的数据导出到数据库中(不要忘记指定分隔符)
首先在数据库中创建和product字段一样的表 
create table tab_back like product;
命令:
sqoop export --connect jdbc:mysql://192.168.0.103:3306/myshop --username root --password root --export-dir '/sqoop/td3' --table tab_back -m 1 --fields-terminated-by '\t'
成功执行,刷新数据库,发现tab_back表中有了数据

shell使用技巧

set -x 调试(即在运行脚本的时候,会将脚本里的内容打印出来)echo "1234"  打印输出STR="Hello World" 定义一个变量echo  "$STR"  输出变量值hadoop jar /cloud/hadoop-2.7.4/share/mapreduce/hadoop-mapreduce-examples-2.7.4.jar wordcount /wc.txt /wcount >> /root/logs   2>&1 &运行计算jar包 并将日志打印到指定文件中2>&1 表示错误输出和标准输出都输出到同一个文件& 表示使其成为一个后台进程CURRENT=`date +%Y%m%d``` 将方法的返回值赋给变量
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: