Паттерн Outbox - теория и практика | Архитектура Микросервисов

  Рет қаралды 10,536

Николай Тузов — Golang

Николай Тузов — Golang

Күн бұрын

Transactional Outbox - паттерн, который обеспечивает атомарность двух операций - сохранения измений в БД и отправки сообщения об этих изменениях в другой сервис.
В этом видео мы подробно разберемся, почему решаемая им проблема важна, как он устроен, а затем реализуем его самостоятельно на языке Go
Хорошая статья моего бывшего коллеги Миши Боровикова на эту же тему, если хотите глубже вникнуть в тему: habr.com/ru/companies/lamoda/...
Здесь подробно разобран пример использования паттерна в компании Lamoda.
Код из ролика я закоммитил в отдельную ветку проекта URL Shortener, т.к. в основной ветке мне этот функционал пока не нужен. Ссылка на соответствующую ветку: github.com/GolangLessons/url-...
----
👾 t.me/ntuzov - мой канал в Telegram.
Пишу в нём много интересного: гайды, которых нет на KZfaq, интересные мысли про разработку, новости и анонсы всех моих активностей и др.
👀 GoLang Digest: t.me/golang_digest - мои регулярные подборки интересных материалов по Go.
🗣️ Наше сообщество GopherClub: t.me/+zsSZ63wEJDs3NGVi
Лучшее русскоязычное Go-сообщество с очень приятной атмосферой, без токсиков. Вежливо и терпеливо помогаем новичкам, конструктивно дискутируем с профессионалами и т.п.
Здесь также присутствуют все звезды Go-сообщества и представители интересных компаний.
❤️ Если у вас есть желание поддержать развитие канала:
Секретный телеграм-канал:
- В рублях: t.me/tribute/app?startapp=s3Q5
- В евро: t.me/tribute/app?startapp=s3Q6
Boosty: boosty.to/nikolay.tuzov
Patreon: / tuzov
----
00:00 Какую проблему мы решаем
05:47 Нам нужна атомарность
07:03 Про Two-Phase Commit
07:36 NoSQL базы данных
09:59 Гарантия доставки - "At Least Once"
11:48 Практика: пишем Outbox для сокращателя ссылок
12:43 Storage: сохраняем сообщения в таблицу
28:01 Event Sender: отправка сообщений из таблицы
36:52 Подключаем Event Sender
39:09 Тестируем отправку сообщений
41:12 Итоги
42:07 Мой Телеграм-канал: почему он важен
43:05 Заключение
#golang #ntuzov

