首页 文章 精选 留言 我的

精选列表

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

《从零开始学Swift》学习笔记(Day 42)——构造函数调用规则

在构造函数中可以使用构造函数代理帮助完成部分构造工作。类构造函数代理分为横向代理和向上代理,横向代理只能在发生在同一类内部,这种构造函数称为便利构造函数。向上代理发生在继承的情况下,在子类构造过程中,要先调用父类构造函数初始化父类的存储属性,这种构造函数称为指定构造函数。 构造函数调用规则 Person和Student类示例: 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 class Person{ varname:String varage:Int funcdescription()->String{ return "\(name)年龄是:\(age)" } convenienceinit(){ //便利构造函数 self.init(name: "Tony" ) self.age= 18 } convenienceinit(name:String){ //便利构造函数 self.init(name:name,age: 18 ) } init(name:String,age:Int){ //指定构造函数 self.name=name self.age=age } } class Student:Person{ varschool:String init(name:String,age:Int,school:String){ //指定构造函数 self.school=school super .init(name:name,age:age) } convenienceoverrideinit(name:String,age:Int){ //便利构造函数 self.init(name:name,age:age,school: "清华大学" ) } } letstudent=Student() print( "学生:\(student.description())" ) 构造函数之间的调用形成了构造函数链,如图所示。 Swift限制构造函数之间的代理调用的规则有3条,如下所示。 指定构造函数必须调用其直接父类的的指定构造函数。从图可见,Student中的④号指定构造函数调用Person中的③号指定构造函数。 便利构造函数必须调用同一类中定义的其他构造函数。从图可见,Student中的⑤号便利构造函数调用同一类中的④号便利构造函数,Person中的①号便利构造函数调用同一类中的②号便利构造函数。 便利构造函数必须最终以调用一个指定构造函数结束。从图可见,Student中的⑤号便利构造函数调用同一类中的④号指定构造函数,Person中的②号便利构造函数调用同一类中的③号指定构造函数。 本文转自 tony关东升 51CTO博客,原文链接:http://blog.51cto.com/tonyguan/1747498,如需转载请自行联系原作者

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

【Android进阶学习】实现没有标题栏的窗口和全屏显示

在Android实现没有标题栏的方法有两种: 在代码中添加 requestWindowFeature(Window.FEATURE_NO_TITLE); 在清单文件AndroidManifest.xml中添加 android:theme="@android:style/Theme.NoTitleBar" 具体的代码如下: 第一种: MainActivity.java packagecom.lingdududu.test; importandroid.app.Activity; importandroid.os.Bundle; importandroid.view.Window; publicclassMainActivityextendsActivity{ /**Calledwhentheactivityisfirstcreated.*/ privatebooleancatchHomeKey=false; publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); this.requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.main); } } 第二种: AndroidManifest.xml <?xmlversion="1.0"encoding="utf-8"?> <manifestxmlns:android="http://schemas.android.com/apk/res/android" package="com.lingdududu.test" android:versionCode="1" android:versionName="1.0"> <uses-sdkandroid:minSdkVersion="10"/> <applicationandroid:icon="@drawable/icon"android:label="@string/app_name"> <activityandroid:name=".MainActivity" android:label="@string/app_name" android:theme="@android:style/Theme.NoTitleBar"> <intent-filter> <actionandroid:name="android.intent.action.MAIN"/> <categoryandroid:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application> </manifest> 效果图: 如果想让窗口全屏显示: 将下面两段代码分别替换上面的两段设置无标题的代码就可以了 getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); android:theme="@android:style/Theme.NoTitleBar.Fullscreen" 效果图: 本文转自 lingdududu 51CTO博客,原文链接: http://blog.51cto.com/liangruijun/732128

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

Spark RDD概念学习系列之Spark的算子的分类(十一)

