读书笔记:大数据平台-流处理架构

简介

流式计算需要各子系统间相互依赖形成一条处理链路,子系统作如下划分

  • 数据采集
    数据源一般来自于各个业务的日志服务器,这些日志被实时采集到消息间件中,被下游实时订阅
  • 数据处理
    数据被采集到中间件后,下游服务订阅数据,并拉取到流式计算系统进行加工处理,通过流式计算引擎计算处理
  • 数据存储
    数据被加工处理后,会以增量形式(不间断地)写到在线存储系统中,提供给下游服务
  • 数据服务
    数据处理结果落地到在线存储系统 ,其会提供统一接口(如HTTP),用于对外发布实时计算结果,供其它服务使用
    读书笔记:大数据平台-流处理架构_第1张图片

数据采集

数据采集是是流处理链路的源头,采集的数据都来自业务服务器,从采集分类可分如下两种:

  • 数据变更日志,MySQL 的 binlog、HBase的hlog日志等
  • 引擎访问日志,用户访问网站产生Apache引擎日志、搜索引擎的接口查询日志等

上述两种方式,都会在业务服务器上落地成文件,所以只要监控到日志文件内容发生变化,采集工具就可以把最新的内容采集下来。

基于吞吐量及系统压力考虑,不是产生一条记录就采集一次,而是基于如下原则批次采集:

  • 数据大小阀值:当达到大小阀值时,把目前采集到的数据作为一批上传(如512KB)
  • 时间阀值 :当达到时间阀值时,把目前采集的新数据作为一批,避免数据量少,没有达到大小阀值情况下,一直不采集(如30s)

只要上述条件满足其一,就会作为一批新数据采集到中间件中。这两个条件可根据业务场景灵活设定,达到一定的平衡。

数据采集的中间件,现在在市场上比较流行的是Kafka。其主要特点如下:

  • 同时为发布和订阅提供高吞吐量。据了解,Kafka 每秒可以生产约 25 万消息(50MB),每秒处理 55 万消息(110MB)
  • 可进行持久化操作。将消息持久化到磁盘,因此可用于批量消费,例如 ETL ,以及实时应用程序。通过将数据持久化到硬盘, 以及replication ,可以防止数据丢失
    分布式系统,易于向外扩展。所有的Producer、Broker 和Consumer 都会有多个,均为分布式。且,无需停机即可扩展机器。
  • 消息被处理的状态是在 Consumer 端维护,而不是由 Broker 端维护。当失败时,能自动平衡。
  • 支持 online 和 offline 的场景

Kafka之所以这么快, 是其内部实现应用了顺序IO内存映射文件Zero-copy等机制,这不在本文讨论范围,有兴趣的同学可google了解。

数据处理

实时计算任务部署在流式计算系统上,通过数据中间件取得数据进行实时加工处理。在各大互联网公司,有各种开源的和非开源的流计算引擎在使用。业界使用比较广泛的Twitter开源的 Storm系统,Apache的SparkStreaming,当前最流行的Flink。现在大多数使用开源流计算引擎公司,比较多的都在向Flink过渡。这些系统架构大同小异,但是很多细节上实现的方式不太一样,适用于不同的场景。

实时数据处理应用出于性能考虑,计算任务往往是多线程的。一般会根据业务主键进行分桶处理,为提高吞吐量,大部分计算过程需要数据放在内存中。为避免内存溢出,内存的过期数据需要定时清理,可以按照LRU算法或者业务时间集合归类清理(比如业务时间属于T-1的,会在今天凌晨进行清理)。

