posts - 28, comments - 37, trackbacks - 0, articles - 0

2011年11月28日


淘宝招聘hadoop工程师若干, 面向在校生(2014年毕业),工作地点:杭州或北京

Hadoop研发工程师
职位描述
您将负责:
1.预研、开发、测试hdfs/mapreduce/hive/hbase的功能、性能和扩展;
2.对有助于提升集群处理能力/高可用性/高扩展性的各种解决方案进行跟踪和落地;
3.解决海量数据不断增长面临的挑战,解决业务需求。

您需要具备:
1、熟练运用java语言;
2、熟悉jvm运行机制、熟悉linux;
3、至少熟悉hadoop、hbase、hive等软件之一;

 

有意者请发送邮件到 yuling.sh@taobao.com 

posted @ 2013-09-15 18:21 俞灵 阅读(939) | 评论 (1)编辑 收藏


mapreduce,一个jobmap个数, 每个map处理的数据量是如何决定的呢? 另外每个map又是如何读取输入文件的内容呢? 用户是否可以自己决定输入方式, 决定map个数呢? 这篇文章将详细讲述hadoop中各种InputFormat的功能和如何编写自定义的InputFormat.

 

简介: mapreduce作业会根据输入目录产生多个map任务, 通过多个map任务并行执行来提高作业运行速度, 但如果map数量过少, 并行量低, 作业执行慢, 如果map数过多, 资源有限, 也会增加调度开销. 因此, 根据输入产生合理的map, 为每个map分配合适的数据量, 能有效的提升资源利用率, 并使作业运行速度加快.

    mapreduce, 每个作业都会通过 InputFormat来决定map数量. InputFormat是一个接口, 提供两个方法:

InputSplit[] getSplits(JobConf job, int numSplits) throws IOException;

RecordReader<K, V> getRecordReader(InputSplit split,

                                     JobConf job,

                                     Reporter reporter) throws IOException;

    其中getSplits方法会根据输入目录产生InputSplit数组, 每个InputSplit会相应产生一个map任务, map的输入定义在InputSplit. getRecordReader方法返回一个RecordReader对象, RecordReader决定了map任务如何读取输入数据, 例如一行一行的读取还是一个字节一个字节的读取, 等等.

    下图是InputFormat的实现类:

       (暂时无法上传)

    这理详细介绍FileInputFormatCombineFileInputFormat, 其它不常用,有兴趣的可以自己查看hadoop源码.


 

FileInputFormat(旧接口org.apache.hadoop.mapred)

 

mapreduce默认使用TextInputFormatTextInputFormat没有实现自己的getSplits方法,继承于FileInputFormat, 因此使用了FileInputFormat的.

org.apache.hadoop.mapred.FileInputFormatgetSplits流程:

两个配置

mapred.min.split.size        (一个map最小输入长度),

mapred.map.tasks                (推荐map数量)

如何决定每个map输入长度呢? 首先获取输入目录下所有文件的长度和, 除以mapred.map.tasks得到一个推荐长度goalSize, 然后通过式子: Math.max(minSize, Math.min(goalSize, blockSize))决定map输入长度. 这里的minSizemapred.min.split.size, blockSize为相应文件的block长度. 这式子能保证一个map的输入至少大于mapred.min.split.size, 对于推荐的map长度,只有它的长度小于blockSize且大于mapred.min.split.size才会有效果. 由于mapred.min.split.size默认长度为1, 因此通常情况下只要小于blockSize就有效果,否则使用blockSize做为map输入长度.

因此, 如果想增加map, 可以把mapred.min.split.size调小(其实默认值即可), 另外还需要把mapred.map.tasks设置大.

如果需要减少map,可以把mapred.min.split.size调大, 另外把mapred.map.tasks调小.

这里要特别指出的是FileInputFormat会让每个输入文件至少产生一个map任务, 因此如果你的输入目录下有许多文件, 而每个文件都很小, 例如几十kb, 那么每个文件都产生一个map会增加调度开销. 作业变慢.

