представлять
Сегодня, когда распределенные системы и микросервисная архитектура популярны, сервисы не могут обращаться друг к другу. Как обрабатывать исключения и как обеспечить согласованность данных, стало неизбежной проблемой в процессе проектирования микросервисов.
В разных бизнес-сценариях решения будут разными. Общие методы:
В этой статье основное внимание уделяется нескольким другим вопросам. В Интернете уже есть много информации о традиционных делах 2PC и 3PC, поэтому я не буду их здесь повторять.
2
блокировка повторной попытки
В существующей микро-служебной архитектуре более распространенным способом является блокировка повторной попытки.
Пример псевдокода:
m := db.Insert(sql)
err := request(B-Service,m)
func request(url string,body interface{}){
for i:=0; i<3; i ++ {
result, err = request.POST(url,body)
if err == nil {
break
} else {
log.Print()
}
}
}
Как указано выше, при сбое запроса API для службы B инициируется до трех повторных попыток. Если трижды все же произошел сбой, распечатайте журнал и продолжите выполнение или выдайте ошибку на верхний уровень.
Такой подход приведет к следующим проблемам:
Первая проблема: решена за счет поддержки идемпотентности API сервиса B.
Второй вопрос: вы можете исправить данные с помощью фоновых шагов синхронизации, но это не очень хороший метод.
Третий вопрос: это необходимая жертва ради улучшения согласованности, доступности и улучшения согласованности.
Блокировка повторной попытки подходит для сценариев, в которых бизнес не чувствителен к требованиям согласованности. Если требуется согласованность данных, необходимо внедрить дополнительные механизмы для решения проблемы.
3
асинхронная очередь
В процессе развития решений введение очередей является распространенным и лучшим способом. Пример:
m := db.Insert(sql)
err := mq.Publish("B-Service-topic",m)
Записать данные в текущий сервис DB После этого отправьте сообщение на MQ, потребляемый независимыми сервисами MQ Обрабатывать бизнес-логику. иблокировка повторной По сравнению с попыткой, хотя MQ Стабильность гораздо выше, чем у обычных бизнес-сервисов, но при отправке сообщений на MQ Все еще существуют возможности сбоя, такие как проблемы с сетью, текущий простой и т. д. Таким образом вы все равно столкнетесь с блокировкой повторной попытка такая же, как и из проблемы, т.е. DB Запись прошла успешно, но отправка не удалась.
Теоретически, в распределенной системе такая ситуация возникнет в коде, включающем несколько вызовов служб. При длительной работе обязательно возникнут сбои вызовов. Это также одна из трудностей проектирования распределенных систем. Кроме того, ищите учеников по ИТ-коду в общедоступных учетных записях в WeChat, отправляйте информацию в фоновом режиме и получайте видеоуроки объемом 2000 ГБ и новейшие упражнения для собеседований.
4
Компенсация TCC имеет значение
Когда есть требования к транзакциям и их неудобно отделять, транзакции, компенсирующие TCC, являются лучшим выбором.
TCC делит вызов каждой услуги на 2 этапа и 3 операции:
TCC требует, чтобы каждая служба реализовала API для трех вышеуказанных операций. Операцию, которая была завершена за один вызов до того, как служба получила доступ к транзакции TCC, теперь необходимо выполнить в два этапа и три операции.
Например, приложению торгового центра необходимо вызвать службу инвентаризации A, службу суммы B и службу точек C, как показано в следующем псевдокоде:
m := db.Insert(sql)
aResult, aErr := A.Try(m)
bResult, bErr := B.Try(m)
cResult, cErr := C.Try(m)
if cErr != nil {
A.Cancel()
B.Cancel()
C.Cancel()
} else {
A.Confirm()
B.Confirm()
C.Confirm()
}
В коде API-интерфейсы служб A, B и C вызываются соответственно для проверки и резервирования ресурсов. Если все они возвращаются успешно, отправляется операция подтверждения (Confirm). Если операция Try службы C завершается неудачно, API-интерфейсы отмены; из A, B и C вызываются соответственно для освобождения своих резервирований.
TCC решает проблему согласованности данных между несколькими сервисами и несколькими базами данных в распределенной системе. Однако у метода TCC все еще есть некоторые проблемы, на которые необходимо обратить внимание при фактическом использовании, включая сбой вызова, упомянутый в предыдущей главе.
пустой выпуск
Если вызов C.Try() в приведенном выше коде действительно завершится неудачно, избыточный вызов C.Cancel() ниже освободит ресурс, не блокируя его. Это связано с тем, что текущая служба не может определить, действительно ли неудачный вызов заблокировал ресурс C. Если вы не вызовете его, он действительно завершится успешно, но возврат не удастся по сетевым причинам. Это приведет к тому, что ресурс C будет заблокирован и никогда не будет освобожден.
пустой часто появляется выпусксуществовать в производственной среде, Служитьсуществовать реализацию TCC дела API пустой должен поддерживаться, когда выпущен осуществлять。
Тайминг
В приведенном выше коде, если C.Try() Если не получится, позвоните C.Cancel() действовать. По сетевым причинам могут быть C.Cancel() Запросы на первом месте C Сервис, C.Try() После поступления запроса это приведет к пустой проблема с выпуском, вызванная одновременно C Ресурсы заблокированы и никогда не освобождаются.
так C Служба должна отказаться освобождать ресурс после Try() действовать. С точки зрения конкретной реализации, уникальный идентификатор дела можно использовать для различения с первого раза. Try() Или после релиза? Try()。
Не удалось позвонить
Во время процесса вызова «Отмена» и «Подтверждение» по-прежнему будут возникать сбои, например, по обычным сетевым причинам.
Сбой операции Cancel() или Confirm() приведет к тому, что ресурс будет заблокирован и никогда не будет освобожден. Общие решения этой ситуации включают в себя:
Теоретически, неатомарные свойства и свойства дела — это два фрагмента кода.,Будет промежуточное состояние существования,иметь Промежуточное состояние будетиметьнеудачаизвозможность。
5
таблица локальных сообщений
таблица локальных сообщений Первоначально это было ebay рейз из, это делает таблицу локальных Таблицы сообщений и бизнес-данных находятся в одной индивидуальной базе данных, так что местные дела могут быть использованы для соответствия характеристикам дел.
Конкретный метод заключается в вставке бизнес-данных в местные дела.,Также вставьте данные сообщения. Затем существуют последующие операции,Если другие операции успешны,затем удалить сообщение, если оно неудачное, то не удалять;,Асинхронно прослушать это индивидуальное сообщение,Продолжайте пытаться еще раз.
Таблица локальных сообщений — очень хорошая идея, и ее можно использовать по-разному:
Сотрудничать с МК
Пример псевдокода:
messageTx := tc.NewTransaction("order")
messageTxSql := tx.TryPlan("content")
m,err := db.InsertTx(sql,messageTxSql)
if err!=nil {
return err
}
aErr := mq.Publish("B-Service-topic",m)
if aErr!=nil { // подтолкнуть к MQ неудача
messageTx.Confirm() // Обновить сообщение о статусе confirm
} else {
messageTx.Cancel() // Удалить сообщение
}
// Асинхронная обработка confirm изMessage, продолжайте нажимать
func OnMessage(task *Task){
err := mq.Publish("B-Service-topic", task.Value())
if err==nil {
messageTx.Cancel()
}
}
Код выше содержит messageTxSql это таблица вставки локальных сообщенийизабзац SQL :
insert into `tcc_async_task` (`uid`,`name`,`value`,`status`)
values ('?','?','?','?')
это и бизнес SQL существоватьтакой жеиндивидуальныйдела Входитьосуществлять,Либо добиться успеха,Илинеудача。
В случае успеха он будет помещен в очередь. Если отправка успешна, он будет вызван. messageTx.Cancel() Удалите локальное сообщение; если отправка не удалась, пометьте сообщение как confirm。таблица локальных сообщенийсередина status иметь 2 состояние try、confirm, Независимо от того, гдесостояниесуществовать OnMessage можно отслеживать и инициировать повторную попытку.
Локальные дела гарантируют, что сообщения и услуги будут записаны в базу данных,этотназадизосуществлять Независимо от времени простоядасетевой толчокнеудача,Асинхронное прослушивание можно обработать позже,Это гарантирует, что сообщение будет отправлено в MQ.
и MQ Тогда гарантия обязательно дойдет до сервисной службы, воспользовавшись MQ из QOS Стратегия,Потребители Служить обязательно с этим справятся,или продолжает доставляться в следующую индивидуальную бизнес-очередь,Целостность дел гарантируется со стороны и.
Сотрудничать с сервисными вызовами
Пример псевдокода:
messageTx := tc.NewTransaction("order")
messageTxSql := tx.TryPlan("content")
body,err := db.InsertTx(sql,messageTxSql)
if err!=nil {
return err
}
aErr := request.POST("B-Service",body)
if aErr!=nil { // вызов B-Service неудача
messageTx.Confirm() // Обновить сообщение о статусе confirm
} else {
messageTx.Cancel() // Удалить сообщение
}
// Асинхронная обработка confirm или try изMessage, продолжить вызов B-Service
func OnMessage(task *Task){
// request.POST("B-Service",body)
}
Это таблица локальных сообщений + вызовдругой Служитьизпример,безиметь MQ из Введено. При этом используются асинхронные повторы и таблица. локальных сообщений гарантирует надежность сообщения и решает проблему блокировки повторной забота приносит проблемы,существование относительно распространено в повседневном развитии. кроме того,WeChat ищет публичную учетную запись ученика ИТ-кода,существуют Backend отправка: информация,Получите 2000 ГБ видеоуроков и новейшие упражнения для собеседований.
Если локально нет, напишите DB вне работы, вы можете просто написать таблицу локальных сообщений,такой жесуществовать Обработано в OnMessage:
messageTx := tc.NewTransaction("order")
messageTx := tx.Try("content")
aErr := request.POST("B-Service",body)
// ....
Срок действия сообщения истекает
Конфигурациятаблица локальных сообщенийиз Try и Confirm информацияизпроцессор:
TCC.SetTryHandler(OnTryMessage())
TCC.SetConfirmHandler(OnConfirmMessage())
В функции обработки сообщений необходимо определить, существует ли текущая задача сообщения слишком долго. Например, если после повторной попытки в течение часа она по-прежнему не выполняется, рассмотрите возможность отправки электронных писем, текстовых сообщений, оповещений журнала и т. д., чтобы разрешить ручную отправку. вмешательство.
func OnConfirmMessage(task *tcc.Task) {
if time.Now().Sub(task.CreatedAt) > time.Hour {
err := task.Cancel() // Удалите сообщение и прекратите повторные попытки.
// doSomeThing() Сигнализация, ручное вмешательство
return
}
}
существовать Try В функции обработки также необходимо отдельно определить, не существует ли слишком короткое хранилище текущей задачи сообщения, поскольку Tryсостояниеизинформация,Вероятно, только что созданный,Отправка еще не подтверждена. Это повторит обычное выполнение бизнес-логики.,означает успех извызов,также будет повторена попытка избежать этой ситуации;,Может определить, очень ли короткое время создания сообщения,Короткие слова можно пропустить.
Механизм повтора должен полагаться на нижестоящие API существоватьбизнес-логикаиз Идемпотентность,Хотя можно и без обработки,Тем не менее, дизайн все равно должен стараться не мешать обычным запросам.
независимая служба обмена сообщениями
независимая служба обмена сообщениямидатаблица локальных сообщенийиз Обновил версию, поставил таблицу локальных сообщенийразделить на одининдивидуальныйнезависимыйиз Служить。Местоиметьдействоватьдосуществоватьинформация Служитьдобавить виндивидуальныйинформация,назад Продолжениедействоватьуспехно Удалить сообщение,неудачано Отправить подтверждениеинформация。
Затем используйте асинхронную логику для прослушивания сообщений.,Сделайте соответствующую обработку,Логика обработки итаблицы локальных сообщений в основном такая же. Но так как добавление сообщения в сообщение Служить,Невозможно поместить локальную операцию в файл,так сохранит существование сообщение успешно добавлено,назад Продолжениенеудача,Тогда из сообщения на данный момент это индивидуальная бесполезная новость.
Следующий пример сценария:
err := request.POST("Message-Service",body)
if err!=nil {
return err
}
aErr := request.POST("B-Service",body)
if aErr!=nil {
return aErr
}
этотиндивидуальныйбесполезныйизинформация,Сообщение Служить необходимо для подтверждения успешности выполнения этого индивидуального сообщения.,Удалить, если нет,иметь возможность Продолжить выполнение последующей логики. По сравнению с таблицей местных дел, попробуйте и подтвердите.,информация Служитьсуществоватьвпереди еще одинсостояние prepare。
6
MQ дела
иметьнекоторый MQ из реализации поддерживает такие дела, как RocketMQ 。MQ издела можно прочитать как независимая служба обмена сообщениямииз Специальная реализация с полностью последовательной логикой.
Местоиметьдействоватьдосуществовать MQ Отправьте сообщение и последующие операции пройдут успешно. Confirm Подтвердите сообщение об отправке и нажмите «Отмена»,чтобы удалить сообщение в случае неудачи. МК делатакже Будет существоватьсуществовать подготовить статус, требуется MQ Логика обработки потребления для подтверждения успешности бизнеса.
7
Подвести итог
С точки зрения практики распределенных систем,Сценарии для обеспечения согласованности данных,Необходимо внедрить дополнительные механизмы обработки.
TCC Преимущество из заключается в том, что он действует на бизнес-уровне, не полагается на конкретного человека, не связан с конкретной структурой, а степень детализации блокировки ресурсов является относительно гибкой, что делает его очень подходящим для сценариев микро-обслуживания. Недостаток в том, что каждый индивидуальный Служить должен быть реализован. 3 индивидуальный API,Для делового вмешательства и больших перемен,иметь дело с различныминеудачааномальный。Разработчикам сложно полностью справиться с различными Состояние,Поиск зрелого человека из рамок может значительно снизить стоимость,Например Али из Фескара.
таблица локальных Преимущество сообщений в том, что они просты, не зависят от других модификаций Служитьиз и могут быть очень хороши в Сотрудничать. с сервисными вызовамии MQ используются вместе,существование более практично в большинстве бизнес-сценариев. Недостатком является то, что в локальной базе данных больше таблиц сообщений.,и Бизнес-столы, спаренные существуют вместе.
в текстетаблица локальных Метод сообщений из примера из индивидуальной библиотеки автора, заинтересованные студенты могут обратиться к следующим https://github.com/mushroomsir/tcc
MQ делаинезависимая служба обмена Преимущество сообщений состоит в том, чтобы извлечь одну индивидуальную публикацию из Служить, чтобы решить деловую проблему и избежать каждого отдельного человека. альный Служить иметь таблицу сообщений, а Служить в сочетании существуют вместе, увеличивая саму Служить из-за сложности обработки. Недостаток в том, что он поддерживает делаиз. MQ Редко и звонил перед каждой операцией; API добавить виндивидуальныйинформация,Увеличит общую задержку вызовов.,существует Подавляющее большинство нормальных ответов из бизнес-сценариев,Это своего рода лишние расходы.