知乎專欄 | 多維度架構 | | | 微信號 netkiller-ebook | | | QQ群:128659835 請註明“讀者” |
在使用超級賬本的過程中我發現一個問題,超級賬本無法並發操作一個 key,stub.PutState 是非同步執行,我們無法確認它是否執行完成,在沒有執行完成之前再發起操作,就會產生覆蓋。這個問題限制了超級賬本的很多場景應用,這是超級賬本的硬傷。
下面舉一個例子來說明超級賬本的問題
func (s *SmartContract) counter(stub shim.ChaincodeStubInterface, args []string) pb.Response { key := "counter" count,err = stub.GetState(key) count = count + 1 stub.PutState(key,count) return shim.Success(count) }
使用多綫程請求chaincode中的counter函數100次。你會發現最終 count 並不等於 100。學習過多綫程的朋友一定很清楚出了什麼問題。
問題出在 stub.PutState 函數count還沒有被寫入,其他綫程就開始讀取stub.GetState(key),導致讀取舊數據,最終計數器數字混亂。
很多場景需要更新區塊中的數據,如果頻繁操作,就會產生覆蓋,目前Hyperledger Fabirc 並沒有提供解決方案。
1. 我們不知道 stub.PutState是否執行完成,因為存儲過程需要共識排序。
2. 超級賬本沒有提供事物處理或者互斥鎖。
golang 提供的 mutex 也無法解決上面的問題,因為 mutex 鎖只能工作在一個進程中。Peer / Orderer 節點不止一個。
使用 redis實現分散式鎖或許能實現,但思考過後決定放棄,轉為傳統資料庫。
總結,超級賬本只適合一次寫,多次讀的場景,和極低頻修改的場景