Harley

Harley 查看完整档案

填写现居城市  |  填写毕业院校  |  填写所在公司/组织填写个人主网站
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 个人简介什么都没有

个人动态

Harley 收藏了文章 · 1月5日

Java复习①-Java基础-Java中的内存划分

Java中的内存主要划分为五部分

  1. 栈(Stack):存放方法中的局部变量
  2. 堆(Heap):new出来的东西
  3. 方法区(Method Area):存储.class相关信息
  4. 本地方法区(Native Method Stack):与操作系统相关
  5. 寄存器(PC Register):与cpu相关

    更具体点可以看图:
    image.png

    下面上实例:

1、数组内存图

(1) 只有一个数组的内存图

image

(2) 两个数组的内存图

image

(3)两个引用指向同一个数组的内存图

image

2、对象内存图

(1)只有一个对象的内存图image
(2)两个对象使用同一个方法的内存图image
(3)两个引用指向同一个对象的内存图image
查看原文

Harley 收藏了文章 · 2020-12-31

如何设计实时数据平台(设计篇)

导读:本文将会分上下两篇对一个重要且常见的大数据基础设施平台展开讨论,即“实时数据平台”。
在上篇设计篇中,我们首先从两个维度介绍实时数据平台:从现代数仓架构角度看待实时数据平台,从典型数据处理角度看待实时数据处理;接着我们会探讨实时数据平台整体设计架构、对具体问题的考量以及解决思路。
在下篇技术篇中,我们会进一步给出实时数据平台的技术选型和相关组件介绍,并探讨不同模式适用哪些应用场景。希望通过对本文的讨论,读者可以得到一个有章可循、可实际落地的实时数据平台构建方案。

一、相关概念背景

1.1 从现代数仓架构角度看待实时数据平台

现代数仓由传统数仓发展而来,对比传统数仓,现代数仓既有与其相同之处,也有诸多发展点。首先我们看一下传统数仓(图1)和现代数仓(图2)的模块架构:

图1 传统数仓

图2 现代数仓

传统数仓大家都很熟悉,这里不做过多介绍,一般来说,传统数仓只能支持T+1天时效延迟的数据处理,数据处理过程以ETL为主,最终产出以报表为主。

现代数仓建立在传统数仓之上,同时增加了更多样化数据源的导入存储,更多样化数据处理方式和时效(支持T+0天时效),更多样化数据使用方式和更多样化数据终端服务。

现代数仓是个很大的话题,在此我们以概念模块的方式来展现其新的特性能力。首先我们先看一下图3中Melissa Coates的整理总结:

在图3 Melissa Coates的总结中我们可以得出,现代数仓之所以“现代”,是因为它有多平台架构、数据虚拟化、数据的近实时分析、敏捷交付方式等等一系列特性。

在借鉴Melissa Coates关于现代数仓总结的基础上,加以自己的理解,我们也在此总结提取了现代数仓的几个重要能力,分别是:

  • 数据实时化(实时同步和流式处理能力)
  • 数据虚拟化(虚拟混算和统一服务能力)
  • 数据平民化(可视化和自助配置能力)
  • 数据协作化(多租户和分工协作能力)

1)数据实时化(实时同步和流式处理能力)

数据实时化,是指数据从产生(更新至业务数据库或日志)到最终消费(数据报表、仪表板、分析、挖掘、数据应用等),支持毫秒级/秒级/分钟级延迟(严格来说,秒级/分钟级属于准实时,这里统一称为实时)。这里涉及到如何将数据实时的从数据源中抽取出来;如何实时流转;为了提高时效性,降低端到端延迟,还需要有能力支持在流转过程中进行计算处理;如何实时落库;如何实时提供后续消费使用。实时同步是指多源到多目标的端到端同步,流式处理指在流上进行逻辑转换处理。

但是我们要知道,不是所有数据处理计算都可以在流上进行,而我们的目的,是尽可能的降低端到端数据延迟,这里就需要和其他数据流转处理方式配合进行,后面我们会进一步讨论。

2) 数据虚拟化(虚拟混算和统一服务能力)

数据虚拟化,是指对于用户或用户程序而言,面对的是统一的交互方式和查询语言,而无需关注数据实际所在的物理库和方言及交互方式(异构系统/异构查询语言)的一种技术。用户的使用体验是面对一个单一数据库进行操作,但其实这是一个虚拟化的数据库,数据本身并不存放于虚拟数据库中。

虚拟混算指的是虚拟化技术可以支持异构系统数据透明混算的能力,统一服务指对于用户提供统一的服务接口和方式。

图4 数据虚拟化

(图1-4均选自“Designing a Modern Data Warehouse + Data Lake” - Melissa Coates, Solution Architect, BlueGranite)

3)数据平民化(可视化和自助配置能力)

普通用户(无专业大数据技术背景的数据从业人员),可以通过可视化的用户界面,自助的通过配置和SQL方式使用数据完成自己的工作和需求,并无需关注底层技术层面问题(通过计算资源云化,数据虚拟化等技术)。以上是我们对数据平民化的解读。

对于Data Democratization的解读,还可以参见以下链接:

https://www.forbes.com/sites/...

文中提到技术层面如何支持数据平民化,并给出了几个例子:Data virtualization software,Data federation software,Cloud storage,Self-service BI applications等。其中数据虚拟化和数据联邦本质上是类似技术方案,并且提到了自助BI这个概念。

4)数据协作化(多租户和分工协作能力)

技术人员应该多了解业务,还是业务人员应该多了解技术?这一直是企业内争论不休的问题。而我们相信现代BI是一个可以深度协作的过程,技术人员和业务人员可以在同一个平台上,发挥各自所长,分工协作完成日常BI活动。这就对平台的多租户能力和分工协作能力提出了较高要求,一个好的现代数据平台是可以支持更好的数据协作化能力的。

我们希望可以设计出一个现代实时数据平台,满足以上提到的实时化、虚拟化、平民化、协作化等能力,成为现代数仓的一个非常重要且必不可少的组成部分。

1.2 从典型数据处理角度看待实时数据处理

典型的数据处理,可分为OLTP, OLAP, Streaming, Adhoc, Machine Learning等。这里给出OLTP和OLAP的定义和对比:

(图5选自文章“Relational Databases are not Designed for Mixed Workloads”-Matt Allen)

从某种角度来说,OLTP活动主要发生在业务交易库端,OLAP活动主要发生在数据分析库端。那么,数据是如何从OLTP库流转到OLAP库呢?如果这个数据流转时效性要求很高,传统的T+1批量ETL方式就无法满足了。

我们将OLTP到OLAP的流转过程叫Data Pipeline(数据处理管道),它是指数据的生产端到消费端之间的所有流转和处理环节,包括了数据抽取、数据同步、流上处理、数据存储、数据查询等。这里可能会发生很复杂的数据处理转换(如重复语义多源异构数据源到统一Star Schema的转换,明细表到汇总表的转换,多实体表联合成宽表等)。如何支持实时性很高的Pipeline处理能力,就成了一个有挑战性的话题,我们将这个话题描述为“在线管道处理”(OLPP, Online Pipeline Processing)问题。

因此,本文所讨论的实时数据平台,希望可以从数据处理角度解决OLPP问题,成为OLTP到OLAP实时流转缺失的课题的解决方案。下面,我们会探讨从架构层面,如何设计这样一个实时数据平台。

二、架构设计方案

2.1 定位和目标

实时数据平台(Real-time Data Platform,以下简称RTDP),旨在提供数据端到端实时处理能力(毫秒级/秒级/分钟级延迟),可以对接多数据源进行实时数据抽取,可以为多数据应用场景提供实时数据消费。作为现代数仓的一部分,RTDP可以支持实时化、虚拟化、平民化、协作化等能力,让实时数据应用开发门槛更低、迭代更快、质量更好、运行更稳、运维更简、能力更强。

2.2 整体设计架构

概念模块架构,是实时数据处理Pipeline的概念层的分层架构和能力梳理,本身是具备通用性和可参考性的,更像是需求模块。图6给出了RTDP的整体概念模块架构,具体每个模块含义都可自解释,这里不再详述。

图6 RTDP整体概念模块架构

下面我们会根据上图做进一步设计讨论,给出从技术层面的高阶设计思路。

图7 整体设计思想

由图7可以看出,我们针对概念模块架构的四个层面进行了统一化抽象:

  • 统一数据采集平台
  • 统一流式处理平台
  • 统一计算服务平台
  • 统一数据可视化平台

同时,也对存储层保持了开放的原则,意味着用户可以选择不同的存储层以满足具体项目的需要,而又不破坏整体架构设计,用户甚至可以在Pipeline中同时选择多个异构存储提供支持。下面分别对四个抽象层进行解读。

1)统一数据采集平台

统一数据采集平台,既可以支持不同数据源的全量抽取,也可以支持增强抽取。其中对于业务数据库的增量抽取会选择读取数据库日志,以减少对业务库的读取压力。平台还可以对抽取的数据进行统一处理,然后以统一格式发布到数据总线上。这里我们选择一种自定义的标准化统一消息格式UMS(Unified Message Schema)做为统一数据采集平台和统一流式处理平台之间的数据层面协议。

UMS自带Namespace信息和Schema信息,这是一种自定位自解释消息协议格式,这样做的好处是:

  • 整个架构无需依赖外部元数据管理平台;
  • 消息和物理媒介解耦(这里物理媒介指如Kafka的Topic, Spark Streaming的Stream等),因此可以通过物理媒介支持多消息流并行,和消息流的自由漂移。

平台也支持多租户体系,和配置化简单处理清洗能力。

2)统一流式处理平台

统一流式处理平台,会消费来自数据总线上的消息,可以支持UMS协议消息,也可以支持普通JSON格式消息。同时,平台还支持以下能力:

  • 支持可视化/配置化/SQL化方式降低流式逻辑开发/部署/管理门槛
  • 支持配置化方式幂等落入多个异构目标库以确保数据的最终一致性
  • 支持多租户体系,做到项目级的计算资源/表资源/用户资源等隔离

3)统一计算服务平台

统一计算服务平台,是一种数据虚拟化/数据联邦的实现。平台对内支持多异构数据源的下推计算和拉取混算,也支持对外的统一服务接口(JDBC/REST)和统一查询语言(SQL)。由于平台可以统一收口服务,因此可以基于平台打造统一元数据管理/数据质量管理/数据安全审计/数据安全策略等模块。平台也支持多租户体系。

4)统一数据可视化平台

统一数据可视化平台,加上多租户和完善的用户体系/权限体系,可以支持跨部门数据从业人员的分工协作能力,让用户在可视化环境下,通过紧密合作的方式,更能发挥各自所长来完成数据平台最后十公里的应用。

以上是基于整体模块架构之上,进行了统一抽象设计,并开放存储选项以提高灵活性和需求适配性。这样的RTDP平台设计,体现了现代数仓的实时化/虚拟化/平民化/协作化等能力,并且覆盖了端到端的OLPP数据流转链路。

2.3 具体问题和考量思路

下面我们会基于RTDP的整体架构设计,分别从不同维度讨论这个设计需要面对的问题考量和解决思路。

1)功能考量

功能考量主要讨论这样一个问题:实时Pipeline能否处理所有ETL复杂逻辑?

我们知道,对于Storm/Flink这样的流式计算引擎,是按每条处理的;对于Spark Streaming流式计算引擎,按每个mini-batch处理;而对于离线跑批任务来说,是按每天数据进行处理的。因此处理范围是数据的一个维度(范围维度)。

另外,流式处理面向的是增量数据,如果数据源来自关系型数据库,那么增量数据往往指的是增量变更数据(增删改,revision);相对的批量处理面向的则是快照数据(snapshot)。因此展现形式是数据的另一个维度(变更维度)。

单条数据的变更维度,是可以投射收敛成单条快照的,因此变更维度可以收敛成范围维度。所以流式处理和批量处理的本质区别在于,面对的数据范围维度的不同,流式处理单位为“有限范围”,批量处理单位为“全表范围”。“全表范围”数据是可以支持各种SQL算子的,而“有限范围”数据只能支持部分SQL算子,具体支持情况如下:

  • join:

