Pull to refresh

Comments 17

Ты очень рассердился на автора той статьи, это понятно. Но кто он такой, что ты вообще его заметил? Чем его статья выделяется из кучи других ошибочных статей и мнений?

Данная статья в топе по запросу "Exactly once". Статья в целом воспринимается как вполне толковая, и кто-то может подумать даже подумать, что в ней есть глубокий смысл. А рассмотрение деталей позволяет прояснить многие ключевые моменты.

UFO just landed and posted this here

Дедупликация делается на входе последующего обработчика, который есть выход предыдущего.

UFO just landed and posted this here

Дубликаты может давать сам обработчик, повторяя действия с последнего восстановленного состояния.

At-most-once, т.е. не более одного раза. При кажущейся очевидности, такое поведение крайне сложно гарантировать при краевых сценариях по типу падений, нарушение сетевой связности и другое

At-least-once, т.е. не менее одного раза. Схема более сложная. И граблей можно насобирать поболее
А почему так сложно гарантировать at most once? И что за грабли в at least once? Разве стратегии «никогда не ретраить»/«ретраить до упора» не обеспечивают поведения at most/at least once?

Бывают нюансы, связанные со взаимодействием с внешними хранилищами. Но в нулевом приближении все просто.

А какие нюансы могут быть с внешним хранилищем, которые что-либо усложняют?

At most once: если ни одна операция в системе не ретраится, как, при условии корректной реализации всех компонентов, могут появиться дубли? Я не говорю про систему без сбоев, только лишь про то, что в компонентах нет багов, которые приводят к дублям.
At least once: если каждый компонент ретраит запросы до победного конца, где могут появиться потери? При условии отсутствия бажных/чересчур оптимистично настроенных компонентов вроде стораджей, которые возвращают успех, никуда толком не сохранив.

Можно пример, который продемонстрировал бы, почему обеспечение этих поведений реализовать сложнее, чем описанные выше стратегии?

Например, мы записываем во внешнюю базу данных, при этом у нас at-most-once. Если при этом не получилось записать, то эту запись мы сохраняем для того, чтобы позже повторить. Можно, конечно, тут же потерять эту запись, но нам бы не хотелось этого делать. После этого можно крешнуться прямо во время записи, а затем, т.к. эта запись осталась в нашем состоянии, то после восстановления снова попытаться ее записать.

Хотел бы я увидеть реализацию без коммита, т.е. без лога транзакций которая тот же print id сделает exactly once.
  1. Реализация без коммита приведена в [2].
  2. Примеру с print id даже коммит не поможет.
Print не очень показательный. Пусть результат будет например сохраняемый в бд счётчик событий. Обеспечить идемпотентность может только фиксация факта учёта и увеличения счётчика в одной транзакции. Причём брокер действительно не может принципиально обеспечить exactly once. Он может предоставить возможность фиксации факта обработки. Но выборка события, обработка и фиксация обработки разнесены во времени. Так что даже в этом случае exactly once в случае ошибок превращается в at least once.

Статью не читаю, комментарий пишу?

Смешались в кучу кони люди… Какой lock-free если в конце концов всё равно «теперь осталось лишь добавить взаимодействие с базой данных… tx.open()… tx.commit()».
И именно об этом и пишется в статье — «can guarantee that updates to state managed by the SPE are committed only once to a durable backend store».
Используя «псеко»… :)

1 подход.
commit_snapshot(snapshot 1)
log_and_apply_transaction(snapshot 2, transaction)
log_and_apply_transaction(snapshot 2, transaction)
...
log_and_apply_transaction(snapshot 2, transaction)
commit_snapshot(snapshot 2)
...

restore:
rollback_all_transactions_since_last_commited_snapshot()
reply_all_transactions_since_last_commited_snapshot()

2 подход.
tx.open()
if tx.log_transaction(transaction.id): apply_transaction(transaction)
tx.commit()

restore: not required, all updates idempotent


Различия в том, что в первом случае лог можно писать только в рамках текущего окна событий. При этом в upstream периодически закидываются пинги, сигналы commit snapshot. О консистентности системы в целом можно судить по min(last commited snapshot) в sink.

А пример с print id автор приводит как раз в контексте того что print как user defined logic — не транзакционная операция, т.е. операция, exactly once выполнение которой в общем случае не может быть гарантировано. Например в случае возникновения ошибки внутри самой операции.

Я потерял нить диалога.


Хочется прояснить следующие вещи:


  1. Что это доказывает/опровергает?
  2. Каково конечное утверждение?
  3. "Обеспечить идемпотентность может только фиксация факта учёта и увеличения счётчика в одной транзакции." — откуда следует это утверждение?
  4. "Причём брокер действительно не может принципиально обеспечить exactly once." Что есть "брокер", и почему он "действительно не может принципиально обеспечить"? В статьях ничего такого не говорилось.
  5. "Так что даже в этом случае exactly once в случае ошибок превращается в at least once." Как это следует из предыдущего?
  6. "commit_snapshot(snapshot 1)". Что такое commit_snapshot и log_and_apply_transaction? Какое хранилище используется для хранения?
  7. Есть ли понимание, что tx.open()… tx.commit() использует другое хранилище, внешнее, по отношению к движку обработки данных?

Хочется понять проблематику и более подробное описание, что означет приведенный код.

Sign up to leave a comment.

Articles