Spark的算子的分类 从大方向来说Spark 算子大致可以分为以下两类: 1Transformation 变换/转换算子这种变换并不触发提交作业完成作业中间过程处理。 Transformation 操作是延迟计算的也就是说从一个RDD 转换生成另一个 RDD 的转换操作不是马上执行需要等到有 Action 操作的时候才会真正触发运算。 2Action 行动算子这类算子会触发 SparkContext 提交 Job 作业。 Action 算子会触发 Spark 提交作业Job并将数据输出 Spark系统。 从小方向来说Spark 算子大致可以分为以下三类: 1Value数据类型的Transformation算子这种变换并不触发提交作业针对处理的数据项是Value型的数据。 2Key-Value数据类型的Transfromation算子这种变换并不触发提交作业针对处理的数据项是Key-Value型的数据对。 3Action算子这类算子会触发SparkContext提交Job作业。 1Value数据类型的Transformation算子 一、输入分区与输出分区一对一型 1、map算子 2、flatMap算子 3、mapPartitions算子 4、glom算子 二、输入分区与输出分区多对一型 5、union算子 6、cartesian算子 三、输入分区与输出分区多对多型 7、grouBy算子 四、输出分区为输入分区子集型 8、filter算子 9、distinct算子 10、subtract算子 11、sample算子 12、takeSample算子 五、Cache型 13、cache算子 14、persist算子 2Key-Value数据类型的Transfromation算子 一、输入分区与输出分区一对一 15、mapValues算子 二、对单个RDD或两个RDD聚集 单个RDD聚集 16、combineByKey算子 17、reduceByKey算子 18、partitionBy算子 两个RDD聚集 19、Cogroup算子 三、连接 20、join算子 21、leftOutJoin和 rightOutJoin算子 Spark算子的作用详细见http://www.cnblogs.com/zlslch/p/5723979.html 3Action算子 一、无输出 22、foreach算子 二、HDFS 23、saveAsTextFile算子 24、saveAsObjectFile算子 三、Scala集合和数据类型 25、collect算子 26、collectAsMap算子 27、reduceByKeyLocally算子 28、lookup算子 29、count算子 30、top算子 31、reduce算子 32、fold算子 33、aggregate算子 Spark算子的作用详细见http://www.cnblogs.com/zlslch/p/5723979.html 1. Transformations 算子 1map 将原来 RDD 的每个数据项通过map 中的用户自定义函数 f映射转变为一个新的元素。源码中 map 算子相当于初始化一个 RDD 新 RDD 叫做 MappedRDD(this, sc.clean(f))。 图 1中每个方框表示一个 RDD 分区左侧的分区经过用户自定义函数 f:T->U映射为右侧的新 RDD 分区。但是实际只有等到 Action算子触发后这个 f 函数才会和其他函数在一个stage 中对数据进行运算。在图 1 中的第一个分区数据记录 V1 输入 f通过 f 转换输出为转换后的分区中的数据记录 V'1。 图1 map 算子对 RDD 转换 2flatMap 将原来 RDD 中的每个元素通过函数 f 转换为新的元素并将生成的 RDD 的每个集合中的元素合并为一个集合内部创建 FlatMappedRDD(thissc.clean(f))。 图 2 表 示 RDD 的 一 个 分 区 进 行 flatMap函 数 操 作 flatMap 中 传 入 的 函 数 为 f:T->UT和 U 可以是任意的数据类型。将分区中的数据通过用户自定义函数 f 转换为新的数据。外部大方框可以认为是一个 RDD 分区小方框代表一个集合。 V1、 V2、 V3 在一个集合作为 RDD 的一个数据项可能存储为数组或其他容器转换为V'1、 V'2、 V'3 后将原来的数组或容器结合拆散拆散的数据形成为 RDD 中的数据项。 图2 flapMap 算子对 RDD 转换 3mapPartitions mapPartitions 函 数 获 取 到 每 个 分 区 的 迭 代器在 函 数 中 通 过 这 个 分 区 整 体 的 迭 代 器 对整 个 分 区 的 元 素 进 行 操 作。 内 部 实 现 是 生 成 MapPartitionsRDD。图 3 中的方框代表一个 RDD 分区。图 3 中用户通过函数 f (iter)=>iter.f ilter(_>=3) 对分区中所有数据进行过滤大于和等于 3 的数据保留。一个方块代表一个 RDD 分区含有 1、 2、 3 的分区过滤只剩下元素 3。 图3 mapPartitions 算子对 RDD 转换 4glom glom函数将每个分区形成一个数组内部实现是返回的GlommedRDD。 图4中的每个方框代表一个RDD分区。图4中的方框代表一个分区。 该图表示含有V1、 V2、 V3的分区通过函数glom形成一数组Array[V1V2V3]。 图 4 glom算子对RDD转换 5union 使用 union 函数时需要保证两个 RDD 元素的数据类型相同返回的 RDD 数据类型和被合并的 RDD 元素数据类型相同并不进行去重操作保存所有元素。如果想去重 可以使用 distinct()。同时 Spark 还提供更为简洁的使用 union 的 API通过 ++ 符号相当于 union 函数操作。 图 5 中左侧大方框代表两个 RDD大方框内的小方框代表 RDD 的分区。右侧大方框代表合并后的 RDD大方框内的小方框代表分区。 含有V1、V2、U1、U2、U3、U4的RDD和含有V1、V8、U5、U6、U7、U8的RDD合并所有元素形成一个RDD。V1、V1、V2、V8形成一个分区U1、U2、U3、U4、U5、U6、U7、U8形成一个分区。 图 5 union 算子对 RDD 转换 6cartesian 对 两 个 RDD 内 的 所 有 元 素进 行 笛 卡 尔 积 操 作。 操 作 后 内 部 实 现 返 回CartesianRDD。图6中左侧大方框代表两个 RDD大方框内的小方框代表 RDD 的分区。右侧大方框代表合并后的 RDD大方框内的小方框代表分区。图6中的大方框代表RDD大方框中的小方框代表RDD分区。 例 如 V1 和 另 一 个 RDD 中 的 W1、 W2、 Q5 进 行 笛 卡 尔 积 运 算 形 成 (V1,W1)、(V1,W2)、 (V1,Q5)。 图 6 cartesian 算子对 RDD 转换 7groupBy groupBy 将元素通过函数生成相应的 Key数据就转化为 Key-Value 格式之后将 Key 相同的元素分为一组。 函数实现如下 1将用户函数预处理 val cleanF = sc.clean(f) 2对数据 map 进行函数操作最后再进行 groupByKey 分组操作。 this.map(t => (cleanF(t), t)).groupByKey(p) 其中 p 确定了分区个数和分区函数也就决定了并行化的程度。 图7 中方框代表一个 RDD 分区相同key 的元素合并到一个组。例如 V1 和 V2 合并为 V Value 为 V1,V2。形成 V,Seq(V1,V2)。 图 7groupBy 算子对 RDD 转换 8filter filter 函数功能是对元素进行过滤对每个 元 素 应 用 f 函 数 返 回 值 为 true 的 元 素 在RDD 中保留返回值为 false 的元素将被过滤掉。 内 部 实 现 相 当 于 生 成 FilteredRDD(thissc.clean(f))。 下面代码为函数的本质实现 deffilter(f:T=>Boolean):RDD[T]=newFilteredRDD(this,sc.clean(f)) 图 8 中每个方框代表一个 RDD 分区 T 可以是任意的类型。通过用户自定义的过滤函数 f对每个数据项操作将满足条件、返回结果为 true 的数据项保留。例如过滤掉 V2 和 V3 保留了 V1为区分命名为 V'1。 图 8 filter 算子对 RDD 转换 9distinct distinct将RDD中的元素进行去重操作。图9中的每个方框代表一个RDD分区通过distinct函数将数据去重。 例如重复数据V1、 V1去重后只保留一份V1。 图9 distinct算子对RDD转换 10subtract subtract相当于进行集合的差操作RDD 1去除RDD 1和RDD 2交集中的所有元素。图10中左侧的大方框代表两个RDD大方框内的小方框代表RDD的分区。 右侧大方框 代表合并后的RDD大方框内的小方框代表分区。 V1在两个RDD中均有根据差集运算规则新RDD不保留V2在第一个RDD有第二个RDD没有则在新RDD元素中包含V2。 图10 subtract算子对RDD转换 11sample sample 将 RDD 这个集合内的元素进行采样获取所有元素的子集。用户可以设定是否有放回的抽样、百分比、随机种子进而决定采样方式。内部实现是生成 SampledRDD(withReplacement fraction seed)。 函数参数设置 withReplacement=true表示有放回的抽样。 withReplacement=false表示无放回的抽样。 图 11中 的 每 个 方 框 是 一 个 RDD 分 区。 通 过 sample 函 数 采 样 50% 的 数 据。V1、 V2、 U1、 U2、U3、U4 采样出数据 V1 和 U1、 U2 形成新的 RDD。 图11 sample 算子对 RDD 转换 12takeSample takeSample函数和上面的sample函数是一个原理但是不使用相对比例采样而是按设定的采样个数进行采样同时返回结果不再是RDD而是相当于对采样后的数据进行 Collect返回结果的集合为单机的数组。 图12中左侧的方框代表分布式的各个节点上的分区右侧方框代表单机上返回的结果数组。 通过takeSample对数据采样设置为采样一份数据返回结果为V1。 图12 takeSample算子对RDD转换 13cache cache将 RDD 元素从磁盘缓存到内存。 相当于 persist(MEMORY_ONLY) 函数的功能。 图13 中每个方框代表一个 RDD 分区左侧相当于数据分区都存储在磁盘通过 cache 算子将数据缓存在内存。 图 13 Cache 算子对 RDD 转换 14persist persist 函数对RDD 进行缓存操作。数据缓存在哪里依据 StorageLevel 这个枚举类型进行确定。 有以下几种类型的组合见10 DISK 代表磁盘MEMORY 代表内存 SER 代表数据是否进行序列化存储。 下面为函数定义 StorageLevel 是枚举类型代表存储模式用户可以通过图 14-1 按需进行选择。 persist(newLevel:StorageLevel) 图 14-1 中列出persist 函数可以进行缓存的模式。例如MEMORY_AND_DISK_SER 代表数据可以存储在内存和磁盘并且以序列化的方式存储其他同理。 图 14-1 persist 算子对 RDD 转换 图 14-2 中方框代表 RDD 分区。 disk 代表存储在磁盘 mem 代表存储在内存。数据最初全部存储在磁盘通过 persist(MEMORY_AND_DISK) 将数据缓存到内存但是有的分区无法容纳在内存将含有 V1、 V2、 V3 的RDD存储到磁盘将含有U1U2的RDD仍旧存储在内存。 图 14-2 Persist 算子对 RDD 转换 15mapValues mapValues 针对Key Value型数据中的 Value 进行 Map 操作而不对 Key 进行处理。 图 15 中的方框代表 RDD 分区。 a=>a+2 代表对 (V1,1) 这样的 Key Value 数据对数据只对 Value 中的 1 进行加 2 操作返回结果为 3。 图 15 mapValues 算子 RDD 对转换 16combineByKey 下面代码为 combineByKey 函数的定义 combineByKey[C](createCombiner:(V) C, mergeValue:(C, V) C, mergeCombiners:(C, C) C, partitioner:Partitioner, mapSideCombine:Boolean=true, serializer:Serializer=null):RDD[(K,C)] 说明 createCombiner V => C C 不存在的情况下比如通过 V 创建 seq C。 mergeValue (C V) => C当 C 已经存在的情况下需要 merge比如把 item V 加到 seq C 中或者叠加。 mergeCombiners (C C) => C合并两个 C。 partitioner Partitioner, Shuff le 时需要的 Partitioner。 mapSideCombine Boolean = true为了减小传输量很多 combine 可以在 map 端先做比如叠加可以先在一个 partition 中把所有相同的 key 的 value 叠加 再 shuff le。 serializerClass String = null传输需要序列化用户可以自定义序列化类 例如相当于将元素为 (Int Int) 的 RDD 转变为了 (Int Seq[Int]) 类型元素的 RDD。图 16中的方框代表 RDD 分区。如图通过 combineByKey 将 (V1,2) (V1,1)数据合并为 V1,Seq(2,1)。 图 16 comBineByKey 算子对 RDD 转换 17reduceByKey reduceByKey 是比 combineByKey 更简单的一种情况只是两个值合并成一个值 Int Int Vto Int Int C比如叠加。所以 createCombiner reduceBykey 很简单就是直接返回 v而 mergeValue和 mergeCombiners 逻辑是相同的没有区别。 函数实现 def reduceByKey(partitioner: Partitioner, func: (V, V) => V): RDD[(K, V)] = { combineByKey[V]((v: V) => v, func, func, partitioner) } 图17中的方框代表 RDD 分区。通过用户自定义函数 (A,B) => (A + B) 函数将相同 key 的数据 (V1,2) 和 (V1,1) 的 value 相加运算结果为 V1,3。 图 17reduceByKey 算子对 RDD 转换 18partitionBy partitionBy函数对RDD进行分区操作。 函数定义如下。 partitionBypartitionerPartitioner如果原有RDD的分区器和现有分区器partitioner一致则不重分区如果不一致则相当于根据分区器生成一个新的ShuffledRDD。 图18中的方框代表RDD分区。 通过新的分区策略将原来在不同分区的V1、 V2数据都合并到了一个分区。 图18 partitionBy算子对RDD转换 19Cogroup cogroup函数将两个RDD进行协同划分cogroup函数的定义如下。 cogroup[W]other RDD[K W] numPartitions Int RDD[K Iterable[V] Iterable[W]] 对在两个RDD中的Key-Value类型的元素每个RDD相同Key的元素分别聚合为一个集合并且返回两个RDD中对应Key的元素集合的迭代器。 K Iterable[V] Iterable[W] 其中Key和ValueValue是两个RDD下相同Key的两个数据集合的迭代器所构成的元组。 图19中的大方框代表RDD大方框内的小方框代表RDD中的分区。 将RDD1中的数据U11、 U12和RDD2中的数据U12合并为U1122。 图19 Cogroup算子对RDD转换 20join join 对两个需要连接的 RDD 进行 cogroup函数操作将相同 key 的数据能够放到一个分区在 cogroup 操作之后形成的新 RDD 对每个key 下的元素进行笛卡尔积的操作返回的结果再展平对应 key 下的所有元组形成一个集合。最后返回 RDD[(K (V W))]。 下 面 代 码 为 join 的 函 数 实 现 本 质 是通 过 cogroup 算 子 先 进 行 协 同 划 分 再 通 过flatMapValues 将合并的数据打散。 this.cogroup(other,partitioner).f latMapValues{case(vs,ws) =>for(v<-vs;w<-ws)yield(v,w) } 图 20是对两个 RDD 的 join 操作示意图。大方框代表 RDD小方框代表 RDD 中的分区。函数对相同 key 的元素如 V1 为 key 做连接后结果为 (V1,(1,1)) 和 (V1,(1,2))。 图 20 join 算子对 RDD 转换 21eftOutJoin和rightOutJoin LeftOutJoin左外连接和RightOutJoin右外连接相当于在join的基础上先判断一侧的RDD元素是否为空如果为空则填充为空。 如果不为空则将数据进行连接运算并 返回结果。 下面代码是leftOutJoin的实现。 if ws.isEmpty { vs.mapv => v None } else { for v <- vs w <- ws yield v Somew } 2. Actions 算子 本质上在 Action 算子中通过 SparkContext 进行了提交作业的 runJob 操作触发了RDD DAG 的执行。 例如 Action 算子 collect 函数的代码如下感兴趣的读者可以顺着这个入口进行源码剖析 /** * Return an array that contains all of the elements in this RDD. */ def collect(): Array[T] = { /* 提交 Job*/ val results = sc.runJob(this, (iter: Iterator[T]) => iter.toArray) Array.concat(results: _*) } 22foreach foreach 对 RDD 中的每个元素都应用 f 函数操作不返回 RDD 和 Array 而是返回Uint。图22表示 foreach 算子通过用户自定义函数对每个数据项进行操作。本例中自定义函数为 println()控制台打印所有数据项。 图 22 foreach 算子对 RDD 转换 23saveAsTextFile 函数将数据输出存储到 HDFS 的指定目录。 下面为 saveAsTextFile 函数的内部实现其内部 通过调用 saveAsHadoopFile 进行实现 this.map(x => (NullWritable.get(), new Text(x.toString))).saveAsHadoopFile[TextOutputFormat[NullWritable, Text]](path) 将 RDD 中的每个元素映射转变为 (null x.toString)然后再将其写入 HDFS。 图 23中左侧方框代表 RDD 分区右侧方框代表 HDFS 的 Block。通过函数将RDD 的每个分区存储为 HDFS 中的一个 Block。 图 23 saveAsHadoopFile 算子对 RDD 转换 24saveAsObjectFile saveAsObjectFile将分区中的每10个元素组成一个Array然后将这个Array序列化映射为NullBytesWritableY的元素写入HDFS为SequenceFile的格式。 下面代码为函数内部实现。 mapx=>NullWritable.getnew BytesWritableUtils.serializex 图24中的左侧方框代表RDD分区右侧方框代表HDFS的Block。 通过函数将RDD的每个分区存储为HDFS上的一个Block。 图24 saveAsObjectFile算子对RDD转换 25collect collect 相当于 toArray toArray 已经过时不推荐使用 collect 将分布式的 RDD 返回为一个单机的 scala Array 数组。在这个数组上运用 scala 的函数式操作。 图 25中左侧方框代表 RDD 分区右侧方框代表单机内存中的数组。通过函数操作将结果返回到 Driver 程序所在的节点以数组形式存储。 图 25 Collect 算子对 RDD 转换 26collectAsMap collectAsMap对KV型的RDD数据返回一个单机HashMap。 对于重复K的RDD元素后面的元素覆盖前面的元素。 图26中的左侧方框代表RDD分区右侧方框代表单机数组。 数据通过collectAsMap函数返回给Driver程序计算结果结果以HashMap形式存储。 图26 CollectAsMap算子对RDD转换 27reduceByKeyLocally 实现的是先reduce再collectAsMap的功能先对RDD的整体进行reduce操作然后再收集所有结果返回为一个HashMap。 28lookup 下面代码为lookup的声明。 lookupkeyKSeq[V] Lookup函数对KeyValue型的RDD操作返回指定Key对应的元素形成的Seq。 这个函数处理优化的部分在于如果这个RDD包含分区器则只会对应处理K所在的分区然后返回由KV形成的Seq。 如果RDD不包含分区器则需要对全RDD元素进行暴力扫描处理搜索指定K对应的元素。 图28中的左侧方框代表RDD分区右侧方框代表Seq最后结果返回到Driver所在节点的应用中。 图28 lookup对RDD转换 29count count 返回整个 RDD 的元素个数。 内部函数实现为 defcount():Long=sc.runJob(this,Utils.getIteratorSize_).sum 图 29中返回数据的个数为 5。一个方块代表一个 RDD 分区。 图29 count 对 RDD 算子转换 30top top可返回最大的k个元素。 函数定义如下。 topnumIntimplicit ordOrdering[T]Array[T] 相近函数说明如下。 ·top返回最大的k个元素。 ·take返回最小的k个元素。 ·takeOrdered返回最小的k个元素并且在返回的数组中保持元素的顺序。 ·first相当于top1返回整个RDD中的前k个元素可以定义排序的方式Ordering[T]。 返回的是一个含前k个元素的数组。 31reduce reduce函数相当于对RDD中的元素进行reduceLeft函数的操作。 函数实现如下。 Someiter.reduceLeftcleanF reduceLeft先对两个元素<KV>进行reduce函数操作然后将结果和迭代器取出的下一个元素<kV>进行reduce函数操作直到迭代器遍历完所有元素得到最后结果。在RDD中先对每个分区中的所有元素<KV>的集合分别进行reduceLeft。 每个分区形成的结果相当于一个元素<KV>再对这个结果集合进行reduceleft操作。 例如用户自定义函数如下。 fAB=>A._1+"@"+B._1A._2+B._2 图31中的方框代表一个RDD分区通过用户自定函数f将数据进行reduce运算。 示例 最后的返回结果为V1@[1]V2U@U2@U3@U412。 图31 reduce算子对RDD转换 32fold fold和reduce的原理相同但是与reduce不同相当于每个reduce时迭代器取的第一个元素是zeroValue。 图32中通过下面的用户自定义函数进行fold运算图中的一个方框代表一个RDD分区。 读者可以参照reduce函数理解。 fold"V0@"2 AB=>A._1+"@"+B._1A._2+B._2 图32 fold算子对RDD转换 33aggregate aggregate先对每个分区的所有元素进行aggregate操作再对分区的结果进行fold操作。 aggreagate与fold和reduce的不同之处在于aggregate相当于采用归并的方式进行数据聚集这种聚集是并行化的。 而在fold和reduce函数的运算过程中每个分区中需要进行串行处理每个分区串行计算完结果结果再按之前的方式进行聚集并返回最终聚集结果。 函数的定义如下。 aggregate[B]z Bseqop BA => Bcombop BB => B B 图33通过用户自定义函数对RDD 进行aggregate的聚集操作图中的每个方框代表一个RDD分区。 rdd.aggregate"V0@"2AB=>A._1+"@"+B._1A._2+B._2AB=>A._1+"@"+B_1A._@+B_.2 最后介绍两个计算模型中的两个特殊变量。 广播broadcast变量其广泛用于广播Map Side Join中的小表以及广播大变量等场景。 这些数据集合在单节点内存能够容纳不需要像RDD那样在节点之间打散存储。 Spark运行时把广播变量数据发到各个节点并保存下来后续计算可以复用。 相比Hadoo的distributed cache广播的内容可以跨作业共享。 Broadcast的底层实现采用了BT机制。 图33 aggregate算子对RDD转换 ②代表V。 ③代表U。 accumulator变量允许做全局累加操作如accumulator变量广泛使用在应用中记录当前的运行指标的情景。 本文转自大数据躺过的坑博客园博客原文链接http://www.cnblogs.com/zlslch/p/5723857.html如需转载请自行联系原作者

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

