本文主要介绍了Flume的功能用途和核心概念,是一个对Flume是什么、能干什么的快速入门介绍,来自《企业大数据处理:Spark、Druid、Flume与Kafka应用实践》读书笔记。
Flume是cloudera公司开发的分布式、高可用的日志收集系统,是Hadoop生态圈内的关键组件之一,目前已开源给apache。Flume原始版本为Flume-OG,经过对整体架构的重新设计,已改名为Flume-NG。Flume发展到现在已经不仅限于日志收集,还可以通过简单的配置收集不同数据源的海量数据并将数据准确高效地传输到不同的中心存储。目前Flume可对接的主流大数据框架有Hadoop、Kafka、ElasticSearch、Hive、HBase等。在使用Flume的过程中,通过配置文件可以实现整个数据收集过程的负载均衡和故障转移,整个流程不需要修改Flume的任何代码。Flume具有上述的诸多特性得益于优秀的框架设计,Flume通过可扩展、插件化、组合式、高可用、高容错的设计模式,为用户提供了简单、高效、准确的轻量化大数据采集工具。
Flume-NG采用三层架构设计:收集(Source)、暂存(Channel)、处理(Sink),如图所示。
一个event在一个agent中的传输流程如图所示,传输顺序为:Source→Interceptor→Selector→Channel→Sink Processor→Sink→中心存储/下一级agent
Source用于对接各种数据源,将收集到的事件发送到临时存储Channel中。常用的source类型有:Avro Source、Exec Source、Kafka Source、Taildir Source、Spooling Directory Source等。
Avro Source支持Avro协议,接收RPC事件请求。Avro Source通过监听Avro端口接收外部Avro客户端流事件(event),在Flume的多层架构中经常被使用接收上游Sink发送的event。
Kafka Source对接分布式消息队列kafka,作为kafka的消费者持续从kafka中拉取数据,如果多个kafka source同时消费kafka中同一个主题(topic),则kafka source的kafka.consumer.group.id应该设置成相同的组id,多个kafka source之间不会消费重复的数据,每一个source都会拉取topic下的不同数据。
Exec Source支持Linux命令,收集标准输出数据或者通过tail -f file的方式监听指定文件。Exec Source可以实现实时的消息传输,但是它不记录已经读取文件的位置,不支持断点续传,如果Exec Source重启或者挂掉都会造成后续增加的消息丢失,建议只是在测试环境使用。
Spooling Directory Source监听一个文件夹,收集文件夹下新文件数据,收集完新文件数据会将文件名称的后缀改为.COMPLETED,缺点是不支持老文件新增数据的收集,并且不能够对嵌套文件夹递归监听。
Taildir Source监听一个文件或文件夹,通过正则表达式匹配需要监听的数据源文件,支持文件夹嵌套递归监听(重要source), Taildir Source将通过监听的文件位置写入到文件中实现断点续传,并且能够保证没有重复数据的读取。
Channel被设计为Event中转临时缓冲区,存储Source收集并且没有被Sink读取的Event,为平衡Source收集和Sink读取数据的速度,可视为Flume内部的消息队列。Channel线程安全并且具有事务性,支持source写失败重复写和sink读失败重复读等操作。常用的Channel类型有Memory Channel、File Channel、Kafka Channel等。
Memory Channel对比Channel, Memory Channel读写速度快,但是存储数据量小,Flume进程挂掉、服务器停机或者重启都会导致数据丢失。部署Flume Agent的线上服务器内存资源充足、不关心数据丢失的场景下可以使用。
File Channel将event写入磁盘文件,与Memory Channel相比存储容量大,无数据丢失风险。File Channle数据存储路径可以配置多磁盘文件路径,通过磁盘并行写入提高File Channel性能。Flume将Event顺序写入到File Channel文件的末尾,在配置文件中通过设置maxFileSize参数配置数据文件大小,当被写入的文件大小达到上限时Flume会重新创建新的文件存储写入的Event。当然数据文件数量也不会无限增长,当一个已关闭的只读数据文件中的Event被读取完成,并且Sink已经提交读取完成的事务,则Flume将删除存储该数据的文件。Flume通过设置检查点和备份检查点实现在Agent重启之后快速将File Channle中的数据按顺序回放到内存中,保证在Agent失败重启后仍然能够快速安全地提供服务。
Kafka Channel将Kafka作为Channel存储,Kafka是分布式、可扩展、高容错、高吞吐的分布式系统,Kafka通过优秀的架构设计充分利用磁盘顺序特性,在廉价的硬件条件下完成高效的消息发布和订阅。
Memory Channel在使用的过程中受内存容量的限制不能缓存大量的消息,并且如果Memory Channel中的消息没来得及写入Sink,此时Agent出现故障就会造成数据丢失。
File Channel虽然能够缓存更多的消息,但如果缓存下来的消息还没有写入Sink,此时Agent出现故障则File Channel中的消息不能被继续使用,直到该Agent重新恢复才能够继续使用File Channel中的消息。
Kafka Channel相对于Memory Channel和File Channel存储容量更大、容错能力更强,弥补了其他两种Channel的短板,如果合理利用Kafka的性能,能够达到事半功倍的效果。
有了Kafka Channel可以在日志收集层只配置Source组件和Kafka Channel组件,不需要再配置Sink组件,减少了日志收集层启动的进程数并且有效降低服务器内存、磁盘等资源使用率,日志汇聚层可以只配置Kafka Channel和Sink,不需要再配置Source,减少日志汇聚层的进程数,这样的配置既能降低服务器的资源使用率又能减少Event在网络之间的传输,有效提高日志采集系统的性能。
Avro Sink常用于对接下一层的Avro Source,通过发送RPC请求将Event发送到下一层的Avro Source,由于通过RPC请求发送Event会占用大量的网络资源,如果采用单条发送不但要占用大量的网络资源还会产生大量的Socket连接,增加系统负载。为了解决上述问题,Avro Sink提供了端到端的批量压缩数据传输,根据实际使用场景设置合适的批量大小和是否使用压缩。
HDFS是目前主流的分布式文件系统,具有高容错、可扩展、高性能、低成本等特点。HDFS Sink将Event写入HDFS文件存储,能够有效的长期存储大量数据。
Kafka是一款开源的分布式消息队列,在消息传递过程中引入Kafka会从很大程度上降低系统之间的耦合度,提高系统稳定性和容错能力。Flume通过Kafka Sink将Event写入到Kafka中的主题,其他应用通过订阅主题消费数据。
Source将Event写入到Channel之前可以使用拦截器对Event进行各种形式的处理,Source和Channel之间可以有多个拦截器,不同的拦截器使用不同的规则处理Event。拦截器是比较轻量级的插件,不建议使用拦截器对Event进行过于复杂的处理,复杂的处理操作可能需要耗费更多的时间,对Flume整体性能会产生负面的影响。Flume已经提供的拦截器有
等多种形式的拦截器。Flume也支持自定义编写拦截器,只需实现Interceptor接口。
Flume使用时间戳拦截器在Event头信息中添加时间戳信息,Key为timestamp, Value为拦截器拦截Event时的时间戳。头信息时间戳的作用,比如HDFS存储的数据采用时间分区存储,Sink可以根据Event头信息中的时间戳将Event按照时间分区写入到HDFS。
Flume使用主机戳拦截器在Event头信息中添加主机名称或者IP, Key通过参数hostHeader配置,默认值host,如果配置参数useIP设置为false则Value值为主机名称,反之Value值为IP。主机拦截器的作用,比如Source将Event按照主机名称写入到不同的Channel中便于后续Sink对不同Channnel中的数据分开处理。
Source发送的Event通过Channle选择器来选择以哪种方式写入到Channel中,Flume提供三种类型Channel选择器,分别是
如果Channel选择器没有指定,默认是复制Channel选择器。复制选择器从字面含义非常容易理解,即一个Source以复制的方式将一个Event同时写入到多个Channel中,不同的Sink可以从不同的Channel中获取相同的Event,比如同一份日志的数据需要同时写入Kafka用于实时计算,另外需要保存一份原始日志到HDFS用于校验和校正结果数据,这就需要一个Event同时写入两个Channel,然后被不同类型的Sink发送到不同的外部存储。
复用Channel选择器需要和拦截器配合使用,根据Event的头信息中不同键值数据来判断Event应该被写入哪个Channel中。从源码MultiplexingChannelSelector类中可以很清晰地了解复用Channel选择器具体执行流程,重要的三个方法configure、getRequiredChannels、getOptionalChannels, configure方法用于初始化上下文,从配置文件中读取配置信息,getRequiredChannels接收参数为Event,返回值为Event应该写入的Channel列表,如果在配置文件中没有设置header信息或者通过headerValue获取到的channel列表为空都会返回默认配置的Channel列表。
Flume为了进一步提高整个系统的容错能力和稳定性,提供了负载均衡和故障转移功能,这两个功能配置简单,使用方便,只需要简单的配置就可以轻松实现负载均衡和故障转移。实现这两个功能首先需要设置Sink组,同一个Sink组内有多个子Sink,不同的Sink之间可以配置成负载均衡或者故障转移。Sink组是一个包含多个Sink的列表,不同Sink设置不同的优先级,优先级从高到低,数值越大优先级越高。
日志收集作为整个业务系统的数据源头具有非常重要的作用,日志收集系统必须保证能够灵活、持续、高效、稳定地提供数据采集服务。Flume的模块化、插件式、易扩展、自动负载均衡、高容错等特性非常适合重要业务系统的数据采集工作,Flume通过简单的配置文件可以构建一个复杂而强大的日志收集系统,虽然Flume如此易用和强大,但也需要优秀的数据收集架构设计,Flume允许各个组件自有组合以实现不同场景的日志收集架构,下面分别介绍单层收集架构和多层收集架构两种方式。
单层日志收集架构单层日志收集架构简单易用,只需要在各个日志生成节点部署单一Agent, Agent将采集到的数据发送到指定的外层存储,比如HDFS、Kafka、HBase等,这种日志采集架构设计存在一些问题:
1)采集的数据源种类比较多、采集服务器节点多,如果将这些不同服务器不同种类的数据发送到HDFS存储会产生很多小文件,HDFS采用分块多备份的存储方式,每个块文件有默认的大小,如果小文件过多会在NameNode中分配更多的内存空间来存储文件的元数据信息,给NameNode带来不必要的内存开销。小文件过多在使用MapReduce处理的时候也会产生更多的Map任务,消耗更多的集群资源,降低集群有效使用率。
2)外部存储升级维护或者出现系统故障需要对所有的日志采集层Agent进行处理,消耗更多的人力成本,降低系统的稳定性。
3)系统安全问题,单层日志收集的架构以及所有外部存储的IP、端口号等系统信息都会暴露在采集端,增大了被黑客攻击的可能,大大降低了系统安全性。
4)采集数据源多种多样,不能够清晰准确地划分层次,对于数据源的日常管理就会非常混乱,很容易引起错误的人工操作。
如果是单一业务,数据量比较小集群规模也比较小,可以选择单一采集架构,但是单一采集架构的采集方式存在上述的诸多问题,需要进一步优化采集架构。
分层日志收集架构将日志采集、日志汇聚分发分开部署,将不同种类的数据源分类划分层次。
第一层日志采集层,负责采集各业务线不同的日志数据,每台日志服务器部署一个或者多个Agent。在Agent内部根据业务场景选择负载均衡、故障转移保证系统稳定高效地运行。
第二层日志汇聚层,负责接收日志采集层实时发送过来的日志数据,根据业务类型分类,对同一类型的日志数据统一处理。如果外部存储对接的是HDFS,可以通过设置批量写入HDFS数据量和滚动生成的文件大小来控制文件数,避免小文件的大量产生。
采用分层日志收集架构的优点:
1)各种类型的日志数据分层整合处理架构清晰,运维高效,降低人工误操作风险。
2)避免过多小文件产生,提高系统稳定性和处理能力。
3)不会对外部暴露关键系统的系统信息,降低被黑客攻击的风险,大大提高系统安全性。
4)各关联系统易升级。
采用分层日志收集架构的缺点:相对于单一日志收集架构部署相对复杂,需要占用的机器资源更多,但是相对于大型的业务系统主要关心的应该是系统的稳定性、容错能力、扩展性、安全性等关键问题。
收集广告日志,广告日志文件采用滚动生成日志文件的方式,一分钟生成一个日志文件。日志采集层需要实时监控每一个新生成的日志文件,将数据发送到日志汇聚层,日志采集层的每一个Agent采用故障切换的方式配置两个或多个Sink,日志汇聚层采用多Agent接收日志采集层的数据,然后分别发送到HDFS和Kafka, HDFS的广告数据用于备份和离线计算,Kafka的数据用于实时计算。