那么如何防止这种问题呢? CombineFileInputFormat能有效的减少map数量.


FileInputFormat(新接口org.apache.hadoop.mapreduce.lib.input)

Hadoop 0.20开始定义了一套新的mapreduce编程接口, 使用新的FileInputFormat, 它与旧接口下的FileInputFormat主要区别在于, 它不再使用mapred.map.tasks, 而使用mapred.max.split.size参数代替goalSize, 通过Math.max(minSize, Math.min(maxSize, blockSize))决定map输入长度, 一个map的输入要大于minSize,小于

Math.min(maxSize, blockSize).

    若需增加map,可以把mapred.min.split.size调小,mapred.max.split.size调大. 若需减少map, 可以把mapred.min.split.size调大, 并把mapred.max.split.size调小.


CombineFileInputFormat

顾名思义, CombineFileInputFormat的作用是把许多文件合并作为一个map的输入.

在它之前,可以使用MultiFileInputFormat,不过其功能太简单, 以文件为单位,一个文件至多分给一个map处理, 如果某个目录下有许多小文件, 另外还有一个超大文件, 处理大文件的map会严重偏慢.

CombineFileInputFormat是一个被推荐使用的InputFormat. 它有三个配置:

mapred.min.split.size.per.node 一个节点上split的至少的大小

mapred.min.split.size.per.rack   一个交换机下split至少的大小

mapred.max.split.size             一个split最大的大小

它的主要思路是把输入目录下的大文件分成多个map的输入, 并合并小文件, 做为一个map的输入. 具体的原理是下述三步:

1.根据输入目录下的每个文件,如果其长度超过mapred.max.split.size,block为单位分成多个split(一个split是一个map的输入),每个split的长度都大于mapred.max.split.size, 因为以block为单位, 因此也会大于blockSize, 此文件剩下的长度如果大于mapred.min.split.size.per.node, 则生成一个split, 否则先暂时保留.

2. 现在剩下的都是一些长度效短的碎片,把每个rack下碎片合并, 只要长度超过mapred.max.split.size就合并成一个split, 最后如果剩下的碎片比mapred.min.split.size.per.rack, 就合并成一个split, 否则暂时保留.

3. 把不同rack下的碎片合并, 只要长度超过mapred.max.split.size就合并成一个split, 剩下的碎片无论长度, 合并成一个split.

举例: mapred.max.split.size=1000

     mapred.min.split.size.per.node=300

      mapred.min.split.size.per.rack=100

输入目录下五个文件,rack1下三个文件,长度为2050,1499,10, rack2下两个文件,长度为1010,80. 另外blockSize500.

经过第一步, 生成五个split: 1000,1000,1000,499,1000. 剩下的碎片为rack1:50,10; rack210:80

由于两个rack下的碎片和都不超过100, 所以经过第二步, split和碎片都没有变化.

第三步,合并四个碎片成一个split, 长度为150.

 

如果要减少map数量, 可以调大mapred.max.split.size, 否则调小即可.

其特点是: 一个块至多作为一个map的输入,一个文件可能有多个块,一个文件可能因为块多分给做为不同map的输入, 一个map可能处理多个块,可能处理多个文件。


编写自己的InputFormat

 

    待续


 

posted @ 2012-07-03 22:17 俞灵 阅读(16437) | 评论 (2)编辑 收藏

Yarn做为hadoop下一代集群资源管理和调度平台, 其上能支持多种计算框架, 本文就简要介绍一下这些计算框架.


1.       MapReduce

首先是大家熟悉的mapreduce, MR2之前, hadoop包括HDFSmapreduce, 做为hadoop上唯一的分布式计算框架, 其优点是用户可以很方便的编写分布式计算程序, 并支持许多的应用, hive, mahout, pig. 但是其缺点是无法充分利用集群资源, 不支持DAG, 迭代式计算等. 为了解决这些问题, yahoo提出了Yarn (next generation mapreduce), 一个分布式集群集群资源管理和调度平台. 这样除了mapreduce, 还可以支持各种计算框架.

