Как организовать буферизацию данных для предотвращения потери сообщений
Что проверяют
Понимаете ли вы разницу между буфером, который сглаживает всплески нагрузки, и гарантией доставки. Буферизованный канал живёт в памяти процесса и исчезает вместе с ним. Следом обычно спрашивают, что станет с сообщениями при kill -9 или деплое и что делать, когда буфер заполнен.
Как отвечать
Разведите уровни задачи:
- буфер в памяти:
make(chan Msg, N)отвязывает скорость продюсера от скорости обработчика. Размер выбирают от ожидаемого всплеска, а заполненность отслеживают метрикой поlen(ch); - переполнение: решение принимают явно. Блокировать отправителя через
selectсctx.Done()и таймаутом, отбрасывать с учётом в метрике или сбрасывать на диск. Молчаливая веткаdefaultвselectозначает потерю данных; - постоянное хранилище: если терять нельзя, сообщение должно лежать вне процесса до подтверждения обработки. Это Kafka с ручным коммитом смещения после обработки, NATS JetStream или RabbitMQ с устойчивыми очередями и подтверждениями публикации;
- outbox: если сообщение порождается изменением в базе, его пишут в таблицу outbox той же транзакцией, а отдельный процесс отправляет в брокер. Так не бывает записи без события и события без записи;
- повторы: экспоненциальная задержка, ограничение попыток, после них очередь недоставленных (DLQ);
- корректная остановка:
signal.NotifyContextловит SIGTERM, продюсер закрывает канал, обработчики дочитывают его до конца,sync.WaitGroupилиerrgroupждёт их, и только потом процесс выходит.
Итог: гарантия «хотя бы один раз» даёт дубли, поэтому обработчик должен быть идемпотентным, например по ключу сообщения.
Где спотыкаются
Возвращают упавшее сообщение в тот же канал, из которого читают. При полном буфере горутина блокируется на отправке самой себе, а если канал уже закрыт, получают панику send on closed channel.
Коммитят смещение в Kafka до обработки. Если сервис упал между коммитом и записью результата, сообщение потеряно без следа.
Считают, что большой буфер решает проблему. Он лишь откладывает её и увеличивает объём данных, которые пропадут при падении.