[BigData]关于Hadoop学习笔记第二天(PPT总结)(一)

Plan: 分布式文件系统与HDFS HDFS体系结构与基本概念 HDFS的shell操作 java接口及常用api HADOOP的RPC机制 HDFS源码分析 远程debug 自己设计一分布式文件系统? Distributed File System 1.数据量越来越多,在一个操作系统管辖的范围存不下了,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,因此迫切需要一种系统来管理多台机器上的文件,这就是分布式文件管理系统 。 2.是一种允许文件通过网络在多台主机上分享的文件系统,可让多机器上的多用户分享文件和存储空间。 3.通透性。让实际上是通过网络来访问文件的动作,由程序与用户看来,就像是访问本地的磁盘一般。 4.容错。即使系统中有某些节点脱机,整体来说系统仍然可以持续运作而不会有数据损失。 5.分布式文件管理系统很多,hdfs只是其中一种。适用于一次写入多次查询的情况,不支持并发写情况,小文件不合适。 HDFS的Shell 1.调用文件系统(FS)Shell命令应使用 bin/hadoop fs 的形式。 2.所有的FS shell命令使用URI路径作为参数。 URI格式是scheme://authority/path。HDFS的scheme是hdfs,对本地文件系统,scheme是file。其中scheme和authority参数都是可选的,如果未加指定,就会使用配置中指定的默认scheme。 例如:/parent/child可以表示成hdfs://namenode:namenodePort/parent/child,或者更简单的/parent/child(假设配置文件是namenode:namenodePort) 3.大多数FS Shell命令的行为和对应的Unix Shell命令类似。 HDFS fs命令 -help [cmd] //显示命令的帮助信息 -ls(r) <path> //显示当前目录下所有文件 -du(s) <path> //显示目录中所有文件大小 -count[-q] <path> //显示目录中文件数量 -mv <src> <dst> //移动多个文件到目标目录 -cp <src> <dst> //复制多个文件到目标目录 -rm(r) //删除文件(夹) -put <localsrc> <dst> //本地文件复制到hdfs -copyFromLocal //同put -moveFromLocal //从本地文件移动到hdfs -get [-ignoreCrc] <src> <localdst> //复制文件到本地,可以忽略crc校验 -getmerge <src> <localdst> //将源目录中的所有文件排序合并到一个文件中 -cat <src> //在终端显示文件内容 -text <src> //在终端显示文件内容 -copyToLocal [-ignoreCrc] <src> <localdst> //复制到本地 -moveToLocal <src> <localdst> -mkdir <path> //创建文件夹 -touchz <path> //创建一个空文件 HDFS的Shell命令练习 #hadoop fs -ls / 查看HDFS根目录 #hadoop fs -mkdir /test 在根目录创建一个目录test #hadoop fs -mkdir /test1 在根目录创建一个目录test1 #hadoop fs -put ./test.txt /test 或#hadoop fs -copyFromLocal ./test.txt /test #hadoop fs -get /test/test.txt . 或#hadoop fs -getToLocal /test/test.txt . #hadoop fs -cp /test/test.txt /test1 #hadoop fs -rm /test1/test.txt #hadoop fs -mv /test/test.txt /test1 #hadoop fs -rmr /test1 HDFS架构 NameNode DataNode Secondary NameNode HDFS Architecture 元数据存储细节 NameNode 1.是整个文件系统的管理节点。它维护着整个文件系统的文件目录树,文件/目录的元信息和每个文件对应的数据块列表。接收用户的操作请求。 2.文件包括: ①fsimage:元数据镜像文件。存储某一时段NameNode内存元数据信息。(hdfs-site.xml的dfs.name.dir属性 ) ②edits:操作日志文件。 ③fstime:保存最近一次checkpoint的时间 3.以上这些文件是保存在linux的文件系统中。 NameNode的工作特点 1.Namenode始终在内存中保存metedata,用于处理“读请求” 2.到有“写请求”到来时,namenode会首先写editlog到磁盘,即向edits文件中写日志,成功返回后,才会修改内存,并且向客户端返回 3.Hadoop会维护一个fsimage文件,也就是namenode中metedata的镜像,但是fsimage不会随时与namenode内存中的metedata保持一致,而是每隔一段时间通过合并edits文件来更新内容。Secondary namenode就是用来合并fsimage和edits文件来更新NameNode的metedata的。 SecondaryNameNode 1.HA的一个解决方案。但不支持热备。配置即可。 2.执行过程:从NameNode上下载元数据信息(fsimage,edits),然后把二者合并,生成新的fsimage,在本地保存,并将其推送到NameNode,替换旧的fsimage. 3.默认在安装在NameNode节点上,但这样...不安全! secondary namenode的工作流程 1.secondary通知namenode切换edits文件 2.secondary从namenode获得fsimage和edits(通过http) 3.secondary将fsimage载入内存,然后开始合并edits 4.secondary将新的fsimage发回给namenode 5.namenode用新的fsimage替换旧的fsimage 什么时候checkpiont 1.fs.checkpoint.period 指定两次checkpoint的最大时间间隔,默认3600秒。 2.fs.checkpoint.size 规定edits文件的最大值,一旦超过这个值则强制checkpoint,不管是否到达最大时间间隔。默认大小是64M。 Datanode 1.提供真实文件数据的存储服务。 2.文件块(block):最基本的存储单位。对于文件内容而言,一个文件的长度大小是size,那么从文件的0偏移开始,按照固定的大小,顺序对文件进行划分并编号,划分好的每一个块称一个Block。HDFS默认Block大小是128MB,以一个256MB文件,共有256/128=2个Block. dfs.block.size 3.不同于普通文件系统的是,HDFS中,如果一个文件小于一个数据块的大小,并不占用整个数据块存储空间 4.Replication。多复本。默认是三个。 hdfs-site.xml的dfs.replication属性 Shell命令练习:验证块大小 1.方法:上传大于128MB的文件,观察块大小 2.验证:使用 http://hadoop0:50070 观察 HDFS的java访问接口——FileSystem •写文件 create •读取文件 open •删除文件delete • • •创建目录 mkdirs •删除文件或目录 delete •列出目录的内容 listStatus •显示文件系统的目录和文件的元数据信息 getFileStatus HDFS的FileSystem读取文件 private static FileSystem getFileSystem() throws URISyntaxException, IOException { Configuration conf = new Configuration(); URI uri = new URI("hdfs://hadoop240:9000"); final FileSystem fileSystem = FileSystem.get(uri , conf); return fileSystem; } /** * 读取文件,调用fileSystem的open(path) * @throws Exception */ private static void readFile() throws Exception { FileSystem fileSystem = getFileSystem(); FSDataInputStream openStream = fileSystem.open(new Path("hdfs://itcast0106:9000/aaa")); IOUtils.copyBytes(openStream, System.out, 1024, false); IOUtils.closeStream(openStream); } HDFS的FileSystem目录 /** * 创建目录,调用fileSystem的mkdirs(path) * @throws Exception */ private static void mkdir() throws Exception { FileSystem fileSystem = getFileSystem(); fileSystem.mkdirs(new Path("hdfs://itcast0106:9000/bbb")); } /** * 删除目录,调用fileSystem的deleteOnExit(path) * @throws Exception */ private static void rmdir() throws Exception { FileSystem fileSystem = getFileSystem(); fileSystem.delete(new Path("hdfs://itcast0106:9000/bbb")); } HDFS的FileSystem遍历目录 /** * 遍历目录,使用FileSystem的listStatus(path) * 如果要查看file状态,使用FileStatus对象 * @throws Exception */ private static void list() throws Exception{ FileSystem fileSystem = getFileSystem(); FileStatus[] listStatus = fileSystem.listStatus(new Path("hdfs://itcast0106:9000/")); for (FileStatus fileStatus : listStatus) { String isDir = fileStatus.isDir()?"目录":"文件"; String name = fileStatus.getPath().toString(); System.out.println(isDir+" "+name); } } FileSystem 用户代码操作HDFS时,是直接调用FileSystem的子类完成的。 Remote Procedure Call 1.RPC——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。 2.RPC采用客户机/服务器模式。请求程序就是一个客户机,而服务提供程序就是一个服务器。首先,客户机调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。在服务器端,进程保持睡眠状态直到调用信息的到达为止。当一个调用信息到达,服务器获得进程参数,计算结果,发送答复信息,然后等待下一个调用信息,最后,客户端调用进程接收答复信息,获得进程结果,然后调用执行继续进行。 3.hadoop的整个体系结构就是构建在RPC之上的(见org.apache.hadoop.ipc)。 RPC示例 public interface Bizable extends VersionedProtocol{ public abstract String hello(String name); } class Biz implements Bizable{ @Override public String hello(String name){ System.out.println("被调用了"); return "hello "+name; } @Override public long getProtocolVersion(String protocol, long clientVersion) throws IOException { System.out.println("Biz.getProtocalVersion()="+MyServer.VERSION); return MyServer.VERSION; } } public class MyServer { public static int PORT = 3242; public static long VERSION = 23234l; public static void main(String[] args) throws IOException { final Server server = RPC.getServer(new Biz(), "127.0.0.1", PORT, new Configuration()); server.start(); } } public class MyClient { public static void main(String[] args) throws IOException { final InetSocketAddress inetSocketAddress = new InetSocketAddress("127.0.0.1", MyServer.PORT); final Bizable proxy = (Bizable) RPC.getProxy(Bizable.class, MyServer.VERSION, inetSocketAddress, new Configuration()); final String ret = proxy.hello("吴超"); System.out.println(ret); RPC.stopProxy(proxy); } } RPC调用流程 ClientProtocol l是客户端(FileSystem)与NameNode通信的接口。 DatanodeProtocol l是DataNode与NameNode通信的接口 NamenodeProtocol l是SecondaryNameNode与NameNode通信的接口。 HDFS读过程 1.初始化FileSystem,然后客户端(client)用FileSystem的open()函数打开文件 2.FileSystem用RPC调用元数据节点,得到文件的数据块信息,对于每一个数据块,元数据节点返回保存数据块的数据节点的地址。 3.FileSystem返回FSDataInputStream给客户端,用来读取数据,客户端调用stream的read()函数开始读取数据。 4.DFSInputStream连接保存此文件第一个数据块的最近的数据节点,data从数据节点读到客户端(client) 5.当此数据块读取完毕时,DFSInputStream关闭和此数据节点的连接,然后连接此文件下一个数据块的最近的数据节点。 6.当客户端读取完毕数据的时候,调用FSDataInputStream的close函数。 7.在读取数据的过程中,如果客户端在与数据节点通信出现错误,则尝试连接包含此数据块的下一个数据节点。 8.失败的数据节点将被记录,以后不再连接。 HDFS写过程 1.初始化FileSystem,客户端调用create()来创建文件 2.FileSystem用RPC调用元数据节点,在文件系统的命名空间中创建一个新的文件,元数据节点首先确定文件原来不存在,并且客户端有创建文件的权限,然后创建新文件。 3.FileSystem返回DFSOutputStream,客户端用于写数据,客户端开始写入数据。 4.DFSOutputStream将数据分成块,写入data queue。data queue由Data Streamer读取,并通知元数据节点分配数据节点,用来存储数据块(每块默认复制3块)。分配的数据节点放在一个pipeline里。Data Streamer将数据块写入pipeline中的第一个数据节点。第一个数据节点将数据块发送给第二个数据节点。第二个数据节点将数据发送给第三个数据节点。 5.DFSOutputStream为发出去的数据块保存了ack queue,等待pipeline中的数据节点告知数据已经写入成功。 6.当客户端结束写入数据,则调用stream的close函数。此操作将所有的数据块写入pipeline中的数据节点,并等待ack queue返回成功。最后通知元数据节点写入完毕。 7.如果数据节点在写入的过程中失败,关闭pipeline,将ack queue中的数据块放入data queue的开始,当前的数据块在已经写入的数据节点中被元数据节点赋予新的标示,则错误节点重启后能够察觉其数据块是过时的,会被删除。失败的数据节点从pipeline中移除,另外的数据块则写入pipeline中的另外两个数据节点。元数据节点则被通知此数据块是复制块数不足,将来会再创建第三份备份。 练习题 1.练习shell命令 2.在HDFS创建一个文本文件hadoop.test。内容自定;然后,用Java程序在本地终端打印hadoop.test文件内容 3.用Java程序实现copyFromLocal 思考题 1.hdfs的组成部分有哪些,分别解释一下 2.hdfs的高可靠如何实现 3.hdfs的常用shell命令有哪些 4.hdfs的常用java api有哪些 5.请用shell命令实现目录、文件的增删改查 6.请用java api实现目录、文件的增删改查 本文转自SummerChill博客园博客,原文链接:http://www.cnblogs.com/DreamDrive/p/4566838.html,如需转载请自行联系原作者

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

