简介
在工作中,生产环境和测试环境各搭建了一套Hadoop HA集群且运行稳定,以下为测试环境的详细部署流程以及在使用过程中踩过的坑和解决方案。
集群配置
服务器:五台
处理器:Intel(R) Core(TM) i5-6500 CPU @ 3.20GHz
内存:16G
磁盘:1T
Hadoop版本:2.7.2
Zookeeper版本:3.4.9
Hbase版本:1.2.4
注意事项
在服务器上编辑配置文件时,切记要用vi或vim编辑,不能直接用文本编辑器对配置文件进行修改,否则可能会出现配置文件编码被修改而导致乱码的问题。
集群基础环境配置
1、关闭防火墙
systemctl stop firewalld //关闭防火墙
systemctl disable firewalld //禁止开机启动
2、配置ntp服务时钟同步
- 在各个节点上安装ntp:
yum -y install ntp
- 在ntp 主节点上修改配置:
vim /etc/ntp.conf
server 127.127.1.0
fudge 127.127.1.0 stratum 10
restrict 90.0.25.0 mask 255.255.255.0 nomodify notrap
server cn.pool.ntp.org iburst
server 216.229.0.179 iburst
server time.nist.gov iburst
如果是在局域网中可以将以下的几行注释掉:
#server 0.centos.pool.ntp.org iburst
#server 1.centos.pool.ntp.org iburst
#server 2.centos.pool.ntp.org iburst
#server 3.centos.pool.ntp.org iburst
- 配置ntp客户端,使其与主节点时间同步,在所有客户端执行:
vim /etc/ntp.conf
server 90.0.25.1
- 在所有节点上执行:
systemctl start ntpd //启动ntp
systemctl enable ntpd //开机启动
- 检查ntp同步情况,在client上执行如下语句会看到同步的主机IP,执行命令:
ntpq -p
这里有两点需要注意:
- 由于centos7系统上安装了一个与NTP相冲突的工具:chrony。使用命令:systemctl is-enabled chronyd来查看,得到的结果是chrony已经被设置为enabled。这就导致利用systemctl enable ntpd设置NTP开机启动后,重启服务器后,NTP并没有启动。解决办法:
systemctl disable chronyd
- 如果输入
ntpq -p
后出现异常:localhost: timed out, nothing received
。
· 原因:服务器开启了ipv6,默认走ipv6。
· 解决办法是:关闭ipv6后重启网络。具体步骤:
1. 在/etc/sysctl.conf
配置文件中添加:
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.eth1.disable_ipv6 = 1
net.ipv6.conf.eth0.disable_ipv6 = 1
2. 保存退出后,执行:systemctl restart network
3、SSH免密登录
- 在各台服务器上执行:
ssh-keygen -t rsa
,在/root下会生成.ssh目录 - 在每台服务器上将id_rsa.pub拷贝到其他服务器(包括本机)上,并更名为authorized_keys,进到/root/.ssh目录,并执行命令:
cat id_rsa.pub | ssh 90.0.25.1 'cat >> /root/.ssh/authorized_keys'
- 更改.ssh权限:
chmod 700 .ssh
- 更改authorized_keys权限:
chmod 640 authorized_keys
- 重启sshd并设置开机启动
systemctl restart sshd
systemctl enable sshd
- 在每台服务器上通过
ssh 90.0.25.1
测试成功
4、配置hosts文件:vim /etc/hosts
90.0.25.1 hb1
90.0.25.2 hb2
90.0.25.3 hb3
90.0.25.4 hb4
90.0.25.5 hb5
5、安装jdk
- 首先,将从官网下载的jdk文件(tar.gz)放到/home/下的新建的java文件夹中,利用tar命令解压:
tar –zxvf jdk-8u111-linux-x64.tar.gz
- 配置Java环境变量:
vim /etc/profile
JAVA_HOME=/home/jdk1.8.0_111
JRE_HOME=$JAVA_HOME/jre
PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin
CLASSPATH=:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib/dt.jar
export JAVA_HOME JRE_HOME PATH CLASSPATH
- 运行
source /etc/profile
使配置生效,并运行java –version
进行检验
Zookeeper安装
安装配置zookeeper,虽然hbase有自带的zookeeper,但没有必要让hbase和zookeeper耦合在一起,所以选择分开部署
- 将zookeeper-3.4.9.tar.gz放到/home目录下,如下命令解压:
tar –zxvf zookeeper-3.4.9.tar.gz
- 配置zookeeper环境变量:
vim /etc/profile
export ZOOKEEPER_HOME=/home/zookeeper-3.4.9
export PATH=$ZOOKEEPER_HOME/bin:$PATH
使配置生效:source /etc/profile
- 在zookeeper-3.4.9目录下新建data目录:
mkdir data
- 在data中新建myid文件:
vim myid
,在其中填入数字1
- 由于conf目录下没有zoo.cfg文件,所以复制zoo_sample.cfg成zoo.cfg:
cp zoo_sample.cfg zoo.cfg
- 编辑zoo.cfg文件,添加如下信息,并在zookeeper-3.4.9目录下新建目录logs:
mkdir logs
dataDir=/home/zookeeper-3.4.9/data
dataLogDir=/home/zookeeper-3.4.9/logs
server.1=hb1:2888:3888
server.2=hb2:2888:3888
server.3=hb3:2888:3888
server.4=hb4:2888:3888
server.5=hb5:2888:3888
- 拷贝zookeeper-3.4.9目录到其他节点的/home目录,并分别更改myid的值为
2~5
:
scp -r zookeeper-3.4.9 hb2:/home
scp -r zookeeper-3.4.9 hb3:/home
scp -r zookeeper-3.4.9 hb4:/home
scp -r zookeeper-3.4.9 hb5:/home
- 因为zookeeper负责协调hbase之间的通信,所以需要在每个节点上分别启动zookeeper服务:
cd /home/zookeeper-3.4.9/bin
./zkServer.sh start
Hadoop HA配置
1、将hadoop-2.7.2.tar.gz放在/home目录下,解压:
tar –zxvf hadoop-2.7.2.tar.gz
2、配置hadoop环境变量:vim /etc/profile
#Hadoop环境变量
export HADOOP_HOME=/home/hadoop-2.7.2-ha/hadoop-2.7.2
export PATH=$PATH:$HADOOP_HOME/bin
使修改生效
source /etc/profile
3、进入/home/hadoop-2.7.2-ha/hadoop-2.7.2/etc/hadoop
目录下修改配置文件
(1) core-site.xml配置:
<configuration>
<!--指定默认hdfs集群服务名是哪个 -->
<property>
<name>fs.defaultFS</name>
<value>hdfs://ns1</value>
</property>
<!-- 指定hadoop临时目录 -->
<property>
<name>hadoop.tmp.dir</name>
<value>/home/hadoop-2.7.2-ha/hadoop-2.7.2/tmp</value>
</property>
<!-- 指定zookeeper地址 -->
<property>
<name>ha.zookeeper.quorum</name>
<value>hb1:2181,hb2:2181,hb3:2181,hb4:2181,hb5:2181</value>
</property>
<property>
<name>ipc.client.connect.max.retries</name>
<value>20</value>
<description>
Indicates the number of retries a clientwill make to establisha server connection.
</description>
</property>
<property>
<name>ipc.client.connect.retry.interval</name>
<value>5000</value>
<description>
Indicates the number of milliseconds aclient will wait for before retrying to establish a server connection.
</description>
</property>
<property>
<name>io.file.buffer.size</name>
<value>262144</value>
</property>
</configuration>
(2) 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>hb1:9000</value>
</property>
<!-- nn1的http通信地址 -->
<property>
<name>dfs.namenode.http-address.ns1.nn1</name>
<value>hb1:50070</value>
</property>
<!-- nn2的RPC通信地址 -->
<property>
<name>dfs.namenode.rpc-address.ns1.nn2</name>
<value>hb2:9000</value>
</property>
<!-- nn2的http通信地址 -->
<property>
<name>dfs.namenode.http-address.ns1.nn2</name>
<value>hb2:50070</value>
</property>
<!-- 指定NameNode的元数据在JournalNode上的存放位置 -->
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://hb1:8485;hb2:8485;hb3:8485;hb4:8485;hb5:8485/ns1</value>
</property>
<!-- 指定JournalNode在本地磁盘存放数据的位置 -->
<property>
<name>dfs.journalnode.edits.dir</name>
<value>/home/hadoop-2.7.2-ha/hadoop-2.7.2/journaldata</value>
</property>
<property>
<name>dfs.namenode.name.dir</name>
<value>/home/hadoop-2.7.2-ha/hadoop-2.7.2/name</value>
</property>
<property>
<name>dfs.datanode.data.dir</name>
<value>/home/hadoop-2.7.2-ha/hadoop-2.7.2/data</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>
<!-- 增加NameNode和DataNode处理线程数 -->
<property>
<name>dfs.namenode.handler.count</name>
<value>50</value>
</property>
<property>
<name>dfs.datanode.handler.count</name>
<value>8</value>
</property>
<property>
<name>dfs.datanode.max.transfer.threads</name>
<value>8192</value>
</property>
<!-- 开启短路读,DataNode传递文件描述符而不是路径 -->
<property>
<name>dfs.client.read.shortcircuit</name>
<value>true</value>
</property>
<property>
<name>dfs.domain.socket.path</name>
<value>/var/lib/hadoop-hdfs/dn.socket</value>
</property>
<property>
<name>dfs.replication</name>
<value>2</value>
</property>
</configuration>
(3) mapred-site.xml配置:
<configuration>
<!-- 指定mr框架为yarn方式 -->
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
<!-- mr转化历史任务的rpc通信地址-->
<property>
<name>mapreduce.jobhistory.address</name>
<value>hb2:10020</value>
</property>
<!-- mr转化历史任务的http通信地址-->
<property>
<name>mapreduce.jobhistory.webapp.address</name>
<value>hb2:19888</value>
</property>
<!-- 会在hdfs的根目录下面创建一个history的文件夹,存放历史任务的相关运行情况-->
<property>
<name>yarn.app.mapreduce.am.staging-dir</name>
<value>/history</value>
</property>
<!-- map和reduce的日志级别-->
<property>
<name>mapreduce.map.log.level</name>
<value>INFO</value>
</property>
<property>
<name>mapreduce.reduce.log.level</name>
<value>INFO</value>
</property>
</configuration>
(4) yarn-site.xml配置:
<configuration>
<!-- Site specific YARN configuration properties -->
<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>hb1</value>
</property>
<property>
<name>yarn.resourcemanager.hostname.rm2</name>
<value>hb2</value>
</property>
<!-- 指定zk集群地址 -->
<property>
<name>yarn.resourcemanager.zk-address</name>
<value>hb1:2181,hb2:2181,hb3:2181,hb4:2181,hb5:2181</value>
</property>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
</configuration>
(5) hadoop-env.sh配置
export JAVA_HOME=/home/jdk1.8.0_111
export HADOOP_HEAPSIZE=6144
export HADOOP_NAMENODE_INIT_HEAPSIZE=2048
export HADOOP_PID_DIR=/home/hadoop-2.7.2-ha/hadoop-2.7.2/pids
export HADOOP_SECURE_DN_PID_DIR=/home/hadoop-2.7.2-ha/hadoop-2.7.2/pids
(6) mapred-env.sh配置
export HADOOP_MAPRED_PID_DIR=/home/hadoop-2.7.2-ha/hadoop-2.7.2/pids
(7) yarn-env.sh配置
export JAVA_HOME=/home/jdk1.8.0_111
export YARN_PID_DIR=/home/hadoop-2.7.2-ha/hadoop-2.7.2/pids
4、slaves配置
hb1
hb2
hb3
hb4
hb5
5、在hadoop-2.7.2下创建目录:mkdir tmp journaldata name data logs pids
,由于配置了短路读,需要在/var/lib目录下新建:hadoop-dfs目录。
6、将hadoop-2.7.2-ha目录拷贝到其他节点上
scp -r hadoop-2.7.2-ha hb2:/home/
7、初始化集群和启动
(1)分别启动各个JournalNode
./hadoop-daemon.sh start journalnode
(2)在其中一个NameNode节点中初始化NameNode,这里选择master1上的NameNode
hdfs namenode -format
(3)启动第2步初始化好的NameNode服务
./hadoop-daemon.sh start namenode
(4)在master2服务器中运行下面命令来同步master1上的NameNode的元数据
hdfs namenode -bootstrapStandby
(5)在其中一个NameNode节点中初始化ZKFC的状态,这里选择master1上的NameNode
hdfs zkfc -formatZK
(6)启动Hadoop的HA集群
./start-dfs.sh
8、查看两个NameNode的状态:一个active,一个standby
hdfs haadmin -getServiceState nn1
hdfs haadmin -getServiceState nn2
9、通过master:50070
访问Hadoop Web UI
Hbase HA集群配置
进入hbase配置文件目录/home/hbase-1.2.4-ha/hbase-1.2.4/conf
1、hbase-env.sh配置
export JAVA_HOME=/home/jdk1.8.0_111
export HADOOP_HOME=/home/hadoop-2.7.2-ha/hadoop-2.7.2
export HBASE_PID_DIR=/home/hbase-1.2.4-ha/hbase-1.2.4/pids
export HBASE_LOG_DIR=/home/hbase-1.2.4-ha/hbase-1.2.4/logs
export HBASE_MANAGES_ZK=false
因为是jdk1.8,所以注释掉下面两行,并配置regionserver内存
export HBASE_OPTS="-Xmn2G -Xss256k -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m -XX:ParallelGCThreads=24 -XX:+UseCompressedOops -XX:GCTimeRatio=19 -XX:SoftRefLRUPolicyMSPerMB=0 -XX:SurvivorRatio=2 -XX:MaxTenuringThreshold=1 -XX:+UseFastAccessorMethods -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=70 -XX:+CMSClassUnloadingEnabled -XX:CMSMaxAbortablePrecleanTime=300 -XX:+CMSScavengeBeforeRemark"
export HBASE_REGIONSERVER_OPTS="-Xms8G -Xmx8G $HBASE_OPTS"
export HBASE_MASTER_OPTS="-Xms3G -Xmx3G $HBASE_OPTS"
2、hbase-site.xml配置
<configuration>
<property>
<name>hbase.rootdir</name>
<value>hdfs://ns1/hbase</value>
</property>
<property>
<name>hbase.cluster.distributed</name>
<value>true</value>
</property>
<property>
<name>hbase.master</name>
<value>60000</value>
</property>
<property>
<name>hbase.tmp.dir</name>
<value>/home/hbase-1.2.4-ha/hbase-1.2.4/tmp</value>
</property>
<property>
<name>hbase.zookeeper.quorum</name>
<value>hb1,hb2,hb3,hb4,hb5</value>
</property>
<property>
<name>hbase.zookeeper.property.dataDir</name>
<value>/home/zookeeper-3.4.9/data</value>
</property>
<property>
<name>hbase.zookeeper.property.clientPort</name>
<value>2181</value>
</property>
<property>
<name>zookeeper.session.timeout</name>
<value>120000</value>
</property>
<property>
<name>hbase.regionserver.restart.on.zk.expire</name>
<value>true</value>
</property>
<!--默认: 10 :RegionServers受理的RPC Server实例数量。对于Master来说,这个属性是Master受理的handler数量.-->
<property>
<name>hbase.regionserver.handler.count</name>
<value>100</value>
</property>
<!--默认: 1 :当调用Scanner的next方法,而值又不在缓存里的时候,从服务端一次获取的行数。越大的值意味着Scanner会快一些,
但是会占用更多的内存。 -->
<property>
<name>hbase.client.scanner.caching</name>
<value>100</value>
</property>
<!--默认: false :体验特性:启用memStore分配本地缓冲区。这个特性是为了防止在大量写负载的时候堆的碎片过多。
这可以减少GC操作的频率。说明:减少因内存碎片导致的Full GC,提高整体性能。-->
<property>
<name>hbase.hregion.memstore.mslab.enabled</name>
<value>true</value>
</property>
<!--默认: 10 :客户端最多重试次数,可以设为11。 -->
<property>
<name>hbase.client.retries.number</name>
<value>11</value>
</property>
<!--默认: false :建议设为true,关闭消息缓冲。 -->
<property>
<name>hbase.ipc.client.tcpnodelay</name>
<value>true</value>
</property>
<!--默认: 60000 :表示HBase客户端发起一次scan操作的rpc调用至得到响应之间总的超时时间。-->
<property>
<name>hbase.client.scanner.timeout.period</name>
<value>120000</value>
</property>
<!--默认: 60000 :该参数表示一次RPC请求的超时时间。如果某次RPC时间超过该值,客户端就会主动关闭socket。 -->
<property>
<name>hbase.rpc.timeout</name>
<value>180000</value>
</property>
<property>
<name>hbase.hregion.memstore.block.multiplier</name>
<value>8</value>
</property>
<property>
<name>hbase.hstore.blockingStoreFiles</name>
<value>30</value>
</property>
<property>
<name>hbase.client.write.buffer</name>
<value>5242880</value>
</property>
</configuration>
3、配置hbase环境变量:vim /etc/profile
export HBASE_HOME=/home/hbase-1.2.4-ha/hbase-1.2.4
export PATH=$PATH:$HBASE_HOME/bin
使配置生效
source /etc/profile
4、在conf目录下新建backup-masters,配置备用节点:vim backup-masters
hb2
5、配置regionservers
hb1
hb2
hb3
hb4
hb5
6、创建目录:mkdir pids tmp logs
7、删除hbase的slf4j-log4j12-1.7.5.jar,解决hbase和hadoop的LSF4J包冲突
mv slf4j-log4j12-1.7.5.jar slf4j-log4j12-1.7.5.jar.bk
8、拷贝hadoop的core-site.xml和hdfs-site.xml拷贝到hbase的conf下
scp core-site.xml hb1:/home/hbase-1.2.4-ha/hbase-1.2.4/conf/
scp hdfs-site.xml hb1:/home/hbase-1.2.4-ha/hbase-1.2.4/conf/
9、将hbase-1.2.4-ha目录拷贝到其他节点上
scp -r hbase-1.2.4-ha/ hb2:/home
10、在主节点上运行hbase:./start-hbase.sh start
11、在浏览器中输入master:16010
进入Hbase Web UI