✔ left join:支持。“限制范围”可以left join外部lookup表(通过下推,类似hashjoin效果)

✔ right join:不支持。每次从lookup拿回所有lookup表数据,这个计算是不可行的也是不合理的

✔ inter join:支持。可以转化为left join +filter,可以支持

✔ outer join:不支持。存在right join,因此不合理

  • union:支持。可以应用在拉回局部范围数据做窗口聚合操作。
  • agg:不支持。可以借助union做局部窗口聚合,但无法支持全表聚合操作。
  • filter:支持。没有shuffle,非常适合。
  • map:支持。没有shuffle,非常适合。
  • project:支持。没有shuffle,非常适合。

Join往往需要shuffle操作,是最费计算资源和时间的操作,而流上join(left join)将join操作转化成hashjoin的队列操作,将批量处理join的集中数据计算资源和时间平摊在数据流转过程中,因此在流上做left join是最划算的计算方式。

复杂的ETL并不是单一算子,经常会是由多个算子组合而成,由上可以看出单纯的流式处理并不能很好的支持所有ETL复杂逻辑。那么如何在实时Pipeline中支持更多复杂的ETL算子,并且保持时效性?这就需要“有限范围”和“全表范围”处理的相互转换能力。

设想一下:流式处理平台可以支持流上适合的处理,然后实时落不同的异构库,计算服务平台可以定时批量混算多源异构库(时间设定可以是每隔几分钟或更短),并将每批计算结果发送到数据总线上继续流转,这样流式处理平台和计算服务平台就形成了计算闭环,各自做擅长的算子处理,数据在不同频率触发流转过程中进行各种算子转换,这样的架构模式理论上即可支持所有ETL复杂逻辑。

图8 数据处理架构演化

图8给出了数据处理架构的演化,和OLPP的一种架构模式。其中wormhole和moonbox分别是我们开源的流式处理平台和计算服务平台,后面会具体介绍。

2)质量考量

上面的图也引出了两个主流实时数据处理架构:Lambda架构和Kappa架构,具体两个架构的介绍网上有很多资料,这里不再赘述。Lambda架构和Kappa架构各有其优劣势,但都支持数据的最终一致性,从某种程度上确保了数据质量,如何在Lambda架构和Kappa架构中取长补短,形成某种融合架构,这个话题会在新起文章中详细探讨。

当然数据质量也是个非常大的话题,只支持重跑和回灌并不能完全解决所有数据质量问题,只是从技术架构层面给出了补数据的工程方案。关于大数据数据质量问题,我们也会起一个新的话题讨论。

3)稳定考量

这个话题涉及但不限于以下几点,这里简单给出应对的思路:

  • 高可用HA

整个实时Pipeline链路都应该选取高可用组件,确保理论上整体高可用;在数据关键链路上支持数据备份和重演机制;在业务关键链路上支持双跑融合机制

  • SLA保障

在确保集群和实时Pipeline高可用的前提下,支持动态扩容和数据处理流程自动漂移

  • 弹性反脆弱

✔ 基于规则和算法的资源弹性伸缩

✔ 支持事件触发动作引擎的失效处理

  • 监控预警

集群设施层面,物理管道层面,数据逻辑层面的多方面监控预警能力

  • 自动运维

能够捕捉并存档缺失数据和处理异常,并具备定期自动重试机制修复问题数据

  • 上游元数据变更抗性

✔上游业务库要求兼容性元数据变更

✔ 实时Pipeline处理显式字段

4)成本考量

这个话题涉及但不限于以下几点,这里简单给出应对的思路:

  • 人力成本

通过支持数据应用平民化降低人才人力成本

  • 资源成本

通过支持动态资源利用降低静态资源占用造成的资源浪费

  • 运维成本

通过支持自动运维/高可用/弹性反脆弱等机制降低运维成本

  • 试错成本

通过支持敏捷开发/快速迭代降低试错成本

5)敏捷考量

敏捷大数据是一整套理论体系和方法学,在前文已有所描述,从数据使用角度来看,敏捷考量意味着:配置化,SQL化,平民化。

6)管理考量

数据管理也是一个非常大的话题,这里我们会重点关注两个方面:元数据管理和数据安全管理。如果在现代数仓多数据存储选型的环境下统一管理元数据和数据安全,是一个非常有挑战的话题,我们会在实时Pipeline上各个环节平台分别考虑这两个方面问题并给出内置支持,同时也可以支持对接外部统一的元数据管理平台和统一数据安全策略。

本文我们探讨了实时数据平台RTDP的相关概念背景和架构设计方案。在架构设计方案中,我们尤其着重讲了RTDP的定位和目标,整体设计架构,以及涉及到的具体问题和考量思路。有些话题很大,可以后续单独形成文章进行专题讨论,但整体上,我们给出了一整套RTDP的设计思路和规划。在下篇技术篇中,我们会将RTDP架构设计具体化落地化,给出推荐的技术选型和我们的开源平台方案,并会结合不同场景需求探讨RTDP的不同模式应用。

拓展阅读:以企业级实时数据平台为例,了解何为敏捷大数据

作者:卢山巍

来源:宜信技术学院

查看原文

Harley 收藏了文章 · 2020-12-31

如何设计实时数据平台(技术篇)

敏捷之歌

我抽数故我存在 | DBus

人人玩转流处理 | Wormhole

就当吾是数据库 | Moonbox

颜值最后十公里 | Davinci

导读:实时数据平台(RTDP,Real-time Data Platform)是一个重要且常见的大数据基础设施平台。在上篇(设计篇)中,我们从现代数仓架构角度和典型数据处理角度介绍了RTDP,并探讨了RTDP的整体设计架构。本文作为下篇(技术篇),则是从技术角度入手,介绍RTDP的技术选型和相关组件,探讨适用不同应用场景的相关模式。RTDP的敏捷之路就此展开~

拓展阅读:以企业级实时数据平台为例,了解何为敏捷大数据

如何设计实时数据平台(设计篇)

一、技术选型介绍

在设计篇中,我们给出了RTDP的一个整体架构设计(图1)。在技术篇里,我们则会推荐整体技术组件选型;对每个技术组件做出简单介绍,尤其对我们抽象并实现的四个技术平台(统一数据采集平台、统一流式处理平台、统一计算服务平台、统一数据可视化平台)着重介绍设计思路;对Pipeline端到端切面话题进行探讨,包括功能整合、数据管理、数据安全等。

图1 RTDP架构

1.1 整体技术选型

图2 整体技术选型

首先,我们简要解读一下图2:

  • 数据源、客户端,列举了大多数数据应用项目的常用数据源类型。
  • 数据总线平台DBus,作为统一数据采集平台,负责对接各种数据源。DBus将数据以增量或全量方式抽取出来,并进行一些常规数据处理,最后将处理后的消息发布在Kafka上。
  • 分布式消息系统Kafka,以分布式、高可用、高吞吐、可发布-订阅等能力,连接消息的生产者和消费者。
  • 流式处理平台Wormhole,作为统一流式处理平台,负责流上处理和对接各种数据目标存储。Wormhole从Kafka消费消息,支持流上配置SQL方式实现流上数据处理逻辑,并支持配置化方式将数据以最终一致性(幂等)效果落入不同数据目标存储(Sink)中。
  • 在数据计算存储层,RTDP架构选择开放技术组件选型,用户可以根据实际数据特性、计算模式、访问模式、数据量等信息选择合适的存储,解决具体数据项目问题。RTDP还支持同时选择多个不同数据存储,从而更灵活的支持不同项目需求。
  • 计算服务平台Moonbox,作为统一计算服务平台,对异构数据存储端负责整合、计算下推优化、异构数据存储混算等(数据虚拟化技术),对数据展示和交互端负责收口统一元数据查询、统一数据计算和下发、统一数据查询语言(SQL)、统一数据服务接口等。
  • 可视应用平台Davinci,作为统一数据可视化平台,以配置化方式支持各种数据可视化和交互需求,并可以整合其他数据应用以提供数据可视化部分需求解决方案,另外还支持不同数据从业人员在平台上协作完成各项日常数据应用。其他数据终端消费系统如数据开发平台Zeppelin、数据算法平台Jupyter等在本文不做介绍。
  • 切面话题如数据管理、数据安全、开发运维、驱动引擎,可以通过对接DBus、Wormhole、Moonbox、Davinci的服务接口进行整合和二次开发,以支持端到端管控和治理需求。

下面我们会进一步细化上图涉及到的技术组件和切面话题,介绍技术组件的功能特性,着重讲解我们自研技术组件的设计思想,并对切面话题展开讨论。

1.2 技术组件介绍

1.2.1 数据总线平台DBus

图3 RTDP架构之DBus

1.2.1.1 DBus设计思想

1)从外部角度看待设计思想

  • 负责对接不同的数据源,实时抽取出增量数据,对于数据库会采用操作日志抽取方式,对于日志类型支持与多种Agent对接。
  • 将所有消息以统一的UMS消息格式发布在Kafka上,UMS是一种标准化的自带元数据信息的JSON格式,通过统一UMS实现逻辑消息与物理Kafka Topic解耦,使得同一Topic可以流转多个UMS消息表。
  • 支持数据库的全量数据拉取,并且和增量数据统一融合成UMS消息,对下游消费透明无感知。

2)从内部角度看待设计思想

  • 基于Storm计算引擎进行数据格式化,确保消息端到端延迟最低。
  • 对不同数据源数据进行标准化格式化,生成UMS信息,其中包括:

✔ 生成每条消息的唯一单调递增id,对应系统字段ums_id_

✔ 确认每条消息的事件时间戳(event timestamp),对应系统字段ums_ts_

✔ 确认每条消息的操作模式(增删改,或insert only),对应系统字段ums_op_

  • 对数据库表结构变更实时感知并采用版本号进行管理,确保下游消费时明确上游元数据变化。
  • 在投放Kafka时确保消息强有序(非绝对有序)和at least once语义。
  • 通过心跳表机制确保消息端到端探活感知。
1.2.1.2 DBus功能特性
  • 支持配置化全量数据拉取
  • 支持配置化增量数据拉取
  • 支持配置化在线格式化日志
  • 支持可视化监控预警
  • 支持配置化多租户安全管控
  • 支持分表数据汇集成单逻辑表
1.2.1.3 DBus技术架构

图4 DBus数据流转架构图

更多DBus技术细节和用户界面,可以参看:

GitHub: https://github.com/BriData

1.2.2 分布式消息系统Kafka

Kafka已经成为事实标准的大数据流式处理分布式消息系统,当然Kafka在不断的扩展和完善,现在也具备了一定的存储能力和流式处理能力。关于Kafka本身的功能和技术已经有很多文章信息可以查阅,本文不再详述Kafka的自身能力。

这里我们具体探讨Kafka上消息元数据管理(Metadata Management)和模式演变(Schema Evolution)的话题。

图5

图片来源:http://cloudurable.com/images...

图5显示,在Kafka背后的Confluent公司解决方案中,引入了一个元数据管理组件:Schema Registry。这个组件主要负责管理在Kafka上流转消息的 元数据信息和Topic信息,并提供一系列元数据管理服务。之所以要引入这样一个组件,是为了Kafka的消费方能够了解不同Topic上流转的是哪些数据,以及数据的元数据信息,并进行有效的解析消费。

任何数据流转链路,不管是在什么系统上流转,都会存在这段数据链路的元数据管理问题,Kafka也不例外。Schema Registry是一种中心化的Kafka数据链路元数据管理解决方案,并且基于Schema Registry,Confluent提供了相应的Kafka数据安全机制和模式演变机制。

更多关于Schema Registry的介绍,可以参看:

Kafka Tutorial:Kafka, Avro Serialization and the Schema Registry

http://cloudurable.com/blog/k...

那么在RTDP架构中,如何解决Kafka消息元数据管理和模式演变问题呢?

1.2.2.1 元数据管理(Metadata Management)
  • DBus会自动将实时感知的数据库元数据变化记录下来并提供服务
  • DBus会自动将在线格式化的日志元数据信息记录下来并提供服务
  • DBus会发布在Kafka上发布统一UMS消息,UMS本身自带消息元数据信息,因此下游消费时无需调用中心化元数据服务,可以直接从UMS消息里拿到数据的元数据信息