Hadoop概念学习系列之大数据、Hadoop和云计算(十三)

我们知道,Hadoop最擅长的事情就是可以高效地处理海量规模的数据,这样Hadoop就和大数据及云计算结下了不解之缘。讲解Hadoop、大数据以及云计算之间的关系,使你从大数据和云计算的角度来认识Hadoop。 大数据一般是指这样的数据:数据量巨大,需要运用新处理模式才能具有更强的决策力、洞察力和流程优化能力的海量、高增长率和多样化的信息资产。大数据可分成大数据技术、大数据工程、大数据科学和大数据应用等领域。目前人们谈论最多的是大数据技术和大数据应用,大数据工程和大数据科学尚未被重视。大数据工程指大数据的规划建设及其运营管理的系统工程;大数据科学关注的是大数据网络发展和运营过程中发现和验证大数据的规律及其与自然和社会活动之间的关系。 大数据的特征有四个层面: 第一、数据量巨大。从TB级别,跃升到PB级别; 第二、数据类型繁多。包括网络fl志、视频、图片、地理位置信息等; 第三,价值密度低。商业价值高,以视频为例.在连续不间断的监控过程中,可能有用的数据仅仅只有一两秒; 第四、处理速度快。最后这一点也和传统的数据挖掘技术有着本质的不同。业界将其归纳为4V —— Volume、Variety、Value 和Velocity。 上面我们介绍了大数据的基本概念以及其显著的特征,下面将从不同的维度来阐述大数据的核心问题。 1.数据态的多样性问题 大数据具有多态性,主要体现在数据源、结构及相关度上。在数据来源上包括(图像、视频、音频、文本、网页、数据流等;在结构上不仅仅包括结构化的数据,还包括非结构化的数据;在相关度上不仅有数据记录彼此间相关性问题,还有时间序列数据的相关性问题。 2.维度复杂性问题 首先,大数据中存在着多元空间的维度问题,例如典型的三元空间中大数据的产生、状态感应以及采集问题,这个问题在物联网中非常常见;其次,就是柔性粒度数据的传输、移动、存储及计算问题;最后,就是数据空间范围和数据密度的不均匀问题。 3.大数据存储问题 大数据最为显著的特征就是数据规模非常巨大,单机系统肯定无法解决存储问题,这就需要分布式存储系统作为大数据的存储支撑服务,而分布式存储系统需要考虑的核心问题包括:高可靠性、扩一展性、伸缩性、容灾及恢复等问题。 4.大数据计算分析问题 由大数据的特征可知,大数据在数据规模上非常巨大,要在一定的时间内达到撷取、管理、处理并整理为能够帮助企业做出经营决策更有效的资讯,传统的顺序计算模式必然不能满足这样的需求,这就要求使用集群计算系统来完成计算分析任务。基于集群的计算模型目前主要包括:基于消息传递的MPI , MapReduce计算模型、流式计算架构Storm , S4、高性能集群计算HPCC,以及基于共享内存RDD的Spark模型。 5.大数据价值挖掘问题 由于大数据的价值密度低而商业价值大,这使得大数据的价值挖掘显得格外重要,而价值挖掘主要包括两个阶段:第一个阶段就是过滤清洗,需要在尽量不损失其价值的条件下减小数据规模,同时在不改变数据基本属性的情况下采取数据清洗、抽样、去重、过滤、筛选、压缩、索引、提取元数据等方法,以直接将大数据变小;第二个阶段就是对商业价值的挖掘,主要是发挥大数据探索式考察与可视化作用,人机的交互分析可以将人的智慧融入数据,再者是通过群体智慧、社会计算、认知计算对数据价值进行提炼,从而挖掘出大数据中隐藏的商业价值。 大数据、Hadoop和云计算的关系 上面的内容讲述了大数据的基本概念及与大数据相关的几个核心问题,通过这些问题我们已对大数据有了一个初步的了解,那么大数据、Hadoop及云计算之间到底是什么关系呢?为了从大数据和云计算的角度去了解Hadoop,下面将阐述这三个概念之间的关系。 可以这样说,正是由于大数据对系统提出了很多极限的要求,不论是存储、传输还是计算,现有计算技术难以满足大数据的需求,因此整个IT架构的革命性重构势在必行,存储能力的增长远远赶不大数据的增长,设i十最合理的分层存储架构已成为信息系统的关键。分布式存储架构不仅需要scale up式的可扩展性,一也需要scale out式的可扩展性,因此大数据处理离不开云计算技术,云计算可为大数据提供弹性可扩展的基础设施支撑环境以及数据服务的高效模式,大数据则为云计算提供了新的商业价值,大数据技术与云计算技术必将有更完美的结合。 我们知道云计算的关键技术包括分布式并行计算、分布式存储以及分布式数据管理技术,而Hadoop就是一个实现了Google云计算系统的开源平台,包括并行计算模型MapReduce、分布式文件系统HDFS,以及分布式数据库Hbase,同时Hadoop的相关项目也很丰富,包括ZooKeeper , Pig , Chukwa , Hive , Elbase , Mahout等,这些项日都使得Hadoop成为一个很大很完备的生态链系统。目前使用Hadoop技术实现的云计算平台包括IBM的蓝云.雅虎、英特尔的“云计划”,百度的云计算基础架构,阿里巴巴云计算平台,以及中国移动的B igCloud大云平台。 总而言之,用一句话概括就是云计算因大数据问题而生,大数据驱动了云讨一算的发展,而Hadoop在大数据和云计算之间建起了一座坚实可靠的桥梁。 本文转自大数据躺过的坑博客园博客,原文链接:http://www.cnblogs.com/zlslch/p/5080573.html,如需转载请自行联系原作者

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

Spark RDD概念学习系列之Spark的算子的作用(十四)

Spark的算子的作用 首先,关于spark算子的分类,详细见http://www.cnblogs.com/zlslch/p/5723857.html 1、Transformation 变换/转换算子 1、map算子 2、flatMap算子 3、mapPartitions算子 4、union算子 5、cartesian算子 6、grouBy算子 7、filter算子 8、sample算子 9、cache算子 10、persist算子 11、mapValues算子 12、combineByKey算子 13、reduceByKey算子 14、join算子 2、Action 行动算子 1、foreach算子 2、saveAsTextFile算子 3、collect算子 4、count算 简单地总结: 通过Action算子,触发Spark提交作业。 通过Cache算子,将数据缓存到内存。 图1 Spark算子和数据空间 上图描述了Spark的输入、 运行转换、 输出。 在运行转换中通过算子对RDD进行转换。算子是RDD中定义的函数,可以对RDD中的数据进行转换和操作。 1)输入:在Spark程序运行中,数据从外部数据空间(如分布式存储:textFile读取HDFS等,parallelize方法输入Scala集合或数据)输入Spark,数据进入Spark运行时数据空间,转化为Spark中的数据块,通过BlockManager进行管理。 2)运行:在Spark数据输入形成RDD后便可以通过变换算子,如fliter等,对数据进行作并将RDD转化为新的RDD,通过Action算子,触发Spark提交作业。 如果数据需要复用,可以通过Cache算子,将数据缓存到内存。 3)输出:程序运行结束数据会输出Spark运行时空间,存储到分布式存储中(如saveAsTextFile输出到HDFS),或Scala数据或集合中(collect输出到Scala集合,count返回Scala int型数据)。Spark的核心数据模型是RDD,但RDD是个抽象类,具体由各子类实现,如MappedRDD、 ShuffledRDD等子类。 Spark将常用的大数据操作都转化成为RDD的子类。 本文转自大数据躺过的坑博客园博客,原文链接:http://www.cnblogs.com/zlslch/p/5723979.html,如需转载请自行联系原作者

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

学习使用Docker、Docker-Compose和Rancher搭建部署Pipeline(一)

这篇文章是一系列文章的第一篇,在这一系列文章中,我们想要分享我们如何使用Docker、Docker-Compose和Rancher完成容器部署工作流的故事。我们想带你从头开始走过pipeline的革命历程,重点指出我们这一路上遇到的痛点和做出的决定,而不只是单纯的回顾。幸好有很多优秀的资源可以帮助你使用Docker设置持续集成和部署工作流。这篇文章并不属于这些资源之一。一个简单的部署工作流相对比较容易设置。但是我们的经验表明,构建一个部署系统的复杂性主要在于原本容易的部分需要在拥有很多依赖的遗留环境中完成,以及当你的开发团队和运营组织发生变化以支持新的过程的时候。希望我们在解决构建我们的pipeline的困难时积累下的经验会帮助你解决你在构建你的pipeline时遇到的困难。 在这第一篇文章里,我们将从头开始,看一看只用Docker时我们开发的初步的工作流。在接下来的文章中,我们将进一步介绍Docker-compose,最后介绍如何将Rancher应用到我们的工作流中。 为了为之后的工作铺平道路,假设接下来的事件都发生在一家SaaS提供商那里,我们曾经在SaaS提供商那里提供过长时间服务。仅为了这篇文章的撰写,我们姑且称这家SaaS提供商为Acme Business Company, Inc,即ABC。这项工程开始时,ABC正处在将大部分基于Java的微服务栈从裸机服务器上的本地部署迁移到运行在AWS上的Docker部署的最初阶段。这项工程的目标很常见:发布新功能时更少的前置时间(lead time)以及更可靠的部署服务。 为了达到该目标,软件的部署计划大致是这样的: 这个过程从代码的变更、提交、推送到git仓库开始。当代码推送到git仓库后,我们的CI系统会被告知运行单元测试。如果测试通过,就会编译代码并将结果作为产出物(artifact)存储起来。如果上一步成功了,就会触发下一步的工作,利用我们的代码产出物创建一个Docker镜像并将镜像推送到一个Docker私有注册表(private Docker registry)中。最后,我们将我们的新镜像部署到一个环境中。 要完成这个过程,如下几点是必须要有的: 一个源代码仓库。ABC已经将他们的代码存放在GitHub私有仓库上了。 一个持续集成和部署的工具。ABC已经在本地安装了Jenkins。 一个私有registry。我们部署了一个Docker registry容器,由Amazon S3支持。 一个主机运行Docker的环境。ABC拥有几个目标环境,每个目标环境都包含过渡性(staging)部署和生产部署。 这样去看的话,这个过程表面上简单,然而实际过程中会复杂一些。像许多其它公司一样,ABC曾经(现在仍然是)将开发团队和运营团队划分为不同的组织。当代码准备好部署时,会创建一个包含应用程序和目标环境详细信息的任务单(ticket)。这个任务单会被分配到运营团队,并将会在几周的部署窗口内执行。现在,我们已经不能清晰地看到一个持续部署和分发的方法了。 最开始,部署任务单可能看起来是这样的: 1 2 3 DEPLOY- 111 : App:JavaService1,branch "release/1.0.1" Environment:Production 部署过程是: 部署工程师用了一周时间在Jenkins上工作,对相关的工程执行”Build Now“,将分支名作为参数传递。之后弹出了一个被标记的Docker镜像。这个镜像被自动的推送到了注册表中。工程师选择了环境中的一台当前没有在负载均衡器中被激活的Docker主机。工程师登陆到这台主机并从注册表中获取新的版本。 1 dockerpullregistry.abc.net/javaservice1:release- 1.0 . 1 找到现存的容器。 1 dockerps 终止现存容器运行。 1 dockerstop[container_id] 开启一个新容器,这个容器必须拥有所有正确启动容器所需的标志。这些标志可以从之前运行的容器那里,主机上的shell历史,或者其它地方的文档借鉴。 1 dockerrun-d-p 8080 : 8080 …registry.abc.net/javaservice1:release- 1.0 . 1 连接这个服务并做一些手工测试确定服务正常工作。 1 curllocalhost: 8080 /api/v1/version 在生产维护窗口中,更新负载均衡器使其指向更新过的主机。 一旦通过验证,这个更新会被应用到环境中所有其它主机上,以防将来需要故障切换(failover)。 不可否认的是,这个部署过程并不怎么让人印象深刻,但这是通往持续部署伟大的第一步。这里有好多地方仍可改进,但我们先考虑一下这么做的优点: 运营工程师有一套部署的方案,并且每个应用的部署都使用相同的步骤。在Docker运行那一步中需要为每个服务查找参数,但是大体步骤总是相同的:Docker pull、Docker stop、Docker run。这个过程非常简单,而且很难忘掉其中一步。 当环境中最少有两台主机时,我们便拥有了一个可管理的蓝绿部署(blue-green deployment)。一个生产窗口只是简单地从负载均衡器配置转换过来。这个生产窗口拥有明显且快速的回滚方法。当部署变得更加动态时,升级、回滚以及发现后端服务器变得愈发困难,需要更多地协调工作。因为部署是手动的,蓝绿部署代价是最小的,并且同样能提供优于就地升级的主要优点。 好吧,现在看一看痛点: 重复输入相同的命令。或者更准确地说,重复地在bash命令行里敲击输入。解决这一点很简单:使用自动化技术!有很多工具可以帮助你启动Docker容器。对于运营工程师,最明显的解决方案是将重复的逻辑包装成bash脚本,这样只需一条命令就可以执行相应逻辑。如果你将自己称作一个开发-运营(devops)工程师,你可能会去使用Ansible、Puppet、Chef或者SaltStack。编写脚本或剧本(playbooks)很简单,但是这里仍有几个问题需要说明:部署逻辑到底放在那里?你怎样追踪每个服务的不同参数?这些问题将带领我们进入下一点。 即便一个运营工程师拥有超能力,在办公室工作一整天后的深夜里仍能避免拼写错误,并且清晰的思考,他也不会知道有一个服务正在监听一个不同的端口并且需要改变Docker端口参数。问题的症结在于开发者确实了解应用运行的详细信息(但愿如此),但是这些信息需要被传递给运营团队。很多时候,运营逻辑放在另外的代码仓库中或这根本没有代码仓库。这种情况下保持应用相关部署逻辑的同步会变得困难。由于这个原因,一个很好的做法是将你的部署逻辑只提交到包含你的Dockerfile的代码仓库。如果在一些情况下无法做到这点,有一些方法可以使这么做可行(更多细节将在稍后谈到)。把细节信息提交到某处是重要的。代码要比部署任务单好,虽然在一些人的脑海中始终认为部署任务单更好。 可见性。对一个容器进行一个故障检测须要登陆主机并且运行相应命令。在现实中,这就意味着登陆许多主机然后运行“docker ps”和“docker logs –tail=100”的命令组合。有很多解决方案可以做到集中登陆。如果你有时间的话,还是相当值得设置成集中登陆的。我们发现,通常情况下我们缺少的能力是查看哪些容器运行在那些主机上的。这对于开发者而言是个问题。开发者想要知道什么版本被部署在怎样的范围内。对于运营人员来说,这也是个主要问题。他们须要捕获到要进行升级或故障检测的容器。 基于以上的情况,我们开始做出一些改变,解决这些痛点。 第一个改进是写一个bash脚本将部署中相同的步骤包装起来。一个简单的包装脚本可以是这样的: 1 2 3 4 5 6 !/bin/bash APPLICATION=$ 1 VERSION=$ 2 dockerpull "registry.abc.net/${APPLICATION}:${VERSION}" dockerrm-f$APPLICATION dockerrun-d--name "${APPLICATION}" "registry.abc.net/${APPLICATION}:${VERSION}" 这样做行得通,但仅对于最简单的容器而言,也就是那种用户不需要连接到的容器。为了能够实现主机端口映射和卷挂载(volume mounts),我们须要增加应用程序特定的逻辑。这里给出一个使用蛮力实现的方法: 1 2 3 4 5 6 7 8 9 10 11 12 13 APPLICATION=$ 1 VERSION=$ 2 case "$APPLICATION" in java-service- 1 ) EXTRA_ARGS= "-p8080:8080" ;; java-service- 2 ) EXTRA_ARGS= "-p8888:8888--privileged" ;; *) EXTRA_ARGS= "" ;; esac dockerpull "registry.abc.net/${APPLICATION}:${VERSION}" dockerstop$APPLICATION dockerrun-d--name "${APPLICATION}" $EXTRA_ARGS "registry.abc.net/${APPLICATION}:${VERSION}" 现在这段脚本被安装在了每一台Docker主机上以帮助部署。运营工程师会登陆到主机并传递必要的参数,之后脚本会完成剩下的工作。部署时的工作被简化了,工程师的需要做的事情变少了。然而将部署代码化的问题仍然存在。我们回到过去,把它变成一个关于向一个共同脚本提交改变并且将这些改变分发到主机上的问题。通常来说,这样做很值得。将代码提交到仓库会给诸如代码审查、测试、改变历史以及可重复性带来巨大的好处。在关键时刻,你要考虑的事情越少越好。 理想状况下,一个应用的相关部署细节和应用本身应当存在于同一个源代码仓库中。有很多原因导致现实情况不是这样,最突出的原因是开发人员可能会反对将运营相关的东西放入他们的代码仓库中。尤其对于一个用于部署的bash脚本,这种情况更可能发生,当然Dockerfile文件本身也经常如此。 这变成了一个文化问题并且只要有可能的话就值得被解决。尽管为你的部署代码维持两个分开的仓库确实是可行的,但是你将不得不耗费额外的精力保持两个仓库的同步。本篇文章当然会努力达到更好的效果,即便实现起来更困难。在ABC,Dockerfiles最开始在一个专门的仓库中,每个工程都对应一个文件夹,部署脚本存在于它自己的仓库中。 Dockerfiles仓库拥有一个工作副本,保存在Jenkins主机上一个熟知的地址中(就比如是‘/opt/abc/Dockerfiles’)。为了为一个应用创建Docker镜像,Jenkins会搜索Dockerfile的路径,在运行”docker build“前将Dockerfile和伴随的脚本复制进来。由于Dockerfile总是在掌控中,你便可能发现你是否处在Dockerfile超前(或落后)应用配置的状态,虽然实际中大部分时候都会处在正常状态。这是来自Jenkins构建逻辑的一段摘录: 1 2 3 4 5 6 7 8 9 if [-fdocker/Dockerfile];then docker_dir=Docker elif[-f/opt/abc/dockerfiles/$APPLICATION/Dockerfile];then docker_dir=/opt/abc/dockerfiles/$APPLICATION else echo "Nodockerfiles.Can’tcontinue!" exit 1 if dockerbuild-t$APPLICATION:$VERSION$docker_dir 随着时间的推移,Dockerfiles以及支持脚本会被迁移到应用程序的源码仓库中。由于Jenkins最开始已经查看了本地的仓库,pipeline的构建不再需要任何变化。在迁移了第一个服务后,仓库的结构大致是这样的: 我们使用分离的仓库时遇到的一个问题是,如果应用源码或打包逻辑任意一个发生改变,Jenkins就会触发应用的重建。由于Dockerfiles仓库包含了许多项目的代码,当改变发生时我们不想触发所有的仓库重建。解决方法是:使用在Jenkins Git插件中一个很隐蔽的选项,叫做Included Regions。当配置完成后,Jenkins将一个变化引起的重建隔离在仓库的某个特定子集里面。这允许我们将所有的Dockerfiles放在一个仓库里,并且仍然能做到当一个改变发生时只会触发特定的构建(与当改变发生在仓库里特定的目录时构建所有的镜像相比)。 关于这个初步的工作流的另一个方面是部署工程师必须在部署前强制构建一个应用镜像。这将导致额外的延迟,尤其是构建存在问题并且开发人员需要参与其中的时候。为了减少这种延迟,并为更加持续的部署铺平道路,我们开始为熟知分支中的每一个提交构建Docker镜像。这要求每一个镜像有一个独一无二的版本标识符,而如果我们仅仅依赖官方的应用版本字符串往往不能满足这一点。最终,我们使用官方版本字符串、提交次数和提交sha码的组合作为版本标识符。 1 2 3 commit_count=$(gitrev-list--countHEAD) commit_short=$(gitrev-parse-- short HEAD) version_string= "${version}-${commit_count}-${commit_short}" 这样得到的版本字符串看起来是这样的:1.0.1-22-7e56158 在结束pipeline的Docker file部分的讨论之前,还有一些参数值得提及。如果我们不会在生产中操作大量的容器,我们很少用到这些参数。但是,它们被证明有助于我们维护Docker集群的线上运行。 重启策略(Restart Policy)-一个重启策略允许你指定当一个容器退出时,每个容器采取什么动作。尽管这个可以被用作应用错误(application panic)时的恢复或当依赖上线时保持容器再次尝试连接,但对运营人员来说真正的好处是在Docker守护进程(daemon)或者主机重启后的自动恢复。从长远来看,你将希望实现一个适当的调度程序(scheduler),它能够在新主机上重启失败的容器。在那天到来之前,节省一些工作,设置一个重启策略吧。在现阶段的ABC中,我们将这项参数默认为“–restart always”,这将会使容器始终重启。简单地拥有一个重启策略就会使计划的(和非计划的)主机重启变得轻松得多。 资源约束(Resource Constraints)-使用运行时的资源约束,你可以设置容器允许消耗的最大内存和CPU。它不会把你从一般的主机过载(over-subscription)中拯救出来,但是它可以抑制住内存泄漏和失控的容器。我们先对容器应用一个充足的内存限制(例如:–memory=”8g”) 。我们知道当内存增长时这样会产生问题。尽管拥有一个硬性限制意味着应用最终会达到内存不足(Out-of-Memory)的状态并产生错误(panic),但是主机和其它容器会保持正确运行。 结合重启策略和资源约束会给你的集群带来更好的稳定性,与此同时最小化失败的影响,缩短恢复的时间。这种类型的安全防护可以让你和开发人员一起专注于“起火”的根本原因,而不是忙于应付不断扩大的火势。 简而言之,我们从一个基础的构建pipeline,即从我们的源码仓库中创建被标记的Docker镜像开始。从使用Docker CLI部署容器一路到使用脚本和代码中定义的参数部署容器。我们也涉及了如何管理我们的部署代码,并且强调了几个帮助运营人员保持服务上线和运行的Docker参数。 此时此刻,在我们的构建pipeline和部署步骤之间仍然存在空缺。部署工程师会通过登入一个服务器并运行部署脚本的方法填补这个空缺。尽管较我们刚开始时有所改进,但仍然有进一步提高自动化水平的空间。所有的部署逻辑都集中在单一的脚本内,当开发者需要安装脚本以及应付它的复杂性时,会使本地测试会变得困难得多。此时此刻,我们的部署脚本也包含了通过环境变量处理任何环境特定信息的方法。追踪一个服务设置的环境变量以及增加新的环境变量是乏味且容易出错的。 在下一篇文章中,我们将看一看怎样通过解构(deconstructing)共同的包装脚本解决这些痛点,并使部署逻辑向使用Docker Compose的应用更近一步。 您也可以下载免费的电子书《Continuous Integration and Deployment with Docker and Rancher》,这本书讲解了如何利用容器帮助你完成整个CI/CD过程。 原文来源:Rancher Labs 本文转自 RancherLabs 51CTO博客,原文链接:http://blog.51cto.com/12462495/1933287

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