2.       Spark

Spark是一种与mapreduce相似的开源计算框架, 不同之处在于Spark在某些工作负载方面表现更优, 因为它使用了内存分布式数据集, 另外除了提供交互式查询外, 它还可以优化迭代工作负载.

3.       Apache HAMA

Apache Hama 是一个运行在HDFS上的BSP(Bulk Synchronous Parallel大容量同步并行) 计算框架, 主要针对大规模科学计算,如矩阵, 图像, 网络算法等.当前它有一下功能:

  • 作业提交和管理接口
  • 单节点上运行多个任务
  • 输入/输出格式化
  • 备份恢复
  • 支持通过Apache Whirr运行在云端
  • 支持与Yarn一起运行

4.       Apache Giraph

图像处理平台上运行这大型算法(page rank, shared connections, personalization-based popularity )已经很流行, Giraph采用BSP模型(bulk-synchronous parallel model),可用于等迭代类算法。

5.       Open MPI

这是一个高性能计算函数库,通常在HPCHigh Performance Computing)中采用,与MapReduce相比,其性能更高,用户可控性更强,但编程复杂,容错性差,可以说,各有所长,在实际应用中,针对不同 该应用会采用MPI或者MapReduce

6.       Apache HBase

HBase是一个hadoop数据库, 其特点是分布式,可扩展的,存储大数据。当有需要随机,实时读写的大数据时, 使用HBase很适合.

本文参考:

http://wiki.apache.org/hadoop/PoweredByYarn
http://www.oschina.net/p/open+mpi

http://incubator.apache.org/hama/
http://incubator.apache.org/giraph/

http://hbase.apache.org/

posted @ 2012-06-03 11:43 俞灵 阅读(3637) | 评论 (0)编辑 收藏

转载
http://fujun.sinaapp.com/2011/11/02/68.html

第一步,打开终端,看看你的显卡Ubuntu能认出多少显示分辨率设置,输入命令

wufujun@wufujun-VirtualBox:~$ xrandr

系统给出的结果

Screen 0: minimum 64 x 64, current 1024 x 768, maximum 32000 x 32000
VBOX0 connected 1024×768+0+0 0mm x 0mm
1024×768 60.0 + 60.0
1600×1200 60.0
1440×1050 60.0
1280×960 60.0
800×600 60.0
640×480 60.0

这里可以看到,没有16:9的的分辨率设置

第二步,用cvt命令测试1368×768是否可用

wufujun@wufujun-VirtualBox:~$ cvt 1368 768

显示结果如下
# 1368×768 59.88 Hz (CVT) hsync: 47.79 kHz; pclk: 85.86 MHz
Modeline “1368x768_60.00″ 85.25 1368 1440 1576 1784 768 771 781 798 -hsync +vsync

从这个结果里可以到,16:9的分辨率是可以用的

第三步 输入

wufujun@wufujun-VirtualBox:~$ sudo xrandr --newmode "1368x768" 85.86 1368 1440 1576 1784 768 771 781 798 -hsync +vsync

建立新的分辨率模式1368×768,把刚才cvt得到的数据写进参数

第四步 继续输入

sudo xrandr --addmode VBOX0 "1368x768"

给当前显示器VBOX0增加1368×768分辨率设置

做完以上操作后,可以在”显示“设置里面看到显示的分辨率列表中多了一个 1368×768(16:9)的选项。选中这个选项,点击应用,完美的宽屏显示回来了!

经过测试,上面的方法做完以后,每次注销后就又变回了4:3的比例,而且会有的报错,没办法,按上面的修改完毕后,还要再修改一下/etc/X11/xorg.conf这个文件,这个配置文件在现在的版里已经取消了,所以需要我们新建一个


$ sudo gedit /etc/X11/xorg.conf

编辑内容为:

Section "Device"
Identifier "Configured Video Device"
EndSection

Section "Monitor"
Identifier "Configured Monitor"
Modeline "1368x768_60.00" 85.86 1368 1440 1584 1800 768 769 772 795 -HSync +Vsync
EndSection

