参考文档:Flume 1.8用户手册中文版
Flume是什么?
Apache Flume 是一个分布式、高可靠、高可用的用来收集、聚合、转移不同来源的大量日志数据到中央数据仓库的工具
Flume的数据流模型:
Event 是Flume定义的一个数据流传输的最小单元。
Agent 就是一个Flume的实例,本质是一个JVM进程,该JVM进程控制Event数据流从外部日志生产者那里传输到目的地(或者是下一个Agent)。
一个完整的 Agent 中包含了三个组件Source、Channel和Sink,Source是指数据的来源和方式,Channel是一个数据的缓冲池,Sink定义了数据输出的方式和目的地。
Source消耗由外部(如Web服务器)传递给它的Event。
外部以Flume Source识别的格式向Flume发送Event。
接收的Event数据可以是任何语言编写的只要符合Thrift协议即可。
当Source接收Event时,它将其存储到一个或多个channel。
该channel是一个被动存储器,可以保持Event直到它被Sink消耗。
sink从channel中移除Event并将其放入外部存储库(如HDFS,通过 Flume的 HDFS Sink 实现)或将其转发到流中下一个Flume Agent(下一跳)的Flume Source。
Agent中的source和sink与channel存取Event是异步的。
flume的可靠性:
Event会在每个Agent的Channel上进行缓存,随后Event将会传递到流中的下一个Agent或目的地(比如HDFS)。只有成功地发送到下一个Agent或目的地后Event才会从Channel中删除。这一步保证了Event数据流在Flume Agent中传输时端到端的可靠性。
同学们这里是知识点啊(敲黑板)!
Flume的这个channel最重要的功能是用来保证数据的可靠传输的。
其实另外一个重要的功能也不可忽视,就是实现了数据流入和流出的异步执行。
Flume使用事务来保证Event的可靠传输。Source和Sink对channel提供的每个Event数据分别封装一个事务用于存储和恢复,这样就保证了数据流的集合在点对点之间的可靠传输。在多层架构的情况下,来自前一层的sink和来自下一层的Source 都会有事务在运行以确保数据安全地传输到下一层的Channel中。
flume的可恢复性
Event数据会缓存在Channel中用来在失败的时候恢复出来。Flume支持保存在本地文件系统中的『文件channel』,也支持保存在内存中的『内存Channel』,『内存Channel』显然速度会更快,缺点是万一Agent挂掉『内存Channel』中缓存的数据也就丢失了。
注:channels的类型可以是memory或file
memory需要设置:
capacity:一个内存channel有最大队列长度的属性
transactionCapacity:source和sink每次从channel写入和读取的Event数量
file需要设置:
checkpointDir:记录检查点的文件的存储目录
dataDirs:逗号分隔的目录列表,用于存储日志文件。在不同物理磁盘上使用多个目录可以提高文件channel的性能
Flume主要由3个重要的组件构成:
Source:完成对日志数据的收集,分成transtion和event打入到channel之中。
Channel:主要提供一个队列的功能,对source提供中的数据进行简单的缓存。
Sink:取出Channel中的数据,进行相应的存储文件系统,数据库,或者提交到远程服务器。
Source:
Source的类型有:
Avro Source、Thrift Source、Exec Source、JMS Source、Spooling Directory Source、Taildir Source、Twitter 1% firehose Source (实验性的)、Kafka Source、NetCat TCP Source、NetCat UDP Source、Sequence Generator Source、Syslog Sources、Syslog TCP Source、Multiport Syslog TCP Source、Syslog UDP Source、HTTP Source、Stress Source、Legacy Sources、Avro Legacy Source、Thrift Legacy Source、Custom Source、Scribe Source需要的时候可查阅官网参数配置
这里列出两种Source的配置:
Spooling Directory Source:
这个Source允许你把要收集的文件放入磁盘上的某个指定目录。它会将监视这个目录中产生的新文件,并在新文件出现时从新文件中解析数据出来。数据解析逻辑是可配置的。在新文件被完全读入Channel之后会重命名该文件以示完成(也可以配置成读完后立即删除)。
属性名 | 默认值 | 解释 |
---|---|---|
channels | – | 与Source绑定的channel,多个用空格分开 |
type | – | 组件类型,这个是: spooldir. |
spoolDir | – | Flume Source监控的文件夹目录,该目录下的文件会被Flume收集 |
fileSuffix | .COMPLETED | 被Flume收集完成的文件被重命名的后缀。1.txt被Flume收集完成后会重命名为1.txt.COMPLETED |
deletePolicy | never | 是否删除已完成收集的文件,可选值: never 或 immediate |
fileHeader | false | 是否添加文件的绝对路径名(绝对路径+文件名)到header中。 |
fileHeaderKey | file | 添加绝对路径名到header里面所使用的key(配合上面的fileHeader一起使用) |
basenameHeader | false | 是否添加文件名(只是文件名,不包括路径)到header 中 |
basenameHeaderKey | basename | 添加文件名到header里面所使用的key(配合上面的basenameHeader一起使用) |
includePattern | ^.*$ | 指定会被收集的文件名正则表达式,它跟下面的ignorePattern不冲突,可以一起使用。如果一个文件名同时被这两个正则匹配到,则会被忽略,换句话说ignorePattern的优先级更高 |
ignorePattern | ^$ | 指定要忽略的文件名称正则表达式。它可以跟 includePattern 一起使用,如果一个文件被 ignorePattern 和 includePattern 两个正则都匹配到,这个文件会被忽略。 |
trackerDir | .flumespool | 用于存储与文件处理相关的元数据的目录。如果配置的是相对目录地址,它会在spoolDir中开始创建 |
consumeOrder | oldest | 设定收集目录内文件的顺序。默认是“先来先走”(也就是最早生成的文件最先被收集),可选值有: oldest 、 youngest 和 random 。当使用oldest和youngest这两种选项的时候,Flume会扫描整个文件夹进行对比排序,当文件夹里面有大量的文件的时候可能会运行缓慢。 当使用random时候,如果一直在产生新的文件,有一部分老文件可能会很久才会被收集 |
pollDelay | 500 | Flume监视目录内新文件产生的时间间隔,单位:毫秒 |
recursiveDirectorySearch | false | 是否收集子目录下的日志文件 |
maxBackoff | 4000 | 等待写入channel的最长退避时间,如果channel已满实例启动时会自动设定一个很低的值,当遇到ChannelException异常时会自动以指数级增加这个超时时间,直到达到设定的这个最大值为止。 |
batchSize | 100 | 每次批量传输到channel时的size大小 |
inputCharset | UTF-8 | 解析器读取文件时使用的编码(解析器会把所有文件当做文本读取) |
decodeErrorPolicy | FAIL | 当从文件读取时遇到不可解析的字符时如何处理。 FAIL :抛出异常,解析文件失败; REPLACE :替换掉这些无法解析的字符,通常是用U+FFFD; IGNORE :忽略无法解析的字符。 |
deserializer | LINE | 指定一个把文件中的数据行解析成Event的解析器。默认是把每一行当做一个Event进行解析,所有解析器必须实现EventDeserializer.Builder接口 |
deserializer.* | 解析器的相关属性,根据解析器不同而不同 | |
bufferMaxLines | – | (已废弃) |
bufferMaxLineLength | 5000 | (已废弃)每行的最大长度。改用 deserializer.maxLineLength 代替 |
selector.type | replicating | 可选值:replicating 或 multiplexing ,分别表示: 复制、多路复用 |
selector.* | channel选择器的相关属性,具体属性根据设定的 selector.type 值不同而不同 | |
interceptors | – | 该source所使用的拦截器,多个用空格分开 |
interceptors.* | 拦截器相关的属性配置 |
配置范例:
a1.channels = ch-1
a1.sources = src-1
# 代表需要监控一个文件夹
a1.sources.src-1.type = spooldir
a1.sources.src-1.channels = ch-1
a1.sources.src-1.spoolDir = /var/log/apache/flumeSpool
a1.sources.src-1.fileHeader = true
Event反序列化器
下面是Flume内置的一些反序列化工具:LINE (source.deserializer=LINE)
这个反序列化器会把文本数据的每行解析成一个Event
属性 | 默认值 | 解释 |
---|---|---|
deserializer.maxLineLength | 2048 | 每个Event数据所包含的最大字符数,如果一行文本字符数超过这个配置就会被截断,剩下的字符会出现再后面的Event数据里 |
deserializer.outputCharset | UTF-8 | 解析Event所使用的编码 |
提示
deserializer.maxLineLength 的默认值是2048,这个数值对于日志行来说有点小,如果实际使用中日志每行字符数可能超过2048,超出的部分会被截断,千万记得根据自己的日志长度调大这个值。
Kafka Source
Kafka Source就是一个Apache Kafka消费者,它从Kafka的topic中读取消息。 如果运行了多个Kafka Source,则可以把它们配置到同一个消费者组,以便每个source都读取一组唯一的topic分区。
属性名 | 默认值 | 解释 |
---|---|---|
channels | – | 与Source绑定的channel,多个用空格分开 |
type | – | 组件类型,这个是: org.apache.flume.source.kafka.KafkaSource |
kafka.bootstrap.servers | – | Source使用的Kafka集群实例列表 |
kafka.consumer.group.id | flume | 消费组的唯一标识符。如果有多个source或者Agent设定了相同的ID,表示它们是同一个消费者组 |
kafka.topics | – | 将要读取消息的目标 Kafka topic 列表,多个用逗号分隔 |
kafka.topics.regex | – | 会被Kafka Source订阅的 topic 集合的正则表达式。这个参数比 kafka.topics 拥有更高的优先级,如果这两个参数同时存在,则会覆盖kafka.topics的配置。 |
batchSize | 1000 | 一批写入 channel 的最大消息数 |
batchDurationMillis | 1000 | 一个批次写入 channel 之前的最大等待时间(毫秒)。达到等待时间或者数量达到 batchSize 都会触发写操作。 |
backoffSleepIncrement | 1000 | 当Kafka topic 显示为空时触发的初始和增量等待时间(毫秒)。等待时间可以避免对Kafka topic的频繁ping操作。默认的1秒钟对于获取数据比较合适, 但是对于使用拦截器时想达到更低的延迟可能就需要配置更低一些。 |
maxBackoffSleep | 5000 | Kafka topic 显示为空时触发的最长等待时间(毫秒)。默认的5秒钟对于获取数据比较合适,但是对于使用拦截器时想达到更低的延迟可能就需要配置更低一些。 |
useFlumeEventFormat | false | 默认情况下,从 Kafka topic 里面读取到的内容直接以字节数组的形式赋值给Event。如果设置为true,会以Flume Avro二进制格式进行读取。与Kafka Sink上的同名参数或者 Kafka channel 的parseAsFlumeEvent参数相关联,这样以对象的形式处理能使生成端发送过来的Event header信息得以保留。 |
setTopicHeader | true | 当设置为true时,会把存储Event的topic名字存储到header中,使用的key就是下面的 topicHeader 的值。 |
topicHeader | topic | 如果 setTopicHeader 设置为 true ,则定义用于存储接收消息的 topic 使用header key。注意如果与 Kafka Sink 的 topicHeader 参数一起使用的时候要小心,避免又循环将消息又发送回 topic。 |
migrateZookeeperOffsets | true | 如果找不到Kafka存储的偏移量,去Zookeeper中查找偏移量并将它们提交给 Kafka 。 它应该设置为true以支持从旧版本的FlumeKafka客户端无缝迁移。 迁移后,可以将其设置为false,但通常不需要这样做。 如果在Zookeeper未找到偏移量,则可通过kafka.consumer.auto.offset.reset配置如何处理偏移量。可以从 Kafka documentation 查看更多详细信息。 |
kafka.consumer.security.protocol | PLAINTEXT | 设置使用哪种安全协议写入Kafka。可选值:SASL_PLAINTEXT、SASL_SSL 和 SSL有关安全设置的其他信息,请参见下文。 |
more consumer security props | 如果使用了SASL_PLAINTEXT、SASL_SSL 或 SSL 等安全协议,参考 Kafka security 来为消费者增加安全相关的参数配置 | |
Other Kafka Consumer Properties | – | 其他一些 Kafka 消费者配置参数。任何 Kafka 支持的消费者参数都可以使用。唯一的要求是使用“kafka.consumer.”这个前缀来配置参数,比如:kafka.consumer.auto.offset.reset |
注解:
Kafka Source 覆盖了两个Kafka 消费者的参数:auto.commit.enable 这个参数被设置成了false,Kafka Source 会提交每一个批处理。Kafka Source 保证至少一次消息恢复策略。 Source 启动时可以存在重复项。Kafka Source 还提供了key.deserializer(org.apache.kafka.common.serialization.StringSerializer) 和 value.deserializer(org.apache.kafka.common.serialization.ByteArraySerializer)的默认值,不建议修改这些参数。
通过逗号分隔的 topic 列表进行 topic 订阅的示例:
tier1.sources.source1.type = org.apache.flume.source.kafka.KafkaSource
tier1.sources.source1.channels = channel1
tier1.sources.source1.batchSize = 5000
tier1.sources.source1.batchDurationMillis = 2000
tier1.sources.source1.kafka.bootstrap.servers = localhost:9092
tier1.sources.source1.kafka.topics = test1, test2
tier1.sources.source1.kafka.consumer.group.id = custom.g.id
正则表达式 topic 订阅的示例:
tier1.sources.source1.type = org.apache.flume.source.kafka.KafkaSource
tier1.sources.source1.channels = channel1
tier1.sources.source1.kafka.bootstrap.servers = localhost:9092
tier1.sources.source1.kafka.topics.regex = ^topic[0-9]$
# the default kafka.consumer.group.id=flume is used
Channel:
channel 是在 Agent 上暂存 Event 的缓冲池。 Event由source添加,由sink消费后删除。
Channel的类型有:Memory Channel、JDBC Channel、Kafka Channel、File Channel、Spillable Memory Channel、Pseudo Transaction Channel、Custom Channel
channel 是在 Agent 上暂存 Event 的缓冲池。 Event由source添加,由sink消费后删除。
这里列出两种Channel的配置:
Memory Channel
内存 channel 是把 Event 队列存储到内存上,队列的最大数量就是 capacity 的设定值。它非常适合对吞吐量有较高要求的场景,但也是有代价的,当发生故障的时候会丢失当时内存中的所有 Event。
属性 | 默认值 | 解释 |
---|---|---|
type | – | 组件类型,这个是: memory |
capacity | 100 | 内存中存储 Event 的最大数 |
transactionCapacity | 100 | source 或者 sink 每个事务中存取 Event 的操作数量(不能比 capacity 大) |
keep-alive | 3 | 添加或删除一个 Event 的超时时间(秒) |
byteCapacityBufferPercentage | 20 | 指定 Event header 所占空间大小与 channel 中所有 Event 的总大小之间的百分比 |
byteCapacity | Channel 中最大允许存储所有 Event 的总字节数(bytes)。默认情况下会使用JVM可用内存的80%作为最大可用内存(就是JVM启动参数里面配置的-Xmx的值)。 计算总字节时只计算 Event 的主体,这也是提供 byteCapacityBufferPercentage 配置参数的原因。注意,当你在一个 Agent 里面有多个内存 channel 的时候, 而且碰巧这些 channel 存储相同的物理 Event(例如:这些 channel 通过复制机制( 复制选择器 )接收同一个 source 中的 Event), 这时候这些 Event 占用的空间是累加的,并不会只计算一次。如果这个值设置为0(不限制),就会达到200G左右的内部硬件限制。 |
提示
举2个例子来帮助理解最后两个参数吧:
两个例子都有共同的前提,假设JVM最大的可用内存是100M(或者说JVM启动时指定了-Xmx=100m)。
例子1: byteCapacityBufferPercentage 设置为20, byteCapacity 设置为52428800(就是50M),此时内存中所有 Event body 的总大小就被限制为50M *(1-20%)=40M,内存channel可用内存是50M。
例子2: byteCapacityBufferPercentage 设置为10, byteCapacity 不设置,此时内存中所有 Event body 的总大小就被限制为100M * 80% *(1-10%)=72M,内存channel可用内存是80M。
配置范例:
a1.channels = c1
a1.channels.c1.type = memory
a1.channels.c1.capacity = 10000
a1.channels.c1.transactionCapacity = 10000
a1.channels.c1.byteCapacityBufferPercentage = 20
a1.channels.c1.byteCapacity = 800000
File Channel
属性 | 默认值 | 解释 |
---|---|---|
type | – | 组件类型,这个是: file. |
checkpointDir | ~/.flume/file-channel/checkpoint | 记录检查点的文件的存储目录 |
useDualCheckpoints | false | 是否备份检查点文件。如果设置为 true , backupCheckpointDir 参数必须设置。 |
backupCheckpointDir | – | 备份检查点的目录。 此目录不能与数据目录或检查点目录 checkpointDir 相同 |
dataDirs | ~/.flume/file-channel/data | 逗号分隔的目录列表,用于存储日志文件。 在不同物理磁盘上使用多个目录可以提高文件channel的性能 |
transactionCapacity | 10000 | channel支持的单个事务最大容量 |
checkpointInterval | 30000 | 检查点的时间间隔(毫秒) |
maxFileSize | 2146435071 | 单个日志文件的最大字节数。这个默认值约等于2047MB |
minimumRequiredSpace | 524288000 | 最小空闲空间的字节数。为了避免数据损坏,当空闲空间低于这个值的时候,文件channel将拒绝一切存取请求 |
capacity | 1000000 | channel的最大容量 |
keep-alive | 3 | 存入Event的最大等待时间(秒) |
use-log-replay-v1 | false | (专家)是否使用老的回放逻辑 (Flume默认是使用v2版本的回放方法,但是如果v2版本不能正常工作可以考虑通过这个参数改为使用v1版本,v1版本是从Flume1.2开始启用的,回放是指系统关闭或者崩溃前执行的校验检查点文件和文件channel记录是否一致程序) |
use-fast-replay | false | (专家)是否开启快速回放(不适用队列) |
checkpointOnClose | true | channel关闭时是否创建检查点文件。开启次功能可以避免回放提高下次文件channel启动的速度 |
encryption.activeKey | – | 加密数据所使用的key名称 |
encryption.cipherProvider | – | 加密类型,目前只支持:AESCTRNOPADDING |
encryption.keyProvider | – | key类型,目前只支持:JCEKSFILE |
encryption.keyProvider.keyStoreFile | – | keystore 文件路径 |
encrpytion.keyProvider.keyStorePasswordFile | – | keystore 密码文件路径 |
encryption.keyProvider.keys | – | 所有key的列表,包含所有使用过的加密key名称 |
encyption.keyProvider.keys.*.passwordFile | – | 可选的秘钥密码文件路径 |
注解:
默认情况下,文件channel使用默认的用户主目录内的检查点和数据目录的路径(说的就是上面的checkpointDir参数的默认值)。 如果一个Agent中有多个活动的文件channel实例,而且都是用了默认的检查点文件, 则只有一个实例可以锁定目录并导致其他channel初始化失败。 因此,这时候有必要为所有已配置的channel显式配置不同的检查点文件目录,最好是在不同的磁盘上。 此外,由于文件channel将在每次提交后会同步到磁盘,因此将其与将Event一起批处理的sink/source耦合可能是必要的,以便在多个磁盘不可用于检查点和数据目录时提供良好的性能。
配置范例:
a1.channels = c1
a1.channels.c1.type = file
a1.channels.c1.checkpointDir = /mnt/flume/checkpoint
a1.channels.c1.dataDirs = /mnt/flume/data
Flume Sinks:
Sink的类型有:HDFS Sink、Hive Sink、Logger Sink、Avro Sink、Thrift Sink、IRC Sink、File Roll Sink、Null Sink、HBaseSinks、HBaseSink、AsyncHBaseSink、MorphlineSolrSink、ElasticSearchSink、Kite Dataset Sink、Kafka Sink、HTTP Sink、Custom Sink
这里列出三种Sink的配置:
HDFS Sink
这个Sink将Event写入Hadoop分布式文件系统(也就是HDFS)。 目前支持创建文本和序列文件。 它支持两种文件类型的压缩。 可以根据写入的时间、文件大小或Event数量定期滚动文件(关闭当前文件并创建新文件)。 它还可以根据Event自带的时间戳或系统时间等属性对数据进行分区。 存储文件的HDFS目录路径可以使用格式转义符,会由HDFS Sink进行动态地替换,以生成用于存储Event的目录或文件名。 使用此Sink需要安装hadoop, 以便Flume可以使用Hadoop的客户端与HDFS集群进行通信。 注意, 需要使用支持sync() 调用的Hadoop版本 。
属性名 | 默认值 | 解释 |
---|---|---|
channel | – | 与 Sink 连接的 channel |
type | – | 组件类型,这个是: hdfs |
hdfs.path | – | HDFS目录路径(例如:hdfs://namenode/flume/webdata/) |
hdfs.filePrefix | FlumeData | Flume在HDFS文件夹下创建新文件的固定前缀 |
hdfs.fileSuffix | – | Flume在HDFS文件夹下创建新文件的后缀(比如:.avro,注意这个“.”不会自动添加,需要显式配置) |
hdfs.inUsePrefix | – | Flume正在写入的临时文件前缀,默认没有 |
hdfs.inUseSuffix | .tmp | Flume正在写入的临时文件后缀 |
hdfs.rollInterval | 30 | 当前文件写入达到该值时间后触发滚动创建新文件(0表示不按照时间来分割文件),单位:秒 |
hdfs.rollSize | 1024 | 当前文件写入达到该大小后触发滚动创建新文件(0表示不根据文件大小来分割文件),单位:字节 |
hdfs.rollCount | 10 | 当前文件写入Event达到该数量后触发滚动创建新文件(0表示不根据 Event 数量来分割文件) |
hdfs.idleTimeout | 0 | 关闭非活动文件的超时时间(0表示禁用自动关闭文件),单位:秒 |
hdfs.batchSize | 100 | 向 HDFS 写入内容时每次批量操作的 Event 数量 |
hdfs.codeC | – | 压缩算法。可选值:gzip 、 bzip2 、 lzo 、 lzop` 、 ``snappy |
hdfs.fileType | SequenceFile | 文件格式,目前支持: SequenceFile 、 DataStream 、 CompressedStream 。 1. DataStream 不会压缩文件,不需要设置hdfs.codeC 2. CompressedStream 必须设置hdfs.codeC参数 |
hdfs.maxOpenFiles | 5000 | 允许打开的最大文件数,如果超过这个数量,最先打开的文件会被关闭 |
hdfs.minBlockReplicas | – | 指定每个HDFS块的最小副本数。 如果未指定,则使用 classpath 中 Hadoop 的默认配置。 |
hdfs.writeFormat | Writable | 文件写入格式。可选值: Text 、 Writable 。在使用 Flume 创建数据文件之前设置为 Text,否则 Apache Impala(孵化)或 Apache Hive 无法读取这些文件。 |
hdfs.callTimeout | 10000 | 允许HDFS操作文件的时间,比如:open、write、flush、close。如果HDFS操作超时次数增加,应该适当调高这个这个值。(毫秒) |
hdfs.threadsPoolSize | 10 | 每个HDFS Sink实例操作HDFS IO时开启的线程数(open、write 等) |
hdfs.rollTimerPoolSize | 1 | 每个HDFS Sink实例调度定时文件滚动的线程数 |
hdfs.kerberosPrincipal | – | 用于安全访问 HDFS 的 Kerberos 用户主体 |
hdfs.kerberosKeytab | – | 用于安全访问 HDFS 的 Kerberos keytab 文件 |
hdfs.proxyUser | 代理名 | |
hdfs.round | false | 是否应将时间戳向下舍入(如果为true,则影响除 %t 之外的所有基于时间的转义符) |
hdfs.roundValue | 1 | 向下舍入(小于当前时间)的这个值的最高倍(单位取决于下面的 hdfs.roundUnit ) 例子:假设当前时间戳是18:32:01,hdfs.roundUnit = minute 如果roundValue=5,则时间戳会取为:18:30 如果roundValue=7,则时间戳会取为:18:28 如果roundValue=10,则时间戳会取为:18:30 |
hdfs.roundUnit | second | 向下舍入的单位,可选值: second 、 minute 、 hour |
hdfs.timeZone | Local Time | 解析存储目录路径时候所使用的时区名,例如:America/Los_Angeles、Asia/Shanghai |
hdfs.useLocalTimeStamp | false | 使用日期时间转义符时是否使用本地时间戳(而不是使用 Event header 中自带的时间戳) |
hdfs.closeTries | 0 | 开始尝试关闭文件时最大的重命名文件的尝试次数(因为打开的文件通常都有个.tmp的后缀,写入结束关闭文件时要重命名把后缀去掉)。 如果设置为1,Sink在重命名失败(可能是因为 NameNode 或 DataNode 发生错误)后不会重试,这样就导致了这个文件会一直保持为打开状态,并且带着.tmp的后缀; 如果设置为0,Sink会一直尝试重命名文件直到成功为止; 关闭文件操作失败时这个文件可能仍然是打开状态,这种情况数据还是完整的不会丢失,只有在Flume重启后文件才会关闭。 |
hdfs.retryInterval | 180 | 连续尝试关闭文件的时间间隔(秒)。 每次关闭操作都会调用多次 RPC 往返于 Namenode ,因此将此设置得太低会导致 Namenode 上产生大量负载。 如果设置为0或更小,则如果第一次尝试失败,将不会再尝试关闭文件,并且可能导致文件保持打开状态或扩展名为“.tmp”。 |
serializer | TEXT | Event 转为文件使用的序列化器。其他可选值有: avro_event 或其他 EventSerializer.Builderinterface 接口的实现类的全限定类名。 |
serializer.* | 根据上面 serializer 配置的类型来根据需要添加序列化器的参数 |
配置范例:
a1.channels = c1
a1.sinks = k1
a1.sinks.k1.type = hdfs
a1.sinks.k1.channel = c1
a1.sinks.k1.hdfs.path = /flume/events/%y-%m-%d/%H%M/%S
a1.sinks.k1.hdfs.filePrefix = events-
a1.sinks.k1.hdfs.round = true
a1.sinks.k1.hdfs.roundValue = 10
a1.sinks.k1.hdfs.roundUnit = minute
Logger Sink
使用INFO级别把Event内容输出到日志中,一般用来测试、调试使用。这个 Sink 是唯一一个不需要额外配置就能把 Event 的原始内容输出的Sink,参照 输出原始数据到日志 。
提示
在 输出原始数据到日志 一节中说过,通常在Flume的运行日志里面输出数据流中的原始的数据内容是非常不可取的,所以 Flume 的组件默认都不会这么做。但是总有特殊的情况想要把 Event 内容打印出来,就可以借助这个Logger Sink了。
属性 | 默认值 | 解释 |
---|---|---|
channel | – | 与 Sink 绑定的 channel |
type | – | 组件类型,这个是: logger |
maxBytesToLog | 16 | Event body 输出到日志的最大字节数,超出的部分会被丢弃 |
配置范例:
a1.channels = c1
a1.sinks = k1
a1.sinks.k1.type = logger
a1.sinks.k1.channel = c1
Kafka Sink
这个 Sink 可以把数据发送到 Kafka topic上。目的就是将 Flume 与 Kafka 集成,以便基于拉的处理系统可以处理来自各种 Flume Source 的数据。目前支持 Kafka 0.9.x 发行版。
Flume1.8 不再支持 Kafka 0.9.x(不包括0.9.x)以前的版本。
属性 | 默认值 | 解释 |
---|---|---|
type | – | 组件类型,这个是: org.apache.flume.sink.kafka.KafkaSink |
kafka.bootstrap.servers | – | Kafka Sink 使用的 Kafka 集群的实例列表,可以是实例的部分列表。但是更建议至少两个用于高可用(HA)支持。格式为 hostname:port,多个用逗号分隔 |
kafka.topic | default-flume-topic | 用于发布消息的 Kafka topic 名称 。如果这个参数配置了值,消息就会被发布到这个 topic 上。如果Event header中包含叫做“topic”的属性, Event 就会被发布到 header 中指定的 topic 上,而不会发布到 kafka.topic 指定的 topic 上。支持任意的 header 属性动态替换, 比如%{lyf}就会被 Event header 中叫做“lyf”的属性值替换(如果使用了这种动态替换,建议将 Kafka 的 auto.create.topics.enable 属性设置为 true )。 |
flumeBatchSize | 100 | 一批中要处理的消息数。设置较大的值可以提高吞吐量,但是会增加延迟。 |
kafka.producer.acks | 1 | 在考虑成功写入之前,要有多少个副本必须确认消息。可选值, 0 :(从不等待确认); 1 :只等待leader确认; -1 :等待所有副本确认。 设置为-1可以避免某些情况 leader 实例失败的情况下丢失数据。 |
useFlumeEventFormat | false | 默认情况下,会直接将 Event body 的字节数组作为消息内容直接发送到 Kafka topic 。如果设置为true,会以 Flume Avro 二进制格式进行读取。 与 Kafka Source 上的同名参数或者 Kafka channel 的 parseAsFlumeEvent 参数相关联,这样以对象的形式处理能使生成端发送过来的 Event header 信息得以保留。 |
defaultPartitionId | – | 指定所有 Event 将要发送到的 Kafka 分区ID,除非被 partitionIdHeader 参数的配置覆盖。 默认情况下,如果没有设置此参数,Event 会被 Kafka 生产者的分发程序分发,包括 key(如果指定了的话),或者被 kafka.partitioner.class 指定的分发程序来分发 |
partitionIdHeader | – | 设置后,Sink将使用 Event header 中使用此属性的值命名的字段的值,并将消息发送到 topic 的指定分区。 如果该值表示无效分区,则将抛出 EventDeliveryException。 如果存在标头值,则此设置将覆盖 defaultPartitionId 。假如这个参数设置为“lyf”,这个 Sink 就会读取 Event header 中的 lyf 属性的值,用该值作为分区ID |
allowTopicOverride | true | 如果设置为 true,会读取 Event header 中的名为 topicHeader 的的属性值,用它作为目标 topic。 |
topicHeader | topic | 与上面的 allowTopicOverride 一起使用,allowTopicOverride 会用当前参数配置的名字从 Event header 获取该属性的值,来作为目标 topic 名称 |
kafka.producer.security.protocol | PLAINTEXT | 设置使用哪种安全协议写入 Kafka。可选值:SASL_PLAINTEXT 、 SASL_SSL 和 SSL, 有关安全设置的其他信息,请参见下文。 |
more producer security props | 如果使用了 SASL_PLAINTEXT 、 SASL_SSL 或 SSL 等安全协议,参考 Kafka security 来为生产者增加安全相关的参数配置 | |
Other Kafka Producer Properties | – | 其他一些 Kafka 生产者配置参数。任何 Kafka 支持的生产者参数都可以使用。唯一的要求是使用“kafka.producer.”这个前缀来配置参数,比如:kafka.producer.linger.ms |
注解
Kafka Sink使用 Event header 中的 topic 和其他关键属性将 Event 发送到 Kafka。 如果 header 中存在 topic,则会将Event发送到该特定 topic,从而覆盖为Sink配置的 topic。 如果 header 中存在指定分区相关的参数,则Kafka将使用相关参数发送到指定分区。 header中特定参数相同的 Event 将被发送到同一分区。 如果为空,则将 Event 会被发送到随机分区。 Kafka Sink 还提供了key.deserializer(org.apache.kafka.common.serialization.StringSerializer) 和value.deserializer(org.apache.kafka.common.serialization.ByteArraySerializer)的默认值,不建议修改这些参数。
弃用的一些参数:
属性 | 默认值 | 解释 |
---|---|---|
brokerList | – | 改用 kafka.bootstrap.servers |
topic | default-flume-topic | 改用 kafka.topic |
batchSize | 100 | 改用 kafka.flumeBatchSize |
requiredAcks | 1 | 改用 kafka.producer.acks |
下面给出 Kafka Sink 的配置示例。Kafka 生产者的属性都是以 kafka.producer 为前缀。Kafka 生产者的属性不限于下面示例的几个。此外,可以在此处包含您的自定义属性,并通过作为方法参数传入的Flume Context对象在预处理器中访问它们。
a1.sinks.k1.channel = c1
a1.sinks.k1.type = org.apache.flume.sink.kafka.KafkaSink
a1.sinks.k1.kafka.topic = mytopic
a1.sinks.k1.kafka.bootstrap.servers = localhost:9092
a1.sinks.k1.kafka.flumeBatchSize = 20
a1.sinks.k1.kafka.producer.acks = 1
a1.sinks.k1.kafka.producer.linger.ms = 1
a1.sinks.k1.kafka.producer.compression.type = snappy
flume的安装和配置:
解压flume压缩包,并重命名:
[root@hadoop100 opt]# tar xf flume-ng-1.6.0-cdh5.14.0.tar.gz
[root@hadoop100 opt]# mv apache-flume-1.6.0-cdh5.14.0-bin/ flume160
修改配置文件flume-env.sh:
cd /opt/flume160/conf/
cp flume-env.sh.template flume-env.sh
修改以下两处配置:
export JAVA_HOME=/opt/java8
export JAVA_OPTS="-Xms2048m -Xmx2048m -Dcom.sun.management.jmxremote"
在source.type的时候我们看到了有netcat的数据源:
netcat (nc)又被称为"瑞士军刀"
安装nc和telnet:
telnet可以实现的功能:
连接服务器端口,并进行通信 登录远程telnet服务器,使用命令行对其进行控制
nc可以实现的功能:
监听服务器端口,并与客户端通信(最多只能接收一个客户端) 对指定服务器进行端口扫描 作为客户端连接到远程服务器进行通信
yum install -y nc
yum list telnet*
yum install -y telnet-server.*
yum install -y telnet.*
测试:
server:
nc -lk 7777
client:
telnet localhost 7777
客户端和服务端可以彼此通信收发信息。会在对方的阻塞窗口展示。
# 定义 source,channel和sink的名字
a1.sources=s1
a1.channels=c1
a1.sinks=sk1
# 对source的一些设置
a1.sources.s1.type=netcat
a1.sources.s1.bind=localhost
a1.sources.s1.port=5678
a1.sources.s1.channels=c1
# 对channel的一些设置
a1.channels.c1.type=memory
# 对sink的一些设置
a1.sinks.sk1.type=logger
a1.sinks.sk1.channel=c1
注意:一个source可以连接多个channel,但是一个channel只能往后连接一个sink 所以最后的channel使用单数
启动flume-ng:【路径上容易出现问题,flume-ng的路径,conf文件的路径,agent的名字】
flume-ng agent --name a1 -f source_netcat.conf -Dflume.root.logger=INFO,console
telnet localhost 5678
输入 hello world
flume监控输出:21/01/15 09:13:37 INFO sink.LoggerSink: Event: { headers:{} body: 68 65 6C 6C 6F 20 77 6F 72 6C 64 0D hello world. }
通过telnet命令将数据发送到了netcat 5678端口号,flume将数据传输到c1中,c1是内存,然后sink的channel是c1会到内存中拉取数据,将数据输出到日志里。
编写agent配置文件:
[root@hadoop100 flume160]# cat ./conf/jobkb09/netcat-flume-logger.conf
a1.sources=r1
a1.channels=c1
a1.sinks=k1
a1.sources.r1.type=netcat
a1.sources.r1.bind=localhost
a1.sources.r1.port=7777
a1.channels.c1.type=memory
# 一个内存channel有最大队列长度的属性(capacity)
a1.channels.c1.capacity=1000
# source和sink每次从channel写入和读取的Event数量
a1.channels.c1.transactionCapacity=1000
a1.sinks.k1.type=logger
a1.sources.r1.channels=c1
a1.sinks.k1.channel=c1
---------------------------------
启动flume agent
[root@hadoop100 flume160]# ./bin/flume-ng agent --name a1 --conf ./conf/ --conf-file ./conf/jobkb09/netcat-flume-logger.conf -Dflume.root.logger=INFO,console
在另外一个session输入
telnet localhost 7777
输入的内容会在flume控制台展示:类似于json字符串的形式
例如输入:aaa
2020-11-30 19:59:17,670 (SinkRunner-PollingRunner-DefaultSinkProcessor) [INFO - org.apache.flume.sink.LoggerSink.process(LoggerSink.java:95)] Event: { headers:{} body: 61 61 61 0D aaa. }
exec source: 案例:实现遍历文件夹
编写echoPath.sh文件:
#!/bin/bash
for i in /path/*.txt
do
echo $i
done
source_exec.conf文件:
# 定义 source,channel和sink的名字
a1.sources=s1
a1.channels=c1
a1.sinks=sk1
# 对source的一些设置 设置类型为exec 代表需要执行一条命令,所以需要command属性
a1.sources.s1.type=exec
a1.sources.s1.command= bash echoPath.sh
a1.sources.s1.channels=c1
# 对channel的一些设置
a1.channels.c1.type=memory
# 对sink的一些设置
a1.sinks.sk1.type=logger
a1.sinks.sk1.channel=c1
从文件输入,控制台输出:
[root@hadoop100 flume160]# cat /opt/flume160/conf/jobkb09/tmp/tmp.txt
hello
spark
[root@hadoop100 ~]# cat /opt/flume160/conf/jobkb09/file-flume-logger.conf
a2.sources=r1
a2.channels=c1
a2.sinks=k1
a2.sources.r1.type=exec
a2.sources.r1.command=tail -f /opt/flume160/conf/jobkb09/tmp/tmp.txt
a2.channels.c1.type=memory
a2.channels.c1.capacity=1000
a2.channels.c1.transactionCapacity=1000
a2.sinks.k1.type=logger
a2.sources.r1.channels=c1
a2.sinks.k1.channel=c1
启动flume agent
[root@hadoop100 flume160]# ./bin/flume-ng agent --name a2 --conf ./conf/ --conf-file ./conf/jobkb09/file-flume-logger.conf -Dflume.root.logger=INFO,console
输出结果:
2020-11-30 20:03:54,602 (SinkRunner-PollingRunner-DefaultSinkProcessor) [INFO - org.apache.flume.sink.LoggerSink.process(LoggerSink.java:95)] Event: { headers:{} body: 68 65 6C 6C 6F hello }
2020-11-30 20:03:54,602 (SinkRunner-PollingRunner-DefaultSinkProcessor) [INFO - org.apache.flume.sink.LoggerSink.process(LoggerSink.java:95)] Event: { headers:{} body: 73 70 61 72 6B spark }
对文件追加:
[root@hadoop100 flume160]# echo flume >> /opt/flume160/conf/jobkb09/tmp/tmp.txt
控制台继续打印:
2020-11-30 20:05:05,048 (SinkRunner-PollingRunner-DefaultSinkProcessor) [INFO - org.apache.flume.sink.LoggerSink.process(LoggerSink.java:95)] Event: { headers:{} body: 66 6C 75 6D 65 flume }
读取csv文件:
[root@hadoop100 opt]# cd flume160/conf/jobkb09/
[root@hadoop100 jobkb09]# vi events-flume-logger.conf
[root@hadoop100 jobkb09]# cat ./events-flume-logger.conf
events.sources=eventsSource
events.channels=eventsChannel
events.sinks=eventsSink
events.sources.eventsSource.type=spooldir
events.sources.eventsSource.spoolDir=/opt/flume160/conf/jobkb09/dataSourceFile/events //events_2020-11-30.csv
events.sources.eventsSource.deserializer=LINE
events.sources.eventsSource.deserializer.maxLineLength=10000
events.sources.eventsSource.includePattern=events_[0-9]{4}-[0-9]{2}-[0-9]{2}.csv
events.channels.eventsChannel.type=file
events.channels.eventsChannel.checkpointDir=/opt/flume160/conf/jobkb09/checkPointFile/events
events.channels.eventsChannel.dataDirs=/opt/flume160/conf/jobkb09/dataChannelFile/events
events.sinks.eventsSink.type=logger
events.sources.eventsSource.channels=eventsChannel
events.sinks.eventsSink.channel=eventsChannel
[root@hadoop100 tmp]# cp ./events.csv /opt/flume160/conf/jobkb09/dataSourceFile/events/events_2020-11-30.csv
./bin/flume-ng agent --name events --conf ./conf/ --conf-file /opt/flume160/conf/jobkb09/events-flume-logger.conf -Dflume.root.logger=INFO,console
写入到hdfs:
user_friend.sources=userFriendSource
user_friend.channels=userFriendChannel
user_friend.sinks=userFriendSink
user_friend.sources.userFriendSource.type=spoolDir
user_friend.sources.userFriendSource.spoolDir=/opt/flume160/conf/jobkb09/dataSourceFile/userFriend
user_friend.sources.userFriendSource.deserializer=LINE
user_friend.sources.userFriendSource.deserializer.maxLineLength=320000
user_friend.sources.userFriendSource.includePattern=userFriend_[0-9]{4}-[0-9]{2}-[0-9]{2}.csv
user_friend.channels.userFriendChannel.type=file
user_friend.channels.userFriendChannel.checkpointDir=/opt/flume160/conf/jobkb09/checkPointFile/userFriend
user_friend.channels.userFriendChannel.dataDirs=/opt/flume160/conf/jobkb09/dataChannelFile/userFriend
user_friend.sinks.userFriendSink.type=hdfs
user_friend.sinks.userFriendSink.hdfs.fileType=DataStream
user_friend.sinks.userFriendSink.hdfs.filePrefix=userFriend
user_friend.sinks.userFriendSink.hdfs.fileSuffix=.csv
user_friend.sinks.userFriendSink.hdfs.path=hdfs://192.168.237.100:9000/kb09file/user/userFriend/%Y-%m-%d
user_friend.sinks.userFriendSink.hdfs.useLocalTimeStamp=true
user_friend.sinks.userFriendSink.hdfs.batchSize=640
user_friend.sinks.userFriendSink.hdfs.rollInterval=20
user_friend.sinks.userFriendSink.hdfs.rollCount=0
user_friend.sinks.userFriendSink.hdfs.rollSize=120000000
user_friend.sources.userFriendSource.channels=userFriendChannel
user_friend.sinks.userFriendSink.channel=userFriendChannel
执行操作:
./bin/flume-ng agent --name user_friend --conf ./conf/ --conf-file /opt/flume160/conf/jobkb09/userfriend-flume-hdfs.conf -Dflume.root.logger=INFO,console
在source里使用interceptors拦截器:
users.sources=userSource
users.channels=userChannel
users.sinks=userSink
users.sources.userSource.type=spooldir
users.sources.userSource.spoolDir=/opt/flume160/conf/jobkb09/dataSourceFile/user
users.sources.userSource.includePattern=users_[0-9]{4}-[0-9]{2}-[0-9]{2}.csv
users.sources.userSource.deserializer=LINE
users.sources.userSource.deserializer.maxLineLength=10000
users.sources.userSource.interceptors=head_filter
users.sources.userSource.interceptors.head_filter.type=regex_filter
users.sources.userSource.interceptors.head_filter.regex=^user_id*
users.sources.userSource.interceptors.head_filter.excludeEvents=true
users.channels.userChannel.type=file
users.channels.userChannel.checkpointDir=/opt/flume160/conf/jobkb09/checkPointFile/user
users.channels.userChannel.dataDirs=/opt/flume160/conf/jobkb09/dataChannelFile/user
users.sinks.userSink.type=hdfs
users.sinks.userSink.hdfs.fileType=DataStream
users.sinks.userSink.hdfs.filePrefix=users
users.sinks.userSink.hdfs.fileSuffix=.csv
users.sinks.userSink.hdfs.path=hdfs://192.168.237.100:9000/kb09file/user/users/%Y-%m-%d
users.sinks.userSink.hdfs.useLocalTimeStamp=true
users.sinks.userSink.hdfs.batchSize=640
users.sinks.userSink.hdfs.rollCount=0
users.sinks.userSink.hdfs.rollSize=120000000
users.sinks.userSink.hdfs.rollInterval=20
users.sources.userSource.channels=userChannel
users.sinks.userSink.channel=userChannel
执行操作:
./bin/flume-ng agent --name users --conf ./conf/ --conf-file ./conf/jobkb09/user-flume-hdfs.conf -Dflume.root.logger=INFO,console