Art of Code
Открываем новую серию постов. Смысл такой: берём известный проект, смотрим, как в нём решили какую-нибудь неочевидную проблему, и разбираемся, чем этот приём полезен лично тебе в твоём коде. Без душной теории — только то, что реально пригодится. И начать хочу с истории, которая случалась с каждым, кто хоть раз что-то куда-то сохранял.
Ты сохранил данные. Сервис ответил «готово». Ты выдохнул и пошёл дальше. Знакомо? А теперь неприятная новость: «сервис ответил готово» и «данные действительно на месте» — это два разных события. Между ними есть щель, и данные умеют в неё проваливаться. Причём случается это ровно в тот момент, когда что-то ломается, — то есть в самый неподходящий. Чтобы увидеть эту щель во всей красе, посмотрим, как с ней воюет Kafka. А потом вернёмся к твоему коду, потому что проблема там ровно та же.
Как Kafka бережёт данные. Она хранит каждую порцию сообщений сразу на нескольких серверах: один главный, он принимает записи, остальные — его копии, они за ним повторяют. Звучит надёжно. Но вот ловушка, в которую попадают почти все. Главный сервер принял сообщение, записал у себя, ответил «принято» — и в следующую секунду умер. А копии не успели повторить за ним. На его место встаёт одна из копий, но у неё этого сообщения нет. Всё, сообщение исчезло. А отправитель-то уверен, что всё хорошо, — ему же ответили «принято».
Как эту дыру закрывают. У отправителя есть настройка, которая решает, когда считать сообщение сохранённым. Можно сказать «мне хватит, что его принял главный» — быстро, но это ровно та история с исчезновением. А можно потребовать «считать сохранённым, только когда его повторили и живые копии тоже». Вот тогда появляется настоящая гарантия: даже если главный умрёт, сообщение уже есть на других.
Но и это не всё. Что, если копии отстали и по одной повыпадали, а живым остался только главный? Тогда правило «пусть подтвердят копии» тихо превращается в «пусть подтвердит главный» — и мы снова там же, откуда начали. Поэтому есть ещё одна настройка
1 · 917 ·