Section "Screen"
Identifier "Default Screen"
Monitor "Configured Monitor"
Device "Configured Video Device"
SubSection "Display"
Modes "1368x768@60"
EndSubSection
EndSection

其中 Modeline “1368x768_60.00″ 85.86 1368 1440 1584 1800 768 769 772 795 -HSync +Vsync 就是用$ cvt 1368 768得到的值。也可以用$ gtf 1368 768 60命令来得到这个Modeline的值,这个命令中,1368 768是分辨率 60为刷新率,用这个命令得到的值可能会更为准确一些。

SubSection "Display"
Modes "1368x768@60"
EndSubSection

这段是设置默认显示最佳分辨率。

注意这段文件中的一些规则

Section “Device”区块中,Identifier指定了显卡的唯一名称,这个名称可以随便取,但一定要与Section “Screen”区块中的device选项中的名称相同。在Section “Monitor”区块中,Identifier指定了显示器的唯一名称,这个名称可以随便取,但一定要与Section “Screen”区块中的Monitor选项中所指定的名称相同。Section “Screen”区块中的Identifier选项,指定了这个显卡与显示器相结合的唯一名称。这个名称也可以随便取的。这个名称需要与Section “ServerLayout” 区块中的名称相同。这个Section “ServerLayout” 区块我们一般不必编写

posted @ 2012-05-24 14:46 俞灵 阅读(2863) | 评论 (0)编辑 收藏

     摘要:      最近这些天学习了classLoader的原理, 原因是因为服务器上的一个java进程启动时加载两个不同版本的jar包, 含有相同名字的类, 而且服务端的jar包排在前面, 我上传的jar包排在后面, 于是每次都使用服务端的jar包, 我的jar包便无法生效, 因此希望修改classLader, 让它按相反的顺序加载jar包.  ...  阅读全文

posted @ 2012-05-20 19:43 俞灵 阅读(5638) | 评论 (1)编辑 收藏

     摘要: High Availability for the HDFS Namenode Sanjay Radia, Suresh Srinivas Yahoo! Inc  (本文为namdnoe HA的设计文档翻译) 1.       问题阐述 有许多方法可以改善HDFS Namednoe(NN)的可用性,包括减少启动时间,更...  阅读全文

posted @ 2012-03-24 21:38 俞灵 阅读(3185) | 评论 (2)编辑 收藏

本文转自:
http://blog.csdn.net/zhouysh/article/details/304767

JAVA代码编写的30条建议
(1) 类名首字母应该大写。字段、方法以及对象(句柄)的首字母应小写。对于所有标识符,其中包含的所有单词都应紧靠在一起,而且大写中间单词的首字母。例如:
ThisIsAClassName
thisIsMethodOrFieldName
若在定义中出现了常数初始化字符,则大写static final基本类型标识符中的所有字母。这样便可标志出它们属于编译期的常数。
Java包(Package)属于一种特殊情况:它们全都是小写字母,即便中间的单词亦是如此。对于域名扩展名称,如com,org,net或者edu等,全部都应小写(这也是Java 1.1和Java 1.2的区别之一)。

(2) 为了常规用途而创建一个类时,请采取"经典形式",并包含对下述元素的定义:

equals()
hashCode()
toString()
clone()(implement Cloneable)
implement Serializable

(3) 对于自己创建的每一个类,都考虑置入一个main(),其中包含了用于测试那个类的代码。为使用一个项目中的类,我们没必要删除测试代码。若进行了任何形式的改动,可方便地返回测试。这些代码也可作为如何使用类的一个示例使用。

(4) 应将方法设计成简要的、功能性单元,用它描述和实现一个不连续的类接口部分。理想情况下,方法应简明扼要。若长度很大,可考虑通过某种方式将其分割成较短的几个方法。这样做也便于类内代码的重复使用(有些时候,方法必须非常大,但它们仍应只做同样的一件事情)。

