参考博文地址:Fluentd-kafka插件用法详解
一个既可以消费 Kafka 也可以向 Kafka 中生产数据的 Fluentd 插件。
将这一行添加到你的应用程序的 Gemfile 中:
gem 'fluent-plugin-kafka'
然后执行:
$ bundle
或者自己安装:
$ gem install fluent-plugin-kafka --no-document
如果需要使用 zookeeper 相关参数,还需要安装 zookeeper gem。zookeeper gem 包含本地扩展,所以需要开发工具,例如 ruby-devel,gcc,make 等。
设置路径为 SSL 相关文件。有关详细信息,请参阅使用 SSL 的加密和身份验证。
with GSSAPI
Set principal and path to keytab for SASL/GSSAPI authentication. See Authentication using SASL for more details.
with Plain/SCRAM
Set username, password, scram_mechanism and sasl_over_ssl for SASL/Plain or Scram authentication. See Authentication using SASL for more details.
插件以“单消费者”模式订阅 kafka 消息。单消费者模式是指:每个 kafka 输入插件独立地订阅 kafka 消息。
这种模式可以满足极简单的应用场景。其缺点为:
单消费者模式下,kafka 输入插件配置说明如下:
<source>
# 插件类型 kafka
@type kafka
# 逗号分隔的 broker 列表,每个 broker 需要指定 ip 和端口
brokers <broker1_host>:<broker1_port>,<broker2_host>:<broker2_port>,..
# 逗号分隔的 topic 列表
topics <listening topics(separate with comma',')>
# 输入消息的格式,有 text、json、ltsv、msgpack 等几种,默认 json
format <input text type (text|json|ltsv|msgpack)> :default => json
# 可选,消息格式为 text 时,指定消息的 key,默认是 message
message_key <key (Optional, for text format only, default is message)>
# tag 增加前缀
add_prefix <tag prefix (Optional)>
# tag 增加后缀
add_suffix <tag suffix (Optional)>
# 还可以使用 zookeeper 管理 topic 偏移量
offset_zookeeper <zookeer node list (> :<zookeeper1_port>,<zookeeper2_host>:<zookeeper2_port>,..)>
offset_zk_root_node <offset path in zookeeper> default => '/fluent-plugin-kafka'
# ruby-kafka 消费者选项
max_bytes (integer) :default => nil (Use default of ruby-kafka)
max_wait_time (integer) :default => nil (Use default of ruby-kafka)
min_bytes (integer) :default => nil (Use default of ruby-kafka)
source>
支持从指定的偏移量开始处理特定 topic。
<source>
@type kafka
brokers <broker1_host>:<broker1_port>,<broker2_host>:<broker2_port>,..
format <input text type (text|json|ltsv|msgpack)>
<topic>
topic <listening topic>
partition <listening partition: default=0>
offset <listening start offset: default=-1>
topic>
<topic>
topic <listening topic>
partition <listening partition: default=0>
offset <listening start offset: default=-1>
topic>
source>
更多关于 ruby-kafka 的详细文档,请参见 ruby-kafka README。
消费 topic 名称用于事件 tag。因此,当目标 topic 名称为app_event
时,tag 为app_event
。如果要修改 tag,请使用add_prefix
或add_suffix
参数。使用add_prefix kafka
,tag 就是kafka.app_event
。
插件以“消费者组”模式订阅 kafka 消息。消费者组模式解决了单消费者模式存在的几个缺点,可以同时启动多个 Fluentd 进程协同工作。
配置说明如下:
<source>
# 插件类型 kafka_group
@type kafka_group
# 逗号分隔的 broker 列表,每个 broker 需要指定 ip 和端口
brokers <broker1_host>:<broker1_port>,<broker2_host>:<broker2_port>,..
# 设定消费者组名称,必须设置
consumer_group <consumer group name, must set>
# 逗号分隔的 topic 列表
topics <listening topics(separate with comma',')>
# 输入消息的格式,有 text、json、ltsv、msgpack 等几种,默认 json
format <input text type (text|json|ltsv|msgpack)> :default => json
# 可选,消息格式为 text 时,指定消息的 key,默认是 message
message_key <key (Optional, for text format only, default is message)>
# 可选,如果指定,则设置 kafka 的 message key 为该 key
kafka_mesasge_key <key (Optional, If specified, set kafka's message key to this key)>
# 如果为 true,添加 kafka 的消息头到记录中
add_headers <If true, add kafka's message headers to record>
# tag 增加前缀
add_prefix <tag prefix (Optional)>
# tag 增加后缀
add_suffix <tag suffix (Optional)>
# 当 BuffereQueueLimitError 发生时等待 retry_emit_limit 秒。默认值是nil,这意味着等待直到 BufferQueueLimitError 被解决
retry_emit_limit <Wait retry_emit_limit x 1s when BuffereQueueLimitError happens. The default is nil and it means waiting until BufferQueueLimitError is resolved>
# 弃用。使用'time_source record'代替。如果为 true,则将事件时间替换为所取记录的'time'字段的内容。
use_record_time (Deprecated. Use 'time_source record' instead.) <If true, replace event time with contents of 'time' field of fetched record>
# 指定日志事件中时间戳来源,可取 now、kafka 和 record,默认为 now
time_source <source for message timestamp (now|kafka|record)> :default => now
# 当时间源为 record 时,设置时间格式以提取其中的时间戳,当 use_record_time 选项被使用时可用
time_format <string (Optional when use_record_time is used)>
# ruby-kafka 消费者 options
max_bytes (integer) :default => 1048576
max_wait_time (integer) :default => nil (Use default of ruby-kafka)
min_bytes (integer) :default => nil (Use default of ruby-kafka)
# 设置 offset 提交时间间隔,默认10秒
offset_commit_interval (integer) :default => nil (Use default of ruby-kafka)
# 插件可批量处理消息后再提交一次 offset,此参数用于设置批量处理的消息数。默认为 0,不采用批量提交机制。
offset_commit_threshold (integer) :default => nil (Use default of ruby-kafka)
fetcher_max_queue_size (integer) :default => nil (Use default of ruby-kafka)
# true 表示从头开始消费 topic。false 表示只消费新消息。默认为 true。
start_from_beginning (bool) :default => true
source>
更多关于 ruby-kafka 的详细文档,请参见 ruby-kafka README。
topic
从 v0.13.1 开始支持正则表达式模式。如果你想使用正则表达式模式,使用/pattern/
像/foo.*/
这样。
消费 topic 名称用于事件 tag。因此,当目标 topic 名称为app_event
时,tag 为app_event
。如果要修改 tag,请使用add_prefix
或add_suffix
参数。使用add_prefix kafka
,tag 就是kafka.app_event
。
in_rdkafka_group 消费者还没有在高的生产负载下进行测试。使用它的风险自负!
随着基于 rdkafka-ruby 的输入插件的引入,我们希望能够支持 2.1 版本以上的 Kafka broker,在这个版本中我们看到了使用基于 ruby-kafka 的 @kafka_group输入类型时的兼容性问题。rdkafka-ruby 库包装了高性能的、可以生产的 librdkafka C 库。
<source>
@type rdkafka_group
topics <listening topics(separate with comma',')>
format <input text type (text|json|ltsv|msgpack)> :default => json
message_key <key (Optional, for text format only, default is message)>
kafka_mesasge_key <key (Optional, If specified, set kafka's message key to this key)>
add_headers <If true, add kafka's message headers to record>
add_prefix <tag prefix (Optional)>
add_suffix <tag suffix (Optional)>
retry_emit_limit <Wait retry_emit_limit x 1s when BuffereQueueLimitError happens. The default is nil and it means waiting until BufferQueueLimitError is resolved>
use_record_time (Deprecated. Use 'time_source record' instead.) <If true, replace event time with contents of 'time' field of fetched record>
time_source <source for message timestamp (now|kafka|record)> :default => now
time_format <string (Optional when use_record_time is used)>
# kafka 消费者 options
max_wait_time_ms 500
max_batch_size 10000
kafka_configs {
"bootstrap.servers": "brokers <broker1_host>:<broker1_port>,<broker2_host>:<broker2_port>",
"group.id": "<consumer group name>"
}
source>
更多关于 ruby-kafka 的详细文档,请参见 ruby-kafka README。
消费 topic 名称用于事件 tag。因此,当目标 topic 名称为app_event
时,tag 为app_event
。如果要修改 tag,请使用add_prefix
或add_suffix
参数。使用add_prefix kafka
,tag 就是kafka.app_event
。
用于向 kafka 发布消息。
这个kafka2
插件适用于 fluentd v1 或更高版本。这个插件使用ruby-kafka
生成器来写数据。如果ruby-kafka
不适合你的 kafka 环境,请检查rdkafka2
插件。未来将使用out_kafka
替代kafka2
。
<match app.**>
# 插件类型 kafka2
@type kafka2
# 逗号分隔的 broker 列表,每个 broker 需要指定 ip 和端口
brokers <broker1_host>:<broker1_port>,<broker2_host>:<broker2_port>,.. # Set brokers directly
# 设置目的 topic 取自日志记录中的哪个字段
topic_key (string) :default => 'topic'
partition_key (string) :default => 'partition'
partition_key_key (string) :default => 'partition_key'
message_key_key (string) :default => 'message_key'
# 默认 topic,若未设置 topic_key,则 topic 取此处的值
default_topic (string) :default => nil
default_partition_key (string) :default => nil
default_message_key (string) :default => nil
exclude_topic_key (bool) :default => false
exclude_partition_key (bool) :default => false
exclude_partition (bool) :default => false
exclude_message_key (bool) :default => false
get_kafka_client_log (bool) :default => false
headers (hash) :default => {}
headers_from_record (hash) :default => {}
use_default_for_unknown_topic (bool) :default => false
# 默认为 false,丢弃 Kafka::DeliveryFailed 引发的记录
discard_kafka_delivery_failed (bool) :default => false (No discard)
# 设置输出消息格式,支持 json、ltsv、msgpack或其他输出插件,默认是 json
<format>
@type (json|ltsv|msgpack|attr:<record name>|<formatter name>) :default => json
format>
# Optional. See https://docs.fluentd.org/v/1.0/configuration/inject-section
<inject>
tag_key tag
time_key time
inject>
# 有关缓冲区的相关参数,请参阅 fluentd 文档: https://docs.fluentd.org/v/1.0/configuration/buffer-section
# 缓冲区块 key 应该与 topic_key 相同。如果在记录中没有找到 value,则使用default_topic。
<buffer topic>
flush_interval 10s
buffer>
# ruby-kafka 生产者 options
idempotent (bool) :default => false
sasl_over_ssl (bool) :default => true
# 默认值 1 ,向 leader 重试发送消息的次数。
max_send_retries (integer) :default => 1
# 设置每个请求的 ack 数,可设置 1、2 这样的小的数字以提高性能,-1 表示不进行确认,默认为 -1
required_acks (integer) :default => -1
# 默认为 nil,生产者等待 ack 的时间。单位为秒。
ack_timeout (integer) :default => nil (Use default of ruby-kafka)
# 设置输出消息的压缩方式,生产者用来压缩消息的编解码器。支持 gzip 和 snappy。默认是 nil,没有压缩
compression_codec (string) :default => nil (No compression. Depends on ruby-kafka: https://github.com/zendesk/ruby-kafka#compression)
match>
比如:topic_key 为日志中的 category 字段,如果某条消息中该字段的值为 app,那么该条消息会被发布到 kafka 中名称为 app 的 topic 中。
需要注意的是,在插件的缓存配置中也需要设置该参数的取值。
topic_key category
<buffer category> # topic_key should be included in buffer chunk key
# ...
buffer>
如果你设置了 topic_key 为 category,那么在 配置中也需要以此作为 chunk 的类型值。
中的
使用 fluentd 的 formatter 插件。参见 formatter article。
ruby-kafka 有时会返回 Kafka::DeliveryFailed 错误,没有良好的信息。在这种情况下,get_kafka_client_log 对于识别错误原因很有用。ruby-kafka 的日志被路由到 fluentd 日志,所以你可以在 fluentd 日志中看到 ruby-kafka 的日志。
支持 ruby-kafka 的生产者选项。
MessageSizeTooLarge
。例如,如果您设置了 1000000(message.max.bytes 在 kafka)。超过 1000000 字节的消息将被丢弃。Kafka::DeliveryFailed
引发的记录。[]
,用于监控的 library。支持 statsd 和 datadog。如果您想了解监控的详细信息,请参见 https://github.com/zendesk/ruby-kafka#monitoring参见 Kafka::Client 获取更多关于 ruby-kafka 的详细文档。
这个插件也支持压缩编解码器“snappy”。在使用 snappy 压缩之前安装 snappy 模块。
$ gem install snappy --no-document
snappy gem 使用本地扩展,所以你需要安装几个包之前。在 Ubuntu 上,需要开发包和 snappy 库。
$ sudo apt-get install build-essential autoconf automake libtool libsnappy-dev
在 CentOS 7 上安装也是必要的。
$ sudo yum install gcc autoconf automake libtool snappy-devel
这个插件也支持压缩编解码“lz4”。在使用 lz4 压缩之前,请安装 extlz4 模块。
$ gem install extlz4 --no-document
这个插件也支持压缩编解码器“zstd”。在使用 zstd 压缩之前先安装 zstd-ruby 模块。
$ gem install zstd-ruby --no-document
默认情况下,发布的消息会被随机分配到 kafka topic 的一个分区。输出插件支持通过设置default_partition_key
或partition_key_key
的方式将消息分配到特定的分区中。具有相同partition
值的消息会被分配到同一个分区。
default_partition_key | partition_key_key | 消息负载均衡方式 |
---|---|---|
未设置 | 不存在 | 所有消息被随机分配到一个分区 |
已设置 | 不存在 | 所有消息都分配到特定的分区 |
未设置 | 已存在 | 含有partition_key_key 字段的消息被分配到该字段指定的分区;其他消息随机分配一个分区 |
已设置 | 已存在 | 含有partition_key_key 字段的消息被分配到该字段指定的分区;其他消息分配到default_partition_key 指定的分区 |
如果消息中存在 key 名为 message_key_key,则该插件将 message_key_key 的值发布给 kafka,并且可以被消费者读取。通过在配置文件中设置 default_message_key,将为所有消息分配相同的消息键。如果 message_key_key 存在且未显式设置 partition_key_key,则 message_key_key 将用于分区。
可以在 Kafka 消息上设置头信息。这只适用于 kafka2 和 rdkafka2 输出插件。
格式为key1:value1,key2:value2
。例如:
<match app.**>
@type kafka2
[...]
headers some_header_name:some_header_value
<match>
您可以基于 fluentd 记录字段的值设置头信息。例如,假设一条 fluentd 记录:
{"source": { "ip": "127.0.0.1" }, "payload": "hello world" }
下面的 fluentd 配置:
<match app.**>
@type kafka2
[...]
headers_from_record source_ip:$.source.ip
<match>
Kafka 消息的头信息是source_ip=12.7.0.0.1
。
配置格式为 jsonpath。详情见 https://docs.fluentd.org/plugin-helper-overview/api-plugin-helper-record_accessor。
这个插件使用 ruby-kafka 生成器来写数据。这个插件是为 v0.12。如果使用 v1,请参见 kafka2。对 fluentd v0.12 的支持已经结束。kafka_buffered
将会是kafka2
的别名,并且会在将来被移除。
<match app.**>
@type kafka_buffered
# Brokers: you can choose either brokers or zookeeper. If you are not familiar with zookeeper, use brokers parameters.
brokers <broker1_host>:<broker1_port>,<broker2_host>:<broker2_port>,.. # Set brokers directly
zookeeper <zookeeper_host>:<zookeeper_port> # Set brokers via Zookeeper
zookeeper_path <broker path in zookeeper> :default => /brokers/ids # Set path in zookeeper for kafka
topic_key (string) :default => 'topic'
partition_key (string) :default => 'partition'
partition_key_key (string) :default => 'partition_key'
message_key_key (string) :default => 'message_key'
default_topic (string) :default => nil
default_partition_key (string) :default => nil
default_message_key (string) :default => nil
exclude_topic_key (bool) :default => false
exclude_partition_key (bool) :default => false
exclude_partition (bool) :default => false
exclude_message_key (bool) :default => false
output_data_type (json|ltsv|msgpack|attr:<record name>|<formatter name>) :default => json
output_include_tag (bool) :default => false
output_include_time (bool) :default => false
exclude_topic_key (bool) :default => false
exclude_partition_key (bool) :default => false
get_kafka_client_log (bool) :default => false
# See fluentd document for buffer related parameters: https://docs.fluentd.org/v/0.12/buffer
# ruby-kafka producer options
idempotent (bool) :default => false
sasl_over_ssl (bool) :default => true
max_send_retries (integer) :default => 1
required_acks (integer) :default => -1
ack_timeout (integer) :default => nil (Use default of ruby-kafka)
compression_codec (string) :default => nil (No compression. Depends on ruby-kafka: https://github.com/zendesk/ruby-kafka#compression)
kafka_agg_max_bytes (integer) :default => 4096
kafka_agg_max_messages (integer) :default => nil (No limit)
max_send_limit_bytes (integer) :default => nil (No drop)
discard_kafka_delivery_failed (bool) :default => false (No discard)
monitoring_list (array) :default => []
match>
kafka_buffered
有两个附加参数:
这个插件使用 ruby-kafka 生产者来写数据。考虑到性能和可靠性,使用 kafka_bufferd 输出代替。这主要用于测试。
<match app.**>
@type kafka
# Brokers: you can choose either brokers or zookeeper.
brokers <broker1_host>:<broker1_port>,<broker2_host>:<broker2_port>,.. # Set brokers directly
zookeeper <zookeeper_host>:<zookeeper_port> # Set brokers via Zookeeper
zookeeper_path <broker path in zookeeper> :default => /brokers/ids # Set path in zookeeper for kafka
default_topic (string) :default => nil
default_partition_key (string) :default => nil
default_message_key (string) :default => nil
output_data_type (json|ltsv|msgpack|attr:<record name>|<formatter name>) :default => json
output_include_tag (bool) :default => false
output_include_time (bool) :default => false
exclude_topic_key (bool) :default => false
exclude_partition_key (bool) :default => false
# ruby-kafka producer options
max_send_retries (integer) :default => 1
required_acks (integer) :default => -1
ack_timeout (integer) :default => nil (Use default of ruby-kafka)
compression_codec (string) :default => nil (No compression. Depends on ruby-kafka: https://github.com/zendesk/ruby-kafka#compression)
max_buffer_size (integer) :default => nil (Use default of ruby-kafka)
max_buffer_bytesize (integer) :default => nil (Use default of ruby-kafka)
match>
该插件还支持 ruby-kafka 相关参数。参阅缓冲输出插件部分。
这个插件在 kafka 客户端使用 rdkafka 而不是 ruby-kafka。需要安装 rdkafka gem。
# rdkafka is C extension library. Need to install development tools like ruby-devel, gcc and etc
# for v0.12 or later
$ gem install rdkafka --no-document
# for v0.11 or earlier
$ gem install rdkafka -v 0.6.0 --no-document
rdkafka2 适用于 fluentd v1.0 或更高版本。
<match app.**>
@type rdkafka2
brokers <broker1_host>:<broker1_port>,<broker2_host>:<broker2_port>,.. # Set brokers directly
topic_key (string) :default => 'topic'
default_topic (string) :default => nil
partition_key (string) :default => 'partition'
partition_key_key (string) :default => 'partition_key'
message_key_key (string) :default => 'message_key'
default_topic (string) :default => nil
default_partition_key (string) :default => nil
default_message_key (string) :default => nil
exclude_topic_key (bool) :default => false
exclude_partition_key (bool) :default => false
discard_kafka_delivery_failed (bool) :default => false (No discard)
# same with kafka2
headers (hash) :default => {}
headers_from_record (hash) :default => {}
<format>
@type (json|ltsv|msgpack|attr:<record name>|<formatter name>) :default => json
format>
# Optional. See https://docs.fluentd.org/v/1.0/configuration/inject-section
<inject>
tag_key tag
time_key time
inject>
# See fluentd document for buffer section parameters: https://docs.fluentd.org/v/1.0/configuration/buffer-section
# Buffer chunk key should be same with topic_key. If value is not found in the record, default_topic is used.
<buffer topic>
flush_interval 10s
buffer>
# You can set any rdkafka configuration via this parameter: https://github.com/edenhill/librdkafka/blob/master/CONFIGURATION.md
rdkafka_options {
"log_level" : 7
}
# rdkafka2 specific parameters
# share kafka producer between flush threads. This is mainly for reducing kafka operations like kerberos
share_producer (bool) :default => false
# Timeout for polling message wait. If 0, no wait.
rdkafka_delivery_handle_poll_timeout (integer) :default => 30
# If the record size is larger than this value, such records are ignored. Default is no limit
max_send_limit_bytes (integer) :default => nil
match>
如果使用 v0.12,请使用rdkafka
。
<match kafka.**>
@type rdkafka
default_topic kafka
flush_interval 1s
output_data_type json
rdkafka_options {
"log_level" : 7
}
match>
为什么 fluent-plugin-kafka 不能发送数据到我们的 kafka 集群?
通常是由于插件使用的 ruby-kafka 和 kafka 集群版本不匹配导致的。更多细节请参见:https://github.com/zendesk/ruby-kafka#compatibility。
解决办法有两个: