MySQL分佈式事務一致性問題

分佈式事務保持一致性,記錄下我的方案,暫命名爲事務傳遞提交

假設有ABCD四個系統,有一個事務,需要在四個系統裏都進行事務修改數據提交。

先設置一個事務傳遞參數,如下:

type AffairArgs struct {
	Sys    string //系統名
	Method RpcMethod //方法名
	Dic    *map[string]interface{} //方法參數
}

第一步,A作爲主系統,先處理完事務,不要提交;
第二步,A生成調用BCD所需要的數據,示意如下:
注意:如果A對BCD執行順序有要求,可以調整BCD的順序,BCD是按照數組的順序依次執行的。

	//rpc調用B系統接口
	argAry := []saRpc.AffairArgs{
		saRpc.AffairArgs{
			Sys:    "B",
			Method: "B的接口",
			Dic:    "參數",
		},
		saRpc.AffairArgs{
			Sys:    "C",
			Method: "C的接口",
			Dic:    "參數",
		},
		saRpc.AffairArgs{
			Sys:    "D",
			Method: "D的接口",
			Dic:    "參數",
		},
	}
	err := saRpc.Call("B接口", &argAry)
	if err != nil {
		_ = sess.Rollback()
	}

第三步,BCD中事務處理示意如下:

//事務接口演示
func Affair_demo(ary *[]saRpc.AffairArgs) error {
	var err error

	if ary != nil {
		var next *saRpc.AffairArgs
		var curr *saRpc.AffairArgs
		var index = -1
		for i, v := range *ary {
			if v.Sys == revel.AppName {
				index = i
				curr = &v
			} else if next == nil {
				next = &v
			}
		}

		//刪除當前系統的事務
		if index >= 0 {
			*ary = append((*ary)[:index], (*ary)[index+1:]...)
		}
		
		var sess *xorm.Session
		if curr != nil {
			//完成當前系統需要完成的操作,不要提交事務
			sess, err = Affair_demo(curr)
		}

		//執行下一個系統的事務
		if next != nil {
			err = saRpc.Call(next.Method, next.Dic, nil)
			if err != nil {
				//roll back
			}
		}

		//提交事務
		if err == nil && sess != nil {
			err = sess.Commit()
			if err != nil && curr != nil {
				saLog.Log(curr.Sys, curr.Method, "提交事務失敗")
			}
		}
	}
	return err
}

事務處理思路是:

  1. 先在數組內,查找到本系統需要處理的事務(curr),再找下一個需要處理事務的系統(next)。
  2. 本系統處理完,不提交事務
  3. 調用下一個系統,等待下一個系統執行結果
  4. 下一個系統如果執行成功,則提交事務;如果失敗,則回滾。
  5. 返回上一個系統執行結果

完整執行過程:
假設事務傳遞的順序是A->B->C->D,在傳導的過程中,執行的過程如下:

  1. ABC事務都完成了,但是都沒提交事務;
  2. 最後D完成事務,成功則commit,失敗則rollback,並返回C結果;
  3. C收到結果後,成功則commit,失敗則rollback,返回B結果;
  4. B收到結果後,成功則commit,失敗則rollback,返回A結果;
  5. A收到結果後,成功則commit,失敗則rollback;
  6. 這樣逐級把結果返回,最終完成整個事務。

這裏會有一個問題,假設D成功了,返回到C的時候,C commit失敗了,則會返回失敗,B和A會回滾,但是D就無法回滾了。

commit失敗是極小概率事件,一般是災難(網絡問題),只能人爲干涉了

該方案優點:
較爲簡單易用,跟一般的rpc服務並沒有太大的差異,且不用擔心單點故障
缺點也很明顯:
ABCD是阻塞、順序調用,執行效率會比較低;對於commit失敗的處理,在極小概率下會出現數據不一致情況。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章