开源中国iOS客户端学习——(十四)使用EGOImageLoading异步加载图片

EGOImageLoading 是一个用的比较多的异步加载图片的第三方类库,简化开发过程,我们直接传入图片的url,这个类库就会自动帮我们异步加载和缓存工作;当从网上获取图片时,如果网速慢图片短时间内不能下载下来,可以先用一张本地的图片代替显示,还可以进行其他操作,让图片下载完成后自动替换占位图片而不影响用户体验; EGOImageLoading 的GitHub 下载地址 https://github.com/enormego/EGOImageLoading GitHub上下载下来的类库会有一个Demo,如果运行出错说明缺少EGOCache类,在https://github.com/enormego/EGOCache添加道工程之中,或者直接在附件上下载 首先还是来分析一下开源中国iOS客户端如何使用这个第三方类库 在我搜索客户端中哪些类使用了这个类库的时候和预期的并不一样,在工程中有很多地方需要使用到图片的异步加载,而使用EGOImageLoading类库加载只有三个地方,也可以说是两个地方 一是在显示个人资料加载个人图片,显示个人信息时候使用的。 二个是显示你的粉丝或者你关注的人,想查看TA的资料的时候 在MyView类和UserView2类中,使用方法一样 声明一个 EGOImageView管理图片的异步加载 1 @property (strong,nonatomic) EGOImageView * egoImgView; 在ViewDidLoad方法中 1 2 3 4 5 6 7 // 初始化 self.egoImgView = [[EGOImageView alloc] initWithFrame:CGRectMake(15, 4, 70, 70)]; // 占位图片 self.egoImgView.image = [UIImage imageNamed:@ "big_avatar_loading.png" ]; // 设置图片圆角弧度 egoImgView.layer.cornerRadius = 10.0f; [self.view addSubview:self.egoImgView]; 然后就是在reload()方法中图片加载处理,先从网络解析获取图片的url资源,如果未获取到图片url仍然显示占位图片,如果获取到了就将占位图片更换为解析获取的图片 1 2 3 4 5 6 7 8 9 10 //头像 NSString *portrait_str = [TBXML textForElement:portrait]; if ([portrait_str isEqualToString:@ "" ]) { self.egoImgView.image = [UIImage imageNamed:@ "big_avatar.png" ]; } else { self.egoImgView.imageURL = [NSURL URLWithString:portrait_str]; } 以上就是使用EGOImageLoading 类库进行图片的异步加载; 以下是一个使用EGOImageLoading 类库进行图片异步加载的示例Demo,下载见附件 在开源中国iOS 客户端的问答、动弹、我的三个视图也涉及到图片的显示加载问题,刚开始误以为使用EGOImageLoading 类库异步加载图片,而实际上是一个延迟加载,先用占位图片显示,然后使用IconDownloader类库从服务器端将图片下载到本地缓存,在进行加载显示; 本文转自新风作浪 51CTO博客,原文链接:http://blog.51cto.com/duxinfeng/1214170,如需转载请自行联系原作者

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