Пікірлер: 79
@nikolay_tuzov
@nikolay_tuzov 5 күн бұрын
Мой канал в Telegram: t.me/ntuzov Пишу там новости, анонсы своих активностей, небольшие текстовые гайды и просто интересные мысли. Также через него я получаю от вас оперативный фидбэк по роликам - что нравится, что не нравится, какой ролик делать следующим и т.п.
@yoloprotector3159
@yoloprotector3159 Күн бұрын
О! Класс, спасибо! Было бы супер увидеть видео про Сагу
@user-rv4hq6xb5o
@user-rv4hq6xb5o 2 күн бұрын
Николай, спасибо за очередное супер видео Очень помогаешь
@DWGFragaed
@DWGFragaed 3 күн бұрын
Николай внатуре легенда!
@user-ui4td4sd6q
@user-ui4td4sd6q Күн бұрын
на фразе "пардон - не та картинка" пришла жена из соседней комнаты и стала спрашивать чего со мной случилось что я так ржу
@nikolay_tuzov
@nikolay_tuzov Күн бұрын
Ну хоть кто-то оценил шутку, спасибо
@man0xff
@man0xff 5 күн бұрын
Супер! Спасибо за отличный материал 👍
@Artemh1994
@Artemh1994 5 күн бұрын
Николай, спасибо! Как обычно очень полезно!
@johnb7657
@johnb7657 5 күн бұрын
Всегда ставлю лайк, смотрю с удовольствием, потом скачиваю и пересматриваю часиенько. Благодарю
@nikolay_tuzov
@nikolay_tuzov 5 күн бұрын
Спасибо, но лучше пересматривать на ютубе, чтобы статистика учитывала это. Если ролики часто пересматривают, то их лучше будут рекомендовать другим людям =)
@user-sx8zv6jj2s
@user-sx8zv6jj2s 5 күн бұрын
Вижу видос на канале - ставлю лайк заранее
@RussiaRedNick
@RussiaRedNick 5 күн бұрын
Пока не смотрел, но для продвижения сразу поставил лайк, успехов автору!)
@littledrongo5469
@littledrongo5469 5 күн бұрын
Николай, спасибо что живой ❤
@user-ml3gc2of1z
@user-ml3gc2of1z 5 күн бұрын
отличный формат видео ! я трейни go могу сказать что ощутил себя в качестве стажера в первом коммерческом прожэкте ) очень интересная необычная подача !
@ironbondar
@ironbondar 5 күн бұрын
четко объяснил, спасибо!
@user-qf2xk1fg6e
@user-qf2xk1fg6e 3 күн бұрын
Просто забить на все это и работать в монолите. Хочешь транзакшн фид? Ну создай в бд еще табличку, будет тебе транзакшн фид. )))) Есть мнение, что микросервисы для надувания щек перед инвесторами. По крайней мере - это одно из главных назначений этого подхода.
@user-vz2gg1pf2m
@user-vz2gg1pf2m Күн бұрын
Возможно пример с фидом неудачный. В общем случае как только есть две системы, между которыми невозможна транзакция, то возникает эта проблема. И одно из решений это аутбокс. В вашем монолите наверняка есть подобная проблема. Например пользователь зарегался, ему надо отправить письмо. В бд записали, письмо не отправили. Или письмо отправили, а транзакция упала. Часто на это просто забивают, и алгоритм аутбокса выполняет сотрудник поддержки :-)
@semenivanoff8615
@semenivanoff8615 Күн бұрын
Ага, а потом нагрузка на монолит вырастет в 100 раз, а монолит уже не вырастет. Или в 100 раз и в 5ти странах.
@user-qf2xk1fg6e
@user-qf2xk1fg6e 18 сағат бұрын
@@user-vz2gg1pf2m Будьте добры, перечислите еще 10 случаев аутбокса в монолите. Кроме письма. Что-то мне подсказывает, что не наберется. А вот в микросервисах они будут на каждый чих и о всех помнить не будешь. В один прекрасный пятничный вечер руководство донесет, что надо восстанавливать какие-то данные, потому что оно где-то скрыто и очень давно работало не так из за того, что в такой сложной системе кто-то что-то когда-то проглядел. У меня на работе монолит и куча интеграций. У нас так бизнес процесс устроен, что если интеграция не ответила, то все, до свидания, смысла развлекать пользователя нет. Эксепшн, обращайтесь завтра после обеда.
@user-ny2tl4qy3m
@user-ny2tl4qy3m 5 күн бұрын
очень полезно. спасибо
@Dantesik1
@Dantesik1 5 күн бұрын
Здравствуйте Николай! Спасибо за видео! Как обычно - все понятно даже дурочку!
@FerelUltra
@FerelUltra 5 күн бұрын
Лол. Не ожидал тут дбд ютубера увидеть))) Ютуб не кормит?
@Dantesik1
@Dantesik1 5 күн бұрын
@@FerelUltra Меня с руки кормит лично Николай
@asylbek_miizamov
@asylbek_miizamov 4 күн бұрын
well done )
@MadMaxxx77
@MadMaxxx77 3 күн бұрын
Очень жду ролик о тестировании!
@nikolay_tuzov
@nikolay_tuzov 3 күн бұрын
А расскажи подробней, что ты хотел бы увидеть в этом ролике?
@aidarark5558
@aidarark5558 5 күн бұрын
Очень круто, хочется с такой же подачей материал посложнее
@nikolay_tuzov
@nikolay_tuzov 5 күн бұрын
Скоро будет ролик посложнее)
@ninshu1138
@ninshu1138 5 күн бұрын
🤓🤓🤓
@sound8bound
@sound8bound 5 күн бұрын
Как всегда супер видос) подскажи модель кресла
@nikolay_tuzov
@nikolay_tuzov 5 күн бұрын
DxRacer Air но мне оно не очень понравилось, неудобное. Хотя, дизайн крутой
@Artem.Alalykin
@Artem.Alalykin 4 күн бұрын
Спасибо за видео! Николай, вопрос не по теме: не подскажешь, что за кресло используешь?
@nikolay_tuzov
@nikolay_tuzov 4 күн бұрын
dxracer air
@user-vt7mk4zh3b
@user-vt7mk4zh3b 4 күн бұрын
Николай, спасибо за очередной опыт. Есть один вопрос, почему мы не прописали логику отправки сообщения внутри case блока тикера ?
@alexanderkuznetsov634
@alexanderkuznetsov634 5 күн бұрын
Вот они проблемы event driven architecture. Я бы взял оркестратор например Temporal, который бы делал retry
@kirillbdev
@kirillbdev 5 күн бұрын
говорят он все еще пытается написать все сам, а copilot все еще мешает..
@Alones116
@Alones116 4 күн бұрын
Спасибо за видео! Ты упомянул двухфазный коммит, про него будет ролик?
@nikolay_tuzov
@nikolay_tuzov 4 күн бұрын
Вряд ли, это уже не моя тема
@sound8bound
@sound8bound 5 күн бұрын
Воркеры не должны брать записи из базы с блокировкой? for update skip locked. Чтобы несколько воркеров не взяли одно и тоже сообщение.
@nikolay_tuzov
@nikolay_tuzov 5 күн бұрын
Да, всё верно, если воркеров больше одного, то так и нужно. Я здесь немного упрощал, чтобы не затягивать, и чтобы было проще для понимания.
@vadimbondarenko7416
@vadimbondarenko7416 3 күн бұрын
Спасибо за видео! А валидно ли архитектурное решение, когда отправляем сообщения в кафку, а воркер уже считывает с кафки и пишет в базу. В то же время другой сервис тоже может считывать с кафки.
@nikolay_tuzov
@nikolay_tuzov 3 күн бұрын
Нет, не решает. Допустим, все сервисы узнали о новом переводе, а что дальше? Наш Transfer Manager начинает этот перевод обрабатывать. В процессе его статус будет меняться: initial -> processing -> done / failed. Как другие сервисы будут узнавать о смене статуса? Ну и дальше та же логика - мы обновляем статус платежа в БД и отправляем сообщение об этом. По сути, Transfer Manager здесь является исходным источником информации. В общем, это не решает текущую проблему, ты просто смещаешь угол обзора. В моём рассказе не принципиально, по какому каналу Transfer Manager получил инфу о новом переводе - по grpc, из кафки и т.п. Суть не меняется. Если хочешь обсудить подробней, приходи в наш чат Gopher Club, обсудим.
@vadimbondarenko7416
@vadimbondarenko7416 3 күн бұрын
@@nikolay_tuzov Да, все верно. Спасибо за объяснение!
@VladA-sj9xb
@VladA-sj9xb 5 күн бұрын
В идеале бы еще сделать sender на основе чтения wal из слота репликации)
@nikolay_tuzov
@nikolay_tuzov 5 күн бұрын
Я похожим в Ламоде занимался, но тот проект так и не запустили( Но вообще, это надо в сторону Debezium смотреть, например.
@VladA-sj9xb
@VladA-sj9xb 4 күн бұрын
@@nikolay_tuzov да, если есть возможность им воспользоваться, оптимальный вариант чтобы свои костыли не делать!
@sadstill
@sadstill 5 күн бұрын
Хотел уточнить, вот кейс когда говорится в начале что сервер упадет, не могу понять одно. У нас же сохранение в бд и отправка сообщения в кафку происходит в рамках одной транзакции? Просто если так, то по-идее при перезагрузке сервера, у нас не получится запродюсить сообщение в кафку и транзакция откатится, нет? Как тогда произойдет неконсистентность?
@EgorKartashov
@EgorKartashov 5 күн бұрын
Не факт. А если получилось запродюсить данные в брокер? Тогда данные есть в брокере (и потенциально в консьюмере), а в БД их нет и наоборот. Идея паттерна в том и заключается, чтобы исключить момент когда в рамках транзакции пишем в разные места (бд и брокер).
@sadstill
@sadstill 5 күн бұрын
То есть ты говоришь про кейс. Что сохранили в базу, запродюсили, а потом упал сервер и транзакция откатилась? И вот типо будет неконсистентность?
@MrLotrus
@MrLotrus 4 күн бұрын
Если открыть транзакцию, добавить запись, отправить сообщение в кафку и только потом закоммитить транзакцию, то это существенно замедлит работу с базой.
@nikolay_tuzov
@nikolay_tuzov 4 күн бұрын
У тебя тут главная ошибка в этом месте: "сохранение в бд и отправка сообщения в кафку происходит в рамках одной транзакции". Транзакции обеспечивают атомарность в рамках одной только БД, а кафка сама по себе. Поэтому, не очень понимаю, что ты имеешь ввиду. Да, бывают распределнные транзакции, например 2-phase commit, о котором я упоминал, но это более сложная штука. В любом случае, приходи лучше к нам в Gopher Club, и там обсудим. В комментах неудобно вести долгие дискуссии.
@evgeniykanovalov3372
@evgeniykanovalov3372 5 күн бұрын
Вопрос: а разве сообщение об ошибке, которое возвращается в saveEvent, не будет перезаписано в SaveURL Потеряется же op из saveEvent?
@nikolay_tuzov
@nikolay_tuzov 5 күн бұрын
Нет, ничего не потеряется, мы просто будем врапить одно в другое. В итоге, получится цепочка из всех ошибок, что мы успели завернуть. Попробуй вернуть ошибку из saveEvent, и посмотри что получтся.
@evgeniykanovalov3372
@evgeniykanovalov3372 5 күн бұрын
@@nikolay_tuzov понял, спасибо
@user-cu9yp3me5y
@user-cu9yp3me5y 5 күн бұрын
А видео про garbage collector будет))
@nikolay_tuzov
@nikolay_tuzov 5 күн бұрын
Будет)
@profered
@profered 5 күн бұрын
Было бы круто если бы выложил код или ссылку на репо
@nikolay_tuzov
@nikolay_tuzov 5 күн бұрын
URL Shortener давно уже выложен на гитхабе, а вот ссылка конкретно на ветку с изменениями из этого ролика: github.com/GolangLessons/url-shortener/tree/outbox
@user-uq5zi4xp7u
@user-uq5zi4xp7u 4 күн бұрын
35:12 а почему бы не написать внутри второго case ?
@nikolay_tuzov
@nikolay_tuzov 4 күн бұрын
Потому что "плоский" код легче читается. Я этот select воспринимаю как Guard Expression
@user-hd3qb8bm2e
@user-hd3qb8bm2e 5 күн бұрын
на 25:00 метод tx.Commit() выплняется только и тогда (!) когда err == nil, то есть когда ошибок на выходе не было до выполнения коммита, то есть нет никакого либо либо и переменная commitErr не нужна, можно сразу записывать выхлоп в err = tx.Commit()
@nikolay_tuzov
@nikolay_tuzov 5 күн бұрын
Да, вы правы, спасибо за замечание. Немного запутался в этом месте)
@megasuperlexa2
@megasuperlexa2 5 күн бұрын
так если сервис отваливается по панике, транзакция зависает?
@nikolay_tuzov
@nikolay_tuzov 5 күн бұрын
Если мы откатываем транзакцию через defer, то не зависнет. Потому что defer выполняется даже в случае паники. Но тут надо быть осторожным, т.к. он не выполнится, к примеру, в случае os.Exit() или log.Fatal(). Или если сам сервер перезагрузился.
@firefizik9307
@firefizik9307 5 күн бұрын
Брат ты в казахстан переехал ?
@nikolay_tuzov
@nikolay_tuzov 5 күн бұрын
Я в Казахстан вернулся)
@firefizik9307
@firefizik9307 5 күн бұрын
@@nikolay_tuzov а ты в Алмате или в Астане?
@user-rk5ln4pk9i
@user-rk5ln4pk9i 2 күн бұрын
это все классно, но каков шанс, что это принесет больше пользы, чем вреда? 99% вам нужен монолит
@user-uq5zi4xp7u
@user-uq5zi4xp7u 5 күн бұрын
Микросеврвисов *
@nikolay_tuzov
@nikolay_tuzov 5 күн бұрын
Спасибо, поправил
@user-uq5zi4xp7u
@user-uq5zi4xp7u 5 күн бұрын
​@@nikolay_tuzovждём видео про планировщик ;)
@dimayudin6945
@dimayudin6945 4 күн бұрын
Капец ты похож на маскота GO 😂
@user-mu1ud3ov6g
@user-mu1ud3ov6g 4 күн бұрын
И зачем тут 30 сервисов с кафкой. Почему сервис истории не может просто опираться на таблицу транзакций, в которую пишется уже что зачислили, а что списали. Ну слать туда poll-select банальный. То есть быть асинхронным. А то получается, хотим писать данные в 2 таблицы двух разных микросервисов. Чтобы первый через кафку во второй сервис пулял сообщения. И о ужас у нас несогласованная транзакция. Надо срочно пойти исправиться, и сделать 3й сервис, который лечит проблемы первого и второго. Выкидываем отсюда кафку. Даём доступ второго сервиса до бд первого и нет проблем. Они нам рассказывают что микро- сервисы не должны знать про данные друг друга. Мол на то они и микросервисы. Зато потом как манну небесную впаривают "паттерны проектирования", которые возникли просто потому что как костыль на костыль из-за парадигмы микросервисов
@defanji8484
@defanji8484 5 күн бұрын
@user-yf5ip7td2y
@user-yf5ip7td2y 5 күн бұрын
Лайк за флаг и годное знание❤
@slavanikulin8069
@slavanikulin8069 5 күн бұрын
проблема воркера на тикере в том, что он увеличивает задержку обработки сообщения. Конкретно в вашем примере клиент будет зря триггерить поддержку: он отправил деньги, а в ленту сообщение попадает не сразу. Поэтому он сразу бежит жаловаться. В данном случае что делать? Меньше интервал в тикере делать? Тогда база заспамится. Плюс будут лишние запросы в базу скорее всего
@nikolay_tuzov
@nikolay_tuzov 5 күн бұрын
Меньше интервал, плюс обрабатывать батчами. База выдержит, это не проблема.
@user-uq5zi4xp7u
@user-uq5zi4xp7u 4 күн бұрын
​@@nikolay_tuzovв ролике ты сказал, что у батча свои проблемы, что это за проблемы и как их решить.
@nikolay_tuzov
@nikolay_tuzov 3 күн бұрын
Я имел ввиду, что это чуть сложнее в реализации, но не критично. Просто чуть сложнее код получится, и его бует сложнее поддерживать.
Docker за 20 минут
21:42
suchkov tech
Рет қаралды 63 М.
I CAN’T BELIEVE I LOST 😱
00:46
Topper Guild
Рет қаралды 50 МЛН
I’m just a kid 🥹🥰 LeoNata family #shorts
00:12
LeoNata Family
Рет қаралды 17 МЛН
Как на самом деле устроены каналы в Golang? | Golang channels internals
41:31
Чистая архитектура проекта на Golang
58:22
Олег Козырев
Рет қаралды 34 М.
Golang's Mocking Techniques - Kyle Yost | hatchpad Huddle
41:20
GoLang Slice в деталях, простым языком
32:09
Николай Тузов — Golang
Рет қаралды 74 М.