分佈式事務一直是微服務的一個難點。相關的解決方案和框架大部分是java的,那麼php該如何解決呢?下面一步一步講解如何用php解決分佈式事務。php
首先從單機事務開始。java
大概邏輯以下 :git
try { // 開始事務 $db->beginTransaction(); // 執行你的操做 // ... // 提交事務 $db->commit(); } catch (Exception $e) { // 執行失敗 回滾 $db->rollBack(); }
若是你業務涉及到多個數據庫,事務大概邏輯是這個樣子:github
try { // 開始事務 $db1->beginTransaction(); $db2->beginTransaction(); // 執行你的操做 // ... // 提交事務 $db1->commit(); $db2->commit(); } catch (Exception $e) { // 執行失敗 回滾 $db1->rollBack(); $db2->rollBack(); }
若是你的數據源和業務代碼都是分開的(微服務)這就是咱們今天的核心。 由前面兩種狀況來看,大概邏輯是差很少的,主要也分爲4個步驟。數據庫
有些文章也稱爲tcc
也就是 234 步驟。網絡
咱們用一個經常使用的例子:下單。
主要3個步驟:框架
假設訂單,庫存,用戶都是獨立的服務。分佈式
按照前面的經驗大概分爲4個步驟,咱們以用戶爲例 代碼以下:微服務
class User { // 開始事務 public function beginTransaction() { $db->beginTransaction(); return $this; } // 執行代碼 public function doTransaction() { // 執行你的操做 // ... return $this; } public function commit() { $db->commit(); } public funtion rollBack() { $db->rollBack(); } }
庫存(stock),訂單(order)和上面相似,也須要這4個方法,我就不寫了。 難點在於咱們無法直接操做數據源,只能經過rpc調用相應的服務來操做。依次執行上面的方法就行了。代碼以下:性能
try { // 開始事務 $user = new User(); $stock = new Stock(); $order = new Order(); $user = $user->beginTransaction(); $stock = $stock->beginTransaction(); $order = $order->beginTransaction(); // 執行你的操做 $user = $user->doTransaction(); $stock = $stock->doTransaction(); $order = $order->doTransaction(); // 提交事務 $user->commit(); $stock->commit(); $order->commit(); } catch (Exception $e) { // 執行失敗 回滾 $user->rollBack(); $stock->rollBack(); $order->rollBack(); }
到這裏可能有人看出問題來了,正常狀況下這樣確定是不行的。要上面這段代碼成立須要知足1個條件:User
分別調用了3次,也就是3個請求。要保證這3個請求是調用的同一個實例化後的對象。Stock
和Order
同樣。
User
調用邏輯以下:
// 第一次請求調用 $user = new User(); $user = $user->beginTransaction(); // 第二次請求調用 複用的第一次 $user $user = $user->doTransaction(); // 第三次請求調用 複用的第一次 $user $user->commit(); //或者 $user->rollBack();
注意: 雖然調用了3次可是隻new
了一次, 第二次和第三次請求是複用的第一次的對象。要知足這個條件 服務供方必須 常駐內存 ,並且提供的rpc服務
必須支持鏈式調用
的功能。
one
框架 https://github.com/lizhichao/one
極簡 . 高性能 . 鬆耦合 . 分佈式 . 可運行於多種環境
one
框架完美支持上面的要求。只須要把上面的User
、Stock
和Order
添加爲rpc服務便可。還須要注意beginTransaction
和doTransaction
方法必須返回$this
提供給後面的方法調用。
user服務以下:
RpcServer::add(User::class);
其餘兩個相似。到此分佈式事務問題就搞定了,可能以爲這麼簡單嗎?這主要因爲one框架
的rpc服務提供了鏈式調用(多個請求複用同一個對象)的功能。
可能有人要問:若是由於網絡問題或者其餘問題致使最後一個服務的最後一次調用失敗了怎麼辦? 解決方案就是事務補償
,你能夠把這類極端的狀況下的錯誤,放到一個隊列裏 起一服務來專門處理這裏問題。