首页 文章 精选 留言 我的

精选列表

搜索[学习],共10000篇文章
优秀的个人博客,低调大师

【干货】2017年深度学习必读31篇论文(附论文下载地址)

一如既往,首先,标准免责声明适用,因为今年仅与GAN有关的论文就超过1660篇。我肯定会有疏漏,试图缩减到每两周一篇论文,包含了Imperial Deep Learning Reading Group上的大量素材。无论如何,我们开始吧。 架构/模型 今年的Convnet网络架构已经少得多,一切都稳定了。 有些论文肯定是在推动这项研究。 其中首先是安德鲁·布鲁克(Andrew Brock)的破解SMASH,尽管有ICLR的评论,但它已经在1000个GPU上进行了神经架构搜索。 SMASH:基于超网络的模型结构搜索SMASH : one shot model architecture search through Hypernetworks论文下载地址:https://arxiv.org/pdf/1708.05344.pdf DenseNet

优秀的个人博客,低调大师

《从零开始学Swift》学习笔记(Day 47)——final关键字

在类的定义中使用final关键字声明类、属性、方法和下标。final声明的类不能被继承,final声明的属性、方法和下标不能被重写。 下面看一个示例: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 final class Person{ //声明为final,说明它是不能被继承的 varname:String final varage:Int //定义的age属性 final funcdescription()->String{ //定义description实例方法 return "\(name)年龄是:\(age)" } final class funcprintClass()->(){ //定义printClass静态方法 print( "Person打印..." ) } init(name:String,age:Int){ self.name=name self.age=age } } class Student:Person{ //编译错误 varschool:String convenienceinit(){ self.init(name: "Tony" ,age: 18 ,school: "清华大学" ) } init(name:String,age:Int,school:String){ self.school=school super .init(name:name,age:age) } overridefuncdescription()->String{ //编译错误//试图重写description实例方法 print( "父类打印\(super.description())" ) return "\(name)年龄是:\(age),所在学校:\(school)。" } override class funcprintClass()->(){ //编译错误//试图重写printClass静态方法 print( "Student打印..." ) } overridevarage:Int{ //编译错误//试图重写age属性 get{ return super .age } set{ super .age=newValue< 8 ? 8 :newValue } } } 定义Student类,并声明为Person子类时,会报如下编译错误: Inheritance from a finalclass 'Person' 定义的age属性也是final,那么在试图重写age属性时,会报如下编译错误: Var overrides a 'final'var 定义description实例方法,它被声明为final,那么在试图重写description实例方法时,会报如下编译错误: Instance method overridesa 'final' instance method 定义printClass静态方法,它被声明为final,那么在试图重写printClass静态方法时,会报如下编译错误: Class method overrides a'final' class method 使用final可以控制我们的类被有限地继承,特别是在开发一些商业软件时,适当地添加final限制是非常有必要的。 本文转自 tony关东升 51CTO博客,原文链接:http://blog.51cto.com/tonyguan/1747532,如需转载请自行联系原作者

优秀的个人博客,低调大师

《从零开始学Swift》学习笔记(Day 21)——函数返回值

返回值3种形式:无返回值、单一返回值和多返回值。 无返回值函数 所谓无返回结果,事实上是Void类型,即表示没有数据的类型。 无返回值函数的语法格式有如下3种形式: func函数名(参数列表) { 语句组 } func函数名(参数列表) ->() { 语句组 } func函数名(参数列表) ->Void { 语句组 } 无返回值函数不需要“return返回值”语句。 多返回值函数 两种方式来实现。 一种是在函数定义的时候,将函数的多个参数声明为引用类型传递,这样当函数调用结束时,这些参数的值就变化了。 另一种是将返回定义为元组类型。 介绍元组类型返回多值的实现。看一个示例: 1 2 3 4 5 6 7 8 9 10 funcposition(dt:Double,speed:(x:Int,y:Int))->(x:Int,y:Int){ letposx:Int=speed.x*Int(dt) letposy:Int=speed.y*Int(dt) return (posx,posy) } letmove=position( 60.0 ,speed:( 10 ,- 5 )) print( "物体位移:\(move.x),\(move.y)" ) 参数speed:(x:Int,y:Int)是元组类型。 position函数的返回值是(x:Int,y:Int)的元组类型。 代码调用函数,传递的时期间是60.0秒,速度是(10, 5)。 输出结果,结果如下: 物体位移:600 , -300 本文转自 tony关东升 51CTO博客,原文链接:http://blog.51cto.com/tonyguan/1746403,如需转载请自行联系原作者

优秀的个人博客,低调大师

【NGN学习笔记】1 NGN的基本概念和体系结构

1.NGN产生的背景和需求: a.通信网发展: PSTN采用集中式架构,交换硬件和呼叫控制以及部分业务逻辑都集中在交换机中完成。 GSM移动通信网结构 智能网体系结构 ·SCF:业务控制功能 ·SDF:业务数据功能 ·SMF:业务管理功能 ·SMAF:业务管理接入功能 ·SSF:业务交换功能 ·CCF:呼叫控制功能 ·SRF:特殊资源功能 ·SCEF:业务生成环境功能 下一代开放的电信网络构架: b.计算机网络发展: c.三网融合: 三网融合是指电信网、计算机网和有线电视网在高层业务应用的融合。 技术推动力 ·数字技术的迅速发展和全面采用 ·大容量光纤通信技术的发展 ·软件技术的发展为三网融合提供了实现手段 ·IP协议的普遍采用为三网融合提供了统一的传送协议 d.未来业务需求: ·传统电话网对日益增长的数据业务不堪重负 ·人们希望IP网能传送数据、语音及更多新业务 2.基本概念 a)概念:NGN是一个具有丰富内涵的术语,涵盖了目前网络发展的多个领域: ·以ASON为主的下一代光网络 ·以IPv6和MPLS为主的下一代因特网 ·以软交换和IMS为主的下一代交换控制网 ·以3G和B3G为主的下一代移动网 ·下一代业务网、下一代接入网、下一代管理网,…… NGN是一个能够利用多种宽带和具有QoS能力的传送技术提供电信业务的基于分组的网络。在NGN中,业务相关功能(service-related functions)独立于底层传送相关技术(transport-related technologies)。该网络允许用户不受限地接入网络,自由地选择服务提供商和/或业务。NGN支持通用移动性(generalized mobility),从而能够向用户提供一致的、无处不在的业务。 b)最终目标:实现在任何时间(Whenever)、任何地点(Wherever)、以任何方式(Whatever)和任何人(Whoever)进行通信,是未来融合网络发展的方向。 c)总体特征: ·基于分组的网络:利用分组交换技术的灵活性传送不同带宽和QoS需求的业务 ·采用分层的体系结构:业务功能与传送功能相分离,控制、承载、会话、业务相分离,接口逐渐开放和标准化,业务相关的功能与底层的传输技术无关,便于各层技术的独立发展 ·业务驱动的网络:NGN的终极目标是实现业务的快速有效提供和使用 ·融合异构的网络:通过核心的分组交换技术实现对各种传统网络和多种接入技术的融合 ·支持通用移动性:真正实现用户随时随地以任何方式使用业务的目标 ·各种不同的识别机制,可以解析到IP地址 d)提供能力要求 ·提供创建、部署和管理各种可能业务的能力:各种媒体类型业务、各种带宽要求业务、会话型业务、消息型业务、数据传送业务、实时和非实时业务、客户定制业务、第三方提供的业务等等。 ·业务与传输无关:业务功能与传输功能之间有明确的区分,它们的演进相互独立,业务提供独立于网络和接入类型。 ·功能实体之间通过标准接口进行通信的能力。 ·支持传统的和NGN感知的终端设备:模拟电话机、传真机、ISDN终端、蜂窝移动电话、GPRS终端、SIP终端,…… ·支持QoS保障和安全能力,业务迁移能力 ·支持通用移动性Generalized mobility:允许用户或者其他移动实体不管位置是否变化,所处的接入技术环境是否变化,都具有通信和接入业务的能力。业务可用性的程度可能取决于几个因素,包括:接入网的能力、用户的归属网络与拜访地网络(如果适用)之间的业务等级协议等等。移动性包括具有或者不具有业务连续性的通信能力。 3.基本架构 对比与传统通信网: VS 允许网络运营商从不同的制造商那里购买最合适的网络部件构建自己的网络,而不必受制于一家公司的解决方案。 具体举例:基于软交换的NGN体系结构(左)和基于IMS的NGN体系结构(右) 基于软交换的NGN体系结构的核心思想:软交换是NGN的控制功能的实现,它为NGN提供实时性业务的呼叫控制和连接控制功能,是NGN呼叫与控制的核心。软交换技术作为业务/控制与传送/接入分离思想的体现,是NGN体系结构中的关键技术,其核心思想是硬件软件化,通过软件方式实现原来交换机的控制、接续和业务处理等功能,各实体之间通过标准的协议进行连接和通信,便于在NGN中更快地实现各类复杂的协议及更方便地提供业务。 功能实体基本功能有: ·软交换设备:呼叫控制、协议功能、业务提供功能、业务交换功能、操作维护功能、计费功能 ·媒体网关功能:接入功能、语音处理功能、媒体流映射功能、受控操作功能、管理和统计功能 ·信令网关功能:对在SCN(电路交换网)中传输的信令进行适配,以便使信令能够以分组的形式传送到媒体网关控制器(MGC),反之对来自MGC的信令进行转换,将以IP分组形式发送到SG的信令进行转换,以便在SCN中进行传输 ·媒体服务器的功能:控制接口、会议功能、录音和回放、录像和回放、语音的编码和解码、视频的编码和解码、语音识别、文转音及音转文功能 ·应用服务器功能:为用户提供各种业务 二者比较 ·相同点:基本技术都是基于IP分组网络,都实现了控制与承载的分离;大部分的协议都是相似或者完全相同的;许多网关设备和终端设备甚至是可以通用的。 ·不同点:总体区别主要是在网络构架上,软交换体系侧基于主从控制(MGC/MG),需利用和继承PSTN的接入网络,以方便过渡.而IMS可在系统/终端侧统一采用基于IP承载网的SIP协议,体现出与接入网的独立性,并天生支持移动性管理并且具有一定的QoS保障机制。 ITU-T的基本参考模型: NGN Service stratum:NGN中向用户提供传送业务相关数据的功能,提供控制和管理业务资源和网络服务以支持用户业务和应用的功能。用户业务可以由业务层的多个子层来实现NGN业务层只关心在对等实体之间操作的应用和业务。从体系结构的角度来看,业务层的每一子层都可以有自己的用户、控制和管理平面。 NGN transport stratum:NGN中向用户提供传送数据的功能,以及控制和管理传输资源以在终端实体之间携带这些数据的功能,这些被携带的数据可以是用户信息、控制信息和管理信息,在传送层实体之间可能建立动态或静态的关联来控制和管理信息传送。NGN传送层可以由多个子层来实现。从体系结构的观点来看,传送层的每一子层有它自己的用户、控制和管理平面。 4.关键技术 ·软交换和IMS技术:在核心控制层,采用软交换或IMS提供端到端的业务控制,前者是在IP电话网关功能分解的基础上提出的一种新的呼叫控制技术,是电信网发展史上的一块里程碑后者由3GPP提出,是对软交换的继承和发展,结构更清晰,功能更完整。 ·核心传送技术:采用光传送网和光交换网解决传输和高带宽问题,采用MPLS和IPv6提供有QoS保证的分组传送能力 ·接入层技术:宽带接入技术、私网穿越技术、安全认证技术等 ·开放业务提供技术:业务层API技术:Parlay/OSA API、JAIN、SIP Servlet,…多种层次的业务生成技术:脚本、组件/架构、API ·端到端的QoS技术、网络安全技术 ·网络管理技术、移动性管理 ·网络融合和业务融合 附注:思考题整理 NGN的定义和主要特点是什么? 基于软交换的下一代网络体系结构与基于IMS的下一代网络体系结构的异同? ITU-T给出的NGN分层模型包括哪几层,各层的主要功能有哪些? 通用移动性的含义? 本文转自gnuhpc博客园博客,原文链接:http://www.cnblogs.com/gnuhpc/archive/2012/12/11/2813464.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

