open atlas
↑ К треку
Основы System Design SD · 06 · 07

Асинхронность и сообщения: чтение кода и конфига

Прочитай реальный код consumer'а, конфиг брокера и обработчик outbox, затем выбери ответ, на который подписался бы senior: баг порядка ack, дубль из-за visibility timeout, двойная запись из inline-публикации и безграничный буфер.

SD Senior ◷ 14 min
Уровень
ОсновыJuniorMiddleSenior

Баги сообщений живут в коде и конфиге, а не в прозе: куда ты поставил ack, во что выставлен visibility timeout, владеет ли relay публикацией и есть ли у буфера граница. Прочитай каждый сниппет, протрассируй падение и выбери ответ, на который подписался бы senior-инженер.

Потренируй петлю, что ты гоняешь на дизайн- или код-ревью: найди несущую строку, протрассируй, что делает с ней падение, и выбери изменение, что уважает семантику доставки, а не прячет её.

Сниппет 1 — порядок ack

def handle(msg):
    queue.ack(msg)          # подтверждено первым
    charge_card(msg.amount) # затем побочный эффект
Викторина

Какую семантику доставки это даёт и в чём риск для платёжного обработчика?

Сниппет 2 — visibility timeout

# SQS consumer
visibility_timeout: 30      # секунд
# измеренное время обработки задачи: p50 = 12с, p99 = 75с
# обработчик НЕ идемпотентен
Викторина

С этими числами что происходит с самыми медленными задачами и какова починка?

Сниппет 3 — обработчик outbox

with db.transaction() as tx:
    tx.insert(order)
    tx.insert(outbox_row(OrderPlaced))   # атомарно с заказом — хорошо
    broker.publish(OrderPlaced)          # также опубликовано inline, «ради экономии хопа»
    tx.commit()
# отдельный relay ТОЖЕ читает outbox и публикует
Викторина

Outbox-строка записана верно, так почему inline `broker.publish` — баг?

Сниппет 4 — буфер

const queue = []                       // в памяти, без макс. размера
function enqueue(job) { queue.push(job) }   // никогда не отвергает
// воркер вычерпывает ~1k/с; producer'ы могут рвануть до ~8k/с во время всплесков
// симптом: во время всплесков RSS пода лезет вверх, пока его не убьют по OOM
Викторина

Почему под падает под всплесками и какое изменение верно?

Вспомните перед уходом
  1. 01
    Как позиция ack решает семантику доставки и что верно для платежа?
  2. 02
    Почему inline-публикация в обработчике outbox возвращает двойную запись?
Итог

Каждое решение по сообщениям в этом разделе всплывает как несущая строка, что ты читаешь прямо из кода. Позиция ack задаёт семантику доставки — ack-первым это at-most-once (с потерями), ack-последним это at-least-once (дубли), а платёж хочет последнее плюс идемпотентность. Visibility timeout должен сидеть выше реального p99 времени обработки и heartbeat’иться, иначе медленные задачи переотправляются и бегут дважды параллельно. Outbox работает, лишь если обработчик делает только локальную транзакцию, а отдельный relay публикует — inline-публикация тихо возвращает двойную запись (фантомные события плюс дубли relay). А внутрипамятная очередь без границы растёт без предела под устойчивой перегрузкой, пока процесс не упадёт по OOM, поэтому ты ограничиваешь её и быстро падаешь (сигнал backpressure), сбрасывая при заполнении и используя долговечный брокер, если буферизованная работа должна пережить падение. Senior-привычка — найти несущую строку, протрассировать, что делает с ней падение, и выбрать починку, которую требует режим отказа, — а не ту, что её прячет.

Что-то непонятно?

Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.

хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.