1.2.2.2 模式演变(Schema Evolution)
  • UMS消息会自带Schema的Namespace信息,Namespace是一个7层定位字符串,可以唯一定位任何表的任何生命周期,相当于数据表的IP地址,形式如下:

[Datastore].[Datastore Instance].[Database].[Table].[TableVersion].[Database Partition].[Table Partition]

例:oracle.oracle01.db1.table1.v2.dbpar01.tablepar01

其中[Table Version]代表了这张表的某个Schema的版本号,如果数据源是数据库,那么这个版本号是由DBus自动维护的。

  • 在RTDP架构中,Kafka的下游是由Wormhole消费的,Wormhole在消费UMS时,会将[TableVersion]作为*处理,意味着当某表上游Schema变更时,Version会自动升号,但Wormhole会无视这个Version变化,将会消费此表所有版本的增量/全量数据,那么Wormhole如何做到兼容性模式演变支持呢?在Wormhole里可以配置流上处理SQL和输出字段,当上游Schema变更是一种“兼容性变更”(指增加字段,或者修改扩大字段类型等)时,是不会影响到Wormhole SQL正确执行的。当上游发生非兼容性变更时,Wormhole会报错,这时就需要人工介入对新Schema的逻辑进行修复。

由上文可以看出,Schema Registry和DBus+UMS是两种不同的解决元数据管理和模式演变的设计思路,两者各有优势和劣势,可以参考表1的简单比较。

表1 Schema Registry 与 DBus+UMS 对比

这里给出一个UMS的例子:

图6 UMS消息举例

1.2.3 流式处理平台Wormhole

图7 RTDP架构之Wormhole

1.2.3.1 Wormhole设计思想

1)从外部角度看待设计思想

  • 消费来自Kafka 的UMS消息和自定义JSON消息
  • 负责对接不同的数据目标存储 (Sink),并通过幂等逻辑实现Sink的最终一致性
  • 支持配置SQL方式实现流上处理逻辑
  • 提供Flow抽象。Flow由一个Source Namespace和一个Sink Namespace定义,且具备唯一性。Flow上可以定义处理逻辑,是一种流上处理的逻辑抽象,通过与物理Spark Streaming、Flink Streaming解耦,使得同一个Stream可以处理多个Flow处理流,且Flow可以在不同Stream上任意切换。
  • 支持基于回灌(backfill)的Kappa架构;支持基于Wormhole Job的Lambda架构

2)从内部角度看待设计思想

  • 基于Spark Streaming、Flink计算引擎进行数据流上处理。Spark Streaming可支持高吞吐、批量Lookup、批量写Sink等场景;Flink可支持低延迟、CEP规则等场景。
  • 通过ums_id_, ums_op_实现不同Sink的幂等入库逻辑
  • 通过计算下推实现Lookup逻辑优化
  • 抽象几个统一以支持功能灵活性和设计一致性

✔ 统一DAG高阶分形抽象

✔ 统一通用流消息UMS协议抽象

✔ 统一数据逻辑表命名空间Namespace抽象

  • 抽象几个接口以支持可扩展性

✔ SinkProcessor:扩展更多Sink支持

✔ SwiftsInterface:自定义流上处理逻辑支持

✔ UDF:更多流上处理UDF支持

  • 通过Feedback消息实时归集流式作业动态指标和统计
1.2.3.2 Wormhole功能特性
  • 支持可视化,配置化,SQL化开发实施流式项目
  • 支持指令式动态流式处理的管理、运维、诊断和监控
  • 支持统一结构化UMS消息和自定义半结构化JSON消息
  • 支持处理增删改三态事件消息流
  • 支持单个物理流同时并行处理多个逻辑业务流
  • 支持流上Lookup Anywhere,Pushdown Anywhere
  • 支持基于业务策略的事件时间戳流式处理
  • 支持UDF的注册管理和动态加载
  • 支持多目标数据系统的并发幂等入库
  • 支持多级基于增量消息的数据质量管理
  • 支持基于增量消息的流式处理和批量处理
  • 支持Lambda架构和Kappa架构
  • 支持与三方系统无缝集成,可作为三方系统的流控引擎
  • 支持私有云部署,安全权限管控和多租户资源管理
1.2.3.3 Wormhole技术架构

图8 Wormhole数据流转架构图

更多Wormhole技术细节和用户界面,可以参看:

GitHub:https://github.com/edp963/wor...

1.2.4 常用数据计算存储选型

RTDP架构对待数据计算存储选型的选择采取开放整合的态度。不同数据系统有各自的优势和适合的场景,但并没有一个数据系统可以适合各种各样的存储计算场景。因此当有合适的、成熟的、主流的数据系统出现,Wormhole和Moonbox会按照需要相应的扩展整合支持。

这里大致列举一些比较通用的选型:

  • 关系型数据库(Oracle/MySQL等):适合小数据量的复杂关系计算
  • 分布式列存储系统

✔ Kudu:Scan优化,适合OLAP分析计算场景

✔ HBase:随机读写,适合提供数据服务场景

✔ Cassandra:高性能写,适合海量数据高频写入场景

✔ ClickHouse:高性能计算,适合只有insert写入场景(后期将支持更新删除操作)

  • 分布式文件系统

✔ HDFS/Parquet/Hive:append only,适合海量数据批量计算场景

  • 分布式文档系统

✔ MongoDB:平衡能力,适合大数据量中等复杂计算

  • 分布式索引系统

✔ ElasticSearch:索引能力,适合做模糊查询和OLAP分析场景

  • 分布式预计算系统

✔ Druid/Kylin:预计算能力,适合高性能OLAP分析场景

1.2.5 计算服务平台Moonbox

图9 RTDP架构之Moonbox

1.2.5.1 Moonbox设计思想

1)从外部角度看待设计思想

  • 负责对接不同的数据系统,支持统一方式跨异构数据系统即席混算
  • 提供三种Client调用方式:RESTful服务、JDBC连接、ODBC连接
  • 统一元数据收口;统一查询语言SQL收口;统一权限控制收口
  • 提供两种查询结果写出模式:Merge、Replace
  • 提供两种交互模式:Batch模式、Adhoc模式
  • 数据虚拟化实现,多租户实现,可看作是虚拟数据库

2)从内部角度看待设计思想

  • 对SQL进行解析,经过常规Catalyst处理解析流程,最终生成可下推数据系统的逻辑执行子树进行下推计算,然后将结果拉回进行混算并返回
  • 支持两层Namespace:database.table,以提供虚拟数据库体验
  • 提供分布式服务模块Moonbox Grid提供高可用高并发能力
  • 对可全部下推逻辑(无混算)提供快速执行通道
1.2.5.2 Moonbox功能特性
  • 支持跨异构系统无缝混算
  • 支持统一SQL语法查询计算和写入
  • 支持三种调用方式:RESTful服务、JDBC连接、ODBC连接
  • 支持两种交互模式:Batch模式、Adhoc模式
  • 支持Cli Command工具和Zeppelin
  • 支持多租户用户权限体系
  • 支持表级权限、列级权限、读权限、写权限、UDF权限
  • 支持YARN调度器资源管理
  • 支持元数据服务
  • 支持定时任务
  • 支持安全策略
1.2.5.3 Moonbox技术架构

图10 Moonbox逻辑模块

更多Moonbox技术细节和用户界面,可以参看:

GitHub: https://github.com/edp963/moo...

1.2.6 可视应用平台Davinci

图11 RTDP架构之Davinci

1.2.6.1 Davinci设计思想

1)从外部角度看待设计思想

  • 负责各种数据可视化展示功能
  • 支持JDBC数据源
  • 提供平权用户体系,每个用户可以建立属于自己的Org、Team和Project
  • 支持SQL编写数据处理逻辑,支持拖拽式编辑可视化展示,提供多用户社交化分工协作环境
  • 提供多种不同的图表交互能力和定制化能力,以应对不同数据可视化需求
  • 提供嵌入整合进其他数据应用的能力

2)从内部角度看待设计思想

  • 围绕View和Widget展开。View是数据的逻辑视图;Widget是数据可视化视图
  • 通过用户自定义选择分类数据、有序数据和量化数据,按照合理的可视化逻辑自动展现视图
1.2.6.2 Davinci功能特性

1)数据源

  • 支持JDBC数据源
  • 支持CSV文件上传

2)数据视图

  • 支持定义SQL模版
  • 支持SQL高亮显示
  • 支持SQL测试
  • 支持回写操作

3)可视组件

  • 支持预定义图表
  • 支持控制器组件
  • 支持自由样式

4)交互能力

  • 支持可视组件全屏显示
  • 支持可视组件本地控制器
  • 支持可视组件间过滤联动
  • 支持群控控制器可视组件
  • 支持可视组件本地高级过滤器
  • 支持大数据量展示分页和滑块

5)集成能力

  • 支持可视组件CSV下载
  • 支持可视组件公共分享
  • 支持可视组件授权分享
  • 支持仪表板公共分享
  • 支持仪表板授权分享

6)安全权限

  • 支持数据行列权限
  • 支持LDAP登录集成

更多Davinci技术细节和用户界面,可以参看:

GitHub:https://github.com/edp963/dav...

1.3 切面话题讨论

1.3.1 数据管理

1)元数据管理

  • DBus可以实时拿到数据源的元数据并提供服务查询
  • Moonbox可以实时拿到数据系统的元数据并提供服务查询
  • 对于RTDP架构来说,实时数据源和即席数据源的元数据信息可以通过调用DBus和Moonbox的RESTful服务归集,可以基于此建设企业级元数据管理系统

2)数据质量

  • Wormhole可以配置消息实时落入HDFS(hdfslog)。基于hdfslog的Wormhole Job支持Lambda架构;基于hdfslog的Backfill支持Kappa架构。可以通过设置定时任务选择Lambda架构或者Kappa架构对Sink进行定时刷新,以确保数据的最终一致性。Wormhole还支持将流上处理异常或Sink写入异常的消息信息实时Feedback到Wormhole系统中,并提供RESTful服务供三方应用调用处理。
  • Moonbox可以对异构系统进行即席混算,这个能力赋予Moonbox“瑞士军刀”般的便利性。可以通过Moonbox编写定时SQL脚本逻辑,对关注的异构系统数据进行比对,或对关注的数据表字段进行统计等,可以基于Moonbox的能力二次开发数据质量检测系统。

3)血缘分析

  • Wormhole的流上处理逻辑通常SQL即可满足,这些SQL可以通过RESTful服务进行归集。
  • Moonbox掌管了数据查询的统一入口,并且所有逻辑均为SQL,这些SQL可以通过Moonbox日志进行归集。
  • 对于RTDP架构来说,实时处理逻辑和即席处理逻辑的SQL可以通过调用Wormhole的RESTful服务和Moonbox的日志归集,可以基于此建设企业级血缘分析系统。

1.3.2 数据安全

图12 RTDP数据安全

上图给出了RTDP架构中,四个开源平台覆盖了端到端数据流转链路,并且在每个节点上都有对数据安全各个方面的考量和支持,确保了实时数据管道端到端的数据安全性。

另外,由于Moonbox成为了面向应用层数据访问的统一入口,因此基于Moonbox的操作审计日志可以获得很多安全层面的信息,可以围绕操作审计日志建立数据安全预警机制,进而建设企业级数据安全系统。

1.3.3 开发运维

1)运维管理

  • 实时数据处理的运维管理向来是个痛点,DBus和Wormhole通过可视化UI提供了可视化运维管理能力,让人工运维变得简单。
  • DBus和Wormhole提供了健康检查、操作管理、Backfill、Flow漂移等RESTful服务,可以基于此研发自动化运维系统。

2)监控预警

  • DBus和Wormhole均提供可视化监控界面,可以实时看到逻辑表级的吞吐和延迟等信息。
  • DBus和Wormhole提供了心跳、Stats、状态等RESTful服务,可以基于此研发自动化预警系统。

二、模式场景探讨

上一章我们介绍了RTDP架构各个技术组件的设计架构和功能特性,至此读者已经对RTDP架构如何落地有了具体的认识和了解。那么RTDP架构可以解决哪些常见数据应用场景呢?下面我们会探讨几种使用模式,以及不同模式适应何种需求场景。

