首页 > Linux操作系统 > Linux操作系统 > 分布式事务的 6 种解决方案
点击▲关注 “ IT168企业级 ”给公众号置顶
更多精彩 第一时间直达
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()
}
}
}
m := db.Insert(sql)
err := mq.Publish(
"B-Service-topic"
,m)
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()
}
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 的消息,继续推送
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 (
'?'
,
'?'
,
'?'
,
'?'
)
confirm
。本地消息表中
status
有 2 种状态
try
、
confirm
, 无论哪种状态在
OnMessage
都可以监听到,从而发起重试。
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 的消息,继续调用 B-Service
func OnMessage(task *Task){
// request.POST(
"B-Service"
,body)
}
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
状态的消息,可能才刚刚创建,还没被确认提交或删除。这会和正常业务逻辑的执行重复,意味着成功的调用,也会被重试;为尽量避免这种情况,可以检测消息的创建时间是否很短,短的话可以跳过。
err := request.POST(
"Message-Service"
,body)
if
err!=nil {
return
err
}
aErr := request.POST(
"B-Service"
,body)
if
aErr!=nil {
return
aErr
}
try
和
confirm
,消息服务在前面多了一种状态
prepare
。
Confirm
确认提交消息,失败则
Cancel
删除消息。MQ 事务也会存在
prepare
状态,需要 MQ 的消费处理逻辑来确认业务是否成功。
原文作者:xxxxx;如有侵权,请联系管理员删除。