大数据平台生产环境部署指南
总结一下在生产环境部署Hadoop+Spark+HBase+Hue等产品遇到的问题、提高效率的方法和相关的配置。
集群规划
假设现在生产环境的信息如下:
- 服务器数量:6
- 操作系统:Centos7
- Master节点数:2
- Zookeeper节点数:3
- Slave节点数:4
划分各个机器的角色如下:
主机名 | 角色 | 运行进程 |
---|---|---|
hadoop1 | Master | Namenode |
hadoop2 | Master_backup | Namenode |
hadoop3 | Slave、Yarn | Datanode、ResourceManager、NodeManager |
hadoop4 | Slave、Zookeeper | Datanode、NodeManager、QuorumPeerMain |
hadoop5 | Slave、Zookeeper | Datanode、NodeManager、QuorumPeerMain |
hadoop6 | Slave、Zookeeper | Datanode、NodeManager、QuorumPeerMain |
一些注意事项
尽量使用非root用户
这是为了避免出现一些安全问题,毕竟是生产环境,即使不是也养成习惯。
各个机器的用户名保持一致,需要超级用户权限时加入sudoers里面即可。
数据存放的目录和配置文件分离
一般我们在自己的虚拟机上搭建集群的时候这个可以忽略不计,但是生产机器上需要注意一下。
由于生产机一般配置都很高,几十T的硬盘很常见,但是这些硬盘都是mount上去的,如果我们按照虚拟机上的操作方式来部署的话,集群的所有数据还是会在/目录下,而这个目录肯定是不会大到哪里去,
有可能就出现跑着跑着抛磁盘空间爆满的异常,但是回头一查,90%的资源没有利用到。
所以,将集群存放数据的目录统一配置到空间大的盘上去,而配置文件保持不变,即配置文件和数据目录的分离,避免互相影响,另外在使用rsync进行集群文件同步的时候也比较方便。
规划集群部署的目录
部署之前提前将各个目录分配好,针对性的干活~
这里将Hadoop、HBase、Spark等软件安装在:/usr/local/bigdata目录下
数据存放目录配置在:/data2/bigdata下
这里的/data2为mount上去的硬盘
集群部署
这里使用的各个软件版本号为:
- Zookeeper3.4.5
- Hadoop2.2.0
- HBase0.98
- Spark1.4.1
- Hive1.2.1
- Hue3.7.0
必要准备
1、修改主机名和IP的映射关系
编辑/etc/hosts文件,确保各个机器主机名和IP地址的映射关系
2、防火墙设置
生产环境上防火墙不可能关闭,所以查考下方的端口表让网络管理员开通吧~
P.S. 当然如果你不care的话直接关防火墙很省事,不过不推荐。。
3、JDK的配置
先检查一下生产机上有没有预装了OpenJDK,有的话卸了吧~
rpm -qa | grep OracleJDK
把出现的所有包都
rpm -e --nodeps
卸载掉。
重新安装OracleJDK,版本没有太高要求,这里使用1.7。
到Oracle官网下载对应版本的JDK之后在安装在/usr/local下面,在~/.bash_profile中配置好环境变量,输入java -version出现对应信息即可。
4、ssh免密码登陆
这个步骤如果机器比较多的话就会很烦了,现在各个机器上生成ssh密钥:
ssh-keygen -t rsa
一路回车保存默认目录:~/.ssh
通过ssh将各个机器的公钥复制到hadoop1的~/.ssh/authorized_keys中,然后发放出去:
#本机的公钥
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
#各个节点的公钥
ssh hadoopN cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
#复制完之后将authorized_keys发放给各个节点
scp ~/.ssh/authorized_keys hadoopN:~/.ssh/authorized_keys
测试:
ssh date hadoop2
如果出现权限问题尝试使用:
chmod -R 700 ~/.ssh
Zookeeper
将zk上传到/usr/local/bigdata中解压缩
进入conf目录,修改zoo.cfg:
cp zoo_sample.cfg zoo.cfg
vim zoo.cfg
#修改:
dataDir=/data2/bigdata/zookeeper/tmp
ticktickTime=20000
#在最后添加:
server.1=hadoop4:2888:3888
server.2=hadoop5:2888:3888
server.3=hadoop6:2888:3888
ticktickTime默认为2000,2-20倍的minSessionTimeout与maxSessionTimeout
注: tickTime 心跳基本时间单位毫秒,ZK基本上所有的时间都是这个时间的整数倍。
zk的详细配置见:
zookeeper配置文件详解
创建配置的dataDir:
mkdir /data2/bigdata/zookeeper/tmp
touch /data2/bigdata/zookeeper/tmp/myid
echo 1 > /data2/bigdata/zookeeper/tmp/myid
配置结束,将Zookeeper传到hadoop5、6上,创建dataDir并修改myid为2、3
启动
在hadoop4、5、6上进入zk的bin目录:
./zkServer.sh start
./zkServer.sh status
正确的结果应该是一个leader,两个follower
Hadoop
上传hadoop包到/usr/local/bigdata并解压缩,进入etc/hadoop目录
hadoop-env.sh
考虑到数据和程序的分离,决定将那些会不断增长的文件都配置到/data2/bigdata/hadoop下,包括:日志文件,pid目录,journal目录。
所以在此文件中需要配置:
- JAVA_HOME
- HADOOP_PID_DIR
- HADOOP_LOG_DIR
- HADOOP_CLASSPATH
HADOOP_CLASSPATH根据需要配置其他jar包的路径
yarn-en.sh
- YARN_LOG_DIR
- YARN_PID_DIR
其他五个核心文件内容如下:
core-site.xml:
<configuration>
<!--hdfs通讯地址-->
<property>
<name>fs.defaultFS</name>
<value>hdfs://ns1</value>
</property>
<!--数据存放目录-->
<property>
<name>hadoop.tmp.dir</name>
<value>/data2/bigdata/hadoop/tmp</value>
</property>
<!--zk地址-->
<property>
<name>ha.zookeeper.quorum</name>
<value>hadoop4:2181,hadoop5:2181,hadoop6:2181</value>
</property>
<!--hdfs回收站文件保留时间-->
<property>
<name>fs.trash.interval</name>
<value>4320</value>
</property>
<!--hue相关配置-->
<property>
<name>hadoop.proxyuser.hue.hosts</name>
<value>*</value>
</property>
<property>
<name>hadoop.proxyuser.hue.groups</name>
<value>*</value>
</property>
<!--Zookeeper连接超时的设置-->
<property>
<name>ha.zookeeper.session-timeout.ms</name>
<value>6000000</value>
</property>
<property>
<name>ha.failover-controller.cli-check.rpc-timeout.ms</name>
<value>6000000</value>
</property>
<property>
<name>ipc.client.connect.timeout</name>
<value>6000000</value>
</property>
</configuration>
hdfs-site.xml:
<configuration>
<!--hdfs元数据存放路径-->
<property>
<name>dfs.name.dir</name>
<value>/data2/hadoop/hdfs/name</value>
</property>
<!--hdfs数据目录,可配置多个-->
<property>
<name>dfs.data.dir</name>
<value>/data2/hadoop/hdfs/data</value>
</property>
<!--节点上剩下多少空间时不再写入,配置为6G,手动调整-->
<property>
<name>dfs.datanode.reserved</name>
<value>6000000000</value>
</property>
<!--节点访问控制-->
<property>
<name>dfs.hosts</name>
<value>/usr/local/bigdata/hadoop/etc/hadoop/datanode-allow.list</value>
</property>
<property>
<name>dfs.hosts.exclude</name>
<value>/usr/local/bigdata/hadoop/etc/hadoop/datanode-deny.list</value>
</property>
<!--Namenode服务名-->
<property>
<name>dfs.nameservices</name>
<value>ns1</value>
</property>
<!--Namenode配置-->
<property>
<name>dfs.ha.namenodes.ns1</name>
<value>nn1,nn2</value>
</property>
<property>
<name>dfs.namenode.rpc-address.ns1.nn1</name>
<value>hadoop1:9000</value>
</property>
<property>
<name>dfs.namenode.http-address.ns1.nn1</name>
<value>hadoop1:50070</value>
</property>
<property>
<name>dfs.namenode.rpc-address.ns1.nn2</name>
<value>hadoop2:9000</value>
</property>
<property>
<name>dfs.namenode.http-address.ns1.nn2</name>
<value>hadoop2:50070</value>
</property>
<!--journalnode配置-->
<property>
<name>dfs.namenode.shared.edits.dir</name>
<value>qjournal://hadoop4:8485;hadoop5:8485;hadoop6:8485/ns1</value>
</property>
<property>
<name>dfs.journalnode.edits.dir</name>
<value>/data2/hadoop/journal</value>
</property>
<!--其他-->
<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>
<property>
<name>dfs.ha.fencing.ssh.private-key-files</name>
<value>/home/hadoop/.ssh/id_rsa</value>
</property>
<property>
<name>dfs.ha.fencing.ssh.connect-timeout</name>
<value>30000</value>
</property>
<!--为hue开启webhdfs-->
<property>
<name>dfs.webhdfs.enabled</name>
<value>true</value>
</property>
<property>
<name>dfs.permissions</name>
<value>false</value>
</property>
<!--连接超时的一些设置-->
<property>
<name>dfs.qjournal.start-segment.timeout.ms</name>
<value>600000000</value>
</property>
<property>
<name>dfs.qjournal.prepare-recovery.timeout.ms</name>
<value>600000000</value>
</property>
<property>
<name>dfs.qjournal.accept-recovery.timeout.ms</name>
<value>600000000</value>
</property>
<property>
<name>dfs.qjournal.prepare-recovery.timeout.ms</name>
<value>600000000</value>
</property>
<property>
<name>dfs.qjournal.accept-recovery.timeout.ms</name>
<value>600000000</value>
</property>
<property>
<name>dfs.qjournal.finalize-segment.timeout.ms</name>
<value>600000000</value>
</property>
<property>
<name>dfs.qjournal.select-input-streams.timeout.ms</name>
<value>600000000</value>
</property>
<property>
<name>dfs.qjournal.get-journal-state.timeout.ms</name>
<value>600000000</value>
</property>
<property>
<name>dfs.qjournal.new-epoch.timeout.ms</name>
<value>600000000</value>
</property>
<property>
<name>dfs.qjournal.write-txns.timeout.ms</name>
<value>600000000</value>
</property>
<property>
<name>ha.zookeeper.session-timeout.ms</name>
<value>6000000</value>
</property>
</configuration>
dfs.name.dir和dfs.data.dir分别是存储hdfs元数据信息和数据的目录,如果没有配置则默认存储到hadoop.tmp.dir中。
其中dfs.name.dir可以配置为多个目录,相当于备份,以免出现元数据被破坏的情况。
mapred-site.xml:
<configuration>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
<property>
<name>mapreduce.jobhistory.webapp.address</name>
<value>hadoop1:19888</value>
</property>
</configuration>
yarn-site.xml:
<configuration>
<property>
<name>yarn.resourcemanager.hostname</name>
<value>hadoop1</value>
</property>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
<property>
<name>yarn.log-aggregation-enable</name>
<value>true</value>
</property>
<property>
<name>yarn.nodemanager.remote-app-log-dir</name>
<value>/data2/bigdata/hadoop/logs/yarn</value>
</property>
<property>
<name>yarn.log-aggregation.retain-seconds</name>
<value>259200</value>
</property>
<property>
<name>yarn.log-aggregation.retain-check-interval-seconds</name>
<value>3600</value>
</property>
<property>
<name>yarn.nodemanager.webapp.address</name>
<value>0.0.0.0:8042</value>
</property>
<property>
<name>yarn.nodemanager.log-dirs</name>
<value>/data2/bigdata/hadoop/logs/yarn/containers</value>
</property>
</configuration>
修改slaves文件将各个子节点主机名加入
将配置好的hadoop通过scp拷贝到其他节点
第一次格式化HDFS
启动journalnode(在hadoop1上启动所有journalnode,注意:是调用的hadoop-daemons.sh这个脚本,注意是复数s的那个脚本)
进入hadoop/sbin目录:
./hadoop-daemons.sh start journalnode
运行jps命令检验,hadoop4、hadoop5、hadoop6上多了JournalNode进程
格式化HDFS(在bin目录下),在hadoop1上执行命令:
./hdfs namenode -format
格式化后会在根据core-site.xml中的hadoop.tmp.dir配置生成个文件,将对应tmp目录拷贝到hadoop2对应的目录下(hadoop初次格式化之后要将两个nn节点的tmp/dfs/name文件夹同步)。
格式化ZK(在hadoop1上执行即可,在bin目录下)
./hdfs zkfc -formatZK
之后启动hdfs和yarn,并用jps命令检查
HBase
解压之后配置hbase集群,要修改3个文件
注意:要把hadoop的hdfs-site.xml和core-site.xml 放到hbase/conf下,让hbase节点知道hdfs的映射关系,也可以在hbase-site.xml中配置
hbase-env.sh
- JAVA_HOME
- HBASE_MANAGES_ZK设置为false,使用外部的zk
- HBASE_CLASSPATH设置为hadoop配置文件的目录
- HBASE_PID_DIR
- HBASE_LOG_DIR
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.zookeeper.quorum</name>
<value>hadoop4:2181,hadoop5:2181,hadoop16:2181</value>
</property>
<property>
<name>hbase.master</name>
<value>hadoop11</value>
</property>
<property>
<name>zookeeper.session.timeout</name>
<value>6000000</value>
</property>
</configuration>
在regionservers中添加各个子节点的主机名并把zoo.cfg 拷贝到hbase的conf目录下
使用scp将配置好的hbase拷贝到集群的各个节点上,在hadoop1上通过hbase/bin/start-hbase.sh来启动
Spark
安装scala
将scala包解压到/usr/local下,配置环境变量即可
上传spark包到/usr/local/bigdata下并解压缩
进入conf目录,修改slaves,将各个子节点的主机名加入
spark-env.sh
- SPARK_MASTER_IP:master主机名
- SPARK_WORKER_MEMORY:子节点可用内存
- JAVA_HOME:java home路径
- SCALA_HOME:scala home路径
- SPARK_HOME:spark home路径
- HADOOP_CONF_DIR:hadoop配置文件路径
- SPARK_LIBRARY_PATH:spark lib目录
- SCALA_LIBRARY_PATH:值同上
- SPARK_WORKER_CORES:子节点的可用核心数
- SPARK_WORKER_INSTANCES:子节点worker进程数
- SPARK_MASTER_PORT:主节点开放端口
- SPARK_CLASSPATH:其他需要添加的jar包路径
- SPARK_DAEMON_JAVA_OPTS:”-Dspark.storage.blockManagerHeartBeatMs=6000000”
- SPARK_LOG_DIR:log目录
- SpARK_PID_DIR:pid目录
spark配置详见:
Spark 配置
将hadoop1上配置好的spark和scala通过scp复制到其他各个节点上(注意其他节点上的~/.bash_profle文件也要配置好)
通过spark/sbin/start-all.sh启动
Hue
安装hue要求有maven环境和其他环境,具体见:
- ant
- asciidoc
- cyrus-sasl-devel
- cyrus-sasl-gssapi
- gcc
- gcc-c++
- krb5-devel
- libtidy (for unit tests only)
- libxml2-devel
- libxslt-devel
- make
- mvn (from maven package or maven3 tarball)
- mysql
- mysql-devel
- openldap-devel
- python-devel
- sqlite-devel
- openssl-devel (for version 7+)
上传hue的安装包到/usr/local/bigdata,解压缩并进入目录,执行:
make apps
进行编译,期间会下载各种依赖包,如果默认中央仓库的地址链接太慢可以换成CSDN的中央仓库:
修改maven/conf/settings.xml,在中添加:
<profile>
<id>jdk-1.4</id>
<activation>
<jdk>1.4</jdk>
</activation>
<repositories>
<repository>
<id>nexus</id>
<name>local private nexus</name>
<url>http://maven.oschina.net/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>nexus</id>
<name>local private nexus</name>
<url>http://maven.oschina.net/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</profile>
如果还是出现相关依赖的错误,可以尝试修改hue/maven/pom.xml,将
2.3.0-mr1-cdh5.0.1-SNAPSHOT
编译成功之后进入hue/desktop/conf修改pseudo-distributed.ini配置文件:
# web监听地址
http_host=0.0.0.0
# web监听端口
http_port=8000
# 时区
time_zone=Asia/Shanghai
# 在linux上运行hue的用户
server_user=hue
# 在linux上运行hue的用户组
server_group=hue
# hue默认用户
default_user=hue
# hdfs配置的用户
default_hdfs_superuser=hadoop
# hadoop->hdfs_clusters->default的选项下
# hdfs访问地址
fs_defaultfs=hdfs://ns1
# hdfs webapi地址
webhdfs_url=http://hadoop1:50070/webhdfs/v1
# hdfs是否使用Kerberos安全机制
security_enabled=false
# hadoop配置文件目录
umask=022
hadoop_conf_dir=/usr/local/bigdata/hadoop/etc/hadoop
# hadoop->yarn_clusters->default的选项下
# yarn主节点地址
resourcemanager_host=hadoop1
# yarn ipc监听端口
resourcemanager_port=8032
# 是否可以在集群上提交作业
submit_to=True
# ResourceManager webapi地址
resourcemanager_api_url=http://hadoop1:8088
# 代理服务地址
proxy_api_url=http://hadoop1:8088
# hadoop->mapred_clusters->default的选项下
# jobtracker的主机
jobtracker_host=hadoop1
# beeswax选项下(hive)
# hive运行的节点
hive_server_host=zx-hadoop1
# hive server端口
hive_server_port=10000
# hive配置文件路径
hive_conf_dir=/usr/local/bigdata/hive/conf
# 连接超时时间等
server_conn_timeout=120
browse_partitioned_table_limit=250
download_row_limit=1000000
# zookeeper->clusters->default选项下
# zk地址
host_ports=hadoop4:2181,hadoop5:2181,hadoop6:2181
# spark选项下
# spark jobserver地址
server_url=http://hadoop1:8090/
这里hue只配置了hadoop,hive(连接到spark需要部署spark jobserver)其余组件需要时进行配置即可。
进入hive目录执行启动metastrore和hiveserver2服务(如果已经启动就不需要了):
bin/hive --service metastore
bin/hiveserver2
进入hue,执行:
build/env/bin/supervisor
进入hadoop:8000即可访问到hue的界面
相关的异常信息
1、hue界面没有读取hdfs的权限
错误现象:使用任何用户启动hue进程之后始终无法访问hdfs文件系统。
异常提示:WebHdfsException: SecurityException: Failed to obtain user group information:
pache.hadoop.security.authorize.AuthorizationException: User: hue is not allowed to impersonate admin (error 401)
原因分析:用户权限问题。
解决方案:需要在hue的配置文件中设置以hue用户启动web进程,并且该用户需要在hadoop用户组中。
2、hue界面无法获取hdfs信息
错误现象:使用任何用户启动hue进程之后始终无法访问hdfs文件系统。
异常提示:not able to access the filesystem.
原因分析:hue通过hadoop的web api进行通讯,无法获取文件系统可能是这个环节出错。
解决方案:在pdfs-site.xml文件中添加dfs.webhdfs.enabled配置项,并重新加载集群配置!
使用rsync进行集群文件同步
集群端口一览表
端口名 | 用途 |
---|---|
50070 | Hadoop Namenode UI端口 |
50075 | Hadoop Datanode UI端口 |
50090 | Hadoop SecondaryNamenode 端口 |
50030 | JobTracker监控端口 |
50060 | TaskTrackers端口 |
8088 | Yarn任务监控端口 |
60010 | Hbase HMaster监控UI端口 |
60030 | Hbase HRegionServer端口 |
8080 | Spark监控UI端口 |
4040 | Spark任务UI端口 |
9000 | HDFS连接端口 |
9090 | HBase Thrift1端口 |
8000 | Hue WebUI端口 |
9083 | Hive metastore端口 |
10000 | Hive service端口 |
不定时更新。
有时候各个集群之间,集群内部各个节点之间,以及外网内网等问题,如果网络组策略比较严格的话,会经常要求开通端口权限,可以参考这个表的内容,以免每次都会漏过一些端口影响效率。
其他一些可用技能
集群中的datanode出现数据分布不均匀的时候可以用hadoop的balancer工具将数据打散
# 进行数据的balancer操作,直到该节点的磁盘使用率低于集群的平均使用率的15%
bin/start-balancer.sh -threshold 15
检查hdfs中出现损坏的block块
bin/hadoop fsck file -blocks -files -locations
作者:@小黑