阿里開源高效簡單易用的分布式事務(wù)解決方案——fescar

FESCAR: 快速簡單的提交和回滾

FESCAR是什么?

A distributed transaction solution with high performance and ease of use for microservices architecture.

一種高性能、易使用的微服務(wù)架構(gòu)分布式事務(wù)解決方案。

在微服務(wù)中的分布式事務(wù)問題

讓我門想象一下一個傳統(tǒng)的單體應(yīng)用,它的業(yè)務(wù)由三個模塊構(gòu)建而成,他們使用了一個單一本地數(shù)據(jù)源。

很顯然,本地事務(wù)可以保證數(shù)據(jù)一致性

Monolithic App

微服務(wù)架構(gòu)中一些事情需要被改變,這三個被上文提及到的模塊,被設(shè)計為三個不同數(shù)據(jù)源之上的三個服務(wù),在本地事務(wù)能夠保證數(shù)據(jù)一致性。

但是對于真?zhèn)€業(yè)務(wù)邏輯范圍如何保證數(shù)據(jù)一致性呢?

Microservices Problem

FESCAR是怎么做的?

FESCAR只是一個上述提及問題的解決方案

FESCAR solution

首先,如何明確這個分布式事務(wù)呢?

我們說,一個分布式事務(wù)是一個全局事務(wù),由一批分支事務(wù)組成,通常分支事務(wù)只是本地事務(wù)

Global & Branch

FESCAR有三個基礎(chǔ)組件:

  • Transaction Coordinator(TC): 全局和分支事務(wù)的狀態(tài)的保持,驅(qū)動這個全局的提交和回滾.
  • Transaction Manager(TM): 明確全局事務(wù)的范圍:開始一個全局事務(wù),提交或者回滾一個全局事務(wù).
  • Resource Manager(RM): 管理分支事務(wù)工作資源,告訴TC,注冊這個分支事務(wù)和上報分支事務(wù)的狀態(tài),驅(qū)動分支事務(wù)的的提交和回滾。
Model

一個典型的FESCAR管理分布式事務(wù)的生命周期:

  1. TM詢問TC開啟一個新的全局事務(wù),TC生成一個XID,代表這個全局事務(wù)

  2. XID 通過微服務(wù)的調(diào)用鏈傳播

  3. RM將本地事務(wù)注冊為XID到TC的相應(yīng)全局事務(wù)的分支。

  4. TM要求TC提交或回滾XID的對應(yīng)的全局事務(wù)。

  5. TC驅(qū)動整個分支在XID對應(yīng)的全局事務(wù)下,去完成分支的提交或者回滾

  6. TM asks TC to begin a new global transaction. TC generates an XID representing the global transaction.

  7. XID is propagated through microservices' invoke chain.

  8. RM register local transaction as a branch of the corresponding global transaction of XID to TC.

  9. TM asks TC for committing or rollbacking the corresponding global transaction of XID.

  10. TC drives all branch transactions under the corresponding global transaction of XID to finish branch committing or rollbacking.

Typical Process

快速開始

讓我們開啟一個微服務(wù)例子

開啟FESCAR服務(wù)

  • 下載正是安裝包并解壓

  • cd bin,運行啟動腳本

    sh fester-server.sh /User/min.ji/Downloads/data

用例

用戶購買商品的業(yè)務(wù)邏輯。整個業(yè)務(wù)邏輯有3個微服務(wù)

  • 倉儲服務(wù):扣減庫存數(shù)量在給定的商品
  • 訂單服務(wù):根據(jù)購買請求創(chuàng)建訂單
  • 賬戶服務(wù):記錄賬戶的余額

架構(gòu):

Architecture

StorageService

public interface StorageService {
    /**
     * deduct storage count
     */
    void deduct(String commodityCode, int count);
}

OrderService

public interface OrderService {
    /**
     * create order
     */
    Order create(String userId, String commodityCode, int orderCount);
}

AccountService

public interface AccountService {
    /**
     * debit balance of user's account
     */
    void debit(String userId, int money);
}

Main business logic