[Android Pro] Android学习——在线查看android源代码的3种方式

原文:http://blog.csdn.net/chuekup/article/details/8067075 1.https://github.com/android 2.http://grepcode.com/project/repository.grepcode.com/java/ext/com.google.android/android/ 上面2种都是通过第三方网站直接访问,这里主要说说下面这种方法: 3. 一个chrome内核浏览器插件:Android SDK Reference Search 这个插件可以直接到扩展中心里搜索 https://chrome.google.com/webstore/search/Android%20SDK%20Reference%20Search%20 安装了这个插件之后就可以直接到android api官方网:http://developer.android.com/reference/packages.html 随便查找一个类:例如Activity:http://developer.android.com/reference/android/app/Activity.html 然后我们就可以看到在Aitivity后面多了个(view source),如下 点击(view source)进去,就可以直接跳转到谷歌提供的在线官方源代码处: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/app/Activity.java 原文链接:http://blog.blundell-apps.com/add-source-code-links-to-android-apis/ 备注:今天换了个浏览器在扩展中心去搜索居然搜不出来了······于是直接google之,第一个链接打开即可~~~ https://chrome.google.com/webstore/detail/android-sdk-reference-sea/hgcbffeicehlpmgmnhnkjbjoldkfhoin 分类: Android Pro 本文转自demoblog博客园博客,原文链接http://www.cnblogs.com/0616--ataozhijia/p/3928924.html如需转载请自行联系原作者 demoblog