(5) 设计一个类时,请设身处地为客户程序员考虑一下(类的使用方法应该是非常明确的)。然后,再设身处地为管理代码的人考虑一下(预计有可能进行哪些形式的修改,想想用什么方法可把它们变得更简单)。
(6) 使类尽可能短小精悍,而且只解决一个特定的问题。下面是对类设计的一些建议:
■一个复杂的开关语句:考虑采用"多形"机制
■数量众多的方法涉及到类型差别极大的操作:考虑用几个类来分别实现
■许多成员变量在特征上有很大的差别:考虑使用几个类

(7) 让一切东西都尽可能地"私有"--private。可使库的某一部分"公共化"(一个方法、类或者一个字段等等),就永远不能把它拿出。若强行拿出,就可 能破坏其他人现有的代码,使他们不得不重新编写和设计。若只公布自己必须公布的,就可放心大胆地改变其他任何东西。在多线程环境中,隐私是特别重要的一个 因素--只有private字段才能在非同步使用的情况下受到保护。

(8) 谨惕"巨大对象综合症"。对一些习惯于顺序编程思维、且初涉OOP领域的新手,往往喜欢先写一个顺序执行的程序,再把它嵌入一个或两个巨大的对象里。根据编程原理,对象表达的应该是应用程序的概念,而非应用程序本身。

(9) 若不得已进行一些不太雅观的编程,至少应该把那些代码置于一个类的内部。

(10) 任何时候只要发现类与类之间结合得非常紧密,就需要考虑是否采用内部类,从而改善编码及维护工作(参见第14章14.1.2小节的"用内部类改进代码")。

(11) 尽可能细致地加上注释,并用javadoc注释文档语法生成自己的程序文档。

(12) 避免使用"魔术数字",这些数字很难与代码很好地配合。如以后需要修改它,无疑会成为一场噩梦,因为根本不知道"100"到底是指"数组大小"还是"其他 全然不同的东西"。所以,我们应创建一个常数,并为其使用具有说服力的描述性名称,并在整个程序中都采用常数标识符。这样可使程序更易理解以及更易维护。

(13) 涉及构建器和异常的时候,通常希望重新丢弃在构建器中捕获的任何异常--如果它造成了那个对象的创建失败。这样一来,调用者就不会以为那个对象已正确地创建,从而盲目地继续。

(14) 当客户程序员用完对象以后,若你的类要求进行任何清除工作,可考虑将清除代码置于一个良好定义的方法里,采用类似于cleanup()这样的名字,明确表 明自己的用途。除此以外,可在类内放置一个boolean(布尔)标记,指出对象是否已被清除。在类的finalize()方法里,请确定对象已被清除, 并已丢弃了从RuntimeException继承的一个类(如果还没有的话),从而指出一个编程错误。在采取象这样的方案之前,请确定 finalize()能够在自己的系统中工作(可能需要调用System.runFinalizersOnExit(true),从而确保这一行为)。

(15) 在一个特定的作用域内,若一个对象必须清除(非由垃圾收集机制处理),请采用下述方法:初始化对象;若成功,则立即进入一个含有finally从句的try块,开始清除工作。

(16) 若在初始化过程中需要覆盖(取消)finalize(),请记住调用super.finalize()(若Object属于我们的直接超类,则无此必 要)。在对finalize()进行覆盖的过程中,对super.finalize()的调用应属于最后一个行动,而不应是第一个行动,这样可确保在需要 基础类组件的时候它们依然有效。

(17) 创建大小固定的对象集合时,请将它们传输至一个数组(若准备从一个方法里返回这个集合,更应如此操作)。这样一来,我们就可享受到数组在编译期进行类型检查的好处。此外,为使用它们,数组的接收者也许并不需要将对象"造型"到数组里。

(18) 尽量使用interfaces,不要使用abstract类。若已知某样东西准备成为一个基础类,那么第一个选择应是将其变成一个interface(接 口)。只有在不得不使用方法定义或者成员变量的时候,才需要将其变成一个abstract(抽象)类。接口主要描述了客户希望做什么事情,而一个类则致力 于(或允许)具体的实施细节。