public class BusinessServiceImpl implements BusinessService {
    private StorageService storageService;
    private OrderService orderService;
    /**
     * purchase
     */
    public void purchase(String userId, String commodityCode, int orderCount) {

        storageService.deduct(commodityCode, orderCount);

        orderService.create(userId, commodityCode, orderCount);
    }
}
public class OrderServiceImpl implements OrderService {
    private OrderDAO orderDAO;
    private AccountService accountService;
    public Order create(String userId, String commodityCode, int orderCount) {
        int orderMoney = calculate(commodityCode, orderCount);
        accountService.debit(userId, orderMoney);
        Order order = new Order();
        order.userId = userId;
        order.commodityCode = commodityCode;
        order.count = orderCount;
        order.money = orderMoney;
        // INSERT INTO orders ...
        return orderDAO.insert(order);
    }

FESCAR分布式事務(wù)解決方案

undefined

我們就需要一個注解@GlobalTransactional在業(yè)務(wù)方法中

    @GlobalTransactional
    public void purchase(String userId, String commodityCode, int orderCount) {
        ......
    }

由Dubbo + FESCAR的例子

第一步:設(shè)置數(shù)據(jù)庫
  • 需求:mysql中的InnoDB引擎

筆記:事實上,在我們使用的例子中,應(yīng)該有三個服務(wù)使用三個這樣的數(shù)據(jù)庫,然而,我們可以簡單穿件一個數(shù)據(jù)庫,但創(chuàng)建三個數(shù)據(jù)源。

根據(jù)你創(chuàng)建的數(shù)據(jù)庫修改springXML文檔

dubbo-account-service.xml dubbo-order-service.xml dubbo-storage-service.xml

    <property name="url" value="jdbc:mysql://x.x.x.x:3306/xxx" />
    <property name="username" value="xxx" />
    <property name="password" value="xxx" />
第二步:創(chuàng)建UNDO_LOG表

UNDO_LOG表在FESCAR AT模式中需要被用到

CREATE TABLE `undo_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `branch_id` bigint(20) NOT NULL,
  `xid` varchar(100) NOT NULL,
  `rollback_info` longblob NOT NULL,
  `log_status` int(11) NOT NULL,
  `log_created` datetime NOT NULL,
  `log_modified` datetime NOT NULL,
  `ext` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_unionkey` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=159 DEFAULT CHARSET=utf8
第三步:創(chuàng)建例程業(yè)務(wù)邏輯表
DROP TABLE IF EXISTS `storage_tbl`;
CREATE TABLE `storage_tbl` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `commodity_code` varchar(255) DEFAULT NULL,
  `count` int(11) DEFAULT 0,
  PRIMARY KEY (`id`),
  UNIQUE KEY (`commodity_code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


DROP TABLE IF EXISTS `order_tbl`;
CREATE TABLE `order_tbl` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` varchar(255) DEFAULT NULL,
  `commodity_code` varchar(255) DEFAULT NULL,
  `count` int(11) DEFAULT 0,
  `money` int(11) DEFAULT 0,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;


DROP TABLE IF EXISTS `account_tbl`;
CREATE TABLE `account_tbl` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` varchar(255) DEFAULT NULL,
  `money` int(11) DEFAULT 0,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
第五步:運行,啟用
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 近日看羋月傳看得心中惱怒,雖那些惡人最后不落得好下場,但聰明伶俐善良之人也不落得好下場,贏通與其母親就是個例子...
    糸愢閱讀 298評論 0 0
  • 接下來的兩個月,要集中精力備考中級會計師,所以文章內(nèi)容會主要集中在經(jīng)濟法和財務(wù)管理方面。加油。 財務(wù)管理 一、考試...
    嘀嗒嘀嗒startS閱讀 274評論 1 0
  • 我的女兒已經(jīng)快三十了。中學(xué)大學(xué)畢業(yè)之后,就一個人在省城漂泊,至今這樣的生活也都七八年了。幸好,好人終有好報...
    俺就是個俗人閱讀 220評論 0 0
  • 大家好,我是大妞。 本文1659字,閱讀需要5分鐘。 圖片來自網(wǎng)絡(luò)。 看到一個問答:90后月收入多少才算正常? 在...
    愛美麗大妞愛思考閱讀 1,209評論 2 2

友情鏈接更多精彩內(nèi)容