优秀的个人博客,低调大师

英特尔深度学习框架BigDL——a distributed deep learning library for Apache Spark

BigDL: Distributed Deep Learning on Apache Spark What is BigDL? BigDL is a distributed deep learning library for Apache Spark; with BigDL, users can write their deep learning applications as standard Spark programs, which can directly run on top of existing Spark or Hadoop clusters. Rich deep learning support.Modeled afterTorch, BigDL provides comprehensive support for deep learning, including numeric computing (viaTensor) and high levelneural networks; in addition, users can load pre-trainedCaffeorTorchmodels into Spark programs using BigDL. Extremely high performance.To achieve high performance, BigDL usesIntel MKLand multi-threaded programming in each Spark task. Consequently, it is orders of magnitude faster than out-of-box open sourceCaffe,TorchorTensorFlowon a single-node Xeon (i.e., comparable with mainstream GPU). Efficiently scale-out.BigDL can efficiently scale out to perform data analytics at "Big Data scale", by leveragingApache Spark(a lightning fast distributed data processing framework), as well as efficient implementations of synchronous SGD and all-reduce communications on Spark. Why BigDL? You may want to write your deep learning programs using BigDL if: You want to analyze a large amount of data on the same Big Data (Hadoop/Spark) cluster where the data are stored (in, say, HDFS, HBase, Hive, etc.). You want to add deep learning functionalities (either training or prediction) to your Big Data (Spark) programs and/or workflow. You want to leverage existing Hadoop/Spark clusters to run your deep learning applications, which can be then dynamically shared with other workloads (e.g., ETL, data warehouse, feature engineering, classical machine learning, graph analytics, etc.) How to use BigDL? More information can be found at the BigDL project website: https://bigdl-project.github.io/ In particular, you can check out theGetting Started pagefor a quick overview of how to use BigDL For step-by-step deep leaning tutorials on BigDL (using Python), you can check out theBigDL Tutorials project You can join theBigDL Google Group(or subscribe to theMail List) for more questions and discussions on BigDL You can post bug reports and feature requests at theIssue Page 本文转自张昺华-sky博客园博客,原文链接:http://www.cnblogs.com/bonelee/p/7349523.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

《从零开始学Swift》学习笔记(Day 18)——有几个分支语句?

分支语句又称条件语句,Swift编程语言提供了if、switch和guard三种分支语句。 if语句 由if语句引导的选择结构有if结构、if-else结构和else-if结构3种。 if结构示例代码如下: 1 2 3 4 5 varscore= 95 if score>= 85 { print( "您真优秀!" ) } 程序运行结果如下: 您真优秀! if-else结构示例代码如下: 1 2 3 4 5 6 7 varscore= 95 if score< 60 { print( "不及格" ) } else { print( "及格" ) } 程序运行结果如下: 及格 else-if结构示例代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 lettestscore= 76 vargrade:Character if testscore>= 90 { grade= "A" } else if testscore>= 80 { grade= "B" } else if testscore>= 70 { grade= "C" } else if testscore>= 60 { grade= "D" } else { grade= "F" } print( "Grade=\(grade)" ) 输出结果如下: Grade = C switch语句 switch语句也称开关语句,它提供多分支程序结构。 switch语句基本形式示例代码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 lettestscore= 86 vargrade:Character switchtestscore/ 10 { case 9 : grade= "优" case 8 : grade= "良" case 7 , 6 : grade= "中" default : grade= "差" } print( "Grade=\(grade)" ) 输出结果如下: Grade =良 guard语句 guard语句是Swift 2.0新添加的关键字,它与if语句非常类似,它设计的目的是提高程序的可读性。 guard语句必须带有else语句,它的语法如下: guard条件表达式else{ 跳转语句 } 语句组 当条件表达式为true时候跳过else语句中的内容,执行语句组内容。条件表达式为false时候执行else语句中的内容,跳转语句一般是return、break、continue和throw。 本文转自 tony关东升 51CTO博客,原文链接:http://blog.51cto.com/tonyguan/1746243,如需转载请自行联系原作者

优秀的个人博客,低调大师

《从零开始学Swift》学习笔记(Day60)——Core Foundation框架

Core Foundation框架是苹果公司提供一套概念来源于Foundation框架,编程接口面向C语言风格的API。虽然在Swift中调用这种C语言风格的API比较麻烦,但是在OS X和iOS开发过程中,有时候使用CoreFoundation框架的API是非常方便的,例如在与C语言混合编码的时候。 Core Foundation框架与Foundation框架紧密相关,他们具有与相同的接口,但是不同。Core Foundation框架是基于C语言风格的,而Foundation框架是基于Objective-C语言风格的。在OS X和iOS程序代码中经常会有多种语言风格的代码混合在一起的情况,这使得我们开发变得更加麻烦。 数据类型映射 Core Foundation框架提供了一些不透明的数据类型,这些数据类型封装了一些数据和操作,他们也可以称为“类”,他们都继承于CFType类,CFType是所用Core Foundation框架类型的根类。这些数据类型在Foundation框架中都有相应的数据类型与之对应,这些数据类型也有一些与Swift原生数据类型有对应关系。 看看Swift原生类型与Core Foundation类型之间的转换示例: 1 2 3 4 5 6 7 8 import CoreFoundation import Foundation varcfstr1:CFString= "Hello,World" //创建CFString字符串 varstr:String=cfstr1asString //将CFString字符串转换为Swift原生字符串String varcfstr2:CFString=str //将Swift原生字符串String转换为CFString字符串 这个转换过程中Core Foundation类型转换为Swift原生类型是需要强制类型转换的。 本文转自 tony关东升 51CTO博客,原文链接:http://blog.51cto.com/tonyguan/1748349,如需转载请自行联系原作者

优秀的个人博客,低调大师

分布式基础学习【二】 —— 分布式计算系统(Map/Reduce)

