Hadoop学习总结

初识Hadoop



Hadoop历史
        雏形开始于2002年的Apache的Nutch,Nutch是一个开源Java 实现的搜索引擎。它提供了我们运行自己的搜索引擎所需的全部工具。包括全文搜索和Web爬虫。
        随后在2003年Google发表了一篇技术学术论文谷歌文件系统(GFS)。GFS也就是google File System,google公司为了存储海量搜索数据而设计的专用文件系统。
        2004年Nutch创始人Doug Cutting基于Google的GFS论文实现了分布式文件存储系统名为NDFS。
        2004年Google又发表了一篇技术学术论文MapReduce。MapReduce是一种编程模型,用于大规模数据集(大于1TB)的并行分析运算。
        2005年Doug Cutting又基于MapReduce,在Nutch搜索引擎实现了该功能。
        2006年,Yahoo雇用了Doug Cutting,Doug Cutting将NDFS和MapReduce升级命名为Hadoop,Yahoo开建了一个独立的团队给Goug Cutting专门研究发展Hadoop。
        不得不说Google和Yahoo对Hadoop的贡献功不可没。
 
Hadoop核心
        Hadoop的核心就是HDFS和MapReduce,而两者只是理论基础,不是具体可使用的高级应用,Hadoop旗下有很多经典子项目,比如HBase、Hive等,这些都是基于HDFS和MapReduce发展出来的。要想了解Hadoop,就必须知道HDFS和MapReduce是什么。
 
HDFS
HDFS(Hadoop Distributed File System,Hadoop分布式文件系统),它是一个高度容错性的系统,适合部署在廉价的机器上。HDFS能提供高吞吐量的数据访问,适合那些有着超大数据集(large data set)的应用程序。
 
HDFS的设计特点是:
1、大数据文件,非常适合上T级别的大文件或者一堆大数据文件的存储,如果文件只有几个G甚至更小就没啥意思了。
2、文件分块存储,HDFS会将一个完整的大文件平均分块存储到不同计算器上,它的意义在于读取文件时可以同时从多个主机取不同区块的文件,多主机读取比单主机读取效率要高得多得都。
3、流式数据访问,一次写入多次读写,这种模式跟传统文件不同,它不支持动态改变文件内容,而是要求让文件一次写入就不做变化,要变化也只能在文件末添加内容。
4、廉价硬件,HDFS可以应用在普通PC机上,这种机制能够让给一些公司用几十台廉价的计算机就可以撑起一个大数据集群。
5、硬件故障,HDFS认为所有计算机都可能会出问题,为了防止某个主机失效读取不到该主机的块文件,它将同一个文件块副本分配到其它某几个主机上,如果其中一台主机失效,可以迅速找另一块副本取文件。
 
HDFS的关键元素:
Block:将一个文件进行分块,通常是64M。
NameNode:保存整个文件系统的目录信息、文件信息及分块信息,这是由唯一一台主机专门保存,当然这台主机如果出错,NameNode就失效了。在Hadoop2.*开始支持activity-standy模式----如果主NameNode失效,启动备用主机运行NameNode。
DataNode:分布在廉价的计算机上,用于存储Block块文件。
  
MapReduce
通俗说MapReduce是一套从海量·源数据提取分析元素最后返回结果集的编程模型,将文件分布式存储到硬盘是第一步,而从海量数据中提取分析我们需要的内容就是MapReduce做的事了。
 
下面以一个计算海量数据最大值为例:一个银行有上亿储户,银行希望找到存储金额最高的金额是多少,按照传统的计算方式,我们会这样:
Java代码  收藏代码
Long moneys[] ...  
Long max = 0L;  
for(int i=0;i<moneys.length;i++){  
  if(moneys[i]>max){  
    max = moneys[i];  
  }  
}  
 
 如果计算的数组长度少的话,这样实现是不会有问题的,还是面对海量数据的时候就会有问题。
MapReduce会这样做:首先数字是分布存储在不同块中的,以某几个块为一个Map,计算出Map中最大的值,然后将每个Map中的最大值做Reduce操作,Reduce再取最大值给用户。


        MapReduce的基本原理就是:将大的数据分析分成小块逐个分析,最后再将提取出来的数据汇总分析,最终获得我们想要的内容。当然怎么分块分析,怎么做Reduce操作非常复杂,Hadoop已经提供了数据分析的实现,我们只需要编写简单的需求命令即可达成我们


想要的数据。
  
总结
        总的来说Hadoop适合应用于大数据存储和大数据分析的应用,适合于服务器几千台到几万台的集群运行,支持PB级的存储容量。
        Hadoop典型应用有:搜索、日志处理、推荐系统、数据分析、视频图像分析、数据保存等。
        但要知道,Hadoop的使用范围远小于SQL或Python之类的脚本语言,所以不要盲目使用Hadoop,看完这篇试读文章,我知道Hadoop不适用于我们的项目。
========

Hadoop快速入门



目的
先决条件
支持平台
所需软件
安装软件
下载
运行Hadoop集群的准备工作
单机模式的操作方法
伪分布式模式的操作方法
配置
免密码ssh设置
执行
完全分布式模式的操作方法
目的
这篇文档的目的是帮助你快速完成单机上的Hadoop安装与使用以便你对Hadoop分布式文件系统(HDFS)和Map-Reduce框架有所体会,比如在HDFS上运行示例程序或简单作业等。


先决条件
支持平台
GNU/Linux是产品开发和运行的平台。 Hadoop已在有2000个节点的GNU/Linux主机组成的集群系统上得到验证。
Win32平台是作为开发平台支持的。由于分布式操作尚未在Win32平台上充分测试,所以还不作为一个生产平台被支持。
所需软件
Linux和Windows所需软件包括:


JavaTM1.5.x,必须安装,建议选择Sun公司发行的Java版本。
ssh 必须安装并且保证 sshd一直运行,以便用Hadoop 脚本管理远端Hadoop守护进程。
Windows下的附加软件需求


Cygwin - 提供上述软件之外的shell支持。
安装软件
如果你的集群尚未安装所需软件,你得首先安装它们。