Hadoop Hive概念学习系列之hive的数据压缩(七)

Hive文件存储格式包括以下几类: 1、TEXTFILE 2、SEQUENCEFILE 3、RCFILE 4、ORCFILE 其中TEXTFILE为默认格式,建表时不指定默认为这个格式,导入数据时会直接把数据文件拷贝到hdfs上不进行处理。 SEQUENCEFILE,RCFILE,ORCFILE格式的表不能直接从本地文件导入数据,数据要先导入到textfile格式的表中, 然后再从表中用insert导入SequenceFile,RCFile,ORCFile表中。 更多用法,一定要去看官网啊!!! https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL 一、TEXTFILE 格式默认格式,数据不做压缩,磁盘开销大,数据解析开销大。 可结合Gzip、Bzip2使用(系统自动检查,执行查询时自动解压),但使用这种方式,Hive不会对数据进行切分, 从而无法对数据进行并行操作。 示例: create table if not exists textfile_table( site string, url string, pv bigint, label string) row format delimited fields terminated by '\t' stored as textfile; 插入数据操作: Hive> Hive.exec.compress.output=true; Hive> set mapred.output.compress=true; Hive> set mapred.output.compression.codec=org.apache.hadoop.io.compress.GzipCodec; Hive> set io.compression.codecs=org.apache.hadoop.io.compress.GzipCodec; Hive> insert overwrite table textfile_table select * from textfile_table; 二、SEQUENCEFILE 格式 SequenceFile是Hadoop API提供的一种二进制文件支持,其具有使用方便、可分割、可压缩的特点。 SequenceFile支持三种压缩选择:NONE,RECORD,BLOCK。Record压缩率低,一般建议使用BLOCK压缩。 示例: create table if not exists seqfile_table( site string, url string, pv bigint, label string) row format delimited fields terminated by '\t' stored as sequencefile; 插入数据操作: Hive> set Hive.exec.compress.output=true; Hive> set mapred.output.compress=true; Hive> set mapred.output.compression.codec=org.apache.hadoop.io.compress.GzipCodec; Hive> set io.compression.codecs=org.apache.hadoop.io.compress.GzipCodec; Hive> SET mapred.output.compression.type=BLOCK; Hive> insert overwrite table seqfile_table select * from textfile_table; 三、RCFILE 文件格式 RCFILE是一种行列存储相结合的存储方式。首先,其将数据按行分块,保证同一个record在一个块上,避免读一个记录需要读取多个block。 其次,块数据列式存储,有利于数据压缩和快速的列存取。 RCFILE文件示例: create table if not exists rcfile_table( site string, url string, pv bigint, label string) row format delimited fields terminated by '\t' stored as rcfile; 插入数据操作: Hive> set Hive.exec.compress.output=true; Hive> set mapred.output.compress=true; Hive> set mapred.output.compression.codec=org.apache.hadoop.io.compress.GzipCodec; Hive> set io.compression.codecs=org.apache.hadoop.io.compress.GzipCodec; Hive> insert overwrite table rcfile_table select * from textfile_table; 四、ORCFILE() 以后补充 五、再看TEXTFILE、SEQUENCEFILE、RCFILE三种文件的存储情况: [hadoop@master ~]$ hadoop dfs -dus /user/Hive/warehouse/* hdfs://master:9000/user/Hive/warehouse/hbase_table_1 0 hdfs://master:9000/user/Hive/warehouse/hbase_table_2 0 hdfs://master:9000/user/Hive/warehouse/orcfile_table 0 hdfs://master:9000/user/Hive/warehouse/rcfile_table 102638073 hdfs://master:9000/user/Hive/warehouse/seqfile_table 112497695 hdfs://master:9000/user/Hive/warehouse/testfile_table 536799616 hdfs://master:9000/user/Hive/warehouse/textfile_table 107308067 [hadoop@singlehadoop ~]$ hadoop dfs -ls /user/Hive/warehouse/*/ -rw-r--r-- 2 hadoop supergroup 51328177 2014-03-20 00:42 /user/Hive/warehouse/rcfile_table/000000_0 -rw-r--r-- 2 hadoop supergroup 51309896 2014-03-20 00:43 /user/Hive/warehouse/rcfile_table/000001_0 -rw-r--r-- 2 hadoop supergroup 56263711 2014-03-20 01:20 /user/Hive/warehouse/seqfile_table/000000_0 -rw-r--r-- 2 hadoop supergroup 56233984 2014-03-20 01:21 /user/Hive/warehouse/seqfile_table/000001_0 -rw-r--r-- 2 hadoop supergroup 536799616 2014-03-19 23:15 /user/Hive/warehouse/testfile_table/weibo.txt -rw-r--r-- 2 hadoop supergroup 53659758 2014-03-19 23:24 /user/Hive/warehouse/textfile_table/000000_0.gz -rw-r--r-- 2 hadoop supergroup 53648309 2014-03-19 23:26 /user/Hive/warehouse/textfile_table/000001_1.gz 总结: 相比TEXTFILE和SEQUENCEFILE,RCFILE由于列式存储方式,数据加载时性能消耗较大,但是具有较好的压缩比和查询响应。 数据仓库的特点是一次写入、多次读取,因此,整体来看,RCFILE相比其余两种格式具有较明显的优势。 以下,本文转自于。http://blog.csdn.net/cnbird2008/article/details/9182869 Hive数据压缩 本文介绍Hadoop系统中Hive数据压缩方案的比较结果及具体压缩方法。 一、压缩方案比较 关于Hadoop HDFS文件的压缩格式选择,我们通过多个真实的Track数据做测试,得出结论如下: 1.系统的默认压缩编码方式 DefaultCodec 无论在压缩性能上还是压缩比上,都优于GZIP 压缩编码。这一点与网上的一些观点不大一致,网上不少人认为GZIP的压缩比要高一些,估计和Cloudera的封装及我们Track的数据类型有关。 2. Hive文件的RCFile 的在压缩比,压缩效率,及查询效率上都优于SEQENCE FILE (包括RECORD, BLOCK 级别) 。 3. 所有压缩文件均可以正常解压为TEXT 文件,但比原始文件略大,可能是行列重组造成的。 关于压缩文件对于其他组件是适用性如下: 1. Pig 不支持任何形式的压缩文件。 2. Impala 目前支持SequenceFile的压缩格式,但还不支持RCFile的压缩格式。 综上所述: 从压缩及查询的空间和时间性能上来说,DefaultCodeC + RCFile的压缩方式均为最优,但使用该方式,会使得Pig 和Impala 无法使用(Impala的不兼容不确定是否是暂时的)。 而DefaultCodeC+ SequenceFile 在压缩比,查询性能上略差于RCFile (压缩比约 6:5), 但可以支持 Impala实时查询。 推荐方案: 采用RCFile 方式压缩历史数据。FackBook全部hive表都用RCFile存数据。 二、局部压缩方法 只需要两步: 1.创建表时指定压缩方式,默认不压缩,以下为示例: create external table track_hist( id bigint, url string, referer string, keyword string, type int, gu_idstring, …/*此处省略中间部分字段*/ …, string,ext_field10 string) partitioned by (ds string)stored asRCFilelocation '/data/share/track_histk' ; 2. 插入数据是设定立即压缩 SET hive.exec.compress.output=true; insert overwrite table track_histpartition(ds='2013-01-01') select id,url, …/*此处省略中间部分字段*/ …, ext_field10 fromtrackinfo where ds='2013-01-01'; 三、全局方式,修改属性文件 在hive-site.xml中设置: <property> <name>hive.default.fileformat</name> <value>RCFile</value> <description>Default file format for CREATE TABLE statement.Options are TextFile and SequenceFile. Users can explicitly say CREAT E TABLE ... STORED AS&lt;TEXTFILE|SEQUENCEFILE&gt; to override</description> </property> <property> <name>hive.exec.compress.output</name> <value>true</value> <description> This controls whether the final outputs of a query(to a local/hdfs file or a hive table) is compressed. The compres sion codec and other options are determinedfrom hadoop config variables mapred.output.compress* </description> 四、注意事项 1、Map阶段输出不进行压缩 2、对输出文本进行处理时不压缩 本文转自大数据躺过的坑博客园博客,原文链接:http://www.cnblogs.com/zlslch/p/6103760.html,如需转载请自行联系原作者

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