二. 分布式计算(Map/Reduce) 分布式式计算,同样是一个宽泛的概念,在这里,它狭义的指代,按Google Map/Reduce框架所设计的分布式框架。在Hadoop中,分布式文件系统,很大程度上,是为各种分布式计算需求所服务的。我们说分布式文件系统就是加了分布式的文件系统,类似的定义推广到分布式计算上,我们可以将其视为 增加了分布式支持的计算函数。从计算的角度上看,Map/Reduce框架接受各种格式的键值对文件作为输入,读取计算后,最终生成自定义格式的输出文件。而从分布式的角度上看,分布式计算的输入文件往往规模巨大,且分布在多个机器上,单机计算完全不可支撑且效率低下,因此Map/Reduce框架需要提供一套机制,将此计算扩展到无限规模的机器集群上进行。依照这样的定义,我们对整个Map/Reduce的理解,也可以分别沿着这两个流程去看。。。 在Map/Reduce框架中,每一次计算请求,被称为 作业。在分布式计算Map/Reduce框架中,为了完成这个作业,它进行两步走的战略,首先是将其拆分成若干个 Map任务,分配到不同的机器上去执行,每一个Map任务拿输入文件的一部分作为自己的输入,经过一些计算,生成某种格式的中间文件,这种格式,与最终所需的文件格式完全一致,但是仅仅包含一部分数据。因此,等到所有Map任务完成后,它会进入下一个步骤,用以合并这些中间文件获得最后的输出文件。此时,系统会生成若干个 Reduce任务,同样也是分配到不同的机器去执行,它的目标,就是将若干个Map任务生成的中间文件为汇总到最后的输出文件中去。当然,这个汇总不总会像1 + 1 = 2那么直接了当,这也就是Reduce任务的价值所在。经过如上步骤,最终,作业完成,所需的目标文件生成。整个算法的关键,就在于增加了一个中间文件生成的流程,大大提高了灵活性,使其分布式扩展性得到了保证。。。 I. 术语对照 和分布式文件系统一样,Google、Hadoop和....我,各执一种方式表述统一概念,为了保证其统一性,特有下表。。。 II. 基本架构 与分布式文件系统类似,Map/Reduce的集群,也由三类服务器构成。其中 作业服务器,在Hadoop中称为 Job Tracker,在Google论文中称为 Master。前者告诉我们,作业服务器是负责管理运行在此框架下所有作业的,后者告诉我们,它也是为各个作业分配任务的核心。与HDFS的主控服务器类似,它也是作为单点存在的,简化了负责的同步流程。具体的 负责执行用户定义操作的,是 任务服务器,每一个作业被拆分成很多的 任务,包括 Map任务和 Reduce任务等,任务是具体执行的基本单元,它们都需要分配到合适任务服务器上去执行,任务服务器一边执行一边向作业服务器汇报各个任务的状态,以此来帮助作业服务器了解作业执行的整体情况,分配新的任务等等。。。 除了作业的管理者执行者,还需要有一个 任务的提交者,这就是客户端。与分布式文件系统一样,客户端也不是一个单独的进程,而是一组API,用户需要自定义好自己需要的内容,经由客户端相关的代码,将作业及其相关内容和配置,提交到作业服务器去,并时刻监控执行的状况。。。 同作为Hadoop的实现,与HDFS的通信机制相同,Hadoop Map/Reduce也是用了协议接口来进行服务器间的交流。实现者作为RPC服务器,调用者经由RPC的代理进行调用,如此,完成大部分的通信,具体服务器的架构,和其中运行的各个协议状况,参见下图。从图中可以看到,与HDFS相比,相关的协议少了几个,客户端与任务服务器,任务服务器之间,都不再有直接通信关系。这并不意味着客户端就不需要了解具体任务的执行状况,也不意味着,任务服务器之间不需要了解别家任务执行的情形,只不过,由于整个集群各机器的联系比HDFS复杂的多,直接通信过于的难以维系,所以,都统一由作业服务器整理转发。另外,从这幅图可以看到,任务服务器不是一个人在战斗,它会像孙悟空一样招出一群宝宝帮助其具体执行任务。这样做的好处,个人觉得,应该有安全性方面的考虑,毕竟,任务的代码是用户提交的,数据也是用户指定的,这质量自然良莠不齐,万一碰上个搞破坏的,把整个任务服务器进程搞死了,就因小失大了。因此,放在单独的地盘进行,爱咋咋地,也算是权责明确了。。。 与分布式文件系统相比,Map/Reduce框架的还有一个特点,就是 可定制性强。文件系统中很多的算法,都是很固定和直观的,不会由于所存储的内容不同而有太多的变化。而作为通用的计算框架,需要面对的问题则要复杂很多,在各种不同的问题、不同的输入、不同的需求之间,很难有一种包治百病的药能够一招鲜吃遍天。作为Map/Reduce框架而言,一方面要尽可能的抽取出公共的一些需求,实现出来。更重要的,是需要提供良好的可扩展机制,满足用户自定义各种算法的需求。Hadoop是由Java来实现的,因此通过反射来实现自定义的扩展,显得比较小菜一碟了。在 JobConf类中,定义了大量的接口,这基本上是Hadoop Map/Reduce框架所有可定制内容的一次集中展示。在JobConf中,有大量set接口接受一个 Class<? extends xxx>的参数,通常它都有一个默认实现的类,用户如果不满意,则可自定义实现。。。 III. 计算流程 如果一切都按部就班的进行,那么整个作业的计算流程,应该是作业的提交 -> Map任务的分配和执行 -> Reduce任务的分配和执行 -> 作业的完成。而在每个任务的执行中,又包含输入的准备 -> 算法的执行 -> 输出的生成,三个子步骤。沿着这个流程,我们可以很快的整理清晰整个Map/Reduce框架下作业的执行。。。 1、作业的提交 一个作业,在提交之前,需要把所有应该配置的东西都配置好,因为一旦提交到了作业服务器上,就陷入了完全自动化的流程,用户除了观望,最多也就能起一个监督作用,惩治一些不好好工作的任务。。。 基本上,用户在提交代码阶段,需要做的工作主要是这样的: 首先,书写好所有自定的代码,最起码,需要有Map和Reduce的执行代码。在Hadoop中,Map需要派生自 Mapper<K1, V1, K2, V2>接口,Reduce需要派生自 Reducer<K2, V2, K3, V3>接口。这里都是用的泛型,用以支持不同的键值类型。这两个接口都仅有一个方法,一个是map,一个是reduce,这两个方法都直接受四个参数,前两个是输入的 键和 值相关的数据结构,第三个是作为 输出相关的数据结构,最后一个,是一个 Reporter类的实例,实现的时候可以利用它来统计一些计数。除了这两个接口,还有大量可以派生的接口,比如分割的 Partitioner<K2, V2>接口。。。 然后,需要书写好主函数的代码,其中最主要的内容就是实例化一个 JobConf类的对象,然后调用其丰富的setXXX接口,设定好所需的内容,包括输入输出的文件路径,Map和Reduce的类,甚至包括读取写入文件所需的格式支持类,等等。。。 最后,调用 JobClient的 runJob方法,提交此JobConf对象。runJob方法会先行调用到 JobSubmissionProtocol接口所定义的 submitJob方法,将此作业,提交给作业服务器。接着,runJob开始循环,不停的调用JobSubmissionProtocol的 getTaskCompletionEvents方法,获得 TaskCompletionEvent类的对象实例,了解此作业各任务的执行状况。。。 2、Map任务的分配 当一个作业提交到了作业服务器上,作业服务器会生成若干个Map任务,每一个Map任务,负责将一部分的输入转换成格式与最终格式相同的中间文件。通常一个 作业的输入都是基于分布式文件系统的文件(当然在单机环境下,文件系统单机的也可以...),因为,它可以很天然的和分布式的计算产生联系。而对于一个Map任务而言,它的输入往往是输入文件的一个数据块,或者是数据块的一部分,但通常, 不跨数据块。因为,一旦跨了数据块,就可能涉及到多个服务器,带来了不必要的复杂性。。。 当一个作业,从客户端提交到了作业服务器上,作业服务器会生成一个 JobInProgress对象,作为与之对应的标识,用于管理。作业被拆分成若干个Map任务后,会预先挂在作业服务器上的任务服务器拓扑树。这是依照分布式文件数据块的位置来划分的,比如一个Map任务需要用某个数据块,这个数据块有三份备份,那么,在这三台服务器上都会挂上此任务,可以视为是一个预分配。。。 关于任务管理和分配的大部分的真实功能和逻辑的实现,JobInProgress则依托 JobInProgressListener和 TaskScheduler的子类。TaskScheduler,顾名思义是用于任务分配的策略类(为了简化描述,用它代指所有TaskScheduler的子类...)。它会掌握好所有作业的任务信息,其 assignTasks函数,接受一个 TaskTrackerStatus作为参数,依照此任务服务器的状态和现有的任务状况,为其分配新的任务。而为了掌握所有作业相关任务的状况,TaskScheduler会将若干个JobInProgressListener注册到 JobTracker中去,当有新的作业到达、移除或更新的时候,JobTracker会告知给所有的JobInProgressListener,以便它们做出相应的处理。。。 任务分配是一个重要的环节,所谓任务分配,就是 将合适作业的合适任务分配到合适的服务器上。不难看出,里面蕴含了两个步骤,先是选择作业,然后是在此作业中选择任务。和所有分配工作一样,任务分配也是一个复杂的活。不良好的任务分配,可能会导致网络流量增加、某些任务服务器负载过重效率下降,等等。不仅如此,任务分配还是一个无一致模式的问题,不同的业务背景,可能需要不同的算法才能满足需求。因此,在Hadoop中,有很多TaskScheduler的子类,像Facebook,Yahoo,都为其贡献出了自家用的算法。在Hadoop中,默认的任务分配器,是 JobQueueTaskScheduler类。它选择作业的基本次序是:Map Clean Up Task(Map任务服务器的清理任务,用于清理相关的过期的文件和环境...) -> Map Setup Task(Map任务服务器的安装任务,负责配置好相关的环境...) -> Map Tasks -> Reduce Clean Up Task -> Reduce Setup Task -> Reduce Tasks。在这个前提下,具体到Map任务的分配上来。当一个任务服务器工作的游刃有余,期待获得新的任务的时候,JobQueueTaskScheduler会按照各个作业的优先级,从 最高优先级的作业开始分配。每分配一个,还会为其留出余量,已被不时之需。举一个例子:系统目前有优先级3、2、1的三个作业,每个作业都有一个可分配的Map任务,一个任务服务器来申请新的任务,它还有能力承载3个任务的执行,JobQueueTaskScheduler会先从优先级3的作业上取一个任务分配给它,然后再留出一个1任务的余量。此时,系统只能在将优先级2作业的任务分配给此服务器,而不能分配优先级1的任务。这样的策略,基本思路就是 一切为高优先级的作业服务,优先分配不说,分配了好保留有余力以备不时之需,如此优待,足以让高优先级的作业喜极而泣,让低优先级的作业感慨既生瑜何生亮,甚至是活活饿死。。。 确定了从哪个作业提取任务后,具体的分配算法,经过一系列的调用,最后实际是由 JobInProgress的 findNewMapTask函数完成的。它的算法很简单,就是 尽全力为此服务器非配且尽可能好的分配任务,也就是说,只要还有可分配的任务,就一定会分给它,而不考虑后来者。作业服务器会从离它最近的服务器开始,看上面是否还挂着未分配的任务(预分配上的),从近到远,如果所有的任务都分配了,那么看有没有开启多次执行,如果开启,考虑把未完成的任务再分配一次(后面有地方详述...)。。。 对于作业服务器来说,把一个任务分配出去了,并不意味着它就彻底解放,可以对此任务可以不管不顾了。因为任务可以在任务服务器上执行失败,可能执行缓慢,这都需要作业服务器帮助它们再来一次。因此在Task中,记录有一个 TaskAttemptID,对于任务服务器而言,它们每次跑的,其实都只是一个Attempt而已,Reduce任务只需要采信一个的输出,其他都算白忙乎了。。。 3、Map任务的执行 与HDFS类似,任务服务器是通过心跳消息,向作业服务器汇报此时此刻其上各个任务执行的状况,并向作业服务器申请新的任务的。具体实现,是 TaskTracker调用 InterTrackerProtocol协议的 heartbeat方法来做的。这个方法接受一个 TaskTrackerStatus对象作为参数,它描述了此时此任务服务器的状态。当其有余力接受新的任务的时候,它还会传入 acceptNewTasks为true的参数,表示希望作业服务器委以重任。 JobTracker接收到相关的参数后,经过处理,会返回一个 HeartbeatResponse对象。这个对象中,定义了一组TaskTrackerAction,用于指导任务服务器进行下一步的工作。系统中已定义的了一堆其TaskTrackerAction的子类,有的对携带的参数进行了扩充,有的只是标明了下ID,具体不详写了,一看便知。。。 当TaskTracker收到的TaskTrackerAction中,包含了 LaunchTaskAction,它会开始执行所分配的新的任务。在TaskTracker中,有一个 TaskTracker.TaskLauncher线程(确切的说是两个,一个等Map任务,一个等Reduce任务),它们在痴痴的守候着新任务的来到。一旦等到了,会最终调用到Task的 createRunner方法,构造出一个 TaskRunner对象,新建一个线程来执行。对于一个Map任务,它对应的Runner是TaskRunner的子类 MapTaskRunner,不过,核心部分都在TaskRunner的实现内。TaskRunner会先将所需的文件全部下载并拆包好,并记录到一个全局缓存中,这是一个全局的目录,可以供所有此作业的所有任务使用。它会用一些软链接,将一些文件名链接到这个缓存中来。然后,根据不同的参数,配置出一个JVM执行的环境,这个环境与 JvmEnv类的对象对应。 接着,TaskRunner会调用 JvmManager的 launchJvm方法,提交给JvmManager处理。JvmManager用于管理该TaskTracker上所有运行的Task子进程。在目前的实现中,尝试的是池化的方式。有若干个固定的槽,如果槽没有满,那么就启动新的子进程,否则,就寻找idle的进程,如果是同Job的直接放进去,否则杀死这个进程,用一个新的进程代替。每一个进程都是由JvmRunner来管理的,它也是位于单独线程中的。但是从实现上看,这个机制好像没有部署开,子进程是死循环等待,而不会阻塞在父进程的相关线程上,父线程的变量一直都没有个调整,一旦分配,始终都处在繁忙的状况了。 真实的执行载体,是Child,它包含一个main函数,进程执行,会将相关参数传进来,它会拆解这些参数,并且构造出相关的Task实例,调用其run函数进行执行。每一个子进程,可以执行指定个数量的Task,这就是上面所说的池化的配置。但是,这套机制在我看来,并没有运行起来,每个进程其实都没有机会不死而执行新的任务,只是傻傻的等待进程池满,而被一刀毙命。也许是我老眼昏花,没看出其中实现的端倪。。。 4、Reduce任务的分配与执行 比之Map任务,Reduce的分配及其简单,基本上是所有Map任务完成了,有空闲的任务服务器,来了就给分配一个Job任务。因为Map任务的结果星罗棋布,且变化多端,真要搞一个全局优化的算法,绝对是得不偿失。而Reduce任务的执行进程的构造和分配流程,与Map基本完全的一致,没有啥可说的了。。。 但其实,Reduce任务与Map任务的最大不同,是Map任务的文件都在本地隔着,而Reduce任务需要到处采集。这个流程是作业服务器经由此Reduce任务所处的任务服务器,告诉Reduce任务正在执行的进程,它需要的Map任务执行过的服务器地址,此Reduce任务服务器会于原Map任务服务器联系(当然本地就免了...),通过FTP服务,下载过来。这个隐含的直接数据联系,就是执行Reduce任务与执行Map任务最大的不同了。。。 5、作业的完成 当所有Reduce任务都完成了,所需数据都写到了分布式文件系统上,整个作业才正式完成了。此中,涉及到很多的类,很多的文件,很多的服务器,所以说起来很费劲,话说,一图解千语,说了那么多,我还是画两幅图,彻底表达一下吧。。。 首先,是一个时序图。它模拟了一个由3个Map任务和1个Reduce任务构成的作业执行流程。我们可以看到,在执行的过程中,只要有人太慢,或者失败,就会增加一次尝试,以此换取最快的执行总时间。一旦所有Map任务完成,Reduce开始运作(其实,不一定要这样的...),对于每一个Map任务来说,只有执行到Reduce任务把它上面的数据下载完成,才算成功,否则,都是失败,需要重新进行尝试。。。 而第二副图,不是我画的,就不转载了,参见 这里,它描述了整个Map/Reduce的服务器状况图,包括整体流程、所处服务器进程、输入输出等,看清楚这幅图,对Map/Reduce的基本流程应该能完全跑通了。有这几点,可能图中描述的不够清晰需要提及一下,一个是在HDFS中,其实还有日志文件,图中没有标明;另一个是步骤5,其实是由TaskTracker主动去拉取而不是JobTracker推送过来的;还有步骤8和步骤11,创建出来的MapTask和ReduceTask,在Hadoop中都是运行在独立的进程上的。。。 IV. Map任务详请 从上面,可以了解到整个Map和Reduce任务的整体流程,而后面要啰嗦的,是具体执行中的细节。Map任务的输入,是分布式文件系统上的,包含键值对信息的文件。为了给每一个Map任务指定输入,我们需要掌握文件格式把它分切成块,并从每一块中分离出键值信息。在HDFS中,输入的文件格式,是由 InputFormat<K, V>类来表示的,在JobConf中,它的默认值是 TextInputFormat类(见 getInputFormat),此类是特化的 FileInputFormat<LongWritable, Text>子类,而 FileInputFormat<K, V>正是InputFormat<K, V>的子类。通过这样的关系我们可以很容易的理解,默认的文件格式是 文本文件,且键是 LongWritable类型(整形数),值是 Text类型(字符串)。仅仅知道文件类型是不够的,我们还需要将文件中的每一条数据,分离成键值对,这个工作,是 RecordReader<K, V>来做的。在TextInputFormat的 getRecordReader方法中我们可以看到,与TextInputFormat默认配套使用的,是 LineRecordReader类,是特化的 RecordReader<LongWritable, Text>的子类,它将每 一行作为一个记录,起始的位置作为键,整行的字符串作为值。有了格式,分出了键值,还需要切开分给每一个Map任务。每一个Map任务的输入用 InputSplit接口表示,对于一个文件输入而言,其实现是 FileSplit,它包含着 文件名、起始位置、长度和存储它的一组服务器地址。。。 当Map任务拿到所属的InputSplit后,就开始一条条读取记录,并调用用于定义的Mapper,进行计算(参见MapRunner<K1, V1, K2, V2>和MapTask的run方法),然后,输出。MapTask会传递给Mapper一个OutputCollector<K, V>对象,作为输出的数据结构。它定义了一个collect的函数,接受一个键值对。在MapTask中,定义了两个OutputCollector的子类,一个是MapTask.DirectMapOutputCollector<K, V>,人如其名,它的实现确实很Direct,直截了当。它会利用一个RecordWriter<K, V>对象,collect一调用,就直接调用RecordWriter<K, V>的write方法,写入本地的文件中去。如果觉着RecordWriter<K, V>出现的很突兀,那么看看上一段提到的RecordReader<K, V>,基本上,数据结构都是对应着的,一个是输入一个是输出。输出很对称也是由RecordWriter<K, V>和OutputFormat<K, V>来协同完成的,其默认实现是LineRecordWriter<K, V>和TextOutputFormat<K, V>,多么的眼熟啊。。。 除了这个非常直接的实现之外,MapTask中还有一个复杂的多的实现,是MapTask.MapOutputBuffer<K extends Object, V extends Object>。有道是简单压倒一切,那为什么有很简单的实现,要琢磨一个复杂的呢。原因在于,看上去很美的往往带着刺,简单的输出实现,每调用一次collect就写一次文件,频繁的硬盘操作很有可能导致此方案的低效。为了解决这个问题,这就有了这个复杂版本,它先开好一段内存做 缓存,然后制定一个比例做 阈值, 开一个线程监控此缓存。collect来的内容,先写到缓存中,当监控线程发现缓存的内容比例超过阈值,挂起所有写入操作,建一个 新的文件,把缓存的内容批量 刷到此文件中去,清空缓存,重新开放,接受继续collect。。。 为什么说是刷到文件中去呢。因为这不是一个简单的照本宣科简单复制的过程,在写入之前,会先将缓存中的内存,经过排序、合并器(Combiner)统计之后,才会写入。如果你觉得Combiner这个名词听着太陌生,那么考虑一下Reducer,Combiner也就是一个Reducer类,通过JobConf的setCombinerClass进行设置,在常用的配置中,Combiner往往就是用用户为Reduce任务定义的那个Reducer子类。只不过,Combiner只是服务的范围更小一些而已,它在Map任务执行的服务器本地,依照Map处理过的那一小部分数据,先做一次Reduce操作,这样,可以压缩需要传输内容的大小,提高速度。每一次刷缓存,都会开一个新的文件,等此任务所有的输入都处理完成后,就有了若干个有序的、经过合并的输出文件。系统会将这些文件搞在一起,再做一个多路的归并外排,同时使用合并器进行合并,最终,得到了唯一的、有序的、经过合并的中间文件(注:文件数量等同于分类数量,在不考虑分类的时候,简单的视为一个...)。它,就是Reduce任务梦寐以求的输入文件。。。 除了做合并,复杂版本的OutputCollector,还具有 分类的功能。分类,是通过 Partitioner<K2, V2>来定义的,默认实现是 HashPartitioner<K2, V2>,作业提交者可以通过JobConf的 setPartitionerClass来自定义。分类的含义是什么呢,简单的说,就是将Map任务的输出,划分到若干个文件中(通常与Reduce任务数目相等),使得每一个Reduce任务,可以处理某一类文件。这样的好处是大大的,举一个例子说明一下。比如有一个作业是进行 单词统计的,其Map任务的中间结果应该是 以单词为键,以单词数量为值的文件。如果这时候只有一个Reduce任务,那还好说,从 全部的Map任务那里收集文件过来,分别统计得到最后的输出文件就好。但是,如果单Reduce任务无法承载此负载或效率太低,就需要多个Reduce任务并行执行。此时,再沿用之前的模式就有了问题。每个Reduce任务从 一部分Map任务那里获得输入文件,但最终的输出结果并不正确,因为同一个单词可能在不同的Reduce任务那里都有统计,需要想方法把它们统计在一起才能获得最后结果,这样就没有将Map/Reduce的作用完全发挥出来。这时候,就需要用到分类。如果此时有两个Reduce任务,那么将输出分成两类,一类存放字母表排序较高的单词,一类存放字母表排序低的单词,每一个Reduce任务从 所有的Map任务那里获取一类的中间文件,得到自己的输出结果。最终的结果,只需要把各个Reduce任务输出的,拼接在一起就可以了。本质上,这就是将Reduce任务的输入, 由垂直分割,变成了水平分割。Partitioner的作用,正是接受一个键值,返回一个分类的序号。它会在从缓存刷到文件之前做这个工作,其实只是多了一个文件名的选择而已,别的逻辑都不需要变化。。。 除了缓存、合并、分类等附加工作之外,复杂版本的OutputCollector还支持错误数据的跳过功能,在后面分布式将排错的时候,还会提及,标记一下,按下不表。。。 V. Reduce任务详情 理论上看,Reduce任务的整个执行流程要比Map任务更为的罗嗦一些,因为,它需要收集输入文件,然后才能进行处理。Reduce任务,主要有这么三个步骤: Copy、 Sort、 Reduce(参见ReduceTask的run方法)。所谓Copy,就是从执行各个Map任务的服务器那里,收罗到本地来。拷贝的任务,是由 ReduceTask.ReduceCopier类来负责,它有一个内嵌类,叫 MapOutputCopier,它会在一个单独的线程内,负责某个Map任务服务器上文件的拷贝工作。远程拷贝过来的内容(当然也可以是本地了...),作为MapOutput对象存在,它可以在内存中也可以序列化在磁盘上,这个根据内存使用状况来自动调节。整个拷贝过程是一个动态的过程,也就是说它不是一次给好所有输入信息就不再变化了。它会不停的调用 TaskUmbilicalProtocol协议的 getMapCompletionEvents方法,向其父TaskTracker询问此作业个Map任务的完成状况(TaskTracker要向JobTracker询问后再转告给它...)。当获取到相关Map任务执行服务器的信息后,都会有一个线程开启,做具体的拷贝工作。同时,还有一个内存Merger线程和一个文件Merger线程在同步工作,它们将新鲜下载过来的文件(可能在内存中,简单的统称为文件...),做着归并排序,以此,节约时间,降低输入文件的数量,为后续的排序工作减负。。。 Sort,排序工作,就相当于上述排序工作的一个延续。它会在所有的文件都拷贝完毕后进行,因为虽然同步有做着归并的工作,但可能留着尾巴,没做彻底。经过这一个流程,该彻底的都彻底了,一个崭新的、合并了所有所需Map任务输出文件的新文件,诞生了。而那些千行万苦从其他各个服务器网罗过来的Map任务输出文件,很快的结束了它们的历史使命,被扫地出门一扫而光,全部删除了。。。 所谓好戏在后头,Reduce任务的最后一个阶段,正是Reduce本身。它也会准备一个 OutputCollector收集输出,与MapTask不同,这个OutputCollector更为简单,仅仅是打开一个 RecordWriter,collect一次,write一次。最大的不同在于,这次传入RecordWriter的文件系统,基本都是 分布式文件系统,或者说是HDFS。而在输入方面,ReduceTask会从JobConf那里调用一堆getMapOutputKeyClass、getMapOutputValueClass、getOutputKeyComparator等等之类的自定义类,构造出Reducer所需的键类型,和值的迭代类型Iterator(一个键到了这里一般是对应一组值)。具体实现颇为拐弯抹角,建议看一下 Merger.MergeQueue, RawKeyValueIterator, ReduceTask.ReduceValuesIterator等等之类的实现。有了输入,有了输出,不断循环调用自定义的Reducer,最终,Reduce阶段完成。。。 VI. 分布式支持 1、服务器正确性保证 Hadoop Map/Reduce服务器状况和HDFS很类似,由此可知,救死扶伤的方法也是大同小异。废话不多说了,直接切正题。同作为客户端,Map/Reduce的客户端只是将作业提交,就开始搬个板凳看戏,没有占茅坑的行动。因此,一旦它挂了,也就挂了,不伤大雅。而任务服务器,也需要随时与作业服务器保持心跳联系,一旦有了问题,作业服务器可以将其上运行的任务,移交给它人完成。作业服务器,作为一个单点,非常类似的是利用还原点(等同于HDFS的镜像)和历史记录(等同于HDFS的日志),来进行恢复。其上,需要持久化用于恢复的内容,包含作业状况、任务状况、各个任务尝试的工作状况等。有了这些内容,再加上任务服务器的动态注册,就算挪了个窝,还是很容易恢复的。 JobHistory是历史记录相关的一个静态类,本来,它也就是一个干写日志活的,只是在Hadoop的实现中,对日志的写入做了面向对象的封装,同时又大量用到观察者模式做了些嵌入,使得看起来不是那么直观。本质上,它就是打开若干个日志文件,利用各类接口来往里面写内容。只不过,这些日志,会放在分布式文件系统中,就不需要像HDFS那样,来一个SecondXXX随时候命,由此可见,有巨人在脚下踩着,真好。JobTracker.RecoveryManager类是作业服务器中用于进行恢复相关的事情,当作业服务器启动的时候,会调用其recover方法,恢复日志文件中的内容。其中步骤,注释中写的很清楚,请自行查看。。。 2、任务执行的正确和速度 整个作业流程的执行,秉承着木桶原理。执行的最慢的Map任务和Reduce任务,决定了系统整体执行时间(当然,如果执行时间在整个流程中占比例很小的话,也许就微不足道了...)。因此,尽量加快最慢的任务执行速度,成为提高整体速度关键。所使用的策略,简约而不简单,就是 一个任务多次执行。当所有未执行的任务都分配出去了,并且先富起来的那部分任务已经完成了,并还有任务服务器孜孜不倦的索取任务的时候,作业服务器会开始炒剩饭,把那些正在吭哧吭哧在某个服务器上慢慢执行的任务,再把此任务分配到一个新的任务服务器上,同时执行。两个服务器各尽其力,成王败寇,先结束者的结果将被采纳。这样的策略,隐含着一个假设,就是我们相信,输入文件的分割算法是公平的,某个任务执行慢,并不是由于这个任务本身负担太重,而是由于服务器不争气负担太重能力有限或者是即将撒手西去,给它换个新环境,人挪死树挪活事半功倍。。。 当然,肯定有哽咽的任务,不论是在哪个服务器上,都无法顺利完成。这就说明,此问题不在于服务器上,而是任务本身天资有缺憾。缺憾在何处?每个作业,功能代码都是一样的,别的任务成功了,就是这个任务不成功,很显然,问题出在输入那里。输入中有非法的输入条目,导致程序无法辨识,只能挥泪惜别。说到这里,解决策略也浮出水面了,三十六计走位上,惹不起,还是躲得起的。在MapTask中的MapTask.SkippingRecordReader<K, V>和ReduceTask里的ReduceTask.SkippingReduceValuesIterator<KEY,VALUE>,都是用于干这个事情的。它们的原理很简单,就是在读一条记录前,把当前的位置信息,封装成SortedRanges.Range对象,经由Task的reportNextRecordRange方法提交到TaskTracker上去。TaskTracker会把这些内容,搁在TaskStatus对象中,随着心跳消息,汇报到JobTracker上面。这样,作业服务器就可以随时随刻了解清楚,每个任务正读取在那个位置,一旦出错,再次执行的时候,就在分配的任务信息里面添加一组SortedRanges信息。MapTask或ReduceTask读取的时候,会看一下这些区域,如果当前区域正好处于上述雷区,跳过不读。如此反复,正可谓,道路曲折,前途光明啊。。。 VII. 总结 对于Map/Reduce而言,真正的困难,在于提高其适应能力,打造一款能够包治百病的执行框架。Hadoop已经做得很好了,但只有真正搞清楚了整个流程,你才能帮助它做的更好。。。 本文转自 duguguiyu 51CTO博客,原文链接:http://blog.51cto.com/duguguiyu/363397,如需转载请自行联系原作者

