A library to increase the throughput of producing messages (coming one at a time) to Kafka by accumulating these messages into batches.
- Add
KafkaBatcherto your list of dependencies inmix.exs:
def deps do
[
{:kafka_batcher, "~> 1.0.0"},
# and one of kafka libraries
# {:kaffe, "~> 1.24"}
# or
# {:kafka_ex, "~> 0.12"}
]
end- Add KafkaBatcher supervisor to your supervisor tree
def start(_type, _args) do
children = [
# Describe the child spec
KafkaBatcher.Supervisor
]
opts = [strategy: :one_for_one, name: MyApp.Supervisor, max_restarts: 3, max_seconds: 5]
Supervisor.start_link(children, opts)
end- Configure a KafkaBatcher Producer
Config example:
config :kafka_batcher, KafkaBatcher.Collector1, topic_name: "topic1"
config :kafka_batcher, KafkaBatcher.Collector2, topic_name: "topic2"
config :kafka_batcher, KafkaBatcher.Collector3, topic_name: "topic3"
config :kafka_batcher, KafkaBatcher.Collector4, topic_name: "topic4"
config :kafka_batcher, KafkaBatcher.Collector5, topic_name: "topic5"
config :kafka_batcher, collectors:
[
KafkaBatcher.Collector1,
KafkaBatcher.Collector2,
KafkaBatcher.Collector3,
KafkaBatcher.Collector4,
KafkaBatcher.Collector5
]
config :kafka_batcher, :kafka,
endpoints: "localhost:9092",
# in case you use SASL
# sasl: %{mechanism: :scram_sha_512, login: "login", password: "password"},
# ssl: true,
telemetry: true,
allow_topic_auto_creation: false,
kafka_topic_aliases: %{
"real_topic_name1" => "incoming-events",
"real_topic_name2" => "special-topic"
}
# In case you use KafkaEx, you need to disable default worker to avoid crashes
config :kafka_ex, :disable_default_worker, trueAvailable parameters:
:required_acksHow many acknowledgements the kafka broker should receive from the clustered replicas before acking producer.:endpointsKafka cluster endpoints, can be any of the brokers in the cluster, which does not necessarily have to be the leader of any partition, e.g. a load-balanced entrypoint to the remote Kafka cluster. More information in the Brod producer docs.:telemetry, if set totrue, metrics will be collected and exposed with PromEx.:allow_topic_auto_creation, if set true, topics automatically are created with default parameters.:partition_strategy, allows values: :random, :md5 or function (e.g.fn _topic, _partitions_count, key, _value -> key end):partition_fn, a function that takes four arguments and returns a number of the partition (see below):collect_by_partition, if set totrue, producer accumulates messages separately for each partition of the topic:batch_size, count of messages to be accumulated by collector before producing:max_wait_time, max interval between batches in milliseconds. The batch will be produced to Kafka either bybatch_sizeor bymax_wait_timeparameter.:batch_flusher, a module implementing a functionflush?(binary(), map()) :: boolean(). If the function returns true, the current batch will be sent to Kafka immediately.:kafka_topic_aliases- you could define custom aliases for Kafka topics, it doesn't affect anything except metric labels.:sasl- optional parameter. The parameter includes three parameters: %{mechanism: mechanism, login: "login", password: "password"}. Mechanism is plain | scram_sha_256 | scram_sha_512. Login and password should be type binary().:ssl- optional parameter. Ssl should be type boolean(). By default:sslisfalse.:min_delay- optional parameter. Set minimal delay before send events. This parameter allows to increase max throughput in case when you get more messages (in term of count per second) than you expected when setbatch_sizeparameter.:max_batch_bytesize- optional parameter. Allows to set a limit on the maximum batch size. By default it is 1_000_000 bytes.
Important: The size of one message should not exceed max_batch_bytesize setting. If you need to work with large messages you must increase max_batch_bytesize value and value of Kafka topic setting max.message.bytes as well.
Note: you can still produce messages to any Kafka topic (even if it is not described in the kafka_batcher config) by using direct calls of Kaffe or KafkaEx.
defmodule MyApp.Collector1 do
use KafkaBatcher.Collector,
collect_by_partition: true,
partition_fn: &MyApp.Collector1.calculate_partition/4,
required_acks: -1,
batch_size: 30,
max_wait_time: 20_000
def calculate_partition(_topic, partitions_count, _key, value) do
val = value["client_id"] || value["device_id"]
:erlang.phash2(val, partitions_count)
end
end
defmodule MyApp.Collector2 do
use KafkaBatcher.Collector,
collect_by_partition: false,
required_acks: 0,
batch_size: 10,
max_wait_time: 20_000
end
defmodule MyApp.Collector3 do
use KafkaBatcher.Collector,
collect_by_partition: false,
required_acks: 0,
batch_size: 10,
max_wait_time: 20_000,
partition_strategy: :random
end
defmodule MyApp.Collector4 do
use KafkaBatcher.Collector,
collect_by_partition: true,
required_acks: 0,
partition_fn: &MyApp.Collector4.calculate_partition/4,
batch_size: 50,
batch_flusher: MyApp.Collector4.BatchFlusher
def calculate_partition(_topic, partitions_count, _key, value) do
rem(key, partitions_count)
end
defmodule BatchFlusher do
def flush?(_key, %{"type" => "SpecialType"}) do
true
end
def flush?(_key, _value) do
false
end
end
end
defmodule MyApp.Collector5 do
use KafkaBatcher.Collector,
collect_by_partition: false,
partition_strategy: :md5,
batch_size: 100,
max_wait_time: 20_000,
min_delay: 100,
max_batch_bytesize: 1_000_000
end defmodule MyApp.MyModule do
...
def produce_to_kafka_topic1(event) do
MyApp.Collector1.add_events(event)
end
def produce_to_kafka_topic2(event) do
MyApp.Collector2.add_events(event)
end
...
end KafkaBatcher.Config.get_collector_config("topic1") KafkaBatcher.Config.get_configs_by_topic()mix testor
mix test --coversee https://github.com/parroty/excoveralls for details
The library exposes the following metrics using the PromEx exporter plugin:
prom_ex_kafka_consumer_batch_messages_count(histogram) - The count of messages in one batch consumer.prom_ex_kafka_consumer_batch_total_size_byte(histogram) - The size of a batch consumer of messages.prom_ex_kafka_consumer_duration_seconds(histogram) - The time to produce one batch to Kafka.prom_ex_kafka_producer_batch_messages_count(histogram) - The count of messages in one batch producer.prom_ex_kafka_producer_batch_total_size_byte(histogram) - The size of a batch producer of messages.prom_ex_kafka_producer_duration_seconds(histogram) - The time to produce one batch to Kafka.