在SIP目设计的过E中Q对于它庞大的日志在开始时p虑使用d分解的多U程处理模式来分析统计,在我从前写的文章《Tiger Concurrent Practice --日志分析q行分解设计与实现》中有所提到。但是由于统计的内容暂时q是十分单,所以就采用Memcache作ؓ计数器,l合MySQL完成了讉K 控制以及l计的工作。然而未来,对于量日志分析的工作,q是需要有所准备。现在最火的技术词汇莫q于“云计?#8221;Q在Open API日益盛行的今天,互联|应用的数据会来有价|如何d析这些数据,挖掘其内在h|需要分布式计算来支撑v量数据的分析工作?/p>
回过头来看,早先那种多线E,多Q务分解的日志分析设计Q其实是分布式计的一个单机版~略Q如何将q种单机的工作进行分拆,变成协同工作的集, 其实是分布式计框架设计所涉及的。在d参加BEA大会的时候,BEA和VMWare合作采用虚拟机来构徏集群Q无非就是希望得计机g能够cM 于应用程序中资源池的资源Q用者无需兛_资源的分配情况,从而最大化了硬件资源的使用价倹{分布式计算也是如此Q具体的计算d交由哪一台机器执行,? 行后p来汇总,q都由分布式框架的Master来抉择,而用者只需单地待分析内容提供l分布式计算pȝ作ؓ输入Q就可以得到分布式计后的结果?/p>
Hadoop是Apache开源组l的一个分布式计算开源框Ӟ在很多大型网站上都已l得C应用Q如亚马逊、Facebook和Yahoo{等? 对于我来_最q的一个用点是服务集成q_的日志分析。服务集成^台的日志量将会很大,而这也正好符合了分布式计的适用场景Q日志分析和索引建立? 是两大应用场景)?/p>
当前没有正式定使用Q所以也是自׃余摸索,后箋所写的相关内容Q都是一个新手的学习q程Q难免会有一些错误,只是希望记录下来可以分nl更多志同道合的朋友?/p>
搞什么东西之前,W一步是要知道WhatQ是什么)Q然后是WhyQؓ什么)Q最后才是HowQ怎么做)。但很多开发的朋友在做了多q项目以后,都习惯是先HowQ然后WhatQ最后才是WhyQ这样只会让自己变得躁Q同时往往会将技术误用于不适合的场景?/p>
Hadoop框架中最核心的设计就是:MapReduce和HDFS。MapReduce的思想是由Google的一论文所提及而被qؓ传的, 单的一句话解释MapReduce是“d的分解与l果的汇?#8221;。HDFS是Hadoop分布式文件系l(Hadoop Distributed File SystemQ的~写Qؓ分布式计存储提供了底层支持?/p>
MapReduce从它名字上来看就大致可以看出个缘由,两个动词Map和ReduceQ?#8220;MapQ展开Q?#8221;是一个Q务分解成为多个Q
务,“Reduce”是分解后多Q务处理的l果汇总v来,得出最后的分析l果。这不是什么新思想Q其实在前面提到的多U程Q多d的设计就可以扑ֈq?
U思想的媄子。不论是现实C会Q还是在E序设计中,一工作往往可以被拆分成为多个Q务,d之间的关pd以分ZU:一U是不相关的dQ可以ƈ行执
行;另一U是d之间有相互的依赖Q先后顺序不能够颠倒,q类d是无法ƈ行处理的。回到大学时期,教授上课时让大家d析关键\径,无非是找最省时?
d分解执行方式。在分布式系l中Q机器集就可以看作g资源池,ƈ行的d拆分Q然后交由每一个空闲机器资源去处理Q能够极大地提高计算效率Q同?
q种资源无关性,对于计算集群的扩展无疑提供了最好的设计保证。(其实我一直认为Hadoop的卡通图标不应该是一个小象,应该是蚂蚁,分布式计就好比
蚂蚁吃大象,廉h的机器群可以ҎM高性能的计机Q纵向扩展的曲线始终敌不q横向扩展的斜线Q。Q务分解处理以后,那就需要将处理以后的结果再汇总v
来,q就是Reduce要做的工作?/p>
上图是MapReduce大致的结构图Q在Map前还可能会对输入的数据有SplitQ分Ԍ的过E,保证dq行效率Q在Map之后q会有ShuffleQ合)的过E,对于提高Reduce的效率以及减数据传输的压力有很大的帮助。后面会具体提及q些部分的细节?/p>
HDFS是分布式计算的存储基矻IHadoop的分布式文gpȝ和其他分布式文gpȝ有很多类似的特质。分布式文gpȝ基本的几个特点: 上图中展C整个HDFS三个重要角色QNameNode、DataNode和Client。NameNode可以看作是分布式文gpȝ中的理
者,主要负责理文gpȝ的命名空间、集配|信息和存储块的复制{。NameNode会将文gpȝ的Meta-data存储在内存中Q这些信息主要包?
了文件信息、每一个文件对应的文g块的信息和每一个文件块在DataNode的信息等。DataNode是文件存储的基本单元Q它Block存储在本?
文gpȝ中,保存了Block的Meta-dataQ同时周期性地所有存在的Block信息发送给NameNode。Client是需要获取分布式?
件系l文件的应用E序。这里通过三个操作来说明他们之间的交互关系?/p>
文g写入Q?/strong> 文gdQ?/strong> 文gBlock复制Q?/strong> 最后再说一下HDFS的几个设计特点(对于框架设计值得借鉴Q: 下面l合MapReduce和HDFS来看Hadoop的结构: 在Hadoop的系l中Q会有一台MasterQ主要负责NameNode的工作以及JobTracker的工作。JobTracker的主要职?
是启动、跟t和调度各个Slave的Q务执行。还会有多台SlaveQ每一台Slave通常hDataNode的功能ƈ负责TaskTracker?
工作。TaskTrackerҎ应用要求来结合本地数据执行Mapd以及Reduced?/p>
说到q里Q就要提到分布式计算最重要的一个设计点QMoving Computation is Cheaper than Moving
Data。就是在分布式处理中Q移动数据的代hL高于转移计算的代仗简单来说就是分而治之的工作Q需要将数据也分而存储,本地d处理本地数据然后?
总,q样才会保证分布式计的高效性?/p>
说完了WhatQ简单地说一下Why。官方网站已l给了很多的说明Q这里就大致说一下其优点及用的场景Q没有不好的工具Q只用不适用的工P因此选择好场景才能够真正发挥分布式计的作用Q: 使用场景Q?/strong>个h觉得最适合的就是v量数据的分析Q其实Google最早提出MapReduce也就是ؓ了v量数
据分析。同时HDFS最早是Z搜烦引擎实现而开发的Q后来才被用于分布式计算框架中。v量数据被分割于多个节点,然后由每一个节点ƈ行计,得出的l?
果归q到输出。同时第一阶段的输出又可以作ؓ下一阶段计算的输入,因此可以惌C个树状结构的分布式计图Q在不同阶段都有不同产出Q同时ƈ行和串行l?
合的计算也可以很好地在分布式集群的资源下得以高效的处理?/p>
其实参看Hadoop官方文档已经能够很容易配|分布式框架q行环境了,不过q里既然写了再多写一点,同时有一些细节需要注意的也说明一下,其实
也就是这些细节会让h摸烦半天。Hadoop可以单机跑,也可以配|集跑Q单׃需要多说了Q只需要按照Demo的运行说明直接执行命令即可。这?
主要重点说一下集配|运行的q程?/p>
7台普通的机器Q操作系l都是Linux。内存和CPU׃说了Q反正Hadoop一大特点就是机器在多不在精。JDK必须?.5以上的,q个切记?台机器的机器名务必不同,后箋会谈到机器名对于MapReduce有很大的影响?/p>
正如上面我描q的Q对于Hadoop的集来_可以分成两大c角ԌMaster和SlaveQ前者主要配|NameNode?
JobTracker的角Ԍ负责ȝ分布式数据和分解d的执行,后者配|DataNode和TaskTracker的角Ԍ负责分布式数据存储以及Q
务的执行。本来我打算看看一台机器是否可以配|成MasterQ同时也作ؓSlave使用Q不q发现在NameNode初始化的q程中以?
TaskTracker执行q程中机器名配置好像有冲H(NameNode和TaskTracker对于Hosts的配|有些冲H,I竟是把机器名对?
IP攑֜配置前面q是把Localhost对应IP攑֜前面有点问题Q不q可能也是我自己的问题吧Q这个大家可以根据实施情늻我反馈)。最后反正决定一
台MasterQ六台SlaveQ后l复杂的应用开发和试l果的比对会增加机器配置?/p>
Hadoop的基配置文g?code>hadoop-default.xmlQ看Hadoop的代码可以知道,默认建立一个Job的时候会建立Job的ConfigQConfig首先d 以下是一个简单的 配置你的Java路径Q记住一定要1.5版本以上Q免得莫名其妙出现问题?/p>
Masters中配|Masters的IP或者机器名Q如果是机器名那么需要在 以上步骤可以启动Hadoop的分布式环境Q然后在Master的机器进入Master的安装目录,执行 l验ȝ和注意事(q部分是我在使用q程中花了一些时间走的弯路)Q?/p>
ȝ来说Z问题或者启动的时候最好去看看日志Q这样心里有底?/p>
q部分内容其实可以通过命o的Help以及介绍了解Q我主要侧重于介l一下我用的比较多的几个命o。Hadoop dfs q个命o后面加参数就是对于HDFS的操作,和Linux操作pȝ的命令很cMQ例如: 其他׃详细介绍了?/p>
一个图片太大了Q只好分割成Z部分。根据流E图来说一下具体一个Q务执行的情况?/p>
业务场景描述Q?/strong>可设定输入和输出路径Q操作系l的路径非HDFS路径Q,Ҏ讉K日志分析某一个应用访问某一个API的L数和L量,l计后分别输出到两个文g中。这里仅仅ؓ了测试,没有ȝ分很多类Q将所有的c都归ƈ于一个类便于说明问题?/p>
LogAnalysiser是ȝQ主要负责创建、提交Q务,q且输出部分信息。内部的几个子类用途可以参看流E中提到的角色职责。具体地看看几个cdҎ的代码片断: LogAnalysiser::MapClass LogAnalysiser:: PartitionerClass LogAnalysiser:: CombinerClass 参看ReduceClassQ通常两者可以用一个,不过q里有些不同的处理就分成了两个。在ReduceClass中蓝色的行表C在CombinerClass中不存在?/p>
LogAnalysiser:: ReduceClass LogAnalysiser 以上的代码就完成了所有的逻辑性代码,然后q需要一个注册驱动类来注册业务ClassZ个可标示的命令,让hadoop jar可以执行?/p>
代码打成jarQƈ且设|jar的mainClass为ExampleDriverq个cR在分布式环境启动以后执行如下语句: ?home/wenchu/test-in中是需要分析的日志文gQ执行后׃看见整个执行q程Q包括了Map和Reduce的进度。执行完毕会
?home/wenchu/test-out下看到输出的内容。有两个文gQpart-00000和part-00001分别记录了统计后的结果?
如果需要看执行的具体情况,可以看在输出目录下的_logs/history/xxxx_analysisjobQ里面罗列了所有的MapQReduce
的创建情况以及执行情c在q行期也可以通过览器来查看Map,Reduce的情况:http://MasterIP:50030
/jobtracker.jsp 首先q里使用上面的范例作为测试,也没有做太多的优化配|,q个试l果只是Z看看集群的效果,以及一些参数配|的影响?/p>
文g复制Cؓ1Qblocksize 5M Blocksize 5M 文g复制Cؓ1 试的数据结果很E_Q基本测几次同样条g下都是一栗通过试l果可以看出以下几点Q?/p>
“云计?#8221;热的烫手Q就和SAAS、Web2及SNS{一P往往都是在搞概念Q只有真正踏t实实的大型互联|公司,才会投入人力物力ȝI符合自
q分布式计。其实当你的数据量没有那么大的时候,q种分布式计也׃仅只是一个玩兯已Q只有在真正解决问题的过E中Q它深层ơ的问题才会被挖掘出
来?/p>
q三文章(分布式计开源框架Hadoop介绍QHadoop中的集群配置和用技巧)仅仅是ؓ了给对分布式计算有兴的朋友抛个砖,要想真的掘到?
子,那么pt实实的ȝ、去惟뀁去分析。或者自׃会更q一步地ȝI框架中的实现机Ӟ在解册己问题的同时Q也能够贡献一些什么?/p>
前几日看到有求成为架构师的方式,看了有些可悲Q有些可W,其实有多架构师知道什么叫做架构?架构师的职责是什么?与其q求q么一个名Pq不如踏t实实地做块矛_沉到水底。要知道Q积累和沉淀的过E就是一U成ѝ?/p>
?QMapReducel构C意?/strong>
?QHDFSl构C意?/strong>
?QHadoopl构C意?/strong>Z么要选择HadoopQ?/h2>
环境
部v考虑
实施步骤
hadoop-env.sh
Q?code>hadoop-site.xml?code>masters?code>slaves?
hadoop-default.xml
的配|,然后再读?code>hadoop-site.xml的配|(q个文g初始的时候配|ؓI)Q?code>hadoop-site.xml中主要配|你需要覆盖的hadoop-default.xml
的系l配置Q以及你需要在你的MapReduceq程中用的自定义配|(具体的一些用例如final{参考文档)?/p>
hadoop-site.xml
的配|:<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<!-- Put site-specific property overrides in this file. -->
<configuration>
<property>
<name>fs.default.name</name>//你的namenode的配|,机器名加端口
<value>hdfs://10.2.224.46:54310/</value>
</property>
<property>
<name>mapred.job.tracker</name>//你的JobTracker的配|,机器名加端口
<value>hdfs://10.2.224.46:54311/</value>
</property>
<property>
<name>dfs.replication</name>//数据需要备份的数量Q默认是?br />
<value>1</value>
</property>
<property>
<name>hadoop.tmp.dir</name>//Hadoop的默认时\径,q个最好配|,如果在新增节Ҏ者其他情况下莫名其妙的DataNode启动不了Q就删除此文件中的tmp目录卛_。不q如果删除了NameNode机器的此目录Q那么就需要重新执行NameNode格式化的命o?br />
<value>/home/wenchu/hadoop/tmp/</value>
</property>
<property>
<name>mapred.child.java.opts</name>//java虚拟机的一些参数可以参照配|?br />
<value>-Xmx512m</value>
</property>
<property>
<name>dfs.block.size</name>//block的大,单位字节Q后面会提到用处Q必L512的倍数Q因为采用crc作文件完整性校验,默认配置512是checksum的最单元?br />
<value>5120000</value>
<description>The default block size for new files.</description>
</property>
</configuration>hadoop-env.sh
文g只需要修改一个参敎ͼ# The java implementation to use. Required.
export JAVA_HOME=/usr/ali/jdk1.5.0_10
/etc/hosts
中有所讄。Slaves中配|的是Slaves的IP或者机器名Q同样如果是机器名需要在/etc/hosts
中有所讄。范例如下,我这里配|的都是IPQ?/p>
Masters:
10.2.224.46
Slaves:
10.2.226.40
10.2.226.39
10.2.226.38
10.2.226.37
10.2.226.41
10.2.224.36 ssh-keygen -t rsa
。执行此命o的时候,看到提示只需要回车。然后就会在/root/.ssh/
下面产生id_rsa.pub
的证书文Ӟ通过scpMaster机器上的q个文g拯到Slave上(记得修改名称Q,例如Q?code>scp root@masterIP:/root/.ssh/id_rsa.pub /root/.ssh/46_rsa.pubQ然后执?code>cat /root/.ssh/46_rsa.pub >>/root/.ssh/authorized_keysQ徏?code>authorized_keys?
件即可,可以打开q个文g看看Q也是rsa的公钥作为keyQuser@IP作ؓvalue。此时可以试验一下,从master
ssh到slave已经不需要密码了。由slave反向建立也是同样。ؓ什么要反向呢?其实如果一直都是Master启动和关闭的话那么没有必要徏立反
向,只是如果惛_Slave也可以关闭Hadoop需要徏立反向?/li>
hadoop-env.sh
?/li>
新增以下内容Q(具体的内Ҏ据你的安装\径修改,q步只是Z方便使用Q?br />
修改完毕后,执行export HADOOP_HOME=/home/wenchu/hadoop-0.17.1
export PATH=$PATH:$HADOOP_HOME/bin
source /etc/profile
来其生效?/li>
hadoop.tmp.dir
目录Q否则是不需要再ơ执行的?/li>
start-all.sh
Q这个命令可以直接执行,因ؓ?中已l添加到了path路径Q这个命令是启动hdfs和mapreduce两部分,当然你也可以分开单独启动hdfs和mapreduceQ分别是bin目录下的start-dfs.sh
?code>start-mapred.sh?/li>
hadoop jar hadoop-0.17.1-examples.jar wordcount
输入路径和输\径,可以看到字数统计的效果了。此处的输入路径和输\径都指的是HDFS中的路径Q因此你可以首先通过拯本地文gpȝ中的目录到HDFS中的方式来徏立HDFS中的输入路径Q?/p>
hadoop dfs -copyFromLocal /home/wenchu/test-in test-in?/code>其中
Q然后重新启动试试看Q如果还是不行那干脆把Master?code>hadoop.tmp.dir删除Q意味着dfs上的数据也会丢失Q,如果删除了Master?code>hadoop.tmp.dirQ那么就需要重?code>namenode –format?/li>
/home/wenchu/test-in
是本地\径,test-in
是将会徏立在HDFS中的路径Q执行完毕以后可以通过hadoop dfs –ls
看到test-in目录已经存在Q同时可以通过hadoop dfs –ls test-in
查看里面的内宏V输\径要求是在HDFS中不存在的,当执行完那个demo以后Q就可以通过hadoop dfs –ls
输出路径看到其中的内容,具体文g的内容可以通过hadoop dfs –cat
文g名称来查看?/p>
/etc/hosts
中必L集群中机器都配置上去Q就在各个配置文g?
使用的是IP。这个吃q不苦_原来以ؓ如果配成IP׃需要去配置HostQ结果发现在执行Reduce的时候L卡住Q在拯的时候就无法l箋?
去,不断重试。另外如果集中如果有两台机器的机器名如果重复也会出现问题?/li>
dfs.block.size
应该?4MQ也是说如果你攄到HDFS上的数据于64Q那么将只有一个BlockQ此时会被放|到某一个DataNode中,q个可以通过使用命oQ?code>hadoop dfsadmin –report可以看到各个节点存储的情况。也可以直接L一个DataNode查看目录Q?code>hadoop.tmp.dir/dfs/data/current?
可以看到那些block了。Block的数量将会直接媄响到Map的个数。当然可以通过配置来设定Map和Reduce的Q务个数。Map的个数通常默认
和HDFS需要处理的blocks相同。也可以通过配置Map的数量或者配|minimum split size来设定,实际的个CؓQ?code>max(min(block_size,data/#maps),min_split_size)。Reduce可以通过q个公式计算Q?code>0.95*num_nodes*mapred.tasktracker.tasks.maximum?/li>
Hadoop中的命oQCommandQȝ
Hadoop dfs –ls
是查看/usr/root目录下的内容Q默认如果不填\径这是当前用户路径Q?/li>
Hadoop dfs –rmr xxx
是删除目录Q还有很多命令看看就很容易上手;Hadoop dfsadmin –report
q个命o可以全局的查看DataNode的情况;Hadoop job
后面增加参数是对于当前运行的Job的操作,例如list,kill{;Hadoop balancer
是前面提到的均衡磁盘负载的命o?/li>
Hadoop基本程
业务场景和代码范?/h2>
试代码cd public static class MapClass extends MapReduceBase
implements Mapper<LongWritable, Text, Text, LongWritable>
{
public void map(LongWritable key, Text value, OutputCollector<Text, LongWritable> output, Reporter reporter)
throws IOException
{
String line = value.toString();//没有配置RecordReaderQ所以默认采用line的实玎ͼkey是行号Qvalue是行内?br />
if (line == null || line.equals(""))
return;
String[] words = line.split(",");
if (words == null || words.length < 8)
return;
String appid = words[1];
String apiName = words[2];
LongWritable recbytes = new LongWritable(Long.parseLong(words[7]));
Text record = new Text();
record.set(new StringBuffer("flow::").append(appid)
.append("::").append(apiName).toString());
reporter.progress();
output.collect(record, recbytes);//输出量的统计结果,通过flow::作ؓ前缀来标C?br />
record.clear();
record.set(new StringBuffer("count::").append(appid).append("::").append(apiName).toString());
output.collect(record, new LongWritable(1));//输出ơ数的统计结果,通过count::作ؓ前缀来标C?br />
}
}
public static class PartitionerClass implements Partitioner<Text, LongWritable>
{
public int getPartition(Text key, LongWritable value, int numPartitions)
{
if (numPartitions >= 2)//Reduce 个数Q判断流量还是次数的l计分配C同的Reduce
if (key.toString().startsWith("flow::"))
return 0;
else
return 1;
else
return 0;
}
public void configure(JobConf job){}
} public static class ReduceClass extends MapReduceBase
implements Reducer<Text, LongWritable,Text, LongWritable>
{
public void reduce(Text key, Iterator<LongWritable> values,
OutputCollector<Text, LongWritable> output, Reporter reporter)throws IOException
{
Text newkey = new Text();
newkey.set(key.toString().substring(key.toString().indexOf("::")+2));
LongWritable result = new LongWritable();
long tmp = 0;
int counter = 0;
while(values.hasNext())//累加同一个key的统计结?br />
{
tmp = tmp + values.next().get();
counter = counter +1;//担心处理太久QJobTracker长时间没有收到报告会认ؓTaskTracker已经失效Q因此定时报告一?br />
if (counter == 1000)
{
counter = 0;
reporter.progress();
}
}
result.set(tmp);
output.collect(newkey, result);//输出最后的汇ȝ?br />
}
} public static void main(String[] args)
{
try
{
run(args);
} catch (Exception e)
{
e.printStackTrace();
}
}
public static void run(String[] args) throws Exception
{
if (args == null || args.length <2)
{
System.out.println("need inputpath and outputpath");
return;
}
String inputpath = args[0];
String outputpath = args[1];
String shortin = args[0];
String shortout = args[1];
if (shortin.indexOf(File.separator) >= 0)
shortin = shortin.substring(shortin.lastIndexOf(File.separator));
if (shortout.indexOf(File.separator) >= 0)
shortout = shortout.substring(shortout.lastIndexOf(File.separator));
SimpleDateFormat formater = new SimpleDateFormat("yyyy.MM.dd");
shortout = new StringBuffer(shortout).append("-")
.append(formater.format(new Date())).toString();
if (!shortin.startsWith("/"))
shortin = "/" + shortin;
if (!shortout.startsWith("/"))
shortout = "/" + shortout;
shortin = "/user/root" + shortin;
shortout = "/user/root" + shortout;
File inputdir = new File(inputpath);
File outputdir = new File(outputpath);
if (!inputdir.exists() || !inputdir.isDirectory())
{
System.out.println("inputpath not exist or isn't dir!");
return;
}
if (!outputdir.exists())
{
new File(outputpath).mkdirs();
}
JobConf conf = new JobConf(new Configuration(),LogAnalysiser.class);//构徏Config
FileSystem fileSys = FileSystem.get(conf);
fileSys.copyFromLocalFile(new Path(inputpath), new Path(shortin));//本地文件系l的文g拯到HDFS?br />
conf.setJobName("analysisjob");
conf.setOutputKeyClass(Text.class);//输出的keycdQ在OutputFormat会检?br />
conf.setOutputValueClass(LongWritable.class); //输出的valuecdQ在OutputFormat会检?br />
conf.setMapperClass(MapClass.class);
conf.setCombinerClass(CombinerClass.class);
conf.setReducerClass(ReduceClass.class);
conf.setPartitionerClass(PartitionerClass.class);
conf.set("mapred.reduce.tasks", "2");//强制需要有两个Reduce来分别处理流量和ơ数的统?br />
FileInputFormat.setInputPaths(conf, shortin);//hdfs中的输入路径
FileOutputFormat.setOutputPath(conf, new Path(shortout));//hdfs中输\?br />
Date startTime = new Date();
System.out.println("Job started: " + startTime);
JobClient.runJob(conf);
Date end_time = new Date();
System.out.println("Job ended: " + end_time);
System.out.println("The job took " + (end_time.getTime() - startTime.getTime()) /1000 + " seconds.");
//删除输入和输出的临时文g
fileSys.copyToLocalFile(new Path(shortout),new Path(outputpath));
fileSys.delete(new Path(shortin),true);
fileSys.delete(new Path(shortout),true);
}
public class ExampleDriver {
public static void main(String argv[]){
ProgramDriver pgd = new ProgramDriver();
try {
pgd.addClass("analysislog", LogAnalysiser.class, "A map/reduce program that analysis log .");
pgd.driver(argv);
}
catch(Throwable e){
e.printStackTrace();
}
}
}hadoop jar analysiser.jar analysislog /home/wenchu/test-in /home/wenchu/test-out
Hadoop集群试
Slave?/td>
处理记录?万条)
执行旉Q秒Q?/td>
2
95
38
2
950
337
4
95
24
4
950
178
6
95
21
6
950
114
Slave?/td>
处理记录?万条)
执行旉Q秒Q?/td>
2Q文件复制数?Q?/td>
950
337
2Q文件复制数?Q?/td>
950
339
6Q文件复制数?Q?/td>
950
114
6Q文件复制数?Q?/td>
950
117
Slave?/td>
处理记录?万条)
执行旉Q秒Q?/td>
6(blocksize 5M)
95
21
6(blocksize 77M)
95
26
4(blocksize 5M)
950
178
4(blocksize 50M)
950
54
6(blocksize 5M)
950
114
6(blocksize 50M)
950
44
6(blocksize 77M)
950
74
随想
作ؓHadoopE序员,他要做的事情是Q?br /> 1、定义MapperQ处理输入的Key-Value对,输出中间l果?br /> 2、定义ReducerQ可选,对中间结果进行规U,输出最l结果?br /> 3、定义InputFormat 和OutputFormatQ可选,InputFormat每行输入文件的内容转换为JavacMMapper函数使用Q不定义旉认ؓString?br /> 4、定义main函数Q在里面定义一个Jobq运行它?br />
然后的事情就交给pȝ了?br />
1.基本概念QHadoop的HDFS实现了google的GFS文gpȝQNameNode作ؓ文gpȝ的负责调度运行在
masterQDataNodeq行在每个机器上。同时Hadoop实现了Google的MapReduceQJobTracker作ؓ
MapReduce的总调度运行在masterQTaskTracker则运行在每个机器上执行Task?br />
2.main()函数Q创建JobConfQ定义MapperQReducerQInput/OutputFormat 和输入输出文件目录,最后把Job提交iJobTrackerQ等待Jobl束?br />
3.JobTrackerQ创Z个InputFormat的实例,调用它的getSplits()ҎQ把输入目录的文件拆分成FileSplist作ؓMapper task 的输入,生成Mapper task加入Queue?br />
4.TaskTracker ?JobTracker索求下一个Map/Reduce?br />
Mapper Task先从InputFormat创徏RecordReaderQ@环读入FileSplits的内容生成Key与ValueQ传lMapper函数Q处理完后中间结果写成SequenceFile.
Reducer Task 从运行Mapper的TaskTracker的Jetty上用http协议获取所需的中间内容(33%Q,Sort/Merge后(66%Q,执行Reducer函数Q最后按照OutputFormat写入l果目录?
TaskTracker ?0U向JobTracker报告一ơ运行情况,每完成一个Task10U后Q就会向JobTracker索求下一个Task?/p>
Nutch目的全部数据处理都构徏在Hadoop之上Q详?a >Scalable Computing with Hadoop?/p>
我们做一个简单的分布式的GrepQ简单对输入文gq行逐行的正则匹配,如果W合将该行打印到输出文件。因为是单的全部输出Q所以我们只要写Mapper函数Q不用写Reducer函数Q也不用定义Input/Output Format?/p>
RegMappercȝconfigure()函数接受由main函数传入的查扑֭W串Qmap() 函数q行正则匚wQkey是行敎ͼvalue是文件行的内容,W合的文件行攑օ中间l果?br /> main()函数定义由命令行参数传入的输入输出目录和匚w字符ԌMapper函数为RegMapperc,Reduce函数是什么都不做Q直接把中间l果输出到最l结果的的IdentityReducerc,q行Job?/p>
整个代码非常单,丝毫没有分布式编E的Ml节?/strong>
Hadoopq方面的文档写得不全面,l合参?a >GettingStartedWithHadoop ?u>Nutch Hadoop Tutorial 两篇后,再碰了很多钉子才l于完整的跑h了,记录如下Q?nbsp;
3.1 localq行模式
完全不进行Q何分布式计算Q不动用Mnamenode,datanode的做法,适合一开始做调试代码?br />
解压hadoopQ其中conf目录是配|目录,hadoop的配|文件在hadoop-default.xmlQ如果要修改配置Q不是直接修改该文gQ而是修改hadoop-site.xmlQ将该属性在hadoop-site.xml里重新赋倹{?br />
hadoop-default.xml的默认配|已l是localq行Q不用Q何修改,配置目录里唯一必须修改的是hadoop-env.sh ?font face="Courier New">JAVA_HOME的位|?/p>
编译好的HadoopGrep与RegMapper.class 攑օhadoop/build/classes/demo/hadoop/目录 找一个比较大的log文g攑օ一个目录,然后q行
查看输出目录的结果,查看hadoop/logs/里的q行日志?nbsp;
在重新运行前Q先删掉输出目录?br />
3.2 单机集群q行模式
现在来搞一下只有单机的集群.假设以完?.1中的讄Q本机名为hadoopserver
W?? 然后修改hadoop-site.xml Q加入如下内容:
从此将q行从local文gpȝ转向了hadoop的hdfspȝQmapreduce的jobtracker也从local的进E内操作变成了分布式的Q务系l,9000Q?001两个端口h随便选择的两个空余端口号?br />
另外Q如果你?tmp目录不够大,可能q要修改hadoop.tmp.dir属性?/p>
W?? 增加ssh不输入密码即可登陆?br />
因ؓHadoop需要不用输入密码的ssh来进行调度,在不su的状态下Q在自己的home目录q行ssh-keygen -t rsa ,然后一路回车生成密钥,再进?ssh目录,cp id_rsa.pub authorized_keys
详细可以man 一下ssh, 此时执行ssh hadoopserverQ不需要输入Q何密码就能进入了?/p>
3.格式化namenodeQ执?br />
bin/hadoop namenode -format
4.启动Hadoop
执行hadoop/bin/start-all.sh, 在本机启动namenode,datanode,jobtracker,tasktracker
5.现在待查找的log文g攑օhdfs,?br />
执行hadoop/bin/hadoop dfs 可以看到它所支持的文件操作指令?br />
执行hadoop/bin/hadoop dfs put log文g所在目?in Q则log文g目录已放入hdfs?user/user-name/in 目录?/p>
6.现在来执行Grep操作
hadoop/bin/hadoop demo.hadoop.HadoopGrep in out
查看hadoop/logs/里的q行日志Q重新执行前。运行hadoop/bin/hadoop dfs rmr out 删除out目录?br />
7.q行hadoop/bin/stop-all.sh l束
3.3 集群q行模式
假设已执行完3.2的配|,假设W?台机器名是hadoopserver2
1.创徏与hadoopserver同样的执行用Phadoop解压到相同的目录?br />
2.同样的修改haoop-env.sh中的JAVA_HOME 及修改与3.2同样的hadoop-site.xml
3. hadoopserver中的/home/username/.ssh/authorized_keys 复制到hadoopserver2,保证hadoopserver可以无需密码登陆hadoopserver2
scp /home/username/.ssh/authorized_keys username@hadoopserver2:/home/username/.ssh/authorized_keys
4.修改hadoop-server的hadoop/conf/slaves文g, 增加集群的节点,localhost改ؓ
hadoop-server
hadoop-server2
5.在hadoop-server执行hadoop/bin/start-all.sh
会在hadoop-server启动namenode,datanode,jobtracker,tasktracker
在hadoop-server2启动datanode 和tasktracker
6.现在来执行Grep操作
hadoop/bin/hadoop demo.hadoop.HadoopGrep in out
重新执行?q行hadoop/bin/hadoop dfs rmr out 删除out目录
7.q行hadoop/bin/stop-all.sh l束?br />
l测试,Hadoopq不是万用灵丹,很取决于文g的大和数量Q处理的复杂度以及群集机器的数量Q相q的带宽Q当以上四者ƈ不大Ӟhadoop优势q不明显?br />
比如Q不用hadoop用java写的单grep函数处理100M的log文g只要4U,用了hadoop local的方式运行是14U,用了hadoop单机集群的方式是30U,用双机集?0M|口的话更慢Q慢C好意思说出来的地步?/p>