五分鐘帶你瞭解Seata分佈式事務

1.Seata介紹

Seata是由阿里中間件團隊發起的開源項目 Fescar,後更名爲Seata,它是一個是開源的分佈式事務框架。

傳統2PC的問題在Seata中得到了解決,它通過對本地關係數據庫的分支事務的協調來驅動完成全局事務。

是工作在應用層的中間件。主要優點是性能較好,且不長時間佔用連接資源,它以高效並且對業務0侵入的方式解決微服 務場景下面臨的分佈式事務問題,它目前提供AT模式(即2PC)及TCC模式的分佈式事務解決方案。

1.1. Seata的設計思想

seata 採用的是大量運用在數據庫軟件的 Write Ahead Log 思想,即把事務的信息以事務日誌的方式記錄下來。這種處理方式,實際上是對傳統兩階段提交的一種改進和優化。主要有幾個關鍵點:

  1. 傳統兩階段提交協議是阻塞協議,性能差

  2. 傳統兩階段提交協議高可用性不好

  3. 傳統兩階段提交協議的全局事務隔離機制不支持

  4. 根據八二原則,80% 的涉及到全局事務的業務是能正常完成並提交的。

因此,seata 採取的做法是,一個事務分支的數據庫操作執行完後,馬上進行本地事務的提交,從而釋放相關的數據庫 資源。

  • 分支事務中數據的 本地鎖 由本地事務管理,在分支事務 Phase1 結束時釋放。·

  • 同時,隨着本地事務結束,連接 也得以釋放。·

  • 分支事務中數據的 全局鎖 在事務協調器側管理,在決議 Phase2 全局提交時,全局鎖馬上可以釋放。只有在決議全 局回滾的情況下,全局鎖 才被持有至分支的 Phase2 結束。

1.2.本地事務執行流程

在進行本地提交的前提是,seata 會解析 SQL,獲取數據庫表的元數據,根絕 SQL 類型,選擇性地生成數據的前置鏡像和後置鏡像, 保存在 undolog 表中,並且要求與保存 undolog 與業務 SQL 在同一個本地事務內。

這就保證了:

  1. 如果一個本地事務被提交,那麼必定對應着相應的 undo_log

  2. 如果保存 undo_log 保存失敗,那麼業務 SQL 也會失敗

1.3.全局事務提交流程

因爲每個分支事務的本地事務都已經被提交,所以如果全局事務能夠順利進行到“提交“這一階段,那麼意味着所有事務分支的本地事 務都已經被提交了,數據的一致性已經得到了保證。

這個時候全局事務的提交就變得十分輕量級,就是把 undo_log 對應的記錄刪掉即可,即使是當時刪除失敗了,也已經不會影響全局事 務的最終結果,這次刪不了,那就待會再刪,程序刪不了,沒事,頂多人工刪。

1.4.全局事務回滾流程

如果全局事務的任何一個事務分支失敗了,那麼全局事務就進入“回滾“流程,回滾時依據先前保存好數據鏡像,將原來的數據回放回去。

如果全局回放成功,那麼數據的一致性也就得到了保證,如果回放不成功,那麼事務就進入異常。應對異常,可能需要重試,可能需要人工介入。

2.Seata在dubbo中的使用

2.1.新增mvn依賴

在需要增加分佈式事務的模塊加上相關依賴


1.  `<dependency>`

2.  `<groupId>io.seata</groupId>`

3.  `<artifactId>seata-spring-boot-starter</artifactId>`

4.  `<version>1.1.0</version>`

5.  `</dependency>` 

2.2.修改properties文件


1.  `#服務名稱`

2.  `dubbo.application.name=service`

3.  `#註冊中心地址`

4.  `dubbo.registry.address=127.0.0.1:2181`

5.  `#註冊中心類型`

6.  `dubbo.registry.protocol=zookeeper`

7.  `#版本號`

8.  `dubbo.application.version=3`

9.  `# Dubbo Protocol`

10.  `#協議名稱`

11.  `dubbo.protocol.name=dubbo`

12.  `#服務暴露端口`

13.  `dubbo.protocol.port=20880`

18.  `seata.enabled=true`

19.  `seata.application-id=biz-service`

20.  `seata.tx-service-group=my_test_tx_group`

21.  `seata.client.rm.async-commit-buffer-limit=1000`

22.  `seata.client.rm.report-retry-count=5`

23.  `seata.client.rm.table-meta-check-enable=false`

24.  `seata.client.rm.report-success-enable=false`

25.  `seata.client.rm.lock.retry-interval=10`

26.  `seata.client.rm.lock.retry-times=30`

27.  `seata.client.rm.lock.retry-policy-branch-rollback-on-conflict=true`

28.  `seata.client.tm.commit-retry-count=5`

29.  `seata.client.tm.rollback-retry-count=5`

30.  `seata.client.undo.data-validation=true`

31.  `seata.client.undo.log-serialization=jackson`

32.  `seata.client.undo.log-table=undo_log`

33.  `seata.client.log.exceptionRate=100`

34.  `seata.service.vgroup-mapping.my_test_tx_group=default`

35.  `seata.service.grouplist.default=127.0.0.1:8091`

36.  `seata.transport.shutdown.wait=3`

37.  `seata.transport.thread-factory.boss-thread-prefix=NettyBoss`

38.  `seata.transport.thread-factory.worker-thread-prefix=NettyServerNIOWorker`