下面针对实时任务几个典型的问题进行讲解。

  • 去重指标
    在BI(商业智能)统计类实时任务中,去重指标对资源的消耗非常之大。由于实时任务为了追加处理性能,计算逻辑一般都在内存中完成,中间结果也会缓存在内存中,这就可能存在对内存消耗过多的问题。在计算去重时,势必要把去重的明细数据保存下来,当去重的数据达到上亿甚至几十亿时,内存放不下了,怎么办???这时需要分两种情况看:

    • 精确去重:这种情况,明细数据是必须要保存下来的,当遇到内存问题时,可以通过数据倾斜来处理,把一个节点的内存压力分散到多个节点上。
    • 模糊去重:在去重的明细数据量非常大,而业务的精度需求不高的情况下,可以使用相关去重算法,把内存的使用量降到千分之一甚至万分之一,从而提高内存的利用率。
    1. 布隆过滤器
      该算法是位数算法的应用,不保存真实的明细数据,只保存明细数据应用的哈希值标记位。当然,会出现哈希值碰撞的情况,但是误差率可以控制,计算出来的去重值比真实值小。采用这个算法存储1亿条数据只需要 100多MB的空间。
      适用场景:统计精度要求不高,统计维度值非常多的情况。比如统计全网各保商家的UV数据,结果记录数达到上千万条。因为在各个维度之间,布隆过滤器是可以共用的。
    2. 基数估计
      该算法也是采用Hash原理,按照数据的分散程度来估算现在数据集的边界,从而得出大概的去重值和。这里估算的去重值可能比真实值大,也可能比真实值小。采用这个算法存储1亿条数据只需要几KB的内存。
      适用场景:统计精度要求不高,统计维度非常粗的情况。比如整个大盘的UV数据,每天的结果只有一条记录。基数估计在各个维度值 之间不能共用,比如统计全天小时的UV数据,就需要有24小基数估计对象,因此不适合细粒度统计的场景。
  • 数据倾斜
    数据倾斜是ETL中经常出现的问题,比如计算一天中全网访客数或成交额时,最终结果只有一个,通常应该是在一个节点上完成相关的计算任务。在数据量非常在时,单个节点的处理能力有限,就会遇到性能瓶颈。这时就需要对数据进行你好分桶处理,分桶处理和离线处理的思路是一样的。

    • 去重指标分桶
      通过对去重值进行分桶Hash,相同的值一定会被放在同一个桶中去重,最后再把每个桶里的值进行加和和到总值,这里利用每个桶的CPU和内存资源。
    • 非去重指标分桶
      数据随机分发每个桶中,最后再把每个桶的值汇总,主要利用的是各个桶的CPU能力。
  • 事务处理
    由于实时计算是分布式处理的,系统的不稳定性必然会导致数据的 处理有可能岀现失败的情况。比如网络的抖动导致数据发送不成功、机器重启导致数据丢失等。
    流计算系统几乎都提供了数据自动 ACK失败重发以 及事务信息等机制。

    • 超时时间
      超进重试(发),由于数据处理是按批次进行的,所以要增加一下限流功能,每批次数据量不宜过大,避免处理超时
    • 事务信息
      每秕数据都会附带一个事务ID,可以让开发者根据事务ID,判断使用何种处理逻辑。
    • 备份机制
      开发人员需要保证内存数据可以通过外存恢复,因此计算中用到的间结果需要存储到外部存储

    以上机制都是为了保证数据的幂等性。

数据存储

实时任务在运行过程中,会计算很多维度和指标,这些数据需要放 在一个存储系统中作为恢复或者关联使用。涉及三种类型的数据:

  • 中间计算结果
    处理过程中,会保存一些中间状态,以备出现故障时恢复内存现场
  • 最终结果数据
    指通过ETL处理后的实时处理结果数据,这些数据是实时更新的,写的频率非常高,可以被下游直接使用
  • 维表数据
    在离线计算系统中,通过同步工具导入到在线存储系统中,供实时任务来关联实时流数据。

实时任务是多线程处理的,这就要求数据存储系统能够较好的支持并发读写,且延时在毫秒级才能满足实时的性能要求。

在实践中,一般使用HBase、MongoDB等列式存储系统。这些数据库写数据时,先写内存再落磁盘,因此写延时在毫秒级;读请求也有相应的缓存机制,重要的是多并发读时也可以达到毫秒级延时。

但这些系统缺点也比较明显,以HBase为例,表必有rowkey,其按照字典序排序,相当于关系数据库的索引 一样,rowkey的规则限制了读取数据的方式。如果业务方需要使用另一种读取数据方式,就必须重新输出rowkey。从 这 个 角 度来看,HBase 没有关系型数据库方便。但是 HBase 的一张表能够存储 几 TB 甚至几十 TB 的数据,而关系型数据库必须要分库分表才能实现 这个量级的数据存储。因此,对于海量数据的实时计算,一般会釆用非关系型数据库,以应对大量的多并发读写。

数据统计中表名设计和 rowkey 设计的一些实践经验。

  1. 表名设计
    设计规则:汇总层标识+数据域+主维度+时间维度
    例如:dws_trd_slr_dtr, 表示汇总层交易数据,根据卖家 (sir) 主 维 度 +0点截至当日 (dtr) 进行统计汇总。
    这样做的好处是,所有主维度相同的数据都放在一张物理表中,避 免表数量过多,难以维护。另外,可以从表名上直观地看到存储的是什 么数据内容,方便排查问题
  2. rowkey设计
    设计规则:MD5 + 主维度 + 维度标识 + 子维度1 + 时间维度 +子维度2
    例如:卖家 ID 的 MD5 前 四 位 + 卖 家 ID + app + —级类目 ID + ddd + 二 级 类 目 ID。
    以 MD5 的前四位作为 rowkey 的第一部分,可以把数据散列,让服务器整体负载是均衡的,避免热点问题。在上面的例子中,卖家 ID 属 于主维度,在查数据时是必传的。每个统计维度都会生成一个维度标识,以便在 rowkey 上做区分。

数据服务

实时数据落地到存储系统中后,使用方就可以通过统一的数据服务获取到实时数据。其好处是:

  • 不需要直连数据库,数据源等信息在数据服务层维护,这样当存储系统迁移时,对下游是透明的。
  • 调用方只需要使用服务层暴露的接口,不需要关心底层取数逻辑的实现。
  • 屏蔽存储系统间的差异,统一的调用日志输出,便于分析和监控下游使用情况

你可能感兴趣的:(读书笔记:大数据平台-流处理架构)