最新发布《数智时代的AI人才粮仓模型解读白皮书(2024版)》,立即领取! 了解详情
写点什么

Flume 在有赞大数据的实践

  • 2020-03-18
  • 本文字数:3799 字

    阅读完需:约 12 分钟

Flume 在有赞大数据的实践

一、前言


Flume 是一个分布式的高可靠,可扩展的数据采集服务。


Flume 在有赞的大数据业务中一直扮演着一个稳定可靠的日志数据“搬运工”的角色。本文主要讲一下有赞大数据部门在 Flume 的应用实践,同时也穿插着我们对 Flume 的一些理解。

二、Delivery 保证

认识 Flume 对事件投递的可靠性保证是非常重要的,它往往是我们是否使用 Flume 来解决问题的决定因素之一。


消息投递的可靠保证有三种:


  • At-least-once

  • At-most-once

  • Exactly-once


基本上所有工具的使用用户都希望工具框架能保证消息 Exactly-once ,这样就不必在设计实现上考虑消息的丢失或者重复的处理场景。但是事实上很少有工具和框架能做到这一点,真正能做到这一点所付出的成本往往很大,或者带来的额外影响反而让你觉得不值得。假设 Flume 真的做到了 Exactly-once ,那势必降低了稳定性和吞吐量,所以 Flume 选择的策略是 At-least-once


当然这里的 At-least-once 需要加上引号,并不是说用上 Flume 的随便哪个组件组成一个实例,运行过程中就能保存消息不会丢失。事实上 At-least-once 原则只是说的是 SourceChannelSink 三者之间上下投递消息的保证。而当你选择 MemoryChannel 时,实例如果异常挂了再重启,在 channel 中的未被 sink 所消费的残留数据也就丢失了,从而没办法保证整条链路的 At-least-once。


Flume 的 At-least-once 保证的实现基础是建立了自身的 Transaction 机制。Flume 的 Transaction 有 4 个生命周期函数,分别是 startcommitrollbackclose


SourceChannel 批量投递事件时首先调用 start 开启事务,批量 put 完事件后通过 commit 来提交事务,如果 commit 异常则 rollback ,然后 close 事务,最后 Source 将刚才提交的一批消息事件向源服务 ack(比如 kafka 提交新的 offset )。 Sink 消费 Channel 也是相同的模式,唯一的区别就是 Sink 需要在向目标源完成写入之后才对事务进行 commit。两个组件的相同做法都是只有向下游成功投递了消息才会向上游 ack,从而保证了数据能 At-least-once 向下投递。

三、datay 应用场景

基于 mysql binlog 的数仓增量同步( datay 业务)是大数据这边使用 Flume 中一个比较经典的应用场景,datay 具体业务不详细说明,需要强调的是它对 Flume 的一个要求是必须保证在 nsq(消息队列)的 binlog消息能可靠的落地到 hdfs ,不允许一条消息的丢失,需要绝对的 At-least-once


Flume 模型本身是基于 At-least-once 原则来传递事件,所以需要需要考虑是在各种异常情况(比如进程异常挂了)下的 At-least-once 保证。显然 MemoryChannel 无法满足,所以我们用 FlieChannel 做代替。由于公司目前是使用 nsq 作为 binlog 的消息中转服务,故我们没有办法使用现有的 KafkaSource,所以基于公司的 nsq sdk 扩展了 NsqSource。这里需要说明的是为了保证 At-least-once, Source 源必须支持消息接收的 ack 机制,比如 kafka 客户端只有认为消费了消息后,才对 offset 进行提交,不然就需要接受重复的消息。


于是我们第一个版本上线了,看上去很有保障了,即使进程异常挂了重启也不会丢数据。



可能有同学想到一个关键性的问题:如果某一天磁盘坏了而进程异常退出,而 FileChannel 刚好又有未被消费的事件数据,这个时候不就丢数据了吗?虽然磁盘坏了是一个极低的概率,但这确实是一个需要考虑的问题。


在 Flume 现有组件中比 FlieChannel 更可靠的,可能想到的是 KafkaChannel ,kafka 可以对消息保留多个副本,从而增强了数据的可靠性。但是我们第二版本的方案没有选择它,而是直接扩展出 NsqChannel 。于是第二个版本就有了。



初次使用 Flume 的用户往往陷入到必须搭配 Source + Channel + Sink 三个组件的固有模式,事实上我们不一定要三个组件都使用上。另外直接 NsqChannelHDFSEventSink 的有几个好处:


  • 每个消息的传递只需要一次事务,而非两次,性能上更佳。

  • 避免引入了新的 kafka 服务,减少了资源成本的同时保持架构上更简单从而更稳定。

