关于spark:大数据计算技术秘史下篇

上周太可研究所(techinstitute)公布了大数据中的计算机技术(上),次要沿着 Spark 梳理了计算引擎技术的局部改革。明天,咱们将沿用上期的思路,持续回顾计算机引擎的技术倒退及格局。 Vol.1只管大家始终强调“算法、算力、数据是 AI 的基石”,但 AI 和大数据技术栈在 10 年代并没有太多交加。一方面,大数据技术对只会写 Python 的算法同学来讲太难了;另一方面,数据方向的同学不太理解算法的场景。Spark 倒是很早之前就开发了 Spark ML 模块,社区里有 Spark NLP 这样的我的项目,且 Databricks 也始终宣称本人是一家 AI 公司。不过,以太可研究所(techinstitute)的经验来看,之前诞生的计算引擎都很难满足 AI 的需要。 AI 场景的确须要分布式计算框架,以满足 AI 负载的特点。总体来看,从大方向来看,AI 包含数据荡涤、训练、推理,须要解决结构化、非结构化数据,须要用到 GPU、CPU,而面向结构化、半结构化的而设计的计算引擎也只能做到数据荡涤这一步。而 AI 须要更符合本身的计算框架,这两年新兴的 Ray 我的项目填补了这一空缺。 Vol.2数据系统最大的问题是没有一个零碎能解决所有的用户需要。Hive 太慢,Spark 更专一离线解决,Presto 对数据更新不敌对,Flink 批处理能力太弱,ClickHouse 存储太关闭、join 不敌对。总之,每个计算引擎都有本人专一的畛域,也都有本人的局限性,所以大一点儿的公司都会集成很多产品,数据集成、对立的查问入口就成为了必需品。 因为离线计算、交互式查问、AI训练、流式计算等需要加在一起,光计算引擎就得部署好几个,再加上存储、调度、数据治理、BI、AI 等产品,让构建数据架构成为了一个非常复杂的工作。 其实,如果想要让架构简略,最现实的状态是一个产品能够满足所有需要。以后有两个方向的产品有心愿实现这一指标,一是从数据处理起家的 Spark,另一个是从数据库起家的 ClickHouse 和 Doris。 Spark 的劣势在于各方面都做得不错,劣势在交互式剖析偏慢,以及不是以服务的模式对外提供服务。目前, Spark 社区有 Gluten 这类 Native 执行引擎,用 C++ 或 Rust 重写执行引擎局部晋升交互式查问的性能。同时, Spark 3.4 之后减少了 Spark connect 模块,能够提供对外常驻服务。此外,Apache kyuubi 还在 Spark 之上构建了一层多租户、交互式的 JDBC 服务。 ...

February 28, 2024 · 1 min · jiezi

关于spark:Sparkplug-规范中涉及-MQTT-Broker-的-5-个关键概念

引言Sparkplug 是一种为 SCADA 零碎量身定制的工业物联网通信协议。它为工业设施和利用提供了一种规范的通信格局,实现了不同厂商设施的互操作性。Sparkplug 标准由 Cirrus Link Solutions 和 Eclipse Foundation 独特制订。它是凋谢的,不属于某一家公司。因而,它给 Sparkplug 社区带来了以下好处: 促成不同零碎和技术之间的顺畅合作,晋升效率、降低成本,为消费者提供更多抉择。保障不同厂商产品的兼容性和协作性,减少消费者的抉择,促成厂商之间的良性竞争。通过推动合作、分享想法和计划,激发翻新,促成新产品、新服务和新技术的倒退。进步透明度、建设信赖,升高厂商锁定或依赖繁多供应商的危险。让产品和服务对各种用户凋谢,包含残障人士。Sparkplug 旨在提供一种标准化的形式,将 MQTT 用于工业利用,并促成不同厂商的设施和零碎之间的互操作性。因而,Sparkplug 标准受到了工业物联网社区的宽泛认可,并失去了泛滥厂商和组织的反对。 概念 1 - MQTT 消息传递架构Sparkplug 标准基于 MQTT 协定,这是一种宽泛用于物联网利用的轻量级音讯协定。它专为低带宽、高提早的网络设计,因为具备以下能力而受到物联网利用的青眼。 轻量级:MQTT 是一种轻量级协定,占用极少的网络带宽,非常适合低带宽环境。可靠性:MQTT 反对不同的服务质量(QoS)等级,可能保障即便在网络故障或连贯不稳固的状况下,音讯也能牢靠地传递。扩展性:MQTT 具备很好的扩展性,能够反对百万级的设施和客户端。灵活性:MQTT 能够用于一对一和一对多的通信,并反对公布/订阅和申请/响应两种音讯模式。安全性:MQTT 反对平安个性,例如认证和加密,有助于确保数据安全窃密地传输。综上所述,应用 MQTT 实现 Sparkplug 标准有许多益处,非常适合工业物联网利用。最重要的是,基于 MQTT 公布/订阅音讯架构,Sparkplug 零碎实现了数据生产者和消费者的解耦。这使得数据交换过程更加灵便和可扩大,因为数据生产者和消费者能够独立地运行。 概念 2 - 会话状态感知解耦带来了扩展性、灵活性和弹性等多方面的好处,但同时也须要对会话进行治理,以确保零碎在多个申请和组件之间保持一致的状态。 会话状态感知是 Sparkplug 的外围个性之一,它使设施在网络连接中断或失落的状况下仍能与 Broker 维持连贯。这是通过利用 Broker 存储的会话状态信息来实现的。当连贯复原时,这些信息可用于从新建设通信。 当设施连贯到 Sparkplug Broker 时,它会与 Broker 创立一个会话。在此会话期间,设施能够公布和订阅音讯。Broker 会记录设施的会话状态,包含因为网络中断而未能传递的任何订阅或音讯。 对于须要高可用性和牢靠通信的工业物联网利用而言,会话状态感知是一个十分重要的个性。Sparkplug 通过保护会话状态信息来确保设施在网络中断后可能疾速与 Broker 从新建设通信,从而升高宕机和数据失落的危险。 概念 3 - 对立命名空间对立命名空间指的是,在工业环境中不同的设施和零碎可能不受厂商或通信协议的影响顺畅共享数据的能力。为了保障互操作性和便当的数据交换,它采纳一种规范的命名规定和数据模型。 另一方面,Sparkplug 是一种消息传递标准,用于使工业物联网设施和利用之间的通信更加高效和平安。它基于 MQTT 协定,交融了对立命名空间的概念,提供了一种标准化的形式来表白不同设施和零碎之间的数据和元数据。 ...

June 8, 2023 · 1 min · jiezi

关于spark:Spark-SQL-Java基础