2.1 同步模式

2.1.1 模式描述

同步模式,是指只配置异构数据系统之间的数据实时同步,在流上不做任何处理逻辑的使用模式。

具体而言,通过配置DBus将数据从数据源实时抽取出来投放在Kafka上,然后通过配置Wormhole将Kafka上数据实时写入到Sink存储中。同步模式主要提供了两个能力:

  • 后续数据处理逻辑不再执行在业务备库上,减少了对业务备库的使用压力
  • 提供了将不同物理业务备库数据实时同步到同一物理数据存储的可能性

2.1.2 技术难点

具体实施比较简单。

IT实施人员无需了解太多流式处理的常见问题,不需要考虑流上处理逻辑实现的设计和实施,只需要了解基本的流控参数配置即可。

2.1.3 运维管理

运维管理比较简单。

需要人工运维。但由于流上没有处理逻辑,因此容易把控流速,无需考虑流上处理逻辑本身的功耗,可以给出一个相对稳定的同步管道配置。并且也很容易做到定时端到端数据比对来确保数据质量,因为源端和目标端的数据是完全一致的。

2.1.4 适用场景

  • 跨部门数据实时同步共享
  • 交易数据库和分析数据库解耦
  • 支持数仓实时ODS层建设
  • 用户自助实时简单报表开发
  • 等等

2.2 流算模式

2.2.1 模式描述

流算模式,是指在同步模式的基础上,在流上配置处理逻辑的使用模式。

在RTDP架构中,流上处理逻辑的配置和支持主要在Wormhole平台上进行。在同步模式的能力之上,流算模式主要提供了两个能力:

  • 流上计算将批量计算集中功耗分散在流上增量计算持续功耗,极大降低了结果快照的时间延迟
  • 流上计算提供了跨异构系统混算的新的计算入口(Lookup)

2.2.2 技术难点

具体实施相对较难。

用户需要了解流上处理能做哪些事,适合做哪些事,如何转化全量计算逻辑成为增量计算逻辑等。还要考虑流上处理逻辑本身功耗和依赖的外部数据系统等因素来调节配置更多参数。

2.2.3 运维管理

运维管理相对较难。

需要人工运维。但比同步模式运维管理更难,主要体现在流控参数配置考虑因素较多、无法支持端到端数据比对、要选择结果快照最终一致性实现策略、要考虑流上Lookup时间对齐策略等方面问题。

2.2.4 适用场景

  • 对低延迟要求较高的数据应用项目或报表
  • 需要低延迟调用外部服务(如流上调用外部规则引擎、在线算法模型使用等)
  • 支持数仓实时事实表+维度表的宽表建设
  • 实时多表融合、分拆、清洗、标准化Mapping场景
  • 等等

2.3 轮转模式

2.3.1 模式描述

轮转模式,是指在流算模式的基础上,在数据实时落库中,同时跑短时定时任务在库上进一步计算后,将结果再次投放在Kafka上跑下一轮流上计算,这样流算转批算、批算转流算的使用模式。

在RTDP架构中,可以利用Kafka->Wormhole->Sink->Moonbox->Kafka的整合方式实现任何轮次任何频次的轮转计算。在流算模式的能力之上,轮转模式提供的主要能力是:理论上支持低延迟的任何复杂流转计算逻辑。

2.3.2 技术难点

具体实施难。

Moonbox转Wormhole能力的引入,比流算模式进一步增加了考虑的变量因素,如多Sink的选择、Moonbox计算的频率设定、如何拆分Wormhole和Moonbox的计算分工等方面问题。

2.3.3 运维管理

运维管理难。

需要人工运维。和流算模式比,需要更多数据系统因素的考虑、更多参数的配置调优、更难的数据质量管理和诊断监控。

2.3.4 适用场景

  • 低延迟的多步骤的复杂数据处理逻辑场景
  • 公司级实时数据流转处理网络建设

2.4 智能模式

2.4.1 模式描述

智能模式,是指利用规则或算法模型来进行优化和增效的使用模式。

可以智能化的点:

  • Wormhole Flow的智能漂移(智能化自动化运维)
  • Moonbox预计算的智能优化(智能化自动化调优)
  • 全量计算逻辑智能转换成流式计算逻辑,然后部署在Wormhole + Moonbox(智能化自动化开发部署)
  • 等等

2.4.2 技术难点

具体实施在理论上最简单,但有效的技术实现最难。

用户只需要完成离线逻辑开发,剩下交由智能化工具完成开发、部署、调优、运维。

2.4.3 运维管理

零运维。

2.4.4 适用场景

全场景。

自此,我们对“如何设计实时数据平台”这个话题的讨论暂时告一段落。我们从概念背景,讨论到架构设计,接着介绍了技术组件,最后探讨了模式场景。由于这里涉及到的每个话题点都很大,本文只是做了浅层的介绍和探讨。后续我们会不定期针对某个具体话题点展开详细讨论,将我们的实践和心得呈现出来,抛砖引玉,集思广益。如果对RTDP架构中的四个开源平台感兴趣,欢迎在GitHub上找到我们,了解使用,交流建议。

作者:卢山巍

来源:宜信技术学院

查看原文

Harley 收藏了文章 · 2020-12-31

走出舒适圈,10份技术图谱+7大项目源码,这才是你该收藏的

最近有好多朋友问我,家里的孩子要工作了,或者工作一直没什么起色,都是程序员这一行的,怎么差距就这么大,想想也是,从外包走到现在,也有10年的时间了,回顾自己工作的这10年,总结一句话就是:

走出舒适圈,保持刻意学习,才有成为架构师的可能。

如今技术发展的速度非常快,接下来你该从哪些地方开始自己的刻意练习呢?给你 5 点建议:

1、读懂框架源码

框架它本身就是一个工具,但是作为高级工程师与架构师这个是你必须要学会和掌握的。让你读源码并不是真的让你读懂它,而是要理解它底层实现的原理,培养起框架思维和自定义框架的能力

2、掌握分布式架构设计

面对互联网项目高并发、高可用、高性能的特点,分布式系统的架构能力是你必须要掌握的。面对亿级的数据系统架构如何迎接高并发流量的挑战,这是作为架构师,必须要考虑的问题。

3、深刻搞懂算法和计算机底层原理

项目性能瓶颈一部分是要通过底层调优实现的,而一些高级的内核和引擎开发往往是需要一些精良算法和对底层原理的理解才能完成的, 只有掌握这些,才能多一些角度进行项目优化。

并且,去一些大厂面试,也是100%都会面到的。就算你现在的工作还用不到算法和底层原理,但如何以后想要进BAT这样的的大厂,还是要尽快学习起来。

4、掌握数据库调优和选型
架构最难的部分就是存储,如何用MySQL支撑起海量的数据,并保持高响应性,如何让数据库持续的稳定运行,都是必须掌握的技能。不管是现在主流的 MySQL,MongoDB、还是大数据 Hadoop 生态圈中的 HBase 等等。

掌握这些数据技术让你不管是面试还是技术方案选型,都可以锦上添花,并且能够应对向大数据延展的业务需求。

5、性能调优与解决方案

对 Tomcat、Nginx 等主流应用服务器能够进行深入使用,通过性能调优能够支撑业务的并发。一些经典场景化问题给出解决方案,如SSO、即时通讯、订单系统、日志系统等等,并能够在面对众多方案时知道如何进行选择。

「关于如何学习?」

这期间,我也带过一些工作不久的新人,他们的普遍问题是:工作那么忙,根本没时间学习。

确实是这样,互联网的节奏太快了,有时下班很晚,到家只想休息。

我个人建议大家利用好下班之后的 2 个小时,每天 2 个小时的学习雷打不动,几年以后你的能力和薪酬一定可以得到很大提升。

主要包括几个方面:学习+实践

其实这也是针对计算机这一行的弊端进行的:学习的很快,但是忘记的更快,如果没有动手操作的话,因此,也给大家整理了一些学习文档和7个项目实践

来看

1、开源框架

框架相关的Mybatis、Spring、SpringMVC这些技术点

2、JVM调优

3、Mysql+并发编程+Netty+Linux+Tomcat

4、高并发、高性能

  • MongoDB

  • Redis

  • Zookeeper

  • Nginx

  • 消息中间件等

5、微服务系列

其它的技术,小天就先不说了,Java程序员若能将以上的技术收入囊中,厂不厂的,对你来说已经没那么重要了。

总而言之,技术能力才是高薪的敲门砖。

最后

我这里整理了以上所有核心技术知识的PDF,还收集一套最新的大厂面试资料,以及系统面试题,需要的朋友帮忙转发一下文章,后台私信【面试】免费领取!

有了知识点之后,下面就是项目实战了,这里总结了7个项目,需要上面的文档以及下面项目的,关注+转发后,私信“资料”即可查看获取方式

SmartAdmin

我们开源一套漂亮的代码和一套整洁的代码规范,让大家在这浮躁的代码世界里感受到一股把代码写好的清流!同时又让开发者节省大量的时间,减少加班,快乐工作,热爱生活。SmartAdmin 让你从认识到忘不了,绝对是你最想要的!

litemall

有一个小商场系统,Spring Boot后端 + Vue管理员前端 + 微信小程序用户前端 + Vue用户移动端。

Timo

TIMO后台管理系统,基于SpringBoot2.0 + Spring Data Jpa + Thymeleaf + Shiro 开发的后台管理系统,采用分模块的方式便于开发和维护,支持前后台模块分别部署,目前支持的功能有:权限管理、部门管理、字典管理、日志记录、文件上传、代码生成等,为快速开发后台系统而生的脚手架!

技术选型

  • 后端技术:SpringBoot + Spring Data Jpa + Thymeleaf + Shiro + Jwt + EhCache
  • 前端技术:Layui + Jquery + zTree + Font-awesome

mall4j

一个基于spring boot、spring oauth2.0、mybatis、redis的轻量级、前后端分离、防范xss攻击、拥有分布式锁,为生产环境多实例完全准备,数据库为b2b2c设计,拥有完整sku和下单流程的完全开源商城。

项目致力于为中小企业打造一个完整、易于维护的开源的电商系统,采用现阶段流行技术实现。后台管理系统包含商品管理、订单管理、运费模板、规格管理、会员管理、运营管理、内容管理、统计报表、权限管理、设置等模块。

web-flash

基于Spring Boot+Vue的后台管理系统,权限管理,字典,配置,定时任务,短信,邮件,根据excel模板导出,cms内容管理,手机端h5,IDEA 代码生成插件。

SPTools

一个基于SpringBoot、JPA、Shiro的后台管理系统,单体架构,依赖少,极易上手,后端开发的福利。最重要的是还附带免费小程序以及微服务版本,可自行选择。

内置功能

  • 组织机构:机构管理、用户管理、角色管理、行政区域。
  • 系统监控:系统日志、在线用户,后期会慢慢追加完善。
  • 应用管理:任务调度、邮件管理、图片管理、文章管理、打卡任务、数据查询、人工智能,每个模块只需要你稍作修改就可以打造成一个项目了。
  • 系统管理:敏捷开发、系统菜单、全局配置、在线代码编辑器,小伙伴们只需要设计好表结构,三秒钟就能撸出一个增删查改的模块。

小结

其实无论是什么,文档、视频、项目,所有的这一些,只是为了能够学习的更加扎实,能够找到一份满意薪资的工作,但是更多的是你在学习路上的坚持

加油吧程序员,需要上面资料的,关注公众号:Java架构师联盟

查看原文

Harley 收藏了文章 · 2020-12-31

技术选型背后的思考

技术选型背后的思考

笔者在工作经历中曾多次遇到关于技术选型的问题,而每一次的技术选型都无一例外的纠结、反复。经常出现的现象是,在项目推进的过程中多次反复修改技术选型,客观上造成了效率的降低,而当最终选定某一个选型时,又觉得这个结果似乎是显而易见的。为了避免反复纠结造成效率降低,笔者觉得有必要总结下选型中常见的思考方式,方便以后参考。
每一次技术选型都是在特定的需求场景下,结合各种各样的主观、客观因素,最初一个最优的选择。很多人觉得技术选型时只要选定的技术产品满足业务需求就可以了,但笔者经过多次观察发现,满足场景需求只是一个前提条件,真正令人纠结的点往往在需求本身之外。
下面按照三个部分梳理了选型中要思考的几个方向:技术特性、技术管理和取舍之道。