四、定制化扩展

Flume 在各个组件的扩展性支持具有非常好的设计考虑。


当无法满足我们的自定义需求,我们可以选择合适的组件上进行扩展。下面就讲讲我们扩展的一些内容。


  • NsqSource


在 Flume 定制化一个 Source 比较简单,继承一个已有通用实现的抽象类,实现相对几个生命周期方法即可。这里说明注意的是 Flume 组件的生命周期在可能被会调用多次,比如 Flume 具有自动发现实例配置发生变化并 restart 各个组件,这种情况需要考虑资源的正确释放。


  • HdfsEventSink 扩展配置


它本身就具有 role file 功能,比如当 Sink 是按小时生成文件,有这一个小时的第一个事件创建新的文件,然后经过固定的 role 配置时间(比如一小时)关闭文件。这里存在的问题就是如果源平时的数据量不大,比如 8 点这个小时的第一个事件是在 8 点 25 分来临,那就是说需要 9 点 25 才能关闭这个文件。由于没有关闭的 tmp 文件会被离线数据任务的计算引擎所忽略,在小时级的数据离线任务就没办法得到实时的数据。而我们做的改造就是 roll file 基于整点时间,而不是第一次事件的时间,比如固定的 05 分关闭上一次小时的文件,而离线任务调度时间设置在每小时的 05 分之后就能解决这个问题。最终的效果给下图:



  • MetricsReportServer


当我们需要收集 Flume 实例运行时的各个组件 counter metric ,就需要开启 MonitorService 服务。自定义了一个定期发生 http 请求汇报 metric 到一个集中的 web 服务。原生的 HTTPMetricsServer 也是基于 http 服务,区别在于它将 Flume 作为 http 服务端,而我们将很多实例部署在一台机器上,端口分配成了比较头疼的问题。


当我们收集到以下的 counter metric 时,就可以利用它来实现一些监控报警。


{  "identity":"olap_offline_daily_olap_druid_test_timezone_4@49",  "startTime":1544287799839,  "reportCount":4933,  "metrics":{    "SINK.olap_offline_daily_olap_druid_test_timezone_4_snk":{      "ConnectionCreatedCount":"9",      "ConnectionClosedCount":"8",      "Type":"SINK",      "BatchCompleteCount":"6335",      "BatchEmptyCount":"2",      "EventDrainAttemptCount":"686278",      "StartTime":"1544287799837",      "EventDrainSuccessCount":"686267",      "BatchUnderflowCount":"5269",      "StopTime":"0",      "ConnectionFailedCount":"48460"    },    "SOURCE.olap_offline_daily_olap_druid_test_timezone_4_src":{      "KafkaEventGetTimer":"26344146",      "AppendBatchAcceptedCount":"0",      "EventAcceptedCount":"686278",      "AppendReceivedCount":"0",      "StartTime":"1544287800219",      "AppendBatchReceivedCount":"0",      "KafkaCommitTimer":"14295",      "EventReceivedCount":"15882278",      "Type":"SOURCE",      "OpenConnectionCount":"0",      "AppendAcceptedCount":"0",      "KafkaEmptyCount":"0",      "StopTime":"0"    },    "CHANNEL.olap_offline_daily_olap_druid_test_timezone_4_cha":{      "ChannelCapacity":"10000",      "ChannelFillPercentage":"0.11",      "Type":"CHANNEL",      "ChannelSize":"11",      "EventTakeSuccessCount":"686267",      "StartTime":"1544287799332",      "EventTakeAttemptCount":"715780",      "EventPutAttemptCount":"15882278",      "EventPutSuccessCount":"686278",      "StopTime":"0"    }  }}
复制代码


  • 事件时间戳拦截。有一些 hdfs sink 业务对消息事件的时间比较敏感,同一小时的数据必须放在同一个目录里,这就要求使用 HdfsEventSink 的时候不能使用系统时间来计算文件目录,而是应该基于消息内容中的某个时间戳字段。这个可以通过扩展 Interceptor 来解决。 Interceptor 用于在 Source 投递事件给 Channel 前的一个拦截处理,一般都是用来对事件丰富 header 信息。强烈不建议在 Source 中直接处理,实现一个 Interceptor 可以满足其他 Source 类似需求的复用性。

五、性能调优