39.  `seata.transport.thread-factory.server-executor-thread-prefix=NettyServerBizHandler`

40.  `seata.transport.thread-factory.share-boss-worker=false`

41.  `seata.transport.thread-factory.client-selector-thread-prefix=NettyClientSelector`

42.  `seata.transport.thread-factory.client-selector-thread-size=1`

43.  `seata.transport.thread-factory.client-worker-thread-prefix=NettyClientWorkerThread`

44.  `seata.transport.thread-factory.worker-thread-size=default`

45.  `seata.transport.thread-factory.boss-thread-size=1`

46.  `seata.transport.type=TCP`

47.  `seata.transport.server=NIO`

48.  `seata.transport.heartbeat=true`

49.  `seata.transport.serialization=seata`

50.  `seata.transport.compressor=none`

51.  `seata.transport.enable-client-batch-send-request=true`

52.  `seata.config.type=file`

53.  `seata.registry.type=file`

2.3.新增配置類


1.  `package cn.enjoy.mt.order.config;`

2.  `import com.alibaba.druid.pool.DruidDataSource;`

3.  `import org.apache.ibatis.session.SqlSessionFactory;`

4.  `import org.mybatis.spring.SqlSessionFactoryBean;`

5.  `import org.springframework.boot.context.properties.ConfigurationProperties;`

6.  `import org.springframework.context.annotation.Bean;`

7.  `import org.springframework.context.annotation.Configuration;`

8.  `import org.springframework.core.io.support.PathMatchingResourcePatternResolver;`

9.  `import javax.sql.DataSource;`

10.  `@Configuration`

11.  `public  class  SeataConfiguration  {`

12.  `@Bean`

14.  `@ConfigurationProperties(prefix =  "spring.datasource")`

16.  `public  DataSource druidDataSource()  {`

18.  `DruidDataSource druidDataSource =  new  DruidDataSource();`

20.  `return druidDataSource;`

22.  `}`

24.  `@Bean`

25.  `public  SqlSessionFactory sqlSessionFactory(DataSource dataSource)  throws  Exception  {`

27.  `SqlSessionFactoryBean factoryBean =  new  SqlSessionFactoryBean();`

29.  `factoryBean.setDataSource(dataSource);`

31.  `factoryBean.setMapperLocations(new  PathMatchingResourcePatternResolver()`

33.  `.getResources("classpath:/mapping/.xml"));`

35.  `return factoryBean.getObject();`

37.  `}`

38.  `}`

2.4.新增undo_log日誌表


1.  `CREATE TABLE undo_log (`

2.  `id bigint(20) NOT NULL AUTO_INCREMENT,`

3.  `branch_id bigint(20) NOT NULL,`

4.  `xid varchar(100) NOT NULL,`

5.  `context varchar(128) NOT NULL,`

6.  `rollback_info longblob NOT NULL,`

7.  `log_status int(11) NOT NULL,`

8.  `log_created datetime NOT NULL,`

9.  `log_modified datetime NOT NULL,`

10.  `ext varchar(100) DEFAULT NULL,`

11.  `PRIMARY KEY (id),`

12.  `UNIQUE KEY ux_undo_log (xid,branch_id)`

13.  `) ENGINE=InnoDB DEFAULT CHARSET=utf8;`

2.5.SeataProperties


1.  `package cn.enjoy.mt.order.config;`

2.  `import org.springframework.boot.context.properties.ConfigurationProperties;`

3.  `@ConfigurationProperties("spring.cloud.alibaba.seata")`

4.  `public  class  SeataProperties  {`

5.  `private  String txServiceGroup;`

6.  `public  SeataProperties()  {`

7.  `}`

8.  `public  String getTxServiceGroup()  {`

9.  `return  this.txServiceGroup;`

10.  `}`

11.  `public  void setTxServiceGroup(String txServiceGroup)  {`

12.  `this.txServiceGroup = txServiceGroup;`

13.  `}`

14.  `}`

2.6.修改啓動類


1.  `package cn.enjoy.mt.order;`

2.  `import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;`

3.  `import org.mybatis.spring.annotation.MapperScan;`

4.  `import org.springframework.boot.SpringApplication;`

5.  `import org.springframework.boot.autoconfigure.SpringBootApplication;`

6.  `import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;`

7.  `import org.springframework.cache.annotation.EnableCaching;`

8.  `import org.springframework.context.annotation.PropertySource;`

9.  `@SpringBootApplication(exclude =  DataSourceAutoConfiguration.class)`

10.  `@EnableDubbo`

11.  `@PropertySource("classpath:mt_db.properties")`

12.  `@MapperScan("cn.enjoy.mt.dao")`

13.  `@EnableCaching`

14.  `public  class  OrderServiceApp  {`

15.  `public  static  void main(String[] args)  {`

16.  `SpringApplication.run(OrderServiceApp.class,args);`

17.  `}`

18.  `}`

2.7.增加 @GlobalTransactional註解

2.7.1.產品服務


1.  `@GlobalTransactional`

2.  `public  void deleteById(Integer id)  {`

3.  `orderService.deleteByProductId(id);`

4.  `int i =  10/0;`

5.  `productInfoMapper.deleteByPrimaryKey(id);`

6.  `}`

2.7.2.訂單服務


1.  `@Override`

3.  `@GlobalTransactional`

5.  `public  void deleteByProductId(int id)  {`

7.  `orderInfoMapper.deleteByProductId(id);`

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