1、根底操作package com.journey.sql;import com.alibaba.fastjson.JSON;import com.journey.sql.bean.User;import org.apache.spark.api.java.JavaRDD;import org.apache.spark.api.java.function.Function;import org.apache.spark.api.java.function.MapFunction;import org.apache.spark.sql.Dataset;import org.apache.spark.sql.Encoder;import org.apache.spark.sql.Encoders;import org.apache.spark.sql.Row;import org.apache.spark.sql.RowFactory;import org.apache.spark.sql.SparkSession;import org.apache.spark.sql.types.DataTypes;import org.apache.spark.sql.types.StructField;import org.apache.spark.sql.types.StructType;import java.util.ArrayList;import java.util.Arrays;import java.util.Collections;import java.util.List;import static org.apache.spark.sql.functions.col;public class SparkSQLTest { public static void main(String[] args) throws Exception { SparkSession spark = SparkSession .builder() .appName("Demo") .master("local[*]") .getOrCreate(); // 读取 json 文件 创立 DataFrame {"username": "lisi","age": 18},DataFrame是一种非凡的Dataset,行是Row Dataset<Row> df = spark.read().json("datas/sql/user.json"); // 展现表构造 + 数据 df.show(); // 打印schema构造 df.printSchema(); // 间接select df.select("username").show(); // 加1 df.select(col("username"), col("age").plus(1)).show(); // 过滤age大于19 df.filter(col("age").gt(19)).show(); // 统计age的个数 df.groupBy("age").count().show(); df.createOrReplaceTempView("user"); // 应用sql来查问 Dataset<Row> sqlDF = spark.sql("select * from user"); sqlDF.show(); // 注册DataFrame作为一个全局的长期视图 df.createGlobalTempView("user2"); spark.sql("select * from global_temp.user2").show(); spark.newSession().sql("select * from global_temp.user2").show(); /** * 数据集与 RDD 相似,然而,它们不应用 Java 序列化或 Kryo,而是应用专门的编码器来序列化对象以进行解决或通过网络传输。 * 尽管编码器和规范序列化都负责将对象转换为字节,但编码器是动静生成的代码,并应用一种格局,容许 Spark 执行许多操作, * 如过滤、排序和散列,而无需将字节反序列化回对象。 */ // 留神 : User不能是static润饰 User user = new User("qiaozhanwei", 20); Encoder<User> userEncoder = Encoders.bean(User.class); Dataset<User> javaBeanDS = spark.createDataset(Collections.singletonList(user), userEncoder); javaBeanDS.show(); Encoder<Integer> integerEncoder = Encoders.INT(); Dataset<Integer> primitiveDS = spark.createDataset(Arrays.asList(1, 2, 3), integerEncoder); Dataset<Integer> transformedDS = primitiveDS.map( (MapFunction<Integer, Integer>) value -> value + 1, integerEncoder); // java: 不兼容的类型: java.lang.Object无奈转换为java.lang.Integer[],跑不通 // Integer[] collect = transformedDS.collect(); transformedDS.show(); Dataset<User> userDS = spark.read().json("datas/sql/user.json").as(userEncoder); userDS.show(); JavaRDD<User> userRDD = spark.read().textFile("datas/sql/user.json") .javaRDD() .map(line -> { User userInfo = JSON.parseObject(line, User.class); return userInfo; }); Dataset<Row> user3DF = spark.createDataFrame(userRDD, User.class); user3DF.createOrReplaceTempView("user3"); List<User> userList = new ArrayList<>(); userList.add(new User("haha", 30)); Dataset<Row> dataFrame = spark.createDataFrame(userList, User.class); dataFrame.show(); Dataset<Row> teenagerDF = spark.sql("select * from user3 where age between 13 and 20"); Encoder<String> stringEncoder = Encoders.STRING(); Dataset<String> teenagerNamesByIndexDF = teenagerDF.map(new MapFunction<Row, String>() { @Override public String call(Row value) throws Exception { return "Name : " + value.getString(1); } }, stringEncoder); teenagerNamesByIndexDF.show(); Dataset<String> teenagerNamesByFieldDF = teenagerDF.map( (MapFunction<Row, String>) row -> "Name: " + row.<String>getAs("userName"), stringEncoder); teenagerNamesByFieldDF.show(); // 定义用户名字段类型 StructField userNameField = DataTypes.createStructField("name", DataTypes.StringType, true); // 定义年龄字段类型 StructField ageField = DataTypes.createStructField("age", DataTypes.IntegerType, true); List<StructField> fields = new ArrayList<>(); fields.add(userNameField); fields.add(ageField); StructType schema = DataTypes.createStructType(fields); JavaRDD<String> user2RDD = spark.sparkContext().textFile("datas/sql/user.txt", 2).toJavaRDD(); JavaRDD<Row> rowRDD = user2RDD.map(new Function<String, Row>() { @Override public Row call(String value) throws Exception { String[] fields = value.split(","); return RowFactory.create(fields[0], Integer.parseInt(fields[1])); } }); Dataset<Row> user4DF = spark.createDataFrame(rowRDD, schema); user4DF.createOrReplaceTempView("user4"); spark.sql("select * from user4").show(); spark.stop(); }}RDD、DataFrame和Dataset的关系及转换 ...

May 16, 2023 · 4 min · jiezi

关于spark:Spark-Core基础知识

1、RDDResilient Distributed Dataset (RDD),弹性分布式数据集 弹性是指什么?1、内存的弹性:内存与磁盘的主动切换2、容错的弹性:数据失落能够主动复原3、计算的弹性:计算出错重试机制4、分片的弹性:依据须要从新分片 分布式就是RDD中的计算逻辑依据分区划分Task发送Executor(不同节点)执行 数据集RDD中是划分了分区了,有数据的援用,不是数据的存储 次要个性A list of partitions 分区A function for computing each split 每个切片有一个计算A list of dependencies on other RDDs RDD之间是相互依赖的Optionally, a Partitioner for key-value RDDs (e.g. to say that the RDD is hash-partitioned) key/value模式的有分区器Optionally, a list of preferred locations to compute each split on (e.g. block locations for an HDFS file) 有优选的地位去计算分片2、RDD依赖血统package com.journey.core.wc;import org.apache.spark.SparkConf;import org.apache.spark.api.java.JavaPairRDD;import org.apache.spark.api.java.JavaRDD;import org.apache.spark.api.java.JavaSparkContext;import org.apache.spark.api.java.function.FlatMapFunction;import org.apache.spark.api.java.function.Function2;import org.apache.spark.api.java.function.PairFunction;import scala.Tuple2;import java.util.Arrays;import java.util.Iterator;import java.util.List;public class WordCount { public static void main(String[] args) { SparkConf conf = new SparkConf() .setAppName("WordCount") .setMaster("local[*]"); JavaSparkContext sc = new JavaSparkContext(conf); // 如果是集群上运行,间接就是hdfs门路了 JavaRDD<String> lineRDD = sc.textFile("datas/wc", 4); System.out.println(lineRDD.toDebugString()); System.out.println("*************************************"); JavaRDD<String> wordsRDD = lineRDD.flatMap(new FlatMapFunction<String, String>() { @Override public Iterator<String> call(String line) throws Exception { return Arrays.asList(line.split(" ")).iterator(); } }); System.out.println(wordsRDD.toDebugString()); System.out.println("*************************************"); JavaPairRDD<String, Integer> wordToPairRDD = wordsRDD.mapToPair(new PairFunction<String, String, Integer>() { @Override public Tuple2<String, Integer> call(String word) throws Exception { return Tuple2.apply(word, 1); } }); System.out.println(wordToPairRDD.toDebugString()); System.out.println("*************************************"); JavaPairRDD<String, Integer> word2CountRDD = wordToPairRDD.reduceByKey(new Function2<Integer, Integer, Integer>() { @Override public Integer call(Integer v1, Integer v2) throws Exception { return v1 + v2; } }); System.out.println(word2CountRDD.toDebugString()); System.out.println("*************************************"); List<Tuple2<String, Integer>> result = word2CountRDD.collect(); System.out.println(result); sc.stop(); }}输入后果 : ...

May 9, 2023 · 2 min · jiezi

关于spark:SparkCeleborn更快更稳更弹性

一、传统 Shuffle 的问题Apache Spark 是广为风行的大数据处理引擎,它有很多应用场景: Spark SQL、批处理、流解决、MLLIB、GraphX 等。在所有组件下是对立的 RDD 形象,RDD 血统通过两种依赖关系形容,窄依赖和宽依赖。其中宽依赖是撑持简单算子(Join, Agg 等)的要害,而宽依赖实现机制就是 Shuffle。 残缺内容请点击下方链接查看: https://developer.aliyun.com/article/1153123?utm_content=g_10... 版权申明:本文内容由阿里云实名注册用户自发奉献,版权归原作者所有,阿里云开发者社区不领有其著作权,亦不承当相应法律责任。具体规定请查看《阿里云开发者社区用户服务协定》和《阿里云开发者社区知识产权爱护指引》。如果您发现本社区中有涉嫌剽窃的内容,填写侵权投诉表单进行举报,一经查实,本社区将立即删除涉嫌侵权内容。

April 28, 2023 · 1 min · jiezi

关于spark:SparkCeleborn更快更稳更弹性

摘要:本文整顿自阿里云 EMR Spark 团队的周克勇(一锤),在 Spark&DS Meetup 的分享。本篇内容次要分为三个局部: 传统 Shuffle 的问题Apache Celeborn (Incubating)简介Celeborn 在性能、稳定性、弹性上的设计一、传统 Shuffle 的问题 Apache Spark 是广为风行的大数据处理引擎,它有很多应用场景: Spark SQL、批处理、流解决、MLLIB、GraphX 等。在所有组件下是对立的 RDD 形象,RDD 血统通过两种依赖关系形容,窄依赖和宽依赖。其中宽依赖是撑持简单算子(Join, Agg 等)的要害,而宽依赖实现机制就是 Shuffle。 传统的 Shuffle 实现如上图两头局部所示,每个 Mapper 对 Shuffle Output 的数据,依据 Partition ID 做排序,而后把排序好的数据和索引写入本地盘。Shuffle Read 阶段,Reducer 从所有 Mapper 的 Shuffle 文件里读取属于本人的 Partition 数据。但这种实现有如下几个缺点: 第一,依赖大容量的本地盘或云盘存储 Shuffle 数据,数据须要驻留直至生产实现。这就限度了存算拆散,因为存算拆散架构下,计算节点通常不心愿有大容量的本地盘,心愿计算完结就能够开释节点。第二,Mapper 做排序会占用较大内存,甚至触发堆外排序,引入额定的磁盘 IO。第三,Shuffle Read 有大量的网络连接,逻辑连接数是 m×n。第四,存在大量的随机读盘。假如一个 Mapper 的 Shuffle 数据是 128M,Reducer 的并发是 2000,那么每个文件将会被读 2000 次,每次只随机读 64k,这就很容易达到磁盘 IOPS 的瓶颈。第五,数据单正本,容错性不高。以上五点缺点最终导致不够高效、不够稳固以及不够弹性。 二、Apache Celeborn (Incubating) ...

February 9, 2023 · 3 min · jiezi

关于spark:BIGO-如何做到夜间同时运行-24K-个工作流实例

点亮 ⭐️ Star · 照亮开源之路 GitHub:https://github.com/apache/dol... 精彩回顾 近期,BIGO 的大数据研发工程师许名勇在社区线上 Meetup 上给大家分享了主题为《DS 及 SPARK 在 BIGO 的利用和改良》的演讲。 次要介绍了 BIGO 如何应用 DophinScheduler 来调度以 SPARK 为主的多种类型的离线工作,以及为了满足业务需要、晋升用户应用体验,在 DS 和 Spark 上所做的各种改良。 讲师介绍 许名勇 Bigo 大数据研发工程师 文章整顿:白鲸开源-曾辉 明天的演讲会围绕上面三点开展: Apache DolphinScheduler 利用详情Apache DolphinScheduler 改良Apache Spark 改良DS 利用详情01 为什么抉择DS?咱们原来的调度平台用过很多个,无一例外都碰到一些难以满足本身需要的痛点问题: Oozie :查看日志不便,短少工作状态统计、工作流数量多了后存在调度压力等;Airflow : 须要用 python 代码来绘制 DAG,存在肯定应用门槛;Crontab:就更原始了,而且是单点,应用不便。通过调研后,咱们最初抉择 DS 调度沿用至今,因为在肯定层面上 DS 满足咱们所有的需要。 对于咱们团队外部来说,次要的劣势是: 能对工作流 DAG 可视化进行编辑,简略易用,日志查看也比拟不便。去中心化的多 master 多 worker 架构,能够线性扩大,从而保障了高可用。反对的工作类型很丰盛,符合大数据生态,不便定制和革新。还反对补数,这个性能很实用。当然,抉择 Apache DolphinScheduler 还有一个契机,咱们正在自研一站式的数据开发平台,须要一个新的工作流调度零碎,综合所有的因素最终促成了咱们抉择海豚调度。 02 DS 集群详情DS 在咱们生产环境运行有1年工夫了,目前部署的状况是:1台 alert 服务,3台 api 服务,10 台 master 9台 worker,这些服务混合部署在10台物理机上。 ...

February 8, 2023 · 2 min · jiezi

关于spark:Spark-在-KaiwuDB-中的应用与实践

01 走进 Spark1、Spark 介绍 (1)Spark 是用于大规模数据处理的对立剖析引擎;(2)运行速度快:Spark 应用先进的 DAG 执行引擎,以反对循环数据流与内存计算,基于内存的执行速度可比 Haddop MapReduce 快上百倍,基于磁盘的执行速度也能快十倍;(3)易用性:Spark 反对应用 Scala、Java、Python 和 R 语言进行编程,简洁的 API 设计有助于用户轻松构建并行程序,并且能够通过 Spark Shell 进行交互式编程;(4)通用性:Spark 提供了残缺而弱小的技术栈,包含 SQL 查问、流式计算、机器学习和图算法组件,这些组件能够无缝整合在同一利用中,足以应答简单的计算;(5)运行模式多样:Spark 可运行于独立的集群模式中,或者运行于 Hadoop 中,也可运行 Amazon EC2 等云环境中,并且能够拜访 HDFS、Cassandra、HBase、Hive 等多种数据源。 2、 Spark 生态系统 Spark 生态圈即 BDAS(伯克利数据分析栈)蕴含了 Spark Core、Spark SQL、Spark Streaming、MLLib 和 GraphX 等组件,这些组件别离解决 Spark Core 提供内存计算框架、SparkStreaming 的实时处理利用、Spark SQL 的即时查问、MLlib 或 MLbase 的机器学习和 GraphX 的图解决,它们都是由 AMP 实验室提供,可能无缝的集成并提供一站式解决平台。  3、 Spark 实用的利用场景 (1)简单的批量解决(Batch Data Processing),偏重点在于解决海量数据的能力,至于处理速度可承受,通常的工夫可能在于数十分钟到数小时。另外随着 Spark 的 AQE 和 Runtime Filter Joins等性能的退出,Spark 性能也有了更大的晋升;(2)基于历史数据的交互式查问(Interactive Query),通常的工夫在数十秒到数十分钟之间;(3)基于实时数据流的数据处理(Streaming Data Processing),通常在数百毫秒到数秒之间。 ...

January 19, 2023 · 2 min · jiezi

关于spark:Apache-Spark-海豚调度PB-级数据调度挑战教你如何构建高效离线工作流

2010年,我国进入挪动互联网,数据规模成几何式增长。在大数据开源技术畛域,以Hadoop为外围的大数据生态系统面对海量数据也一直倒退与迭代,大数据处理流程中的各个开源组件,也一起开启了狂飙突进的大数据时代,推动整个行业开启了数字化改革之路。 * 2010-2025年寰球数据规模量,起源IDC 近年来,大数据行业的开发者都在感叹:技术迭代更新速度的太快了,往年还在风行,明年就可能被雪藏!其实咱们十分分明,技术永远是在“更新”或“替换”中失去倒退。 通过十余年倒退,已经的一些老牌开源我的项目已风光不在,大数据三驾马车(分布式文件系统GFS、计算引擎MapReduce、分布式数据库BigTable),其中的计算引擎MapReduce 逐步倒退到 Spark 时代,对于大数据调度新星 Apache DolphinScheduler 来说,集成大数据畛域优良的开源我的项目之后,如何突破数据孤岛,如何降本增效,如何应答大规模的数据离线调度也成为了新的挑战! 家喻户晓,因为各种起因, 遇到 Apache Spark 应用程序的失败是不可避免的。 最常见的故障之一是 OOM(驱动程序或执行程序级别的内存不足)。 咱们能够通过治理(调度、重试、警报等)Spark 应用程序以及 Apache DolphinScheduler 中的其余类型的工作,也不须要 Apache DolphinScheduler 生态系统之外的任何代码,并且还反对利落拽 Spark 工作解决其余的一些问题。 Apache Spark 是用于大规模数据处理的对立剖析引擎。是一个弱小的开源工具,它提供了 Java、Python、Scala 和 R 的高级 API,以及一个优化的引擎,反对用于数据分析和不同工作负载的通用计算图。Spark 另一个乏味的个性是它的疾速解决能力和容错能力,您能够释怀,在呈现资源故障的状况下,您的部署能够保持一致。 为了让两个社区的独特用户既有中央反馈,还有中央学习,咱们联结 Apache Spark 社区推出了这个主题流动:洞悉 Spark 任务调度新能力|Apache Spark + DolphinScheduler Meetup,如果你也是接触开源“计算引擎+调度”的用户,想理解最新 Spark 迷人的个性,那这次的分享你肯定不要错过了,咱们还顺便邀请了 EMR 数据开发平台团队负责人孙一凡、BIGO大数据研发工程师许名勇、EMR Spark 引擎负责人周克勇 ,通过他们的分享让你能更快更好更便捷的应用Apahce DolphinScheduler+Spark。 无论你是热衷于钻研开源技术的开发者,还是关注大数据最新技术动静的小伙伴,我都倡议你来听听,从中取得全新的灵感。 我置信社区破费精力筹备的流动,你肯定能听到一手的分享,失去一手的播种! Apache DolphinScheduler & Spark 联结 Meetup | 1月线上直播报名通道已开启,赶快预约吧! ...

January 9, 2023 · 1 min · jiezi

关于spark:Spark-在-KaiwuDB-中的应用与实践

线上沙龙-技术流第 24 期营业啦01月12日(周四)19:30开务数据库 - B站直播间 当数据库面对大量数据简单 OLAP 查问时,性能呈现局限性,无奈满足用户 AP 方面的高性能要求。为此,KaiwuDB 推出了此项解决方案:借助 Spark 平台,交融了 KaiwuDB 分布式集群及列存存储的性能劣势,定制了 Spark 工具,为用户提供一个高性能的 OLAP 解决方案,并满足了大数据生态的客户需要。 本期直播咱们邀请到 KaiwuDB 高级研发工程师李盟老师为大家介绍《Spark 在 KaiwuDB 中的利用与实际》。李老师次要负责 KaiwuDB 列存存储引擎的开发和保护,拓展优化 KaiwuDB 大数据工具,并参加主导定制化 Spark 计算下推等重点项目。 直播敲重点1、Spark 简介:根本介绍、Spark 的生态系统及倒退2、Spark 架构:架构组建、架构组成及运行流程3、Spark 定制化:数据读写、平安权限认证、地区亲和、计算下推、Spark 版本兼容对 Spark 利用与实际感兴趣的搭档千万不要错过本期直播,扫描下方二维码,B 站直播不迷路,1月12日晚 7:30,咱们不见不散↓ ↓ ↓ KaiwuDB-线上沙龙系列流动如果你想理解数据库畛域的最新动静、前沿技术干货、实战落地案例等,那么开务数据库线上沙龙系列流动,你值得领有!咱们定期举办以技术、学术、培训等为主题的系列内容直播,欢送大家来 KaiwuDB- B 站直播间线上做客!让咱们一起携手漫游在数据库常识的陆地!

January 6, 2023 · 1 min · jiezi

关于spark:Spark从磁盘到内存的跨度

如果说对于的大数据处理最有奉献的当属Hadoop的三招绝学,HDFS、YARN、MapReduce,而Spark师从Hadoop,青出于蓝而胜于蓝,创立的Spark Core改良了Hadoop基于磁盘的分布式计算,独成一派创立了时机内存的分布式计算引擎。Hadoop MapReduce欲知Spark详情还必须从Hadoop的三招绝学说起,其一便是MapReduce。顾名思义,MapReduce实际上就是两种计算的形象,Map和Reduce类。Map:用于封装数据映射逻辑,通过map接口来定义数据转换流程关上文件Reduce:用户封装数据聚合逻辑,通过reduce接口来定义数据汇聚过程Map计算完结后,一般来说须要对数据进行散发能力启动Reduce计算逻辑来执行数据汇聚的操作,数据散发的过程称之为Shuffle。MapReduce 提供的分布式任务调度让开发者专一于业务逻辑实现,而无需关怀依赖治理、代码散发等分布式实现问题。在 MapReduce 框架下,为了实现端到端的计算作业,Hadoop 采纳 YARN 来实现分布式资源调度从而充分利用便宜的硬件资源,采纳 HDFS 作为计算形象之间的数据接口来躲避便宜磁盘引入的零碎稳定性问题。尽管Hadoop自成体系的三板斧能够实现任何分布式解决工作,然而也存在一个不可扭转的弊病,基于磁盘的分片正本会带来微小的磁盘I/O和网络I/O开销。Spark CoreSpark是基于Hadoop的一种改良,基于内存的分布式计算引擎。基于内存的计算并不是将所有的计算都放在的内存中实现,而是通过RDD来实现。RDDRDD(Resilient Distributed Datasets),全称是“弹性分布式数据集”,是Spark对于分布式数据进行形象的数据模型,这种数据模型用于囊括、封装所有内存中和磁盘中的分布式数据实体。RDD算子 VS HDFS算子?回顾Hadoop计算流程,MapReduce计算模型中采纳HDFS所做算子之间的数据接口,所有算子的长期后果都以文件的模式存储到HDFS,以供上游数据的生产,上游的算子再从HDFS读取文件转为键值对,通过Map或者Reduce操作后再以文件的存储到HDFS。不难发现,以HDFS作为数据接口才是Hadoop计算效率低的本源RDD 的设计以数据作为第一视角,不再强调算子的重要性,算子仅仅是 RDD 数据转换的一种计算规定,map 算子和 reduce 算子纷纷被弱化、浓缩。以RDD外围属性中的 dependencies 与 compute 来确定RDD流转操作,这两个操作形容了“从以后 RDD 登程,再通过怎么的计算规定与转换,能够取得新的数据集”。能够看出RDD通过dependencies 中指定的依赖关系和 compute 定义的计算逻辑形成了一条从终点到起点的数据转换门路。这条门路在Spark有个专门的术语,叫做Lineage——血统。Spark Core 依赖血统进行依赖治理、阶段划分、工作散发、失败重试,任意一个 Spark 计算作业都能够析构为一个 Spark Core 血统。另外三个外围属性就是partitions、partitioner 和 preferredLocations。partitions 属性记录了 RDD 的每一个数据分片,不便开发者灵便地拜访数据集partitioner 则形容了 RDD 划分数据分片的规定和逻辑,采纳不同的 partitioner 对 RDD 进行划分,可能以不同的形式失去不同数量的数据分片preferredLocations —— 地位偏好,该属性与 partitions 属性一一对应,定义了每一个数据分片的物理地位偏好。具体来说包含:本地内存、本地磁盘、本机架磁盘、其余机架磁盘Lineage VS DAG如果说Lineage是从数据流转的视角登程来形容RDD转换逻辑,那么DAG(Directed Acyclic Graph,有向无环图)就是就是从计算角度来形容RDD转换逻辑。由DAG实现的数据流转能够通过节点示意RDD数据,通过DAG的连接线示意算子的操作。依据RDD之间依赖关系的不同将DAG划分成不同的Stage(调度阶段)。对于窄依赖,partition的转换解决在一个Stage中实现计算。对于宽依赖,因为有Shuffle的存在,只能在parent RDD解决实现后,能力开始接下来的计算,因而宽依赖是划分Stage的根据。内存计算的由来本着缩小数据IO的目标,遵循“数据不动代码动”的准则。Spark Core尊重数据分片的存储地位的偏好,尽可能将计算散发到本地计算节点去执行,从而缩小来源于数据传输带来的大幅开销,进而从整体上晋升了执行性能。为了实现这一目标,RDD的5大外围属性别离从数据视角和计算视角来刻画数据模型的形象,任何分布式作业都能够通过RDD形象之间的转换来实现。实践上来说,如果计算节点的内存足够多,所有的RDD转换操作都能够放到内存中来执行。

November 29, 2022 · 1 min · jiezi

关于spark:Apache-Kyuubi-在B站大数据场景下的应用实践

01 背景介绍近几年随着B站业务高速倒退,数据量一直减少,离线计算集群规模从最后的两百台倒退到目前近万台,从单机房倒退到多机房架构。在离线计算引擎上目前咱们次要应用Spark、Presto、Hive。架构图如下所示,咱们的BI、ADHOC以及DQC服务都是通过自研的Dispatcher路由服务来实现对立SQL调度,Dispatcher会联合查问SQL语法特色、读HDFS量以及以后引擎的负载状况,动静地抉择以后最佳计算引擎执行工作。如果用户SQL失败了会做引擎主动降级,升高用户应用门槛;其中对于Spark查问晚期咱们都是走STS,然而STS自身有很多性能和可用性上的问题,因而咱们引入了Kyuubi,通过Kyuubi提供的多租户、多引擎代理以及齐全兼容Hive Thrift协定能力,实现各个部门Adhoc工作的资源隔离和权限验证。 Query查问状况 目前在Adhoc查问场景下,SparkSQL占比靠近一半,依赖Kyuubi对于Scala语法的反对,目前曾经有局部高级用户应用scala语法提交语句执行,并且能够在SQL和Scala模式做自在切换,这大大丰盛了adhoc的应用场景。 02 Kyuubi利用Kyuubi 是网易数帆大数据团队奉献给 Apache 社区的开源我的项目。Kyuubi 次要利用在大数据畛域场景,包含大数据离线计算、adhoc、BI等方向。Kyuubi 是一个分布式、反对多用户、兼容 JDBC 或 ODBC 的大数据处理服务。 为目前热门的计算引擎(例如Spark、Presto或Flink等)提供SQL等查问服务。 咱们抉择Kyuubi的起因: 1. 齐全兼容Hive thrift 协定,合乎B站已有的技术选型。 2. 高可用和资源隔离,对于大规模的生产环境必不可少。 3. 灵便可扩大,基于kyuubi能够做更多适配性开发。 4. 反对多引擎代理,为将来对立计算入口打下基础。 5. 社区高质量实现以及社区沉闷。 Kyuubi 的架构能够分成三个局部: 1.客户端: 用户应用jdbc或者restful协定来提交作业获取后果。 2.kyuubi server: 接管、治理和调度与客户端建设的Kyuubi Session,Kyuubi Session最终被路由到理论的引擎执行。 3.kyuubi engine: 承受解决 kyuubi server发送过去的工作,不同engine有着不同的实现形式。 03 基于Kyuubi的改良Kyuubi曾经在B站生产环境稳固运行一年以上,目前所有的Adhoc查问都通过kyuubi来接入大数据计算引擎。 在这一年中咱们经验了两次大版本的演进过程,从最后kyuubi 1.3到kyuubi 1.4版本,再从kyuubi 1.4降级kyuubi 1.6版本。与之前的STS相比,kyuubi在稳定性和查问性能方面有着更好的体现。在此演进过程中,咱们联合B站业务以及kyuubi性能特点,对kyuubi进行局部革新。 3.1 减少QUEUE模式Kyuubi Engine原生提供了CONNECTION、USER、GROUP和SERVER多种隔离级别。在B站大数据计算资源容量依照部门划分,不同部门在Yarn上对应不同的队列。咱们基于GROUP模式进行了革新,实现Queue级别的资源隔离和权限管制。 用户信息和队列的映射由下层工具平台对立配置和治理,Kyuubi只需关怀上游Dispatcher提交过去user和queue信息,进行调度并散发到对应队列的spark engine上进行计算。目前咱们有20+个adhoc队列,每个队列都对应一个或者多个Engine实例(Engine pool)。 3.2 在QUEUE模式下反对多租户kyuubi server端由超级用户Hive启动,在spark场景下driver和executor共享同一个的用户名。不同的用户提交不同的sql, driver端和executor端无奈辨别以后的工作是由谁提交的,在数据安全、资源申请和权限访问控制方面都存在着问题。 针对该问题,咱们对以下几个方面进行了革新。 3.2.1 kyuubi server端 ...

October 27, 2022 · 2 min · jiezi

关于spark:4SparkSQL中如何定义UDF和使用UDF

Spark SQL中用户自定义函数,用法和Spark SQL中的内置函数相似;是saprk SQL中内置函数无奈满足要求,用户依据业务需要自定义的函数。首先定义一个UDF函数: package com.udf;import org.apache.spark.sql.api.java.UDF1;import org.apache.spark.sql.api.java.UDF2;import org.apache.spark.sql.catalyst.expressions.GenericRowWithSchema;import scala.collection.mutable.WrappedArray;/** * Created by lj on 2022-07-25. */public class TestUDF implements UDF1<String, String> { @Override public String call(String s) throws Exception { return s+"_udf"; }}应用UDF函数: package com.examples;import com.pojo.WaterSensor;import com.udf.TestUDF;import org.apache.spark.SparkConf;import org.apache.spark.api.java.JavaRDD;import org.apache.spark.api.java.function.Function;import org.apache.spark.api.java.function.VoidFunction2;import org.apache.spark.sql.Dataset;import org.apache.spark.sql.Row;import org.apache.spark.sql.SparkSession;import org.apache.spark.sql.types.DataTypes;import org.apache.spark.streaming.Durations;import org.apache.spark.streaming.Time;import org.apache.spark.streaming.api.java.JavaDStream;import org.apache.spark.streaming.api.java.JavaReceiverInputDStream;import org.apache.spark.streaming.api.java.JavaStreamingContext;/** * Created by lj on 2022-07-25. */public class SparkSql_Socket_UDF { private static String appName = "spark.streaming.demo"; private static String master = "local[*]"; private static String host = "localhost"; private static int port = 9999; public static void main(String[] args) { //初始化sparkConf SparkConf sparkConf = new SparkConf().setMaster(master).setAppName(appName); //取得JavaStreamingContext JavaStreamingContext ssc = new JavaStreamingContext(sparkConf, Durations.minutes(3)); /** * 设置日志的级别: 防止日志反复 */ ssc.sparkContext().setLogLevel("ERROR"); //从socket源获取数据 JavaReceiverInputDStream<String> lines = ssc.socketTextStream(host, port); JavaDStream<WaterSensor> mapDStream = lines.map(new Function<String, WaterSensor>() { private static final long serialVersionUID = 1L; public WaterSensor call(String s) throws Exception { String[] cols = s.split(","); WaterSensor waterSensor = new WaterSensor(cols[0], Long.parseLong(cols[1]), Integer.parseInt(cols[2])); return waterSensor; } }).window(Durations.minutes(6), Durations.minutes(9)); //指定窗口大小 和 滑动频率 必须是批处理工夫的整数倍 mapDStream.foreachRDD(new VoidFunction2<JavaRDD<WaterSensor>, Time>() { @Override public void call(JavaRDD<WaterSensor> waterSensorJavaRDD, Time time) throws Exception { SparkSession spark = JavaSparkSessionSingleton.getInstance(waterSensorJavaRDD.context().getConf()); spark.udf().register("TestUDF", new TestUDF(), DataTypes.StringType); Dataset<Row> dataFrame = spark.createDataFrame(waterSensorJavaRDD, WaterSensor.class); // 创立长期表 dataFrame.createOrReplaceTempView("log"); Dataset<Row> result = spark.sql("select *,TestUDF(id) as udftest from log"); System.out.println("========= " + time + "========="); //输入前20条数据 result.show(); } }); //开始作业 ssc.start(); try { ssc.awaitTermination(); } catch (Exception e) { e.printStackTrace(); } finally { ssc.close(); } }}代码阐明:利用成果展现: ...

September 26, 2022 · 2 min · jiezi

关于spark:2sparkstreaming滚动窗口和滑动窗口演示

一、滚动窗口(Tumbling Windows) 滚动窗口有固定的大小,是一种对数据进行平均切片的划分形式。窗口之间没有重叠,也不会有距离,是“首尾相接”的状态。滚动窗口能够基于工夫定义,也能够基于数据个数定义;须要的参数只有一个,就是窗口的大小(window size)。在sparkstreaming中,滚动窗口须要设置窗口大小和滑动距离,窗口大小和滑动距离都是StreamingContext的间隔时间的倍数,同时窗口大小和滑动距离相等,如:.window(Seconds(10),Seconds(10)) 10秒的窗口大小和10秒的滑动大小,不存在重叠局部 package com.examples;import com.pojo.WaterSensor;import org.apache.spark.SparkConf;import org.apache.spark.api.java.JavaRDD;import org.apache.spark.api.java.function.Function;import org.apache.spark.api.java.function.VoidFunction2;import org.apache.spark.sql.Dataset;import org.apache.spark.sql.Row;import org.apache.spark.sql.SparkSession;import org.apache.spark.streaming.Durations;import org.apache.spark.streaming.Time;import org.apache.spark.streaming.api.java.JavaDStream;import org.apache.spark.streaming.api.java.JavaReceiverInputDStream;import org.apache.spark.streaming.api.java.JavaStreamingContext;/** * Created by lj on 2022-07-12. */public class SparkSql_Socket_Tumble { private static String appName = "spark.streaming.demo"; private static String master = "local[*]"; private static String host = "localhost"; private static int port = 9999; public static void main(String[] args) { //初始化sparkConf SparkConf sparkConf = new SparkConf().setMaster(master).setAppName(appName); //取得JavaStreamingContext JavaStreamingContext ssc = new JavaStreamingContext(sparkConf, Durations.minutes(1)); /** * 设置日志的级别: 防止日志反复 */ ssc.sparkContext().setLogLevel("ERROR"); //从socket源获取数据 JavaReceiverInputDStream<String> lines = ssc.socketTextStream(host, port); JavaDStream<WaterSensor> mapDStream = lines.map(new Function<String, WaterSensor>() { private static final long serialVersionUID = 1L; public WaterSensor call(String s) throws Exception { String[] cols = s.split(","); WaterSensor waterSensor = new WaterSensor(cols[0], Long.parseLong(cols[1]), Integer.parseInt(cols[2])); return waterSensor; } }).window(Durations.minutes(3), Durations.minutes(3)); //滚动窗口:须要设置窗口大小和滑动距离,窗口大小和滑动距离都是StreamingContext的间隔时间的倍数,同时窗口大小和滑动距离相等。 mapDStream.foreachRDD(new VoidFunction2<JavaRDD<WaterSensor>, Time>() { @Override public void call(JavaRDD<WaterSensor> waterSensorJavaRDD, Time time) throws Exception { SparkSession spark = JavaSparkSessionSingleton.getInstance(waterSensorJavaRDD.context().getConf()); Dataset<Row> dataFrame = spark.createDataFrame(waterSensorJavaRDD, WaterSensor.class); // 创立长期表 dataFrame.createOrReplaceTempView("log"); Dataset<Row> result = spark.sql("select * from log"); System.out.println("========= " + time + "========="); //输入前20条数据 result.show(); } }); //开始作业 ssc.start(); try { ssc.awaitTermination(); } catch (Exception e) { e.printStackTrace(); } finally { ssc.close(); } }}代码中定义了一个3分钟的工夫窗口和3分钟的滑动大小,运行后果能够看出数据没有呈现重叠,实现了滚动窗口的成果:二、滑动窗口(Sliding Windows)与滚动窗口相似,滑动窗口的大小也是固定的。区别在于,窗口之间并不是首尾相接的,而是能够“错开”肯定的地位。如果看作一个窗口的静止,那么就像是向前小步“滑动”一样。定义滑动窗口的参数有两个:除去窗口大小(window size)之外,还有一个滑动步长(window slide),代表窗口计算的频率。在sparkstreaming中,滑动窗口须要设置窗口大小和滑动距离,窗口大小和滑动距离都是StreamingContext的间隔时间的倍数,同时窗口大小和滑动距离不相等,如:.window(Seconds(10),Seconds(5)) 10秒的窗口大小和5秒的流动大小,存在重叠局部 ...

September 5, 2022 · 2 min · jiezi

关于spark:提速-10-倍深度解读字节跳动新型云原生-Spark-History-Server

更多技术交换、求职机会,欢送关注字节跳动数据平台微信公众号,回复【1】进入官网交换群前不久,在 6月29日 Databricks 举办的 Data + AI Summit 上,火山引擎向大家首次介绍了 UIMeta,一款致力于监控、剖析和优化的新型云原生 Spark History Server,相比于传统的事件日志文件,它在放大了近乎 10倍体积的根底上,竟然还实现了提速 10倍!!! 目前,UIMeta Service 曾经取代了原有的 History Server,为字节跳动每天数百万的作业提供服务,并且成为火山引擎 湖仓一体剖析服务 LAS(LakeHouse Analytics Service)的默认服务。 实际上,对于 History Server来说,事件日志蕴含太多冗余信息,长时间运行的应用程序可能会带来微小的事件日志,这可能须要大量保护并且须要很长时间能力重构 UI 数据从而提供服务。在大规模生产中,作业的数量可能很大,会给历史服务器带来惨重的累赘。接下来,火山引擎 LAS 团队将向大家具体介绍字节跳动外部是怎么基于 UIMeta 实现海量数据业务的安稳和高效运行,让技术驱动业务一直倒退。 业务背景开源 Spark History Server 架构为了可能更好了解本次重构的背景和意义,首先对原生 Spark History Server 原理做个简略的介绍。 开源 Spark History Server 流程图 Spark History 建设在 Spark 事件(Spark Event)体系之上。在 Spark 工作运行期间会产生大量蕴含运行信息的SparkListenerEvent,例如 ApplicationStart / StageCompleted / MetricsUpdate 等等,都有对应的 SparkListenerEvent 实现。所有的 event 会发送到ListenerBus中,被注册在ListenerBus中的所有listener监听。其中EventLoggingListener是专门用于生成 event log 的监听器。它会将 event 序列化为 Json 格局的 event log 文件,写到文件系统中(如 HDFS)。通常一个机房的工作的文件都存储在一个门路下。 ...

August 31, 2022 · 2 min · jiezi

关于spark:1sparkstreaming结合sparksql读取socket实时数据流

Spark Streaming是构建在Spark Core的RDD根底之上的,与此同时Spark Streaming引入了一个新的概念:DStream(Discretized Stream,离散化数据流),示意连续不断的数据流。DStream形象是Spark Streaming的流解决模型,在外部实现上,Spark Streaming会对输出数据依照工夫距离(如1秒)分段,每一段数据转换为Spark中的RDD,这些分段就是Dstream,并且对DStream的操作都最终转变为对相应的RDD的操作。Spark SQL 是 Spark 用于结构化数据(structured data)解决的 Spark 模块。Spark SQL 的前身是Shark,Shark是基于 Hive 所开发的工具,它批改了下图所示的右下角的内存治理、物理打算、执行三个模块,并使之能运行在 Spark 引擎上。(1)pom依赖:<dependencies> <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-core_${scala.version}</artifactId> <version>${spark.version}</version></dependency><dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-streaming_${scala.version}</artifactId> <version>${spark.version}</version></dependency><dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-sql_${scala.version}</artifactId> <version>${spark.version}</version></dependency><dependency> <groupId>org.scala-lang</groupId> <artifactId>scala-library</artifactId> <version>2.11.11</version></dependency><dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-streaming-kafka-0-10_2.11</artifactId> <version>2.3.1</version></dependency><dependency> <groupId>org.apache.kafka</groupId> <artifactId>kafka-clients</artifactId> <version>2.3.1</version></dependency><dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.66</version></dependency></dependencies>(2)定义音讯对象package com.pojo; import java.io.Serializable;import java.util.Date; /** Created by lj on 2022-07-13. */public class WaterSensor implements Serializable { public String id;public long ts;public int vc;public WaterSensor(){}public WaterSensor(String id,long ts,int vc){ this.id = id; this.ts = ts; this.vc = vc;}public int getVc() { return vc;}public void setVc(int vc) { this.vc = vc;}public String getId() { return id;}public void setId(String id) { this.id = id;}public long getTs() { return ts;}public void setTs(long ts) { this.ts = ts;}}(3)构建数据生产者package com.producers; ...

August 31, 2022 · 2 min · jiezi

关于spark:Spark-Optimizer-规则下的-BUG-排查与修复全记录

本文作者: 朱亮堂,观远数据计算引擎开发工程师,13 年毕业于湖南大学,有七年多的大数据研发教训。曾就任于出名互联网公司数据研发专家岗位,负责打造服务公司外部各业务线的数据中台,是开源我的项目 byzer-lang(基于 Spark 的开源中台计算引擎)的次要贡献者之一。背景测试同学在外部环境测试发现一个重大的问题,ETL 执行后果不合乎预期,依据 Rawdata Date 字段筛选 等于 2022-07-12 筛选进去的数据是 7.11 号的,间接筛选 2022-07-11 进去的数据是空的。 排查过程简化逻辑ETL 流程过于宏大,首先须要花点工夫简化 ETL,尽量最小化的复现出问题,利于排查。简化的办法:如果 ETL 执行工夫较长,首先缩减数据集的大小,能够 limit 之后保留新的数据集,用新的数据集进行测试。从头尾往两头缩减逻辑,直到不能复现问题。头部的缩减能够保留长期数据集,而后应用长期数据集进行计算,尾部的则间接预览上一个步骤的后果。简化后的逻辑是两个数据集,一张 A 表,有日期类型字段 a,一张 B 表,有日期类型字段 a,b,用 sql 示意为: select  to_date(a) as a, to_date(b) as b from (select to_date(a) as a, to_date(A)  as b from (select to_date(a) as a from A group by to_date(a)) t1union all select to_date(a) as a, to_date(b) as b from B group by to_date(a), to_date(b)) t2group by  to_date(a), to_date(b)当然 job engine 失去的是脚本文件,这里写成 sql 更加直观看出逻辑,通过查看脚本,确定 BI 生成的逻辑是正确的,那问题是出在了 engine 层。 spark 本地复现排查本地复现将简化后的脚本转化为 spark 算子或者 spark sql,测试环境是 spark 3.2.1,在 spark 3.2.1 版本复现了该问题,本地复现后就便于去 debug 调试。  test("test1") {    val sqlText =      """        |select to_date(a) a, to_date(b) b from        |(select  to_date(a) a, to_date(a) as b from        |(select to_date(a) a from        | values ('2020-02-01') as t1(a)        | group by to_date(a)) t3        |union all        |select to_date(a) a, to_date(b) b from        |(select to_date(a) a, to_date(b) b from        |values ('2020-01-01','2020-01-02') as t1(a, b)        | group by to_date(a), to_date(b)) t4) t5        |group by to_date(a), to_date(b)        |""".stripMargin    spark.sql(sqlText).show()  }期待的后果:返回的后果: 能够看进去,所有数据的 b 取了 a 的值,接下来就是查看 spark 执行打算。 执行打算 先简略介绍下 Spark Catalyst 优化器。一条 SQL 语句生成执行引擎可辨认的程序,就离不开解析(Parser)、优化(Optimizer)、执行(Execution) 这三大过程。 而 Catalyst 优化器在执行打算生成和优化的工作时候,它离不开本人外部的五大组件,如下所示: ...

August 25, 2022 · 2 min · jiezi

关于spark:Spark-Driver-CPU-占用异常问题排查

本文作者: Jamie,观远数据in-house Spark之父,ABI畛域史诗级工程师。年初咱们接到了一个客户反馈,示意服务器 cpu 占用异样,于是咱们近程连贯到服务器下面排查,发现是 Spark driver 占用了大部分 cpu。对于 cpu 占用问题,用 jstack 能很快定位到 jvm 的执行逻辑。剖析 jstack 后果发现,大部分占用 cpu 的线程都在执行一个叫做 transpose window 的优化规定,而且都和这个逻辑里的一段办法无关: private def compatiblePartitions(ps1 : Seq[Expression], ps2: Seq[Expression]): Boolean = {  ps1.length < ps2.length && ps2.take(ps1.length).permutations.exists(    ps1.zip(_).forall {      case (l, r) => l.semanticEquals(r)    })  }这段逻辑看上去并不简单,留神到这个办法里有一个 permutations 函数调用,这个函数会返回一个数组的所有排列。对于一个有 n 个不同元素的数组,他的排列数是 n!,也就是说这个算法工夫复杂度会到 O(n!),那么咱们遇到的问题很有可能和这个有关系了。然而咱们还是须要找到是什么 sql 语句触发了这个问题。 从监控上来看,driver 的 cpu 是呈阶梯状回升的,那这些回升的工夫点应该就是有问题工作提交的工夫点,再联合 call stack 外面的逻辑是在做 window 相干的优化,咱们重点去找这些工夫点蕴含 window function 相干的工作。很快咱们就定位到了一个 ETL,从监控上看,每运行一次这个 ETL,Spark driver 就会多占用一个 cpu,并且长时间不开释。 原始的 ETL 逻辑比较复杂,咱们把他简化之后发现只和两个带窗口函数的计算字段有关系,特点就是 partition by 应用的字段比拟多,为了 debug 不便,咱们用 spark-shell 复现了一下: val df = spark.range(10).selectExpr("id AS a1", "id AS a2", "id AS a3", "id AS a4", "id AS a5", "id AS a6", "id AS a7", "id AS a8", "id AS a9", "id AS a10", "id AS a11", "id AS a12", "id AS a13", "id AS a14", "id AS a15", "id AS a16") df.selectExpr(  "sum(`a16`) OVER(PARTITION BY `a1`,`a2`,`a3`,`a4`,`a5`,`a6`,`a7`,`a8`,`a9`,`a10`,`a11`,`a12`,`a13`,`a14`,`a15`) as p1",   "sum(`a16`) OVER(PARTITION BY `a14`,`a2`,`a3`,`a4`,`a5`,`a6`,`a7`,`a8`,`a9`,`a10`,`a11`,`a12`,`a13`,`a1`) as p2"  ).explain在 3.0 版本以上的 spark-shell 外面运行下面的代码就会发现 spark-shell 卡住了,而卡住的中央正是 compatiblePartitions 办法。 也就是说如果加了多个带有窗口函数的计算字段,而 partition by 的字段过多的话,很容易触发这个问题,比方下面这个例子,大家能够算算 14 个元素的数组全排列有多少种组合。那么这个问题咱们有没有方法优化呢。 ...

August 22, 2022 · 1 min · jiezi

关于spark:Scala-WorkCount-null-entry-in-command-string-null-ls-F

java.io.IOException: (null) entry in command string: null ls -F+一个文件门路:解决办法运行环境为idea,本地运行scala编写的WordCount实例时,呈现了java.io.IOException: (null) entry in command string: null ls -F+文件门路的谬误。 起因是想要一次性加载所有文件,然而在加载所有文件的时候,门路指向的写法不对。 我想要读取的是datas上面的所有文件: 本来的代码:val value = sc.textFile("{datas")批改为:val value = sc.textFile("{datas/*}") 运行胜利

August 12, 2022 · 1 min · jiezi

关于spark:某课SparkClickHouse实战企业级数据仓库进军大厂必备

download:Spark+ClickHouse实战企业级数据仓库,进军大厂必备验证框架次要分为两种,即分层验证与JavaBean验证分层验证模型传统的校验模式,即每一层都增加数据验证。然而其验证逻辑重复性大,会呈现冗余代码过多的状况 JavaBean验证JavaBean验证模式指向前端接收数据时,在JavaBean上做数据校验。其校验逻辑无需写在其余层中 Bean Validation Bean Validation 为 JavaBean 验证定义了相应的元数据模型和API。---维基百科 分类限度阐明空/非空查看@NULL限度只能为NULL@NotNull限度必须不为NULL@NotNull验证注解的元素值不为Null且不为空(字符串长度不为0,汇合大小不为0)@NotBlack验证注解的元素值不为空(不为Null,去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只利用于字符串且在比拟时会去除字符串的空格Boolean值查看@AssertFalse限度必须为False@AssertTrue限度必须为True长度查看@Size(max,min)限度字符长度必须在min到max之间@Leanth限度字符长度必须在min到max之间日期查看@Future限度日期为以后工夫之后@FutureOrPresent限度日期为以后工夫或之后@Past限度日期为以后工夫之前@PastOrPresent限度日期为以后工夫或之前数值查看@Max(Value)限度必须为一个不大于指定值的数字@Min(Value)限度必须为一个不小于指定值的数字@DecimalMin(value)限度必须为一个不小于指定值的数字@DecimalMax(value)限度必须为一个不小于指定值的数字@Digits(integer,fraction)限度必须为小数,且整数局部的位数不能超过Integer,小数局部的位数不能超过fraction@Negative限度必须为负整数@NegativeOrZero(value)限度必须为负整数或零@Positive(value)限度必须为正整数@PositiveOrZero(value)限度必须为正整数或零其余查看@Pattern(Value)限度必须合乎指定的正则表达式@Email限度必须为email格局@Validated用于Controller层向前端接管参数时,对参数合法性进行校验的开启 @PostMapping("/testMethod")@ApiOperation(value = "testMethod")public RespResult testMethod(@RequestBody @Validated TestParam testParam){ ... ...}复制代码@Validated只用于对性能的开启,代表本次开启参数校验真正的参数校验注解在要进行参数合法性校验的类中进行书写/** 测试类 *@author WeiYL@date 2022/7/27 16:15 */@Data@ApiModel(value = "测试解决类")public class TestParamDTO{ /** * 名称 */@ApiModelProperty(value = "隐患形容", example = "隐患形容编辑测试")@Length(max = 512, message = "长度非法,超过{max}字符!")String testName;/** * 形容 */@ApiModelProperty(value = "形容", example = "形容编辑测试")@NotBlank(message = "形容不能为空")@Length(max = 512, message = "长度非法,超过{max}字符!")String testDescribe;/** * 等级 */@ApiModelProperty(value = "等级", example = "1")@NotBlank(message = "等级不能为空")@Length(min = 1, max = 1, message = "等级字符长度不为{max}")String testGrade;} ...

August 5, 2022 · 1 min · jiezi

关于spark:SparkClickHouse实战企业级数据仓库进军大厂必备

download:Spark+ClickHouse实战企业级数据仓库,进军大厂必备CI/CD 次要针对在集成新代码时所引发的问题(俗称"集成地狱")。为什么会有集成地狱这个“雅称”呢?大家想想咱们一个我的项目部署的过程,拉取代码->构建->测试->打包->部署,如果咱们常常需要部署我的项目,特地是在微服务期间,服务特地多的情况下,不停的测试打包部署,那估计得有集体一整天顺便做这事了,而这事又是繁琐的重复无意义的。具体而言,CI/CD 可让继续自动化和继续监控贯穿于利用的整个生命周期(从集成和测试阶段,到托付和部署),这些关联的事务通常被统称为"CI/CD 管道",由开发和运维团队以敏捷形式协同反对。1.1 CI(Continuous Integration)CI/CD 中的"CI"始终指继续集成,它属于开发人员的自动化流程。胜利的 CI 意味着利用代码的新更改会定期构建、测试并合并到代码仓库中,该解决打算可能解决在一次开发中有太多利用分支,从而导致相互冲突的问题。1.2 CD(Continuous Delivery/Continuous Deployment)CI/CD 中的"CD"指的是继续托付和/或继续部署,这些相干概念有时会交叉使用。两者都事关管道后续阶段的自动化,但它们有时也会独自使用,用于说明自动化程度。继续托付(Continuous Delivery)通常是指开发人员对利用的更改会主动进行谬误测试并上传到代码仓库(如 GitHub、GitLab 等),而后由运维团队将其部署到实时生产环境中。这旨在解决开发和运维团队之间可见性及沟通较差的问题。因此,继续托付的目标就是确保尽可能减少部署新代码时所需的工作量。继续部署(Continuous Deployment)指的是主动将开发人员的更改从代码仓库公布到生产环境,以供客户使用。通过一套全自动化的流程,来解决手动测试、编译、打包等操作。继续部署以继续托付的劣势为根基,实现了管道后续阶段的自动化。 什么是 Jenkins后面说的 CI/CD 算是一种思维,思维要落地,就需要对应的工具。Jenkins 是一款开源的 CI/CD 软件,可能算是 CI/CD 软件指导者,它提供了超过 1000 个插件来反对构建、部署、自动化,基本上能够满足任何我的项目的需要。

August 4, 2022 · 1 min · jiezi

关于spark:SparkClickHouse实战企业级数据仓库进军大厂必备

点击下崽ZY:百度网盘原作者首先申明了他并没有贬斥Vue3的意思。他认为Vue3是十分十分棒的框架,解决了Vue2中很多潜在问题,技术层面改善了开发人员的开发体验,并显著进步了性能。原作者次要的问题,是从Vue3突破性的扭转以及周边生态圈未能及时跟上的角度,重点强调了迁徙降级老本+危险较大。 对于降级老本问题:尤大也抵赖了Vue3降级体验并没有设想中的那么晦涩,Vue4会吸取经验,做好安稳迭代。这一点本文会在上面具体阐明。 接下来,咱们针对原文中提到的观点逐个列举解读。 ps: 为了防止语言翻译差别问题,所有原作者和尤大的观点都是附上英语原文。 一、破坏性的api变更(Breaking changes) [Events API]的弃用让这个问题首当其冲。(straightforward like the depreciation of the Events API)。Vue实例再也不能作为事件总线做事件通信,$on,$off,$once的彻底移除意味着之前所有无关代码都必须从新颠覆重写,尽管有很好的插件工具让这件事变得没那么简单,然而依然会带来不小的迁徙老本。代码构建问题。 你会常常遇到用Vue2写法写进去的代码在构建(build) 失败或抛出正告。因为这些api写法在Vue3中曾经被废除。这问题在已存在的大型项目中的尤为突出(In an existing large-scale application built with Vue 2, you would probably use some of the deprecated or changed APIs)。下图展现了一部分Breaking changes,能够看到破坏性的api变更数的确很多: 二、颠覆式的设计模式(composition-api)颠覆式的composition-api缓缓向面向函数思维转变,导致很多原有习惯于options-api的开发者恶感Vue正在像react聚拢,没有保持住Vue特色。它提出了一种新的基于函数的 Vue 组件编写形式,引起了Vue社区大量的争议和决裂,甚至将社区分隔为两种观点营垒唇枪舌剑,最终导致了三、生态系统(The ecosystem) 框架的真正力量来自社区和它四周的生态系统。(The true power of a framework comes from the community and the ecosystem around it.) 生态系统和框架自身一样重要。因为没有责任机制,在有争议的决定和在弃用性能的时候,很多框架周边的生态系统的许多贡献者会被迫来到,并导致许多库被放弃或者提早更新。很多时候,咱们没有方法做版本兼容时,咱们往往只能把责任归咎于,开源库不足同理心和对大局的了解。

July 31, 2022 · 1 min · jiezi

关于spark:Spark-Standalone模式

SparkSpark的局部内容和之前Spark系列重合,然而有些细节之前没有深刻。 Master启动基于高可用的思考,Master会启动多个,然而只能有一个Master是提供服务的(ALIVE状态),其余Master都是STANDBY状态。 zookeeper集群的左右,一个是用来选举,另外一个是保留长久化Application、Driver、Executor的信息,便于复原。 Worker启动Worker在启动的时候,就会向Master进行注册,注册时须要上传workid,host,端口以及cup外围数,内存大小。 因为Master是高可用的,所以刚开始Worker并不知道ALIVE节点是哪个,于是他就会把注册申请发送给每一个Master节点。 Worker只有注册胜利,才会被Master调用,所以为了保障注册胜利,Worker会进行一直的尝试。 一共尝试的次数是16次,为了防止所有的Worker同一时间发送心跳,给Master造成压力,所以发送心跳的间隔时间是随机的。 后面6次的心跳间隔时间是5~15s之间,前面10次的心跳间隔时间是30~90s之间。 如果在这16次内注册胜利,那就会勾销尝试。如果16次都没胜利,那这个Worker也没必要启动了,间接退出Worker过程。 这里重试的和刚开始注册的时候,有些不同。有可能因为某些起因导致重试,然而这个时候Worker是有Master的ALIVE节点信息,那Worker注册的时候,就间接往ALIVE节点注册就好了,不必每个Master都发送注册申请。 Master接管注册时,会看看本人是不是ALIVE节点,如果是STANDBY节点,那间接跟Worker说我是STANDBY节点,Worker晓得他是STANDBY节点,就不做任何解决。 而后Master就会看这个Worker是否注册过了(依据worker注册提供的workid),如果注册过了,就跟Worker说,注册失败了。 Worker接管到注册失败的信息,就会看看我有木有注册胜利啊(注册胜利会有变量保留),如果注册胜利,就疏忽这条音讯,晓得本人是反复注册。 如果发现自己没注册胜利,Master也说没注册胜利,那就是没注册胜利,所以退出Worker过程。 如果既不是STANDBY节点,Worker也没注册过,那就保留Worker的相应的信息,进行长久化,而后告知Worker曾经注册胜利。 Worker接管到胜利后,就会把变量更改为注册胜利(下面判断有用到),而后记录Master的地址(前面申请间接发这个地址了),勾销注册的重试工作(曾经胜利了就不须要再尝试注册了)。 最初会发状态给Master,因为刚开始注册,Worker中并没有Driver和Executor,所以Master不会解决。 Master如何晓得Worker存活Worker注册胜利后,还有一个十分重要的事件,就是发送心跳,维持状态。发送心跳的时候,间接发送workerid就好。 Master接管申请后,先看看是否注册过,如果没有注册过,就会让Worker从新注册,就会反复下面的注册流程。如果注册过,就批改Worker最初的心跳工夫。 Master会有一个每隔60s的定时工作,对超过60s没有发送的Worker进行解决,会把这个Worker标记为DEAD状态,并移除其余相干内存(idToWorker用于映射workerid和Worker的关系,addressToWorker用于映射地址和Worker的关系)。 如果Worker曾经是DEAD状态了,那超过960s就把Worker信息也移除。 比方60s没发心跳,此时Master会移除相干内容,而后在960s内,Worker重启后进行注册,那就会把Worker中为DEAD状态的Worker删除,再从新加新的Worker信息。 Driver启动Driver在启动后须要向Master注册Application信息,和Worker注册Master一样,Driver也不晓得哪个是ALIVE节点,所以他也向所有的Master进行注册。 注册信息包含Application的名称,Application须要的最大内核数,每个Executor所须要的内存大小,每个Executor所需的内核数,执行Executor的命令等信息。 这里的注册也有重试次数,最大重试3次,每次距离20s,注册胜利后,就会勾销重试。 Master收到申请后,如果是STANDBY节点,那不做解决,也不回复任何信息(这个和Worker注册不一样,Wokrer那边回回复信息,然而Worker不解决)。 如果不是STANDBY节点,那就会把Application信息保留内存中,并做长久化。 接着就会给Driver发送曾经注册胜利的音讯,Driver接管到音讯,就会记录Master的信息,以及外部标识曾经注册胜利,不须要再重试。 Master如何晓得Driver存活Driver和Master之间并没有心跳,不像Worker会定时发送心跳,Master依据心跳移除过期的Worker,那Master怎么晓得Driver是否退出呢? 第一种形式是Driver被动告知Master,第二种形式是Driver不失常退出,Master一旦监听到Driver退出了。这两种形式都会勾销Application的注册。 Master接管到勾销注册Application的音讯后,就会移除缓存的Application及Application相干的Driver信息。 对于Driver,有可能还存在运行的Executor,就会发消息给Driver,让他杀死Executor,Driver收到音讯后就会进行Application。 对应Worker,Master会群发给所有的Worker,告知这个Application已实现,Worker收到音讯后,会清理Driver的临时文件。 最初把Application的信息长久化,并且告知其余Worker这个Application已实现。 Executor启动Master在资源调度的时候,会让Worker启动Executor。 Worker接管到音讯后,会判断是否是STANDBY节点的Master发送的音讯,如果不是则疏忽。 如果是,Worker就会创立一个线程,用来启动一个Executor的过程,启动Executor的过程后会回复Master说Executor曾经启动胜利。 Master晓得Executor启动胜利,也会告知Driver,你的Executor我曾经帮你启动了。因为Executor并没有完结,Driver并没有做其余解决。 Executor启动后,就会向Driver进行注册,Driver先判断是否曾经注册过或者在黑名单里,如果是,返回失败,如果不是,则保留这个Executor的信息,并告知Executor曾经注册胜利。 Driver在Executor注册时,还做了一件事,就是把注册信息发送给事件总线。Driver里还有有一个心跳接收器,用于治理Executor状态的。 这个心跳接收器会对总线的事件进行监听,当发现有Executor新增的时候,就会记录这个Executor的id和工夫。 Worker如何晓得Executor存活Worker创立线程用来启动Executor过程的时候,这个线程创立完并不会间接退出,而是始终期待获取Executor过程的退出状态。 获取后就会把状态发送给Worker,Worker再把状态转发给Master,并更改本身的内存、CPU信息。 Master发现Executor执行完了(不论失败还是胜利),就会更新内存信息,并且把状态转发给Driver。 Driver收到状态后,发现Executor执行完了,会发移除Executor的事件给事件总线。 心跳接收器会对总线的事件进行监听,当发现有Executor移除的时候,就会移除Executor。 Executor如何晓得Worker存活Executor有一个WorkerWatcher,当Worker过程退出、连贯断开、网络出错时,就会被WorkerWatcher监听到,进而终止Executor的过程。 Driver如何晓得Executor存活Executor收到Drvier注册胜利的音讯后,就开始创立Executor对象,这个对象实例化后,就会开始对Driver的心跳申请,因为可能会多个Executor启动,所以为了防止同一时间申请过多,这里的延时工夫会加一个随机值。 心跳接收器接管到心跳申请后,先看看这个Executor是否曾经注册了,如果没有,让Executor从新注册,如果注册过了,则更新工夫。 心跳接收器有一个定时工作,会扫描每个Executor最初上报的工夫,如果Executor曾经超过肯定工夫没有发心跳了,就会把这个Executor的信息从内存中移除,并且提交“杀死”Executor的工作。 这个工作最初会发送到ClientEndpoint,ClientEndpoint再转发给Master。

July 19, 2022 · 1 min · jiezi

关于spark:向量化执行引擎框架-Gluten-宣布正式开源并亮相-Spark-技术峰会

近日举办的 Databricks Data & AI Summit 2022 上,来自 Intel 的陈韦廷和来自 Kyligence 的张智超独特分享了 Intel 和 Kyligence 两家企业自 2021 年单干共建的全新开源我的项目「Gluten」。这也是 Gluten 首次在寰球平台上亮相,明天咱们将一起通过本文进一步理解 Gluten。 Gluten 我的项目旨在为 Apache Spark 注入 Native Vectorized Execution 的能力,极大优化 Spark 的执行效率和老本。目前,Gluten 社区的次要参与方有 Intel、Kyligence 等。 “ Kyligence 企业级产品源自 Apache Kylin,明天,两者在离线数据处理、即时查问剖析等方面,都深度集成了 Spark 的能力。通过 Gluten 这一开源我的项目,Kylin 和 Kyligence 企业级产品将无效晋升 OLAP 查问性能和执行效率,尤其是在云原生版本 Kyligence Cloud 中,将更大程度地升高整体领有老本(TCO),进步云端数据分析的老本效率,减速大型客户从传统数据分析架构转向云原生数据湖架构的过程。” ——Kyligence 联结创始人兼 CTO 李扬1. 为什么须要 Gluten近年来,随着 IO 技术的晋升,尤其是 SSD 和万兆网卡的遍及,大家基于 Apache Spark 的数据负载场景遇到越来越多的 CPU 计算瓶颈,而不是传统认知中的 IO 瓶颈。而家喻户晓,基于 JVM 进行 CPU 指令的优化比拟艰难,因为 JVM 提供的 CPU 指令级的优化(例如 SIMD)要远远少于其余 Native 语言(例如 C++)。 ...

July 18, 2022 · 2 min · jiezi

关于spark:即刻报名|前沿技术探索如何让-Spark-更强劲更灵活

July 14, 2022 · 0 min · jiezi

关于spark:SparkScala-Learning

Problem 1:Unable to make private java.nio.DirectByteBuffer(long,int) accessible: module java.base does not "opens java.nio" to unnamed moduleSolution:Apache Spark is NOT COMPATIBLE with Java 16.When downloading a JDK for Spark, Java 11 is the safest choice.I am using Java 16, so need to shift JDK to 11.Download JDK11 installer from Oracle. Install.File - Project Structure - Platform Settings - + - add JDK11File - Project Structure - Project - SDK - choose JDK11Rebuild the project. Run. ...

June 14, 2022 · 1 min · jiezi

关于spark:实时数据湖在字节跳动的实践

导读:明天分享的主题是实时数据湖在字节跳动的实际。将围绕上面四点开展: 对实时数据湖的解读在落地实时数据湖的过程中遇到的一些挑战和应答形式联合场景介绍实时数据湖在字节外部的一些实际案例数据湖倒退的一些布局 1. 对实时数据湖的解读数据湖的概念是比拟宽泛的,不同的人可能有着不同的解读。这个名词诞生以来,在不同的阶段被赋予了不同的含意。数据湖的概念最早是在Hadoop World大会上提出的。过后的提出者给数据湖赋予了一个十分形象的含意,他认为它能解决数据集市面临的一些重要问题。其中最次要的两个问题是:首先,数据集市只保留了局部属性,只能解决事后定义好的问题;另外,数据集市中反映细节的原始数据失落了,限度了通过数据解决问题。从解决问题的角度登程,心愿有一个适合的存储来保留这些明细的、未加工的数据。因而在这个阶段,人们对数据湖的解读更多的是聚焦在中心化的存储之上。不同的云厂商也把本人的对象产存储产品称为数据湖。比方AWS在那个阶段就强调数据湖的存储属性,对应的就是自家的对象存储S3。在Wiki的定义中也是强调数据湖是一个中心化存储,能够存海量的不同品种的数据。然而当对象存储满足了大家对存储海量数据的诉求之后,人们对数据湖的解读又产生了变动。第二阶段,对数据湖的解读更多的是从开源社区和背地的商业公司发动的。比方Databricks 作为一个云中立的产品,它将云厂商的这个对象存储称为 data lakes storage,而后把本人的重心聚焦在如何基于一个中心化的存储构建一个数据分析、数据迷信和机器学习的数据湖解决方案,并且把这个计划称之为lake。他们认为在这个中心化的存储之上构建事务层、索引层,元数据层,能够去解决数据湖上的可靠性、性能和平安的问题。与此同时,Uber最后也将Hudi对外称为一个事务型的数据湖,名字实际上也是由 Hadoop Updates and Incrementals缩写而来,最早也是被用于解决Uber外部离线数据的合规问题。当初他们更偏向的定义是一个流式数据湖平台,Iceberg也经常被人们纳入数据湖的探讨。只管Ryan Blue始终声称 Iceberg 是一个Open Table Format。这三者有一些共同点,一个是对 ACID的反对,引入了一个事务层,第二是对 streaming 和 batch的等同反对,第三就是聚焦在如何能更快的查问数据。国内也有人将 Hudi、Iceberg、Delta Lake称为数据湖的三剑客。讲完了业界的解读,来看一下字节跳动对数据湖的解读。咱们是联合字节的业务场景来解读的。通过实际总结,咱们发现数据湖须要具备六大能力:第一是高效的并发更新能力。因为它可能扭转咱们在 Hive 数仓中遇到的数据更新老本高的问题,反对对海量的离线数据做更新删除。第二是智能的查问减速。用户应用数据湖的时候,不心愿感知到数据湖的底层实现细节,数据湖的解决方案应该可能主动地优化数据分布,提供稳固的产品性能。第三是批流一体的存储。数据湖这个技术呈现以来,被数仓行业给予了厚望,他们认为数据湖能够最终去解决一份存储流批两种应用形式的问题,从而从根本上晋升开发效率和数据品质。第四是对立的元数据和权限。在一个企业级的数据湖当中,元数据和权限必定是不能少的。同时在湖仓共存的状况下,用户不心愿元数据和权限在湖仓两种状况下是割裂的。第五是极致的查问性能。用户对于数据湖的冀望就是可能在数据实时入湖的同时还能做到数据的秒级可视化。第六是 AI + BI。数据湖数据的对外输入,不只局限于BI,同时AI也是数据湖的一等公民,数据湖也被利用在了字节的整个举荐体系,尤其是特色工程当中。实时数据湖其实是数据湖之上,更加重视数据的实时属性或者说流属性的一个数据湖倒退方向。当然,正如业界对于数据湖的解读始终在演变,咱们对数据湖的解读也不会局限于以上场景和性能。 2. 落地实时数据湖过程中的挑战和应答形式接下来介绍数据湖落地的挑战和应答。字节外部的数据湖最后是基于开源的数据湖框架Hudi构建的,抉择Hudi,最简略的一个起因就是因为相比于Iceberg 和Delta Lake,Hudi原生反对可扩大的索引零碎,可能帮忙数据疾速定位到所在的地位,达到高效更新的成果。在尝试规模化落地的过程中,咱们次要遇到了四个挑战:数据难治理,并发更新弱,更新性能差,以及日志难入湖。接下来会一一介绍这些挑战背地呈现的起因以及咱们应答的策略。(1)数据难治理下图是一个典型的基于中心化存储构建数仓机器学习和数据迷信的架构。这里将加工过后的数据保留在数仓中,通过数仓的元数据进行组织。数据科学家和机器学习框架都会间接去这个中心化的存储中获取原始数据。因而在这个中心化存储之上的数据对用户来说是齐全扩散的,没有一个全局的视图。 为了解决这个数据难治理的问题,Databricks 提出了一个Lakehouse 的架构,就是在存储层之下来构建对立的元数据缓存和索引层,所有对数据湖之上数据的应用都会通过这个对立的一层。在这一点上和咱们的指标是很类似的,然而事实是比拟残暴的,咱们面临的是海量存量数据,这些存量数据不论是数据格式的迁徙,还是应用形式的迁徙,亦或是元数据的迁徙,都意味着微小的投入。因而在很长一段时间里,咱们都会面临数仓和数据湖共存这样一个阶段。在这一阶段,两者的连通性是用户最为关怀的。咱们在数据湖和数仓之上,构建了一层对立的元数据层,这层元数据层屏蔽了上层各个系统的元数据的异构性,由对立的元数据层去对接 BI 工具,对接计算引擎,以及数据开发、治理和权限管控的一系列数据工具。而这一层对外裸露的 API 是与 Hive 兼容的。只管 Hive 这个引擎曾经逐步被其余的更新的计算引擎代替了,比方Spark、Presto、Flink,然而它的源数据管理仍旧是业界的事实标准。另外一些云厂商即便抉择构建了本人的元数据服务,也都同时提供了和 HMS 兼容的元数据查问接口,各个计算引擎也都内置了Hive Catalog 这一层。解决了下层的拜访对立的问题,但仍旧没有解决数据湖和数仓元数据自身的异构问题。这个异构问题是如何导致的呢?为什么Hive Matestore 没有方法去满足元数据管理的这个诉求?这就波及到数据湖治理元数据的特殊性。以Hudi为例,作为一个典型的事务型数据湖,Hudi应用工夫线 Timeline 来追踪针对表的各种操作。比方commit compaction clean, Timeline 相似于数据湖里的事务管理器,记录对表的更改状况。而这些更改或事务记录了每次更新的操作是产生在哪些文件当中,哪些文件为新增,哪些文件生效,哪些数据新增,哪些数据更新。总结下来,数据湖是通过追踪文件来治理元数据。治理的力度更细了,天然也就防止了有效的读写放大,从而提供了高效的更新删除、增量生产、工夫旅行等一系列的能力。但这其实也就意味着另外一个问题,就是一个目录中能够蕴含多个版本的文件,这与 Hive 治理元数据的形式就产生了一致,因为 Hive Metastore 是通过目录的模式来治理元数据的,数据更新也是通过笼罩目录来保障事务。因为对元信息的治理力度不同,基于 Hive Metastore的元数据管理其实是没有方法实现数据湖刚刚提到的一系列能力的。针对这个问题,Hudi社区的解决方案是应用一个分布式存储来治理这个 Timeline 。Timeline 外面记录了每次操作的元数据,也记录了一些表的 schema 和分区的信息,通过同步到Hive Metastore来做元数据的展现。这个过程中咱们发现了三个问题。第一个问题就是分区的元数据是扩散在两个零碎当中的,不足 single source of true。第二个是分区的元数据的获取须要从 HDFS 拉取多个文件,没有方法给出相似于 HMS 这样的秒级拜访响应。服务在线的数据利用和开发工具时,这个提早是没有方法满足需要的。第三个是读表的时候须要拉取大量的目录和 Timeline 上记录的表操作对应的元数据进行比对,找出最新的这个版本蕴含的文件。元数据读取自身就很重,并且不足裁剪能力,这在近实时的场景下带来了比拟大的overhead。Hudi Metastore Server 交融了Hive Metastore和Hudi MetaData治理的劣势。首先,Hudi Metastore Server 提供了多租户的、中心化的元数据管理服务,将文件一级的元数据保留在适宜随机读写的存储中,让数据湖的元数据不再扩散在多个文件当中,满足了single source of true。其次,Hudi Metastore Server 针对元数据的查问,尤其是一些变更操作。比方Job position 提供了与 Hive Metastore齐全兼容的接口,用户在应用一张数据湖上的表的时候,享受到这些减少的高效更新、删除、增量生产等能力的同时,也能享受到一张 Hive 表所具备的性能,例如通过Spark、Flink、Presto查问,以及在一些数据开发工具上在线的去获取到元数据以及一些分区 TTL清理的能力。此外,Hudi Metastore Server还解决了一个关键性的问题,就是多任务并发更新弱的问题。(2)并发更新弱咱们最早是基于Hudi社区的0.7版本的内核进行研发的,过后Hudi的Timeline中的操作必须是齐全程序的,每一个新的事务都会去回滚之前未实现的事务,因而无奈反对并发写入。后续社区也实现了一个并发写入的计划,整体是基于分布式锁实现的,并且只反对了Spark COW表的并发写,并不适用于 Flink 或者实时的MOR表。然而多任务的并发写入是咱们外部实际当中一个十分通用的诉求。因而咱们在Hudi Metastore Server的Timeline之上,应用乐观锁去从新实现了这个并发的更新能力。同时咱们这个并发管制模块还能反对更灵便的行列级别并发写策略,为后续要介绍到的实时数据关联的场景的落地提供了一个可能。 ...

June 6, 2022 · 1 min · jiezi

关于spark:在字节跳动一个更好的企业级SparkSQL-Server这么做

SparkSQL是Spark生态系统中十分重要的组件。面向企业级服务时,SparkSQL存在易用性较差的问题,导致难满足日常的业务开发需要。本文将具体解读,如何通过构建SparkSQL服务器实现应用效率晋升和应用门槛升高。 前言Spark 组件因为其较好的容错与故障复原机制,在企业的长时作业中应用的十分宽泛,而SparkSQL又是应用Spark组件中最为罕用的一种形式。 相比间接应用编程式的形式操作Spark的RDD或者DataFrame的API,SparkSQL可间接输出SQL对数据进行ETL等工作的解决,极大晋升了易用度。然而相比Hive等引擎来说,因为SparkSQL不足一个相似Hive Server2的SQL服务器,导致SparkSQL在易用性上比不上Hive。 很多时候,SparkSQL只能将本身SQL作业打包成一个Jar,进行spark-submit命令提交,因此大大降低Spark的易用性。除此之外,还可应用周边工具,如Livy,但Livy更像一个Spark 服务器,而不是SparkSQL服务器,因而无奈反对相似BI工具或者JDBC这样的标准接口进行拜访。 尽管Spark 提供Spark Thrift Server,然而Spark Thrift Server的局限十分多,简直很难满足日常的业务开发需要,具体的剖析请查看:观点|SparkSQL在企业级数仓建设的劣势 规范的JDBC接口Java.sql包下定义了应用Java拜访存储介质的所有接口,然而并没有具体的实现,也就是说JavaEE外面仅仅定义了应用Java拜访存储介质的规范流程,具体的实现须要依附周边的第三方服务实现。 例如,拜访MySQL的mysql-connector-java启动包,即基于java.sql包下定义的接口,实现了如何去连贯MySQL的流程,在代码中只须要通过如下的代码形式: Class.forName("com.mysql.cj.jdbc.Driver");Connection connection= DriverManager.getConnection(DB_URL,USER,PASS);//操作connection.close();第一,初始化驱动、创立连贯,第二,基于连贯进行对数据的操作,例如增删改查。能够看到在Java定义的标准接口拜访中,先创立一个connection实现存储介质,而后实现connection后续操作。 性能问题导致单次申请实时创立connection的性能较差。因而咱们往往通过保护一个存有多个connection的连接池,将connection的创立与应用离开以晋升性能,因此也衍生出很多数据库连接池,例如C3P0,DBCP等。 Hive 的JDBC实现构建SparkSQL服务器最好的形式是用如上Java接口,且大数据生态下行业已有标杆例子,即Hive Server2。Hive Server2在遵循Java JDBC接口标准上,通过对数据操作的形式,实现了拜访Hive服务。除此之外,Hive Server2在实现上,与MySQL等关系型数据稍有不同。 首先,Hive Server2自身是提供了一系列RPC接口,具体的接口定义在org.apache.hive.service.rpc.thrift包下的TCLIService.Iface中,局部接口如下: public TOpenSessionResp OpenSession(TOpenSessionReq req) throws org.apache.thrift.TException;public TCloseSessionResp CloseSession(TCloseSessionReq req) throws org.apache.thrift.TException;public TGetInfoResp GetInfo(TGetInfoReq req) throws org.apache.thrift.TException;public TExecuteStatementResp ExecuteStatement(TExecuteStatementReq req) throws org.apache.thrift.TException;public TGetTypeInfoResp GetTypeInfo(TGetTypeInfoReq req) throws org.apache.thrift.TException;public TGetCatalogsResp GetCatalogs(TGetCatalogsReq req) throws org.apache.thrift.TException;public TGetSchemasResp GetSchemas(TGetSchemasReq req) throws org.apache.thrift.TException;public TGetTablesResp GetTables(TGetTablesReq req) throws org.apache.thrift.TException;public TGetTableTypesResp GetTableTypes(TGetTableTypesReq req) throws org.apache.thrift.TException;public TGetColumnsResp GetColumns(TGetColumnsReq req) throws org.apache.thrift.TException;也就是说,Hive Server2的每一个申请都是独立的,并且是通过参数的形式将操作和认证信息传递。Hive 提供了一个JDBC的驱动实现,通过如下的依赖便可引入: ...

May 11, 2022 · 2 min · jiezi

关于spark:Spark-SQL-字段血缘在-vivo-互联网的实践

一、背景字段血统是在表处理的过程中将字段的处理过程保留下来。为什么会须要字段血统呢? 有了字段间的血缘关系,便能够晓得数据的起源去处,以及字段之间的转换关系,这样对数据的品质,治理有很大的帮忙。 Spark SQL 绝对于 Hive 来说通常状况下效率会比拟高,对于运行工夫、资源的应用下面等都会有较大的收益。 平台打算将 Hive 工作迁徙到 Spark SQL 上,同时也须要实现字段血统的性能。 二、后期调研开发前咱们做了很多相干调研,从中得悉 Spark 是反对扩大的:容许用户对 Spark SQL 的 SQL 解析、逻辑打算的剖析和查看、逻辑打算的优化、物理打算的造成等进行扩大。 该计划可行,且对 Spark 的源码没有改变,代价也比拟小,确定应用该计划。 三、Spark SQL 扩大3.1 Spark 可扩大的内容SparkSessionExtensions是比拟重要的一个类,其中定义了注入规定的办法,当初反对以下内容: 【Analyzer Rules】逻辑打算剖析规定【Check Analysis Rules】逻辑打算查看规定【Optimizer Rules.】 逻辑打算优化规定【Planning Strategies】造成物理打算的策略【Customized Parser】自定义的sql解析器【(External) Catalog listeners catalog】监听器在以上六种能够用户自定义的中央,咱们抉择了【Check Analysis Rules】。因为该查看规定在办法调用的时候是不须要有返回值的,也就意味着不须要对以后遍历的逻辑打算树进行批改,这正是咱们须要的。 而【Analyzer Rules】、【Optimizer Rules】则须要对以后的逻辑打算进行批改,使得咱们难以迭代整个树,难以失去咱们想要的后果。 3.2 实现本人的扩大class ExtralSparkExtension extends (SparkSessionExtensions => Unit) { override def apply(spark: SparkSessionExtensions): Unit = { //字段血统 spark.injectCheckRule(FieldLineageCheckRuleV3) //sql解析器 spark.injectParser { case (_, parser) => new ExtraSparkParser(parser) } }}

April 25, 2022 · 1 min · jiezi

关于spark:Spark-SQL-字段血缘在-vivo-互联网的实践

作者:vivo互联网服务器团队-Hao Guangshi一、背景字段血统是在表处理的过程中将字段的处理过程保留下来。为什么会须要字段血统呢? 有了字段间的血缘关系,便能够晓得数据的起源去处,以及字段之间的转换关系,这样对数据的品质,治理有很大的帮忙。 Spark SQL 绝对于 Hive 来说通常状况下效率会比拟高,对于运行工夫、资源的应用下面等都会有较大的收益。 平台打算将 Hive 工作迁徙到 Spark SQL 上,同时也须要实现字段血统的性能。 二、后期调研开发前咱们做了很多相干调研,从中得悉 Spark 是反对扩大的:容许用户对 Spark SQL 的 SQL 解析、逻辑打算的剖析和查看、逻辑打算的优化、物理打算的造成等进行扩大。 该计划可行,且对 Spark 的源码没有改变,代价也比拟小,确定应用该计划。 三、Spark SQL 扩大3.1 Spark 可扩大的内容SparkSessionExtensions 是比拟重要的一个类,其中定义了注入规定的办法,当初反对以下内容: 【Analyzer Rules】逻辑打算剖析规定【Check Analysis Rules】逻辑打算查看规定【Optimizer Rules.】 逻辑打算优化规定【Planning Strategies】造成物理打算的策略【Customized Parser】自定义的sql解析器【(External) Catalog listeners catalog】监听器在以上六种能够用户自定义的中央,咱们抉择了【Check Analysis Rules】。因为该查看规定在办法调用的时候是不须要有返回值的,也就意味着不须要对以后遍历的逻辑打算树进行批改,这正是咱们须要的。 而【Analyzer Rules】、【Optimizer Rules】则须要对以后的逻辑打算进行批改,使得咱们难以迭代整个树,难以失去咱们想要的后果。 3.2 实现本人的扩大class ExtralSparkExtension extends (SparkSessionExtensions => Unit) { override def apply(spark: SparkSessionExtensions): Unit = { //字段血统 spark.injectCheckRule(FieldLineageCheckRuleV3) //sql解析器 spark.injectParser { case (_, parser) => new ExtraSparkParser(parser) } }}下面依照这种形式实现扩大,并在 apply 办法中把本人须要的规定注入到 SparkSessionExtensions 即可,除了以上四种能够注入的以外还有其余的规定。要让 ExtralSparkExtension 起到作用的话咱们须要在spark-default.conf 下配置 spark.sql.extensions=org.apache.spark.sql.hive.ExtralSparkExtension 在启动 Spark 工作的时候即可失效。 ...

April 25, 2022 · 3 min · jiezi

关于spark:Spark与Flink-架构之间对比区别

Flink和Spark比照 通过学习,咱们理解到,Spark和Flink都反对批处理和流解决,接下来让咱们对这两种风行的数据处理框架在各方面进行比照。首先,这两个数据处理框架有很多相同点。 •都基于内存计算; •都有对立的批处理和流解决APl,都反对相似SQL的编程接口; •都反对很多雷同的转换操作,编程都是用相似于Scala Collection APl的函数式编程模式; •都有欠缺的谬误复原机制; •都反对Exactly once的语义一致性。 当然,它们的不同点也是相当显著,咱们能够从4个不同的角度来看。 从流解决的角度来讲,Spark基于微批量解决,把流数据看成是一个个小的批处理数据块别离解决,所以提早性只能做到秒级。而Flink基于每个事件处理,每当有新的数据输出都会立即解决,是真正的流式计算,反对毫秒级计算。因为雷同的起因,Spark只反对基于工夫的窗口操作(解决工夫或者事件工夫),而Flink反对的窗口操作则非常灵活,不仅反对工夫窗口,还反对基于数据自身的窗口,开发者能够自在定义想要的窗口操作。 从SQL 性能的角度来讲,Spark和Flink别离提供SparkSQL和Table APl提供SQL交互反对。 两者相比拟,Spark对SQL反对更好,相应的优化、扩大和性能更好,而Flink在SQL反对方面还有很大晋升空间。 从迭代计算的角度来讲,Spark对机器学习的反对很好,因为能够在内存中缓存两头计算结果来减速机器学习算法的运行。然而大部分机器学习算法其实是一个有环的数据流,在Spark中,却是用无环图来示意。而Flink反对在运行工夫中的有环数据流,从而能够更无效的对机器学习算法进行运算。 从相应的生态系统角度来讲,Spark 的社区无疑更加沉闷。Spark能够说有着Apache旗下最多的开源贡献者,而且有很多不同的库来用在不同场景。而Flink因为较新,现阶段的开源社区不如Spark沉闷,各种库的性能也不如Spark全面。然而Flink还在一直倒退,各种性能也在逐步欠缺。 如何抉择Spark和Flink 对于以下场景,你能够抉择 Spark。 •数据量十分大而且逻辑简单的批数据处理,并且对计算效率有较高要求(比方用大数据分析来构建举荐零碎进行个性化举荐、广告定点投放等); •基于历史数据的交互式查问,要求响应较快; •基于实时数据流的数据处理,提早性要求在在数百毫秒到数秒之间。 Spark完满满足这些场景的需要,而且它能够一站式解决这些问题,无需用别的数据处理平台。因为Flink是为了晋升流解决而创立的平台,所以它实用于各种须要非常低提早(微秒到毫秒级)的实时数据处理场景,比方实时日志报表剖析。 而且Flink 用流解决去模仿批处理的思维,比Spark 用批处理去模仿流解决的思维扩展性更好。 关键词:大数据培训

April 7, 2022 · 1 min · jiezi

关于spark:Spark的jobstage和task的机制论述

Spark任务调度机制阐述 在生产环境下,Spark集群的部署形式个别为YARN-Cluster模式。 Driver线程次要是初始化SparkContext对象,筹备运行所需的上下文,而后一方面放弃与ApplicationMaster的RPC连贯,通过ApplicationMaster申请资源,另一方面依据用户业务逻辑开始调度工作,将工作下发到已有的闲暇Executor上。当ResourceManager向ApplicationMaster返回Container资源时,ApplicationMaster就尝试在对应的Container上启动Executor过程,Executor过程起来后,会向Driver反向注册,注册胜利后放弃与Driver的心跳,同时期待Driver散发工作,当散发的工作执行结束后,将工作状态上报给Driver。 Spark任务调度概述1.1 根底概念 当Driver起来后,Driver则会依据用户程序逻辑筹备工作,并依据Executor资源状况逐渐散发工作。在具体论述任务调度前,首先阐明下Spark里的几个概念。一个Spark应用程序包含Job、Stage以及Task三个概念: job:以 action 办法为界,一个 action 触发一个 job stage:它是 job 的子集,以 RDD 宽依赖为界,遇到宽依赖即划分 stage task:它是 stage 的子集,以分区数来掂量,分区数多少,task 就有多少 1.2 任务调度 spark 工作从发动到执行可用下图示意 1.3 Client—>ResourceManage (1). Client 端通过 spark-submit + 参数 发动工作,即向ResourceManage 提交 application,留神该 application 蕴含了一堆参数,如 Executor 数,Executor 内存,Driver 内存等; (2). ResourceManage 须要先判断当初资源是否能满足该 application,如果满足,则响应该 application,如果不满足,报错; (3). 如果资源满足,Client 端筹备 ApplicationMaster 的启动上下文,并交给 ResourceManage; (4). 并且循环监控 application 的状态; 1.4 ResourceManage—>ApplicationMaster (1). ResourceManage 找一个 worker 启动 ApplicationMaster; (2). ApplicationMaster 向 ResourceManage 申请 Container; ...

March 29, 2022 · 2 min · jiezi

关于spark:SparkGraphX编程指南

Spark系列面试题 Spark面试题(一)Spark面试题(二)Spark面试题(三)Spark面试题(四)Spark面试题(五)——数据歪斜调优Spark面试题(六)——Spark资源调优Spark面试题(七)——Spark程序开发调优Spark面试题(八)——Spark的Shuffle配置调优GraphX 是新的图形和图像并行计算的Spark API。从整顿上看,GraphX 通过引入 弹性分布式属性图(Resilient Distributed Property Graph)继承了Spark RDD:一个将无效信息放在顶点和边的有向多重图。为了反对图形计算,GraphX 公开了一组根本的运算(例如,subgraph,joinVertices和mapReduceTriplets),以及在一个优化后的 PregelAPI的变形。此外,GraphX 包含越来越多的图算法和 builder 结构器,以简化图形剖析工作。 图并行计算的背景从社交网络到语言建模,日益扩充的规模和图形数据的重要性已带动许多新的图像并行零碎(例如,Giraph和 GraphLab)。通过限度可示意计算的类型以及引入新的技术来划分和分布图,这些零碎比个别的数据并行零碎在执行简单图形算法方面有大幅度地进步。 然而,这些限度在取得重大性能晋升的同时,也使其难以表白一个典型的图表剖析流程中的许多重要阶段:结构图,批改它的构造或表白计算逾越多重图的计算。此外,如何对待数据取决于咱们的指标,雷同的原始数据,可能有许多不同的表(table)和图表视图(graph views)。 因而,可能在同一组物理数据的表和图表视图之间切换是很有必要的,并利用各视图的属性,以不便地和无效地表白计算。然而,现有的图形剖析管道必须由图并行和数据并行零碎组成,从而导致大量的数据挪动和反复以及简单的编程模型。 该 GraphX 我的项目的指标是建设一个零碎,建设一个对立的图和数据并行计算的 API。该GraphX API 使用户可能将数据既能够当作一个图,也能够当作汇合(即RDDS)而不必进行数据挪动或数据复制。通过引入在图并行零碎中的最新进展,GraphX可能优化图形操作的执行。 GraphX 替换 Spark Bagel 的 API在GraphX 的公布之前,Spark的图计算是通过Bagel实现的,后者是Pregel的一个具体实现。GraphX提供了更丰盛的图属性API,从而加强了Bagel。从而达到一个更加精简的Pregel形象,系统优化,性能晋升以及缩小内存开销。尽管咱们打算最终弃用Bagel,咱们将持续反对Bagel的API和Bagel编程指南。不过,咱们激励Bagel用户,摸索新的GraphXAPI,并就从Bagel降级中遇到的阻碍反馈给咱们。 入门首先,你要导入 Spark 和 GraphX 到你的我的项目,如下所示: import org.apache.spark._import org.apache.spark.graphx._// To make some of the examples work we will also need RDDimport org.apache.spark.rdd.RDD如果你不应用Spark shell,你还须要一个 SparkContext。要理解更多无关如何开始应用Spark参考 Spark疾速入门指南。 属性图该 属性图是一个用户定义的顶点和边的有向多重图。有向多重图是一个有向图,它可能有多个平行边共享雷同的源和目标顶点。多重图反对并行边的能力简化了有多重关系(例如,共事和敌人)的建模场景。每个顶点是 惟一 的 64位长的标识符(VertexID)作为主键。GraphX并没有对顶点增加任何程序的束缚。同样,每条边具备相应的源和目标顶点的标识符。 该属性表的参数由顶点(VD)和边缘(ED)的类型来决定。这些是别离与每个顶点和边相关联的对象的类型。 GraphX 优化顶点和边的类型的示意办法,当他们是一般的旧的数据类型(例如,整数,双精度等)通过将它们存储在专门的阵列减小了在内存占用量。 ...

March 27, 2022 · 12 min · jiezi

关于spark:Spark启动及提交流程内部核心原理剖析

Apache Spark 是专为大规模数据处理而设计的疾速通用的计算引擎,并且领有Hadoop MapReduce所具备的长处;但不同于MapReduce的是——Job两头输入后果能够保留在内存中,从而不再须要读写HDFS,因而Spark能更好地实用于须要迭代MapReduce的算法。接下来带大家摸索一下Spark启动及提交流程的外部外围原理。 Netty 在摸索Spark启动及提交流程的外部外围原理之前,咱们得先简略介绍一下Spark外部的通信框架----Netty Spark中通信框架的倒退: Spark晚期版本中采纳Akka作为外部通信部件。 Spark1.3中引入Netty通信框架,为了解决Shuffle的大数据传输问题应用 Spark1.6中Akka和Netty能够配置应用。Netty齐全实现了Akka在Spark中的性能。 Spark2系列中,Spark摈弃Akka,应用Netty。 尚硅谷大数据培训_业余的大数据培训机构_值得信赖的大数据教程大数据大数据教程大数据培训尚硅谷大数据拼课程、论口碑更给力尚硅谷IT培训立刻征询Netty通信架构解析 Netty通信架构如下: RpcEndpoint:RPC通信终端。Spark针对每个节点(Client/Master/Worker)都称之为一个RPC终端,且都实现RpcEndpoint接口,外部依据不同端点的需要,设计不同的音讯和不同的业务解决,如果须要发送(询问)则调用Dispatcher。在Spark中,所有的终端都存在生命周期: Constructor onStart receive* onStop RpcEnv:RPC上下文环境,每个RPC终端运行时依赖的上下文环境称为RpcEnv;在把以后Spark版本中应用的NettyRpcEnv(即每个节点都有环境上下文) Dispatcher:音讯调度(散发)器,针对于RPC终端须要发送近程音讯或者从近程RPC接管到的音讯,散发至对应的指令收件箱(发件箱)。如果指令接管方是本人则存入收件箱,如果指令接管方不是本人,则放入发件箱;一个环境一个 Inbox:指令音讯收件箱。一个本地RpcEndpoint对应一个收件箱,Dispatcher在每次向Inbox存入音讯时,都将对应EndpointData退出外部ReceiverQueue中,另外Dispatcher创立时会启动一个独自线程进行轮询ReceiverQueue,进行收件箱音讯生产; RpcEndpointRef:RpcEndpointRef是对近程RpcEndpoint的一个援用。当咱们须要向一个具体的RpcEndpoint发送音讯时,个别咱们须要获取到该RpcEndpoint的援用,而后通过该利用发送音讯。 OutBox:指令音讯发件箱。对于以后RpcEndpoint来说,一个指标RpcEndpoint对应一个发件箱,如果向多个指标RpcEndpoint发送信息,则有多个OutBox。当音讯放入Outbox后,紧接着通过TransportClient将音讯发送进来。音讯放入发件箱以及发送过程是在同一个线程中进行; RpcAddress:示意近程的RpcEndpointRef的地址,Host + Port。 TransportClient:Netty通信客户端,一个OutBox对应一个TransportClient,TransportClient一直轮询OutBox,依据OutBox音讯的receiver信息,申请对应的近程TransportServer;(相似socket) TransportServer:Netty通信服务端,一个RpcEndpoint对应一个TransportServer,承受近程音讯后调用Dispatcher散发音讯至对应收发件箱(通过本地指令); Netty通信流程总结 在一个rpcEnv里, RpcEndpoint通过持有RpcEndpointRef,向Dispatcher发送音讯,Dispatcher辨认到音讯是近程指令,会把音讯发送到OutBox。 TransportClient一直轮询OutBox的队列,一旦OutBox队列有音讯,就会将音讯发往对应RpcEndpoint的TransportServer。 接管的RpcEndpoint的TransportServer会把音讯发往Dispatcher,Dispatcher辨认到本地指令后,会把音讯给发往本身的InBox外面,这样就实现了通信。 Spark启动流程分析 在分析Spark启动流程中,咱们次要通过StandAlone模式下的Master / Work启动流程来看Spark是怎么通信的。 Master启动流程 咱们首先从启动命令start-all.sh登程(因为他会启动master和work),一步一步查看启动的调用流程: start-all.sh 会加载sparkhome作为变量,所以学习spark装置多种模式spark时最好不配 start-master.sh CLASS="org.apache.spark.deploy.master.Master" "${SPARK_HOME}/sbin"/spark-daemon.sh start $CLASS 1 \ --host $SPARK_MASTER_HOST --port $SPARK_MASTER_PORT --webui-port $SPARK_MASTER_WEBUI_PORT \ $ORIGINAL_ARGS run_command class "$@" --运行传过来的所有参数 ${SPARK_HOME}"/bin/spark-class "$command" "$@" java .. org.apache.spark.deploy.master.Master 最终启动这个类,启动java虚拟机 -- main -- startRpcEnvAndEndpoint // master和worker通信须要现有通信环境,先创立通信环境和endpoint ...

March 23, 2022 · 3 min · jiezi

关于spark:揭秘字节跳动云原生Spark-History-服务-UIService

本文是字节跳动数据平台数据引擎SparkSQL团队针对 Spark History Server (SHS) 的优化实际分享。文 | 字节跳动数据平台—数据引擎—SparkSQL团队 在字节跳动外部,咱们实现了一套全新的云原生 Spark History 服务—— UIService,相比开源的 SHS,UIService 存储占用和拜访提早均升高 90% 以上,目前 UIService 服务曾经在字节跳动外部宽泛应用,并且作为火山引擎湖仓一体剖析服务 LAS(LakeHouse Analytics Service)的默认服务。LAS 业务背景开源 Spark History Server 架构为了可能更好了解本次重构的背景和意义,首先对原生 Spark History Server 原理做个简略的介绍。开源 Spark History Server 流程图 Spark History 建设在 Spark 事件(Spark Event)体系之上。在 Spark 工作运行期间会产生大量蕴含运行信息的SparkListenerEvent,例如 ApplicationStart / StageCompleted / MetricsUpdate 等等,都有对应的 SparkListenerEvent 实现。所有的 event 会发送到ListenerBus中,被注册在ListenerBus中的所有listener监听。其中EventLoggingListener是专门用于生成 event log 的监听器。它会将 event 序列化为 Json 格局的 event log 文件,写到文件系统中(如 HDFS)。通常一个机房的工作的文件都存储在一个门路下。 在 History Server 侧,外围逻辑在 FsHistoryProvider中。FsHistoryProvider 会维持一个线程间歇扫描配置好的 event log 存储门路,遍历其中的 event log 文件,提取其中概要信息(次要是 appliaction_id, user, status, start_time, end_time, event_log_path),保护一个列表。当用户拜访 UI,会从列表中查找申请所需的工作,如果存在,就残缺读取对应的 event log 文件,进行解析。解析的过程就是一个回放过程(replay)。Event log 文件中的每一行是一个序列化的 event,将它们逐行反序列化,并应用 ReplayListener将其中信息反馈到 KVStore 中,还原工作的状态。 ...

March 14, 2022 · 2 min · jiezi

关于spark:Spark和Hadoop以及区别

Spark是什么?Spark,是一种通用的大数据计算框架,正如传统大数据技术Hadoop的MapReduce、Hive引擎,以及Storm流式实时计算引擎等。 Spark蕴含了大数据畛域常见的各种计算框架:比方Spark Core用于离线计算,Spark SQL用于交互式查问,Spark Streaming用于实时流式计算,Spark MLlib用于机器学习,Spark GraphX用于图计算。 Spark次要用于大数据的计算,而Hadoop当前次要用于大数据的存储(比方HDFS、Hive、HBase等),以及资源调度(Yarn)。 2.Spark整体架构 Spark的特点: 速度快:Spark基于内存进行计算(当然也有局部计算基于磁盘,比方shuffle)。 容易上手开发:Spark的基于RDD的计算模型,比Hadoop的基于Map-Reduce的计算模型要更加易于了解,更加易于上手开发,实现各种简单性能,比方二次排序、topn等简单操作时,更加便捷。 超强的通用性:Spark提供了Spark RDD、Spark SQL、Spark Streaming、Spark MLlib、Spark GraphX等技术组件,能够一站式地实现大数据畛域的离线批处理、交互式查问、流式计算、机器学习、图计算等常见的工作。 集成Hadoop:Spark并不是要成为一个大数据畛域的“独裁者”,一个人霸占大数据畛域所有的“地盘”,而是与Hadoop进行了高度的集成,两者能够完满的配合应用。Hadoop的HDFS、Hive、HBase负责存储,YARN负责资源调度;大数据培训Spark简单大数据计算。实际上,Hadoop+Spark的组合,是一种“double win”的组合。 极高的活跃度:Spark目前是Apache基金会的顶级我的项目,全世界有大量的优良工程师是Spark的committer。并且世界上很多顶级的IT公司都在大规模地应用Spark。 Hadoop是什么? Hadoop是我的项目的总称。次要是由HDFS和MapReduce组成。HDFS是Google File System(GFS)的开源实现。MapReduce是Google MapReduce的开源实现。 具体而言,Apache Hadoop软件库是一个容许应用简略编程模型跨计算机集群解决大型数据汇合的框架,其设计的初衷是将单个服务器扩大成上千个机器组成的一个集群为大数据提供计算服务,其中每个机器都提供本地计算和存储服务。 Hadoop的外围: 1.HDFS和MapReduce是Hadoop的两大外围。通过HDFS来实现对分布式贮存的底层反对,达到高速并行读写与大容量的贮存扩大。 2.通过MapReduce实现对分布式工作进行处理程序反对,保障高速分区解决数据。 MapReduce的计算模型分为Map和Reduce两个过程。在日常教训里,咱们统计数据须要分类,分类越细、参加统计的人数越多,计算的工夫就越短,这就是Map的形象比喻,在大数据计算中,成千盈百台机器同时读取指标文件的各个局部,而后对每个局部的统计量进行计算,Map就是负责这一工作的;而Reduce就是对分类计数之后的共计,是大数据计算的第二阶段。可见,数据的计算过程就是在HDFS根底上进行分类汇总。 HDFS把节点分成两类:NameNode和DataNode。NameNode是惟一的,程序与之通信,而后从DataNode上存取文件。这些操作是通明的,与一般的文件系统API没有区别。 MapReduce则是JobTracker节点为主,调配工作以及负责和用户程序通信。 Spark和Hadoop的区别和比拟: 1.原理比拟: Hadoop和Spark都是并行计算,两者都是用MR模型进行计算 Hadoop一个作业称为一个Job,Job外面分为Map Task和Reduce Task阶段,每个Task都在本人的过程中运行,当Task完结时,过程也会随之完结; Spark用户提交的工作称为application,一个application对应一个SparkContext,app中存在多个job,每触发一次action操作就会产生一个job。这些job能够并行或串行执行,每个job中有多个stage,stage是shuffle过程中DAGScheduler通过RDD之间的依赖关系划分job而来的,每个stage外面有多个task,组成taskset,由TaskScheduler散发到各个executor中执行;executor的生命周期是和app一样的,即便没有job运行也是存在的,所以task能够疾速启动读取内存进行计算。 2.数据的存储和解决: hadoop: Hadoop本质上更多是一个分布式系统基础架构: 它将微小的数据集分派到一个由一般计算机组成的集群中的多个节点进行存储,同时还会索引和跟踪这些数据,大幅度晋升大数据处理和剖析效率。Hadoop 能够独立实现数据的存储和解决工作,因为其除了提供HDFS分布式数据存储性能,还提供MapReduce数据处理性能。 spark: Spark 是一个专门用来对那些分布式存储的大数据进行解决的工具,没有提供文件管理系统,本身不会进行数据的存储。它必须和其余的分布式文件系统进行集成能力运作。能够抉择Hadoop的HDFS,也能够抉择其余平台。 3.处理速度: hadoop: Hadoop是磁盘级计算,计算时须要在磁盘中读取数据;其采纳的是MapReduce的逻辑,把数据进行切片计算用这种形式来解决大量的离线数据. spark: Spark,它会在内存中以靠近“实时”的工夫实现所有的数据分析。Spark的批处理速度比MapReduce快近10倍,内存中的数据分析速度则快近100倍。 4.恢复性: hadoop: Hadoop将每次解决后的数据写入磁盘中,对应对系统谬误具备天生劣势。 spark: Spark的数据对象存储在弹性分布式数据集(RDD:)中。“这些数据对象既可放在内存,也能够放在磁盘,所以RDD也提供残缺的劫难复原性能。 5.解决数据: hadoop: Hadoop适宜解决静态数据,对于迭代式流式数据的解决能力差; spark: Spark通过在内存中缓存解决的数据,进步了解决流式数据和迭代式数据的性能; 6.两头后果: hadoop: Hadoop中两头后果寄存在HDFS中,每次MR都须要刷写-调用, spark: ...

December 10, 2021 · 1 min · jiezi

关于spark:Spark常见面试题

Spark常见面试题 Spark on Yarn 两种形式的区别以及工作流程Spark 内存治理 官网优化这块查看Spark作业资源的设置状况 excutor 个数 memory core driverShuffle 机制DataFrame/DataSet 和 RDD的区别以及编程数据歪斜RDD的五大个性Spark作业的执行流程:Count后续干了什么事件Spark中的饮食转换的作用,联合ScalaSpark和MR的区别Spark集群规模Spark OOM如何解决ThriftServer如何实现HAKafka整合Spark的时候OFFSET的治理Spark Storm Flink 的区别Spark应用中遇到过哪些问题,怎么解决,亮点在哪里正当的算子抉择Catalyst的流程

November 8, 2021 · 1 min · jiezi

关于spark:SparkSQL数据抽象与执行过程分享

SparkSQL数据抽象引入DataFrame就易用性而言,比照传统的MapReduce API,Spark的RDD API有了数量级的飞跃并不为过。然而,对于没有MapReduce和函数式编程教训的老手来说,RDD API依然存在着肯定的门槛。另一方面,数据科学家们所相熟的R、Pandas等传统数据框架尽管提供了直观的API,却局限于单机解决,无奈大数据培训胜任大数据场景。为了解决这一矛盾,Spark SQL 1.3.0在原有SchemaRDD的根底上提供了与R和Pandas格调相似的DataFrame API。新的DataFrame AP不仅能够大幅度降低一般开发者的学习门槛,同时还反对Scala、Java与Python三种语言。更重要的是,因为脱胎自SchemaRDD,DataFrame人造实用于分布式大数据场景。留神:DataFrame它不是Spark SQL提出来的,而是晚期在R、Pandas语言就曾经有了的。DataFrame是什么在Spark中,DataFrame是一种以RDD为根底的分布式数据集,相似于传统数据库中的二维表格。DataFrame与RDD的次要区别在于,前者带有schema元信息,即DataFrame所示意的二维表数据集的每一列都带有名称和类型。使得Spark SQL得以洞察更多的构造信息,从而对藏于DataFrame背地的数据源以及作用于DataFrame之上的变换进行针对性的优化,最终达到大幅晋升运行时效率。反观RDD,因为无从得悉所存数据元素的具体内部结构,Spark Core只能在stage层面进行简略、通用的流水线优化。上图中左侧的RDD[Person]尽管以Person为类型参数,但Spark框架自身不理解Person类的内部结构。而两头的DataFrame却提供了具体的构造信息,使得Spark SQL能够分明地晓得该数据集中蕴含哪些列,每列的名称和类型各是什么。理解了这些信息之后,Spark SQL的查问优化器就能够进行针对性的优化。后者因为在编译期有详尽的类型信息,编译期就能够编译出更加有针对性、更加优化的可执行代码。官网定义:• Dataset:A DataSet is a distributed collection of data. (分布式的数据集)• DataFrame:A DataFrame is a DataSet organized into named columns.(以列(列名,列类型,列值)的模式形成的分布式的数据集,依照列赋予不同的名称) DataFrame有如下个性:1)分布式的数据集,并且以列的形式组合的,相当于具备schema的RDD;2)相当于关系型数据库中的表,然而底层有优化;3)提供了一些形象的操作,如select、filter、aggregation、plot;4)它是因为R语言或者Pandas语言解决小数据集的教训利用到解决分布式大数据集上;5)在1.3版本之前,叫SchemaRDD;Schema 信息查看DataFrame中Schema是什么,执行如下命令:df.schemaSchema信息封装在StructType中,蕴含很多StructField对象,源码。StructType 定义,是一个样例类,属性为StructField的数组StructField 定义,同样是一个样例类,有四个属性,其中字段名称和类型为必填自定义Schema构造,官网提供的示例代码:RowDataFrame中每条数据封装在Row中,Row示意每行数据。如何构建Row对象:要么是传递value,要么传递Seq形式一:下标获取,从0开始,相似数组下标获取如何获取Row中每个字段的值呢?形式二:指定下标,晓得类型形式三:通过As转换类型Dataset引入Spark在Spark 1.3版本中引入了Dataframe,DataFrame是组织到命名列中的分布式数据汇合,然而有如下几点限度:编译时类型不平安:Dataframe API不反对编译时安全性,这限度了在构造不晓得时操纵数据。以下示例在编译期间无效。然而,执行此代码时将呈现运行时异样。无奈对域对象(失落域对象)进行操作:将域对象转换为DataFrame后,无奈从中从新生成它;上面的示例中,一旦咱们从personRDD创立personDF,将不会复原Person类的原始RDD(RDD [Person])。基于上述的两点,从Spark 1.6开始呈现Dataset,至Spark 2.0中将DataFrame与Dataset合并,其中DataFrame为Dataset非凡类型,类型为Row。针对RDD、DataFrame与Dataset三者编程比拟来说,Dataset API无论语法错误和剖析谬误在编译时都能发现,然而RDD和DataFrame有的须要在运行时能力发现。此外RDD与Dataset相比较而言,因为Dataset数据应用非凡编码,所以在存储数据时更加节俭内存。总结:Dataset是在Spark1.6中增加的新的接口,是DataFrame API的一个扩大,是Spark最新的数据抽象,联合了RDD和DataFrame的长处。与RDD相比:保留了更多的形容信息,概念上等同于关系型数据库中的二维表;与DataFrame相比:保留了类型信息,是强类型的,提供了编译时类型查看,调用Dataset的办法先会生成逻辑打算,而后被Spark的优化器进行优化,最终生成物理打算,而后提交到集群中运行;Dataset 是什么Dataset是一个强类型的特定畛域的对象,这种对象能够函数式或者关系操作并行地转换。从Spark 2.0开始,DataFrame与Dataset合并,每个Dataset也有一个被称为一个DataFrame的类型化视图,这种DataFrame是Row类型的Dataset,即Dataset[Row]。Dataset API是DataFrames的扩大,它提供了一种类型平安的,面向对象的编程接口。它是一个强类型,不可变的对象汇合,映射到关系模式。在数据集的外围 API是一个称为编码器的新概念,它负责在JVM对象和表格示意之间进行转换。表格示意应用Spark外部Tungsten二进制格局存储,容许对序列化数据进行操作并进步内存利用率。Spark 1.6反对主动生成各种类型的编码器,包含根本类型(例如String,Integer,Long),Scala案例类和Java Bean。针对Dataset数据结构来说,能够简略的从如下四个要点记忆与了解:Spark 框架从最后的数据结构RDD、到SparkSQL中针对结构化数据封装的数据结构DataFrame,最终应用Dataset数据集进行封装,倒退流程如下。所以在理论我的项目中倡议应用Dataset进行数据封装,数据分析性能和数据存储更加好。SparkSQL底层如何执行RDD 的运行流程大抵运行步骤:• 先将 RDD 解析为由 Stage 组成的 DAG, 后将 Stage 转为 Task 间接运行 问题:• 工作会依照代码所示运行, 依赖开发者的优化, 开发者的会在很大水平上影响运行效率 解决办法:• 创立一个组件, 帮忙开发者批改和优化代码, 但这在 RDD 上是无奈实现的 ...

October 29, 2021 · 2 min · jiezi

关于spark:Spark面试题一

1、spark的有几种部署模式,每种模式特点?(☆☆☆☆☆)1)本地模式 Spark不肯定非要跑在hadoop集群,能够在本地,起多个线程的形式来指定。将Spark利用以多线程的形式间接运行在本地,个别都是为了不便调试,本地模式分三类 local:只启动一个executor local[k]:启动k个executor local[*]:启动跟cpu数目雷同的 executor 2)standalone模式 分布式部署集群,自带残缺的服务,资源管理和工作监控是Spark本人监控,这个模式也是其余模式的根底。 3)Spark on yarn模式 分布式部署集群,资源和工作监控交给yarn治理,然而目前仅反对粗粒度资源分配形式,蕴含cluster和client运行模式,cluster适宜生产,driver运行在集群子节点,具备容错性能,client适宜调试,dirver运行在客户端。 4)Spark On Mesos模式。 官网举荐这种模式(当然,起因之一是血缘关系)。正是因为Spark开发之初就思考到反对Mesos,因而,目前而言,Spark运行在Mesos上会比运行在YARN上更加灵便,更加天然。用户可抉择两种调度模式之一运行本人的应用程序: (1)粗粒度模式(Coarse-grained Mode):每个应用程序的运行环境由一个Dirver和若干个Executor组成,其中,每个Executor占用若干资源,外部可运行多个Task(对应多少个“slot”)。应用程序的各个工作正式运行之前,须要将运行环境中的资源全副申请好,且运行过程中要始终占用这些资源,即便不必,最初程序运行完结后,回收这些资源。 (2)细粒度模式(Fine-grained Mode):鉴于粗粒度模式会造成大量资源节约,Spark On Mesos还提供了另外一种调度模式:细粒度模式,这种模式相似于当初的云计算,思维是按需分配。 2、Spark为什么比mapreduce快?(☆☆☆☆☆) 1)基于内存计算,缩小低效的磁盘交互; 2)高效的调度算法,基于DAG; 3)容错机制Linage,精髓局部就是DAG和Lingae 3、简略说一下hadoop和spark的shuffle雷同和差别?(☆☆☆☆☆) 1)从 high-level 的角度来看,两者并没有大的差异。 都是将 mapper(Spark 里是 ShuffleMapTask)的输入进行 partition,不同的 partition 送到不同的 reducer(Spark 里 reducer 可能是下一个 stage 里的 ShuffleMapTask,也可能是 ResultTask)。Reducer 以内存作缓冲区,边 shuffle 边 aggregate 数据,等到数据 aggregate 好当前进行 reduce() (Spark 里可能是后续的一系列操作)。 2)从 low-level 的角度来看,两者差异不小。 Hadoop MapReduce 是 sort-based,进入 combine() 和 reduce() 的 records 必须先 sort。这样的益处在于 combine/reduce() 能够解决大规模的数据,因为其输出数据能够通过外排失去(mapper 对每段数据先做排序,reducer 的 shuffle 对排好序的每段数据做归并)。目前的 Spark 默认抉择的是 hash-based,通常应用 HashMap 来对 shuffle 来的数据进行 aggregate,不会对数据进行提前排序。如果用户须要通过排序的数据,那么须要本人调用相似 sortByKey() 的操作;如果你是Spark 1.1的用户,能够将spark.shuffle.manager设置为sort,则会对数据进行排序。在Spark 1.2中,sort将作为默认的Shuffle实现。 3)从实现角度来看,两者也有不少差异。 Hadoop MapReduce 将解决流程划分出显著的几个阶段:map(), spill, merge, shuffle, sort, reduce() 等。每个阶段各司其职,能够依照过程式的编程思维来逐个实现每个阶段的性能。在 Spark 中,没有这样性能明确的阶段,只有不同的 stage 和一系列的 transformation(),所以 spill, merge, aggregate 等操作须要蕴含在 transformation() 中。 如果咱们将 map 端划分数据、长久化数据的过程称为 shuffle write,而将 reducer 读入数据、aggregate 数据的过程称为 shuffle read。那么在 Spark 中,问题就变为怎么在 job 的逻辑或者物理执行图中退出 shuffle write 和 shuffle read的解决逻辑?以及两个解决逻辑应该怎么高效实现? Shuffle write因为不要求数据有序,shuffle write 的工作很简略:将数据 partition 好,并长久化。之所以要长久化,一方面是要缩小内存存储空间压力,另一方面也是为了 fault-tolerance。 ...