英特尔推出全新自主学习芯片加速人工智能发展

Michael C. Mayberry博士 Michael C. Mayberry博士 英特尔公司副总裁兼英特尔研究院院长 Michael C. Mayberry博士现任英特尔公司副总裁兼英特尔研究院院长,负责英特尔在计算和通信领域的全球研究工作。此外,他还领导公司研究委员会,负责推动英特尔大学定向研究项目的资源调配与优先排序。 自从1984年加入英特尔公司并担任制程集成工程师以来,Mayberry博士曾在公司的多个职位任职。作为加州技术开发团队的成员,他开发了EPROM、闪存和逻辑晶圆制造工艺。1994年,他加入晶圆测试技术开发团队,负责英特尔微处理器测试流程的路线图制定与开发工作。2005年,他进入组件研究团队,负责为英特尔的技术开发部门提供未来制程的选项。 Mayberry博士于1983年在加州大学伯克利分校获得物理化学博士学位,并于

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

Hadoop概念学习系列之pagerank的友情链接(三十八)

博主我带大家,弄清楚一个事实。 比如,搜狐主页下方,有很多友情链接,这些友情链接,那可是一个位置就是多少钱。 有人说,一个位置多少钱,这又没有给我带来点击量,那我干嘛还每年花上几十万,给搜狐,就那么放在友情链接里呢? 不懂行情的人,说好傻啊。 其实啊,虽然,搜狐,没给它们带来流量和点击量,但是,带来了pr值,即pagerank值啊!亲 你的搜索引擎里的pr值或百度引擎值升高,就会造成你在自然排名中,你的排名放在前面。 这就是自然排名啊。放在前面越前。 本文转自大数据躺过的坑博客园博客,原文链接:http://www.cnblogs.com/zlslch/p/6056475.html,如需转载请自行联系原作者

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