1 技术特性

了解各个技术选型的技术特性是一次选型的开始,也是必须做好的一部分工作。笔者经验性的发现,往往选型过程中的反复、纠结,都是由于一开始并没有真正体系化的将每一个选型理解透彻。还是延续上面的说法:了解一个技术是否能够满足场景需求只是一个前提条件,除此以外还要了解的还有很多。下面笔者将结合个人经验,一一说明。

1.1 满足场景需求

这个点其实是老生常谈了,做技术选型当然要首先考虑各个选型是否能够满足场景需求。但是这里面有几个容易被大家忽略的点,值得一提:

  • 了解能否满足需求,更要了解是如何满足需求的
    对于一些相对简单的需求,可能会有很多技术选型都可以满足。但是实现方式细节上的差异,会导致后期场景迭代过程中引入天翻地覆的变化。据一个比较蠢的例子,某团队需要一个消息队列,那么到底用kafka还是RocketMQ呢?消息队列是一个非常简单的需求,但是不同使用场景的迭代过程中的对消息队列的追加需求会越来越多。能否持久化、是否支持EXACTLY-ONCE模式、能否按时间戳复现消息、读多还是写多、是否支持事务等等,这些都会影响选型上的倾向性。
  • 很多时候,所有技术选型都能满足“最低需求”,但是没有一个技术选型能“完美的满足需求”
    需求不明确的初期,往往会发现:世界这么小,却能找到这么多满足的要求的技术。但需求逐渐细化后,又会发现:天下这么大,竟没有一个技术选型能完美满足所有需求。遇到这种问题,其实思路就两种:一种是“忍”,体现在凑合用或者绕开不完美的部分上;一种是“干”,那就是想办法进行开发。

1.2 完善的技术体系

当一个技术选型基本满足了场景需求后,作为一个技术人员,还要思考很多场景之外的问题。比如:

  • 如何监控、运维
    一个优秀的技术选型会在设计阶段就将运维和监控等考虑在内,方便技术使用者可以清晰的了解到系统的运行状态,方便问题的排查。这些配套的工具是否完善对于一个技术人员来说是至关重要的。个人觉得Flink之所以如此风靡,除了它的技术层面的成就外,也离不开它原生完备的监控运维可视化工具。
  • 周边技术体系
    一个大型的技术选型往往绑定了很多其他的小的技术选型,比如Flink绑定了RocksDB,很多google的开源技术都绑定了protobuf等。除了关注技术选型主体外,还要注意分析下主体以外绑定的其他选型是否能够很好的融入已有的技术体系。

1.3 机器资源评估

技术选型上线后,必然会引入机器资源的开销。不同的选型在性能上的表现可能千差万别。如:rt、cpu、内存占用、网络IO、磁盘IO、存储开销。这里重点要提到的是,上述指标不能单一的看某一项指标,而是要整体评估所有指标。
举例说明:
假设要对两个数据存储技术进行选型。线上一台机器有4T磁盘、500G内存、96核CPU、2GB/s网络带宽。技术选型A 磁盘占用1T,内存占用200G,满负载运行时CPU 40%,网络IO 1GB/s。技术选型B 磁盘占用0.5T,内存占用100G,满负载运行时CPU 20%,网络IO 2GB/s。
单从存储开销、内存占用、CPU上来看,B选型完胜。但是由于选型网络IO做的不好,导致IO成为瓶颈。如果考虑到docker混布的话,一台机器可以布署两个A实例,但是却只能布署一个B实例。由于网络IO的瓶颈效应,导致选型B的节省的存储开销无法体现在节省机器资源上。

1.4 技术产品的稳定性

要不要做第一个吃螃蟹的人?这是一个问题。
一千个读者眼中有一千个哈姆雷特,但是一千个开发工程师在上面这个问题上却只能给出两种答案:要或不要。新兴技术总是吸引人眼球,并勾引着技术人员的好奇心,让后者有一种先睹而后快的冲动;但是内心理性的小人又在反复揣摩,为了满足一时的好奇心搞出个故障被扣工资甚至跑路,把孩子的奶粉钱都搞没了到底值不值得。一个技术选型是否有长时间稳定运行的先例,这一点对于选型者至关重要,但是如果所有人都因这么想而不愿意尝试新技术,那又何来的长时间稳定运行的先例呢?
个人冒昧分析,抉择的关键在于业务场景是新兴业务或是长期稳定业务、选型失败的后果是否严重、新技术提供的增量价值是否能打动使用者等因素,这里因业务而已,不做结论性说明。

2 管理模式

在工作中完成一次技术选型,绝不能简单的仅仅从纯技术角度出发思考。一次看似偶然的选型会给后续工作带来方向性的影响,这里的影响指的不光是技术层面,更多的是管理层面。这就如同在公司一次公开的项目招标中,考虑绝不仅仅是解决方案本身的优劣,更重要的考量方案的成本是否符合预期,方案提供方的实力、诚信度,甚至还要从商业模式上去思考未来的合作方式是什么,等等。而这一切,都能在一次技术选型的过程中,得以体现。
下面就从几个主要阐述下选型中遇到的常见问题。

2.1 时间成本与人力成本

再决定技术选型时,除了机器资源等成本以外,一定不要忘记了,作为一个团队投入的还有时间成本和人力成本。在一些争分夺秒的项目中,哪种选型能够达到快速迁移的目的,几乎就可以确定哪种选型会胜出。如果不得不使用一个复杂的技术,而时间有十分紧迫,那么唯一的方式就是通过加大人力投入来实现。
是什么决定投入成本的规模呢?是收益。不仅仅是完成一个项目的短期收益,更要衡量用该技术手段带来的长远收益。因此会有一个有趣的现象,有时通过技术选型就能看出一个业务线的盈利能力。

2.2 维护团队

一个技术选型要长期、稳定、完全的在生产上服务,离不开背后的维护团队。一个维护团队小则可以对使用过程中遇到的疑难问题进行解答,大则可以临危受命解决技术选型引入的线上故障。因此,在进行技术选型时,要考虑如下几点:

  • 是否有维护团队,团队是否稳定
    在对比同是来源于公司内部的技术选型时,要调研技术选型背后的支持团队是否仍然稳定存在。一个稳定的支持团队至少说明了这个技术选型对公司十分重要,因此它出现的任何问题都会得到高度重视。
  • 维护团队的技术能力与合作意愿
    由于不同公司各种组织架构划分模式,导致并不是所有的维护团队都是具有强烈的合作意愿的。一般情况下,成熟稳定技术的维护团队在解决稳定性问题和技术答疑上积极性较高,而在支持新feature和使用教学上热情有限;新推广技术的维护团队在支持各种新feature的工作上有很强的合作意愿。
  • 维护团队与自身团队关系是否密切
    维护团队和自身团队的利益绑定关系是否牢靠,leader之间是否同出一门,这等等因素都会影响日后寻求帮助时的便利性。此间细节,往往会在不经意间影响业务的稳定性和迭代效率。

2.3 新feature的开发模式

在业务迭代过程中经常会出现对技术上新的feature需求,此时若需要在选型上进行开发,则需要寻找到一种技术开发团队的有效合作方式,常见合作方式有如下:

  • 提需求
    这种模式就是简单的提需求,由维护团队来开发,极大降低人力成本,但是可控性不强,如果和未还团队之间没有较强的利益绑定关系,很容易出现时间拖延的情况。同时,这种模式带来的另外一个问题就是,自身团队的成员对技术了解十分有限,难以获得成长。
  • 共建
    这种方式多见于新推广技术。业务团队提供具体的业务场景,技术团队进行技术抽象与打磨。在合作的同时,业务团队的成员也有机会参与到技术开发中,提升技术储备。这种方式是共赢的,但是对时机和人事环境的要求相对苛刻。
  • 自主研发
    可控性最强,团队技术储备增长最快。但需考虑是否存在重复建设,是否存在增量价值,能否孵化出有亮点的结果产出。

在笔者实际工作经历中曾遇到过如下一次选型。
选型一:基本满足业务需求,技术成熟,很多业务线都在用,但是技术内部对外是一个黑盒,而且是一个与本团队关系疏远的团队在维护
选型二:需要一定的开发才能满足业务需求,技术相对成熟,维护团队与本团队是兄弟团队
选型三:完全满足业务需求,是一个新型技术,团队有能力自主研发,但周边设施并不是十分完善,与选型一存在大量的重复建设
在选型过程中经历了各种纠结,最终由于不能重复建设而放弃了选型三,由于兄弟团队无法支持定制开发而放弃了选型二,归根结底还是选择了选型一。

3 取舍之道

选型的核心在于取舍,取舍也是体现一个技术人员技术视野和综合判断力的关键决定。笔者结合自身的一些思考,提出了以下经验性结论。

3.1 技术特性的取舍

如1.1节中提到的,很多时候会出现没有任何一个技术选型“完美满足”业务需求。此时除了进行定制开发一种思路外,还可以选择绕开问题,曲线超车。这里的“绕开”并不是逃避,而是集中把精力放在解决关键问题上,而对于不那么关键的瑕疵,可以有多种方式解决。
举个例子,加入现在有一个集群A,它进行计算后会将结果发往下游集群B,集群B收到计算结果后会将结果写入数据库。我们要在集群A到集群B的通信方式上进行一次选型。直观上,我们需要一个消息队列来连接集群A和集群B,集群A是生产者,集群B是消费者,并且需要考虑如何保证集群B的各个机器之间读到的消息不能重复。但是,如果我们手边并没有合适的消息队列选型,我们该怎么做呢?有两种方法可以推进解决这个问题:

  • 继续寻找/定制开发
    我们可以继续寻找合适的消息队列选型,或者选择自己开发一套合适的消息队列。这样时间成本上和人力成本上必须加大投入。
  • 绕开问题
    消息队列提供的能力不光是通信,还有持久化、保证顺序、EXCECTLY-ONCE等能力。但是假如我们业务场景并不需要这些附加能力,而是仅仅需要“通信”这一个功能,那么其实我们完全可以使用“rpc单向调用”来完成通信。集群A发送rpc请求,集群B收到请求后立刻返回一个空结果(反正集群A也不关心返回内容),然后进行些数据库操作。

上面提到的案例并不是鼓励大家绕开问题,事实上,如果所有的人都绕开问题,就不会出现如今这么多优秀的技术选型。我们要做的是:把精力放到核心问题上。如果开发一个消息队列是我们要解决的核心问题,那我们绝不能绕开它,而是要知难而上;但如果我们是要完成一次业务架构的选型,就不应该把过多的注意力放在细枝末节上。

3.2 技术管理的取舍

由于笔者并没有实际参与过管理岗位的工作,在这里只能从一个被管理者的视角给出一些观点。在工作中,解决历史遗留问题(俗称填坑),是最没有成就感的工作,而且“日后填坑”的成本远高于“当时填坑”。日积月累,只能通过“爆破”(整体重构)这种巨额成本的工作来解决历史遗留问题。看上去破旧不堪的系统仍然继续在线上运转,每天耗费大量人力用于维护系统正常,这些都是多次选型不慎引入的长久隐患。因此,笔者认为,在技术选型时,维护团队的稳定性、技术产品的稳定性等因素的重要性要远大于较低的迁移成本的重要性。

如果感兴趣,欢迎关注微信技术公众号

clipboard.png

查看原文

Harley 赞了文章 · 2020-12-31

技术选型:为什么批处理我们却选择了Flink

最近接手了一个改造多平台日志服务的需求,经过梳理,我认为之前服务在设计上存在缺陷。经过一段时间的技术方案调研,最终我们决定选择使用 Flink 重构该服务。

目前重构后的服务已成功经受了国庆节流量洪峰的考验,今日特来总结回顾,和大家分享一下经验。

业务需求及背景

在了解改造服务的需求前,我们首先要明确,要解决什么问题以及目前的服务是如何解决的。

