out_kafka2: Fix later writes failing until restart after a delivery error (#588)
- out_kafka2: Fix later writes failing until restart after a delivery error
Since v0.18.0, the producer is reused per flush thread. When delivery fails, ruby-kafka keeps the undelivered messages in the producer. The rescue in write left the producer as is, so the messages were sent again with every later chunk. Once they pushed a batch over the size limit, every write failed until Fluentd restarted.
Discard the producer of the failed thread, and let the next write create a new one. Clearing only its buffer is not enough. An idempotent producer keeps its sequence numbers, so Kafka may drop the next batch as a duplicate. Fluentd retries the chunk from its own buffer. A shared producer is left as is, because other flush threads may be using it.
Refs #587
Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com Signed-off-by: Shizuo Fujita fujita@clear-code.com
- out_kafka2: Fix a producer shutdown error hiding the original write error
discard_producer runs in the rescue of write. If Producer#shutdown raised there, its error replaced the original one, and ignore_exceptions no longer applied. Log the error instead.
Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com Signed-off-by: Shizuo Fujita fujita@clear-code.com
Signed-off-by: Shizuo Fujita fujita@clear-code.com Co-authored-by: Claude Opus 5.5 noreply@anthropic.com
版权所有:中国计算机学会技术支持:开源发展技术委员会
京ICP备13000930号-9
京公网安备 11010802047560号
fluent-plugin-kafka, a plugin for Fluentd
A fluentd plugin to both consume and produce data for Apache Kafka.
Installation
Add this line to your application’s Gemfile:
And then execute:
Or install it yourself as:
If you want to use zookeeper related parameters, you also need to install zookeeper gem. zookeeper gem includes native extension, so development tools are needed, e.g. ruby-devel, gcc, make and etc.
Requirements
Usage
Common parameters
SSL authentication
Set path to SSL related files. See Encryption and Authentication using SSL for more detail.
SASL authentication
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.
Input plugin (@type ‘kafka’)
Consume events by single consumer.
Supports a start of processing from the assigned offset for specific topics.
See also ruby-kafka README for more detailed documentation about ruby-kafka.
Consuming topic name is used for event tag. So when the target topic name is
app_event, the tag isapp_event. If you want to modify tag, useadd_prefixoradd_suffixparameters. Withadd_prefix kafka, the tag iskafka.app_event.Input plugin (@type ‘kafka_group’, supports kafka group)
Consume events by kafka consumer group features..
See also ruby-kafka README for more detailed documentation about ruby-kafka options.
topicssupports regex pattern since v0.13.1. If you want to use regex pattern, use/pattern/like/foo.*/.Consuming topic name is used for event tag. So when the target topic name is
app_event, the tag isapp_event. If you want to modify tag, useadd_prefixoradd_suffixparameter. Withadd_prefix kafka, the tag iskafka.app_event.Input plugin (@type ‘rdkafka_group’, supports kafka consumer groups, uses rdkafka-ruby)
With the introduction of the rdkafka-ruby based input plugin we hope to support Kafka brokers above version 2.1 where we saw compatibility issues when using the ruby-kafka based @kafka_group input type. The rdkafka-ruby lib wraps the highly performant and production ready librdkafka C lib.
See also rdkafka-ruby and librdkafka for more detailed documentation about Kafka consumer options.
topicssupports POSIX Extended Regular Expression pattern (not Ruby regex syntax) since v0.19.6. If you want to use regex pattern, use/pattern/like/foo.*/.Note: A caret (
^) is automatically added to the beginning of the pattern.Consuming topic name is used for event tag. So when the target topic name is
app_event, the tag isapp_event. If you want to modify tag, useadd_prefixoradd_suffixparameter. Withadd_prefix kafka, the tag iskafka.app_event.Output plugin
This
kafka2plugin is for fluentd v1 or later. This plugin usesruby-kafkaproducer for writing data. Ifruby-kafkadoesn’t fit your kafka environment, checkrdkafka2plugin instead. This will beout_kafkaplugin in the future.The
<formatter name>in<format>uses fluentd’s formatter plugins. See formatter article.Note: Java based Kafka client uses
murmur2as partitioner function by default. If you want to use same partitioning behavior with fluent-plugin-kafka, change it tomurmur2instead ofcrc32. Note that for usingmurmur2hash partitioner function, you must installdigest-murmurhashgem.ruby-kafka sometimes returns
Kafka::DeliveryFailederror without good information. In this case,get_kafka_client_logis useful for identifying the error cause. ruby-kafka’s log is routed to fluentd log so you can see ruby-kafka’s log in fluentd logs.Supports following ruby-kafka’s producer options.
If you want to know about detail of monitoring, see also https://github.com/zendesk/ruby-kafka#monitoring
See also Kafka::Client for more detailed documentation about ruby-kafka.
This plugin supports compression codec “snappy” also. Install snappy module before you use snappy compression.
snappy gem uses native extension, so you need to install several packages before. On Ubuntu, need development packages and snappy library.
On CentOS 7 installation is also necessary.
This plugin supports compression codec “lz4” also. Install extlz4 module before you use lz4 compression.
This plugin supports compression codec “zstd” also. Install zstd-ruby module before you use zstd compression.
Load balancing
Messages will be assigned a partition at random as default by ruby-kafka, but messages with the same partition key will always be assigned to the same partition by setting
default_partition_keyin config file. If key namepartition_key_keyexists in a message, this plugin set the value of partition_key_key as key.If key name
message_key_keyexists in a message, this plugin publishes the value of message_key_key to kafka and can be read by consumers. Same message key will be assigned to all messages by settingdefault_message_keyin config file. If message_key_key exists and if partition_key_key is not set explicitly, messsage_key_key will be used for partitioning.Headers
It is possible to set headers on Kafka messages. This only works for kafka2 and rdkafka2 output plugin.
The format is like key1:value1,key2:value2. For example:
You may set header values based on a value of a fluentd record field. For example, imagine a fluentd record like:
And the following fluentd config:
The Kafka message will have a header of source_ip=12.7.0.0.1.
The configuration format is jsonpath. It is descibed in https://docs.fluentd.org/plugin-helper-overview/api-plugin-helper-record_accessor
Excluding fields
Fields can be excluded from output data. Only works for kafka2 and rdkafka2 output plugin.
Fields must be specified using an array of dot notation
$., for example:This config can be used to remove fields used on another configs.
For example,
$.source.ipcan be extracted with configheaders_from_recordand excluded from message payload.Send only a sub field as a message payload
If
record_keyis provided, the plugin sends only a sub field given by that key. The configuration format is jsonpath.e.g. When the following configuration and the incoming record are given:
configuration:
record:
only the
datafield will be serialized by the formatter and sent to Kafka. The topleveldatakey will be removed.Buffered output plugin
This plugin uses ruby-kafka producer for writing data. This plugin is for v0.12. If you use v1, see
kafka2. Support of fluentd v0.12 has ended.kafka_bufferedwill be an alias ofkafka2and will be removed in the future.kafka_bufferedsupports the followingruby-kafkaparameters:kafka_bufferedhas two additional parameters:Note: Java based Kafka client uses
murmur2as partitioner function by default. If you want to use same partitioning behavior with fluent-plugin-kafka, change it tomurmur2instead ofcrc32. Note that for usingmurmur2hash partitioner function, you must installdigest-murmurhashgem.Non-buffered output plugin
This plugin uses ruby-kafka producer for writing data. For performance and reliability concerns, use
kafka_bufferdoutput instead. This is mainly for testing.This plugin also supports ruby-kafka related parameters. See Buffered output plugin section.
Note: Java based Kafka client uses
murmur2as partitioner function by default. If you want to use same partitioning behavior with fluent-plugin-kafka, change it tomurmur2instead ofcrc32. Note that for usingmurmur2hash partitioner function, you must installdigest-murmurhashgem.rdkafka based output plugin
This plugin uses
rdkafkainstead ofruby-kafkafor kafka client. You need to install rdkafka gem.rdkafka2is for fluentd v1.0 or later.rdkafka2supportsdiscard_kafka_delivery_failed_regexparameter:discard_kafka_delivery_failed_regex- default: nil - discard the record where the Kafka::DeliveryFailed occurred and the emitted message matches the given regex pattern, such as/unknown_topic/.rdkafka2supportsunrecoverable_error_codesparameter:unrecoverable_error_codes- default:["topic_authorization_failed", "msg_size_too_large"]- librdkafka error codes to treat as unrecoverable errors. When a listed code is returned,Fluent::UnrecoverableErroris raised, so Fluentd hands the whole chunk to the secondary output or to the backup directory instead of retrying it untilretry_timeoutexpires. Both the produce call and the delivery report are covered, the latter only whilerdkafka_delivery_handle_poll_timeoutis not 0. Set the parameter to an empty value keeping retrying every error, as this plugin did before v0.19.x.Rdkafka::RdkafkaError#codereports it, that is the librdkafka name lowercased with the leading underscore removed, soRD_KAFKA_RESP_ERR__UNKNOWN_PARTITIONis written asunknown_partition. A name that matches no error code is accepted and never matches anything.discard_kafka_delivery_failedanddiscard_kafka_delivery_failed_regextake precedence over this parameter. The regex is matched against the librdkafka message, such asBroker: Message size too large (msg_size_too_large).If you use v0.12, use
rdkafkainstead.FAQ
Why fluent-plugin-kafka can’t send data to our kafka cluster?
We got lots of similar questions. Almost cases, this problem happens by version mismatch between ruby-kafka and kafka cluster. See ruby-kafka README for more details: https://github.com/zendesk/ruby-kafka#compatibility
To avoid the problem, there are 2 approaches:
Why does Fluentd fail with Kafka::MessageSizeTooLarge (or msg_size_too_large)?
Kafka rejects a record batch that is larger than the size limit of the topic. The limit is
max.message.bytesof the topic if it is set, andmessage.max.bytesof the broker otherwise. The topic value can be larger or smaller than the broker value. Below, “the topic limit” means this value. If one output writes to several topics, use the smallest one.kafka2sends all records of a buffer chunk at once, and the records for the same partition go into one record batch. In the worst case, the whole chunk becomes one record batch. To make the batches smaller, lowerchunk_limit_sizein<buffer>.chunk_limit_sizeis the size of a chunk in the buffer, where records are kept as msgpack. The records sent to Kafka can be larger, because of<format>,<inject>and the overhead of each Kafka record. Start with about half of the topic limit, and lower it if the error continues. If<buffer>hascompress gziporcompress zstd,chunk_limit_sizelimits the compressed size, and a chunk can hold several times more data. In that case, divide it further by the compression ratio of your data.compression_codecworks the other way. Kafka checks the size of a record batch after compression, so compressed batches leave more room. How much depends on how well your data compresses.max_send_limit_bytesdoes not make the batch smaller. It checks only the formatted value of each record, and drops the records larger than this setting. The message key, headers and the overhead of the batch are not counted. To drop a single record that Kafka would reject, set it below the topic limit with some room for them.The following example assumes a topic limit of 1MB.
Fluentd may log
chunk bytes limit exceeds for an emitted event stream. This warning comes from the Fluentd buffer. It means that one event stream emitted to the output was larger thanchunk_limit_size, and Fluentd splits it into several chunks. The number in the warning is the size of that event stream in the buffer, not the growth by formatting. If a single record is larger thanchunk_limit_size, that record cannot be stored, and Fluentd raisesBufferChunkOverflowError.kafka_bufferedsplits a chunk into smaller deliveries bykafka_agg_max_bytes(default: 4096) andkafka_agg_max_messages, sochunk_limit_sizedoes not decide its batch size.rdkafka2passes records to librdkafka one by one, and librdkafka builds the record batches within its ownbatch.sizeandmessage.max.bytes. You can set them inrdkafka_options. Keep them below the topic limit.msg_size_too_largeis in the default ofunrecoverable_error_codes, so Fluentd does not retry a chunk that hits it.Contributing
git checkout -b my-new-feature)git commit -am 'Added some feature')git push origin my-new-feature)