开篇概述
随着计算机网络基础设施的完善,社交网络和电商的发展以及物连网的推进,产生了越来越多的大数据,使得人工智能最近几年也有了长足的发展(可供机器学习的样本数据量足够大了),大数据的存储和处理也越来越重要,国家对此也比较重视(可上网搜索关键字“大数据白皮书”关键字,以了解详细情况),会长决定和年轻人也一块儿学习一下,于是报了网易云课堂的课程,不定时将学习到的东西整理为博客,此乃开篇。
学习大数据必先学习Hadoop,因为它是目前世界上最流行的分布式数据处理框架。
Tips:所谓大数据,是指数据量庞大、产生数度快、结构多样的价值密度低的数据。其中,数据量庞大是指数据规模超出了1,2台高性能主机所能处理范围;结构多样性是指除了关系型数据库能够处理的结构化数据还包含半结构化数据(如各类传感设备必如地镑、卫星、GPS设备等产生的纯文本格式的数据,还有良心网站NASA官网公布的txt格式的空间天气数据等成行成列的数据)和非结构化数据(视频、图像等)。这些数据的价值密度普遍较低(和具体的应用范围也有关系,比如NASA的数据,如果想知道某天的太阳射电情况,看当天发布的txt就好了,价值密度很高,但是这就不算大数据了,因为需要采集的数据量很小;如果想知道过去N年太阳射电的极值就需要处理很多数据,这些数据的价值密度就低了),大数据处理的目的就是从价值密度的数据里把有价值的数据过滤分析出来。
Hadoop概述
Hadoop是一个用于分布式大数据处理的编程框架。同时它也是个大数据处理完整的生态系统,围绕着Hadoop,这个生态系统还包括但不限于:
- HBase
- Hive
- Pig
- Spark
- ZooKeeper
希望本系列的写作能够坚持下去,对上述内容都有所涉及吧。
Hadoop能干什么
假设老王在某不知名IT公司工作,由于最近太阳活动异常,引起了领导的外甥的读硕士的同学的关注,领导让老王把山西铁岛太阳射电望远镜观测到的近30年的太阳射电数据下载下来,让老王从里面找到最高的记录。老王毕竟搞挨踢已有多年,虽然技术不行,终日碌碌无为,但多年的直觉告诉老王这个很简单。老王立刻下载了其中一个文件并大致看了文件的机构:数据保存在txt文件里,每行N列,其中包含了时间和数据信息列,大约每0.1s记录一条数据,一个文件记录15分钟的数据,大约有9000条记录,1个小时4个文件,1天96个文件,30年大约1051200个文件,一共大约100亿条数据,这其中还有一些损坏的文件,还有一些用9999表示的未检测到值的占位数据需要特殊照顾。
老王觉得单机处理这些数据耗时太久,于是老王找来一些公司淘汰下来的旧服务器(一般小公司最破的机器都是服务器),准备每个机器负责一部分,最后把结果汇总,老王在开发的过程中还是遇到了很多问题,比如,如何分配任务,有的机器破,有的机器新,还有的文件大,有的文件小,总是不能保证所有的任务一起完成,先完成任务的机器闲置浪费掉了资源;还有最后把结果通过网络通信汇总起来,如何保证数据不丢失,不覆盖;还有如果某台机器出了问题,如何重新分配任务,这些非核心业务的开发使得老王心力憔悴,还好,老王最后找到了Hadoop这个工具,这个工具给老王提供了一个简单的编程模型,老王在map方法中写了分配的任务的逻辑,在reduce方法中写了合并结果的逻辑,然后Hadoop帮老王完成了其他所有事情,Hadoop就是干这个的。以上故事纯属虚构,如有雷同,实属巧合。
其实上述意淫的例子里的数据量不是很大,如果每天产生上TB级别的数据,就算是速度很快的固态硬盘也需要小时级时间才能读取一遍,速度还是远远跟不上,终归有上限,而且高性能主机价格不菲,不如把数据分开放到一个相对廉价又可扩展的计算机集群中,每个节点上运行一段程序并处理一小块数据,然后在汇总处理结果,使用Hadoop可以让开发者不必把精力放在集群的建设上,采用Hadoop提供的简单的编程模型就可以实现分布式处理。
Hadoop的构造模块
Hadoop集群中运行的守护进程共有5类:
- NameNode
- DataNode
- Secondary NameNode
- JobTracker
- TaskTracker
Hadoop集群中的机器(节点)分为2类:主节点和从节点,NameNode、JobTracker所在节点为主节点(负责管理),DataNode和TaskTracker所在节点为从节点(负责干活儿)。
NameNode
NameNode节点负责将一个文件分成若干文件块,并记录了HDFS文件系统中的文件块放了在哪些DataNode中(一个数据块被冗余地放到1个或多个DataNode节点中),一个集群中只有一个NameNode节点(Hadoop2.X中情况有所不同了),且该节点通常不再运行DataNode和TaskTracker守护进程。
DataNode
DataNode实际管理很多NameNode分配给它的很多数据块,当有文件块变动时会通知NameNode,同时也从NameNode接受指令。一个集群中有多个DataNode节点,DataNode之间也会保持联系,复制冗余文件块,这样当一个DataNode出现故障后不会影响到文件的完整性。
Secondary NameNode
SNN只与NameNode通信,定时获取HDFS元数据的快照,一个集群只有一个SNN,且SNN所在节点只运行SNN守护进程,不干其它的事情。当NameNode出现故障后,可以人工启用SNN作为NameNode。
JobTracker
JobTracker负责分配MapReduce任务给TaskTracker,负责监控任务的执行,如任务失败后重启任务。JobTracker守护进程运行在主节点上,通常该节点不运行DataNode和TaskTracker守护进程。
TaskTracker
TaskTracker负责完成JobTracker分配的任务并和JobTranker进行通信,回报情况。TaskTracker守护进程运行在多个子节点上
看图说话
上图中,NameNode和JobTracker是分开的,如果集群规模不大也可以运行在同一个节点上(如果这个节点出现故障该如何恢复?)
安装Hadoop
在安装Hadoop之前需要先安装如下软件:
- JDK
- ssh
- sshd
- ssh-kengen
我用的是Ubuntu16.04,已经预装了ssh和ssh-kengen了,只需要安装jdk和sshd,可以通过执行命令which
命令来检查是否安装了某软件,如which sshd
安装JDK8
下载压缩包解压即可:sudo mkdir /usr/local/lib/jvm
sudo tar -zxv -f ~/setupFiles/jdk-8u101-linux-x64.tar.gz -C /usr/local/lib/jvm
配置环境变量:
修改 /etc/profile文件,追加:export JAVA_HOME=/usr/local/lib/jvm/jdk1.8.0_101 export PATH=$JAVA_HOME/bin:$PATH
配置完毕后执行命令source /etc/profile
,此刻通过echo $JAVA_HOME
应该能看到刚才设置的了。
安装sshd
sudo apt install openssh-server
安装完了sshd后应该可以通过ssh lcoalhost
命令远程访问了,但是需要输入密码,Hadoop集群节点间要进行通信需要配置为无密码登录方式。
无密码ssh登录设置
执行如下命令:
ssh-keygen -t rsa
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
chmod 0600 ~/.ssh/authorized_keys
其中,执行ssh-keygen
命令时一路回车不要输入密码,执行完毕后会在/home/userName/.ssh路径下生成公钥和私钥id_rsa和id_rsa.pub。如果一切顺利的话,现在可以通过ssh localhost
无密码登录了
安装Hadoop
我下载的是1.0.4版本(2.X版本和1.X版本有着很大的差别,还是先学会1.X再看2.X吧,我们的课程也是以1.X为例的,事实上我刚才下的2.X,发现很多东西不懂,又退回1.X了,:-)),先把下载下来的压缩包解压到~/wiley/hadoop(其实最好放按照Linux的习惯放到/usr/local下,然后把hadoop目录及里面的文件所属用户和所属组改成当前用户和当前用户所属组)
解压后配置文件conf/hadoop-env.sh文件中的JAVA_HOME,反注释如下行# export JAVA_HOME=/usr/lib/j2sdk1.5-sun
,并且设置为相应的Java所在路径。
Hadoop可以在三种模式下工作:
- 单节点模式
- 伪分布式模式
- 分布式模式
工作环境下是分布式模式,开发环境下可以使用单节点模式或伪分布式模式,方便调试。解压后不做配置就是单节点模式,而伪分布式模式意思是指集群中的各个节点实际配置为同一台机器。下面的步骤用来配置伪分布式模式:
配置conf/hadoop-env.sh
反注释并修改JAVA_HOME:
export JAVA_HOME=/usr/local/lib/jvm/jdk1.8.0_101
配置conf/core-site.xml
<configuration>
<property>
<name>hadoop.tmp.dir</name>
<value>/home/joey/wiley/hadoop/hadoop_temp/</value>
<description>http://stackoverflow.com/questions/2354525/what-should-be-hadoop-tmp-dir</description>
</property>
<property>
<name>fs.default.name</name>
<value>hdfs://localhost:9000</value>
<description>NameNode守护进程所在机器和端口</description>
</property>
</configuration>
配置conf/hdfs-site.xml
<configuration>
<property>
<name>dfs.replication</name>
<value>1</value>
<description>HDFS的默认副本数,由于是伪分布式模式,所以设置为1</description>
</property>
</configuration>
配置conf/mapred-site.xml
<configuration>
<property>
<name>mapred.job.tracker</name>
<value>localhost:9001</value>
<description>JobTracker守护进程所在机器及端口</description>
</property>
</configuration>
启动Hadoop
在启动之前先格式和HDFS文件系统:cd ~/wiley/hadoop/bin ./hadoop namenode -format
然后启动Hadoop:./start-all.sh
,如果一切顺利的话用jps
命令查看会有5个进程(不包括jps本身):
此时可以打开两个基于Web的界面
- http://localhost:50070 :HDFS的状态
- http://localhost:50030 :MapReduce作业运行状态
运行例子WordCount
文章的最后运行一个简单的MapReduceJob:单词统计。Hadoop中已经附有一些实例Java代码,放在了hadoop/src/examples/org/apache/hadoop/examples,其中一个叫做WordCount.java,是用来统计文件中单词数量的,代码很简单的,大家可以去看看。此处先运行一下这个例子感受一下,执行如下命令mkdir test
mkdir test/classes
mkdir test/src
cp src/examples/org/apache/hadoop/examples/WordCount.java test/src
生成jar文件:javac -classpath hadoop-core-1.0.4.jar:lib/commons-cli-1.2.jar -d test/classes test/src/WordCount.java
jar -cvf test/WordCount.jar -C test/classes/ .
运行该程序需要两个参数(可参考源码文件),一个是放置文本文件的input路径,一个是输出结果的output路径,先在HDFS中创建之:bin/hadoop dfs -mkdir input
在本地文件系统中创建一个文本文件test/f1.txt,写入一句话:2b or not 2b is ff
,把文件put到HDFS里:bin/hadoop fs -put test/f1.txt /user/joey/input
激动人心的时刻到了:bin/hadoop jar test/WordCount.jar org.apache.hadoop.examples.WordCount input output
由于input和output位于/user/joey下面,而/user/joey是默认的工作目录,所有直接写input和output,不用在前面加/user/joey/。现在看看运行结果:
居然用了整整两天时间才写完,啊,虽然有点蛇尾,可是我太累了。到此结束,欢迎批评。
*参考资料:
- 网易云课堂:大数据工程师
- 《Hadoop in Action》*