当前的业务逻辑还是比较清晰的:

  • 采集同一时段不同数据源的日志;
  • 对采集的数据进行处理;
  • 将处理后的数据上传到指定位置,供客户下载。

我们面临的痛点和难点:

  • 日志的数据量比较大:每小时未压缩的日志数据量有 50 多个 G,节假日等特殊时间节点,日志量会翻倍。
  • 目前服务使用单机进行处理,速度比较慢,扩容不方便。
  • 目前服务处理数据时需要清洗字段,按时间排序,统计某字段的频率等步骤。这些步骤都属于 ETL 中的常规操作,但是目前是以代码的形式实现的,我们想以配置形式减少重复编码,尽量更加简单、通用。

方案1:我们需要一个数据库吗?

针对以上业务需求,有同学提出:“我们可以把所有原始数据放到数据库中,后续的 ETL 可以通过 SQL 实现。”

如果你一听到"数据库"想到的就是 Pg、Mysql、Oracle 等,觉得这个方案不具有可行性,那你就错了。数据库的类型和维度是非常丰富的,如下图所示:

数据库行业全景图

按业务负载特征,关系型数据库可分为 OLTP 数据库(交易型)和 OLAP 数据库(分析型) :

  • OLTP,Online Transaction Processing。OLTP 数据库最大的特点是支持事务,增删查改等功能强大,适合需要被频繁修改的"热数据"。我们耳熟能详的 Mysql、Pg 等都属于这一类。缺点就是由于支持事务,插入时比较慢。拿来实现我们的需求显然是不合适的。
  • OLAP,Online Analytical Processing,数据分析为主。不支持事务,或者说是对事务的支持有限。OLAP 的场景是:大多数是读请求,数据总是以相当大的批(> 1000 rows)进行写入,不修改已添加的数据。

方案 1 小结

OLAP 的使用场景符合我们的需求,为此我们还专门去调研了一下 ClickHouse。但是有一个因素让我们最终放弃了使用 OLAP。请注意,数据库存储的数据都是二维的,有行和列两个维度。但是日志只有行一个维度。如果说为了把日志存入数据库把每行日志都切分,那统计字段的需求也就顺手实现了,又何必存到数据呢?

所以,OLAP 使用场景隐含的一个特点是:存入的数据需要被多维度反复分析的。这样才有把数据存入数据库的动力,像我们当前的需求对日志进行简单的变形后仍旧以文本日志的形式输出,使用 OLAP 是不合适的。

方案2:Hive 为什么不行?

看到这,熟悉大数据的同学可能会觉得我们水平很 Low,因为业务需求归根到底就是三个字:批处理。

那我们为什么第一时间没有考虑上大数据呢?

大数据处理流程

大数据确实如雷贯耳,但现在我们的日志处理这块大部分都是用 Golang 实现的,团队内的其他业务用了 Python、Lua、C,就是没有用过到 Java。而目前大数据都是基于 JVM 开发的。Golang 调用这些服务没有一个好用的客户端。

所以基于团队目前的技术储备,大数据才没有成为我们的首选。但是从目前的状况来看大数据是最优解了。那么我们该选用大数据的什么组件实现需求呢?

放弃使用数据库直接使用 HDFS 存储日志文件,应该是毋庸置疑的。

我们需求是离线批处理数据,对时效性没有要求,MapReduce 和 Hive 都能满足需求。但是 MapReduce 与 Hive 相比,Hive 在 MapReduce 上做了一层封装并且支持 SQL。看起来 Hive 是非常合适的。

那为什么最终放弃了 Hive 呢?

  • 机器资源问题。公司其他团队已经有一套 HDFS 的设施,只用来做存储,Hadoop 的 MapReduce 这个组件根本没跑起来。那套 HDFS 部署的机器资源比较紧张,他们担心我们使用 MapReduce 和 Hive 跑计算,会影响现在 HDFS 的性能; 我们想审批一批新的机器,重新使用 Ambari 搭建一套 Hadoop,却被告知没那么多闲置的机器资源。而且我们即便申请下来了机器,只跑目前服务也跑不满,机器资源大部分也会被闲置,也有浪费资源的嫌疑。
  • 存储分离是趋势。在调研中我们发现,像 Hadoop 这样把存储和计算放到一起的已经比较"落伍"了。Hadoop 存储分离,需要修改源码,目前没有开源实现,只是云厂商和各个大数据公司有相关商业产品。从这个角度讲,即便我们自己搞定了机器资源搭一套 Hadoop,也只不过是拾人牙慧罢了。

大数据生态图

方案 2 小结

再合适的技术方案不能落地也是空谈。但是技术方案想要落地时,已经不是一个单纯的技术问题了,资源限制,团队限制等都需要考虑在内。

一个优秀的技术方案立足于解决当下的问题,并且能放眼未来勾画蓝图,这样大家觉得 "有利可图",才愿意跟你一起折腾。

方案3:为什么我们放弃了 Spark?

通用的计算引擎

虽然使用 HDFS 的团队不赞成在他们的机器上跑 Hive,但是我们把日志数据存到他们的 HDFS 上还是没问题的。在已知 "存储和分离是趋势" 是前提的基础下,"我们到底需要什么" 这个问题已经有答案了。

我们需要的是一个通用的计算引擎。存储已经剥离给 HDFS 了,所以我们只需要找一个工具,帮我们处理 ETL 就可以了。Spark 和 Flink 正是这样的场景。

Spark 与 Flink 初次交锋

Spark 和 Flink 之间,我们毫不犹豫地选择了 Spark。原因非常简单:

  • Spark 适合批处理。Spark 当初的设计目标就是用来替换 MapReduce。而 Spark 流处理的能力是后来加上去的。所以用 Spark 进行批处理,可谓得心应手。
  • Spark 成熟度高。Spark 目前已经发布到 3.0,而 Flink 尚在 Flink 1.x 阶段。Flink 向来以流处理闻名,虽然被国内某云收购后开始鼓吹 "流批一体",但是线上效果还是有待检验的。
  • Scala 的加持。Spark 大部分是用 Scala 实现的。Scala 是一门多范式的编程语言,并且与 Haskell 有很深的渊源。Haskell 是一门大名鼎鼎的函数式编程语言。对于函数式编程语言,想必大多数程序猿都有一种 "虽不能至,然心向往之" 的情结。现在使用 Spark 能捎带着耍一耍函数式编程语言 Scala,岂不妙哉?

Scala

挥泪斩 Spark

前文已经交代过了,我们否决掉 Hive 的一个重要因素是没有足够的机器资源。所以我们把 Spark 直接部署到云平台上。

对于我司的云平台要补充一些细节。

我们的云平台是基于 K8S 二次开发的,目前还在迭代当中,因此"Spark on K8S" 的运行模式我们暂时用不了。在这样的情况下,我们采用了 "Spark Standalone" 的模式。Standalone 模式,也就是Master Slaver 模式,类似于 Nginx 那样的架构,Master 节点负责接收分发任务,Slaver 节点负责"干活"。

等到我们在云平台上以 "Spark Standalone" 模式部署好了,跑了几个测试 Case 发现了新问题。我们的云平台与办公网络是隔离的,如果办公网络想访问云平台的某个 Docker 容器,需要配置域名。而 Spark 的管理页面上很多 URL 的 domain 是所在机器的 IP,容器的 IP 是虚拟 IP,容器重启后IP 就会改变。具体如图:

部署在云平台的 spark

Spark 的管理平台非常重要,因为能从这上面看到当前各个节点运行情况,任务的异常信息等,现在很多链接不能访问,不利于我们对 Spark 任务进行问题排查和调优。基于这个原因,我们最终放弃了 Spark。

方案 3 小结

Spark 你真的很优秀,擅长批处理,如此成熟,还有函数式的基因 。。。这些优点早让我倾心不已。

Spark 你真的是个好人,如果不是云平台的限制,我一定选择你。

Spark,对不起。

方案4:Flink,真香!

给 Spark 发完好人卡后,我们看一看新欢 Flink。不客气的说,Flink 初期时很多实现都是抄的 Spark,所以二者的很多概念相似。所以 Flink 同样有 Standalone 模式,我们在部署阶段没遇到任何问题。

在跑了几个 Flink 测试 Case 后,我们由衷的感叹 Flink 真香。

放弃 Spark 时我们的痛点在于 "部署在云平台上的 Spark 服务的管理界面很多功能无法使用",而 Flink 的管理平台完全没有这个问题。除此之外,Flink 管理平台的 "颜值" 和功能都是 Spark 无法比拟的。

管理平台颜值对比

Spark管理平台页面

Flink管理平台页面

对比之下,Spark 的页面完全是个"黄脸婆"。

Flink 管理平台功能

由于 Spark 的功能很多不能使用,所以就不重点和 Flink 做比较了。这里只说 Flink 几个让人眼前一亮的功能。

  • 完善的 Restful API

部署了 Flink 或 Spark 服务后,该如何下发计算任务呢? 一般是通过 bin 目录下的一个名称中包含 submit 的可执行程序。那如果想把 Flink 或 Spark 做成微服务,通过 http 接口去下发任务呢?

Spark1.0 的时候支持 http,2.0时这个功能基本上废掉了,很多参数不支持了,把 http 这个功能交由 jobService 一个第三方开源组件去实现。这个 jobService 的开源组件对云平台的支持也非常不友好。所以在我们看来,Spark 通过 Http 下发任务的路子基本被堵死了。

反观 Flink,管理平台的接口是 Restful 的,不仅支持 Http 下发计算任务,还可以通过相关接口查看任务状态和获取异常或返回值。

  • 强大的任务分析能力

Flink 的任务分为几个不同的阶段,每个不同的阶段有不同的颜色。这样仅从颜色就可以判断出当前 Flink 任务执行的大致情况。如下图:

Flink管理平台页面

在任务详情页面,会有任务分解图和任务执行耗时表格,这两个结合起来能够知道当然 Flink 任务是如何分解的,是否出现数据倾斜的情况,哪个步骤耗时最多,是否有优化的空间。

管理平台页面

这就是做批处理技术选型时候的心路历程,随笔记了下来,希望对大家有所帮助。

推荐阅读

如何选择适合自己网站的防盗链

HTTP/3 来了,你了解它么?

查看原文

赞 8 收藏 7 评论 0

Harley 收藏了文章 · 2020-12-30

Impala--实战之整合HBASE&JDBC&性能优化(三)

Impala与HBase整合

  • impala可以通过Hive外部表的方式和Hbase进行整合

-步骤一:创建HBASE表,添加数据

create 'test_info','info';
put 'test_info','1','info:name','similarFish';
put 'test_info','2','info:name','fish';

-步骤二:创建hive表

create external table test_info(
key string,
name string
)
row format serde 'org.apache.hadoop.hive.hbase.HbaseSerDe'
stored by 'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
with serdeproperties("hbase.columns.mapping"="row_key:key,info:name")
tblproperties("hbase.table.name"="test_info")

-步骤三:刷新impala表

invalidate metadata 

注:本质是hive元数据库建立一张表去映射HBASE数据库的表的元数据,这样impala在和hive共用元数据库时也能读取到这张表,以hive作为跳板去访问hbase

Impala JDBC

  • 配置
impala.driver=org.apache.hive.jdbc.HiveDriver
impala.url=jdbc://hive2://hdp01:21050/;auth=noSasl
impala.username=
impala.password=

注:尽量使用PreparedStatement执行SQL语句,因为性能上要好于Statement,而且Statement存在查不出数据的情况

Impala性能优化

  • SQL优化,使用之前调用执行计划
1,执行SQL前对SQL进行一个分析,使用explain sql(分析哪个步骤需要内存多,指定机器),profile(为什么这次的SQL执行的这么慢)
2,哪些SQL会导致数据倾斜,保证谓词下推的成功
3,多层嵌套,select * 都是可以优化的
  • 选择合适的文件格式进行存储
  • 避免产生很多小文件,少用insert,如果有其他程序产生的小文件,可以使用中间表
  • 使用合适的分区技术,根据分区粒度测算
  • 使用compute stats进行表信息搜集
  • 网络IO的优化:
      1,避免把整个数据发送到客户端(执行完了直接落地,在本地查看执行结果)
      2,尽可能的做条件过滤
      3,使用limit字句
      4,输出文件时,避免使用美化输出
  • 使用profile输出底层信息计划,再做相应的环境优化