以Ubuntu Linux为例:


$ sudo apt-get install ssh 
$ sudo apt-get install rsync


在Windows平台上,如果安装cygwin时未安装全部所需软件,则需启动cyqwin安装管理器安装如下软件包:


openssh - Net 类
下载
为了获取Hadoop的发行版,从Apache的某个镜像服务器上下载最近的 稳定发行版。


运行Hadoop集群的准备工作
解压所下载的Hadoop发行版。编辑 conf/hadoop-env.sh文件,至少需要将JAVA_HOME设置为Java安装根路径。


尝试如下命令:
$ bin/hadoop 
将会显示hadoop 脚本的使用文档。


现在你可以用以下三种支持的模式中的一种启动Hadoop集群:


单机模式
伪分布式模式
完全分布式模式
单机模式的操作方法
默认情况下,Hadoop被配置成以非分布式模式运行的一个独立Java进程。这对调试非常有帮助。


下面的实例将已解压的 conf 目录拷贝作为输入,查找并显示匹配给定正则表达式的条目。输出写入到指定的output目录。 
$ mkdir input 
$ cp conf/*.xml input 
$ bin/hadoop jar hadoop-*-examples.jar grep input output 'dfs[a-z.]+' 
$ cat output/*


伪分布式模式的操作方法
Hadoop可以在单节点上以所谓的伪分布式模式运行,此时每一个Hadoop守护进程都作为一个独立的Java进程运行。


配置
使用如下的 conf/hadoop-site.xml:


<configuration>
  <property>
    <name>fs.default.name</name>
    <value>localhost:9000</value>
  </property>
  <property>
    <name>mapred.job.tracker</name>
    <value>localhost:9001</value>
  </property>
  <property>
    <name>dfs.replication</name>
    <value>1</value>
  </property>
</configuration>
免密码ssh设置
现在确认能否不输入口令就用ssh登录localhost:
$ ssh localhost


如果不输入口令就无法用ssh登陆localhost,执行下面的命令:
$ ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa 
$ cat ~/.ssh/id_dsa.pub >> ~/.ssh/authorized_keys


执行
格式化一个新的分布式文件系统:
$ bin/hadoop namenode -format


启动Hadoop守护进程:
$ bin/start-all.sh


Hadoop守护进程的日志写入到 ${HADOOP_LOG_DIR} 目录 (默认是 ${HADOOP_HOME}/logs).


浏览NameNode和JobTracker的网络接口,它们的地址默认为:


NameNode - http://localhost:50070/
JobTracker - http://localhost:50030/
将输入文件拷贝到分布式文件系统:
$ bin/hadoop fs -put conf input


运行发行版提供的示例程序:
$ bin/hadoop jar hadoop-*-examples.jar grep input output 'dfs[a-z.]+'


查看输出文件:


将输出文件从分布式文件系统拷贝到本地文件系统查看:
$ bin/hadoop fs -get output output 
$ cat output/*


或者


在分布式文件系统上查看输出文件:
$ bin/hadoop fs -cat output/*


完成全部操作后,停止守护进程:
$ bin/stop-all.sh


完全分布式模式的操作方法
关于搭建完全分布式模式的,有实际意义的集群的资料可以在这里找到。


========

Hadoop基础教程之搭建开发环境及编写Hello World



整个Hadoop是基于Java开发的,所以要开发Hadoop相应的程序就得用JAVA。在linux下开发JAVA还数eclipse方便。
1、下载
进入官网:http://eclipse.org/downloads/。
找到相应的版本进行下载,我这里用的是eclipse-SDK-3.7.1-linux-gtk版本。
2、解压
下载下来一般是tar.gz文件,运行:
$tar -zxvf eclipse-SDK-3.7.1-linux-gtk.tar.gz -c ~/Tool
这里Tool是需要解压的目录。
解完后,在tool下,就可以看到eclipse文件夹。
运行:
$~/Tool/eclipse/eclipse
3、创建开始菜单项
每次运行时,输入命令行比较麻烦,最好能创建在左侧快捷菜单上。
$sudo gedit /usr/share/applications/eclipse.desktop
1)启动文本编译器,并创建文件,添加以下内容:
[Desktop Entry]
Version=1.0
Encoding=UTF-8
Name=Eclipse3.7.1
Exec=eclipse
TryExec=eclipse
Comment=Eclipse3.7.1,EclipseSDK
Exec=/usr/zjf/Tool/eclipse/eclipse
Icon=/usr/ zjf/Tool/eclipse/icon.xpm
Terminal=false
Type=Application
Categories=Application;Development;
[注意上面的路径] 
    2)创建启动器
 
sudo gedit /usr/bin/eclipse
添加如下内容
#!/bin/sh
export MOZILLA_FIVE_HOME="/usr/lib/mozilla/"
export ECLIPSE_HOME="/usr/local/eclipse"
$ECLIPSE_HOME/eclipse $* 
    3)添加可执行权限
 
sudo chmod +x /usr/bin/eclipse 
4)在开始菜单中输入eclipse:


就会看到软件图标,然后将其拖到左侧工具条中即可。


 
4、下载hadoop在eclise中的插件并配置
直接在网上搜:hadoop-0.20.2-eclipse-plugin.jar
https://issues.apache.org/jira/secure/attachment/12460491/hadoop-eclipse-plugin-0.20.3-SNAPSHOT.jar
下载后,将jar包放在eclipse安装目录下的plugins文件夹下。然后启动eclipse


第一次启动eclpse后,会让我们设定一个工作目录,即以后建的项目都在这个工作目录下。
进入后,在菜单window->Rreferences下打开设置:




点击browse选择hadoop的源码下的Build目录,然后点OK
打开Window->View View->Other 选择Map/Reduce Tools,单击Map/Reduce Locations,会打开一个View,




添加Hadoop Loacation,其中Host和Port的内容跟据conf/hadoop-site.xml的配置填写,UserName 是用户名,如


在配置完后,在Project Explorer中就可以浏览到DFS中的文件,一级级展开,可以看到之前我们上传的in文件夹,以及当是存放的2个txt文件,同时看到一个在计算完后的out文件夹。


现在我们要准备自己写个Hadoop 程序了,所以我们要把这个out文件夹删除,有两种方式,一是可以在这树上,执行右健删除。 二是可以用命令行:
$bin/hadoop fs -rmr out
用$bin/hadoop fs -ls 查看
5、编写HelloWorld
环境搭建好了,之前运行Hadoop时,直接用了examples中的示例程序跑了下,现在可以自己来写这个HelloWorld了。
在eclipse菜单下 new Project 可以看到,里面增加了Map/Reduce选项:


选中,点下一步:


输入项目名称后,继续(next), 再点Finish


然后在Project Explorer中就可以看到该项目了,展开,src发现里面啥也没有,于是右健菜单,新建类(new->new class):


然后点击Finish,就可以看到创建了一个java类了:


然后在这个类中填入代码:
public static class TokenizerMapper
extends Mapper<Object, Text, Text, IntWritable>{
private final static IntWritable one = new IntWritable(1);
private Text word = new Text();
public void map(Object key, Text value, Context context
) throws IOException, InterruptedException {
System.out.println("key=" +key.toString());
System.out.println("Value=" + value.toString());
StringTokenizer itr = new StringTokenizer(value.toString());
while (itr.hasMoreTokens()) {
word.set(itr.nextToken());
context.write(word, one);
}
}
}
public static class IntSumReducer
extends Reducer<Text,IntWritable,Text,IntWritable> {
private IntWritable result = new IntWritable();
public void reduce(Text key, Iterable<IntWritable> values,
Context context
) throws IOException, InterruptedException {
int sum = 0;
for (IntWritable val : values) {
sum += val.get();
}
result.set(sum);
context.write(key, result);
}
}
public static void main(String[] args) throws Exception {
Configuration conf = new Configuration();
System.out.println("url:" + conf.get("fs.default.name"));
String[] otherArgs = new GenericOptionsParser(conf, args).getRemainingArgs();
if (otherArgs.length != 2) {
System.err.println("Usage: wordcount <in> <out>");
System.exit(2);
}
Job job = new Job(conf, "word count");
job.setJarByClass(WordCount.class);
job.setMapperClass(TokenizerMapper.class);
job.setCombinerClass(IntSumReducer.class);
job.setReducerClass(IntSumReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(IntWritable.class);
FileInputFormat.addInputPath(job, new Path(otherArgs[0]));
FileOutputFormat.setOutputPath(job, new Path(otherArgs[1]));
System.exit(job.waitForCompletion(true) ? 0 : 1);
}


填入代码后,会看到一些错误,没关系,点击边上的红叉,然后选择里面的import即可;
如果想偷懒,则可以直接在类的开头帖入下面的这些引用:
import java.io.IOException;
import java.util.StringTokenizer;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;
这里,如果直接用源码来操作,可能会GenericOptionsParser这个类找不到定义,还是红叉,没关系,如果还是红叉,可以添加commons-cli-1.2.jar
 
这个jar包,在build/ivy/lib/Hadoop/Common下,右健Project Explorer中的MyHelloWorld工程,选择Build Path->Config Build Path


在Liberaries Tab页下,点击Add External JARs 在弹出窗口中,跟据前面说的目录,找到这个jar包,点确定后,回到工程,可以看到红叉消失,说明编译都通过了。
在确保整个工程没有错误后,点击上面的小绿箭头,然后在弹出的小窗口上,选择Run On Hadoop:


点OK后,会弹出小窗口:


然手中选择Choose an existing server from the list below。然后找到之前配置的地址项,选中后,点Finish,然后系统不会Run起来,在控制台(双击可最大化)中可以看到运行结果:


运行完后,用命令行可以看到 $bin/hadoop fs –ls 可以看到多了一个out文件夹,再用$bin/hadoop fs –cat out/*可以将out文件夹内容全显示出来,则可以看到单词的统计结果来。
问题1 :过程中,如果点了Run On Hadoop没有反应,则可能你下的这个有问题,重新到:https://issues.apache.org/jira/secure/attachment/12460491/hadoop-eclipse-plugin-0.20.3-SNAPSHOT.jar
上下载,然后将下载的插件重命名为"hadoop-0.20.2-eclipse-plugin.jar",放入eclipse中的plugins目录下。
问题2:运行后,如果结果里只输入了个usage <in> <out>,则需要修改下参数,在运行菜单边上小箭头,下拉,点击Run Configuration,:


左边选中 JavaApplication中的 WordCount,右边,在Arguments中输入 in out。
然后再点Run 就可以看到结果了。
问题3:第二次运行会报错,仔细看提示,可以看到报错的是out目录已经存在,所以需要手动来删除一下。
========

Hadoop教程之编写HelloWorld(2)

 
前面我们写了一个Hadoop程序,并让它跑起来了。但想想不对啊,Hadoop不是有两块功能么,DFS和MapReduce。没错,上一节我们写了一个MapReduce的HelloWorld程序,那这一节,我们就也学一学DFS程序的编写。
DFS 是什么,之前已经了解过,它是一个分布式文件存储系统。不管是远程或本地的文件系统,其实从接口上讲,应该是一至的,不然很难处理。同时在第2节的最后, 我们列出了很多一些DFS的操作命令,仔细看一下,这些命令其实跟linux中的文件操作命令很相似,


所以说,对于分布式文件系统,我们完全可以用本地文 件的方式来理解。
那理一下,一般常用操作有哪些? 当然我们可以从编程角度来:
创建、读、写一个文件,列出文件夹中的文件及文件夹列表,删除文件夹,删除目录,移动文件或文件夹,重命名文件或文件夹。
同样,这里我们就依葫芦画瓢跑起个程序来:
启 动eclipse,新建Hadoop项目,名称MyDFSTest,新建类DFSTest,点击确定,然后同样工程属性Configure BuildPath中把 build/ivy/lib/Hadoop下的所有jar包都引用进来。「这里就不详细截图了,可以参考前一节中的内容」
在类中,添加main函数:
public static void main(String[] args) {
}
也可以在添加类时,勾选上创建main,则会自动添加上。
 
在Main函数中添加以下内容:
try {
Configuration conf = new Configuration();
conf.set("fs.default.name", "hdfs://localhost:9000");
FileSystem hdfs = FileSystem.get(conf);
Path path = new Path("in/test3.txt");
FSDataOutputStream outputStream = hdfs.create(path);
byte[] buffer = " 你好Hello".getBytes();
outputStream.write(buffer, 0, buffer.length);
outputStream.flush();
outputStream.close();
System.out.println("Create OK");
} catch (IOException e) {
e.printStackTrace();
}
直接添加进来会报错,然后需要添加一些引用才行:
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.fs.FSDataOutputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
在没有错误后,点击工具条上的运行, 但这次跟前次不一样,选择Run as Java Application。然后,就可以在输出框中看到Create OK的字样了,表明程序运行成功。
这段代码的意思是在in文件夹下,创建test3.txt,里面的内容是"你好Hello"。 在运行完后,我们可以到eclipse的Project Explorer中查看是否有这文件以及内容。同样也可以用命令行查看$bin/hadoop fs -ls in。
好了,第一个操作DFS的程序跑起来了,那其它功能只要套上相应的处理类就可以了。
为了方便查找操作,我们列举了张表:
操作说明
操作本地文件
操作DFS文件
主要命名空间
 
 
java.io.File
java.io.FileInputStream
java.io.FileOutputStream
org.apache.hadoop.conf.Configuration
org.apache.hadoop.fs.FileSystem
org.apache.hadoop.fs.Path
org.apache.hadoop.fs.FSDataInputStream;
org.apache.hadoop.fs.FSDataOutputStream
初使化对象
new File(路径);
Configuration
FileSystem hdfs
创建文件
File.createNewFile();
FSDataOutputStream = hdfs.create(path)
FSDataOutputStream.write(
buffer, 0, buffer.length);
创建文件夹
File.mkdir()
hdfs.mkdirs(Path);
读文件
new FileInputStream();
FileInputStream.read(buffer)
FSDataInputStream = hdfs.open(path);
FSDataInputStream.read(buffer);
写文件
FileOutputStream.write(
buffer, 0, buffer.length);
FSDataOutputStream = hdfs.append(path)
FSDataOutputStream.write(
buffer, 0, buffer.length);
删除文件(夹)
File.delete()
FileSystem.delete(Path)
列出文件夹内容
File.list();
FileSystem.listStatus()
重命令文件(夹)
File.renameTo(File)
FileSystem.rename(Path, Path)        
有了这张表,以后不怕了,代码搬搬即可。
接下来换个话题。
本人主要从事.net开发的,所以对于java上,还是有点生。所以接下来半章中,简要的把JAVA的学习列一列。
JAVA和.net现在从语言角度看,的确有很多相似之处。但也有不同之处,这就是我们要学的。
在.Net中,主要有dll和exe, dll为类库, exe为可执行程序,在exe中有唯一的main函数,作为函数入口。dll 类库是无法执行的,exe可以双击运行,也可以命令行执行。编译后,.net会把所有定义的类编译进exe或dll中,一个工程产出文件就是一个。
在JAVA中,jar 对应的类库,可以被别人调用。exe就不存在了。一个工程编译后,产出物是一堆的.class文件,在开发中每一个定义的类,都会被编译成这 个.class文件。而且一个.java文件中,不能定义多个顶级类(嵌套类是可以的),且文件名与类名必须相同,文


件所以的目录必须和命名空间相同。所 以编译后,可以讲一个.java文件将会编译成一个.class文件,且有与原先的目录相同。
也就是说,java有点像散装的一样,产物就是一堆的.class文件。 那jar文件呢,简单的说,就是一个zip包,把一堆的.class文件打包成一个压缩包。
同时,一个工程中,支持多个main函数,即多个入口。
说了一堆,还不如实践一下:
在eclipse中,创建一个JAVA project 取名为JAVAStudy。
然后创建两个类,没有目录的,ch1 ch2 再创建一个包叫pkg1,在这个包下创建一个类ch3:


然后,每个类下都建一个main函数,内容打印类名:
public static void main(String[] args) {
System.out.println(ch1.class.getName());
}
注意,复制到ch2 ch3中后要改一下里面的类名。
然后每当你切换到一个新的类代码中,点击运行,都会提示Run As ,都选Java Application。 然后就可以看到结果了,每个类都可以作为入口执行。
OK,程序好了,如何发布呢,或如何从命令行运行呢?
我们进入目录先看一下:


进入工程目录,可以看到有src和bin,进入bin,就可以看到一个个的class文件了,的确跟前面描述一样,目录与代码相同结构。


输入java ch1 就可以看到结果了。执行ch3时,注意中间不是斜线,而是点,因为这里输入的是命名空间+类名,而不是class文件的路径。
如果不在这个目录执行,看到会报错,或命名空间输错了,也是这个错。


如果我就在这里想执行呢? 可以这样:


利用classpath指定class的路径。
如何打成jar包:
进入bin目录:
$cd bin
$jar cvf test.jar ch1.class ch2.class pkg1/.class
然后在bin目录下就可以看到test.jar文件了。
如何执行jar呢,为了防止与里面的class文件冲突,我们将test.jar复制到外面来:
$cp test.jar ../
$cd ..
再执行:
$java –classpath test.jar ch1


同样,输入classpath就可以搞定了的。
了解了这些后,我们又可以做个试验证了。 第一章中我们运行hadoop中Helloword时,是调用了example的jar包。所以这里我们可以把上一章的程序也来打个jar包,试下是否能运行:
$cd ~/workspace/MyHelloWorld      //进入HelloWorld代码目录
$cd bin
$jar cvf test.jar *.class     //打上jar包
$cp test.jar ../../hadoop-0.20.2    //将jar包复制到hadoop目录下
$cd ../../hadoop-0.20.2
$bin/start-all.sh             //启动hadoop
$bin/hadoop test.jar WordCount in out //运行我们写的程序
然后就可以看到与之前一样的结果了。
========

Hadoop基础教程-运行环境搭建

 
一、Hadoop是什么
一个分布式系统基础架构,由Apache基金会所开发。用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力进行高速运算和存储。 Hadoop实现了一个分布式文件系统(Hadoop Distributed File System),简称HDFS。HDFS有高容错性的特点


,并且设计用来部署在低廉的(low-cost)硬件上;而且它提供高传输率(high throughput)来访问应用程序的数据,适合那些有着超大数据集(large data set)的应用程序。HDFS放宽了(relax)POSIX的要求,可以以流的形式访问(streaming access)文件系统中


的数据。Hadoop的框架最核心的设计就是:HDFS和MapReduce。HDFS为海量的数据提供了存储,则 MapReduce为海量的数据提供了计算。
Hadoop主要用于一些分布式计算。在这个大数据年代,那这个的确是一个很不错的工具。所以很有必要来学一学。
二、运行环境搭建
首先,这个是需要运行在linux系统中的,所以得安装个linux才行,市面上有很多个linux的版本,如红帽子、Fedra、Ubuntu。选哪种呢,对我这种习惯windows的来说,当然要使用方便的,所以选择了Ubuntu。
安 装Ubuntu,这里我就不多说了,在官网上有很多,其实也很简单,一路下一步。当然这里可以安装在Vmware虚拟机上,也可以直接安装在硬盘上。 我个人建议,可以直接安装在硬盘上,与现有windows做个双系统。因为后面还要跑开发环境 eclipse,在虚拟机上会有


点吃力。 同时安装在硬盘上后,还可以这样玩,在进入windows后,安装 vmware,然后新建虚拟机后,不要创建硬盘,直接使用硬盘的分区,这样, 就可以在vmware中启动安装在硬盘上的ubuntu了。做到双系统,双启动。这样好处是,当要开发时,可以直接进ubuntu


系统,当只是看看代码,以及后面模拟分布式部署时,就可以用vmware来启动,同时再建上几个虚拟机来进行分布式部署。 
操作系统准备好后,就需要一些组件了,hadoop比较简单,只需要ssh和java环境,再加个下代码的SVN。
先用 sudo apt-get install subversion ssh ant 这个命令,把SSH、Ant和SVN安装起来。
java环境,可以在网上下载一个JDK安装包,如:jdk-6u24-linux-i586.bin
安装直接在目录下运行./jdk-6u24-linux-i586.bin即可。
然后配置jdk目录:
先进入安装目录 cd jdk-6u24-…
然后输入 PWD 就可以看到java安装目录,复制下来:


命令行执行:sudo gedit /etc/profile
在打开的文件里,追加:
export JAVA_HOME=/home/administrator/hadoop/jdk1.6.0_27 //这里要写安装目录
export PATH=${JAVA_HOME}/bin:$PATH
执行source /etc/profile 立即生效
验证是否安装完成,那比较容易了,在命令行下运行 java -version ant svn ssh 看是否找不到命令,如果都能找到,说明OK了。
三、下载代码:
这是个开源的系统,代码很方便用SVN就可以下载到,版本也很多,在这里我选择0.20.2版本,一个是网上好多书都基于这个版本的,另外是看源码,还是以前点版本吧,后面的版本里面肯定又加了很多。
运行这个命令来下载:
svn co http://svn.apache.org/repos/asf/hadoop/common/tags/release-0.20.2/
下载完成后,会在当前文件夹内产生一个新文件夹release-0.20.2,这里面就是代码了。
为了后面方便操作,把这文件夹重命令一下:
mv release-0.20.2/ hadoop-0.20.2
好了,用图形界面进入该文件夹,看一看:


 
四、编译代码
刚下完的代码是无法直接运行的,需要编译一下,但用什么编译呢?
编译前先修改一下build.xml,打开,将里面的版本号改成:0.20.2,如下:


看到代码里面有个build.xml,这个是典型的用ant编译用的配置文件,所以直接在命令行里输入:
~/hadoop-0.20.2$ant
~/hadoop-0.20.2$ant jar
~/hadoop-0.20.2$ant examples
[注意] 编译时需要联网,否则在自动下载jar包时会挂掉。
然后屏幕会刷啊刷,等到完成看到下面字符时,也就OK了:


五、配置SSH
我们了解到,这个hadoop是支持分布式运行的,每台机器到时都会来安装hadoop程序,如果想启动所有程序怎么办? 一台台去启动? 那也太土了, 当然是远程去启动咯。为实现这个目标,就得用上SSH了。
SSH是什么,说白了,这个就是一个远程登陆器,跟远程桌面、telnet差不多。在linux上所有操作都可以用命令行来完成,所有SSH也就是一个命令行形式,同时比telnet高级,因为通过了加密通道传输信息。
那我们就部署了一台机器,还要这个SSH吗? 答案是要的,因为在运行hadoop里,即使是本机的,里面也要通过SSH localhost的方式来启动,这样代码统一。
前面不是安装过SSH了么,还要配置什么?SSH正常登陆时,是需要输入用户名密码的,但是当所有的hadoop子服务都受主服务管了后,最好就直接信任了,不要输入帐号信息,所以我们配置的目的也就是这个。
先试一下,我用SSH登陆当前本机信息:


可以看到,登陆本机时,也要输入一下密码,怎么办?
SSH是能过RSA加密的,所以有公钥私钥的说法,所以,我们先产生一对固定的公私钥,运行这个ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa命令:


这里产生公私钥,并生成在.ssh文件夹下,于是我们就进入看一下:


果然,这里多了两个文件,id_dsa为私钥,id_dsa.pub为公钥
然后再把公钥复制成authorized_key,即将这个公钥固定为SSH登陆所用。


这步很重要,做完这步后,就可以再试一下登陆本机了:


看,现在再ssh localhost时,就直接进入,没有再输入帐号了。
到这里,SSH配置就成功了。
6、修改配置文件
在正式运行之前,还要修改一下配置文件才地,这里具体的配置参数,就不讲,葫芦画瓢么,先跑起来,后面再来研究这是为啥:
在代码的conf文件夹内,就可以找到下面几个配置文件,分别配置成以下内容:
core-site.xml
<configuration>
<property>
<name>fs.default.name</name>
<value>hdfs://localhost:9000</value>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>/home/zjf/hadoop-0.20.2/tmpPath</value> !这里改下路径
</property>
</configuration>
hdfs-site.xml
<configuration>
<property>
<name>dfs.replication</name>
<value>1</value>
</property>
</configuration>
mapred-site.xml
<configuration>
<property>
<name>fs.default.name</name>
<value>hdfs://localhost:9000</value>
</property>
<property>
<name>mapred.job.tracker</name>
<value>hdfs://localhost:9001</value>
</property>
</configuration>
修改conf/hadoop-env.sh
将里面的JAVA_HOME注释打开,并把里面的地址配置正确。
7、运行
Hadoop是一头神奇的大象,那我们得站在大象背上说句Hello world了。
进入hadoop目录: $cd Hadoop-0.20.2
首次运行,需要对namenode进行格式化:bin/hadoop namenode -format    
启动hadoop:
bin/start-all.sh
关闭hadoop可以用:
bin/stop-all.sh
如果验证启动成功呢?有两种方式
访问一下管理页面看:
Job跟踪:http://localhost:50030


NameNode结点:http://localhost:50070


 
用jps看一下有几个java进程在运行,如果是下面几个就正常了:


主要有DataNode NameNode SecondaryNameNode TaskTracker JobTracker这几个进程,就表示正常了
系统启动正常后,跑个程序吧
$mkdir input
$cd input
$echo "hello world">test1.txt
$echo "hello hadoop">test2.txt
$cd ..
$bin/hadoop dfs -put input in
$bin/hadoop jar build/hadoop-0.20.2-examples.jar wordcount in out
$bin/hadoop dfs -cat out/* 


最关健的是,最后输入:


输出这个结果这就表示我们的程序运行成功了。至于这结果是什么意思,我想看到后大概也猜到了吧,至于详细解说,下期再看。


========

Hadoop基础教程之高级编程

 
从前面的学习中,我们了解到了MapReduce整个过程需要经过以下几个步骤:
1.输入(input):将输入数据分成一个个split,并将split进一步拆成<key, value>。
2.映射(map):根据输入的<key, value>进生处理,
3.合并(combiner):合并中间相两同的key值。
4.分区(Partition):将<key, value>分成N分,分别送到下一环节。
5.化简(Reduce):将中间结果合并,得到最终结果
6.输出(output):负责输入最终结果。
其中第3、4步又成洗牌(shuffle)过程。
从前面HelloWorld示例中,我们看到,我们只去个性化了Map和Reduce函数,那其他函数呢,是否可以个性化?答案当然是肯定的。下面我们就对每个环节的个性化进行介绍。
自定义输入格式
输 入格式(InputFormat)用于描述整个MapReduce作业的数据输入规范。先对输入的文件进行格式规范检查,如输入路径,后缀等检查;然后对 数据文件进行输入分块(split);再对数据块逐一读出;最后转换成Map所需要的<key, value>健值对。
系统中提供丰富的预置输入格式。最常用的以下两种:
TextInputFormat:系统默认的数据输入格式。将文件分块,并逐行读入,每一行记录行成一对<key, value>。其中,key值为当前行在整个文件中的偏移量,value值为这一行的文本内容。
KeyValueTextInputFormat:这是另一个常用的数据输入格式,读入的文本文件内容要求是以<key, value>形式。读出的结果也就直接形成<key, value>送入map函数中。
如果选择输入格式呢?那就只要在job函数中调用
job.setInputFormatClass(TextInputFormat.class);
在Hello中我们没有设定,系统默认选择了TextInputFormat。
一般情况够用了,但某些情况下,还是无法满足用户的需求,所以还是需要个性化。个性化则按下面的方式进行:
如果数据我们是来源于文件,则可以继承FileInputFormat:
    public class MyInputFormat extends FileInputFormat<Text,Text> {
       @Override
       public RecordReader<Text, Text> createRecordReader(InputSplit split,
             TaskAttemptContext context) throws IOException, InterruptedException {
          // TODO Auto-generated method stub
          return null;
       }
    } 
如果数据我们是来源于非文件,如关系数据,则继承
    public class MyInputFormat extends InputFormat<Text,Text> {
       @Override
       public RecordReader<Text, Text> createRecordReader(InputSplit arg0,
             TaskAttemptContext arg1) throws IOException, InterruptedException {
          // TODO Auto-generated method stub
          return null;
       }
       @Override
       public List<InputSplit> getSplits(JobContext arg0) throws IOException,
             InterruptedException {
          // TODO Auto-generated method stub
          return null;
       }
    } 
这里比较清晰了,下面个函数为拆分成split,上面个函数跟据split输出成Key,value。
自定义map处理
这个好理解,我们的HelloWorld程序中就自定义了map处理函数。然后在job中指定了我们的处理类:
job.setMapperClass(TokenizerMapper.class);
能不能没有map呢? 可以的,如果没有map,也就是这与上面的这个setMapperClass,则系统自动指定一个null,这时处理是将输入的<key,value>值,不作任何修改,直接送到下一环节中。
个性化代码如下:
    public static class TokenizerMapper
           extends Mapper<Object, Text, Text, IntWritable>{
        public void map(Object key, Text value, Context context
                        ) throws IOException, InterruptedException {
            context.write(key, value);
        }
      } 
自定义合并Combiner
自定义合并Combiner类,主要目的是减少Map阶段输出中间结果的数据量,降低数据的网络传输开销。
Combine 过程,实际跟Reduce过程相似,只是执行不同,Reduce是在Reducer环节运行,而Combine是紧跟着Map之后,在同一台机器上预先将 结时进行一轮合并,以减少送到Reducer的数据量。所以在HelloWorld时,可以看到,Combiner和Reducer用的是同一个类:
    job.setCombinerClass(IntSumReducer.class);
    job.setReducerClass(IntSumReducer.class); 
如何个性化呢,这个跟Reducer差不多了:
    public static class MyCombiner
          extends Reducer<Text,IntWritable,Text,IntWritable> {
       public void reduce(Text key, Iterable<IntWritable> values,
                          Context context
                          ) throws IOException, InterruptedException {
         context.write(key, new IntWritable(1));
       }
     } 
自定义分区Partitioner
在 MapReduce程序中,Partitioner决定着Map节点的输出将被分区到哪个Reduce节点。而默认的Partitioner是 HashPartitioner,它根据每条数据记录的主健值进行Hash操作,获得一个非负整数的Hash码,然后用当前作业的Reduce节点数取模 运算,有N个结点的话,就


会平均分配置到N个节点上,一个隔一个依次。大多情况下这个平均分配是够用了,但也会有一些特殊情况,比如某个文件的,不能被拆 开到两个结点中,这样就需要个性化了。
个性化方式如下:
    public static class MyPartitioner
          extends HashPartitioner<K,V> {
       public void getPartition(K key, V value,int numReduceTasks) {
         super.getPartition(key,value,numReduceTasks);
       }
     } 
方式其实就是在执行之前可以改变一下key,来欺骗这个hash表。
自定义化简(Reducer)
这一块是将Map送来的结果进行化简处理,并形成最终的输出值。与前面map一样,在HelloWorld中我们就见到过了。通过下面代码可以设置其值:
job.setReducerClass(IntSumReducer.class);
同样,也可以这样类可以不设置,如果不设置的话,就是把前面送来的值,直接送向输出格式器中。
如果要个性化,则如下:
      public static class IntSumReducer
         extends Reducer<Text,IntWritable,Text,IntWritable> {
      public void reduce(Text key, Iterable<IntWritable> values,
                         Context context
                         ) throws IOException, InterruptedException {
        context.write(key, result);
      }
    } 
自定义输出格式
数 据输出格式(OutPutFormat)用于描述MapReduce作业的数据输出规范。Hadoop提供了丰富的内置数据输出格式。最常的数据输出格式 是TextOutputFormat,也是系统默认的数据输出格式,将结果以"key+\t+value"的形式逐行输出到文本文件中。还有其它的, 如:


DBOutputFormat,FileOutputFormat,FilterOutputFormat,IndexUpdataOutputFormat,LazyOutputFormat,MapFileOutputFormat, 等等。
如果要个性化,则按下面方式进行:
    public class MyOutputFormat extends OutputFormat<Text,Text> {
       @Override
       public void checkOutputSpecs(JobContext arg0) throws IOException,
             InterruptedException {
          // TODO Auto-generated method stub
       }
       @Override
       public OutputCommitter getOutputCommitter(TaskAttemptContext arg0)
             throws IOException, InterruptedException {
          // TODO Auto-generated method stub
          return null;
       }
       @Override
       public RecordWriter<Text, Text> getRecordWriter(TaskAttemptContext arg0)
             throws IOException, InterruptedException {
          // TODO Auto-generated method stub
          return null;
       }
    } 
复合健——用户自定义类型。
从前面的整个过程中可以看到,都是采用key-value的方式进行传入传出,而这些类型大多是单一的字符串,和整型。如果我的key中需要包含多个信息怎么办?用字符串直接拼接么? 太不方便了,最好能够自己定义一个类,作为这个key,这样就方便了。 如果定义一个


类作为key 或value的类型? 有什么要求?就是这个类型必须要继承WritableComparable<T>这个类,所以如果要自定义一个类型则可以这么实现:
    public class MyType implements WritableComparable<MyType> {
       private float x,y;
       public float GetX(){return x;}
       public float GetY(){return y;}
          @Override
          public void readFields(DataInput in) throws IOException {
             x = in.readFloat();
             y = in.readFloat();
          }
          @Override
          public void write(DataOutput out) throws IOException {
             out.writeFloat(x);
             out.writeFloat(y);
          }
          @Override
          public int compareTo(MyType arg0) {
             //输入:-1(小于) 0(等于) 1(大于)
             return 0;
          }
       } 
这个示例中,我们添加了两个float变量:x,y 。 这个信息能过int 和out按次序进行输入输出。最后,再实现一个比较函数即可。
Job任务的创建
    Job job = new Job(conf, "word count");
       job.setJarByClass(WordCount.class);
       job.setInputFormatClass(MyInputFormat.class);
       job.setMapperClass(TokenizerMapper.class);
       job.setCombinerClass(IntSumReducer.class);
       job.setPartitionerClass(MyPartitioner.class);
       job.setReducerClass(IntSumReducer.class);
       job.setOutputFormatClass(TextOutputFormat.class);
       job.setOutputKeyClass(Text.class);
       job.setOutputValueClass(IntWritable.class);
       FileInputFormat.addInputPath(job, new Path(otherArgs[0]));
       FileOutputFormat.setOutputPath(job, new Path(otherArgs[1])); 
任务创建比较容易,其实就是new一个实例,然后把上面描述的过程类设置好,然后加上第2行中,jar包的主类,第10、11行的输入输出路径。这样就完事了。
Job任务的执行
单个任务的执行,没有什么问题,可以用这个:
    job.waitForCompletion(true);
但多个任务呢? 多个任务的话,就会形成其组织方式,有串行,有并行,有无关,有组合的,如下图:


图中,Job2和Job3将会等Job1执行完了再执行,且可以同时开始,而Job4必须等Job2和Job3同时结束后才结束。
这个组合,就可以采用这样的代码来实现:
    Configuration conf = new Configuration();
          Job job1 = new Job(conf, "job1");
          //.. config Job1
          Job job2 = new Job(conf, "job2");
          //.. config Job2
          Job job3 = new Job(conf, "job3");
          //.. config Job3
          Job job4 = new Job(conf, "job4");
          //.. config Job4
          //添加依赖关系
          job2.addDependingJob(job1);
          job3.addDependingJob(job1);
          job4.addDependingJob(job2);
          job4.addDependingJob(job3);
          JobControl jc = new JobControl("jbo name");
          jc.addJob(job1);
          jc.addJob(job2);
          jc.addJob(job3);
          jc.addJob(job4);
          jc.run(); 
总述
现在回头看看,其实整个hadoop编程,也就是这几块内容了,要实现某个功能,我们就往上面这些步骤上套,然后联起来执行,达到我们的目的。


========

hadoop 本地库 说明



问题导读
1.hadoop本地库支持哪些平台?
2.本地库是否有32,64之分?
3.hadoop通过什么工具来检测本地库是否加载正确?
4.如何加载本地库?包含哪些步骤?
5.本地库在什么情况下不需要使用DistibutedCache?


概述


这个指南描述了hadoop本地库,包括关于共享本地库的小讨论。


注意:
取决于你的环境,这个词 “native libraries”涉及所有的*.so’,你需要编译;这个词 “native compression”涉及所有的*.so’的你需要编译指定与压缩相关的。当前,尽管如此,这个文档仅限于hadoop本地库 (libhadoop.so).文档为libhdfs库(libhdfs.so)点


这 here.


hadoop本地库


处于性能考虑和非可用性 Java 实现,Hadoop的具有某些部件的本地实现,这些组件单独是可用的。动态链接库调用本地原生Hadoop库。 在 *nix(如:Linux,unix) 平台上本地库名字为 libhadoop.so.


用法
相当容易使用hadoop本地库:
1.查看组件
2.查看支持平台
3.下载一个构建好的hadoop发布版本或则自己构建本地库。无论是自己下载还是自己构建(编译),本地的名字是相同的: libhadoop.so
4.安装压缩编解码开发包(> > zlib-1.2,gzip-1.2):
如果你下载本地库,安装一个或则多个开发包,无论压缩编解码你想用于部署。
如果你想编译本地库,它是强制性安装了开发包。
5.检查运行时日志文件


组件


本地库包含各种组件:
Compression Codecs (bzip2, lz4, snappy, zlib)
Native IO utilities for HDFS Short-Circuit Local Reads and Centralized Cache Management in HDFS
CRC32 校验实现


支持平台


hadoop本地库仅支持在*nix平台上,不支持 Cygwin和Mac OS X 平台.
hadoop本地库主要用在GNU/Linus平台,已测试


RHEL4/Fedora
Ubuntu
Gentoo
上面hadoop 32/64位本地库与相应的32/64 位 jvm工作




下载


hadoop预构建 32-位 i386-Linux本地库作为hadoop分布式一部分是有效的,位于e lib/native目录。你可以下载从hadoop Common Releases.
一定要安装zlib和/或gzip 开发包 


构建
hadoop本地库是用ANSI C编写,并使用GNU自动工具链 (autoconf, autoheader, automake, autoscan, libtool)构建。这意味着他可以直接使用工具链 (autoconf, autoheader, automake, autoscan, libtool)在任何平台上构建(查看支持平台)
在平台上包需要安装:
C compiler (e.g. GNU C Compiler)
GNU Autools Chain: autoconf, automake, libtool
zlib-development package (stable version >= 1.2.0)
openssl-development package(e.g. libssl-dev)




一旦你安装必备包使用标准的Hadoop的pom.xml文件,通过本地库标识构建hadoop本地库
[Bash shell] 纯文本查看 复制代码
?
1
$ mvn package -Pdist,native -DskipTests -Dtar


你可以查看新构建的库在
[Bash shell] 纯文本查看 复制代码
?
1
$ hadoop-dist/target/hadoop-2.7.1/lib/native




请注意以下几点:
1.它强制安装 zlib 和 gzip 开发包在目标平台,构建hadoop本地库。尽管如此,如果你想安装部署使用一个codec包,也是足够的。
2.为了构建和部署hadoop本地库,使用正确的zlib 32/64位 库是需要的 ,在目标平台上依赖32/64 位 jvm,


运行时
bin/hadoop脚本确保hadoop本地库通过系统属性-Djava.library.path=<path>在库路径。
在运行时,检查hadoop MapReduce任务日志文件
1.如果所有的事情准备好,然后调试util.NativeCodeLoader ,尝试加载自定义构建本地库。。。 INFO util.NativeCodeLoader - Loaded the native-hadoop library
2.如果产生错误,然后:INFO util.NativeCodeLoader - Unable to load native-hadoop library for your platform... using builtin-java classes where applicable


检查


NativeLibraryChecker是一个工具用来检测本地库是否加载正确,你可以启动nativelibrarychecker如下:


[Bash shell] 纯文本查看 复制代码
$ hadoop checknative -a
14/12/06 01:30:45 WARN bzip2.Bzip2Factory: Failed to load/initialize native-bzip2 library system-native, will use pure-Java version
14/12/06 01:30:45 INFO zlib.ZlibFactory: Successfully loaded & initialized native-zlib library
Native library checking:
hadoop: true /home/ozawa/hadoop/lib/native/libhadoop.so.1.0.0
zlib:   true /lib/x86_64-linux-gnu/libz.so.1
snappy: true /usr/lib/libsnappy.so.1
lz4:    true revision:99
bzip2:  false




本地共享库


你可以加载任何本地共享库使用DistributedCache,分发和符号链接库文件
这个例子展示了如何分发共享本地库mylib.so,和从mapreduc任务加载的。1.首先复制库到hdfs:bin/hadoop fs -copyFromLocal mylib.so.1 /libraries/mylib.so.1
2.job启动程序应该包含下面:
[Bash shell] 纯文本查看 复制代码
?


DistributedCache.createSymlink(conf);
DistributedCache.addCacheFile("hdfs://host:port/libraries/mylib.so. 1#mylib.so", conf);


3.MapReduce 任务应该包含:
[Bash shell] 纯文本查看 复制代码
?


System.loadLibrary("mylib.so");


注意:
如果你下载或则构建了hadoop本地库,不需要使用DistibutedCache使库提供给mapreduce任务


版本:2.7.1 
========


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值