Flume 实例进行性能调优最常见的配置是 事务batchChannelCapacity


  • 事务 batch 指的是合理设置 batch 配置,可以明显的改善实例的吞吐量。上面已经讲到 SourceChannel 进行 put 或者 SinkChannel 进行 take 都是通过开启事务来操作,所以调大两个组件的 batch 配置可以降低 cpu 消耗,减少网络 IO 等待等。

  • Channel 的 capacity 大小直接影响着 source 和 sink 两端的事件生产和消费。capacity 越大,吞吐量越好,但是其他因素制约着不能设置的很大。比如 MemoryChannel ,直接表现着对内存的消耗,以及进程异常退出所丢失的事件数量。不同的 Channel 需要不同的考虑,最终 trade-off 是难免的。

六、总结和展望

Flume 是一个非常稳定的服务,这一点在我们生产环境中得到充分验证。


同时它的模型设计也非常清晰易懂,每一种组件类型都有很多现成的实现,同时特考虑到各个扩展点,所以我们很容易找到或者定制化我们所需要的数据管道的解决方案。


随着用户越来越多,需要有一个统一的平台来集中管理所有的 Flume 实例。


有以下几点好处:


  • 降低用户对 Flume 的成本。尽可能在不太了解 Flume 的情况下就可以享受到它带来的价值。

  • 有效对机器的资源进行合理协调使用。

  • 完善的监控让 FLume 运行的更加稳定可靠。


当然这一步我们也才刚启动,希望它未来的价值变得越来越大。


2020-03-18 19:54936

评论

发布
暂无评论
发现更多内容

你没必要活的那么累

小天同学

深度思考 个人成长 生活 成长 感悟

写给产品经理的信(1):产品经理的经济基础逻辑思维能力

punkboy

产品经理 产品设计 职业规划 逻辑思维 工作

【迁移】CQRS很难吗?(译文:底部有原文地址)

罗琦

领域驱动设计 DDD

要弄清楚if/switch的本质区别,以及优化方式

张驰

Java

《从0到1学习Flink》—— Flink 配置文件详解

zhisheng

大数据 flink 流计算

【迁移】读完了GFS论文之后的感悟

罗琦

大数据 GFS 论文阅读

《从0到1学习Flink》—— Flink 中几种 Time 详解

zhisheng

大数据 flink 流计算

《从0到1学习Flink》—— Flink 写入数据到 ElasticSearch

zhisheng

大数据 flink 流计算

《从0到1学习Flink》—— Flink 读取 Kafka 数据写入到 RabbitMQ

zhisheng

大数据 flink 流计算

极客时间的三种身份:碎片整合的大师、成长焦虑的救星、工作技能的提升站

大橘栗

【迁移】Flink vs Spark

罗琦

大数据 flink spark

《从0到1学习Flink》—— Data Source 介绍

zhisheng

大数据 flink 流计算

码农理财(二)

北漂码农有话说

Review week1: Amazon的领导力法则

猫吃小怪兽

学习 高效工作 程序员 个人成长

ARTS 第 51 周

马克图布

ARTS 打卡计划

【迁移】用Redlock构建Redis分布式锁【译】

罗琦

分布式锁

《从0到1学习Flink》—— Mac 上搭建 Flink 1.6.0 环境并构建运行简单程序入门

zhisheng

大数据 flink 流计算

《从0到1学习Flink》—— 介绍Flink中的Stream Windows

zhisheng

大数据 flink 流计算

《从0到1学习Flink》—— Data Sink 介绍

zhisheng

大数据 flink 流计算

勇攀监控高峰-EMonitor之根因分析

乒乓狂魔

监控 全链路监控 故障定位 根因分析 AIOPS

图文并茂讲述如何正确的使用缓存

小趴菜~

缓存 后端 缓存穿透 缓存击穿 缓存雪崩

《从0到1学习Flink》—— Apache Flink 介绍

zhisheng

大数据 flink 流计算

《从0到1学习Flink》—— 如何自定义 Data Source ?

zhisheng

大数据 flink 流计算

《从0到1学习Flink》—— 如何自定义 Data Sink ?

zhisheng

大数据 flink 流计算

《从0到1学习Flink》—— Flink Data transformation(转换)

zhisheng

大数据 flink 流计算

《从0到1学习Flink》—— Flink 写入数据到 Kafka

zhisheng

大数据 flink 流计算

python 实现·十大排序算法之选择排序(Selection Sort)

南风以南

Python 排序算法

《从0到1学习Flink》—— Flink 项目如何运行?

zhisheng

大数据 flink 流计算

《从0到1学习Flink》—— Flink 读取 Kafka 数据批量写入到 MySQL

zhisheng

大数据 flink 流计算

【迁移】撸论文系列之——Bigtable

罗琦

论文阅读 bigtable

《从0到1学习Flink》—— Flink JobManager 高可用性配置

zhisheng

大数据 flink 流计算

Flume 在有赞大数据的实践_文化 & 方法_hujiahua_InfoQ精选文章