(19) 在构建器内部,只进行那些将对象设为正确状态所需的工作。尽可能地避免调用其他方法,因为那些方法可能被其他人覆盖或取消,从而在构建过程中产生不可预知的结果(参见第7章的详细说明)。

(20) 对象不应只是简单地容纳一些数据;它们的行为也应得到良好的定义。

(21) 在现成类的基础上创建新类时,请首先选择"新建"或"创作"。只有自己的设计要求必须继承时,才应考虑这方面的问题。若在本来允许新建的场合使用了继承,则整个设计会变得没有必要地复杂。

(22) 用继承及方法覆盖来表示行为间的差异,而用字段表示状态间的区别。一个非常极端的例子是通过对不同类的继承来表示颜色,这是绝对应该避免的:应直接使用一个"颜色"字段。

(23) 为避免编程时遇到麻烦,请保证在自己类路径指到的任何地方,每个名字都仅对应一个类。否则,编译器可能先找到同名的另一个类,并报告出错消息。若怀疑自己碰到了类路径问题,请试试在类路径的每一个起点,搜索一下同名的.class文件。

(24) 在Java 1.1 AWT中使用事件"适配器"时,特别容易碰到一个陷阱。若覆盖了某个适配器方法,同时拼写方法没有特别讲究,最后的结果就是新添加一个方法,而不是覆盖现 成方法。然而,由于这样做是完全合法的,所以不会从编译器或运行期系统获得任何出错提示--只不过代码的工作就变得不正常了。

(25) 用合理的设计方案消除"伪功能"。也就是说,假若只需要创建类的一个对象,就不要提前限制自己使用应用程序,并加上一条"只生成其中一个"注释。请考虑将 其封装成一个"独生子"的形式。若在主程序里有大量散乱的代码,用于创建自己的对象,请考虑采纳一种创造性的方案,将些代码封装起来。

(26) 警惕"分析瘫痪"。请记住,无论如何都要提前了解整个项目的状况,再去考察其中的细节。由于把握了全局,可快速认识自己未知的一些因素,防止在考察细节的时候陷入"死逻辑"中。

(27) 警惕"过早优化"。首先让它运行起来,再考虑变得更快--但只有在自己必须这样做、而且经证实在某部分代码中的确存在一个性能瓶颈的时候,才应进行优化。 除非用专门的工具分析瓶颈,否则很有可能是在浪费自己的时间。性能提升的隐含代价是自己的代码变得难于理解,而且难于维护。

(28) 请记住,阅读代码的时间比写代码的时间多得多。思路清晰的设计可获得易于理解的程序,但注释、细致的解释以及一些示例往往具有不可估量的价值。无论对你自 己,还是对后来的人,它们都是相当重要的。如对此仍有怀疑,那么请试想自己试图从联机Java文档里找出有用信息时碰到的挫折,这样或许能将你说服。

(29) 如认为自己已进行了良好的分析、设计或者实施,那么请稍微更换一下思维角度。试试邀请一些外来人士--并不一定是专家,但可以是来自本公司其他部门的人。 请他们用完全新鲜的眼光考察你的工作,看看是否能找出你一度熟视无睹的问题。采取这种方式,往往能在最适合修改的阶段找出一些关键性的问题,避免产品发行 后再解决问题而造成的金钱及精力方面的损失。

(30) 良好的设计能带来最大的回报。简言之,对于一个特定的问题,通常会花较长的时间才能找到一种最恰当的解决方案。但一旦找到了正确的方法,以后的工作就轻松 多了,再也不用经历数小时、数天或者数月的痛苦挣扎。我们的努力工作会带来最大的回报(甚至无可估量)。而且由于自己倾注了大量心血,最终获得一个出色的 设计方案,成功的快感也是令人心动的。坚持抵制草草完工的诱惑--那样做往往得不偿失

posted @ 2011-11-28 14:34 俞灵 阅读(572) | 评论 (0)编辑 收藏