Spark 概念学习系列之Spark相比Hadoop MapReduce的特点(二)

Spark相比Hadoop MapReduce的特点 (1)中间结果输出 基于MapReduce的计算引擎通常会将中间结果输出到磁盘上,进行存储和容错。 出于任务管道承接的考虑,当一些查询翻译到MapReduce任务时,往往会产生多个Stage,而这些串联的Stage又依赖于底层文件系统(如HDFS)来存储每一个Stage的输出结果。Spark将执行模型抽象为通用的有向无环图执行计划(DAG),这可以将多Stage的任务串联或者并行执行,而无须将Stage中间结果输出到HDFS中。 类似的引擎包括Dryad、Tez。 (2)数据格式和内存布局 由于MapReduce Schema on Read处理方式会引起较大的处理开销。 Spark抽象出分布式内存存储结构弹性分布式数据集RDD,进行数据的存储。 RDD能支持粗粒度写操作,但对于读取操作,RDD可以精确到每条记录,这使得RDD可以用来作为分布式索引。 Spark的特性是能够控制数据在不同节点上的分区,用户可以自定义分区策略,如Hash分区等。 Shark和Spark SQL在Spark的基础之上实现了列存储和列存储压缩。 (3)执行策略 在数据Shuffle之前花费了大量的时间来排序,Spark则可减轻上述问题带来的开销。 因为Spark任务在Shuffle中不是所有情景都需要排序,所以支持基于Hash的分布式聚合,调度中采用更为通用的任务执行计划图(DAG),每一轮次的输出结果在内存缓存。 (4)任务调度的开销 传统的MapReduce系统,如Hadoop,是为了运行长达数小时的批量作业而设计的,在某些极端情况下,提交一个任务的延迟非常高。Spark采用了事件驱动的类库AKKA来启动任务,通过线程池复用线程来避免进程或线程启动和切换开销。 本文转自大数据躺过的坑博客园博客,原文链接:http://www.cnblogs.com/zlslch/p/5706933.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应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

用户登录
用户注册