October 26, 2021 · 2 min · jiezi

关于spark:spark性能优化一

本文内容阐明初始化配置给rdd和dataframe带来的影响repartition的相干阐明cache&persist的相干阐明性能优化的阐明倡议以及实例配置阐明spark:2.4.0服务器:5台(8核32G)初始化配置项%%init_sparklauncher.master = "yarn"launcher.conf.spark.app.name = "BDP-xw"launcher.conf.spark.driver.cores = 1launcher.conf.spark.driver.memory = '1g'launcher.conf.spark.executor.instances = 3launcher.conf.spark.executor.memory = '1g'launcher.conf.spark.executor.cores = 2launcher.conf.spark.default.parallelism = 5launcher.conf.spark.dynamicAllocation.enabled = Falseimport org.apache.spark.sql.SparkSessionvar NumExecutors = spark.conf.getOption("spark.num_executors").reprvar ExecutorMemory = spark.conf.getOption("spark.executor.memory").reprvar AppName = spark.conf.getOption("spark.app.name").reprvar max_buffer = spark.conf.getOption("spark.kryoserializer.buffer.max").reprimport org.apache.spark.rdd.RDDimport org.apache.spark.sql.{DataFrame, Row}import org.apache.spark.sql.SparkSessionimport org.apache.spark.sql.functions.monotonically_increasing_idimport org.apache.log4j.{Level, Logger}import org.apache.spark.sql.types.{StructType, StructField, StringType, IntegerType}import org.apache.spark.sql.functions.{udf, _}import org.apache.spark.{SparkConf, SparkContext}object LoadingData_from_files{ def main(args: Tuple2[String, Array[String]]=Tuple2(hdfs_file, etl_date:Array[String])): Unit = { for( a <- etl_date){ val hdfs_file_ = s"$hdfs_file" + a val rdd_20210113 = spark.sparkContext.textFile(hdfs_file_).cache() val num1 = rdd_20210113.count println(s"加载数据啦:$a RDD的数据量是$num1") } val rdd_20210113_test = spark.sparkContext.textFile(hdfs_file + "20210328").cache() var num1 = rdd_20210113_test.count() println(s"加载数据啦:20210113 RDD的数据量是$num1") rdd_20210113_test.unpersist() // 解除长久化 val df_20210420 = spark.sparkContext.textFile(hdfs_file + "20210113").toDF.cache() num1 = df_20210420.count() // 指定memory之后,cache的数量太多之前cache的后果会被干掉 println(s"加载数据啦:20210420 DataFrame的数据量是$num1") }}// 配置参数multiple_duplicatedval hdfs_file = "hdfs://path/etl_date="val etl_date = Array("20210113","20210112","20210112","20210112","20210112","20210112", "20210113")LoadingData_from_files.main(hdfs_file, etl_date)失去后果如下: ...

October 17, 2021 · 3 min · jiezi

关于spark:个推技术实践-Spark性能调优看这篇性能提升60↑-成本降低50↓

前言 Spark是目前支流的大数据计算引擎,性能涵盖了大数据畛域的离线批处理、SQL类解决、流式/实时计算、机器学习、图计算等各种不同类型的计算操作,利用范畴与前景十分宽泛。作为一种内存计算框架,Spark运算速度快,并可能满足UDF、大小表Join、多路输入等多样化的数据计算和解决需要。 作为国内业余的数据智能服务商,个推从晚期的1.3版本便引入Spark,并基于Spark建设数仓,进行大规模数据的离线和实时计算。因为Spark 在2.x版本之前的优化重心在计算引擎方面,而在元数据管理方面并未做重大改良和降级。因而个推依然应用Hive进行元数据管理,采纳Hive元数据管理+ Spark计算引擎的大数据架构,以撑持本身大数据业务倒退。个推还将Spark广泛应用到报表剖析、机器学习等场景中,为行业客户和政府部门提供实时人口洞察、群体画像构建等服务。 ▲个推在理论业务场景中,别离应用SparkSQL 和 HiveSQL对一份3T数据进行了计算,上图展现了跑数速度。数据显示:在锁死队列(120G内存,<50core)前提下, SparkSQL2.3 的计算速度是Hive1.2 的5-10倍。 对企业来讲,效率和老本始终是其进行海量数据处理和计算时所必须关注的问题。如何充分发挥Spark的劣势,在进行大数据作业时真正实现降本增效呢?个推将多年积攒的Spark性能调优妙招进行了总结,与大家分享。 Spark性能调优-根底篇家喻户晓,正确的参数配置对晋升Spark的应用效率具备极大助力。因而,针对 不理解底层原理的Spark使用者,咱们提供了能够间接抄作业的参数配置模板,帮忙相干数据开发、剖析人员更高效地应用Spark进行离线批处理和SQL报表剖析等作业。 举荐参数配置模板如下: Spark-submit 提交形式脚本 /xxx/spark23/xxx/spark-submit --master yarn-cluster \--name ${mainClassName} \--conf spark.serializer=org.apache.spark.serializer.KryoSerializer \--conf spark.yarn.maxAppAttempts=2 \--conf spark.executor.extraJavaOptions=-XX:+UseConcMarkSweepGC \--driver-memory 2g \--conf spark.sql.shuffle.partitions=1000 \--conf hive.metastore.schema.verification=false \--conf spark.sql.catalogImplementation=hive \--conf spark.sql.warehouse.dir=${warehouse} \--conf spark.sql.hive.manageFilesourcePartitions=false \--conf hive.metastore.try.direct.sql=true \--conf spark.executor.memoryOverhead=512M \--conf spark.yarn.executor.memoryOverhead=512 \--executor-cores 2 \--executor-memory 4g \--num-executors 50 \--class 启动类 \${jarPath} \-M ${mainClassName} spark-sql 提交形式脚本 option=/xxx/spark23/xxx/spark-sqlexport SPARK_MAJOR_VERSION=2${option} --master yarn-client \--driver-memory 1G \--executor-memory 4G \--executor-cores 2 \--num-executors 50 \--conf "spark.driver.extraJavaOptions=-Dlog4j.configuration=file:log4j.properties" \--conf spark.sql.hive.caseSensitiveInferenceMode=NEVER_INFER \--conf spark.sql.auto.repartition=true \--conf spark.sql.autoBroadcastJoinThreshold=104857600 \--conf "spark.sql.hive.metastore.try.direct.sql=true" \--conf spark.dynamicAllocation.enabled=true \--conf spark.dynamicAllocation.minExecutors=1 \--conf spark.dynamicAllocation.maxExecutors=200 \--conf spark.dynamicAllocation.executorIdleTimeout=10m \--conf spark.port.maxRetries=300 \--conf spark.executor.memoryOverhead=512M \--conf spark.yarn.executor.memoryOverhead=512 \--conf spark.sql.shuffle.partitions=10000 \--conf spark.sql.adaptive.enabled=true \--conf spark.sql.adaptive.shuffle.targetPostShuffleInputSize=134217728 \--conf spark.sql.parquet.compression.codec=gzip \--conf spark.sql.orc.compression.codec=zlib \--conf spark.ui.showConsoleProgress=true-f pro.sqlpro.sql 为业务逻辑脚本Spark性能调优-进阶篇针对有志愿理解Spark底层原理的读者,本文梳理了standalone、Yarn-client、Yarn-cluster等3种常见工作提交形式的交互图,以帮忙相干使用者更直观地了解Spark的核心技术原理、为浏览接下来的进阶篇内容打好根底。 ...

September 22, 2021 · 2 min · jiezi

关于spark:spark相关介绍提取hive表一

本文环境阐明centos服务器jupyter的scala核spylon-kernelspark-2.4.0scala-2.11.12hadoop-2.6.0本文次要内容spark读取hive表的数据,次要包含间接sql读取hive表;通过hdfs文件读取hive表,以及hive分区表的读取。通过jupyter上的cell来初始化sparksession。文末还有通过spark提取hdfs文件的残缺示例jupyter配置文件咱们能够在jupyter的cell框外面,对spark的session做出对应的初始化,具体能够见上面的示例。%%init_sparklauncher.master = "local[*]"launcher.conf.spark.app.name = "BDP-xw"launcher.conf.spark.driver.cores = 2launcher.conf.spark.num_executors = 3launcher.conf.spark.executor.cores = 4launcher.conf.spark.driver.memory = '4g'launcher.conf.spark.executor.memory = '4g'// launcher.conf.spark.serializer = "org.apache.spark.serializer.KryoSerializer"// launcher.conf.spark.kryoserializer.buffer.max = '4g'import org.apache.spark.sql.SparkSessionvar NumExecutors = spark.conf.getOption("spark.num_executors").reprvar ExecutorMemory = spark.conf.getOption("spark.executor.memory").reprvar AppName = spark.conf.getOption("spark.app.name").reprvar max_buffer = spark.conf.getOption("spark.kryoserializer.buffer.max").reprprintln(f"Config as follows: \nNumExecutors: $NumExecutors, \nAppName: $AppName,\nmax_buffer:$max_buffer") 间接查看咱们初始化的sparksession对应的环境各变量 从hive中取数间接sparksql走起import org.apache.spark.sql.SparkSessionval sql_1 = """select * from tbs limit 4 """var df = sql(sql_1)df.show(5, false) 通过hdfs取数具体示例能够参考文末的从hdfs取数残缺脚本示例object LoadingData_from_hdfs_base extends mylog{// with Logging ... def main(args: Array[String]=Array("tb1", "3", "\001", "cols", "")): Unit = { if (args.length < 2) { println("Usage: LoadingData_from_hdfs <tb_name, parts. sep_line, cols, paths>") System.err.println("Usage: LoadingData_from_hdfs <tb_name, parts, sep_line, cols, paths>") System.exit(1) } log.warn("开始啦调度") val tb_name = args(0) val parts = args(1) val sep_line = args(2) val select_col = args(3) val save_paths = args(4) val select_cols = select_col.split("#").toSeq log.warn(s"Loading cols are : \n $select_cols") val gb_sql = s"DESCRIBE FORMATTED ${tb_name}" val gb_desc = sql(gb_sql) val hdfs_address = gb_desc.filter($"col_name".contains("Location")).take(1)(0).getString(1) val hdfs_address_cha = s"$hdfs_address/*/" val Cs = new DataProcess_base(spark) val tb_desc = Cs.get_table_desc(tb_name) val raw_data = Cs.get_hdfs_data(hdfs_address) val len1 = raw_data.map(item => item.split(sep_line)).first.length val names = tb_desc.filter(!$"col_name".contains("#")).dropDuplicates(Seq("col_name")).sort("id").select("col_name").take(len1).map(_(0)).toSeq.map(_.toString) val schema1 = StructType(names.map(fieldName => StructField(fieldName, StringType))) val rawRDD = raw_data.map(_.split(sep_line).map(_.toString)).map(p => Row(p: _*)).filter(_.length == len1) val df_data = spark.createDataFrame(rawRDD, schema1)//.filter("custommsgtype = '1'") val df_desc = select_cols.toDF.join(tb_desc, $"value"===$"col_name", "left") val df_gb_result = df_data.select(select_cols.map(df_data.col(_)): _*)//.limit(100) df_gb_result.show(5, false) ...// spark.stop() }}val cols = "area_name#city_name#province_name"val tb_name = "tb1"val sep_line = "\u0001"// 执行脚本LoadingData_from_hdfs_base.main(Array(tb_name, "4", sep_line, cols, "")) ...

September 19, 2021 · 6 min · jiezi

关于spark:SparkESClickHouse-构建DMP用户画像一起学习

download:Spark+ES+ClickHouse 构建DMP用户画像package wzh.Http; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.URL; import java.net.URLConnection; import java.util.List; import java.util.Map; public class HttpRequest { /** * 向指定URL发送GET办法的申请 * * @param url * 发送申请的URL * @param param * 申请参数,申请参数应该是 name1=value1&name2=value2 的模式。 * @return URL 所代表近程资源的响应后果 */ public static String sendGet(String url, String param) { String result = ""; BufferedReader in = null; try { String urlNameString = url + "?" + param; URL realUrl = new URL(urlNameString); // 关上和URL之间的连贯 URLConnection connection = realUrl.openConnection(); // 设置通用的申请属性 connection.setRequestProperty("accept", "*/*"); connection.setRequestProperty("connection", "Keep-Alive"); connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); // 建设理论的连贯 connection.connect(); // 获取所有响应头字段 Map<String, List<String>> map = connection.getHeaderFields(); // 遍历所有的响应头字段 for (String key : map.keySet()) { System.out.println(key + "--->" + map.get(key)); } // 定义 BufferedReader输出流来读取URL的响应 in = new BufferedReader(new InputStreamReader( connection.getInputStream())); String line; while ((line = in.readLine()) != null) { result += line; } } catch (Exception e) { System.out.println("发送GET申请出现异常!" + e); e.printStackTrace(); } // 应用finally块来敞开输出流 finally { try { if (in != null) { in.close(); } } catch (Exception e2) { e2.printStackTrace(); } } return result; } /** * 向指定 URL 发送POST办法的申请 * * @param url * 发送申请的 URL * @param param * 申请参数,申请参数应该是 name1=value1&name2=value2 的模式。 * @return 所代表近程资源的响应后果 */ public static String sendPost(String url, String param) { PrintWriter out = null; BufferedReader in = null; String result = ""; try { URL realUrl = new URL(url); // 关上和URL之间的连贯 URLConnection conn = realUrl.openConnection(); // 设置通用的申请属性 conn.setRequestProperty("accept", "*/*"); conn.setRequestProperty("connection", "Keep-Alive"); conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)"); // 发送POST申请必须设置如下两行 conn.setDoOutput(true); conn.setDoInput(true); // 获取URLConnection对象对应的输入流 out = new PrintWriter(conn.getOutputStream()); // 发送申请参数 out.print(param); // flush输入流的缓冲 out.flush(); // 定义BufferedReader输出流来读取URL的响应 in = new BufferedReader( new InputStreamReader(conn.getInputStream())); String line; while ((line = in.readLine()) != null) { result += line; } } catch (Exception e) { System.out.println("发送 POST 申请出现异常!"+e); e.printStackTrace(); } //应用finally块来敞开输入流、输出流 finally{ try{ if(out!=null){ out.close(); } if(in!=null){ in.close(); } } catch(IOException ex){ ex.printStackTrace(); } } return result; } } ...

September 10, 2021 · 2 min · jiezi

关于spark:Spark-Iceberg-本地存储-一开篇学习

指标:从 iceberg 从找到 spark 相干类就算胜利 获得 plan:ReplaceData、MergeInto、DynamicFileFilterExec、ExtendedBatchScan 版本:spark 3.0.1,iceberg 0.11.0 数据源门路:file:///Users/bjhl/tmp/icebergData 创立一个 maven 我的项目,pom.xml 文件如下<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>spark-3.x-worker</artifactId> <version>1.0-SNAPSHOT</version> <inceptionYear>2008</inceptionYear> <properties> <scala.version>2.12.8</scala.version> </properties> <repositories> <repository> <id>scala-tools.org</id> <name>Scala-Tools Maven2 Repository</name> <url>http://scala-tools.org/repo-releases</url> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>scala-tools.org</id> <name>Scala-Tools Maven2 Repository</name> <url>http://scala-tools.org/repo-releases</url> </pluginRepository> </pluginRepositories> <dependencies> <dependency> <groupId>org.scala-lang</groupId> <artifactId>scala-library</artifactId> <version>${scala.version}</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.4</version> <scope>test</scope> </dependency> <dependency> <groupId>org.specs</groupId> <artifactId>specs</artifactId> <version>1.2.5</version> <scope>test</scope> </dependency> <!-- spark --> <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-core_2.12</artifactId> <version>3.0.1</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.spark</groupId> <artifactId>spark-sql_2.12</artifactId> <version>3.0.1</version> <scope>provided</scope> </dependency> <!-- https://mvnrepository.com/artifact/org.apache.iceberg/iceberg-spark3-runtime --> <dependency> <groupId>org.apache.iceberg</groupId> <artifactId>iceberg-spark3-runtime</artifactId> <version>0.11.0</version> </dependency><!-- &lt;!&ndash; https://mvnrepository.com/artifact/org.apache.avro/avro &ndash;&gt;--> <dependency> <groupId>org.apache.avro</groupId> <artifactId>avro</artifactId> <version>1.9.2</version> </dependency> </dependencies> <build> <sourceDirectory>src/main/scala</sourceDirectory> <testSourceDirectory>src/test/scala</testSourceDirectory> <plugins> <plugin> <groupId>org.scala-tools</groupId> <artifactId>maven-scala-plugin</artifactId> <executions> <execution> <goals> <goal>compile</goal> <goal>testCompile</goal> </goals> </execution> </executions> <configuration> <scalaVersion>${scala.version}</scalaVersion> <args> <arg>-target:jvm-1.5</arg> </args> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-eclipse-plugin</artifactId> <configuration> <downloadSources>true</downloadSources> <buildcommands> <buildcommand>ch.epfl.lamp.sdt.core.scalabuilder</buildcommand> </buildcommands> <additionalProjectnatures> <projectnature>ch.epfl.lamp.sdt.core.scalanature</projectnature> </additionalProjectnatures> <classpathContainers> <classpathContainer>org.eclipse.jdt.launching.JRE_CONTAINER</classpathContainer> <classpathContainer>ch.epfl.lamp.sdt.launching.SCALA_CONTAINER</classpathContainer> </classpathContainers> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>6</source> <target>6</target> </configuration> </plugin> </plugins> </build> <reporting> <plugins> <plugin> <groupId>org.scala-tools</groupId> <artifactId>maven-scala-plugin</artifactId> <configuration> <scalaVersion>${scala.version}</scalaVersion> </configuration> </plugin> </plugins> </reporting></project>SparkSession 配置 val spark = SparkSession .builder() .config("spark.sql.catalog.hadoop_prod.type", "hadoop") // 设置数据源类别为hadoop .config("spark.sql.catalog.hadoop_prod", "org.apache.iceberg.spark.SparkSessionCatalog") .config("spark.sql.catalog.hadoop_prod.warehouse", "file:///Users/bjhl/tmp/icebergData") // 设置数据源地位(本地) .config("spark.sql.extensions", "org.apache.iceberg.spark.extensions.IcebergSparkSessionExtensions") // 设置扩大,反对 merge into 等性能 .appName(this.getClass.getSimpleName) .master("local[*]") .getOrCreate()创立一张表 // 获取 catalog val hdpCatalog = spark.sessionState.catalogManager.catalog("hadoop_prod").asInstanceOf[SparkCatalog] val namespaces = Array("test") // 自定义 Identifier val identifier = new SimpleLocalIdentifierImpl("/Users/bjhl/tmp/icebergData/test/table_a", namespaces) val options = new util.HashMap[String, String]() // 用 spark StructType 创立 schema val schema = new StructType() .add("c1", IntegerType, true) .add("c2", StringType, true) .add("c3", StringType, true) // 创立一张表 hdpCatalog.createTable(identifier, schema, null, options) // 插入一条数据 spark.sql("insert into hadoop_prod.test.table_a VALUES (1, \"wlq\",\"zyc\")")生成的构造如下蕴含元数据信息和数据信息,test 相似库名,table_a 是表名 ...

September 9, 2021 · 2 min · jiezi

关于spark:SparkESClickHouse-构建DMP用户画像

package com.xolo.core.entity;import com.baomidou.mybatisplus.annotations.TableField;import com.baomidou.mybatisplus.annotations.TableId;import com.baomidou.mybatisplus.annotations.TableName;import com.baomidou.mybatisplus.enums.IdType;import io.swagger.annotations.ApiModel;import io.swagger.annotations.ApiModelProperty;import lombok.AllArgsConstructor;import lombok.Data;import lombok.NoArgsConstructor;import java.io.Serializable;import java.util.Date;@TableName("kpi_user") //对应于数据库中的表名@NoArgsConstructor@AllArgsConstructor@Data //注解在类上, 为类提供读写属性, 此外还提供了 equals()、hashCode()、toString() 方法@ApiModel("管理员用户信息") //实体正文public class User implements Serializable { @TableField("id") //对应于数据库中的字段名@ApiModelProperty("用户id") //字段正文@TableId(value = "id",type = IdType.AUTO) //进行插入操作必须将该字段设为自增类型private Integer id;@TableField("role_id")@ApiModelProperty("角色id,更新用户角色时传入")private Integer roleId;@TableField("group_id")@ApiModelProperty("组id,更新用户组时传入")private Integer groupId;@TableField("username")@ApiModelProperty("用户名")private String username;@TableField("mobile")@ApiModelProperty("管理员用户手机号")private String mobile;@TableField("password")@ApiModelProperty(hidden = true) //将该字段藏匿,对请求不可见private String password;@TableField("real_name")@ApiModelProperty("实在姓名")private String realName;@TableField("avatar")@ApiModelProperty("头像url")private String avatar;@TableField("is_delete")@ApiModelProperty(hidden = true)private Integer isDelete;@TableField("create_time")@ApiModelProperty(hidden = true)private Date createTime;@TableField("update_time")@ApiModelProperty(hidden = true)private Date updateTime;@ApiModelProperty("角色名称")@TableField(exist = false) //申明数据库中不存在的字段private String roleName;}

September 9, 2021 · 1 min · jiezi

关于spark:伴鱼借助-Flink-完成机器学习特征系统的升级

简介: Flink 用于机器学习特色工程,解决了特色上线难的问题;以及 SQL + Python UDF 如何用于生产实践。 本文作者陈易生,介绍了伴鱼平台机器学习特色零碎的降级,在架构上,从 Spark 转为 Flink,解决了特色上线难的问题,以及 SQL + Python UDF 如何用于生产实践。 次要内容为: 前言 老版特色零碎 V1 新版特色零碎 V2 总结 一、前言在伴鱼,咱们在多个在线场景应用机器学习进步用户的应用体验,例如:在伴鱼绘本中,咱们依据用户的帖子浏览记录,为用户举荐他们感兴趣的帖子;在转化后盾里,咱们依据用户的绘本购买记录,为用户举荐他们可能感兴趣的课程等。 特色是机器学习模型的输出。如何高效地将特色从数据源加工进去,让它可能被在线服务高效地拜访,决定了咱们是否在生产环境牢靠地应用机器学习。为此,咱们搭建了特色零碎,系统性地解决这一问题。目前,伴鱼的机器学习特色零碎运行了靠近 100 个特色,反对了多个业务线的模型对在线获取特色的需要。 上面,咱们将介绍特色零碎在伴鱼的演进过程,以及其中的衡量考量。 二、旧版特色零碎 V1特色零碎 V1 由三个外围组件形成:特色管道,特色仓库,和特色服务。整体架构如下图所示: 特色管道包含流特色管道和批特色管道,它们别离生产流数据源和批数据源,对数据通过预处理加工成特色 (这一步称为特色工程),并将特色写入特色仓库。 批特色管道应用 Spark 实现,由 DolphinScheduler 进行调度,跑在 YARN 集群上;出于技术栈的统一思考,流特色管道应用 Spark Structured Streaming 实现,和批特色管道一样跑在 YARN 集群上。特色仓库选用适合的存储组件 (Redis) 和数据结构 (Hashes),为模型服务提供低提早的特色拜访能力。之所以选用 Redis 作为存储,是因为: 伴鱼有丰盛的 Redis 应用教训;包含 DoorDash Feature Store和 Feast在内的业界特色仓库解决方案都应用了 Redis。特色服务屏蔽特色仓库的存储和数据结构,对外裸露 RPC 接口 GetFeatures(EntityName, FeatureNames),提供对特色的低提早点查问。在实现上,这一接口根本对应于 Redis 的 HMGET EntityName FeatureName_1 ... FeatureName_N 操作。 ...

September 7, 2021 · 2 min · jiezi

关于spark:SparkESClickHouse-构建DMP用户画像

download:Spark+ES+ClickHouse 构建DMP用户画像一:类型映射(Mapped Types) const data = { value: 123, text: "text", subData: { value: false}};type Data = typeof data;// type Data = {// value: number;// text: string;// subData: {// value: boolean;// }const data = ["text 1", "text 2"] as const;type Data = typeof data[number]; // "text 1" | "text 2"const locales = [ { locale: "se",language: "Swedish"}, { locale: "en",language: "English"}] as const;type Locale = typeof localesnumber; // "se" | "en"const currencySymbols = { GBP: "£", USD: "$", EUR: ""};type CurrencySymbol = keyof typeof currencySymbols; // "GBP" | "USD" | "EUR"二:Keyof与泛型(Generics) ...

September 7, 2021 · 2 min · jiezi

关于spark:EMR-on-ACK-全新发布助力企业高效构建大数据平台

简介: 阿里云 EMR on ACK 为用户提供了全新的构建大数据平台的形式,用户能够将开源大数据服务部署在阿里云容器服务(ACK)上。利用 ACK 在服务部署和对高性能可伸缩的容器利用治理的能力劣势,用户只须要专一在大数据作业自身。用户能够便捷地将 Spark、Presto、Flink 作业执行在 ACK 集群上,100%兼容开源,性能优于开源。 一、背景介绍技术趋势存储与计算拆散,向云原生演进在线业务、AI、大数据对立接入 ACK 集群,错峰调度,离线在线混部,晋升机器利用率对立运维入口,对立运维工具链,对立监控体系以集群为核心->以作业为核心多版本反对,例如能够同时跑 Spark2.x、Spark3.x云原生面临挑战计算与存储拆散:如何构建以对象存储 OSS 为底座的 HCFS 文件系统 • 须要齐全兼容现有的 HDFS • 性能对标 HDFS,老本升高 计算引擎 shuffle 数据存算拆散:如何解决 ACK 混合异构机型• 异构机型没有本地盘 • 社区[ Spark-25299]探讨,反对 Spark 动静资源,成为业界共识 ACK 调度能力:如何解决调度性能瓶颈 • 性能对标 Yarn • 多级队列治理 错峰调度 • 借助 K8s 操作系统能力,编排组织各种业务的波峰波谷 EMR on ACK 劣势Remote Shuffle Service 提供两头 shuffle 数据的存储计算拆散计划 • 能够使计算节点无需本地盘和云盘 • 反对关上 Spark 动静资源性能,Spark-25299 终极计划 JindoFS 针对 OSS 存储提供湖减速解决方案 ...

September 3, 2021 · 1 min · jiezi

关于spark:SparkESClickHouse-构建DMP用户画像

获取ZY:Spark+ES+ClickHouse 构建DMP用户画像importjava.util.Arrays;importjava.util.Collections;importjava.util.List; publicclassListPageUtil{ /** * 每页浮现条数 */privateintpageSize; /** * 总页数 */privateintpageCount; /** * 原汇合 */privateListdata;publicListPageUtil(Listdata,intpageSize) { if(data ==null|| data.isEmpty()) { thrownewIllegalArgumentException("data must be not empty!"); } this.data = data; this.pageSize = pageSize; this.pageCount = data.size()/pageSize; if(data.size()%pageSize!=0){ this.pageCount++; }}/** * 失去分页后的数据 * * @param pageNum 页码 * @return 分页后后果 */publicListgetPagedList(intpageNum) { intfromIndex = (pageNum -1) * pageSize; if(fromIndex >= data.size()) { returnCollections.emptyList(); } inttoIndex = pageNum * pageSize; if(toIndex >= data.size()) { toIndex = data.size(); } returndata.subList(fromIndex, toIndex);}publicintgetPageSize() { returnpageSize;}publicListgetData() { returndata;}publicintgetPageCount() { returnpageCount;}publicstaticvoidmain(String[] args) { Integer[] array = {1,2,3,4,5,6,7,8,9,10,11,12}; Listlist = Arrays.asList(array); ListPageUtilpager =newListPageUtil(list,10); System.out.println(pager.getPageCount()); Listpage1 = pager.getPagedList(1); System.out.println(page1); Listpage2 = pager.getPagedList(2); System.out.println(page2); Listpage3 = pager.getPagedList(3); System.out.println(page3);}} ...

September 2, 2021 · 1 min · jiezi

关于spark:Spark系列

Spark - 分布式高可用集群装置Spark - Spark Shell应用Spark - Spark Submit应用Spark - RDD应用Spark - 各个组件的RPC是怎么通信的Spark - Master和WorkerSpark - Application注册Spark - Executor的资源调度Spark - Executor的运行Spark - 长久化引擎Spark - Leader选举Spark - Standalone部署模式Spark - Standalone部署模式下,Application执行完了怎么办Spark - Executor异样退出怎么办Spark - Worker退出怎么办Spark - 宽依赖和窄依赖Spark - stage切分Spark - TaskSet提交Spark - Task的资源分配Spark - Task的执行过程(一)- BypassMergeSortShuffleWriterSpark - Task的执行过程(二)- UnsafeShuffleWriterSpark - Task的执行过程(三)- SortShuffleWriterSpark - 内存管理器与执行内存Spark - Task执行后果的解决Spark - 说说存储的那些事

August 30, 2021 · 1 min · jiezi

关于spark:Spark-说说存储的那些事

后面曾经差不多把执行的流程都讲完了,这篇讲讲每个Task执行的后果是如何存储和读取的。 BlockManagerBlockManager是SparkEnv中的组件之一,存储体系的所有组件和性能都是依赖着BlockManager,包含之前提到的ShuffleManager、DiskBlockManager、MapOutputTracker等,这篇会的流程也会再解说一次。 BlockManagerMasterBlockManager是SparkEnv的一部分,那Driver和Executor启动的时候,都会对BlockManager进行实例化。而Driver和Executor之间的BlockManager通信,包含注册BlockManager、更新Block信息、获取Block的地位(即Block所在的BlockManager)、删除Executor等,都是通过BlockManagerMaster。Driver启动的时候,BlockManagerMaster会创立BlockManagerMasterEndpoint并注册到Driver的RpcEnv中,而Executor启动的时候,会创立BlockManagerMasterEndpointRef,指向Driver的BlockManagerMasterEndpoint。BlockManagerMasterEndpoint中保护着一个HashMap,key为BlockManagerId,value为BlockManagerInfo。BlockManagerId是惟一的,就是通过BlockManagerMasterEndpoint来治理的。当Driver和Executor初始化BlockManager的时候,都会向BlockManagerMasterEndpoint发动RegisterBlockManager申请。Driver是发送给本人的,Executor通过BlockManagerMasterEndpointRef发送给BlockManagerMasterEndpoint。BlockManagerMasterEndpoint收到申请后,就会更新map里的值,所以BlockManagerMasterEndpoint治理着所有的BlockManagerId。并且把BlockManagerId返回给申请方。那BlockManagerId是什么? BlockManagerId不同节点和实例上的BlockManager进行互相通信的时候,就须要有一个惟一的身份标识-BlockManagerId。BlockManagerId包含host、port、executorId等信息。如果实例是Driver,那么executorId为driver,否则由Master负责给各个Executor调配,ID格局为app-日期格局字符串-数字。上图中,第一个是的Driver的BlockManager,她的executorId为driver。第二个是Executor的BlockManager,她的executorId略过日期格局,简写为app-0。第三个Executor的BlockManager,她的executorId略过日期格局,简写为app-1。 DiskBlockManagerBlockManager中有一个用来对磁盘上的文件及目录的读写操作进行治理,叫做磁盘块管理器DiskBlockManager。当要写入磁盘的时候(这里能够看之前Task的执行过程),DiskBlockManager就会创立惟一的BlockId和文件,用来存储Shuffle两头后果。DiskBlockManager保护着本地目录的数组localDirs以及本地子目录的二维数组subDirs。localDirs为blockmgr-为前缀,前面加UUID。subDirs记录本地子目录的数量,默认是64,所以创立文件的时候,就会依据判断二级目录是否存在,如果不存在则创立二级目录。整个树形构造如下:比方创立TempShuffleBlock,文件门路如下: DiskBlockObjectWriterDiskBlockManager创立文件后,对文件的写入操作是由DiskBlockObjectWriter来实现的(这里能够看之前Task的执行过程),最初合并后,就有了data数据文件和index索引文件。而后告知Driver文件的信息,此步骤具体见Task执行后果的解决。 BlockTransferServiceExecutor执行的过程中,会创立很多个块,块的传输都是通过块传输服务BlockTransferService,次要用于不同阶段的工作之间的Block数据的传输与读写。默认为NettyBlockTransferService,每个BlockTransferService都有netty对应的server用于提供服务和clientFactory用于创立client。假如Executor1执行的时候,通过trackerEndpoint向Driver的MapOutputTrackerMasterEndpoint获取到了她须要的block信息(此步骤具体见Task执行后果的解决)在Executor0,与是通过NettyBlockTransferService向Executor0获取block信息。Executor0接管到信息后,就会通过DiskBlockManager把data文件和index文件取出来,依据起始偏移量返回数据给Executor1。

August 29, 2021 · 1 min · jiezi

关于spark:Spark-Task执行结果的处理

后面曾经讲了每个action算子,都会进行stage切分,而后把每个stage依据分区创立TaskSet,依据资源运行Task,那这个stage就运行完结了。那stage怎么晓得本人各个分区曾经运行完结了,stage与stage间接数据是怎么传递的,每个具备依赖的stage是怎么执行的,是本章的重点。这里用之前的例子持续解说。 MapOutputTrackerMasterMapOutputTracker用于跟踪map工作的输入状态,在Drvier中的MapOutputTracker叫做MapOutputTrackerMaster,在Worker中的MapOutputTracker叫做MapOutputTrackerWorker。在stage进行切分的时候,每个ShuffleMapStage都会把他的shuffleId以及本人的分区数量,注册到MapOutputTrackerMaster。MapOutputTrackerMaster中保护着一个map,这个map的key就是shuffleId,他的value是ShuffleStatus。所以咱们之前的例子,就会有0到3的shuffleId注册到MapOutputTrackerMaster的map中。每个ShuffleStatus依据分区数,都会生成等同长度的类型为MapStatus数组mapStatuses,MapStatus示意ShuffleMapTask返回给TaskScheduler的执行后果。因为当初还没运行,所以数组mapStatuses是空的。这里只画了ShuffleStatus0,其余的ShuffleStatus也是一样的构造。 waitingStages这里补充一下TaskSet提交对于waitingStages的局部,因为waitingStages的作用是在这个篇幅中。stage切分完结后,开始提交stage。此时stage4发现他有父类stage0和stage3,于是就先提交父类。stage0并没有其余父类,于是他就提交给TaskSchedulerImpl。stage3有两个父类stage1和stage2,于是就先提交父类。stage1并没有其余父类,于是他就提交给TaskSchedulerImpl,这个时候,stage0和stage1都曾经提交了。stage2并没有其余父类,于是他就提交给TaskSchedulerImpl,这个时候,stage0和stage1、stage2都曾经提交了。stage3的两个父类stage1和stage2都解决了,于是他就退出到退出到waitingStages。stage4的两个父类stage0和stage3都解决了,于是他就退出到退出到waitingStages。waitingStages里的stage并没有理论提交,所以此时是stage0和stage1、stage2开始运行,stage3、stage4期待运行。 执行流程Executor执行完task后,通过DriverEndpointRfe把发消息给Drvier的DriverEndpointRef,告知以后的task运行完结。Drvier收到音讯后,发现状态是FINISHED,依据shuffleId和分区,更新MapOutputTrackerMaster的shuffleStatuses里的mapStatuses数组。咱们假如是分区1实现了,此时mapStatuses[1]就有后果数据了,而后_numAvailableOutputs就加1。如果_numAvailableOutputs和分区数量numPartitions相等,即都等于4,阐明这个stage就实现了。如果执行失败,就会把还没有实现的分区从新提交。当这个stage0胜利后,发现waitingStages中有本人的子stage4,就把stage4从waitingStages拿进去,开始尝试提交,后果他发现stage4另外一个父stage3还没执行,于是就持续退出到waitingStages。持续下面的流程,当stage1和stage2都执行完后,就会从waitingStages中拿出stage3继续执行,当stage3执行完后,stage4的两个父类都执行完了,所以stage4此时才开始执行。从这里能够看出,具备依赖关系的会等依赖的先执行,是串行的,如果没有依赖关系的,会并发执行,这个是并行的。 MapOutputTrackerWorker下面的stage3依赖着stage1和stage2,那stage3开始执行的时候,是须要stage1和stage2的执行后果的。Executor的MapOutputTrackerWorker保护着map,key是shuffleId,value是MapStatus数组,对应着下面的mapStatuses。假如stage3拿stage1的时候,发现他并没有存储stage1的数据,于是就持有MapOutputTrackerMasterEndpoint援用的trackerEndpoint给MapOutputTrackerMasterEndpoint发送GetMapOutputStatuses音讯。MapOutputTrackerMasterEndpoint收到音讯后,就把音讯发送给MapOutputTrackerMaster的阻塞队列mapOutputRequests。MapOutputTrackerMaster里有一个线程池,保护着线程来解决这个阻塞队列。当线程发送阻塞队列有音讯后,就会开始解决这个音讯,并把后果返回给申请方。Executor拿到数据后,就开始对数据进行计算。

August 28, 2021 · 1 min · jiezi

关于spark:Spark学习记录之SparkCore核心属性

Spark学习记录之SparkCore初步概念Spark是一种基于内存的疾速、通用、可扩大的大数据分析计算引擎。 蕴含的模块有,Spark Core,Spark SQL,Spark Streaming,Spark MLib,Spark GraphX Spark Submit例子Standalone bin/spark-submit \--class org.apache.spark.examples.SparkPi \--master spark://spark111:7077 \./examples/jars/spark-examples_2.12-3.0.0.jar \1000Yarn bin/spark-submit \--class org.apache.spark.examples.SparkPi \--master yarn \--deploy-mode cluster \./examples/jars/spark-examples_2.12-3.0.0.jar \100bin/spark-submit \ --class org.apache.spark.examples.SparkPi \ --master yarn \ --deploy-mode client \ ./examples/jars/spark-examples_2.12-3.0.0.jar \ 100Spark On Yarn两种模式的区别在于:Driver程序运行的节点不同。Client模式将用于监控和调度的Driver模块启动在客户端,而Cluster则将Driver模块启动在集群中。因而Client模式个别用于测试,Cluster则用于生产部署。 Yarn Client模式 Driver在提交工作的本地运行Driver启动后,会和ReourceManager通信,申请启动ApplicationMasterResourceManager调配Container,在适合的NodeManager上启动ApplicationMaster,负责向ResourceManager申请Executor的资源ResourceManager接到ApplicationMaster的申请后,调配Container,而后ApplicationMaster在资源分配指定的NodeManager上启动Executor过程。Executor过程启动后,会反向注册到Driver,Executor全副启动实现后,Driver开始执行main函数执行到Action算子时,触发一个job,并依据宽依赖开始切分stage,每个stage生成对应的TaskSet,之后Driver会将task散发到各个Executor上执行Yarn Cluster模式 在Yarn Cluster模式下,工作提交后会向ResourceManager通信申请启动ApplicationMaster随后ResourceManger调配Container,在适合的NodeManager上启动ApplicationMaster,此时ApplicationMaster就是DriverDriver启动后,向ResourceManager申请Exexutor资源。ResourceManager调配Contaioner,ApplicationMaster在对应的NodeManager上启动Excutor。Executor启动后会向Driver进行反向注册当Executor全副启动结束后,Driver开始执行main函数执行到Action算子时,触发一个job,并依据宽依赖切分stage,每个stage上生成对应的TaskSet,之后Driver回将task散发到各个Executor上执行RDDRDD(Resilient Distributed Dataset),弹性分布式数据集 分区,与Hadoop MapReduce的比照 MapReduce有切片和分区,这是两个不同的概念,切片次要作用于MapTask阶段,以TextInputFormat为例,切片依据文件块大小来决定,默认状况下,切片大小就等于块大小,当然切片大小可通过配置调节,个别状况下,块大小为128M或256M,以磁盘速度决定。一个文件会以切片大小来切分为多个逻辑上的小文件,因而切片个数就等于MapTask的个数,即MapTask的并行数MapReduce的分区是要在代码中指定设置的,默认为一个分区,分区个数对应的是ReduceTask的个数。默认的分区器Partitioner是HashPartitioner,以(key & Long.MAX_VALUE)%numReduceTasks计算得来,即在HashPartitioner的计算逻辑中,设定多少个numReduceTasks就会有多少个分区。用户能够通过继承Partioner来自定义分区器,以实现指定的分区个数。MapReduce的分区数也会作用在MapTask阶段,在数据处理map办法进入环形缓冲区前会给数据标记上分区,在环形缓冲区的溢写排序和多个溢写文件的排序合并中都会以分区为单位进行RDD中,一个stage中的task数量,是以该stage中的最初一个算子的分区数决定的5个外围属性 分区列表 protected def getPartitions: Array[Partition]分区计算函数 def compute(split: Partition, context: TaskContext): Iterator[T]RDD之间的依赖关系 protected def getDependencies: Seq[Dependency[_]] = deps分区器(可选) ...

August 25, 2021 · 2 min · jiezi

关于spark:基于英特尔®-优化分析包OAP的-Spark-性能优化方案

简介: Spark SQL 作为 Spark 用来解决结构化数据的一个根本模块,曾经成为少数企业构建大数据利用的重要抉择。然而,在大规模连贯(Join)、聚合(Aggregate)等工作负载下,Spark 性能会面临稳定性和性能方面的挑战。Spark SQL 作为 Spark 用来解决结构化数据的一个根本模块,曾经成为少数企业构建大数据利用的重要抉择。然而,在大规模连贯(Join)、聚合(Aggregate)等工作负载下,Spark 性能会面临稳定性和性能方面的挑战。 为了晋升 Spark SQL 的性能,用户能够抉择应用英特尔® 优化剖析包(Optimized Analytics Package,OAP)以及英特尔® 傲腾™ 长久内存和新一代英特尔® 至强® 处理器来改善典型 Spark SQL 工作负载的运行效率。 Spark SQL 面临多场景性能瓶颈IDC 报告显示,寰球数据规模将从2019年的45 ZB 增长到2025年的175 ZB ,2020年创立、捕捉和耗费的数据量预计过 59 ZB。在数据疾速挪动、迅猛增长的趋势下,企业须要应用先进的剖析技术来实时处理数据以取得实时的业务洞察力。大数据分析技术的新倒退与革命性新硬件的问世,显著进步了大数据分析性能,使得数据科学家、分析师和业务用户可能取得更粗浅的业务洞察。 作为面向大规模数据处理而设计的疾速通用的计算引擎,Spark 具备开源、经济、灵便等长处,罕用来构建大型、低提早的数据分析应用程序。然而,Spark 在特定场景下仍然会面临性能挑战,特地是当解决特大规模数据及交互式查问时。例如,因为短少高性能缓存计划,数据 I/O 很容易成为瓶颈。此外,Spark Shuffle 也经常因为大量的较小随机磁盘 IO、序列化、网络数据传输成为性能瓶颈,导致作业提早大幅减少,进而影响工作负载性能。 新兴的硬件技术能够帮忙解决这些挑战。例如,高级矢量扩大(AVX)性能使 Spark 可能利用 SIMD 同时解决更多的数据来放慢执行速度,而英特尔® 傲腾™ 长久内存能够利用其高性能,大容量和低提早翻新的突破性组合来进步 Spark SQL 性能。OAP(优化剖析包)是英特尔和社区开发的一个开源我的项目,旨在借助先进的英特尔处理器、内存和存储以及网络技术,通过数据源缓存、SQL 索引、Native SQL 引擎、MLlib 优化等翻新软件性能进步 Spark 性能,以解决 Spark 外围和相干组件面临的计算和 I/O挑战。 英特尔 Spark 优化剖析包(OAP)英特尔® 优化剖析包(OAP)是英特尔和社区开发的开源我的项目,旨在进步 Spark 性能。它基于先进的英特尔硬件技术,提供了多种性能来改善 Spark 高速缓存、Shuffle、执行和机器学习性能。如下图1显示了 OAP 架构,它包含以下组件:OAP 数据源高速缓存、Native SQL 引擎、Arrow 数据源、OAP MLlib、RDD 高速缓存、RPMem Shuffle 和远端 Shuffle。 ...

August 20, 2021 · 2 min · jiezi

关于spark:26万奖金-第一届-EMapReduce-极客挑战赛-诚邀英才前来挑战

日前,“ 第一届 E-MapReduce 极客挑战赛 ”在阿里云天池官网正式开赛。据悉,本次大赛由阿里云、英特尔联结举办,聚焦 SparkSQL 执行效率,摸索 TPC-DS 测试集最优性能,助力海量数据轻松上云,全程将有资深技术专家提供技术领导。大赛现已面向全社会凋谢报名,集体开发者、高等院校、企业、科研单位等人员均可报名参赛,为宽广大数据爱好者以及相干的科研企业提供挑战平台。报名链接:(报名工夫即日起至 09/21):https://tianchi.aliyun.com/co... 大赛背景与赛题阐明大数据时代,上云已成为越来越多终端客户大数据计划的落地抉择。如何晋升数据效率,对企业倒退至关重要。本次大赛聚焦外围业务场景难题,联合阿里云 EMR和英特尔® 傲腾™ 数据中心级长久内存以及Intel OAP 软件包,优化软件系统和利用硬件的特色,谋求TPC-DS测试集的最优性能。 EMR 团队提供用于较量的Spark 3.1.2代码分支,选手进行 Spark 代码优化和参数调优以晋升SparkSQL执行效率,同时组委会提供性能测评工具供选手自行测试(单机环境或EMR集群环境)。在较量阶段,选手将最终优化后的Spark代码和调优参数打包,通过天池平台提交,天池平台会应用雷同的性能测评工具,进行评测和排名。 大赛炽热报名中,快来挑战吧本届大赛从即日起——9月21日均可报名,通过初赛、复赛两轮比试后,复赛成绩排名TOP6的参赛队伍将受邀加入11月举办的决赛问难。 瓜分26万元奖金池• 冠军:1支队伍/赛道,奖金10万,颁发获奖证书• 亚军:2支队伍/赛道,奖金5万,并颁发获奖证书• 季军:3支队伍/赛道,奖金2万,并颁发获奖证书 惊喜好礼送不停为了让宽广开发者们的“打榜”之路更加好玩,组委会设置了以下流动并装备了超多精美好礼回馈社区。 云上举荐达人流动工夫:7月5日-9月20日参加形式:流动期间,点击赛制页面邀请参赛按钮,获取专属邀请海报并分享给好友,好友报名胜利后即可取得20张粮票。本次较量拉新总奖金池共计五万张粮票,粮票计算规定为10:1。云上冲榜达人流动工夫:7月27日-9月24日参加形式:流动期间,报名EMR极客挑战赛,提交出分上榜后即可参加冲榜达人评比。自8月13日起以每周五早晨21点测评问题为准,每周周冠军队伍将取得T恤一件(不得反复支付)。依据9月24日晚20点排行后果,排名TOP30队伍成为云上冲榜达人,每队将取得EMR定制雨伞1个+较量定制T恤1件。云上进阶达人流动工夫:9月27日-10月29日参加形式:复赛期间(9月27日-10月29日),提交出分上榜后即可参加进阶达人评比。依据10月29日晚20点排行后果,排名TOP10队伍成为云上进阶达人,每队将取得EMR定制双肩包1个。云上分享达人流动工夫:7月5日-10月29日参加形式:如何成为云上分享达人?流动期间,报名EMR极客挑战赛并在论坛公布提分攻略,关联到挑战赛。即可参加云上分享达人奖项评比,获赞最多的帖子发布者获胜,将取得EMR大礼包1套(EMR定制雨伞+双肩包+T恤)。更多福利咱们不定期会推出更多流动,但凡参加本次大赛的选手,均有机会取得好礼哦。退出大赛选手钉钉交换群:35434038,第一工夫捕捉最新动静!除了惯例奖项,为广罗大数据高技能人才,体现优良的参赛选手还可取得阿里云EMR产品事业部优先内推名额,与行业精英共建产品新生态。 取得与大咖面对面畅聊技术的机会:贾扬清阿里巴巴团体副总裁 | 阿里云计算平台事业部负责人“心愿通过这次大赛,让开发者们在体验云原生的开发环境的同时,能够尝试一次技术的挑战。不仅在较量中播种好的问题,更重要的是寻找到代码的乐趣和技术的播种。”王峰(莫问)阿里云研究员 | 阿里云开源大数据平台负责人“咱们欢送来自高校、企业及各行业的开发者们退出咱们的较量,心愿各位开发者能在这次比赛中充沛展现本人的技术能力。”陈守元(巴真)阿里云开源大数据平台产品负责人“咱们心愿为宽广的大数据爱好者及科研企业提供一个翻新挑战的平台,一起来摸索性能极限。”Heidi PanIntel 数据分析软件部门总监“心愿大家通过这次较量可能有所播种,可能对数据分析引擎的性能优化有更粗浅的领会与了解洞察。”于邦旭CSDN副总裁“心愿选手们能够在此次大赛中大展才华,施展出实在程度,一战成名!同时预祝本届E-MapReduce 极客挑战赛获得圆满成功!”陈绪汇量科技大数据与机器学习平台负责人“心愿参赛队伍能够深入分析查问计算现有性能瓶颈,做出针对性的优化,期待看到更多翻新计划来挑战性能极限。”黄继映客技术平台总监“心愿EMR成为名列前茅的数据平台,同时祝福参赛者们能够充分发挥技术能力,挖掘出零碎更大的性能后劲。” 技术专家全程护航领导本届 E-MapReduce 极客挑战赛全程有资深技术专家为参赛选手们提供最业余的技术答疑和领导。为助力选手高效答题,组委会制作了赛题解析,解说自测工具的应用以及代码的提交和评测,返回查看>>对较量感兴趣或者参赛过程中有疑难的小伙伴,欢送扫描下方二维码退出交换群一起来交换探讨~

August 19, 2021 · 1 min · jiezi

关于spark:SparkESClickHouse-构建DMP用户画像

download:Spark+ES+ClickHouse 构建DMP用户画像include<iostream.h>typedef int Status;typedef char Cstack; define OK 1define ERROR 0typedef struct StackNode{ Cstack data;struct StackNode *next;}StackNode,*LinkStack; Status InitStack(LinkStack &S){ S=NULL;return OK;}Status Push(LinkStack &S,Cstack e){ StackNode *p;p=new StackNode;p->data=e;p->next=S;S=p;return OK;}Status Pop(LinkStack &S,Cstack &e){ StackNode *p;if(S==NULL) return ERROR;e=S->data;p=S;S=S->next;delete p;return OK;}Cstack GetTop(LinkStack S){ if(S!=NULL)return S->data;}Status In(Cstack ch){ cin>>ch;if(ch=='+') return OK;else if(ch=='-') return OK;else if(ch=='*') return OK;else if(ch=='/') return OK;else if(ch=='#') return OK;else return ERROR;}Cstack Precede(Cstack t1,Cstack t2){ switch(t1){case '+': switch(t2) { case '+':return '>';break; case '-':return '>';break; case '*':return '<';break; case '/':return '<';break; case '(':return '<';break; case ')':return '>';break; case '#':return '>';break; } break; case '-': switch(t2) { case '+':return '>';break; case '-':return '>';break; case '*':return '<';break; case '/':return '<';break; case '(':return '<';break; case ')':return '>';break; case '#':return '>';break; } break; case '*': switch(t2) { case '+':return '>';break; case '-':return '>';break; case '*':return '>';break; case '/':return '>';break; case '(':return '<';break; case ')':return '>';break; case '#':return '>';break; } break; case '/': switch(t2) { case '+':return '>';break; case '-':return '>';break; case '*':return '>';break; case '/':return '>';break; case '(':return '<';break; case ')':return '>';break; case '#':return '>';break; } break; case '(': switch(t2) { case '+':return '<';break; case '-':return '<';break; case '*':return '<';break; case '/':return '<';break; case '(':return '<';break; case ')':return '=';break; case '#':return '>';break; } break; case ')': switch(t2) { case '+':return '>';break; case '-':return '>';break; case '*':return '>';break; case '/':return '>';break; case '(':return '=';break; case ')':return '>';break; case '#':return '>';break; } break; case '#': return '='; break;}}Cstack Operator(Cstack t1,Cstack t2,Cstack t3){ ...

August 18, 2021 · 2 min · jiezi

关于spark:Spark-内存管理器与执行内存

在SortShuffleWriter和UnsafeShuffleWriter都提到了执行内存的申请,为了阐明内存的申请过程,咱们先看看内存管理器。 内存管理器Executor启动的时候,就会创立一个内存管理器MemoryManager(默认UnifiedMemoryManager),MemoryManager对存储体系和内存计算所应用的内存进行治理。内存又分为堆外内存和堆内存,所以MemoryManager就有4个内存池,别离为堆内存的存储内存池onHeapStorageMemoryPool、堆外内存的存储内存池offHeapStorageMemoryPool、堆内存的执行计算内存池onHeapExecutionMemoryPool、堆外内存的执行计算内存池offHeapExecutionMemoryPool,每个内存池都记录着内存池的大小和已应用的大小。下图把堆内和堆外的执行计算的内存和存储的内存并在一起,是因为他们之间并没有一个显著的界线,比如说堆内执行计算的内存不够用了,就会向堆内存储的内存“借”内存,堆内存储的内存也会向堆内执行计算的内存“借”内存。堆外执行计算的内存和存储的内存也是能够互相“借”内存。 内存消费者和工作内存管理器Task的资源分配中曾经晓得,Driver会把task封装成TaskDescription,交给Executor去执行。Executor会把TaskDescription封装成TaskRunner并放入线程池中,如果须要内部排序的话,最初会用到UnsafeShuffleWriter的ShuffleExternalSorter或者SortShuffleWriter的ExternalSorter。这两个内部排序器其实都是内存消费者MemoryConsumer。内存消费者仅仅定义了内存消费者的标准,实际上对内存的申请、开释是由工作内存管理器TaskMemoryManager来治理的。工作内存管理器实际上依赖于MemoryManager提供的内存治理能力,所以Executor同时有多个TaskRunner在执行的时候,就会有多个内存消费者,每个内存消费者都会通过工作内存管理器对内存管理器申请、开释内存。 申请内存内存消费者为了排序性能的进步,会把RDD的数据集事后寄存在内存中,这个内存是须要向内存管理器申请的。咱们假设内存模式是堆内存,那申请的内存就是堆内存的执行计算内存池,内存池的大小_poolSize为100。每个执行内存池中都保护着一个map,叫做memoryForTask,key是工作内存管理器的身份标识taskAttemptId,value是工作内存管理器已申请的内存大小。此时,taskAttemptId为1的工作内存管理器去堆内存的执行计算内存池申请10内存,他发现memoryForTask里并没有taskAttemptId为1的key,于是就把key为1,value为0赋值给memoryForTask。每个工作所能申请的内存范畴是poolSize/2N到maxPoolSize/N之间,这个N是memoryForTask中key的数量,poolSize是以后内存池的大小,maxPoolSize是以后内存池可应用的最大大小,这个值是包含堆内存的存储内存池的局部甚至全副内存大小,也就是说,如果执行计算内存池不够用了,是能够从存储内存池借的。当然存储内存池也能够向执行计算内存池借内存。目前执行计算内存池的内存可能满足taskAttemptId为1所须要的内存,所以间接给分配内存,并更新memoryForTask中taskAttemptId为1的值为10。taskAttemptId为2的工作内存管理器去堆内存的执行计算内存池申请50内存,流程同上。此时线程池中,可用内存就剩下100-10-10-50=30了。taskAttemptId为3的工作内存管理器去堆内存的执行计算内存池申请20内存,流程同上。此时线程池中,可用内存就剩下100-10-10-50-20=10了。taskAttemptId为3的工作内存管理器去堆内存的执行计算内存池持续申请20内存,此时内存曾经不够用了,执行计算内存池就会去存储内存池要回借出去的内存(如果有的话),并且向存储内存池借了10内存,taskAttemptId为3的值就变成了20+20=40。此时这4个工作内存管理器申请的内存曾经超过了堆内存的执行计算内存池。taskAttemptId为4的工作内存管理器去堆内存的执行计算内存池申请20内存,然而执行计算内存池和存储内存池借来的内存曾经不满足20,或者比要求的内存最小值还小,以后线程处于期待状态。 内存开释taskAttemptId为2的工作内存管理器此时开释了40内存,此时对应的value就变成了50-40=10,而后唤醒所有阻塞的线程,比方下面的taskAttemptId为4对应的线程。taskAttemptId为4对应的线程被唤醒后,发现能够申请20,于是更新对应的值。taskAttemptId为2的工作内存管理器此时持续开释了10内存,此时对应的value就变成了10-10=0,因为小于等于0了,所以这个key就删除掉,并且再唤醒所有阻塞的线程。

August 18, 2021 · 1 min · jiezi

关于spark:SparkESClickHouse-构建DMP用户画像

download:Spark+ES+ClickHouse 构建DMP用户画像public static String getPubTimeVarious(String url,String urlContent) { String pubTime = getPubTimeFromUrl(url); //链接外面没有,匹配文本中的 if(pubTime == null) { if(urlContent!=null&&!urlContent.trim().equals("")) return extractPageDate(urlContent); } return pubTime;} /**从url外面抽取出公布工夫,返回YYYY-MM-DD HH:mm:ss格局的字符串 * @param url * @return */public static String getPubTimeFromUrl(String url){ Pattern p_whole = Pattern.compile(url_reg_whole); Matcher m_whole = p_whole.matcher(url); if(m_whole.find(0)&&m_whole.groupCount()>0) { String time = m_whole.group(0); time = time.substring(1,time.length()); //每一步都不可能超出以后工夫 if(current.compareTo(TimeUtil.strToCalendar(time, "yyyyMMdd"))>=0) { return time.substring(0,4)+"-"+time.substring(4,6)+"-"+ time.substring(6,8)+" "+"00:00:00"; } } p_whole = null; m_whole = null; Pattern p_sep = Pattern.compile(url_reg_sep_ymd); Matcher m_sep = p_sep.matcher(url); if(m_sep.find(0)&&m_sep.groupCount()>0) { String time = m_sep.group(0); time = time.substring(1,time.length()); String[] seg = time.split("[-|/|_]{1}"); Calendar theTime = Calendar.getInstance(); theTime.set(Calendar.YEAR,Integer.parseInt(seg[0])); theTime.set(Calendar.MONTH, Integer.parseInt(seg[1])); theTime.set(Calendar.DAY_OF_MONTH, Integer.parseInt(seg[2])); if(current.compareTo(theTime)>=0) { return seg[0]+"-"+seg[1]+"-"+seg[2]+" "+"00:00:00"; } } p_sep = null; m_sep = null; Pattern p_sep_ym = Pattern.compile(url_reg_sep_ym); Matcher m_sep_ym = p_sep_ym.matcher(url); if(m_sep_ym.find(0)&&m_sep_ym.groupCount()>0) { String time = m_sep_ym.group(0); time = time.substring(1,time.length()); Calendar theTime = Calendar.getInstance(); String[] seg = time.split("[-|/|_]{1}"); theTime.set(Calendar.YEAR,Integer.parseInt(seg[0])); theTime.set(Calendar.MONTH, Integer.parseInt(seg[1])); theTime.set(Calendar.DAY_OF_MONTH, 1); if(current.compareTo(theTime)>=0) { return seg[0]+"-"+seg[1]+"-"+"01"+" "+"00:00:00"; } } return null;}

August 17, 2021 · 1 min · jiezi

关于spark:Spark-Task的执行过程三-SortShuffleWriter

后面曾经介绍了BypassMergeSortShuffleWriter和UnsafeShuffleWriter两种ShuffleWriter实现,这里开始SortShuffleWriter的解说。SortShuffleWriter应用ExternalSorter作为排序器,ExternalSorter又蕴含了具备聚合性能的PartitionedAppendOnlyMap和没有聚合性能的PartitionedPairBuffer这两种缓存,所以SortShuffleWriter既有反对排序的性能,也反对聚合的性能。 聚合聚合是通过PartitionedAppendOnlyMap来解决的,所以记录会迭代输出给PartitionedAppendOnlyMap,上面聚合的例子均为reduce为算法。PartitionedAppendOnlyMap反对key是null值的,haveNullValue是用来判断是否曾经有了key为null的值,nullValue是用来存储key为null的值。所以没有传入key为null的时候,haveNullValue为false,nullValue为null。此时records迭代的记录为(null,1),因为haveNullValue为false,间接赋值nullValue为1,并把haveNullValue就改为true。records新迭代的记录为(null,10),因为haveNullValue为true,则把nullValue的值1拿进去,并跟新值10进行相加,失去的11从新赋值给nullValue。如果key不为null,PartitionedAppendOnlyMap是有一个数组data来存储的,格局就是key0,value0,key1,value1的模式。key的格局是(partitionId, key)。records新迭代的记录为(a,1),咱们假如a对应的分区为0,且a在hash及与mask进行与运算后,失去的pos为1,所以数组的2*1=2的地位就是key,因为此时key是空的,key的值为(0,a),2+1的地位,就是(0,a)对应的值1。2*pos的2,是因为每个值都占有2个地位。records新迭代的记录为(a,10),此时这个key对应的地位是有值的,所以把旧值1拿进去,和新值10进行相加,失去的11存入key前面的地位。records新迭代的记录为(b,2),咱们假如b对应的分区为1,且b在hash及与mask进行与运算后,失去的pos为2,所以数组的2*2=4的地位就是key,因为此时key是空的,key的值为(1,b),4+1的地位,就是(1,b)对应的值2。每次往空的key插入数据的时候,都会测验是否扩容。records新迭代的记录为(b,10),此时这个key对应的地位是有值的,所以把旧值2拿进去,和新值10进行相加,失去的12存入key前面的地位。records新迭代的记录为(c,3),咱们假如c对应的分区为0,且b在hash及与mask进行与运算后,失去的pos为1,所以数组的2*1=2的地位就是key,因为此时key不为空,且key是(0,a),并不是(0,c),所以pos会进行加1并且与mask进行与运算后,从新获取pos,如果拿到的pos地位还是有其余的key,则pos再加1从新计算,直至pos地位并无其余key或者key为(0,c)。咱们假如最初的地位是6。每次迭代records后,会看以后的内存是否超过了内存阈值,如果超过了,就会依据公式2 * currentMemory - myMemoryThreshold尝试获取内存,如果获取内存失败,阐明曾经没有多余的内存能够调配了,这个时候就会进行溢出。溢出之前,先对data中的数据向前整顿排列,就是往左边的空值进行迁徙,依照分区ID的程序进行从新排序。此时程序就是(0,a),(0,c),(1,b)。而后再依据整顿后的data以及haveNullValue、nullValue创立迭代器。这个迭代器会先拜访nullValue,而后再迭代data。每写入1万次,就会有一个flush操作,把输入流中的数据真正写入到磁盘,并记录每个分区的元素个数以及每次写入磁盘的数据大小。当迭代器迭代完结,就会开释占用的内存,并从新创立一个PartitionedAppendOnlyMap,每次溢出都会记录在spills数组中。当records的数据迭代结束,就会依据内存的数据和溢出到磁盘的文件进行归并排序,最终合并到一个文件中,并记录每个分区的长度。最初依据分区的长度,生成索引文件。 非聚合聚合是通过PartitionedPairBuffer来解决的,所以记录会迭代输出给PartitionedPairBuffer,上面聚合的例子均为reduce为算法。PartitionedPairBuffer里的构造就相似于一个汇合,数据依照程序进行插入,插入的时候也是每次插入2个,一个是kye一个是value,这个和PartitionedAppendOnlyMap一样。records新迭代的记录为(a,1),咱们假如a对应的分区为0,所以间接在数组里插入(0,a)和1。records新迭代的记录为(b,2),咱们假如b对应的分区为1,所以间接在数组里插入(1,b)和2。records新迭代的记录为(c,3),咱们假如c对应的分区为0,所以间接在数组里插入(0,c)和3。records新迭代的记录为(a,4),咱们假如a对应的分区为0,所以间接在数组里插入(0,a)和4,这里并没有聚合。溢出、写文件、写索引前面的流程同聚合。

August 16, 2021 · 1 min · jiezi

关于spark:SparkESClickHouse-构建DMP用户画像

download:Spark+ES+ClickHouse 构建DMP用户画像package test; import java.util.regex.Matcher; import java.util.regex.Pattern; /** 正则表达式正则表达式 的用法次要是4种方面的应用匹配,宰割,替换,获取.用一些简略的符号来代表代码的操作@author cyc*/public class Rex { public static void main(String[] args) { //针对字符串解决 Rex reg = new Rex(); //校验qq的reg正则表达式 //这里的\w 是指的是[a-zA-Z0-9],还有一个重要的是?,*.+这三个别离 //?示意呈现1次或者1次都没有, //+示意呈现1次或者n次, //*示意呈现0次或者n次, //还有些非凡的写法X{n}恰好n次X{n,}至多n次,X{n,m}n次到m次, String mathReg = "[1-9]\\d{4,19}"; String divisionReg = "(.)\\1+"; //\\b 是指的边界值 String getStringReg = "\\b\\w{3}\\b"; //字符串匹配(首位是除0 的字符串) reg.getMatch("739295732",mathReg); reg.getMatch("039295732",mathReg); //字符串的替换 //去除叠词 reg.getReplace("12111123ASDASDAAADDD",divisionReg,"$1"); //字符串的宰割 //切割叠词,反复的 //这里要晓得一个组的概念(.)\\1第二个和第一个至雷同 reg.getDivision("aadddddasdasdasaaaaaassssfq",divisionReg); //字符串的获取 //当初获取三个字符串取出 reg.getString("ming tian jiu yao fangjia le ",getStringReg); } /** * 获取查问的字符串 * 将匹配的字符串取出 */ private void getString(String str, String regx) { //1.将正在表达式封装成对象Patten 类来实现 Pattern pattern = Pattern.compile(regx); //2.将字符串和正则表达式相关联 Matcher matcher = pattern.matcher(str); //3.String 对象中的matches 办法就是通过这个Matcher和pattern来实现的。 System.out.println(matcher.matches()); //查找合乎规定的子串 while(matcher.find()){ //获取 字符串 System.out.println(matcher.group()); //获取的字符串的首地位和末地位 System.out.println(matcher.start()+"--"+matcher.end()); } } /** * 字符串的宰割 */ private void getDivision(String str, String regx) { String [] dataStr = str.split(regx); for(String s:dataStr){ System.out.println("正则表达式宰割++"+s); } } /** * 字符串的替换 */ private void getReplace(String str, String regx,String replaceStr) { String stri = str.replaceAll(regx,replaceStr) ; System.out.println("正则表达式替换"+stri); } /** * 字符串解决之匹配 * String类中的match 办法 */ public void getMatch(String str, String regx){ System.out.println("正则表白匹配"+str.matches(regx)); } } ...

August 16, 2021 · 1 min · jiezi

关于spark:Spark-Task的执行过程二-UnsafeShuffleWriter

上一篇讲了BypassMergeSortShuffleWriter实现形式,并且晓得抉择BypassMergeSortShuffleWriter的时候,分区数是不能超过200的,因为每次执行的时候,会依据分区数量,学生成临时文件,如果分区数很多的话,那就会很有很多的临时文件,磁盘性能就十分不好。UnsafeShuffleWriter也是不具备聚合性能的,然而他应用Tungsten的内存作为缓存,这样磁盘的性能就失去了大大的晋升。 流程拿到RDD的后果后,迭代每条记录,把记录的键值对写入到SerializationStream的输入流中,SerializationStream是包装了名为serBuffer的MyByteArrayOutputStream对象。而后把字节数组交给ShuffleExternalSorter,一个专门用于对Shuffle数据进行排序的内部排序器。内部排序器拿到字节数组,发现此时没有page(即MemoryBlock),于是就创立了一个page,把字节数组放在page中。另外须要把创立的page退出到曾经调配的Page列表allocatedPages,并把创立的page作为currentPage。同时还要记录元数据信息,寄存在ShuffleInMemorySorter的长整型数组中用于排序,其中高24位存储分区ID,两头13位存储页号,低27位存储偏移量。反复着下面的步骤,迭代RDD每条记录,直至page没有足够的空间。此时就要申请调配新的Page,把这个page退出到曾经调配的Page列表allocatedPages,并把新创建的page作为currentPage,新的字节数组就往新的page里放。RDD的后果持续迭代,ShuffleInMemorySorter中的记录数超过设定的值,或者长整型数组曾经不够用然而无奈扩大的时候,就须要内存中的数据将被溢出到磁盘。首先是对内存中的数据依据分区进行排序,咱们上面用0或1示意分区,XY标识页号和偏移量。通过排序后,内存中的数据就依据分区有序的排列起来。而后依据分区,把数据写入文件中,并把文件信息写在SpillInfo中,SpillInfo记录了这个文件的信息、blockId信息以及每个分区对应文件里的长度(比方4,4)。这个SpillInfo最终寄存在元数据信息的列表spills中。数据都保留在磁盘后,那内存中的数据就能够革除回收了,包含曾经调配的Page列表allocatedPages、每个page、currentPage、ShuffleInMemorySorter。假如RDD的后果在写完3次file时完结了,那此时spills列表就有3个SpillInfo,每个SpillInfo都指向着文件,并且记录每个分区对应的长度(假如为(4,4),(3,2),(5,1))。最终依据spilss列表中的3个SpillInfo,依据每个分区对应的长度,把每个文件分区0的内容写入到新的文件,并记录分区0的长度为12,再把每个文件分区1的内容写入到新的文件,并记录分区1的长度为7,依据两个分区的长度,生成索引文件。和BypassMergeSortShuffleWriter比起来,假如有1万个分区,BypassMergeSortShuffleWriter是会学生成1万个临时文件,最初再进行合并,而UnsafeShuffleWriter是依据RDD后果集的数据大小,生成临时文件,大大减少了临时文件的个数。

August 12, 2021 · 1 min · jiezi

关于spark:Spark-Task的执行过程一

后面讲了Task的创立、提交,以及对Task进行资源调度与调配,对于Task的实现细节一笔带过,所以这篇开始解说Task的执行过程。Task又分为ShuffleMapTask和ResultTask,咱们离开来讲。 ShuffleMapTaskShuffleMapTask进行写入的时候,有三种形式,别离是UnsafeShuffleWriter、BypassMergeSortShuffleWriter、SortShuffleWriter。而最终应用哪个ShuffleWriter是取决于RDD依赖的ShuffleHandle。如果不须要map端进行合并且分区数小于等于200,则ShuffleHandle为BypassMergeSortShuffleHandle,最终的ShuffleWriter是BypassMergeSortShuffleWriter。如果不须要map端进行合并且分区数<16777216、Serializer反对relocation则ShuffleHandle为SerializedShuffleHandle,最终的ShuffleWriter是UnsafeShuffleWriter。其余状况下,ShuffleHandle为BaseShuffleHandle,最终的ShuffleWriter是SortShuffleWriter。上面就先介绍BypassMergeSortShuffleWriter的写入过程,其余两个留前面讲。 BypassMergeSortShuffleWriter咱们假如有2个分区,这样最终就有2个Task,假如每个Task发给一个Executor,上面看看Executor是怎么解决每个Task中RDD计算的数据。首先Executor会依据分区的数量,创立等同数量的DiskBlockObjectWriter。因为咱们的分区数是2,所以DiskBlockObjectWriter是个数也是2,每一个DiskBlockObjectWriter解决一个分区的数据,最初把map工作的输入写入磁盘。每个DiskBlockObjectWriter都维持着BlockId以及他的文件File。DiskBlockObjectWriter筹备好后,开始迭代RDD计算的后果records,假如第一条是(a,1),应用分区计算器算出a这个key的分区,比方右边的分区0,而后让右边的DiskBlockObjectWriter把(a,1)写入到Shuffle文件的输入流中。同理,(b,1),(c,1),(d,1)也假如都在右边,(e,1),(f,1),(g,1),(h,1)依据key的分区计算,都在左边。records后果都解决完后,DiskBlockObjectWriter就会把输入流中的数据写入到磁盘,文件的信息、索引的地位,都交给FileSegment来解决。此时曾经生成了两个长期的Shuffle文件,为了缩小网络的IO,这些临时文件须要进行合并。所以会把这两个长期的Shuffle文件内容,写入到Shuffle数据文件,并记录每个文件的长度(比方4,4)。写入到Shuffle数据文件后,临时文件就没有用了,就把他们都删除。此时还要一个索引文件,因为咱们把两个文件的内容合并了,须要晓得原先每个文件里有哪些货色,下面咱们不是保留了文件的长度(4,4),所以依据这个失去了索引的值(0,4,8)。这样咱们从文件里拿到对应的数据,就能够通过索引了。 ResultTask如果一个RDD的数据,最终发到3个Executor,每个Executor都只解决一个Task,那最初会有3个dataFile文件。最初执行ResultTask的时候,就会从这些dataFile文件拿出数据,调用函数进行最终的解决,失去最初的后果。

August 11, 2021 · 1 min · jiezi

关于spark:Spark-Task的资源分配

在上一篇中,咱们晓得了每个stage会依据分区数,把数据进行切分,并生成Task,也就是说,有多少个分区数,就有多少个Task,这些task会封装在TaskSet中。咱们持续上篇的流程,从stage0开始。stage0有4个分区,上面是stage0对应的TaskSet 0.0,TaskSet 0.0里有4个Task。TaskSet 0.0提交后,会封装成TaskSetManager,这个TaskSetManager是Schedulable类型的。最初扔到资源池里,这个资源池默认是FIFO,先进先出,所以前面就会依照这个程序来把TaskSetManager取出来。而后让调度后端给Task分配资源并运行Task,以后线程持续往资源池扔TaskSetManager(我这里只画了两个,实际上会把stage2、stage3、stage4顺次扔进来)。调度后端接管到申请后,就会看看本人有哪些资源,如果是local模式,就间接创立一个WorkerOffer,如果是Standalone模式,他就会看看本人有多少个闲暇的Executor,从而创立对应的WorkerOffer个数。如果申请到资源,就会把task封装成TaskDescription,交给Executor去执行。Executor外部也有一个线程池,他收到TaskDescription后,封装成TaskRunner,扔到线程池中。下图中,右边是driver端,左边是Executor端。此时才把数据发到Executor。Executor线程池的线程,解决玩task后,把工作发回到driver端。

August 10, 2021 · 1 min · jiezi

关于spark:Spark-TaskSet提交

stage切分后,就会创立一个Job,所以在一个Application中,如果有多个action算子,那就有多少个Job,每个Job依据shuffle依赖,切分成多个stage。最初生成的这个job会把援用给finalStage,也就是上篇的stage4里。Job生成后,就开始提交stage,咱们以stage切分的流程往下讲。次要是先找到未提交的stage,而后依据stage的分区数生成对应的task个数,封装到TaskSet进行提交。这个流程和切分有点相似,都是从左边往左边寻找。 stage4首先拿到的是最左边的stage4,会把stage4.rddz(这里就是RDD11)压入waitingForVisit栈中,这个waitingForVisit栈就是寄存窄依赖的,而后通过窄依赖的依赖去查找shuffle依赖。此外还有两个数据结构,missing汇合,用来寄存未提交的stage,visited汇合,用来寄存曾经遍历过的RDD。此时waitingForVisit栈中曾经有RDD,就会把RDD[11]拿进去,RDD[11]是没有遍历过的,所以会放入visited汇合,另外RDD[11]的依赖RDD[10]是窄依赖,所以RDD[10]就会压入waitingForVisit栈中。waitingForVisit栈发现还有RDD,就会把RDD[10]拿进去,RDD[10]是没有遍历过的,所以会放入visited汇合,另外RDD[10]的依赖RDD[9]是窄依赖,所以RDD[9]就会压入waitingForVisit栈中。waitingForVisit栈发现还有RDD,就会把RDD[9]拿进去,RDD[9]是没有遍历过的,所以会放入visited汇合,另外RDD[9]的依赖RDD[4]、RDD[8]是shuffle依赖,所以stage3、state0会放入missing汇合。waitingForVisit栈曾经为空了,missing汇合不为空,所以持续从stage3、state0持续下面stage4的操作。 stage0stage0的rdd,即RDD8压入waitingForVisit栈中。此时waitingForVisit栈中曾经有RDD,就会把RDD[8]拿进去,RDD[8]是没有遍历过的,所以会放入visited汇合,另外RDD[8]的依赖RDD[6]、RDD[7]是窄依赖,所以RDD[6]、RDD[7]就会压入waitingForVisit栈中。waitingForVisit栈发现还有RDD,就会把RDD[7]拿进去,RDD[7]是没有遍历过的,所以会放入visited汇合,另外RDD[7]没有任何依赖,于是不做解决。waitingForVisit栈发现还有RDD,就会把RDD[6]拿进去,RDD[6]是没有遍历过的,所以会放入visited汇合,另外RDD[6]的依赖RDD[5]是窄依赖,所以RDD[5]就会压入waitingForVisit栈中。waitingForVisit栈发现还有RDD,就会把RDD[5]拿进去,RDD[5]是没有遍历过的,所以会放入visited汇合,另外RDD[5]没有任何依赖,于是不做解决。waitingForVisit栈曾经为空了,这次RDD[8]并没有任何shuffle依赖,于是开始创立TaskSet。stage0的分区数是4,所以会把数据存入4个Task,stage0是ShuffleMapStage,所以这个Task就是ShuffleMapTask,最初把Task汇合封装在TaskSet中,交给TaskSchedulerImpl解决。 stage3stage0解决完后,就开始解决stage3,把RDD4压入waitingForVisit栈中。此时waitingForVisit栈中曾经有RDD,就会把RDD[4]拿进去,RDD[4]是没有遍历过的,所以会放入visited汇合,另外RDD[8]的依赖RDD[3]是窄依赖,所以RDD[3]就会压入waitingForVisit栈中。waitingForVisit栈发现还有RDD,就会把RDD[3]拿进去,RDD[3]是没有遍历过的,所以会放入visited汇合,另外RDD[3]的依赖RDD[2]是窄依赖,所以RDD[2]就会压入waitingForVisit栈中。waitingForVisit栈发现还有RDD,就会把RDD[2]拿进去,RDD[2]是没有遍历过的,所以会放入visited汇合,另外RDD[2]的依赖RDD[1]、RDD[0]是shuffle依赖,所以stage1、state2会放入missing汇合。waitingForVisit栈曾经为空了,并且stage1、state2并没有任何shuffle依赖,于是开始创立TaskSet。stage1、state2的分区数是2,所以会把数据存入2个Task,stage1、state2是ShuffleMapStage,所以这两个stage的Task都是ShuffleMapTask,最初把Task汇合封装在TaskSet中,交给TaskSchedulerImpl解决。此时最右边的三个stage都曾经封装好TaskSet,TaskSet的提交工作完结。

August 9, 2021 · 1 min · jiezi

关于spark:Spark-stage切分

本文以宽依赖和窄依赖的例子来解说stage切分的过程,这里跟之前不一样的是,join操作是宽依赖。为了看的更不便一些,咱们把上一篇的最终的图片简化一下,能够看到多了4个灰色的RDD,这是因为有些转换,比方join,外面还有做一些其余的转换操作。数据的流程是右边到左边的,stage的切分流程是相同的,是从左边到右边。次要的操作是从左边往左边走,碰到shuffle依赖后,就会把他当做本人的stage的父节点。stage的父节点也会往左边,看看有没有shuffle依赖,反复着下面的过程,直至所有RDD都走完。这样说有些形象,上面用图形一步步解说stage切分的全过程。 RDD[11]首先拿到的是最左边的RDD[11],会把RDD[11]压入waitingForVisit栈中,这个waitingForVisit栈就是寄存窄依赖的,而后通过窄依赖的依赖去查找shuffle依赖。此外还有两个数据结构,parents汇合,用来寄存shuffle依赖,visited汇合,用来寄存曾经遍历过的RDD。此时waitingForVisit栈中曾经有RDD,就会把RDD[11]拿进去,RDD[11]是没有遍历过的,所以会放入visited汇合,另外RDD[11]的依赖RDD[10]是窄依赖,所以RDD[10]就会压入waitingForVisit栈中。waitingForVisit栈发现还有RDD,就会把RDD[10]拿进去,RDD[10]是没有遍历过的,所以会放入visited汇合,另外RDD[10]的依赖RDD[9]是窄依赖,所以RDD[9]就会压入waitingForVisit栈中。waitingForVisit栈发现还有RDD,就会把RDD[9]拿进去,RDD[9]是没有遍历过的,所以会放入visited汇合,另外RDD[9]的依赖RDD[4]、RDD[8]是shuffle依赖,所以RDD[4]、RDD[8]会放入parents汇合。waitingForVisit栈曾经为空了,所以就能够开始创立stage。这个stage是左边的,所以还要看看他是否有父节点,也就是是否还有shuffle依赖,这个查找的过程,跟下面一样。 RDD[8]RDD[11]中的shuffle依赖RDD[8]压入waitingForVisit栈中。此时waitingForVisit栈中曾经有RDD,就会把RDD[8]拿进去,RDD[8]是没有遍历过的,所以会放入visited汇合,另外RDD[8]的依赖RDD[6]、RDD[7]是窄依赖,所以RDD[6]、RDD[7]就会压入waitingForVisit栈中。waitingForVisit栈发现还有RDD,就会把RDD[7]拿进去,RDD[7]是没有遍历过的,所以会放入visited汇合,另外RDD[7]没有任何依赖,于是不做解决。waitingForVisit栈发现还有RDD,就会把RDD[6]拿进去,RDD[6]是没有遍历过的,所以会放入visited汇合,另外RDD[6]的依赖RDD[5]是窄依赖,所以RDD[5]就会压入waitingForVisit栈中。waitingForVisit栈发现还有RDD,就会把RDD[5]拿进去,RDD[5]是没有遍历过的,所以会放入visited汇合,另外RDD[5]没有任何依赖,于是不做解决。waitingForVisit栈曾经为空了,这次RDD[8]并没有任何shuffle依赖,于是间接创立id为0的stage0。 RDD[4]RDD[11]中的shuffle依赖RDD[8]曾经解决了,而后shuffle依赖RDD[4]压入waitingForVisit栈中。此时waitingForVisit栈中曾经有RDD,就会把RDD[4]拿进去,RDD[4]是没有遍历过的,所以会放入visited汇合,另外RDD[8]的依赖RDD[3]是窄依赖,所以RDD[3]就会压入waitingForVisit栈中。waitingForVisit栈发现还有RDD,就会把RDD[3]拿进去,RDD[3]是没有遍历过的,所以会放入visited汇合,另外RDD[3]的依赖RDD[2]是窄依赖,所以RDD[2]就会压入waitingForVisit栈中。waitingForVisit栈发现还有RDD,就会把RDD[2]拿进去,RDD[2]是没有遍历过的,所以会放入visited汇合,另外RDD[2]的依赖RDD[1]、RDD[0]是shuffle依赖,所以RDD[1]、RDD[0]会放入parents汇合。waitingForVisit栈曾经为空了,所以又开始创立stage了。因为RDD[1]、RDD[0]没有父节点,于是就间接id为1、2的stage1和stage2。而后咱们回到RDD[4],为RDD[4]创立stage,因为他shuffle依赖为stage1和stage2,所以RDD[4]创立了一个id为3,父节点为stage1和stage2的stage3。 RDD[11]咱们再回到RDD[11],此时他的shuffle依赖RDD[4]和RDD[8]都曾经创立好了stage,所以RDD[11]创立了一个id为4,父节点为stage3和stage0的stage4。至此,stage创立实现。

August 8, 2021 · 1 min · jiezi

关于spark:Spark-宽依赖和窄依赖

后面Standalone模式下的Master对资源的调度,是第一层调度。为了前面第二层调度解说,这里先用一个例子作为铺垫,也顺便讲一下宽依赖和窄依赖。所波及的RDD应用之前曾经讲过了,这里不做赘述。 join这里有两个RDD,分区都是2,通过join转换为rdd3,为了更直观的看出每个数据在哪个分区,上面都通过p+数字的模式打印进去。 val sc = new SparkContext(new SparkConf().setAppName("MixRDD").setMaster("local"))sc.setLogLevel("ERROR")val rdd1: RDD[(String, Int)] = sc.parallelize(List(("a", 1), ("b", 1), ("c", 1), ("d", 1)), 2)val rdd2: RDD[(String, Int)] = sc.parallelize(List(("a", 2), ("d", 2), ("e", 2), ("f", 2)), 2)val rdd3: RDD[(String, (Int, Int))] = rdd1.join(rdd2)// rdd1:ArrayBuffer((a,1), (b,1), (c,1), (d,1))println("rdd1:" + rdd1.collect().toBuffer)// rdd2:ArrayBuffer((a,2), (d,2), (e,2), (f,2))println("rdd2:" + rdd2.collect().toBuffer)// rdd3:ArrayBuffer((d,(1,2)), (a,(1,2)))println("rdd3:" + rdd3.collect().toBuffer)val p1: RDD[String] = rdd1.mapPartitionsWithIndex(f1)val p2: RDD[String] = rdd2.mapPartitionsWithIndex(f1)val p3: RDD[String] = rdd3.mapPartitionsWithIndex(f2)// p1:ArrayBuffer(a:0, b:0, c:1, d:1)println("p1:" + p1.collect().toBuffer)// p2:ArrayBuffer(a:0, d:0, e:1, f:1)println("p2:" + p2.collect().toBuffer)// p3:ArrayBuffer(d:0, a:1)println("p3:" + p3.collect().toBuffer)下面的代码的流程图如下,能够看到RDD1的分区0连着RDD3的分区1,RDD1的分区1连着RDD2的分区0(图例没有分区数字,从上到下递增,0开始),RDD2同理。RDD1的每个分区都只有一个“儿子”,也就是说RDD1的每个分区仅被一个RDD3的一个分区依赖,这样咱们能够称为窄依赖。 ...

August 8, 2021 · 2 min · jiezi

关于spark:Spark-Worker退出怎么办

如果是被动退出,那Worker在退出之前,这里叫worker_1,会杀死本人每个Executor过程。Executor异样退出的流程之前曾经讲过了。咱们在Master和Worker晓得,Worker会定期的向Master发送心跳,如果worker_1退出,那咱们就能够心跳信息中就能够发现,超过60秒没有心跳的Worker此时可能异样退出了,所以就会把这个worker_1的状态改为DEAD,并把他从缓存中移除。从worker_1中获取对应的Executor对应的Application,告知这些Application,你的Executor不能用了。而后把ApplicationInfo中对应的Executor移除掉,ApplicationInfo移除Executor时,会记录被移除的Executor,把Executor从executors中移除,并且把申请到的CPU资源扣减回去。如果worker_1下面有运行着Driver,那就会把内存中的DriverInfo信息和长久化引擎的DriverInfo信息移除。从新创立一个Driver信息,保留内存中,并进行长久化。最初进行资源调度,从新在worker上调配driver和Executor。

August 6, 2021 · 1 min · jiezi

关于spark:Spark-Executor异常退出怎么办

当Worker创立Executor的时候,会启动一个线程来创立这个Executor,并且期待获取Executor过程的退出状态。如果Executor异样退出,这个线程就会晓得,而后就会发信息告知Worker。Worker收到音讯后,就会把这个音讯转发给Master。这个音讯会携带Application的ID和Executor的ID。Master收到音讯后,就会依据Application的ID和Executor的ID找到Master内存中Application和Executor信息,并告知Application。而后把ApplicationInfo中对应的Executor以及WorkerInfo对应的Executor移除掉。ApplicationInfo移除Executor时,会记录被移除的Executor,把Executor从executors中移除,并且把申请到的CPU资源扣减回去。WorkerInfo移除Executor时,会把Executor占用的CPU、内存资源扣减回去。因为Executor曾经退出,以及Master保留的申请的资源也还原,所以Master会从新给Application进行资源调度。

August 6, 2021 · 1 min · jiezi

关于spark:Spark-Standalone部署模式下Application执行完了怎么办

在后面的文章中曾经晓得,Application既占用了Master的资源,也占用Worker里的Executor资源。当Application运行完后这些资源是都要开释的。 进行ExecutorApplication首先会从内存中,拿出调配给以后Application的Executors信息,通过Executor的RpcEndpointRef,给每个Executor发送RPC申请,让他们进行Executor,Executor收到申请后,就会进行以后的Executor(字体红色标识)。 开释DriverExecutor进行后,Driver就没用了,所以这里进行DriverEndpoint。 勾销注册ApplicationApplication向Master发送申请,要求勾销以后的Application。Master收到申请后,就把内存中对于Application的局部进行变更,而后给相应的Worker发送音讯,音讯包含Executor的ID,要求杀死Executor相干内容。而后再从长久化中移除Application。Worker收到杀死Executor的申请,依据Master提供的Executor的ID,找到对应的Executor,把过程杀死。 开释ClientEndpointApplication注册勾销后,ClientEndpoint就没用了,所以这里进行ClientEndpoint。 异样退出如果是异样退出,Master会监听客户端与以后节点的连贯断开,而后会被动的执行下面勾销注册Application的操作,并且会告诉Application,告知你曾经被Master移除了,而后Application收到音讯就会进行ClientEndpoint。

August 6, 2021 · 1 min · jiezi

关于spark:Spark-Standalone部署模式

Standalone部署模式有两种,一个是client模式,一个是cluster模式,其中client模式是默认的。 client某个能够连Spark集群的服务器,通过spark-submit的shell脚本,启动SparkSubmit的时候,就会创立一个Application。这个Application里会有ClientEndpoint和集群管理器进行对话,还有一个DriverEndpoint,用于Worker的Executor进行对话,所以咱们这个Application是和SparkSubmit同一个过程的。 clustercluster也是某个能够连Spark集群的服务器,通过spark-submit的shell脚本,启动SparkSubmit的时候,会创立一个与Master通信的RPC服务。这个RPC服务,就是向Master申请Driver资源。Master收到申请Driver的申请后,就会创立一个Driver信息,保留在内存中,并把Driver长久化,便于故障转移复原。Master发现此时有个Worker的CPU和内存,够启动Driver,于是让发信息给这个Worker让他去启动,并且回复给SparkSubmit说曾经创立好Driver了,并且把driverId给SparkSubmit。SparkSubmit5秒后,会那着这个driverId去验证一下是否无效,如果有效,则敞开以后过程。Worker收到信息后,就会下载用户指定的Jar文件,通过这个jar文件开启一个过程,创立Driver,这个Driver会依据反射,启动Application。前面的流程就跟下面client一样了,Application里会有ClientEndpoint和集群管理器进行对话,还有一个DriverEndpoint,用于Worker的Executor进行对话。所以client和cluster的区别是,clien的Application是间接在提交程序的过程里,而cluster是在worker的某个过程里。 源码思维导图SparkSubmitSparkSubmit音讯master-解决音讯Worker-解决信息

August 5, 2021 · 1 min · jiezi

关于spark:Spark-Leader选举

流程Leader选举模式包含ZOOKEEPER、基于文件系统的、默认空实现以及自定义实现的,选举模式和长久化引擎是对应的。 长久化引擎Leader选举模式基于文件系统MonarchyLeaderAgent基于ZooKeeperZooKeeperLeaderElectionAgent空实现MonarchyLeaderAgentMonarchyLeaderAgent是服务启动的时候,就间接成为Leader节点,而ZooKeeperLeaderElectionAgent是基于ZooKeeper的Leader来选举的。 拉取数据当成为Leader节点的时候,Master就会去长久化引擎里拉取ApplicationInfo、DriverInfo、WorkerInfo等信息(拉取的过程在长久化引擎里说过了),如果这些数据都是空的,就间接变成ALIVE状态,对外提供服务。如果不是空的,那就须要把数据进行还原,这样原ALIVE节点的数据就不会失落。 复原ApplicationMaster拿到ApplicationInfo数据后,就开始对Application进行注册,把Application的状态改为UNKNOWN,而后发消息给对应的Application,告知他Master地址曾经变更,此音讯将携带被选举为领导的Master和此Master的masterWebUiUrl属性。Application接管到新的Master的告诉,就断开了和旧的Master的连贯,并指向新的master,而后发信息给Master说我曾经晓得了。Master收到音讯后,把Application的状态改为WAITING。 复原Driver遍历从长久化引擎中读取的DriverInfo,将每个DriverInfo增加到drivers缓存。 复原WorkerMaster拿到WorkerInfo数据后,就开始对Worker进行注册,把WorkerInfo的状态改为UNKNOWN,而后发消息给对应的Application,告知他Master地址曾经变更,此音讯将携带被选举为领导的Master和此Master的masterWebUiUrl属性。Worker接管到新的Master的告诉,把Master的相干信息进行了变更,而后发消息给Master,这个音讯携带了Worker的ID、这个Worker里的Executor的信息列表。Master收到音讯后,对Worker和Executor的信息进行了复原,并把WorkerInfo的状态改为ALIVE。 调度Application和Worker复原的时候,都会先把状态改为UNKNOWN。等Application响应的时候,再把状态改为WAITING或者ALIVE。此时如果状态为UNKNOWN的WorkerInfo或ApplicationInfo阐明还没发消息给Master,Master不确定他们是否存活,所以在调度之前就须要移除他们。对Application、Driver、Worker等信息进行复原后,就开启了资源调度。资源调度之前曾经讲过,这里就不再累述。

August 5, 2021 · 1 min · jiezi

关于spark:Spark-持久化引擎

分布式高可用集群装置是Standalone集群,这里会有两个master,一个是ALIVE,一个是STANDBY。ALIVE节点是提供服务的,STANDBY是备胎,当ALIVE节点挂了当前,STANDBY会顶替成为新的ALIVE。咱们晓得Worker和Application等数据,都会存在内存中,但只是存在内存中,当旧的ALIVE节点挂了当前,数据就丢了,新的ALIVE节点接替整个集群的管理工作时,没有能力从故障中复原整个集群的状态信息,进而复原对集群资源的治理和调配。所以就须要一个长久化引擎,把集群的Worker、Driver和Application的信息长久化,当新的ALIVE节点接替整个集群后,就能够从长久化拿数据对集群状态进行复原。长久化引擎有四个,包含用于用于单元测试的、空实现的(也就是没有长久化)、基于文件系统的长久化引擎、基于ZooKeeper的长久化引擎。 基于文件系统的长久化引擎FileSystemPersistenceEngine,即基于文件系统的长久化引擎。因为Master可能在不同的服务器中,所以这里要求文件系统是分布式的。咱们以对WorkerInfo的操作为例。当咱们想对worker_1进行长久化的时候,FileSystemPersistenceEngine就会创立一个叫做worker_1的文件,而后关上文件输入流,并对数据进行序列化后写入磁盘的。当咱们想对worker_2,worker_3进行长久化的时候,流程和下面一样,这样就有了三个文件,别离为worker_1,worker_2,worker_3。当咱们想对worker_3进行移除长久化的时候,其实就是删除worker_3的文件。当咱们想读取长久化里的信息的时候,就会把worker_1,worker_2文件里的数据读取进去,并进行反序列化(理论还包含app_和driver_,这里略)。 基于ZooKeeper的长久化引擎ZooKeeperPersistenceEngine,即基于ZooKeeper的长久化引擎。咱们还是以对WorkerInfo的操作为例。当咱们想对worker_1进行长久化的时候,ZooKeeperPersistenceEngine就会在/spark/master_status上面创立worker_1的长久化节点(伪装上面的是树形构造)。当咱们想对worker_2,worker_3进行长久化的时候,流程和下面一样,这样就有了三个节点,别离为worker_1,worker_2,worker_3。当咱们想对worker_3进行移除长久化的时候,其实就是删除worker_3的节点。当咱们想读取长久化里的信息的时候,就会把worker_1,worker_2节点里的数据读取进去,并进行反序列化(实际上还包含/spark/master_status节点下的其余数据)

August 4, 2021 · 1 min · jiezi

关于spark:Spark-Executor的运行

在Executor的资源调度曾经提到了Worker上怎么调配Executor资源的过程,这里就讲Worker调配到Executor后是怎么运行这些Executor的。 流程在调用Worker启动Executor之前,Master须要更新内存中Application的信息,包含启动一个Executor的各种信息(这里包含Worker的信息、CPU数量、内存大小等)、曾经调配了多少外围数。被调配的Worker也要更新他所启动的Executor,曾经应用的CPU数量、曾经应用的内存大小。Master筹备好内存数据变更后,就开始告诉Worker启动Executor,向Worker发送的音讯包含masterUrl、Application的ID、Executor的ID、Application的形容信息ApplicationDescription、Executor调配取得的内核数、Executor调配取得的内存大小等。Master同时也给Application Driver发送音讯,告知Worker上的executor曾经启动,Application Driver收到音讯后,打印日志。Worker收到Master发送过去的启动Executor的命令后,封装了Master传过来的信息,保留在内存中,并启动了一个Executor的过程,这个过程用来Driver与Executor通信。Executor过程启动后,更新曾经应用的内核数coresUsed和曾经应用的内存大小memoryUsed。Executor的过程启动后,会向DriverEndpoint申请数据,包含Spark属性信息和密钥,Executor拿到这些数据后,就开始创立本人的RPC服务,用于通信。Executor筹备好后,开始向DriverEndpoint发送注册申请。DriverEndpoint收到申请后,把Executor的数据保留在内存中,而后再发消息给Executor,告知曾经解决好注册信息。Executor晓得本人注册胜利后,就创立了一个Executor对象。 源码思维导图master-资源调度Worker-解决信息DriverEndpoint音讯解决CoarseGrainedExecutorBackendCoarseGrainedExecutorBackend音讯

August 4, 2021 · 1 min · jiezi

关于spark:Spark-Executor的资源调度

Master的资源调度是Spark的一级资源调度,分为对Driver的资源调度和对Executor的资源调度。这篇次要是讲Executor的资源调度。咱们假如初始条件是这样的:曾经5个Worker注册到Master,别离是4核16G(Dead),1核0.5G,4核4G,2核8G,4核8G。(这里的4核阐明的是残余的CPU核数,并不是服务器配置)有2个Application注册到Master,队列第一个的Application的要求是,每个Executor要求1核1G,须要的总内核数是5。 流程在开始调配的时候,就会过滤一下这些Worker,比方状态为Dead的,或者CPU内存不满足Application要求的1核1G,这些Worker都不能用。过滤后剩下的Worker再依照闲暇内核数倒序排列(排序是因为能够优先将利用调配给内核资源短缺的Worker),所以过滤并排序后如下:排序后会建两个数组,一个是assignedCores记录每个Worker给Application调配的内核数的数组,另外一个是assignedExecutors记录每个Worker给利用调配的Executor数的数组,所以两个数组的长度就是筛选后的Worker的个数,这里两个数组的长度都为3。这里调配的计划有两个,默认的是容许Application可能在所有节点间调度,会顺次从Worker上拿资源。 计划一步骤1:Worker1调配1核1G进去,所以assignedCores对应Worker1的地位赋值为1,assignedExecutors对应Worker1的地位赋值为1,阐明Worker1曾经被调配1核1G。同时Application的total改完4,阐明还须要4个内核。步骤2:Worker2调配1核1G进去,所以assignedCores对应Worker2的地位赋值为1,assignedExecutors对应Worker2的地位赋值为1,阐明Worker2曾经被调配1核1G。同时Application的total改完3,阐明还须要3个内核。步骤3:Worker3调配1核1G进去,所以assignedCores对应Worker3的地位赋值为1,assignedExecutors对应Worker3的地位赋值为1,阐明Worker3曾经被调配1核1G。同时Application的total改完2,阐明还须要2个内核。步骤4:Worker1调配1核1G进去,所以assignedCores对应Worker1的地位赋值为2,assignedExecutors对应Worker1的地位赋值为2,阐明Worker1曾经被调配2核2G。同时Application的total改完1,阐明还须要1个内核。步骤5:Worker2调配1核1G进去,所以assignedCores对应Worker2的地位赋值为2,assignedExecutors对应Worker2的地位赋值为2,阐明Worker2曾经被调配2核2G。同时Application的total改完0,阐明调配完结。 计划2这个计划,就是使劲的往一个Worker上褥羊毛,直到他资源耗尽,才会换一个。步骤1:Worker1调配1核1G进去,所以assignedCores对应Worker1的地位赋值为1,assignedExecutors对应Worker1的地位赋值为1,阐明Worker1曾经被调配1核1G。同时Application的total改完4,阐明还须要4个内核。步骤2:Worker1调配1核1G进去,所以assignedCores对应Worker1的地位赋值为2,assignedExecutors对应Worker1的地位赋值为2,阐明Worker1曾经被调配2核2G。同时Application的total改完3,阐明还须要3个内核。步骤3:Worker1调配1核1G进去,所以assignedCores对应Worker1的地位赋值为3,assignedExecutors对应Worker1的地位赋值为3,阐明Worker1曾经被调配3核3G。同时Application的total改完2,阐明还须要2个内核。步骤4:Worker1调配1核1G进去,所以assignedCores对应Worker1的地位赋值为4,assignedExecutors对应Worker1的地位赋值为4,阐明Worker1曾经被调配4核4G。同时Application的total改完1,阐明还须要1个内核。步骤5:此时Worker1的CPU和内存曾经不满要求了,所以开始往Worker2要资源。Worker2调配1核1G进去,所以assignedCores对应Worker2的地位赋值为1,assignedExecutors对应Worker2的地位赋值为1,阐明Worker2曾经被调配1核1G。同时Application的total改完0,阐明调配完结。 源码思维导图master-资源调度

August 3, 2021 · 1 min · jiezi

关于spark:Spark-Application注册

Spark Submit应用中提到了在standalone模式下,通过spark-submit提交集群中的应用程序的案例,这里就讲讲这个应用程序的注册到集群的过程。这里须要引入两个角色,Driver和Executor。Driver是客户端驱动程序,用于将工作程序转换为RDD和DAG,并与Cluster Manager进行通信与调度。本章次要是与Cluster Manager进行通信与调度。Executor:执行计算工作的一些过程。次要负责工作的执行以及与Worker、Driver Application的信息同步。 流程Application启动的时候,会创立一个和集群管理器进行对话的客户端,叫做StandaloneAppClient,这个StandaloneAppClient里寄存了很多信息,比方Master地址信息,以后Application的名称、须要的最大CPU外围数、每个Executor须要的内存等信息。因为须要和集群管理器进行通信,所以StandaloneAppClient还有一个组件,叫做ClientEndpoint。当Application启动的时候,ClientEndpoint组件就开始尝试向Master进行注册,并提供本人Application的相干信息,这样Master就能将Worker上的资源及Executor调配给Driver。Master接管到注册信息,就会把Application的信息存在内存中,同时把这个Application放入到期待调度的队列里,等到资源进行调度。Master解决完后,就会发信息给ClientEndpoint,告知曾经注册胜利,ClientEndpoint收到Master信息后,就标记本人曾经注册胜利。除了ClientEndpoint用来和集群管理器进行对话,Application还定义了另外一个组件DriverEndpoint,用来和其余组件通信进行通信,比方Task状态更新、注册Executor等,这些留着后文来讲。 源码思维导图StandaloneSchedulerBackendClientEndpoint音讯解决DriverEndpoint音讯解决master-解决音讯

August 2, 2021 · 1 min · jiezi

关于spark:Spark-Master和Worker

之前在分布式高可用集群装置中,能够看到这个集群是主从架构,在Spark集群形式中,叫做Standalone集群。主节点叫做Master,Master除了对Worker、Application、Driver等治理外,还要负责对整个集群中所有资源的对立治理和调配。这篇次要还是讲对Worker的治理。Worker是工作节点,他会把本身的资源信息,比方CPU、内存大小等提供给Master,由Master对Worker的资源进行调度。 流程集群启动的时候,只有Master节点,为了可能对各个Worker进行治理,Worker启动的时候须要向Master进行注册,把本人的信息,包含Ip信息、端口、CPU、内存大小等,注册到Master,这样Master就能够晓得这个Worker的具体情况。Master接管到Worker的注册申请后,就会把Worker的信息放入内存中,便于资源的调配以及调度,并且为了容灾思考,把Worker的信息进行了长久化,这样新选举进去的Master可能从长久化中读取Worker的数据,而不必放心上一个Master节点中的内存数据失落。Master解决完Worker申请后,就会发信息告知Worker曾经注册,Worker就会把Master的信息保留在内存中。为了保障Master晓得本人是存活的,于是worker每隔15秒开始发送心跳给Master。这个Master的信息就是下面一步保留在内存的信息。Master收到心跳信息后,就会更新Worker的最初心跳工夫。除了Worker被动发送心跳告知Master本人的状态是存活的,Master也会每隔60秒去查看内存中Worker的汇合,把最初心跳工夫超过60秒的筛选进去,把这些Worker从内存以及长久化中移除。 源码思维导图master启动worker启动并注册到mastermaster-解决音讯Worker-解决信息

August 1, 2021 · 1 min · jiezi

关于spark:编译支持-spark-读写-osscdh-5x

前言背景:应用 spark 读取 hdfs 文件写入到 osshadoop : 2.6.0-cdh5.15.1spark : 2.4.1次要参考链接:https://blog.csdn.net/wankund...减少了留神点和坑点编译 hadoop-aliyunhadoop 高版本曾经默认反对 aliyun-oss 的拜访,而本版本不反对,须要编译反对下拉取 hadoop trunk 分支代码,copy hadoop-tools/hadoop-aliyun 模块代码到 cdh 对应的我的项目模块中批改 hadoop-tools pom.xml <module>hadoop-aliyun</module> 增加 hadoop-aliyun 子 module批改根 pom.xml 中的 java 版本为 1.8,hadoop-aliyun 应用了 1.8 的 lambda 语法,也能够间接批改代码反对批改 hadoop-aliyun pom.xml,批改 version,以及相干的 oss,http 依赖包,应用 shade 插件将相干依赖打进去代码批改 import org.apache.commons.lang3 改为 import org.apache.commons.lang复制(cdh版本) hadoop-aws 模块下的 BlockingThreadPoolExecutorService 和 SemaphoredDelegatingExecutor 两个类 到 org.apache.hadoop.util 目录下编译模块 hadoop-aliyun mvn clean package -pl hadoop-tools/hadoop-aliyun最终的配置文件如下 <?xml version="1.0" encoding="UTF-8"?><!-- Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. See accompanying LICENSE file.--><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-project</artifactId> <version>2.6.0-cdh5.15.1</version> <relativePath>../../hadoop-project</relativePath> </parent> <artifactId>hadoop-aliyun</artifactId> <name>Apache Hadoop Aliyun OSS support</name> <packaging>jar</packaging> <properties> <file.encoding>UTF-8</file.encoding> <downloadSources>true</downloadSources> </properties> <profiles> <profile> <id>tests-off</id> <activation> <file> <missing>src/test/resources/auth-keys.xml</missing> </file> </activation> <properties> <maven.test.skip>true</maven.test.skip> </properties> </profile> <profile> <id>tests-on</id> <activation> <file> <exists>src/test/resources/auth-keys.xml</exists> </file> </activation> <properties> <maven.test.skip>false</maven.test.skip> </properties> </profile> </profiles> <build> <plugins> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>findbugs-maven-plugin</artifactId> <configuration> <findbugsXmlOutput>true</findbugsXmlOutput> <xmlOutput>true</xmlOutput> <excludeFilterFile>${basedir}/dev-support/findbugs-exclude.xml </excludeFilterFile> <effort>Max</effort> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <forkedProcessTimeoutInSeconds>3600</forkedProcessTimeoutInSeconds> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-dependency-plugin</artifactId> <executions> <execution> <id>deplist</id> <phase>compile</phase> <goals> <goal>list</goal> </goals> <configuration> <!-- build a shellprofile --> <outputFile> ${project.basedir}/target/hadoop-tools-deps/${project.artifactId}.tools-optional.txt </outputFile> </configuration> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>3.1.0</version> <executions> <execution> <id>shade-aliyun-sdk-oss</id> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <shadedArtifactAttached>false</shadedArtifactAttached> <promoteTransitiveDependencies>true</promoteTransitiveDependencies> <createDependencyReducedPom>true</createDependencyReducedPom> <createSourcesJar>true</createSourcesJar> <relocations> <relocation> <pattern>org.apache.http</pattern> <shadedPattern>com.xxx.thirdparty.org.apache.http</shadedPattern> </relocation> </relocations> </configuration> </execution> </executions> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>com.aliyun.oss</groupId> <artifactId>aliyun-sdk-oss</artifactId> <version>3.4.1</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.4.1</version> </dependency> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpcore</artifactId> <version>4.4.1</version> </dependency> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-common</artifactId> <exclusions> <exclusion> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> </exclusion> <exclusion> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpcore</artifactId> </exclusion> </exclusions> <scope>provided</scope> </dependency> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-common</artifactId> <scope>test</scope> <type>test-jar</type> </dependency> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-distcp</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-distcp</artifactId> <scope>test</scope> <type>test-jar</type> </dependency> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-yarn-server-tests</artifactId> <scope>test</scope> <type>test-jar</type> </dependency> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-mapreduce-client-jobclient</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.hadoop</groupId> <artifactId>hadoop-mapreduce-examples</artifactId> <scope>test</scope> <type>jar</type> </dependency> </dependencies></project>spark 读写取 oss 文件val inputPath = "hdfs:///xxx"val outputPath = "oss://bucket/OSS_FILES"val conf = new SparkConf() conf.set("spark.hadoop.fs.oss.endpoint", "oss-cn-xxx") conf.set("spark.hadoop.fs.oss.accessKeyId", "xxx") conf.set("spark.hadoop.fs.oss.accessKeySecret", "xxx") conf.set("spark.hadoop.fs.oss.impl", "org.apache.hadoop.fs.aliyun.oss.AliyunOSSFileSystem") conf.set("spark.hadoop.fs.oss.buffer.dir", "/tmp/oss") conf.set("spark.hadoop.fs.oss.connection.secure.enabled", "false") conf.set("spark.hadoop.fs.oss.connection.maximum", "2048") spark.write.format("orc").mode("overwrite").save(outputPath)其它以 spark sql 以及 hdfs 读取 oss 的形式能够参考前面的第三个链接spark submitspark-submit \--class org.example.HdfsToOSS \--master yarn \--deploy-mode cluster \--num-executors 2 \--executor-cores 2 \--executor-memory 3G \--driver-cores 1 \--driver-memory 3G \--conf "spark.driver.extraClassPath=hadoop-common-2.6.0-cdh5.15.1.jar" \--conf "spark.executor.extraClassPath=hadoop-common-2.6.0-cdh5.15.1.jar" \--jars ./hadoop-aliyun-2.6.0-cdh5.15.1.jar,./hadoop-common-2.6.0-cdh5.15.1.jar \./spark-2.4-worker-1.0-SNAPSHOT.jar留神下 extraClassPath 这个参数,如果没有非凡的配置,spark 会默认加载本身的 hadoop-common 包,如果版本不对,可能会导致 ClassNotFound,须要 extraClassPath 指定,会优先加载满腹经纶,如果有谬误的中央,欢送斧正 ...

July 25, 2021 · 2 min · jiezi

关于spark:Spark-开源新特性Catalyst-优化流程裁剪

摘要:为了解决过多依赖 Hive 的问题, SparkSQL 应用了一个新的 SQL 优化器代替 Hive 中的优化器, 这个优化器就是 Catalyst。本文分享自华为云社区《Spark 开源新个性:Catalyst 优化流程裁剪》,作者:hzjturbo 。 1. 问题背景 上图是典型的Spark Catalyst优化器的布局,一条由用户输出的SQL,到实在可调度执行的RDD DAG工作,须要经验以下五个阶段: Parser: 将SQL解析成相应的形象语法树(AST),spark也称为 Unresolved Logical Plan;Analyzer: 通过查找Metadata的Catalog信息,将 Unresolved Logical Plan 变为 Resolved Logical Plan,这个过程会做表、列、数据类型等做校验;Optimizer: 逻辑优化流程,通过一些优化规定对匹配上的Plan做转换,失去优化后的逻辑PlanPlanner:依据Optimized Logical Plan的统计信息等转换成相应的Physical PlanQuery Execution: 次要是执行前的一些preparations优化,比方AQE, Exchange Reuse, CodeGen stages合并等上述的五个阶段中,除了Parser (由Antlr实现),其余的每个阶段都是由一个个规定(Rule)形成,总共大概有200+个,对于不同的规定,还可能须要跑屡次,所以对于绝对比较复杂的查问,可能失去一个executed Plan都须要消耗数秒。 Databricks外部基准测试表明,对于TPC-DS查问,每个查问均匀调用树转换函数约280k次,这远远超出了必要的范畴。因而,咱们摸索在每个树节点中嵌入BitSet,以传递本身及其子树的信息,并利用打算不变性来修剪不必要的遍历。通过原型实现验证:在TPC-DS基准测试中,咱们看到优化的速度约为50%,剖析的速度约为30%,整个查问编译的速度约为34%(包含Hive元存储RPC和文件列表)[1]。 2. 设计实现2.1 Tree Pattern Bits and Rule Id BitsTree pattern bits在TreeNode 减少nodePatterns属性,所有继承该类的节点能够通过复写该属性值来标识本人的属性。 /** * @return a sequence of tree pattern enums in a TreeNode T. It does not include propagated * patterns in the subtree of T. */protected val nodePatterns: Seq[TreePattern] = Seq()TreePattern 是一个枚举类型, 对于每个节点/表达式都能够为其设置一个TreePattern不便标识,具体可见 TreePatterns.scala 。 ...

July 23, 2021 · 3 min · jiezi

关于spark:Spark-各个组件的RPC是怎么通信的

基本概念在开始之前,先说几个概念: RpcEndPoint:RPC分布式的一个实例,他用于指定音讯的解决,比方接管音讯。RpcEndpointRef:RpcEndPoint的援用,也就是说,他指向的是服务端的RpcEndPoint,所以RpcEndpointRef会有服务端的RPC地址。 Inbox:除了RpcEndPoint和RpcEndpointRef(下图太挤了这两个没画),还存储InboxMessage的音讯队列。EndpointData:包含了RpcEndpoint、NettyRpcEndpointRef及Inbox。综上,EndpointData的构造是这样: RpcEndPoint注册RpcEndPoint实例化并通过Dispatcher注册的时候,就会实例化下面那些组件,并封装一个EndpointData。这里须要留神的是,Inbox组件在实例化的时候,会往messages这个音讯队列放入OnStart音讯。当拿到EndpointData后,Dispatcher就会把这个Dispatcher扔到receivers队列中。除此之前,还会存储EndpointData和名称的映射关系、RpcEndPoint和RpcEndPointRef的映射关系。扔到receivers队列的EndpointData必定不是仅仅就扔在那边的,所以他会有一个线程池来进行解决,这个线程池里会有N个叫做MessageLoop的线程,会监听receivers队列,如果队列里有数据,就会把队列的数据拿进去。这个数据就是EndpointData,对EndpointData进行解决的,是EndpointData外部的Inbox。咱们下面说过,Inbox外面也保护了一个InboxMessage的音讯队列messages,Inbox就会把messages的音讯拿进去,一个个进行生产。这里的音讯都是有本人的类型,比方RpcMessage、OnStart、OnStop等等。下面还提了,实例化Inbox的时候,messages会有一个OnStart,所以刚开始Inbox的messages队列就是有货色的,也就是说马上就会执行OnStart里对应的办法,也就是RpcEndpoint的onStart。所以RpcEndpoint的生命周期的签名局部就是结构->onStart。 客户端申请发送RpcEndpoint注册后,就能够承受申请了,咱们当初看看客户端怎么发送申请的。客户端在发送音讯前,会把音讯封装成RequestMessage,而后再判断音讯发送的地址是否是以后地址,如果是以后地址,那流程和下面一样,把音讯放入inbox,而后存入receivers队列,期待线程生产。如果是不一样,那就须要把音讯进行序列化,并封装成OutboxMessage,交给Outbox进行解决。和Inbox相似,Outbox也有本人的OutboxMessage音讯队列,一直的从队列拿出messages,把音讯发送进来。服务端接管到申请后,就会把音讯进行反序列化,而后扔到receivers队列。 总体流程1、客户端产生一个音讯,而后序列化后放入Outbox的队列中。2、客户端的一个线程把音讯取出来,依据服务端的地址,通过netty进行发送3、服务端接管到音讯,把音讯进行反序列号,而后通过客户端给定的信息,找到EndpointData。4、从EndpointData中取出Inbox,并把音讯放入到队列。5、把EndpointData放入receivers队列。6、线程池中的线程会从receivers队列取出EndpointData,而后调用Inbox的RpcEndPoint对音讯进行解决。7、如果有返回值,就会通过RpcEndPointRef,把音讯序列号后,存入Outbox,服务端的线程就会把这个音讯返回给客户端。8、客户端接管音讯后,反复第三步骤对音讯进行解决。 源码思维导图RpcEnv的创立NettyRpcEnv#stopDispatcher#postMessageDispatcher#stop客户端发送申请服务端解决申请

July 17, 2021 · 1 min · jiezi

关于spark:Spark-RDD使用

弹性分布式数据集(Resilient Distributed Dataset,RDD)是 Spark 中的外围概念。简略的说,就是在Spark中创立一个RDD,而后通过RDD对数据进行各种各样的操作。 RDD创立RDD的创立包含: 从汇合中创立从其余存储(比方hdfs、本地文件等)创立从其余RDD创立上面通过这几种形式来创立RDD,在创立RDD之前须要创立SparkContext,从上面的例子能够看出SparkContext须要一个conf,这个conf的master属性,在后面两张曾经提过了。从汇合中创立有两个办法,parallelize以及makeRDD,makeRDD实际上调用的是parallelize办法,这两个办法都容许除了汇合外,还能够再传递一个分区的参数。从其余存储包含本地文件系统、HDFS、Cassandra、HBase、Amazon S3等,这里的文件能够用通配符,而不限定某一个文件,比方textFile("/my/directory/*.txt"),就是/my/directory下所有的txt文件。 object CreateRDD { def main(args: Array[String]): Unit = { val conf = new SparkConf().setAppName("CreateRDD").setMaster("local") val sc = new SparkContext(conf) // parallelize val data = Array(1, 2, 3, 4, 5) val rdd1: RDD[Int] = sc.parallelize(data) println(rdd1.count) val rdd2: RDD[Int] = sc.makeRDD(data) // makeRDD println(rdd2.count) val rdd3: RDD[String] = sc.textFile("D:\\data\\test.txt") // 从其余存储 println(rdd3.first) // 从其余RDD val rdd4: RDD[String] = rdd3.map(_ + "bbb") println(rdd4.first) // 敞开 sc.stop }}RDD的操作RDD反对两种操作:transformations和action。transformations从字面上了解,就是转换,能够说从一个数据集转换成另外一个数据集,这里须要留神的是,所有的transformations都是lazy的,也就是说他只管执行了咱们那行语句,比方map映射,他并不会进行map映射,只有触发到action的时候,才会进行计算。action,会触发RDD的计算并把最终后果返回给驱动程序。 ...

July 14, 2021 · 6 min · jiezi

关于spark:Spark-Spark-Submit使用

Spark Submit用于启动集群中的应用程序,他的运行命令跟Spark Shell差不多。 ./bin/spark-submit \ --class <main-class> \ --master <master-url> \ --deploy-mode <deploy-mode> \ --conf <key>=<value> \ ... # other options <application-jar> \ [application-arguments]--class:应用程序的入口--master:master URL,这个同Spark Shellapplication-jar:jar包地址application-arguments:应用程序入口的参数其余参数也和Spark Shell差不多,能够通过$SPARK_HOME/bin/spark-submit --help查看。上面咱们用Spark自带的程序来计算Pi。相似的例子能够参考官网 $SPARK_HOME/bin/spark-submit \--class org.apache.spark.examples.SparkPi \--master spark://bigdata01:7077,bigdata03:7077 \--executor-memory 512m \--total-executor-cores 2 \$SPARK_HOME/examples/jars/spark-examples_2.11-2.4.5.jar \100运行过程中的web界面,运行时通过http://bigdata01:4040/jobs 拜访:运行后果如下:http://bigdata01:8080/能够看到,曾经实现了两次Applications,在Completed Applications中还能够看到运行的信息

July 8, 2021 · 1 min · jiezi

关于spark:Spark-Spark-Shell使用

NSpark Shell是Spark提供的一个弱小的交互剖析数据的工具,咱们间接用$SPARK_HOME/bin/spark-shell命令来Spark Shell启动,如果在bin目录下,能够间接用spark-shell。进入后,能够看到曾经初始化了sc和spark。 参数Spark Shell还反对其余参数,比方master、executor-memory等。咱们能够通过$SPARK_HOME/bin/spark-shell --help来查看 mastermaster的值包含spark、mesos、yarn、k8s以及local,咱们下面没有指定master,默认是local的,从上图能够看进去。 模式形容格局spark在spark的stanalone集群运行,也就是上一篇搭建的高可用集群spark://host:portmesos运行在mesos资源管理器上mesos://host:portyarn运行在yarn资源管理器上 k8s运行在k8s集群上https://host:portlocal本地模式,本地运行local:1个线程;local[*];不限线程,local[N]:N个线程比方咱们运行在咱们搭建的spark集群上,能够看到sc前面的master就是咱们的spark集群。 [bigdata@bigdata01 test]$ $SPARK_HOME/bin/spark-shell \> --master spark://bigdata01:7077,bigdata03:7077 其余executor-memory:executor的内存,默认1Gtotal-executor-cores:standalone模式才有的参数,定义所有executors的cpu数。实例从hdfs中读取一个文件,并统计这个文件多少行,以及第一行的内容等。文件test.txt内容: aaaaabbbbbcccccdddddeeeeefffff上传到hdfs [bigdata@bigdata01 test]$ hadoop fs -put /home/bigdata/test/test.txt /dajun/test进入spark shell [bigdata@bigdata01 test]$ $SPARK_HOME/bin/spark-shell --master spark://bigdata01:7077,bigdata03:7077 --executor-memory 512M --total-executor-cores 2在spark shell中操作 # 读取文件scala> val textFile = spark.read.textFile("/dajun/test/test.txt")textFile: org.apache.spark.sql.Dataset[String] = [value: string]# 统计数量scala> textFile.count()res0: Long = 6 # 获取第一行scala> textFile.first()res1: String = aaaaa# 过滤scala> textFile.filter(line => line.contains("a")).count()res2: Long = 1

July 7, 2021 · 1 min · jiezi

关于spark:Spark-分布式高可用集群安装

筹备工作下载地址官网下载页面有个Spark release archives,点击能够查看历史版本我这里抉择的是spark-2.4.5,因为我Hadoop抉择的是2.7.7版本,所以下载的是spark-2.4.5-bin-hadoop2.7.tgz。 环境依赖Spark-2.4.5依赖的java和scala版本散布为Java8和Scala 2.12。装置过程略。我本机的版本: 集群布局角色节点Masterbigdata01,bigdata03Salvebigdata01,bigdata02,bigdata03,bigdata04Spark HistoryServerbigdata02分布式高可用装置上传安装包并解压到对应目录: tar -zxvf spark-2.4.5-bin-hadoop2.7.tgz -C /home/bigdata/apps/批改配置文件spark-env.sh: [bigdata@bigdata01 apps]$ cd /home/bigdata/apps/spark-2.4.5-bin-hadoop2.7/conf[bigdata@bigdata01 conf]$ lltotal 36-rw-r--r-- 1 bigdata bigdata 996 Feb 3 2020 docker.properties.template-rw-r--r-- 1 bigdata bigdata 1105 Feb 3 2020 fairscheduler.xml.template-rw-r--r-- 1 bigdata bigdata 2025 Feb 3 2020 log4j.properties.template-rw-r--r-- 1 bigdata bigdata 7801 Feb 3 2020 metrics.properties.template-rw-r--r-- 1 bigdata bigdata 865 Feb 3 2020 slaves.template-rw-r--r-- 1 bigdata bigdata 1292 Feb 3 2020 spark-defaults.conf.template-rwxr-xr-x 1 bigdata bigdata 4221 Feb 3 2020 spark-env.sh.template[bigdata@bigdata01 conf]$ mv spark-env.sh.template spark-env.sh[bigdata@bigdata01 conf]$ vim spark-env.sh 在spark-env.sh前面增加如下内容: ...

July 5, 2021 · 1 min · jiezi

关于spark:Spark源代码Spark多线程NettyRpcEnvask解读

背景Spark中有很多异步解决的例子,每一个中央都值得好好去扫视一番,对辅助了解spark的机理以及为本人写出优雅的代码都会有很大的帮忙。 NettyRpcEnv.ask解读RpcEnv作用NettyRpcEnv是RpcEnv的在spark中的惟一一个实现。RpcEnv是什么呢,能够先看一下它的class头信息 /** * An RPC environment. [[RpcEndpoint]]s need to register itself with a name to [[RpcEnv]] to * receives messages. Then [[RpcEnv]] will process messages sent from [[RpcEndpointRef]] or remote * nodes, and deliver them to corresponding [[RpcEndpoint]]s. For uncaught exceptions caught by * [[RpcEnv]], [[RpcEnv]] will use [[RpcCallContext.sendFailure]] to send exceptions back to the * sender, or logging them if no such sender or `NotSerializableException`. * * [[RpcEnv]] also provides some methods to retrieve [[RpcEndpointRef]]s given name or uri. */就是一句话,RPC的环境。在这里,最重要的2个操作莫过于 ...

June 14, 2021 · 4 min · jiezi

关于spark:在-windows-上安装-spark-遇到的一些坑-避坑指南

在 windows 上装置 spark 遇到的一些坑 | 避坑指南 最近有个活:给了我一个阿里云桌面(windows 10零碎),让我在下面用 scala + spark 写一些货色。 总是报错一直,根本的逻辑都运行不了。经验了很久的 debug ,我总结进去:但凡 IDEA 没有在我的脚本里明确指出哪行有问题的谬误,都是因为版本不兼容。别犹豫,赶快查看版本。 查看波及到: 根本的 java 环境: 1.8.0_201语言 scala 版本: 2.12.13hadoop 版本: 2.6.4spark 版本: 2.4.8第一关:scala小版本不兼容只管咱们在 spark 官网看到:Spark 2.4.8 配置 Scala 2.12.x 版本就行,然而呵呵,运行时报错如下。 ... java.lang.NoSuchMethodError: scala.Predef$.refArrayOps ...我自身刚开始用 scala ,还认为是本人写的程序哪里出了问题。好家伙这顿找哇,最初感激『运行spark呈现java.lang.NoSuchMethodError: scala.Predef$.refArrayOps』,让我意识到了或者更换 scala 版本能够一试。 下面那篇文章倡议在 mvnrepository.com/artifact/org.apache.spark/spark-core 下面看版本兼容,我感觉不靠谱。我这里举荐两个办法,都是我本人摸索的: 办法一: 关上咱们的命令行(cmd或者powershell都行),输出 spark-shell ,看咱们本地装置的 spark 用了啥版本的 scala 。如下图。 办法二: 去 spark 装置门路上面看看外面那 scala 依赖都啥版本。如下图。 于是把 scala 2.12.13 卸载了,去 scala 官网下载了 scala 2.11.12 版本的。 ...

June 14, 2021 · 1 min · jiezi

关于spark:阿里大数据云原生化实践EMR-Spark-on-ACK-产品介绍

开源大数据社区 & 阿里云 EMR 系列直播 第六期 主题:EMR spark on ACK 产品演示及最佳实际 讲师:石磊,阿里云 EMR 团队技术专家 内容框架: • 云原生化挑战及阿里实际• Spark 容器化计划• 产品介绍和演示 直播回放:扫描文章底部二维码退出钉群观看回放,或进入链接https://developer.aliyun.com/... 一、云原生化挑战及阿里实际大数据技术发展趋势 云原生化面临挑战计算与存储拆散 如何构建以对象存储为底座的 HCFS 文件系统 • 齐全兼容现有的 HDFS• 性能对标 HDFS,老本升高 shuffle 存算拆散 如何解决 ACK 混合异构机型 • 异构机型没有本地盘• 社区 [Spark-25299] 探讨,反对 Spark 动静资源,成为业界共识 缓存计划 如何无效反对跨机房、跨专线混合云 • 须要在容器内反对缓存零碎ACK 调度如何解决调度性能瓶颈• 性能对标 Yarn• 多级队列治理 其余 • 错峰调度• Yarnon ACK 节点资源互相感知 阿里实际 - EMR on ACK 整体计划介绍 • 通过数据开发集群/调度平台提交到不同的执行平台• 错峰调度,依据业务顶峰低峰策略调整• 云原生数据湖架构,ACK 弹性扩缩容能力强• 通过专线,云上云下混合调度• ACK 治理异构机型集群,灵活性好 ...

June 7, 2021 · 1 min · jiezi

关于spark:超详攻略Databricks-数据洞察-企业级全托管-Spark-大数据分析平台及案例分析

简介: 5分钟读懂 Databricks 数据洞察 开源大数据社区 & 阿里云 EMR 系列直播 第四期主题:Databricks 数据洞察 - 企业级全托管 Spark 大数据分析平台及案例剖析讲师:棕泽,阿里云技术专家,计算平台事业部开放平台-生态企业团队负责人 内容框架:Databricks 数据洞察产品介绍性能介绍典型场景客户案例产品Demo 一、Databricks 数据洞察产品介绍1、 Databricks 公司简介2、 什么是阿里云 Databricks 数据洞察产品01\ Databricks 公司简介 ① ApacheSpark 开创公司,也是 Spark 的最大代码贡献者,Spark 技术生态背地的商业公司。在2013年,由加州大学伯克利分校 AMPLab 的开创团队 ApacheSpark 的创建者所成立。 ② 外围产品和技术,主导和推动 Spark 开源生态ApacheSpark、DeltaLake、Koalas 、MLFlow、OneLakehousePlatform ③ 公司定位Databricksis the Data + AI company,为客户提供数据分析、数据工程、数据迷信和人工智能方面的服务,一体化的 Lakehouse 架构开源版本 VS 商业版本:公司绝大部分技术研发资源投入在商业化产品多云策略,与顶级云服务商单干,提供数据开发、数据分析、机器学习等产品,Data+AI 一体化剖析平台④ 市场位置科技独角兽,行业标杆,领导Spark整体技术生态的走向及风向标2021年最受期待的科技上市公司 02\ Databricks 公司估值及融资历史(起源 Databricks 官网)① 2019年10月G轮,估值 $ 6.2 Billion② 2021年2月初F轮,估值 $ 28 Billion 本轮融资,三大云服务商 AWS、GCP、MSAzure 以及 Salesforce 都进行了跟投——足以看到云厂商对 Databricks 的倒退的器重上市预期:打算 IPO 在2021年——多方预测 Databricks 上市之时其估值可能达到350亿美元,甚至是高达500亿美元 ...

June 7, 2021 · 2 min · jiezi

关于spark:Spark30源码解读环境准备源码Yarn集群

Spark提交一个计算是调用spark-submit。spark-submit 调用的是 bin目录下的spark-submit脚本,咱们关上spark-submit脚本; exec "${SPARK_HOME}"/bin/spark-class org.apache.spark.deploy.SparkSubmit "$@"能够看到 spark-submit执行的是bin/spark-class文件。 CMD=("${CMD[@]:0:$LAST}")exec "${CMD[@]}"咱们加一行打印命令: ......CMD=("${CMD[@]:0:$LAST}")echo "${CMD[@]}"exec "${CMD[@]}"咱们提交一个计算: spark-submit \--class org.apache.spark.examples.SparkPi\--master yarn \--deploy-mode client \--driver-memory 512m \--executor-memory 512m \--total-executor-cores 2 \/home/hadoop/examples/jars/spark-examples_2.12-3.0.0.jar打印进去的代码: java -cp......-Xmx512m org.apache.spark.deploy.SparkSubmit --master yarn --deploy-mode client --conf spark.driver.memory=512m --class MySpark --executor-memory 512m --total-executor-cores 2 / /home/hadoop/examples/jars/spark-examples_2.12-3.0.0.jarjava会启动一个SparkSubmit过程,执行SparkSubmit main 办法。 override def main(args: Array[String]): Unit = { val submit = new SparkSubmit() { self => override protected def parseArguments(args: Array[String]): SparkSubmitArguments = { new SparkSubmitArguments(args) { override protected def logInfo(msg: => String): Unit = self.logInfo(msg) override protected def logWarning(msg: => String): Unit = self.logWarning(msg) override protected def logError(msg: => String): Unit = self.logError(msg) } } override protected def logInfo(msg: => String): Unit = printMessage(msg) override protected def logWarning(msg: => String): Unit = printMessage(s"Warning: $msg") override protected def logError(msg: => String): Unit = printMessage(s"Error: $msg") override def doSubmit(args: Array[String]): Unit = { try { super.doSubmit(args) } catch { case e: SparkUserAppException => exitFn(e.exitCode) } } } submit.doSubmit(args) }main办法会创立SparkSubmit对象,并且执行doSubmit办法; ...

May 31, 2021 · 14 min · jiezi

关于spark:实时计算框架Spark集群搭建与入门案例

一、Spark概述1、Spark简介Spark是专为大规模数据处理而设计的,基于内存疾速通用,可扩大的集群计算引擎,实现了高效的DAG执行引擎,能够通过基于内存来高效解决数据流,运算速度相比于MapReduce失去了显著的进步。 2、运行构造 Driver 运行Spark的Applicaion中main()函数,会创立SparkContext,SparkContext负责和Cluster-Manager进行通信,并负责申请资源、任务分配和监控等。 ClusterManager 负责申请和治理在WorkerNode上运行利用所需的资源,能够高效地在一个计算节点到数千个计算节点之间伸缩计算,目前包含Spark原生的ClusterManager、ApacheMesos和HadoopYARN。 Executor Application运行在WorkerNode上的一个过程,作为工作节点负责运行Task工作,并且负责将数据存在内存或者磁盘上,每个 Application都有各自独立的一批Executor,工作间互相独立。 二、环境部署1、Scala环境安装包治理 [root@hop01 opt]# tar -zxvf scala-2.12.2.tgz[root@hop01 opt]# mv scala-2.12.2 scala2.12配置变量 [root@hop01 opt]# vim /etc/profileexport SCALA_HOME=/opt/scala2.12export PATH=$PATH:$SCALA_HOME/bin[root@hop01 opt]# source /etc/profile版本查看 [root@hop01 opt]# scala -versionScala环境须要部署在Spark运行的相干服务节点上。 2、Spark根底环境安装包治理 [root@hop01 opt]# tar -zxvf spark-2.1.1-bin-hadoop2.7.tgz[root@hop01 opt]# mv spark-2.1.1-bin-hadoop2.7 spark2.1配置变量 [root@hop01 opt]# vim /etc/profileexport SPARK_HOME=/opt/spark2.1export PATH=$PATH:$SPARK_HOME/bin[root@hop01 opt]# source /etc/profile版本查看 [root@hop01 opt]# spark-shell 3、Spark集群配置服务节点 [root@hop01 opt]# cd /opt/spark2.1/conf/[root@hop01 conf]# cp slaves.template slaves[root@hop01 conf]# vim slaveshop01hop02hop03环境配置 [root@hop01 conf]# cp spark-env.sh.template spark-env.sh[root@hop01 conf]# vim spark-env.shexport JAVA_HOME=/opt/jdk1.8export SCALA_HOME=/opt/scala2.12export SPARK_MASTER_IP=hop01export SPARK_LOCAL_IP=装置节点IPexport SPARK_WORKER_MEMORY=1gexport HADOOP_CONF_DIR=/opt/hadoop2.7/etc/hadoop留神SPARK_LOCAL_IP的配置。 ...

April 26, 2021 · 2 min · jiezi

关于spark:Spark内存管理机制

Spark 作为一个基于内存的分布式计算引擎,其内存治理模块在整个零碎中扮演着十分重要的角色。了解 Spark 内存治理的基本原理,有助于更好地开发 Spark 应用程序和进行性能调优。本文旨在梳理出 Spark 内存治理的脉络,抛砖引玉,引出读者对这个话题的深入探讨。本文中论述的原理基于 Spark 2.1 版本,浏览本文须要读者有肯定的 Spark 和 Java 根底,理解 RDD、Shuffle、JVM 等相干概念。 在执行 Spark 的应用程序时,Spark 集群会启动 Driver 和 Executor 两种 JVM 过程,前者为主控过程,负责创立 Spark 上下文,提交 Spark 作业(Job),并将作业转化为计算工作(Task),在各个 Executor 过程间协调工作的调度,后者负责在工作节点上执行具体的计算工作,并将后果返回给 Driver,同时为须要长久化的 RDD 提供存储性能[1]。因为 Driver 的内存治理相对来说较为简单,本文次要对 Executor 的内存治理进行剖析,下文中的 Spark 内存均特指 Executor 的内存。 1 . Spark Shuffle进化史在MapReduce框架中,shuffle是连贯Map和Reduce之间的桥梁,Map的输入要用到Reduce中必须通过shuffle这个环节,shuffle的性能高下间接影响了整个程序的性能和吞吐量。Spark作为MapReduce框架的一种实现,天然也实现了shuffle的逻辑。 Shuffle是MapReduce框架中的一个特定的phase,介于Map phase和Reduce phase之间,当Map的输入后果要被Reduce应用时,输入后果须要按key哈希,并且散发到每一个Reducer下来,这个过程就是shuffle。因为shuffle波及到了磁盘的读写和网络的传输,因而shuffle性能的高下间接影响到了整个程序的运行效率。 上面这幅图清晰地形容了MapReduce算法的整个流程,其中shuffle phase是介于Map phase和Reduce phase之间。   概念上shuffle就是一个沟通数据连贯的桥梁,那么实际上shuffle(partition)这一部分是如何实现的的呢,上面咱们就以Spark为例讲一下shuffle在Spark中的实现。 先以图为例简略形容一下Spark中shuffle的整一个流程:   首先每一个Mapper会依据Reducer的数量创立出相应的bucket,bucket的数量是MM×RR,其中MM是Map的个数,RR是Reduce的个数。其次Mapper产生的后果会依据设置的partition算法填充到每个bucket中去。这里的partition算法是能够自定义的,当然默认的算法是依据key哈希到不同的bucket中去。当Reducer启动时,它会依据本人task的id和所依赖的Mapper的id从远端或是本地的block manager中获得相应的bucket作为Reducer的输出进行解决。这里的bucket是一个抽象概念,在实现中每个bucket能够对应一个文件,能够对应文件的一部分或是其余等。 Apache Spark 的 Shuffle 过程与 Apache Hadoop 的 Shuffle 过程有着诸多相似,一些概念可间接套用,例如,Shuffle 过程中,提供数据的一端,被称作 Map 端,Map 端每个生成数据的工作称为 Mapper,对应的,接收数据的一端,被称作 Reduce 端,Reduce 端每个拉取数据的工作称为 Reducer,Shuffle 过程实质上都是将 Map 端取得的数据应用分区器进行划分,并将数据发送给对应的 Reducer 的过程。 ...

April 9, 2021 · 4 min · jiezi

关于spark:Spark参数调优

Spark参数调优参考spark官网文档:http://spark.apache.org/docs/... Shuffle 相干Shuffle操作大略是对Spark性能影响最大的步骤之一(因为可能波及到排序,磁盘IO,网络IO等泛滥CPU或IO密集的操作),这也是为什么在Spark 1.1的代码中对整个Shuffle框架代码进行了重构,将Shuffle相干读写操作形象封装到Pluggable的Shuffle Manager中,便于试验和实现不同的Shuffle功能模块。例如为了解决Hash Based的Shuffle Manager在文件读写效率方面的问题而实现的Sort Base的Shuffle Manager。 spark.shuffle.manager用来配置所应用的Shuffle Manager,目前可选的Shuffle Manager包含默认的org.apache.spark.shuffle.sort.HashShuffleManager(配置参数值为hash)和新的org.apache.spark.shuffle.sort.SortShuffleManager(配置参数值为sort)。 这两个ShuffleManager如何抉择呢,首先须要理解他们在实现形式上的区别。 HashShuffleManager,故名思义也就是在Shuffle的过程中写数据时不做排序操作,只是将数据依据Hash的后果,将各个Reduce分区的数据写到各自的磁盘文件中。带来的问题就是如果Reduce分区的数量比拟大的话,将会产生大量的磁盘文件。如果文件数量特地微小,对文件读写的性能会带来比拟大的影响,此外因为同时关上的文件句柄数量泛滥,序列化,以及压缩等操作须要调配的长期内存空间也可能会迅速收缩到无奈承受的境地,对内存的应用和GC带来很大的压力,在Executor内存比拟小的状况下尤为突出,例如Spark on Yarn模式。 SortShuffleManager,是1.1版本之后实现的一个试验性(也就是一些性能和接口还在开发演变中)的ShuffleManager,它在写入分区数据的时候,首先会依据理论状况对数据采纳不同的形式进行排序操作,底线是至多依照Reduce分区Partition进行排序,这样来至于同一个Map工作Shuffle到不同的Reduce分区中去的所有数据都能够写入到同一个内部磁盘文件中去,用简略的Offset标记不同Reduce分区的数据在这个文件中的偏移量。这样一个Map工作就只须要生成一个shuffle文件,从而防止了上述HashShuffleManager可能遇到的文件数量微小的问题 两者的性能比拟,取决于内存,排序,文件操作等因素的综合影响。 对于不须要进行排序的Shuffle操作来说,如repartition等,如果文件数量不是特地微小,HashShuffleManager面临的内存问题不大,而SortShuffleManager须要额定的依据Partition进行排序,显然HashShuffleManager的效率会更高。 而对于原本就须要在Map端进行排序的Shuffle操作来说,如ReduceByKey等,应用HashShuffleManager尽管在写数据时不排序,但在其它的步骤中依然须要排序,而SortShuffleManager则能够将写数据和排序两个工作合并在一起执行,因而即便不思考HashShuffleManager的内存应用问题,SortShuffleManager仍旧可能更快。 spark.shuffle.sort.bypassMergeThreshold这个参数仅实用于SortShuffleManager,如前所述,SortShuffleManager在解决不须要排序的Shuffle操作时,因为排序带来性能的降落。这个参数决定了在这种状况下,当Reduce分区的数量小于多少的时候,在SortShuffleManager外部不应用Merge Sort的形式解决数据,而是与Hash Shuffle相似,间接将分区文件写入独自的文件,不同的是,在最初一步还是会将这些文件合并成一个独自的文件。这样通过去除Sort步骤来放慢处理速度,代价是须要并发关上多个文件,所以内存消耗量减少,实质上是绝对HashShuffleMananger一个折衷方案。 这个参数的默认值是200个分区,如果内存GC问题重大,能够升高这个值。 spark.shuffle.consolidateFiles这个配置参数仅实用于HashShuffleMananger的实现,同样是为了解决生成过多文件的问题,采纳的形式是在不同批次运行的Map工作之间重用Shuffle输入文件,也就是说合并的是不同批次的Map工作的输入数据,然而每个Map工作所须要的文件还是取决于Reduce分区的数量,因而,它并不缩小同时关上的输入文件的数量,因而对内存使用量的缩小并没有帮忙。只是HashShuffleManager里的一个折中的解决方案。 须要留神的是,这部分的代码实现只管原理上说很简略,然而波及到底层具体的文件系统的实现和限度等因素,例如在并发拜访等方面,须要解决的细节很多,因而始终存在着这样那样的bug或者问题,导致在例如EXT3上应用时,特定状况下性能反而可能降落,因而从Spark 0.8的代码开始,始终到Spark 1.1的代码为止也还没有被标记为Stable,不是默认采纳的形式。此外因为并不缩小同时关上的输入文件的数量,因而对性能具体能带来多大的改善也取决于具体的文件数量的状况。所以即便你面临着Shuffle文件数量微小的问题,这个配置参数是否应用,在什么版本中能够应用,也最好还是理论测试当前再决定。 spark.shuffle.spillshuffle的过程中,如果波及到排序,聚合等操作,势必会须要在内存中保护一些数据结构,进而占用额定的内存。如果内存不够用怎么办,那只有两条路能够走,一就是out of memory 出错了,二就是将局部数据长期写到内部存储设备中去,最初再合并到最终的Shuffle输入文件中去。 这里spark.shuffle.spill 决定是否Spill到内部存储设备(默认关上),如果你的内存足够应用,或者数据集足够小,当然也就不须要Spill,毕竟Spill带来了额定的磁盘操作。 spark.shuffle.memoryFraction / spark.shuffle.safetyFraction在启用Spill的状况下,spark.shuffle.memoryFraction(1.1后默认为0.2)决定了当Shuffle过程中应用的内存达到总内存多少比例的时候开始Spill。 通过spark.shuffle.memoryFraction能够调整Spill的触发条件,即Shuffle占用内存的大小,进而调整Spill的频率和GC的行为。总的来说,如果Spill太过频繁,能够适当减少spark.shuffle.memoryFraction的大小,减少用于Shuffle的内存,缩小Spill的次数。当然这样一来为了防止内存溢出,对应的可能须要缩小RDD cache占用的内存,即减小spark.storage.memoryFraction的值,这样RDD cache的容量缩小,有可能带来性能影响,因而须要综合思考。 因为Shuffle数据的大小是估算进去的,一来为了升高开销,并不是每减少一个数据项都残缺的估算一次,二来估算也会有误差,所以理论暂用的内存可能比估算值要大,这里spark.shuffle.safetyFraction(默认为0.8)用来作为一个保险系数,升高理论Shuffle应用的内存阀值,减少肯定的缓冲,升高理论内存占用超过用户配置值的概率。 spark.shuffle.spill.compress / spark.shuffle.compress这两个配置参数都是用来设置Shuffle过程中是否应用压缩算法对Shuffle数据进行压缩,前者针对Spill的两头数据,后者针对最终的shuffle输入文件,默认都是True 实践上说,spark.shuffle.compress设置为True通常都是正当的,因为如果应用千兆以下的网卡,网络带宽往往最容易成为瓶颈。此外,目前的Spark任务调度实现中,以Shuffle划分Stage,下一个Stage的工作是要期待上一个Stage的工作全副实现当前能力开始执行,所以shuffle数据的传输和CPU计算工作之间通常不会重叠,这样Shuffle数据传输量的大小和所需的工夫就间接影响到了整个工作的实现速度。然而压缩也是要耗费大量的CPU资源的,所以关上压缩选项会减少Map工作的执行工夫,因而如果在CPU负载的影响远大于磁盘和网络带宽的影响的场合下,也可能将spark.shuffle.compress 设置为False才是最佳的计划 对于spark.shuffle.spill.compress而言,状况相似,然而spill数据不会被发送到网络中,仅仅是长期写入本地磁盘,而且在一个工作中同时须要执行压缩和解压缩两个步骤,所以对CPU负载的影响会更大一些,而磁盘带宽(如果标配12HDD的话)可能往往不会成为Spark利用的次要问题,所以这个参数相对而言,或者更有机会须要设置为False。 总之,Shuffle过程中数据是否应该压缩,取决于CPU/DISK/NETWORK的理论能力和负载,应该综合思考。 Storage相干配置参数spark.local.dir这个看起来很简略,就是Spark用于写两头数据,如RDD Cache,Shuffle,Spill等数据的地位,那么有什么能够留神的呢。 首先,最根本的当然是咱们能够配置多个门路(用逗号分隔)到多个磁盘上减少整体IO带宽,这个大家都晓得。 其次,目前的实现中,Spark是通过对文件名采纳hash算法散布到多个门路下的目录中去,如果你的存储设备有快有慢,比方SSD+HDD混合应用,那么你能够通过在SSD上配置更多的目录门路来增大它被Spark应用的比例,从而更好地利用SSD的IO带宽能力。当然这只是一种变通的办法,终极解决方案还是应该像目前HDFS的实现方向一样,让Spark可能感知具体的存储设备类型,针对性的应用。 须要留神的是,在Spark 1.0 当前,SPARK_LOCAL_DIRS (Standalone, Mesos) or LOCAL_DIRS (YARN)参数会笼罩这个配置。比方Spark On YARN的时候,Spark Executor的本地门路依赖于Yarn的配置,而不取决于这个参数。 spark.executor.memoryExecutor 内存的大小,和性能自身当然并没有间接的关系,然而简直所有运行时性能相干的内容都或多或少间接和内存大小相干。这个参数最终会被设置到Executor的JVM的heap尺寸上,对应的就是Xmx和Xms的值 实践上Executor 内存当然是多多益善,然而理论受机器配置,以及运行环境,资源共享,JVM GC效率等因素的影响,还是有可能须要为它设置一个正当的大小。 多大算正当,要看理论状况 ...

March 17, 2021 · 1 min · jiezi

关于spark:Spark的五种JOIN策略

JOIN操作是十分常见的数据处理操作,Spark作为一个对立的大数据处理引擎,提供了十分丰盛的JOIN场景。本文分享将介绍Spark所提供的5种JOIN策略,心愿对你有所帮忙。本文次要包含以下内容: 影响JOIN操作的因素Spark中JOIN执行的5种策略Spark是如何抉择JOIN策略的影响JOIN操作的因素数据集的大小参加JOIN的数据集的大小会间接影响Join操作的执行效率。同样,也会影响JOIN机制的抉择和JOIN的执行效率。 JOIN的条件JOIN的条件会波及字段之间的逻辑比拟。依据JOIN的条件,JOIN可分为两大类:等值连贯和非等值连贯。等值连贯会波及一个或多个须要同时满足的相等条件。在两个输出数据集的属性之间利用每个等值条件。当应用其余运算符(运算连接符不为=)时,称之为非等值连贯。 JOIN的类型在输出数据集的记录之间利用连贯条件之后,JOIN类型会影响JOIN操作的后果。次要有以下几种JOIN类型: 内连贯(_Inner Join_):仅从输出数据集中输入匹配连贯条件的记录。外连贯(_Outer Join_):又分为左外连贯、右外链接和全外连贯。半连贯(_Semi Join_):右表只用于过滤左表的数据而不呈现在后果集中。穿插连贯(_Cross Join_):穿插联接返回左表中的所有行,左表中的每一行与右表中的所有行组合。穿插联接也称作笛卡尔积。Spark中JOIN执行的5种策略Spark提供了5种JOIN机制来执行具体的JOIN操作。该5种JOIN机制如下所示: Shuffle Hash JoinBroadcast Hash JoinSort Merge JoinCartesian JoinBroadcast Nested Loop JoinShuffle Hash Join简介当要JOIN的表数据量比拟大时,能够抉择Shuffle Hash Join。这样能够将大表进行依照JOIN的key进行重分区,保障每个雷同的JOIN key都发送到同一个分区中。如下图示: image 如上图所示:Shuffle Hash Join的根本步骤次要有以下两点: 首先,对于两张参加JOIN的表,别离依照join key进行重分区,该过程会波及Shuffle,其目标是将雷同join key的数据发送到同一个分区,不便分区内进行join。其次,对于每个Shuffle之后的分区,会将小表的分区数据构建成一个Hash table,而后依据join key与大表的分区数据记录进行匹配。条件与特点仅反对等值连贯,join key不须要排序反对除了全外连贯(full outer joins)之外的所有join类型须要对小表构建Hash map,属于内存密集型的操作,如果构建Hash表的一侧数据比拟大,可能会造成OOM将参数_spark.sql.join.prefersortmergeJoin (default true)_置为falseBroadcast Hash Join简介也称之为Map端JOIN。当有一张表较小时,咱们通常抉择Broadcast Hash Join,这样能够防止Shuffle带来的开销,从而进步性能。比方事实表与维表进行JOIN时,因为维表的数据通常会很小,所以能够应用Broadcast Hash Join将维表进行Broadcast。这样能够防止数据的Shuffle(在Spark中Shuffle操作是很耗时的),从而进步JOIN的效率。在进行 Broadcast Join 之前,Spark 须要把处于 Executor 端的数据先发送到 Driver 端,而后 Driver 端再把数据播送到 Executor 端。如果咱们须要播送的数据比拟多,会造成 Driver 端呈现 OOM。具体如下图示: image Broadcast Hash Join次要包含两个阶段: Broadcast阶段 :小表被缓存在executor中Hash Join阶段:在每个 executor中执行Hash Join条件与特点仅反对等值连贯,join key不须要排序反对除了全外连贯(full outer joins)之外的所有join类型Broadcast Hash Join相比其余的JOIN机制而言,效率更高。然而,Broadcast Hash Join属于网络密集型的操作(数据冗余传输),除此之外,须要在Driver端缓存数据,所以当小表的数据量较大时,会呈现OOM的状况被播送的小表的数据量要小于spark.sql.autoBroadcastJoinThreshold值,默认是10MB(10485760)被播送表的大小阈值不能超过8GB,spark2.4源码如下:BroadcastExchangeExec.scalalongMetric("dataSize") += dataSize if (dataSize >= (8L << 30)) { throw new SparkException( s"Cannot broadcast the table that is larger than 8GB: ${dataSize >> 30} GB") } 基表不能被broadcast,比方左连贯时,只能将右表进行播送。形如:fact_table.join(broadcast(dimension_table),能够不应用broadcast提醒,当满足条件时会主动转为该JOIN形式。Sort Merge Join简介该JOIN机制是Spark默认的,能够通过参数spark.sql.join.preferSortMergeJoin进行配置,默认是true,即优先应用Sort Merge Join。个别在两张大表进行JOIN时,应用该形式。Sort Merge Join能够缩小集群中的数据传输,该形式不会先加载所有数据的到内存,而后进行hashjoin,然而在JOIN之前须要对join key进行排序。具体图示: ...

March 15, 2021 · 3 min · jiezi

关于spark:HiveSqlSparkSQL常用函数

一、获取以后工夫current_date获取以后日期2018-04-09current_timestamp/now()获取以后工夫2018-04-09 15:20:49.247二、从日期工夫中提取字段year,month,day/dayofmonth,hour,minute,secondExamples: > SELECT day('2009-07-30'); 30` * 1* 2dayofweek (1 = Sunday, 2 = Monday, …, 7 = Saturday),dayofyearExamples: > SELECT dayofweek('2009-07-30'); 5` * 1* 2weekofyearweekofyear(date) - Returns the week of the year of the given date. A week is considered to start on a Monday and week 1 is the first week with >3 days.Examples: > SELECT weekofyear('2008-02-20'); 8` * 1* 2trunc截取某局部的日期,其余局部默认为01第二个参数 [“year”, “yyyy”, “yy”, “mon”, “month”, “mm”]Examples: > SELECT trunc('2009-02-12', 'MM'); 2009-02-01 > SELECT trunc('2015-10-27', 'YEAR'); 2015-01-01` * 1* 2* 3* 4date_trunc [“YEAR”, “YYYY”, “YY”, “MON”, “MONTH”, “MM”, “DAY”, “DD”, “HOUR”, “MINUTE”, “SECOND”, “WEEK”, “QUARTER”]Examples: > SELECT date_trunc('2015-03-05T09:32:05.359', 'HOUR'); 2015-03-05T09:00:00` * 1* 2date_format将工夫转化为某种格局的字符串Examples: > SELECT date_format('2016-04-08', 'y'); 2016` * 1* 2三、日期工夫转换unix_timestamp返回以后工夫的unix工夫戳Examples: > SELECT unix_timestamp(); 1476884637 > SELECT unix_timestamp('2016-04-08', 'yyyy-MM-dd'); 1460041200` * 1* 2from_unixtime将工夫戳换算成以后工夫,to_unix_timestamp将工夫转化为工夫戳Examples: > SELECT from_unixtime(0, 'yyyy-MM-dd HH:mm:ss'); 1970-01-01 00:00:00 > SELECT to_unix_timestamp('2016-04-08', 'yyyy-MM-dd'); 1460041200` * 1* 2to_date/date将字符串转化为日期格局,to_timestamp(Since: 2.2.0) > SELECT to_date('2009-07-30 04:17:52'); 2009-07-30 > SELECT to_date('2016-12-31', 'yyyy-MM-dd'); 2016-12-31 > SELECT to_timestamp('2016-12-31 00:12:00'); 2016-12-31 00:12:00` * 1* 2* 3quarter 将1年4等分(range 1 to 4)Examples: > SELECT quarter('2016-08-31'); 3` * 1* 2四、日期、工夫计算months_between两个日期之间的月数months_between(timestamp1, timestamp2) - Returns number of months between timestamp1 and timestamp2.Examples: > SELECT months_between('1997-02-28 10:30:00', '1996-10-30'); 3.94959677` * 1* 2add_months返回日期后n个月后的日期Examples: > SELECT add_months('2016-08-31', 1); 2016-09-30` * 1* 2* 3last_day(date),next_day(start_date, day_of_week)Examples: > SELECT last_day('2009-01-12'); 2009-01-31 > SELECT next_day('2015-01-14', 'TU'); 2015-01-20` * 1* 2date_add,date_sub(减)date_add(start_date, num_days) - Returns the date that is num_days after start_date.Examples: > SELECT date_add('2016-07-30', 1); 2016-07-31` * 1datediff(两个日期间的天数)datediff(endDate, startDate) - Returns the number of days from startDate to endDate.Examples: > SELECT datediff('2009-07-31', '2009-07-30'); 1` * 1* 2对于UTC工夫to_utc_timestampto_utc_timestamp(timestamp, timezone) - Given a timestamp like ‘2017-07-14 02:40:00.0’, interprets it as a time in the given time zone, and renders that time as a timestamp in UTC. For example, ‘GMT+1’ would yield ‘2017-07-14 01:40:00.0’.Examples: > SELECT to_utc_timestamp('2016-08-31', 'Asia/Seoul'); 2016-08-30 15:00:00` * 1* 2from_utc_timestampfrom_utc_timestamp(timestamp, timezone) - Given a timestamp like ‘2017-07-14 02:40:00.0’, interprets it as a time in UTC, and renders that time as a timestamp in the given time zone. For example, ‘GMT+1’ would yield ‘2017-07-14 03:40:00.0’.Examples: > SELECT from_utc_timestamp('2016-08-31', 'Asia/Seoul'); 2016-08-31 09:00:00五、Hive罕用函数1.数学函数 ...

March 15, 2021 · 3 min · jiezi

关于spark:Spark入门与进阶

(一)初识Spark

March 1, 2021 · 1 min · jiezi

关于spark:Spark底层原理详细解析深度好文建议收藏

Spark简介Apache Spark是用于大规模数据处理的对立剖析引擎,基于内存计算,进步了在大数据环境下数据处理的实时性,同时保障了高容错性和高可伸缩性,容许用户将Spark部署在大量硬件之上,造成集群。 Spark源码从1.x的40w行倒退到当初的超过100w行,有1400多位大牛奉献了代码。整个Spark框架源码是一个微小的工程。上面咱们一起来看下spark的底层执行原理。 Spark运行流程 具体运行流程如下: SparkContext 向资源管理器注册并向资源管理器申请运行Executor资源管理器调配Executor,而后资源管理器启动ExecutorExecutor 发送心跳至资源管理器SparkContext 构建DAG有向无环图将DAG分解成Stage(TaskSet)把Stage发送给TaskSchedulerExecutor 向 SparkContext 申请 TaskTaskScheduler 将 Task 发送给 Executor 运行同时 SparkContext 将利用程序代码发放给 ExecutorTask 在 Executor 上运行,运行结束开释所有资源1. 从代码角度看DAG图的构建Val lines1 = sc.textFile(inputPath1).map(...).map(...)Val lines2 = sc.textFile(inputPath2).map(...)Val lines3 = sc.textFile(inputPath3)Val dtinone1 = lines2.union(lines3)Val dtinone = lines1.join(dtinone1)dtinone.saveAsTextFile(...)dtinone.filter(...).foreach(...)上述代码的DAG图如下所示: Spark内核会在须要计算产生的时刻绘制一张对于计算门路的有向无环图,也就是如上图所示的DAG。 Spark 的计算产生在RDD的Action操作,而对Action之前的所有Transformation,Spark只是记录下RDD生成的轨迹,而不会触发真正的计算。 2. 将DAG划分为Stage外围算法一个Application能够有多个job多个Stage: Spark Application中能够因为不同的Action触发泛滥的job,一个Application中能够有很多的job,每个job是由一个或者多个Stage形成的,前面的Stage依赖于后面的Stage,也就是说只有后面依赖的Stage计算结束后,前面的Stage才会运行。 划分根据: Stage划分的根据就是宽依赖,像reduceByKey,groupByKey等算子,会导致宽依赖的产生。 回顾下宽窄依赖的划分准则:窄依赖:父RDD的一个分区只会被子RDD的一个分区依赖。即一对一或者多对一的关系,可了解为独生子女。 常见的窄依赖有:map、filter、union、mapPartitions、mapValues、join(父RDD是hash-partitioned)等。宽依赖:父RDD的一个分区会被子RDD的多个分区依赖(波及到shuffle)。即一对多的关系,可了解为超生。 常见的宽依赖有groupByKey、partitionBy、reduceByKey、join(父RDD不是hash-partitioned)等。外围算法:回溯算法 从后往前回溯/反向解析,遇到窄依赖退出本Stage,遇见宽依赖进行Stage切分。 Spark内核会从触发Action操作的那个RDD开始从后往前推,首先会为最初一个RDD创立一个Stage,而后持续倒推,如果发现对某个RDD是宽依赖,那么就会将宽依赖的那个RDD创立一个新的Stage,那个RDD就是新的Stage的最初一个RDD。而后顺次类推,持续倒推,依据窄依赖或者宽依赖进行Stage的划分,直到所有的RDD全副遍历实现为止。 3. 将DAG划分为Stage分析 一个Spark程序能够有多个DAG(有几个Action,就有几个DAG,上图最初只有一个Action(图中未体现),那么就是一个DAG)。 一个DAG能够有多个Stage(依据宽依赖/shuffle进行划分)。 同一个Stage能够有多个Task并行执行(task数=分区数,如上图,Stage1 中有三个分区P1、P2、P3,对应的也有三个 Task)。 能够看到这个DAG中只reduceByKey操作是一个宽依赖,Spark内核会以此为边界将其前后划分成不同的Stage。 同时咱们能够留神到,在图中Stage1中,从textFile到flatMap到map都是窄依赖,这几步操作能够造成一个流水线操作,通过flatMap操作生成的partition能够不必期待整个RDD计算完结,而是持续进行map操作,这样大大提高了计算的效率。 4. 提交Stages调度阶段的提交,最终会被转换成一个工作集的提交,DAGScheduler通过TaskScheduler接口提交工作集,这个工作集最终会触发TaskScheduler构建一个TaskSetManager的实例来治理这个工作集的生命周期,对于DAGScheduler来说,提交调度阶段的工作到此就实现了。 而TaskScheduler的具体实现则会在失去计算资源的时候,进一步通过TaskSetManager调度具体的工作到对应的Executor节点上进行运算。 5. 监控Job、Task、ExecutorDAGScheduler监控Job与Task:要保障相互依赖的作业调度阶段可能失去顺利的调度执行,DAGScheduler须要监控以后作业调度阶段乃至工作的实现状况。 ...

January 29, 2021 · 1 min · jiezi

关于spark:Spark的cache和persist的区别

spark的数据长久化 昨天面试的时候被问到了spark cache和persist的区别, 明天学习了一下并做一些记录首先要理解的是RDD是lazy的,具体贴一段stack over flow的解答,很具体的介绍了怎么了解RDD, 加cache与不加有什么区别,这个区别具体作用在哪里。 Most RDD operations are lazy. Think of an RDD as a description of a series of operations. An RDD is not data. So this line: val textFile = sc.textFile("/user/emp.txt") It does nothing. It creates an RDD that says "we will need to load this file". The file is not loaded at this point. RDD operations that require observing the contents of the data cannot be lazy. (These are called _actions_.) An example is RDD.count — to tell you the number of lines in the file, the file needs to be read. So if you write textFile.count, at this point the file will be read, the lines will be counted, and the count will be returned. ...

January 28, 2021 · 2 min · jiezi

关于spark:KubeEdge和Kuiper双剑合并轻松解决边缘流式数据处理

摘要:本篇文章次要分享基于KubeEdge和Kuiper实现边缘流式数据处理的实践经验。引言:KubeEdge 是一个开源的边缘计算平台,它在Kubernetes原生的容器编排和调度能力之上,扩大实现了 云边协同、计算下沉、海量边缘设施治理、边缘自治等能力。KubeEdge还将通过插件的模式反对5G MEC、AI云边协同等场景,目前在很多畛域都已落地利用。 在边缘的散失解决产品KuiperKuiper是从2019年初开始做的,在2019年10月份,公布了第一个版本,始终继续迭代到当初,它的整个架构是一个比拟经典的流式解决架构。 产品设计指标:在云端运行的流式解决,像Spark与Flink能够运行在边缘端 Kuiper架构图 整体架构可分为3局部,左侧为sources,代表数据起源的地位,数据起源可能是KubeEdge外面有个边缘端的MQTT macOS broker,也可能是文件、窗口、数据库;右侧为Sinks,代表数据处理实现后所要存储的地位,也就是指标零碎,指标能够是MQTT,能够将其存到文件、数据库外面,也能够调用HTTP service; 两头局部分成了这几层,最上层为数据业务逻辑解决,这个层面提供了SQL statement、Rule Parser,SQL processors进行解决后并将其转化成SQL plan;上面层为Streaming runtime和SQL runtime, 运行最终执行进去的 plan;最底层为storage,用来存储有些音讯流出。 Kuiper应用场景流式解决:实现在边缘端的实时流式解决 规定引擎:灵便定义规定引擎,实现告警和音讯转发 数据格式与协定转换:实现边缘与云端不同类型的数据格式与异构协定之间灵便转换,实现IT&OT交融 KubeEdge与Kuiper集成 局部架构图 Kuiper是装在 KubeEdge MQTT Broker前面,整个都运行在边缘端,底下为不同的Mapper,也就是接入各种各样不同的协定。边缘MQTT Broker用来替换音讯。 数据处理的类型: 从设施模型文件定义中获取类型定义 将数据转换为Kuiper的数据类型 创立流时,可应用schema-less流定义 反对的数据类型有int、string、bool、float KubeEdge模型文件和配置下图为局部配置文件,包含设施的名称、属性、name、data type、Description等。 局部配置文件 保留设施模型文件 在ect/mqtt_source.yaml中配置模型文件信息 1)KubeEdgeVersion:目前未应用,为适配未来不同的版本模型文件预留 2)KubeEdgeModelFile:模型文件门路 通过config-map下发配置,保留到相干目录下 Kuiper应用过程1)定义流:相似余数据库中表格的定义 DATASOURCE=”$hw/events/device/+/twin/update”为KubeEdge里定义好的topic 2)定义并提交规定 用SQL实现业务逻辑,并将运行后果发送到指定指标 反对的SQL SELECT/FROM/WHERE/ORDER JOIN/GROUP/HAVING 4类工夫窗口+1个计数窗口 60+SQL函数 3)运行 KubeEdge中部署Kuiper规定1)使用Kuiper-Kubernetes-tool 2)该程序为一个工具类,独自运行在容器中,执行通过config-map下发的命令配置文件 配置文件中用于指定kuiper服务所在的地址和端口等信息 命令文件所在的目录 3)通过config-map下发命令执行文件,该工具定期主动扫描文件,而后执行命令 Kuiper manager-云边协同治理控制台另外一种形式是通过治理控制台来治理很多Kuiper节点,因为Kuiper能够运行在很多节点上。 比方Kuiper能够运行在车联网的盒子外面,车联网有很多车,能够通过Kuiper-manager把所有的实例都接入进来,对立对其进行规定更新。 第一步是装置插件,咱们提供了一些插件的常识,比方要接入不同的源,如果咱们这边的源不反对,则能够本人写个插件,将插件进行装置,装置下来之后咱们提供安卓插件界面,就能够应用了。 接下来为创立流定义 ...

January 25, 2021 · 1 min · jiezi

关于spark:Spark-30-已来是时候-on-kubernetes-了

随着kubernetes的倒退,大数据体系拥抱k8s成为了必经之路。 从Spark 2.4 版本开始,Spark 实验性反对 Kubernetes 作为资源管理器。不过尽管是试验性质,然而曾经有很多单位将之用于生产环境了,并获得很好的成果,在可移植性,可扩展性,老本等方面都获得了收益。 本文次要解读一下Spark 3.0 对于kubernetes的加强。 本文共分为5个局部,每个局部都有一个性能类别。你将首先看到配置更改,而后是运行时环境和安全性加强。之后,将理解Kubernetes的次要倒退之一-pod模板。到文章开端,将理解到从贡献者的角度来看产生了什么变动。 配置此类别的第一个重要更改是配置验证。从Apache Spark 3.0开始,与模式_[-._a-zA-Z][-._a-zA-Z0-9]*_不匹配的Kubernetes属性(带有spark.executorEnv前缀)将被疏忽并显示正告音讯如下: Invalid key: ... a valid environment variable name must consist of alphabetic characters, digits, '_', '-', or '.', and must not start with a digit.在3.0版本中,能够应用spark.kubernetes.driver.request.cores属性为 driver 申请特定数量的CPU核。而 executor 的属性(spark.kubernetes.executor.request.cores)自Spark 2.4.0起可用。 除此之外,还增加了一些工夫管制属性。应用spark.kubernetes.submission.connectionTimeout和spark.kubernetes.submission.requestTimeout,能够管制连贯和申请超时,以在客户端模式下启动 executor 程序。还存在两个相似的属性来解决申请 driver 的雷同超时(spark.kubernetes.driver.requestTimeout,spark.kubernetes.driver.connectionTimeout)。 运行时环境另一类性能与运行时环境无关。首先,对于PySpark的用户,Python 3是Docker镜像中的默认绑定(仍反对版本2) // Default change in the config val PYSPARK_MAJOR_PYTHON_VERSION = ConfigBuilder("spark.kubernetes.pyspark.pythonVersion") .doc("This sets the major Python version. Either 2 or 3. (Python2 or Python3)") .version("2.4.0") .stringConf .checkValue(pv => List("2", "3").contains(pv), "Ensure that major Python version is either Python2 or Python3") .createWithDefault("3") // was "2" in Spark 2.4.0如果对绑定感到好奇,能够认真钻研以下的代码: ...

January 24, 2021 · 1 min · jiezi

关于spark:Spark项目落地实战以及日常大数据开发注意事项

Spark简介基于内存的分布式集群计算平台可适配 Python、Java、Scala、SQL拓展性能:机器学习、流式计算、图计算 Spark特点高效 内存计算引擎DAG图比MapReduce快10~100倍易用 提供丰盛的API,反对Java,Scala, Python代码量小与Hadoop集成 读写HDFS、Hbase、Hive和Yarn集成与Oracle存过的比照Spark利用场景 数据仓库机器学习海量数据离线剖析实时数据流解决基本概念集群架构 集群资源管理器(Cluster Manager)运行作业工作的工作节点(Worker Node)每个利用的工作管制节点(Driver)每个工作节点上负责具体任务的执行过程 (Executor)资源管理器Mesos或YARN工作执行流程 首先为利用构建起根本的运行环境,即由 Driver创立一个SparkContext,进行资源 的申请、工作的调配和监控资源管理器为Executor分配资源,并启动 Executor过程SparkContext依据RDD的依赖关系构建 DAG图,DAG图提交给DAGScheduler解 析成Stage,而后把一个个TaskSet提交给 底层调度器TaskScheduler解决; Executor向SparkContext申请Task,Task Scheduler将Task发放给Executor运行, 并提供利用程序代码Task在Executor上运行,把执行后果反馈 给TaskScheduler,而后反馈给 DAGScheduler,运行结束后写入数据并 开释所有资源。数据处理过程 读入内部数据源转换算子进行数据处理动作算子进行解决流程触发解决实现输入后果罕用算子-转换开发案例--团体电信三码低效资产剖析Spark很香、也很坑 坑1:无奈自定义自增序列 坑2:Spark Stage之间的血统简短 坑3:直连Oracle读取慢 坑4:工夫格局反对不敌对常见问题1-无奈自定义自增序列问题论述:在不同的业务逻辑中,因为会存在多种维度的剖析,然而他们的后果是写入到同一张表格中的。在oracle中执行的时候是依据oracle中定义的序列来保障ID的唯一性,然而 咱们代码实现的时候采纳的数据加载模式时无奈加载oracle中的序列,并且读取序列也会收到oracle序列缓冲的影响。所以在业务逻辑解决上咱们得本人定义一个属于咱们 业务的ID序列,并且须要保障唯一性。常见问题2-血缘关系简短问题论述:因为SparkSQL在解析成ATS树时会向上追溯血统并反复解析,且随着血缘关系的增长ATS树会变的越来越简单,导致工作执行效率会重大升高。具体表象为 Spark工作在执行过程中会卡住不动,程序持续卡顿几个小时之后才会开始持续运行。计划一:checkpoints形式切割形式 计划二:hdfs落地,应用时二次读取常见问题3-读Oracle速率慢问题论述:在读取Oracle时,数据表未做分区,程序无奈通过指定分区并行加载数据,且为了减小数据库IO压力,采纳限度高频、数据读取限度等策略,导致读取Oracle速 率很慢,影响计算效率。常见问题4-Oracle工夫格局反对不敌对问题论述: park在读写Oracle时date类型数据容易失落精度,例如: Oracle中 2019-12-20 05:44:30读取后为2019-12-20, Spark中2019-12-20 05:44:30写入后变成2019-12-20 00:00:00解决方案: Oracle方言,即自定义一种数据库解释语言,实际上的实现 为数据的类型转换。OracleDateTypeInit.oracleInit()

December 28, 2020 · 1 min · jiezi

关于spark:Spark的分布式存储系统BlockManager全解析

摘要:BlockManager 是 spark 中至关重要的一个组件,在spark的运行过程中到处都有 BlockManager 的身影,只有搞清楚 BlockManager 的原理和机制,你能力更加深刻的了解 spark。§ BlockManager是什么?BlockManager的作用?我了解是负责做RDD的存储,如何存下来给后续工作去应用。其外部模块图如下: 图中看到有个memoryStore和DiskStore,阐明把block做存储时,有内存和磁盘2种形式,存储后就都i通过这个Store去治理。存储时以Block为单位,所以会有个映射用的数组有一个负责和Driver的BlockManagerMaster通信的援用接口还有个shuffClient,负责做 备份 和 下载, 即各executor之间会通过shuffClient来做block的传输。§ BlockManager和Driver、executor的关系其关系如图: 从中能够看到 blockManagerMaster在driver端生成executor中生成blockManager,并负责向BMM注册。spark中注册音讯通过ActorSystem进行发送§ 把块block 存入blockManager的流程 比方非凡的2个中央: 试图put时,会先看下该blockId是否有缓存,有的话间接取过去,否则就从新创立blockInfo存储时会先判断内存是否短缺,短缺就写入memoryStore,如果不够会先开释再尝试放入。§ 从blockManager中删除块 删除的操作没什么特地的,次要是会判断一下块的存储级别,抉择从不同的store中取块。 § shuffClient 下载block操作 BMMAC就是BlockManagerMasterActor,我当初瞎写的简称 留神点:当要取的块来自好几个BlockManager时, 把它打乱程序,防止好几个BM同时从某一个BM上下载数据!§ shuffeClinet的备份操作 BM为什么要备份他的block?书里作者没解释,我的了解是为了避免节点解体或者失落,导致两头工作无奈继续执行?因为其余的BlockManager能接管的block可能无限,所以备份时可能会波及多个block, 每次咱们一样,从BMmaster那里拿一个 随机的blockManager做备份,防止都往同一个上备份。§ BlockManager和Executor、driver的关系: 从中能够看到 blockManagerMaster在driver端生成executor中生成blockManager,并负责向BMM注册。spark中注册音讯通过ActorSystem进行发送点击关注,第一工夫理解华为云陈腐技术~

December 21, 2020 · 1 min · jiezi