优秀的个人博客,低调大师

Hadoop MapReduce概念学习系列之MapReduce的体系结构(二)

MapReduce 也采用了 Master/Slave(M/S)架构。它主要由以下几个组件组成 :Client、JobTracker、 TaskTracker 和 Task。下面分别对 这几个组件进行介绍。 (1)Client 用户编写的MapReduce程序通过Client提交到JobTracker端;同时,用户可通过Client提供的一些接口查看作业运行状态。在Hadoop内部用“作业” (Job)表示MapReduce程序。一个 MapReduce程序可对应若干个作业,而每个作业会被分解成若干个Map/Reduce任务(Task)。 (2)JobTracker JobTracker 主要负责资源监控和作业调度。JobTracker 监控所有 TaskTracker 与作业Job的健康状况,一旦发现失败情况后,其会将相应的任务转移到其他节点;同时,JobTracker 会跟踪任务的执行进度、资源使用量等信息,并将这些信息告诉任务调度器,而调度器会在资源出现空闲时,选择合适的任务使用这些资源。在Hadoop 中,任务调度器是一个可插拔的模块,用户可以根据自己的需要设计相应的调度器。 (3)TaskTracker TaskTracker会周期性地通过Heartbeat将本节点上资源的使用情况和任务的运行进度汇报给JobTracker,同时接收JobTracker发送过来的命令并执行相应的操作(如启动新任务、杀死 任务等)。TaskTracker 使用“slot”等量划分本节点上的资源量。 “slot”代表计算资源(CPU、 内存等)。一个 Task 获取到一个slot 后才有机会运行,而Hadoop调度器的作用就是将各个TaskTracker上的空闲slot分配给Task使用。slot分为Map slot和Reduce slot 两种,分别供Map Task和Reduce Task使用。TaskTracker通过slot数目(可配置参数)限定Task的并发度。 (4)Task Task 分为 Map Task 和 Reduce Task 两种,均由TaskTracker启动。从上一小节中我们知道,HDFS以固定大小的block 为基本单位存储数据,而对于MapReduce 而言,其处理单位是split。 split 与 block 的对应关系如下图所示。split 是一个逻辑概念,它只包含一些元数据信息,比如 数据起始位置、数据长度、数据所在节点等。它的划分方法完全由用户自己决定。但需要注意的是,split的多少决定了Map Task的数目,因为每个split会交由一个Map Task处理。 Map Task 执行过程如下图所示。由该图可知,Map Task 先将对应的split 迭代解析成一 个个 key/value 对,依次调用用户自定义的map() 函数进行处理,最终将临时结果存放到本地磁盘上,其中临时数据被分成若干个partition(分片),每个partition 将被一个Reduce Task处理。 Reduce Task 执行过程如下图所示。该过程分为三个阶段: ①从远程节点上读取Map Task 中间结果(称为“Shuffle阶段”); ②按照key对key/value 对进行排序(称为“Sort阶段”); ③依次读取 <key, value list>,调用用户自定义的 reduce() 函数处理,并将最终结果存到HDFS上(称为“Reduce 阶段”)。 MapReduce是一种并行编程模式,利用这种模式软件开发者可以轻松地编写出分布式并行程序。在Hadoop的体系结构中,MapReduce是一个简单易用的软件框架,基于它可以将任务分发到由上千台商用机器组成的集群上,并以一种可靠容错的方式并行处理大量的数据集,实现Hadoop的并行任务处理功能。MapReduce框架是由一个单独运行在主节点的JobTrack和运行在每个集群从节点的TaskTrack共同组成的。 主节点负责调度构成一个作业的所有任务,这些任务分布在不同的节点上。主节点监控它们的执行情况,并且重新执行之前失败的任务; 从节点仅负责由主节点指派的任务。 当一个Job任务被提交时,JobTrack接收到提交作业和其配置信息之后,就会配置信息等发给从节点,同时调度任务并监控TaskTrack的执行。 本文转自大数据躺过的坑博客园博客,原文链接:http://www.cnblogs.com/zlslch/p/5058629.html,如需转载请自行联系原作者

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

用户登录
用户注册