|
|
楼主 |
发表于 2022-11-15 10:00:33
|
显示全部楼层
一、高可用简介+ h( x+ s4 U% L: |5 e. q
二、集群规划
9 l- e( g8 a/ a5 t( A& Q三、前置条件
* a: m8 H, J/ m8 m# I( z9 A四、集群配置
6 y9 S0 X1 n* m; k五、启动集群4 d6 r& L. Z) h- p
六、查看集群
& d- W- e1 {3 d, g# Q$ x七、集群的二次启动5 _% k' `; n( C6 y% X
一、高可用简介8 B7 `$ a# [# _/ H; y9 w t: D2 N
Hadoop 高可用 (High Availability) 分为 HDFS 高可用和 YARN 高可用,两者的实现基本类似,但 HDFS NameNode 对数据存储及其一致性的要求比 YARN ResourceManger 高得多,所以它的实现也更加复杂,故下面先进行讲解:6 }3 l+ B0 U ~$ |9 e
9 r% s7 u/ c @. L$ u, R; P
1.1 高可用整体架构
6 _6 i! y, y6 x$ N9 ? bHDFS 高可用架构如下:. ?3 k+ c; Z# K0 D1 u: ]
/ |! c1 ~8 H: G! |% i
9 H& U8 ~ D' c( d6 r9 p
图片引用自:https://www.edureka.co/blog/how- ... -high-availability/7 C" E' } r, b8 b" ~
2 c- P r# h1 f/ x
HDFS 高可用架构主要由以下组件所构成:: ?8 w {2 Y) [
; @! P, }: }6 v
Active NameNode 和 Standby NameNode:两台 NameNode 形成互备,一台处于 Active 状态,为主 NameNode,另外一台处于 Standby 状态,为备 NameNode,只有主 NameNode 才能对外提供读写服务。
! \( {: D V% M, E: O0 M8 I5 L$ v! q
主备切换控制器 ZKFailoverController:ZKFailoverController 作为独立的进程运行,对 NameNode 的主备切换进行总体控制。ZKFailoverController 能及时检测到 NameNode 的健康状况,在主 NameNode 故障时借助 Zookeeper 实现自动的主备选举和切换,当然 NameNode 目前也支持不依赖于 Zookeeper 的手动主备切换。3 U1 J# j2 U" y* s
. g; U2 \5 R6 [& c6 e
Zookeeper 集群:为主备切换控制器提供主备选举支持。
2 e- S) j1 C% g* P
1 P9 K& P `* ^" h共享存储系统:共享存储系统是实现 NameNode 的高可用最为关键的部分,共享存储系统保存了 NameNode 在运行过程中所产生的 HDFS 的元数据。主 NameNode 和 NameNode 通过共享存储系统实现元数据同步。在进行主备切换的时候,新的主 NameNode 在确认元数据完全同步之后才能继续对外提供服务。( }* O4 T- ~ k4 e
7 E$ \& v0 N, A& v& g8 v/ B7 n. M
DataNode 节点:除了通过共享存储系统共享 HDFS 的元数据信息之外,主 NameNode 和备 NameNode 还需要共享 HDFS 的数据块和 DataNode 之间的映射关系。DataNode 会同时向主 NameNode 和备 NameNode 上报数据块的位置信息。. P. g2 Y/ v. y3 d( I+ J7 ?
2 r4 @& m1 c( z3 U
1.2 基于 QJM 的共享存储系统的数据同步机制分析
# j# ?, ~; O6 U# M目前 Hadoop 支持使用 Quorum Journal Manager (QJM) 或 Network File System (NFS) 作为共享的存储系统,这里以 QJM 集群为例进行说明:Active NameNode 首先把 EditLog 提交到 JournalNode 集群,然后 Standby NameNode 再从 JournalNode 集群定时同步 EditLog,当 Active NameNode 宕机后, Standby NameNode 在确认元数据完全同步之后就可以对外提供服务。
" T/ D K2 U, z* N
2 B" I; l/ [$ Z" ~% A& x. F需要说明的是向 JournalNode 集群写入 EditLog 是遵循 “过半写入则成功” 的策略,所以你至少要有 3 个 JournalNode 节点,当然你也可以继续增加节点数量,但是应该保证节点总数是奇数。同时如果有 2N+1 台 JournalNode,那么根据过半写的原则,最多可以容忍有 N 台 JournalNode 节点挂掉。" c9 `% k2 p+ y- V
. q/ r3 p n4 n1 Z
! L( I) l! j% Z, w; J. {+ p
1.3 NameNode 主备切换9 _6 X8 u& I/ v4 f
NameNode 实现主备切换的流程下图所示:6 y1 a& P6 I7 L
- e* [5 z* D U7 h' Z( M6 [
! s0 y# s" D$ u V+ F5 ~
1. HealthMonitor 初始化完成之后会启动内部的线程来定时调用对应 NameNode 的 HAServiceProtocol RPC 接口的方法,对 NameNode 的健康状态进行检测。 2. HealthMonitor 如果检测到 NameNode 的健康状态发生变化,会回调 ZKFailoverController 注册的相应方法进行处理。 3. 如果 ZKFailoverController 判断需要进行主备切换,会首先使用 ActiveStandbyElector 来进行自动的主备选举。 4. ActiveStandbyElector 与 Zookeeper 进行交互完成自动的主备选举。 5. ActiveStandbyElector 在主备选举完成后,会回调 ZKFailoverController 的相应方法来通知当前的 NameNode 成为主 NameNode 或备 NameNode。 6. ZKFailoverController 调用对应 NameNode 的 HAServiceProtocol RPC 接口的方法将 NameNode 转换为 Active 状态或 Standby 状态。8 f. y$ T0 C( {
1.4 YARN高可用% S3 s r) I% Z7 G+ R
YARN ResourceManager 的高可用与 HDFS NameNode 的高可用类似,但是 ResourceManager 不像 NameNode ,没有那么多的元数据信息需要维护,所以它的状态信息可以直接写到 Zookeeper 上,并依赖 Zookeeper 来进行主备选举。6 D* C# r: m' Z! D
; ]$ @1 n: o6 [& X) V3 R7 |9 C
" z/ B7 x) N+ z. z二、集群规划! Y5 U3 B% N, l
按照高可用的设计目标:需要保证至少有两个 NameNode (一主一备) 和 两个 ResourceManager (一主一备) ,同时为满足“过半写入则成功”的原则,需要至少要有 3 个 JournalNode 节点。这里使用三台主机进行搭建,集群规划如下:
D7 A9 V2 k1 ?+ Y( @! a
. @2 p% c q" Q! |/ j- R1 ?: ?% m% ^ F
三、前置条件
5 l p( }5 ^0 N; _( A, G/ ~所有服务器都安装有 JDK,安装步骤可以参见:Linux 下 JDK 的安装;0 D# P5 Z; m) C4 u2 J/ y w
搭建好 ZooKeeper 集群,搭建步骤可以参见:Zookeeper 单机环境和集群环境搭建* x7 h- h9 K4 H1 j: V3 ^
所有服务器之间都配置好 SSH 免密登录。8 u6 Y, w. V+ M7 N; q3 I4 K
四、集群配置1 Q) g% l6 f8 ]# s# `* u, A
4.1 下载并解压
0 _$ {5 p1 g9 Y) M# S下载 Hadoop。这里我下载的是 CDH 版本 Hadoop,下载地址为:http://archive.cloudera.com/cdh5/cdh/5/
- G' \, r" G% G. @
3 N& E. F) @3 [3 F' C, F; k8 x# tar -zvxf hadoop-2.6.0-cdh5.15.2.tar.gz A" q% h$ C t1 @7 A5 P5 Q
4.2 配置环境变量3 N( u! a6 l& i, p- K n
编辑 profile 文件:/ ]9 Z( C$ ~& m" C r. h- Q, y6 P
$ A9 ~# N( A3 C& A
# vim /etc/profile. v0 j v- v! v W# ~/ q
增加如下配置:4 U9 e% M" I" O3 r$ x# t
6 f3 X% G" D! o/ n: B: W. i/ {9 I6 a
export HADOOP_HOME=/usr/app/hadoop-2.6.0-cdh5.15.2
) H8 @* H# h5 L$ rexport PATH=${HADOOP_HOME}/bin:$PATH
0 k# L4 z0 E- o2 i1 L: _( n执行 source 命令,使得配置立即生效:$ \- Q1 ^/ v/ ?# {1 J% r: `
# q$ U* _, X: O$ G+ B) ~6 d
# source /etc/profile& g0 l* z) X n2 U
4.3 修改配置$ {& M$ T, }: U: g6 U0 |/ G( {1 ^
进入 ${HADOOP_HOME}/etc/hadoop 目录下,修改配置文件。各个配置文件内容如下:
; H1 G) A& \$ H8 S3 f, F/ w; A% G% V7 S4 ?5 C; A8 H+ }
1. hadoop-env.sh
) W4 a/ |4 Q, S5 H6 x( ^# 指定JDK的安装位置
; [7 C3 \! ?- T x3 M! eexport JAVA_HOME=/usr/java/jdk1.8.0_201/& o4 `. W5 Z! I
2. core-site.xml6 v. X/ b. S! Y4 w* s( n
<configuration>* q, b3 a& [3 s) c5 I
<property>
5 W; l; c; g0 U! R* m4 s <!-- 指定 namenode 的 hdfs 协议文件系统的通信地址 -->
7 k, a7 v/ p3 b' ^5 l: r3 M% | <name>fs.defaultFS</name> p8 v# k( z, j
<value>hdfs://hadoop001:8020</value>
- Y. O3 M2 c4 N& h' A' b: _ </property>9 i5 O' D- p9 d4 k( Q; C6 A
<property>
; S: L2 G/ H2 } v9 ]1 ]5 g <!-- 指定 hadoop 集群存储临时文件的目录 -->0 f& g+ d; z" u6 v/ B0 q1 j: ^! f
<name>hadoop.tmp.dir</name>
7 k0 D2 E* v( g5 ^5 t <value>/home/hadoop/tmp</value>5 A! ~+ Z) \* n5 S8 h
</property>
; v8 g' O- h: b <property>
3 c2 E; k6 p+ Y# Y <!-- ZooKeeper 集群的地址 -->3 R% R' w4 ?7 ?" j# Q
<name>ha.zookeeper.quorum</name>3 x4 y" `9 _, z' M% J, Y1 r
<value>hadoop001:2181,hadoop002:2181,hadoop003:2181</value> T! ?* @# a* I* W: K3 P
</property>
1 `9 ^+ S: X( z* ^; w( {" N <property>3 ?. @3 ~6 ]* U, i' s
<!-- ZKFC 连接到 ZooKeeper 超时时长 --># X) {) o4 R- ~; R* O% D
<name>ha.zookeeper.session-timeout.ms</name>
, M5 [, H) u7 J1 m& X2 K2 A2 z <value>10000</value>
% z- J- I% s ^ U </property> k3 x' L% E: v( i3 L: W \* k+ f
</configuration>
- p3 \ a6 y2 Q0 d* m' P, g3. hdfs-site.xml- ]) F( Y/ Z- O7 d4 |' q: ]
<configuration>8 c) M) L7 d0 |/ W' V3 {! a, V. w8 e
<property>
( ^2 }3 b& V ~6 t7 Q <!-- 指定 HDFS 副本的数量 -->
* l1 y5 u0 [0 M# y7 M6 D <name>dfs.replication</name>
0 @9 E6 k- `# R0 }# }# x9 _1 A# V <value>3</value>
: O% x& L K; d9 h </property>- j$ `" W ?1 Q4 J: {
<property>( T0 W# _8 N E! Z# [! K; u. K
<!-- namenode 节点数据(即元数据)的存放位置,可以指定多个目录实现容错,多个目录用逗号分隔 -->1 ?( D% E) \0 ~$ d
<name>dfs.namenode.name.dir</name>% p- }) k# n7 r/ v. ~/ w( P) _! Z
<value>/home/hadoop/namenode/data</value>
! |! t7 D+ ^6 X </property>2 U: l" W, R8 Y2 {6 [
<property>* R9 Q& F \8 z6 r" P
<!-- datanode 节点数据(即数据块)的存放位置 -->
7 Y# B& g3 r) a+ j% T9 Z <name>dfs.datanode.data.dir</name>
6 C& ^5 `; H+ G: b5 J, h <value>/home/hadoop/datanode/data</value>
9 R- S, Z# u9 h0 t/ J </property>
) A# f4 V! \, @% d9 [7 X <property>0 S1 r# f |/ n1 _! y4 g7 Z" C
<!-- 集群服务的逻辑名称 -->( w( P7 F6 f: v" [0 G0 Z' _
<name>dfs.nameservices</name>3 u% W7 R. {7 }; O3 j
<value>mycluster</value># ^' H, p) i" ~+ R) y5 s& m1 L% W: a
</property>
* z( e% F, b" D6 T1 G9 q/ Z" O <property>! Z4 m X, ]! s
<!-- NameNode ID 列表-->$ D/ Q" v( P% n
<name>dfs.ha.namenodes.mycluster</name>, r8 b1 ]' x0 t, T8 I( w5 }
<value>nn1,nn2</value>: H% `6 s2 a6 v
</property>
$ W* x4 j) ^1 s3 L- Z <property>
: }* q4 ]9 x* F! U1 r: y2 }: N <!-- nn1 的 RPC 通信地址 -->
K5 Q6 F. O4 |5 k6 b <name>dfs.namenode.rpc-address.mycluster.nn1</name>5 z% ?2 Z# C* k/ F" e3 G$ X
<value>hadoop001:8020</value># f# x" J2 M) [, ], E: x* E g+ @
</property>
. t. I1 U! Q2 g7 m <property>: i: @- P( Q, Q, O) A& D
<!-- nn2 的 RPC 通信地址 -->. I8 W% C7 g, F% A' U$ [
<name>dfs.namenode.rpc-address.mycluster.nn2</name>0 T1 O9 A# Y5 c6 x
<value>hadoop002:8020</value>4 E, M" _: }: _! z
</property>. Y) F, A5 B3 k7 Y- e! l
<property>& m" n4 }* ~- i5 N; y6 o. e
<!-- nn1 的 http 通信地址 -->
8 g6 U w4 \7 J$ K <name>dfs.namenode.http-address.mycluster.nn1</name>8 v3 n2 U6 ^8 w2 I {
<value>hadoop001:50070</value>$ Q/ k$ F7 a5 @8 x. c6 j9 T
</property>( S8 |& l2 J4 ^9 m6 d
<property>
8 j5 e$ E( ?7 D4 A+ l9 H <!-- nn2 的 http 通信地址 -->
5 o, U% Y5 H3 h/ ]7 P( ^' r <name>dfs.namenode.http-address.mycluster.nn2</name>
1 {0 e) @1 V# s9 f6 O' ` <value>hadoop002:50070</value>& v5 {0 R |' x0 ~# l& Z3 G0 G
</property>2 c6 ?) {3 K! m- i& o% G; @! A4 ?$ a
<property>
, k9 N& x! ~" [8 ~* T; k! G) E <!-- NameNode 元数据在 JournalNode 上的共享存储目录 -->
3 e. b t/ S% C2 |7 P# } <name>dfs.namenode.shared.edits.dir</name>9 Q8 x% R7 {8 s- |2 F
<value>qjournal://hadoop001:8485;hadoop002:8485;hadoop003:8485/mycluster</value>
3 }. V: z5 i3 R </property>9 Y7 m7 R- p" _* }* Z. z% k; }
<property>; F; g; _. H% T- M
<!-- Journal Edit Files 的存储目录 -->" a5 c/ h% n' t5 h$ C5 O4 q
<name>dfs.journalnode.edits.dir</name>
8 u, P6 z+ g9 |3 e* l7 Z; E) H <value>/home/hadoop/journalnode/data</value>
. w( m6 a/ s- k1 } </property>
# b2 D2 M9 Q% t* w4 u7 r) S7 W& W( j3 W- S <property>
* O. g. |3 a3 s( x <!-- 配置隔离机制,确保在任何给定时间只有一个 NameNode 处于活动状态 -->$ F; [+ H1 G! i* \
<name>dfs.ha.fencing.methods</name>% g1 @) d8 P+ G9 z+ R- Z
<value>sshfence</value>% V2 P% B* l" Q0 Q# y C3 t" [9 {
</property>
- H8 h5 a1 B8 B; w9 } <property>* X" h3 C& Z* a4 i1 q% k
<!-- 使用 sshfence 机制时需要 ssh 免密登录 -->7 [. C2 @ C+ t
<name>dfs.ha.fencing.ssh.private-key-files</name>
1 L, j# [: R3 J6 w <value>/root/.ssh/id_rsa</value>
4 S. ?, G% r/ O. e- ~2 Z# G. _ </property>
: d; b3 c8 z( t$ q, @) d <property>
9 r9 c( D. n& Z" _ <!-- SSH 超时时间 -->0 q, \% L3 v- p& N1 V
<name>dfs.ha.fencing.ssh.connect-timeout</name>2 l+ P/ Y, R o, W, D+ c
<value>30000</value>
/ B3 m# y# N$ L6 c6 ` </property>! Q' @5 ~& A/ Z% P, `+ M+ ]
<property>; E* D; Z! o& ^4 ~! s n/ x
<!-- 访问代理类,用于确定当前处于 Active 状态的 NameNode -->6 S8 K1 ~, Z9 R. Q
<name>dfs.client.failover.proxy.provider.mycluster</name>
7 l; C: @5 R N <value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
0 ?* g/ r: c% `. r7 P0 c </property>
m; n% o% g( d8 F' O <property>( s/ C( n5 X' k( Z
<!-- 开启故障自动转移 -->
2 K8 q- Y t* M6 h0 G& ~ <name>dfs.ha.automatic-failover.enabled</name>
- D! j {! K- R; J <value>true</value>
: C# h; `! b L! O: f; J </property>
* L. k) |- I# A* T4 u: O; u</configuration>
/ l+ `8 j- U$ {: g7 I9 H# M4. yarn-site.xml
. I( \& g, Y7 P<configuration>
0 j+ p: ] @$ j) Z3 D0 ^ <property>* k+ J# C( h4 A6 h- S
<!--配置 NodeManager 上运行的附属服务。需要配置成 mapreduce_shuffle 后才可以在 Yarn 上运行 MapReduce 程序。-->- _4 B( R5 ^* `1 Z* ]
<name>yarn.nodemanager.aux-services</name>
- j$ v( s. |: m5 H7 v <value>mapreduce_shuffle</value>
8 c+ K' s5 U' I6 y# b </property>
1 i5 N$ k2 U# j. p$ m' b3 r2 Z2 k <property>
' \5 p2 H6 g1 c- z <!-- 是否启用日志聚合 (可选) -->
; H; Y: X9 z7 S, @( F7 k* D; ] h <name>yarn.log-aggregation-enable</name>
6 V! C/ f4 A- ~$ J7 F F! f# D8 I <value>true</value>
4 A( \1 ~/ H8 p+ D( ` </property> w% [ ~4 B. M3 Q. Y' ^) q" [
<property>
9 L. n' i% b0 X8 T) l7 A <!-- 聚合日志的保存时间 (可选) -->
- p3 Z/ a+ \6 t! B6 b" Q4 @ <name>yarn.log-aggregation.retain-seconds</name>( ^ H Q2 Z; }! n8 ~$ y" Q
<value>86400</value>! O. v( W! y# r+ M3 D
</property>! |6 J) e* g+ j
<property>8 P* K z1 k; x8 O; t' l
<!-- 启用 RM HA -->
. A+ s% Y1 d& E7 Y1 [) \ <name>yarn.resourcemanager.ha.enabled</name>, [, P$ [5 A# P. {0 z
<value>true</value>, k; W; C/ d: q0 i
</property>
, A# P, X( z- N M% U6 z/ d; N <property>
: H, d" Z$ M( u/ f5 j) Y <!-- RM 集群标识 -->7 l+ U' w" p+ |4 s6 p r c4 v
<name>yarn.resourcemanager.cluster-id</name>
( v' j$ L& X; m* v3 [ g7 z <value>my-yarn-cluster</value>
9 Z. R! X' X4 ^( W, g1 C </property>
0 \$ e$ ?' x1 V! j4 R4 q <property>' H: y$ ]+ u, x
<!-- RM 的逻辑 ID 列表 -->9 Z: ^% b+ ~( a$ t `
<name>yarn.resourcemanager.ha.rm-ids</name>: U; p" ~' S8 [ U
<value>rm1,rm2</value>
0 q0 h% \8 B1 b; O( s7 O </property>
* A1 t( A" L) C" j& p <property>
9 j, x3 |1 D+ A* Z* t6 X- O2 o7 ? <!-- RM1 的服务地址 -->4 L5 C- l2 I6 d8 N9 e# Z' ]+ R5 q
<name>yarn.resourcemanager.hostname.rm1</name>' |: U7 k6 z3 j( f# W. B" ]3 `6 [
<value>hadoop002</value>1 d0 \( ?; Y7 Z0 ~# J
</property>3 p1 x: u# `$ b* I; `$ P2 R
<property>; E8 G. m, i' B/ t9 ^6 Z* n
<!-- RM2 的服务地址 -->0 W8 m: Y% o" U0 U- @: O
<name>yarn.resourcemanager.hostname.rm2</name>
$ _8 i; J6 I5 j+ V; i <value>hadoop003</value>- n# t* s/ a( ]# y$ w0 k
</property>
+ P5 M$ ?+ F5 @! Q <property>. y- E- Y4 C' | d2 e+ R
<!-- RM1 Web 应用程序的地址 -->
+ R9 \2 O% [' m- b, S <name>yarn.resourcemanager.webapp.address.rm1</name>3 i0 I2 I/ l; X* [% _( s# Z. N
<value>hadoop002:8088</value>
9 ]: W) W% p- B8 {7 G </property>
2 ^) r/ V5 b3 R% M <property>/ C& }& `4 ~ \3 `& @
<!-- RM2 Web 应用程序的地址 -->
- ?& ~! R. L/ I" D. d <name>yarn.resourcemanager.webapp.address.rm2</name>( F1 I1 i* W* u! h' @6 T$ @
<value>hadoop003:8088</value>
0 Q* ~! X* ^) i% s0 @ </property>
W& \8 ]: i0 m- K <property>
8 R* b) z4 v8 G) t3 V <!-- ZooKeeper 集群的地址 -->% {& E( F, \; m; T
<name>yarn.resourcemanager.zk-address</name>5 T s- X4 E* i/ m+ }& |" w
<value>hadoop001:2181,hadoop002:2181,hadoop003:2181</value># l. J; T1 ~* L% T I1 b6 {" ~
</property>0 R) J- w5 S* H0 H8 C+ U
<property>9 B( S: J2 { w6 P) _3 G* l9 z
<!-- 启用自动恢复 -->
: y0 h! T8 d# P5 A <name>yarn.resourcemanager.recovery.enabled</name>( Y1 b1 G" @: G4 V, J0 k0 n5 c
<value>true</value>
: D, T" ?' q7 r( m </property>( U" o4 j' L. S* g6 b% D7 f
<property>
* Q3 v4 ?" y% c+ b <!-- 用于进行持久化存储的类 -->: c! v* f. [) X* J8 M4 m
<name>yarn.resourcemanager.store.class</name>
! ~! Q8 c0 j( r! O- h% K$ h- I3 E <value>org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore</value>
4 a. u: L9 t$ ]. O# y6 G </property>
0 d0 x- I+ k3 p; J</configuration>7 k" E1 U0 e5 y! x7 w5 r9 w& w+ y
5. mapred-site.xml. B# T5 q" X7 ^; R- ?6 q
<configuration>7 L# ]3 r, G8 ^/ A0 {9 z9 q
<property>: `4 s0 D% e" ?' H
<!--指定 mapreduce 作业运行在 yarn 上-->
$ L! o5 w: k; C* j$ C2 z- E% ~ <name>mapreduce.framework.name</name># P+ g1 B2 F- ]3 l
<value>yarn</value>1 G- m: k: a' j& I' N7 X6 t
</property>
) j; N( P# }9 [! D* f</configuration>
% m5 H6 T+ l- V6 y' Z- s5. slaves, p; p- W% y1 ~0 e7 |
配置所有从属节点的主机名或 IP 地址,每行一个。所有从属节点上的 DataNode 服务和 NodeManager 服务都会被启动。
7 |2 v: \5 ^0 t' v& |0 P* f; g- a9 l, H# G4 O1 t5 w- V" [7 d
hadoop001: ~. Y0 h' y0 `. J% P
hadoop002- a5 t( N+ |2 x5 l, }& k
hadoop003
3 A" B' F2 f3 c6 T$ ^4.4 分发程序: @, \1 \; e5 s9 L3 S+ E
将 Hadoop 安装包分发到其他两台服务器,分发后建议在这两台服务器上也配置一下 Hadoop 的环境变量。" a7 o+ w) m* I, L8 s
. v. Y' K6 z, d1 T* f+ X# 将安装包分发到hadoop002
) _( R% R4 S; W% a3 k$ Gscp -r /usr/app/hadoop-2.6.0-cdh5.15.2/ hadoop002:/usr/app/2 K7 x- s6 f5 f. [7 x4 a. U, A$ U6 \
# 将安装包分发到hadoop003
# n0 {5 @0 }6 T9 p" V w% Kscp -r /usr/app/hadoop-2.6.0-cdh5.15.2/ hadoop003:/usr/app/
8 K1 P- h6 v5 \1 ~5 L( J: u五、启动集群6 x; ~4 @% ^% G% j! X( s
5.1 启动ZooKeeper4 |" a8 O$ F r& N, l( m: ]
分别到三台服务器上启动 ZooKeeper 服务:
5 A$ W) l( N7 W. K( T
% J! U. I9 I9 k9 F5 C zkServer.sh start
* p" h8 H" f# T; }- `5.2 启动Journalnode2 h* W( k4 X/ B- L3 k) `
分别到三台服务器的的 ${HADOOP_HOME}/sbin 目录下,启动 journalnode 进程:* r+ R/ b, Q, |$ ~2 E |9 h
: o" q, a: A! _9 t' S; S9 D
hadoop-daemon.sh start journalnode
5 \% o) t6 G" f/ u$ l/ m5 g# `5.3 初始化NameNode: K" V V8 _: E" u! b t; }
在 hadop001 上执行 NameNode 初始化命令:" }. `' @0 u2 t$ ?3 \
6 Y# v9 Z+ i7 [; Z6 xhdfs namenode -format
3 r: S6 p# D3 e4 @/ A: B0 ], n执行初始化命令后,需要将 NameNode 元数据目录的内容,复制到其他未格式化的 NameNode 上。元数据存储目录就是我们在 hdfs-site.xml 中使用 dfs.namenode.name.dir 属性指定的目录。这里我们需要将其复制到 hadoop002 上:
" r0 {! I+ M# ]. @" _/ [: M1 H# s5 s( J5 p& X8 N: ?2 V, ?
scp -r /home/hadoop/namenode/data hadoop002:/home/hadoop/namenode/
0 X/ d: J. y6 d6 B+ x5.4 初始化HA状态8 D+ n8 z- D9 q/ f2 s2 h
在任意一台 NameNode 上使用以下命令来初始化 ZooKeeper 中的 HA 状态:$ j& ~& F' V4 F
2 A5 h, L- j$ W. i* ehdfs zkfc -formatZK
4 R# K$ M5 X$ W" f. f/ b) R5.5 启动HDFS
: ~, R; p7 B$ K. W8 _( U2 Y; s进入到 hadoop001 的 ${HADOOP_HOME}/sbin 目录下,启动 HDFS。此时 hadoop001 和 hadoop002 上的 NameNode 服务,和三台服务器上的 DataNode 服务都会被启动:: W0 [0 Q2 M# a/ m; e4 D
0 H' W3 @) p: I& X0 a& S8 G( P' Nstart-dfs.sh8 i, P- N: A Y5 {1 X8 F
5.6 启动YARN
7 {, D" o! M3 @" [/ n0 N m' P进入到 hadoop002 的 ${HADOOP_HOME}/sbin 目录下,启动 YARN。此时 hadoop002 上的 ResourceManager 服务,和三台服务器上的 NodeManager 服务都会被启动:7 i% g5 ]# U* L! i; A: Y6 g
8 s) w8 s3 D6 q7 U
start-yarn.sh
- N" x d5 f, `9 C" Q需要注意的是,这个时候 hadoop003 上的 ResourceManager 服务通常是没有启动的,需要手动启动:6 g/ v$ U; c& R9 g! p
2 h, H+ I) e7 B) X, |) @
yarn-daemon.sh start resourcemanager! M. E: ]( Y4 o5 |% E# a
六、查看集群
9 g, b# [: Q/ Q7 [5 ?3 W; L8 r) q- V6.1 查看进程4 w6 T! G/ d. L$ w3 k9 R6 M& q4 {3 @
成功启动后,每台服务器上的进程应该如下:
5 m$ S- S7 \2 u) D- e2 E1 W
. N" g# u: G. L[root@hadoop001 sbin]# jps
6 I3 I- v9 O7 m4512 DFSZKFailoverController% R% m9 T# W: s4 b8 s( ~7 x
3714 JournalNode
' |$ N5 Y: [6 \2 X4114 NameNode. y4 b6 ^/ c2 L+ ^; i
3668 QuorumPeerMain
! ?$ R/ T8 N- y$ {5012 DataNode0 A& o0 Y4 D' H7 D! a; {
4639 NodeManager8 Z1 _4 ]% S( l0 [) ~+ _ x$ @
& [% z3 H5 K* U! Z5 o$ G6 q" f
0 R+ i, f1 h. ~% c. \5 A) S0 Y[root@hadoop002 sbin]# jps! x! H3 p4 N* g- w$ C" `# k
4499 ResourceManager
9 M& d. c, u. e, u" e6 ^4595 NodeManager
, w0 ~$ d/ w) M, R% b+ y3465 QuorumPeerMain
8 k: Q% ~( [9 T3705 NameNode
+ n# h' ^* A* N( Y* m2 L3915 DFSZKFailoverController
6 C6 y% G6 e1 L; o( \6 n5211 DataNode$ `: q- J: r) }! s3 a
3533 JournalNode& O2 {. h" p; W0 V
- R" F* r9 Q* Z( ]2 o* H
4 P; r% E0 o( A+ I5 s8 U
[root@hadoop003 sbin]# jps% Y P# u0 k) \$ n
3491 JournalNode
- h$ |6 b- `, {/ G; x( l3 d3942 NodeManager& @: B5 g3 k/ _8 |
4102 ResourceManager
; D: |* a& c4 Q4201 DataNode; X- ~; J* w- U% m) q
3435 QuorumPeerMain
4 Y( r5 k* T$ e P6.2 查看Web UI
/ q* n* p0 o6 d% x3 V7 SHDFS 和 YARN 的端口号分别为 50070 和 8080,界面应该如下:) S0 y" c6 G1 U/ h. D6 m
, M6 v, C8 _* d0 u7 O. D此时 hadoop001 上的 NameNode 处于可用状态:" O) P: i/ @$ V5 i. Y I7 g, i) V
9 ]! `/ c& Z" D+ u' `' [
; @ V @# ]1 e5 Y4 s2 f
而 hadoop002 上的 `NameNode` 则处于备用状态:
L7 f0 Q( w V; q+ V- B$ N4 ]/ U( N4 J
2 g- ^8 Y5 o/ W6 M- z, Q3 S0 O/ U7 Ohadoop002 上的 ResourceManager 处于可用状态:# W5 J7 x& C8 F% R
8 g4 x& |1 N6 D2 E
; ?# k2 d* o+ N1 ^) ?
- ~8 [4 r7 F4 c7 l! k! T6 f9 O) b+ ]6 z) x2 U8 y
hadoop003 上的 ResourceManager 则处于备用状态:
' C1 X' p f3 V f; u* @; V( c W* k. p
4 s% b+ I0 _9 p/ B8 ?0 c
Q" N/ c6 H2 z$ v" }( i$ t" y4 k) O3 ^1 ?' z5 E
同时界面上也有 Journal Manager 的相关信息:
7 r7 S/ H5 O1 L3 I9 p m- g
) ], O, S/ ~) B, V; X: x
1 |% b+ L9 |5 T- B* L& E' e& s8 N& W$ G$ D, o; i
## 七、集群的二次启动
/ U7 i/ c8 K+ w$ C上面的集群初次启动涉及到一些必要初始化操作,所以过程略显繁琐。但是集群一旦搭建好后,想要再次启用它是比较方便的,步骤如下(首选需要确保 ZooKeeper 集群已经启动):
, _' Q6 A7 L$ D1 R' P# _( `
: C/ l4 w& @. {7 W) ~4 ?/ ?: M在 hadoop001 启动 HDFS,此时会启动所有与 HDFS 高可用相关的服务,包括 NameNode,DataNode 和 JournalNode:# U- a" ?& c$ @( p0 z5 e: X z
3 g3 m! {2 e# qstart-dfs.sh3 m& p( b. @ J8 s9 T- [7 M" m% o
在 hadoop002 启动 YARN:1 f0 Q0 K" K. l- k# t
/ z# \- ~3 Q& j. i1 L! S; mstart-yarn.sh- X! N% R3 h- E. \
这个时候 hadoop003 上的 ResourceManager 服务通常还是没有启动的,需要手动启动:' I- m+ K4 X7 k
! C8 q* b% B: r5 N4 v
yarn-daemon.sh start resourcemanager
- {, k0 M" |$ J- M5 g9 v" R" | F. u1 Q/ E
|
|