查看原文

Harley 收藏了文章 · 2020-12-30

技本功|Hive优化之Spark执行引擎参数调优(二)

Hive是大数据领域常用的组件之一,主要是大数据离线数仓的运算,关于Hive的性能调优在日常工作和面试中是经常涉及的的一个点,因此掌握一些Hive调优是必不可少的一项技能。影响Hive效率的主要有数据倾斜、数据冗余、job的IO以及不同底层引擎配置情况和Hive本身参数和HiveSQL的执行等因素。本文主要结合实际业务情况,在使用Spark作为底层引擎时,通过一些常见的配置参数对报错任务进行调整优化。

下面从两个方面对复杂任务的优化:

Spark资源参数优化
主要针对Spark运行过程中各个使用资源的地方,通过调节资源相关参数,来优化资源使用的效率,从而提升Spark作业的执行性能。例如:num-executors、executor-memory、executor-cores等。

Shuffle相关参数调优
主要针对spark运行过程中的shuffle,通过调节参数,提高shuffle的执行效率,从而提升spark作业的执行性能。例如:spark.shuffle.memoryFraction,spark.sql.shuffle.partitions等。

案例1
复杂任务执行失败,大约有400行sql,较为复杂,join聚合函数操作较多。手动重试任务后仍然报错。

查看任务报错日志
image.png

分析关键信息

Exception in thread "broadcast-exchange-0" java.lang.OutOfMemoryError: Not enough memory to build and broadcast the table to all worker nodes. As a workaround, you can either disable broadcast by setting 
spark.sql.autoBroadcastJoinThreshold to -1 or increase the spark driver memory by setting spark.driver.memory to a higher value

得出结论
当前所有的工作节点均没有足够的内存去build并且广播表,建议处理方法:将广播置为无效或者增加spark的driver memory。

优化效果
经过对比测试验证,在同时调大excutor内存和driver内存后,任务可以成功运行。单独调大driver或excutor内存,任务运行依然失败。

Q1:什么情况下应将广播设置为无效?
根据官网文档对该参数的描述可知:其默认值为10M,意味着执行join时,这张表字节大小在10M内可以自动广播到所有工作节点。将表广播到其他工作节点,会减少shuffle的过程,提升效率。如果在内存足够并且数据量过多的情况下,可以将适当提高该参数值作为一种优化手段。如果在表都很大的情况下,建议将自动广播参数置为无效。将参数值设置为-1时会禁用自动广播。
image.png

案例2 
某个任务已经运行了40多个小时,自动重试了3次,一直处于阻塞状态。

查看异常任务SQL
发现任务中由10多个SQL语句构成,一个语句大概有200+行,union all、join、sum操作较多。

image.png

查看任务报错日志
image.png

分析关键信息

org.apache.spark.shuffle.MetadataFetchFailedException: 
Missing an output location for shuffle 433

得出结论
一般任务有大量shuffle操作的时候,我们可以从shuffle数据量及shuffle分区数的角度对任务进行优化调整。

优化效果
只采取调大executor内存的方式进行优化,任务可以运行成功,但任务执行耗时仍然需20+分钟,执行效率与优化前相比无明显变化。原因在于任务执行中产生了较多的task,此时可以通过调整分区参数进行深入优化。分区参数spark.sql.shuffle.partitions是Spark SQL专用的设置,将该参数的值由200(默认值)调小为50,任务运行成功,执行耗时减少50%,约10分钟;继续将该参数调小为10,任务运行成功,执行耗时减少70%,约6分钟,优化完成。

**Q2:spark.default.parallelism参数与
spark.sql.shuffle.partitions参数有什么区别?**

虽然这两个参数较为相似,但default.parallelism只在处理RDD时才会起作用,对Spark SQL无效。其值设置为【num- executors * executor-cores】的2~3倍较为合理。可以参考官网的定义说明:
image.png

延伸拓展
1.shuffle分为shuffle write和shuffle read两部分。

2.shuffle write的分区数由上一阶段的RDD分区数控制,shuffle read的分区数则是由Spark提供的一些参数控制。

3.shuffle write可以简单理解为类似于saveAsLocalDiskFile的操作,将计算的中间结果按某种规则临时放到各个executor所在的本地磁盘上。

4.shuffle read时数据的分区数则是由spark提供的一些参数控制。如果这个参数值设置的很小,同时shuffle read的量很大,那么将会导致一个task需要处理的数据非常大,容易引发JVM crash。如果这个参数值设置的很大,可能会导致task的数量过多,任务执行速度过慢。
image.png

job和stage以及task的关系如下图所示,job的划分是action操作造成的,Stage是job通过依赖关系划分出来的,一个Stage对应一个TaskSet,一个Task对应一个rdd分区。同时大量使用shuffle操作也会使task数量变多。
image.png

本次优化主要是结合实际优化案例,对底层引擎spark的参数进行调优。如何通过优化提升任务执行效率?如何利用监控分析将被动运维转为主动运维?请关注后续Hive性能优化及监控方面的实践连载。
image.png

查看原文

Harley 收藏了文章 · 2020-12-30

技本功|Hive优化之建表配置参数调优(一)

简介: Hive是大数据领域常用的组件之一,主要用于大数据离线数仓的运算,关于Hive的性能调优在日常工作和面试中是经常涉及的一个点,因此掌握一些Hive调优是必不可少的一项技能。影响Hive效率的主要因素有数据倾斜、数据冗余、job的IO以及不同底层引擎配置情况和Hive本身参数和HiveSQL的执行等。本文主要从建表配置参数方面对Hive优化进行讲解。

创建一个普通的表

create table test\_user1(id int, name string,code string,code\_id string ) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',';                                         

查看表信息

DESCRIBE FORMATTED test\_user1;

我们从该表的描述信息介绍建表时的一些可优化点。

2.1表的文件数

numFiles表示表中含有的文件数,当文件数过多时可能意味着该表的小文件过多,这时候我们可以针对小文件的问题进行一些优化,HDFS本身提供了

解决方案:

1.Hadoop Archive/HAR:将小文件打包成大文件。

2.SEQUENCEFILE格式:将大量小文件压缩成一个SEQUENCEFILE文件。

3.CombineFileInputFormat:在map和reduce处理之前组合小文件。

4.HDFS Federation:HDFS联盟,使用多个namenode节点管理文件。

除此之外,我们还可以通过设置hive的参数来合并小文件。 

1.输入阶段合并

需要更改Hive的输入文件格式即参hive.input.format

默认值是org.apache.hadoop.hive.ql.io.HiveInputFormat我们改成org.apache.hadoop.hive.ql.io.CombineHiveInputFormat

这样比起上面对mapper数的调整,会多出两个参数,分别是mapred.min.split.size.per.nodemapred.min.split.size.per.rack,含义是单节点和单机架上的最小split大小。如果发现有split大小小于这两个值(默认都是100MB),则会进行合并。具体逻辑可以参看Hive源码中的对应类。

2.输出阶段合并

直接将hive.merge.mapfiles和hive.merge.mapredfiles都设为true即可,前者表示将map-only任务的输出合并,后者表示将map-reduce任务的输出合并,Hive会额外启动一个mr作业将输出的小文件合并成大文件。

另外,hive.merge.size.per.task可以指定每个task输出后合并文件大小的期望值,hive.merge.size.smallfiles.avgsize可以指定所有输出文件大小的均值阈值,默认值都是1GB。如果平均大小不足的话,就会另外启动一个任务来进行合并。

2.2表的存储格式

通过InputFormat和OutputFormat可以看出表的存储格式是TEXT类型,Hive支持TEXTFILE, SEQUENCEFILE, AVRO, RCFILE, ORC,以及PARQUET文件格式,可以通过两种方式指定表的文件格式:

1.CREATE TABLE ... STORE AS <file_format>:在建表时指定文件格式,默认是TEXTFILE

2.ALTER TABLE ... [PARTITION partition_spec] SET FILEFORMAT <file_format>:修改具体表的文件格式。

如果要改变创建表的默认文件格式,可以使用set hive.default.fileformat=<file_format>进行配置,适用于所有表。

同时也可以使用set hive.default.fileformat.managed =<file_format>进行配置,仅适用于内部表或外部表。

扩展:不同存储方式的情况

TEXT, SEQUENCE和 AVRO文件是面向行的文件存储格式,不是最佳的文件格式,因为即便只查询一列数据,使用这些存储格式的表也需要读取完整的一行数据。另一方面,面向列的存储格式(RCFILE, ORC, PARQUET)可以很好地解决上面的问题。

关于每种文件格式的说明,如下:

1.TEXTFILE

创建表时的默认文件格式,数据被存储成文本格式。文本文件可以被分割和并行处理,也可以使用压缩,比如GZip、LZO或者Snappy。然而大部分的压缩文件不支持分割和并行处理,会造成一个作业只有一个mapper去处理数据,使用压缩的文本文件要确保文件不要过大,一般接近两个HDFS块的大小。

2.SEQUENCEFILE

key/value对的二进制存储格式,sequence文件的优势是比文本格式更好压缩,sequence文件可以被压缩成块级别的记录,块级别的压缩是一个很好的压缩比例。如果使用块压缩,需要使用下面的配置:

set hive.exec.compress.output=true;
set io.seqfile.compression.type=BLOCK

3.AVRO

二进制格式文件,除此之外,avro也是一个序列化和反序列化的框架。avro提供了具体的数据schema。

4.RCFILE

全称是Record Columnar File,首先将表分为几个行组,对每个行组内的数据进行按列存储,每一列的数据都是分开存储,即先水平划分,再垂直划分。

5.ORC

全称是Optimized Row Columnar,从hive0.11版本开始支持,ORC格式是RCFILE格式的一种优化的格式,提供了更大的默认块(256M)

6.PARQUET

另外一种列式存储的文件格式,与ORC非常类似,与ORC相比,Parquet格式支持的生态更广,比如低版本的impala不支持ORC格式。

配置同样数据同样字段的两张表,以常见的TEXT行存储和ORC列存储两种存储方式为例,对比执行速度。

TEXT存储方式

ORC存储方式

总结:

从上图中可以看出列存储在对指定列进行查询时,速度更快,建议在建表时设置列存储的存储方式。

2.3 表的压缩

对Hive表进行压缩是常见的优化手段,一些存储方式自带压缩选择,比如SEQUENCEFILE支持三种压缩选择:NONE,RECORD,BLOCK。Record压缩率低,一般建议使用BLOCK压缩。

ORC支持三种压缩选择:NONE,ZLIB,SNAPPY。我们以TEXT存储方式和ORC存储方式为例,查看表的压缩情况。

配置同样数据同样字段的四张表,一张TEXT存储方式,另外三张分别是默认压缩方式的ORC存储、SNAPPY压缩方式的ORC存储和NONE压缩方式的ORC存储,查看在hdfs上的存储情况:

TEXT存储方式

默认压缩ORC存储方式

SNAPPY压缩的ORC存储方式

NONE压缩的ORC存储方式

总结:

可以看到ORC存储方式将数据存放为两个block,默认压缩大小加起来134.69M,SNAPPY压缩大小加起来196.67M,NONE压缩大小加起来247.55M。

TEXT存储方式的文件大小为366.58M,且默认block两种存储方式分别为256M和128M。

ORC默认的压缩方式比SNAPPY压缩得到的文件还小,原因是ORZ默认的ZLIB压缩方式采用的是deflate压缩算法,比Snappy压缩算法得到的压缩比高,压缩的文件更小。

ORC不同压缩方式之间的执行速度,经过多次测试发现三种压缩方式的执行速度差不多,所以建议采用ORC默认的存储方式进行存储数据。

2.4分桶分区

Num Buckets表示桶的数量,我们可以通过分桶和分区操作对Hive表进行优化。

对于一张较大的表,可以将它设计成分区表,如果不设置成分区表,数据是全盘扫描的,设置成分区表后,查询时只在指定的分区中进行数据扫描,提升查询效率。要注意尽量避免多级分区,一般二级分区足够使用。常见的分区字段:

1.日期或者时间,比如year、month、day或者hour,当表中存在时间或者日期字段时,可以使用些字段。

2.地理位置,比如国家、省份、城市等。

3.业务逻辑,比如部门、销售区域、客户等等。

与分区表类似,分桶表的组织方式是将HDFS上的一张大表文件分割成多个文件。

分桶是相对分区进行更细粒度的划分,分桶将整个数据内容按照分桶字段属性值得hash值进行区分,分桶可以加快数据采样,也可以提升join的性能(join的字段是分桶字段),因为分桶可以确保某个key对应的数据在一个特定的桶内(文件),所以巧妙地选择分桶字段可以大幅度提升join的性能。

通常情况下,分桶字段可以选择经常用在过滤操作或者join操作的字段。

创建分桶表 

createtabletest\_user\_bucket(idint,namestring,codestring,code\_idstring) clusteredby(id)into3bucketsROWFORMATDELIMITEDFIELDSTERMINATEDBY',';

查看描述信息

DESCRIBEFORMATTED test\_user\_bucket

多出了如下信息

查看该表的hdfs

同样的数据查看普通表和分桶表查询效率

普通表

分桶表

普通表是全表扫描,分桶表在按照分桶字段的hash值分桶后,根据join字段或者where过滤字段在特定的桶中进行扫描,效率提升。

本次优化主要建表配置参数方面对Hive优化进行讲解,这是Hive优化的第一步,正如大多数据库一样,完整的调优必定还包括模型设计、引擎调优,关于这部分的内容请关注后续连载。

未命名的设计 (1).png

查看原文

Harley 收藏了文章 · 2020-12-22

Git如何回滚一次错误的合并

原文发表在知乎专栏 前端杂货铺, 欢迎关注我的专栏,转载请注明出处

今天不说前端,来聊聊git吧。
发现现在的小孩,玩框架一套一套的,等到玩点实质的工程化的东西就不行了。
git 这么好的工具,培训班怎么可以忽视他的重要性呢?

再来聊聊git的工作流程

很多人对Git究竟是一个怎样的系统,还是一知半解。
在这里强烈建议大家先理解git的核心思想和工作原理,有过subversion或者perforce使用经验的人更是需要摒弃之前所见所学,重新接受这样一个新思想。
我们不再这里赘述其几本原理,我们来介绍一下其简单工作流程。
Git以一个自有的思维框架管理着三个不同的盒子Commit HistoryINDEXWorking Directory

  • Commit History 历史记录,存储着所有提交的版本快照,并由当前分支引用的指针HEAD指向该分支最新一条提交。
  • INDEX 索引,也叫暂存区域。它是一个文件,保存着即将提交的文件列表快照。
  • Working Directory 工作目录,是从git仓库压缩数据当前版本中解包出来的文件列表。所以你在本地磁盘看到的你项目源码的文件列表,其实就是git开放给你的一个沙盒。在你将文件的修改天道到暂存区域并将快照记录到历史之前,你可以随意更改。

理解了这三者的含义后,我们试着来理解一下git的工作流程。
一切的开始,混沌之间,我们要干一件大事,在terminal里面敲打了几下键盘

git init 

混沌初开,幻化三界:HEADINDEXWorking Directory。这就是世界最开始的样子git仓库仿佛就是掌管三界之神。而Working Directory就是他分配给你生产和工作的地方,你可以在这里肆意的创造。而为了安全和管理的有序我们需要把我们的添加与修改的文件交给git仓库。Git首先会将修改的文件标记起来放入暂存区、然后git找到暂存区域的文件内容将其永久性的存储为快照到git仓库,此时HEAD的指针指向这个最新的快照。

如图,总结下三个步骤

  1. 在工作目录中修改文件。
  2. 暂存文件,将文件的快照放入暂存区域。git add
  3. 提交更新,找到暂存区域的文件,将快照永久性存储到 Git 仓库目录 git commit

git 的基本工作流程就是在不断的重复这三个步骤,最终git仓库目录形成了一个快照堆栈,每产生一次新的版本,HEAD就会指向这个版本。

这里我们创建了下面这些文件:

├── README.md
├── v1.js
├── v2.js
└── v3.js

形成了下图的提交历史


3aa5dfb v3  (<- HEAD)
        |
5aab391 v2
        |
ff7b88e v1
        |
95d7816 init commit

下面我们来看看怎么利用checkout、reset、revert 来操作这个仓库目录

checkout 、reset 还是 revert ?

checkout

版本控制系统背后的思想就是「安全」地储存项目的拷贝,这样你永远不用担心什么时候不可复原地破坏了你的代码库。当你建立了项目历史之后,git checkout 是一种便捷的方式,来将保存的快照「解包」到你的工作目录上去。
git checkout 可以检出提交、也可以检出单个文件甚至还可以检出分支(此处省略)。

git checkout 5aab391

检出v2,当前工作目录和5aab391完全一致,你可以查看这个版本的文件编辑、运行、测试都不会被保存到git仓库里面。你可以git checkout master 或者 git checkout -回到原来的工作状态上来。

git checkout 5aab391 v1.js

以检出v2版本对于v1.js的改动,只针对v1.js这个文件检出到5aab391版本。所以 它会影响你当前的工作状态,它会把当前状态的v1.js文件内容覆盖为5aab391版本。所以除非你清楚你在做什么,最好不要轻易的做这个操作。但这个操作对于舍弃我当前的所有改动很有用:比如当前我在v1.js上面做了一些改动,但我又不想要这些改动了,而我又不想一个个去还原,那么我可以git checkout HEAD v1.js 或者 git checkout -- v1.js

reset 重置

git checkout 一样, git reset 有很多用法。

git reset <file>

从暂存区移除特定文件,但不改变工作目录。它会取消这个文件的缓存,而不覆盖任何更改。

git reset

重置暂存区,匹配最近的一次提交,但工作目录不变。它会取消所有文件的暂存,而不会覆盖任何修改,给你了一个重设暂存快照的机会。

git reset --hard

加上--hard标记后会告诉git要重置缓存区和工作目录的更改,就是说:先将你的暂存区清除掉,然后将你所有未暂存的更改都清除掉,所以在使用前确定你想扔掉所有的本地工作。

git reset <commit>

将当前分支的指针HEAD移到 <commit>,将缓存区重设到这个提交,但不改变工作目录。所有 <commit> 之后的更改会保留在工作目录中,这允许你用更干净、原子性的快照重新提交项目历史。

git reset --hard <commit>

将当前分支的指针HEAD移到 <commit>,将缓存区和工作目录都重设到这个提交。它不仅清除了未提交的更改,同时还清除了 <commit> 之后的所有提交。

可以看出,git reset 通过取消缓存或者取消一系列提交的操作会摒弃一些你当前工作目录上的更改,这样的操作带有一定的危险性。下面我们开始介绍一种相对稳妥的方式 revert

revert 撤销

git revert被用来撤销一个已经提交的快照。但实现上和reset是完全不同的。通过搞清楚如何撤销这个提交引入的更改,然后在最后加上一个撤销了更改的 新 提交,而不是从项目历史中移除这个提交。

git revert <commit>

生成一个撤消了 <commit> 引入的修改的新提交,然后应用到当前分支。

例如:

81f734d commit after bug
        |
3a395af bug
        |
3aa5dfb v3  (<- HEAD)
        |
5aab391 v2
        |
ff7b88e v1
        |
95d7816 init commit

我们在3a395af 引入了一个bug,我们明确是由于3a395af造成的bug的时候,以其我们通过新的提交来fix这个bug,不如git revert , 让他来帮你剔除这个bug。

git revert 3a395af

得到结果

cfb71fc Revert "bug"
        |
81f734d commit after bug
        |
3a395af bug
        |
3aa5dfb v3  (<- HEAD)
        |
5aab391 v2
        |
ff7b88e v1
        |
95d7816 init commit

这个时候bug的改动被撤销了,产生了一个新的commit,但是commit after bug没有被清初。

所以相较于resetrevert不会改变项目历史,对那些已经发布到共享仓库的提交来说这是一个安全的操作。其次git revert 可以将提交历史中的任何一个提交撤销、而reset会把历史上某个提交及之后所有的提交都移除掉,这太野蛮了。

另外revert的设计,还有一个考量,那就是撤销一个公共仓库的提交。至于为什么不能用reset,你们可以自己思考一下。
下面我们就用一个麻烦事(回滚一个错误的合并),来讲解这个操作。

合并操作

相对于常规的commit,当使用git merge <branch>合并两个分支的时候,你会得到一个新的merge commit.
当我们git show <commit>的时候会出现类似信息:

commit 6dd0e2b9398ca8cd12bfd1faa1531d86dc41021a
Merge: d24d3b4 11a7112
Author: 前端杂货铺 
...............

Merge: d24d3b4 11a7112 这行表明了两个分支在合并时,所处的parent的版本线索。

比如在上述项目中我们开出了一个dev分支并做了一些操作,现在分支的样子变成了这样:

init -> v1 -> v2 -> v3  (master)
           \      
            d1 -> d2  (dev)

当我们在dev开发的差不多了

#git:(dev)
git checkout master 
#git:(master)
git merge dev

这个时候形成了一个Merge Commit faulty merge

init -> v1 -> v2 -> v3 -- faulty merge  (master)
           \            /
            d1  -->  d2  (dev)

此时faulty merge有两个parent 分别是v3 和 d2。

回滚错误的合并

这个merge之后还继续在dev开发,另一波人也在从别的分支往master合并代码。变成这样:

init -> v1 -> v2 -> v3 -- faulty merge -> v4 -> vc3 (master)
        \  \            /                     /
         \  d1  -->  d2  --> d3 --> d4  (dev)/
          \                                 / 
           c1  -->  c2 -------------------c3 (other)

这个时候你发现, 妈也上次那个merge 好像给共享分支master引入了一个bug。这个bug导致团队其他同学跑不通测试,或者这是一个线上的bug,如果不及时修复老板要骂街了。

这个时候第一想到的肯定是回滚代码,但怎么回滚呢。用reset?不现实,因为太流氓不说,还会把别人的代码也干掉,所以只能用revert。而revert它最初被设计出来就是干这个活的。

怎么操作呢?首先想到的是上面所说的 git revert <commit> ,但是貌似不太行。

git revert faulty merge
error: Commit faulty merge is a merge but no -m option was given.
fatal: revert failed

这是因为试图撤销两个分支的合并的时候Git不知道要保留哪一个分支上的修改。所以我们需要告诉git我们保留那个分支m 或者mainline.

git revert -m 1 faulty merge

-m后面带的参数值 可以是1或者2,对应着parent的顺序.上面列子:1代表v3,2代表d2
所以该操作会保留master分支的修改,而撤销dev分支合并过来的修改。

提交历史变为

init -> v1 -> v2 -> v3 -- faulty merge -> v4 -> vc3 -> rev3 (master)
          \            /                     
           d1  -->  d2  --> d3 --> d4  (dev)

此处rev3是一个常规commit,其内容包含了之前在faulty merge撤销掉的dev合并过来的commit的【反操作】的合集。

到这个时候还没完,我们要记住,因为我们抛弃过之前dev合并过来的commit,下次dev再往master合并,之前抛弃过的其实是不包含在里面的。那怎么办呢?

恢复之前的回滚

很简单我们把之前master那个带有【反操作】的commit给撤销掉不就好了?

git checkout master
git revert rev3
git merge dev

此时提交历史变成了

init -> v1 -> v2 -> v3 -- faulty merge -> v4 -> vc3 -> rev3 -> rev3` -> final merge (master)
          \            /                                               /
           d1  -->  d2  --> d3 --> d4  --------------------------------(dev)

总结

以上就是我想要讲的关于git回滚代码的一些操作,有不对的地方还望指正。另Git 是一门艺术,是一种非常精妙的设计,当你使用上手后,你会发现越来越多好玩的东西,并为设计git的人默默点个赞。也希望在前端领域不论是初学还是深凿者,在追逐流行框架的时候,都不要忘了学习这些基础的工具。

参考

查看原文

认证与成就

  • 获得 0 次点赞
  • 获得 1 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 1 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2020-12-22
个人主页被 69 人浏览