Apache Kafka как основа для велосипедостроения
Цель okmeter: найти проблему. Для этого нужен контент — метрики. Их собирает агент, отправляет в платформу и считает метрики.
Metric store v1: chunked
- копим данные за 4 часа
- интервал знаем, поэтому не храним timestamp
- сериализуем и жмём lz4
- пишем в cassandra
- при каждой точке перезаписываем весь chunk
- чтобы не читать при записи, версионируем чанки
- при чтении объединяем все версии
Результаты:
- примерно десятикратное сжатие объема
- в несколько раз ускорилось чтение
- увеличилась нагрузка на Cassandra
- в результате нагрузка на диск в форме пилы.
Metric store v1.1: bunched
Bunch — набор метрик, который пишется и читается одновременно. Пишем в один BLOB.
- Ещё вдвое сжали
- В несколько раз ускорилось чтение
- Иногда читаем лишнее
Metric store v2: идея!
Научиться хранить «хвост» данных в памяти надёжно.
- Уметь восстановить откуда-то за разумное время
- несколько консистентных реплик
Сможем хвост читать из этой памяти, а более давние данные — уже из Casssandra.
В результате начали изобретать велосипед. В любой БД есть WAL — write ahead log. Копим данные, а потом асинхронно пишем их, потому что сразу писать — дорого. Есть offset — какие данные мы уже записали.
Концепция такая:
- Пишем в primary
- Он реплицируется в реплики
- Читать можем только из реплик
В качестве WAL будем использовать kafka. Это просто надёжный лог. Producer в него пишет, а Consumer читает.
Преимущества kafka:
- репликация из коробки
- шардинг из коробки
Как работает Consumer:
- на низком уровне: ConsumePartition(…), GetOffset(…), и другие методы
- на высоком уровне: Consumer groups.
В okmeter использовали низкоуровневый интерфейс.
Если большой лаг или запрашивают диапазон больше чем у нас есть — ошибка.
In-memory storage: реузльтаты
- быстрое чтение
- легко масштабируется
- простой код (ничего не знаем про репликацию, всё из коробки)
Проблема: на полный потк метрик нужно 1,5 ядра на каждом инстансе
Long-term storage
Long-term storage: chunker
- сидит на потоке и формирует 4х-часовые чанки
- знает, откуда нужно начинать читать
- готовые чанки складывает в отдельный топик
- если пришла точка из прошлого — дописывает в тот же чанк, но с отдельным типом сообщения
Long-term storage: chunks-writer
- Читает чанки
- если прилетает чанк — пишем его в C*
- если точка из прошлого — достаём чанк, добавляем точку, перезаписываем
Результаты
Cassandra: 30000 → 150 writes/second.
Kafka в production
- 6 x brokers v1.o
- подселяем брокеры на ноды k8s
- сырые точки храним 5 дней, это 5 терабайт
- чанки храним 2 месяца, это 3.3 терабайта с учётом репликации
- 20000 produced messages/second
- суммарно на kafka: 10 ядер и 45Gb памяти
Рекомендации
- Не обновляйтесь на *.0 релизы, даже если очень хочется. Могут быть баги.
- Kafka не парится о том, чтобы уменьшить количество копирований. Используйте generate.
- Если не задать лимит на скорость копирования, kafka убьёт диск, сеть и проц. После запуска лимит для операций копирования задать нельзя. Но если задать лимит заранее, можно поменять значение лимита.
- Не запускайте много переносов партиций за раз. С одного брокера-лидера только одну партицию за раз.
Результат
- Больше года в продакшене
- Поняли, как всё работает
Бонус: легкость экспериментов. * Можно выгрузить настоящие сырые данные * можно сесть на поток настоящих сырых данных * небольшой overhead на хранение * можно хранить много данных на дешёвых и больших дисках
Бонус: точка опоры
- от БД теперь не требуется распределённость
- Consumer + standalone db
Итоги
Если вы хотите написать свою специализированную БД:
- Подумайте 100 раз
- разберитесь, как работают взрослые БД
- используйте kafka в качестве wal
- напишите остаток кода
- Profit!?