HDFS 完全分布式搭建
分布式规划:
node1 | node2 | node3 | node4 |
NameNode | SecondaryNameNode | ||
DataNode-1 | DataNode-2 | DataNode-3 |
搭建步骤
1、免秘钥设置
0、免密钥设置
a、首先在四台服务器上都要执行:ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa
b、在node1上将node1 的公钥拷贝到authorized_keys中:
cat ~/.ssh/id_dsa.pub >> ~/.ssh/authorized_keys
将该文件拷贝给node2:scp ~/.ssh/authorized_keys node2:/root/.ssh/
c、在node2中将node2的公钥追加到authorized_keys中:
cat ~/.ssh/id_dsa.pub >> ~/.ssh/authorized_keys
将该文件拷贝给node3:scp ~/.ssh/authorized_keys node3:/root/.ssh/
d、在node3中将node3的公钥追加到authorized_keys中:
cat ~/.ssh/id_dsa.pub >> ~/.ssh/authorized_keys
将该文件拷贝给node4:scp ~/.ssh/authorized_keys node4:/root/.ssh/
e、在node4中将node4的公钥追加到authorized_keys中:
cat ~/.ssh/id_dsa.pub >> ~/.ssh/authorized_keys
将该文件拷贝给node1、node2、node3:scp ~/.ssh/authorized_keys node[123]:/root/.ssh//
2、通过scp拷贝
首先将node1中的hadoop-2.6.5/share/doc删除
再删除$HADOOP_HOME/logs/*
将/opt/hadoop-2.6.5 scp到node2、node3、node4的对应目录中
scp -r hadoop-2.6.5/ node2:`pwd`
scp -r hadoop-2.6.5/ node3:`pwd`
scp -r hadoop-2.6.5/ node4:`pwd`
将/root/下的jdk.rpm scp到node2、node3、node4的对应目录中
scp jdk-8u191-linux-x64.rpm node2:`pwd`
scp jdk-8u191-linux-x64.rpm node3:`pwd`
scp jdk-8u191-linux-x64.rpm node4:`pwd`
3、配置
在node2、node3、node4上安装jdk并配置profile文件
rpm -ivh jdk-8u191-linux-x64.rpm
/etc/profile
将node1的/etc/profile拷贝到node2、node3、node4上并执行. /etc/profile
修改node1:/opt/hadoop-2.6.5/etc/hadoop/中的slaves
指定datanode的位置
node2
node3
node4
修改node1:/opt/hadoop-2.6.5/etc/hadoop/中的hdfs-site.xml
指定SNN的位置
<property>
<name>dfs.namenode.secondary.http-address</name>
<value>node2:50090</value>
</property>
<property>
<name>dfs.replication</name>
<value>2</value>
</property>
修改node1:/opt/hadoop-2.6.5/etc/hadoop/中的core-site.xml
<property>
<name>hadoop.tmp.dir</name>
<value>/var/bjsxt/hadoop/full</value>
</property>
将这四个文件core-site.xml/hdfs-site.xml/slaves/hadoop-env.sh在四台服务器之间共享
scp /opt/hadoop-2.6.5/etc/hadoop/* node[234]:/opt/hadoop-2.6.5/etc/hadoop
4、格式化并启动
格式化
在node1上执行:hdfs namenode -format
启动即可(该命令在四台服务器上哪一台执行都可以)
start-dfs.sh
5、停止
stop-dfs.sh
Hadoop 3.X 新特性(了解)
1、将默认的最低jdk从7升级到8
2、纠删码可以将3倍副本占据的空间压缩到1.5倍,并保持3倍副本的容错。由于在读取数据的时候需要进行额外的计算,用于存储使用不频繁的数据
3、通过扩展YARN的资源类型,支持CPU和内存之外的其他资源,如GPU、FPGA、软件许可证、本地存储等。
4、重写了hadoop中的shell脚本,修复了很多长期存在的bug并添加了新特性。有一些改进兼容老版本,有一些不兼容。
5、对map阶段的输出收集器增加了本地实现,对于洗牌密集型工作,可以提高30%以上的性能。
6、hadoop2.x中NameNode的HA包含一个active的NameNode和一个Standby的NameNode。解决了系统中NameNode的单点故障问题。在hadoop3中允许多个standby状态的NameNode以达到更高级别容错的目的。
7、以前,多个Hadoop服务的默认端口位于Linux临时端口范围(32768-61000)。 这意味着在启动时,由于与另一个应用程序的冲突,服务有时无法绑定到端口。这些冲突的端口已移出临时范围,影响NameNode,Secondary NameNode,DataNode和KMS。
8、Hadoop现在支持与Microsoft Azure Data Lake和Aliyun对象存储系统的集成,作为替代Hadoop兼容的文件系统。
9、单个DataNode管理多个磁盘。 在正常写入操作期间,磁盘将被均匀填充。 但是,添加或替换磁盘可能会导致DataNode内的严重数据偏斜。 旧的HDFS平衡器不能处理,旧的HDFS平衡器处理DN之间而非内部的数据偏斜。
10、对Hadoop守护进程以及MapReduce任务的堆管理做了一系列更改。现在可以根据主机的内存大小进行自动调整,并且不推荐使用HADOOP_HEAPSIZE变量。简化了map和reduce任务堆空间的配置,在任务中不再需要以java选项的方式进行指定
11、为Amazon S3存储的S3A客户端添加了一个可选功能:能够将DynamoDB表用于文件和目录元数据的快速一致存储。
12、HDFS基于路由器的联邦添加了一个RPC路由层,该层提供多个HDFS命名空间的联合视图。 这与现有的ViewFs和HDFS联合功能类似,不同之处在于安装表由路由层而不是客户端在服务器端进行管理, 简化了对现有HDFS客户端对联邦群集的访问。
Hadoop Federation(了解)联邦
NameNode需要多少内存
问题:NameNode需要多大的内存?
业界看法:1GB内存放1,000,000block元数据。
200个节点的集群中每个节点有24TB存储空间,block大小为128MB,block复制因子为3,能存储大概2000,000个block(或更多):200×24,000,000MB/(128MB×3)。此时,NameNode内存大概需要12000MB。
一万个节点的集群需要多大的NameNode的内存?
HDFS组成
1、Namespace
a) 包括目录,文件和block块。
b) 支持所有跟文件系统命名空间相关的操作
如:创建、删除、修改和列出文件及目录。
2、Block存储服务包含两部分:
a) NameNode中的block块管理
i. 通过心跳机制和注册机制提供了对DataNode集群的管理。
ii. 处理block块报告,管理block块的位置。
iii. 提供跟block块相关的操作,如:创建、修改、删除和查询block块的位置。
iv. 管理block副本如何放置,当副本数少于指定值之后增加副本,当副本数多余指定值之后删除副本。
b) 存储:
在DataNode本地文件系统中存储block块,并提供读/写访问。
1、NameNode节点之间是相互独立的联邦的关系,即它们之间不需要协调服务。
2、DataNode向集群中所有的NameNode注册,发送心跳和block块列表报告,处理来自NameNode的指令。
3、用户可以使用ViewFs创建个性化的命名空间视图,ViewFs类似于在Unix/Linux系统中的客户端挂载表。
VERSION
namespaceID 用于标记namenode的ID
blockpoolID 用于标记block存储池子的ID
clusterID 集群的ID
hadopp-env.sh
配置JAVA_HOME
core-site.xml配置:
<configuration> <property> <name>fs.defaultFS</name> <value>viewfs://ClusterX</value> </property> <property> <name>fs.viewfs.mounttable.ClusterX.link./data</name> <value>hdfs://node1:8020/data</value> </property> <property> <name>fs.viewfs.mounttable.ClusterX.link./project</name> <value>hdfs://node1:8020/project</value> </property> <property> <name>fs.viewfs.mounttable.ClusterX.link./user</name> <value>hdfs://node2:8020/user</value> </property> <property> <name>fs.viewfs.mounttable.ClusterX.link./tmp</name> <value>hdfs://node2:8020/tmp</value> </property> <!-- <property> <name>fs.viewfs.mounttable.ClusterX.linkFallback</name> <value>hdfs://node2:8020/home</value> </property> --> <property> <name>hadoop.tmp.dir</name> <value>/var/bjsxt/hadoop/federation</value> </property> </configuration> |
hdfs-site.xml
<configuration> <property> <name>dfs.replication</name> <value>2</value> </property> <property> <name>dfs.blocksize</name> <value>1048576</value> </property> <property> <name>dfs.nameservices</name> <value>ns1,ns2</value> </property> <property> <name>dfs.namenode.rpc-address.ns1</name> <value>node1:8020</value> </property> <property> <name>dfs.namenode.http-address.ns1</name> <value>node1:50070</value> </property> <property> <name>dfs.namenode.secondary.http-address.ns1</name> <value>node3:50090</value> </property> <property> <name>dfs.namenode.rpc-address.ns2</name> <value>node2:8020</value> </property> <property> <name>dfs.namenode.http-address.ns2</name> <value>node2:50070</value> </property> <property> <name>dfs.namenode.secondary.http-address.ns2</name> <value>node4:50090</value> </property> </configuration> |
slaves
node2 node3 node4 |
格式化node1
$HADOOP_PREFIX_HOME/bin/hdfs namenode -format -clusterId myviewfs
格式化node2
$HADOOP_PREFIX_HOME/bin/hdfs namenode -format -clusterId myviewfs
在格式化node1和node2上的namenode时候,需要指定clusterId,并且两个格式化的时候这个clusterId要一致,两个namenode具有相同的clusterId,它们在一个集群中,它们是联邦的关系。
start-dfs.sh
stop-dfs.sh
优点
- 通过多个namenode/namespace把元数据的存储和管理分散到多个节点中,使得namenode/namespace可以通过增加机器来进行水平扩展。
- 能把单个namenode的负载分散到多个节点中,在HDFS数据规模较大的时候不会也降低HDFS的性能。
- 可以通过多个namespace来隔离不同类型的应用,把不同类型应用的HDFS元数据的存储和管理分派到不同的namenode中。
Hadoop HA
HDFS 2.x
解决HDFS 1.0中单点故障和内存受限问题,联邦 HA
HDFS2.x中Federation和HA分离,HA只能有两个NameNode
解决单点故障
HDFS HA:通过主备NameNode解决
如果主NameNode发生故障,则切换到备NameNode上。
解决内存受限问题
HDFS Federation(联邦);水平扩展,支持多个NameNode;
(1)所有NameNode共享所有DataNode存储资源
(2)每个NameNode分管一部分目录;
手动HA
fsimage+edits log需要
由StandbyNameNode做合并工作
fsimage推送的时机可以通过参数来调整: dfs.namenode.checkpoint.period 1小时 dfs.namenode.checkpoint.txns 100 0000事务 dfs.namenode.checkpoint.check.period 3s dfs.namenode.num.checkpoints.retained dfs.ha.tail-edits.period |
- 一个NameNode进程处于Active状态,另1个NameNode进程处于Standby状态。Active的NameNode负责处理客户端的请求。
- Active的NN修改了元数据之后,会在JNs的半数以上的节点上记录这个日志。Standby状态的NameNode会监视任何对JNs上edit log的更改。一旦edits log出现更改,Standby的NN就会根据edits log更改自己记录的元数据。
- 当发生故障转移时,Standby主机会确保已经读取了JNs上所有的更改来同步它本身记录的元数据,然后由Standby状态切换为Active状态。
- 为了确保在发生故障转移操作时拥有相同的数据块位置信息,DNs向所有NN发送数据块位置信息和心跳数据。
- JNs只允许一台NameNode向JNs写edits log数据,这样就能保证不会发生“脑裂”。
自动HA
总结
主备NameNode
解决单点故障(属性,位置)à元数据
主NameNode对外提供服务,备NameNode同步主NameNode元数据,以待切换
所有DataNode同时向两个NameNode汇报数据块信息(位置)
JNN:集群(属性)同步edits log
standby:备,完成了edits.log文件的合并产生新的image,推送回ANN
两种切换选择
手动切换:通过命令实现主备之间的切换,可以用HDFS升级等场合
自动切换:基于Zookeeper实现
基于Zookeeper自动切换方案
ZooKeeper Failover Controller:监控NameNode健康状态,
并向Zookeeper注册NameNode
NameNode挂掉后,ZKFC为NameNode竞争锁,获得ZKFC 锁的NameNode变为active
zookeeper的分布式锁,keepalived
Hadoop HA 集群搭建
规划
搭建步骤
如何让ssh不提示fingerprint信息,然后输入yes或者no
/etc/ssh/ssh_config(客户端配置文件) 区别于sshd_config(服务端配置文件)
1、zookeeper集群搭建
a) 将zookeeper.tar.gz上传到node2、node3、node4
b) 解压到/opt
tar -zxf zookeeper-3.4.6.tar.gz -C /opt
c) 配置环境变量:
export ZOOKEEPER_PREFIX=/opt/zookeeper-3.4.6
export PATH=$PATH:$ZOOKEEPER_PREFIX/bin
然后. /etc/profile让配置生效
d) 到$ZOOKEEPER_PREFIX/conf下
复制zoo_sample.cfg为zoo.cfg
cp zoo_sample.cfg zoo.cfg
e) 编辑zoo.cfg
添加如下行:
server.1=node2:2881:3881
server.2=node3:2881:3881
server.3=node4:2881:3881
修改
dataDir=/var/bjsxt/zookeeper/data
f) 创建/var/bjsxt/zookeeper/data目录,并在该目录下放一个文件:myid
在myid中写下当前zookeeper的编号
mkdir -p /var/bjsxt/zookeeper/data
echo 3 > /var/bjsxt/zookeeper/data/myid
2181 用户客户端连接zk集群的端口
zkCli.sh 客户端启动脚本
zkServer.sh 服务端启动脚本
mysql -uroot -p123456
mysqld 服务端
g) 将/opt/zookeeper-3.4.6通过网络拷贝到node2、node3上
scp -r zookeeper-3.4.6/ node2:/opt
scp -r zookeeper-3.4.6/ node3:/opt
h) 在node2和node3上分别创建/var/bjsxt/zookeeper/data目录,
并在该目录下放一个文件:myid
node2:
mkdir -p /var/bjsxt/zookeeper/data
echo 1 > /var/bjsxt/zookeeper/data/myid
node3:
mkdir -p /var/bjsxt/zookeeper/data
echo 2 > /var/bjsxt/zookeeper/data/myid
i) 启动zookeeper
zkServer.sh start 启动zk
zkServer.sh stop 停止zk
zkServer.sh status 查看zk状态
zkServer.sh start|stop|status
j) 关闭zookeeper
zkServer.sh stop
l) 连接zookeeper
zkCli.sh node2、node3、node4都可以
m) 退出zkCli.sh命令
quit
- hadoop配置
一律在node1上操作,做完后scp到node2、node3、node4
hadoop-env.sh配置JDK
core-site.xml
<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://mycluster</value> hdfs://node1:9000
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>/var/bjsxt/hadoop/ha</value>
</property>
<!-- 指定每个zookeeper服务器的位置和客户端端口号 -->
<property>
<name>ha.zookeeper.quorum</name>
<value>node2:2181,node3:2181,node4:2181</value>
</property>
</configuration>
hdfs-site.xml
<configuration>
<!-- 指定block默认副本个数 -->
<property>
<name>dfs.replication</name>
<value>2</value>
</property>
<!-- 用于解析fs.defaultFS中hdfs://mycluster中的mycluster地址 -->
<property>
<name>dfs.nameservices</name>
<value>mycluster</value>
</property>
<!-- mycluster下面由两个namenode服务支撑 -->
<property>
<name>dfs.ha.namenodes.mycluster</name>
<value>nn1,nn2</value>
</property>
<!--指定nn1的地址和端口号,发布的是一个hdfs://的服务-->
<property>
<name>dfs.namenode.rpc-address.mycluster.nn1</name>
<value>node1:8020</value>
</property>
<property>
<name>dfs.namenode.rpc-address.mycluster.nn2</name>
<value>node2:8020</value>
</property>
<!--指定三台journal服务器的地址-->
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://node1:8485;node2:8485;node3:8485/mycluster</value>
</property>
<!-- 指定客户端查找active的namenode的策略:
会给所有namenode发请求,以决定哪个是active的 -->
<property>
<name>dfs.client.failover.proxy.provider.mycluster</name>
<value>org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider</value>
</property>
<!--在发生故障切换的时候,ssh到对方服务器,将namenode进程kill掉 kill -9 55767-->
<property>
<name>dfs.ha.fencing.methods</name>
<value>sshfence</value>
</property>
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/root/.ssh/id_dsa</value>
</property>
<!-- 指定journalnode在哪个目录存放edits log文件 -->
<property>
<name>dfs.journalnode.edits.dir</name>
<value>/var/bjsxt/hadoop/ha/jnn</value>
</property>
<!--启用自动故障切换-->
<property>
<name>dfs.ha.automatic-failover.enabled</name>
<value>true</value>
</property>
</configuration>
3、启动ha的hadoop
先同步配置文件到node2、node3、node4
scp -r $HADOOP_HOME/etc/hadoop/* node[234]:/opt/hadoop-2.6.5/etc/hadoop/
0)启动zookeeper集群
a) 在node1\node2\node3上启动三台journalnode
hadoop-daemon.sh start journalnode
b) 任意选择node1,格式化HDFS
hdfs namenode -format
格式化后,启动namenode进程
hadoop-daemon.sh start namenode
c) 在另一台node2上同步元数据
hdfs namenode -bootstrapStandby
d) 初始化zookeeper上的内容 一定是在namenode节点上。
hdfs zkfc -formatZK
e) 启动hadoop集群,可在node1到node4这四台服务器上任意位置执行
start-dfs.sh
stop-dfs.sh停止hadoop服务。
如果格式化之后,启动:
启动三台zk
随意节点:start-dfs.sh
hadoop-daemon.sh stop namenode
hadoop-daemon.sh stop zkfc
4、zookeeper操作
在node2或者node3或者node4上运行
zkCli.sh
ls /hadoop-ha/mycluster 查看临时文件
get /hadoop-ha/mycluster/ActiveStandbyElectorLock 查看临时文件的内容
退出zkCli.sh
quit
hdfs dfs -mkdir /user
hdfs dfs -mkdir /user/root
/user/root是用户root家目录
5、停止集群:
首先
stop-dfs.sh
其次,停止zookeeper集群
node2、node3、node4上执行:
zkServer.sh stop
(扩展)
用法: haadmin [-transitionToActive <serviceId>] [-transitionToStandby <serviceId>] [-failover [--forcefence] [--forceactive] <serviceId> <serviceId>] [-getServiceState <serviceId>] [-getAllServiceState] [-checkHealth <serviceId>] [-help <command>] |
可以“hdfs haadmin -help <command>”查看帮助
transitionToActive和transitionToStandby - 将NameNode切换到Active或Standby状态
这两个命令不进行围栏操作,最好少用。最好使用“hdfs haadmin -failover”。
failover – 在指定的两个NameNode之间触发一个故障切换
如果第一个NameNode处于Standby状态,这个命令简单地让第二个NameNode处于Active状态,不报错。如果第一个处于Active状态,则尝试将它置于Standby状态。如果失败了,则fencing method会执行dfs.ha.fencing.methods列表中的下一个命令,直到有一个执行成功。在这之后才会将第二个NameNode转换为Active状态。如果没有fencing method成功,第二个NameNode不会转换为Active状态,同时报错。
getServiceState – 返回指定的NameNode处于Active或Standby状态
连接给定的NameNode并获取它的状态,返回“standby”或“active”到标准输出。这个命令用于定时器作业或监控脚本等需要根据NameNode状态执行不同操作的场合。
getAllServiceState – 返回所有NameNode的状态
连接到所有配置的NameNode,在标准输出为每个NameNode打印“standby”或“active”。
checkHealth – 检查给定NameNode的健康状态
连接到指定的NameNode并检查其健康状态。NameNode会进行自我诊断,包括检查内部服务是否正常运行。如果NameNode运行正常,则返回0,非0表示运行不正常。一般监控的时候使用。
需要注意的是,该命令还没有实现,当前如果不是NameNode宕机,只返回成功。
java客户端操作HDFS
1、windows上部署hadoop包
部署包 win版本
源码包 zip包
lib整合
$HADOOP_PREFIX/share/hadoop/{common,hdfs,mapreduce,yarn,tools}/{lib,.}*.jar 121个jar包
将widows版本hadoop/bin/hadoop.dll 放到 c:/windows/system32下
2、windows环境变量配置
hadoop的bin和sbin目录放PATH中+HADOOP_HOME+HADOOP_USER_NAME=root
3、eclipse插件
安装插件
配置
重启电脑!!!!!!!加载hadoop.dll
创建java project
添加依赖jar
创建源码包
拷贝linux集群中的core-site.xml和hdfs-site.xml到项目的源码包下
程序可以做到本地化读取
input.seek(param);
HDFS本地化读取是一个优势