docs/Spring全家桶/SpringCloudAlibaba/SpringCloudAlibabaSeata.md
Ƕ֪ Seata һֲʽĽǾ˽һʲôǷֲʽ˽һ»֪ʶ˽һĸʲô
IJֹɡ ACID
Ϊ֣ͷֲʽ
ڼϵͳУȽ϶ͨϵݿݿⱾԽʵֵģΪӦҪϵݿάݿӦöͬһԻڹϵݵֱΪ
ֲʽָIJߡ֧ķԴԼ߷ֱλڲͬķֲʽϵͳIJͬڵ֮ϣڲͬӦãֲʽҪ֤ЩҪôȫɹҪôȫʧܣֲʽΪ˱֤ڲͬݿݵһԡ
Seata ˼·ǽıһȫɸACIDγһķֲʽֲʽDzһ
ֲʽϵͳһӦòΪɶķڷ֮ͨҪԶЭIJֲַʽϵͳڲͬķ֮ͨԶЭɵΪֲʽ繩ӦϵͳУɶۼ桢Լ֪ͨȡ
ͼǿԿֻҪ漰Դͻ⣬ʵʿӦҪij֣ȻϵͳչӦúӦ֮ȻӦ֮ķ룬ܹУҪMQSeata˽֮ǰ˽һ·ֲʽɣԼʵֵġ
ֲʽָIJߣ֧ķԴֱλڷֲʽϵͳIJͬڵ֮ϣͨһֲʽл漰ԶԴҵϵͳIJ
Żķչ֮ǰĵһĿֲʽתڸ˾ѾձڣʱıѾֲʽӦõҪ˷ֲʽ֮ЭͲ⣬֮IJܹһѭACIDԭΪһ⣬ڴţDzϵ̽£ҵ˷ֲʽݣCAPɺBASEۡ
CAPһ(C)(A)ݴ(P)ɣڷֲʽϵͳУͬʱConsistency(һ)/Availability()/Partition tolerance(ݴ) ԣֻͬʱ
ͼǿԿûȥﳵµʱȻᾭǿжϿǷ㹻㣬ۼԺҪͬϣһΪ˱֤ݵĽһԣʱˣǵϵͳҪ֤ݴԣҲDZһЩ⣬ʱ뱣֤һԣҪԡ
Ϊ˱֤߿ԣôڸ߲£֤ʱڸӦIJɿǵĶõµݣҪûӦôҲ֤һԣAP֤ǿһԵġ
Ҫ֤߿Ҫ֤һԣõ²ʵ֣ôֻһǾҪ桢Լŵһ𣬵ȥãҲͲǷֲʽϵͳˡ
ڷֲʽϵͳУݴDZڵģֻһԺͿȡᣬ¾͵BASEۡ
BASE (Basically Available)״̬ (Soft state) һ (Eventually consistent) ɣǶCAPһԺͿȨĽԴڶԻϵͳֲʽʵܽᣬǻCAPݻģϵǸǼʱǿһԣÿӦöԸҵص㣬ʵķʽʹϵͳﵽһԡ
õ˼ǣǵĺķǿʹõģķʵĽӦʱ䣬ǽзڵǰУͶ϶ǺķǵķϵͳڵʱֻҪ֤þУͬһӳٸߣȴ߷ȥԺڽлָ
״̬˼˵Ǵµʱۼʱʱʵ߶УܻὫϵͳŪ壬ǿݵͬӳ٣Ӱϵͳʹá
߷Ժһʱͬм״̬һԣ֤ݵһԡ
2PCύЭ飬ǽ̷ΪΣPָΣCָύΡ
ͺñȥKCCܳԣǸպлڶۣһˣʱպиСڿܳԣʱAAҲͻ˵ֻеͬʱܹһͬôͲܳԡ
һ ϰҪȽиͬ⸶ɺҪŮŮͬ⸶ɡ
ζύ ɣϰͣ˶Եܡ
ӾһŮ˫һ˾ܾôϰͲͣһȡǮԭ·˻ء
ͲɵģϰǸŮDzߣֲʽڼйϵ֧ύЭ飺
undo־Ǽ¼ǰݣݿع
Redo ־Ǽ¼ĺݣύдļ
в߷ݣѯǷˣȴߵӦڵִ UndoRedo Ϣ־С߳ɹִYESʾִУЭߴеIJ÷YesӦôͻִύ
κһNoָߵȴʱ֮յвߵķӦôжͻعв߽ڵ㷢 RollBack ߽յ RollBack ڽһ¼UndoϢִĻعɻع֮ͷִڼռõԴع֮Э߷ACKϢڽܵв߷ACKϢ֮жϡ
3PC ҪΪ˽ύЭĵСΧǶύ2PCĸĽ汾ڵijʱ֮⣬3PC2PCηֳѯʣýβԤύ,ηֱΪ CanCommitPreCommitDoCommit
CanCommit Э(Coordinator)(Participant) CanCommitϢѯǷִвյϢʾִܹУ᷵ظЭִܹе(yes)
ִ߲У᷵No,ͷԴ
PreCommit Эյ߷ص״ֵ̬ΪYESô֤ǶȥִôЭ߾ͻв PreCommit ϢЭյ PreCommitϢȥִбִгɹὫ浽 undoredo ٷظЭYESִָбʧܣЭNo,ֻҪЭյһִʧܣв߷жϢյϢлع
βߺЭ߶˳ʱƣûյЭߵϢЭûյ߷صԤִн״̬ڵȴʱ֮жϣ
Э߷PreCommitִгɹyes
ִʧܣֻһNoЭߣЭ߷жϢع
Эյв߷ص״̬YESʱЭеIJ߶ DoCommit յ DoCommit ύύɹЭYES״̬ʾѾύˣЭյв߶YES״̬ô˱
ij߷NoϢЭ߷жϢ(abort)ǣع
3PC2PC棬˳ʱƣ˵⣬3PCȻܽһԵ⣬ΪDoCommitΣ߳ʱԭ²ղЭ߷ жϢ(abort) ʱύӦýлعύᵼݲһµ֣2PCȻ´ǿһԱƻ⣬ǹϻָԺܱ֤һԣ3PCȻгʱʱ䣬˿ԣһԣ粨һϣ2PC3PCġ
https://seata.io/zh-cn/docs/overview/what-is-seata.html
Seata һԴķֲʽṩܺͼõķֲʽSeata Ϊûṩ ATTCCSAGA XA ģʽΪûһվʽķֲʽ
ϵͳУһҵᱻֳɶģ飬ڹٷṩĽṹͼУǿԿǰҪΪģ顣
ڵǰܹУûѡǵƷµҪɲÿһڲӵһı֤ǰݵǿһԣɵȫһԾû취б֤ôSeataġ
ַhttps://seata.io/zh-cn/docs/overview/terminology.html
˽Seata֮ǰ˽һ Seata ؼĸ
һΣ ҵݺͻع־¼ͬһύͷűԴ
Σ ύ첽dzٵɡعͨһεĻع־з
һαύǰҪȷõ ȫ òȫ ύȫijԱһΧڣΧعͷű
ݿⱾ뼶ύϵĻϣSeataAT ģʽĬȫָ뼶 δύ
Ӧض£Ҫȫֵ ύ Ŀǰ Seata ķʽͨ SELECT FOR UPDATE Ĵ
Seata̷ִ
ÿRM ʹ DataSourceProxy ·Ŀʹ ConnectionProxy ʹԴݴĿڵһν undoҵݷһύͱֻҪҵһdudo־
ڵһУundoǰĵֵΪعڵһɾѾ֧ύˣҲͷԴ
TMȫʼXIDȫIDУͨfeignýXIDηУÿ֧Լ Branch ID֧IDXIDй
ڵڶȫύTC֪֧ͨύ֧ڵһѾύ˷ֻ֧Ҫɾundoɣҿ첽ִС
ijһ֧쳣ˣڶȫعTC֪֧ͨع֧ͨXIDBranch-IDҵӦĻع־ͨع־ɵķSQLִУɷ֧ع֮ǰ״̬
صַhttps://github.com/seata/seata/releases
ѹҵconfĿ¼
seata֮ǰҪnacosʵҲֻܼҪnacosУ֪nacosôĿĽnacosܣ֮seatabinĿ¼seata-server.bat
ǿ8091˿ڼnacosעȥˣͱʾseataɹˡ
ǹڷֲʽĺseataĽܾͽˣʵڷֲʽMQʵֿɿϢһԣMQҪܣϢ͵ԭ⡣뷽ϢĿɿԡ
һǽˣڷֲʽseataĻܺʹãȤСԻعһ˵㲻ֲ֪ʽ! СũҲ˵ˣڻҹSeataйseataATTCCSAGA XA ģʽĽܺʹãSeataзֲʽģ͵Ľܡ
SeataΪģ飬ֱ TMRM TC
TC (Transaction Coordinator) - Эߣάȫֺͷ֧״̬ȫύع
**TM (Transaction Manager) - **ȫķΧʼȫύعȫ
RM (Resource Manager) - Դ֧ԴTC̸ע֧ͱ֧״̬֧ύع
Seata Уֲʽִ̣
TM RM Ϊ Seata ĿͻҵϵͳһTC Ϊ Seata ķ˶
˴洢ģʽ֧֣
file ģʽȫỰϢڴжд־ûļroot.dataܽϸߣĬϣ
DB: ߿ģʽȫỰϢͨDBܲһЩ
redis Seata-Server1.3ϰ汾֧֣ܽϸߣϢʧգҪʵʳʹá
ʹDB߿ģʽҵconf/file.confļ
еϢҵӦdbãеjdbcӣҪע漰global_tablebranch_tablelock_tableͬʱ mysql5mysql8Dzһġ
mysql5com.mysql.jdbc.Driver
mysql8com.mysql.cj.jdbc.Driver
ַhttps://github.com/seata/seata/blob/develop/script/server/db/mysql.sql
global_table ȫÿһȫͻڸñм¼ȫID
branch_table ֧¼ÿһ֧ ID֧ĸݿϢ
lock_table ȫ
úԺSeataЧ
Seata֧עNacosԼ֧Seata÷ŵNacosģNacosͳһά ߿ģʽ¾ҪNacos
ҵ conf/registry.confregistryϢ
registry {
# file nacos eurekarediszkconsuletcd3sofa
type = "nacos"
nacos {
application = "seata-server" # ҪͿͻ˱һ
serverAddr = "127.0.0.1:8848"
group = "SEATA_GROUP" # ҪͿͻ˱һ
namespace = ""
cluster = "default"
username = "nacos"
password = "nacos"
}
config {
# filenacos apollozkconsuletcd3
type = "nacos"
nacos {
serverAddr = "127.0.0.1:8848"
namespace = ""
group = "SEATA_GROUP"
username = "nacos"
password = "nacos"
dataId = "seataServer.properties"
}
......
}
ĺúseataеһЩϴNacosУΪȽ϶࣬Թٷṩһconfig.txtֻزijЩϴNacosмɡ
صַhttps://github.com/seata/seata/tree/develop/script/config-center
£
service.vgroupMapping.mygroup=default #
store.mode=db
store.db.driverClassName=com.mysql.cj.jdbc.Driver
store.db.url=jdbc:mysql://127.0.0.1:3306/seata?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
store.db.user=root
store.db.password=123456
ĺļԺļŵseataĿ¼£
Щö뵽NacosУҪһűִУٷѾṩá
ַΪhttps://github.com/seata/seata/blob/develop/script/config-center/nacos/nacos-config.sh
½һnacos-config.shļűݸƽȥcongfig.txt·
ļĺúgitߣnacos-config.shקмɻʹ
sh nacos-config.sh -h 127.0.0.1 -p 8848 -g SEATA_GROUP -t 88b8f583-43f9-4272-bd46-78a9f89c56e8 -u nacos -w nacos
-hnacosַ
-p˿ڣĬ8848
-gseataķбơ
-tnacosռid
-u-wnacosû롣
ĸִʧܣΪredisĹϵԺԣӰʹáԿNacosкܶ˵ɹseataɹ8091˿ڣʾǰùѾɡ
Seata ȫĿܣҪΪ¼
Seata ȫ ̣ΪΣ
Seata νģʽָ Seata ȫµ ֧ ΪģʽȷؽӦý ֧ģʽ
ͬ ģʽ ֧ ʹòͬķʽﵽȫεĿꡣش⣺
ATģʽΪ
ִнΣ
ɻع SQL ¼ع־
־ûع־ҵ SQL ͬһύݿ
ɽΣ
֧ύ첽ɾع־¼
֧عݻع־з
ͽͷϷSeataĴģʽĽܡ
Seata 1.2.0 汾µģͣXAģʽʵ˶XAЭ֧֡XAģʽҪȥ
Ҫ֪XAģʲôXA 淶 90 ͱڽֲʽ⣬ҲķֲʽΪҪݿڲҲ֧XAģʽģMYSQLXAģʽǿһԵص㣬ݿռʱȽϳܱȽϵ͡
XAģʽύ
ATģʽTCCSAGAЩģʽԴXA淶ijЩҵ㡣
XA淶X/OPEN֯ķֲʽDTPDistributed Transaction ProcessingXA淶ȫ;ֲԴ֮ĽӿڣXA淶ĿԴ(ݿ⣬Ӧ÷Ϣеȣͬһзʣʹ ACID ԿԽӦóЧ
XA 淶 ʹύ2PCTwo-Phase Commit֤ԴͬʱύعκضΪXA淶类ԼеݿⶼжXA淶֧֡
ֲʽDTPģͶĽɫ£
DTPģʽTMRM֮ͨѶĽӿڹ淶XAΪݿṩ2PCӿЭ飬ݿXAЭʵֵ2PCֳΪXA
Ӧó(AP)жͿ⣬Ӧó(AP)ͨTM֪ͨ(RM)Ϳ(RM)пۼɶʱRMûύԴ
TMյִϢһRMִʧܣֱRMҲͻععϣͷԴ
TMյִϢRMȫɹRMύύϣͷԴ
ֲʽͨЭXA淶ִʾ
һAPRM1,RM2JDBCӡ
ڶAP֪ͨȫIDRM1RM2עᵽȫID
ִжЭеĵһprepare
IJprepareύع
ǶXAԣһȫԴʧˣôζTMղ֧ôݣһֱӶҲSeataҪص⡣
SeataķֲʽܹУԴ(ݾ֡Ϣ)ȶXAЭ֧֣XAЭĻ֧
ִнΣ
ɻعҵSQLXA֧нУԴXAЭ֧֤ɻع
־ûZA֧Ժִ XA prepareͬԴXAЭ֧֤־û
ɽΣ
Seata Ѿ֧ģʽAT\TCC\SAGADzƹ Դ ֮(Ҫôм棬ҪôӦò)Դڷֲʽ֪ģֶڷֲʽ֪һԵ⣬ȫһԡ
һ¼ڲУ80ۼΪ60ʱֿԱѯݽ60֮Ϊ쳣ععԭ80ôʱԱ60ʵݣм״̬Dzڵݡ
ͲͬXAЭҪԴ ṩԹ淶Э֧֣ΪԴֲ֪ʽУԴԱ֤ӽǶݵķЧԣȫݵһԡ
ٷhttps://github.com/seata/seata-samples
Ŀseata-samples
ҵʼbusiness-xastock-xaorder-xa˺ŷaccount-xa
ĿԺҵĿΪseata-xaĿ¼вݿӣòݿ⣬ֻҪĹٷĵݿϢɡ
ȹע business-xaĿĹעBusinessService.purchase()
@GlobalTransactional
public void purchase(String userId, String commodityCode, int orderCount, boolean rollback) {
String xid = RootContext.getXID();
LOGGER.info("New Transaction Begins: " + xid);
//ÿ
String result = stockFeignClient.deduct(commodityCode, orderCount);
if (!SUCCESS.equals(result)) {
throw new RuntimeException("ʧ,ع!");
}
//ɶ
result = orderFeignClient.create(userId, commodityCode, orderCount);
if (!SUCCESS.equals(result)) {
throw new RuntimeException("ʧ,ع!");
}
if (rollback) {
throw new RuntimeException("Force rollback ... ");
}
}
ʵַ֮ǰֻ࣬Ҫorder-xa(OrderService.create)Ϊ(int i = 1/0;)
public void create(String userId, String commodityCode, Integer count) {
String xid = RootContext.getXID();
LOGGER.info("create order in transaction: " + xid);
int i = 1/0;
// ܼ = (count) * Ʒ(100)
int orderMoney = count * 100;
// ɶ
jdbcTemplate.update("insert order_tbl(user_id,commodity_code,count,money) values(?,?,?,?)",
new Object[] {userId, commodityCode, count, orderMoney});
// ˻ۼ
String result = accountFeignClient.reduce(userId, orderMoney);
if (!SUCCESS.equals(result)) {
throw new RuntimeException("Failed to call Account Service. ");
}
}
һԽXAģʽATģʽתOrderXADataSourceConfiguration.dataSource
@Bean("dataSourceProxy")
public DataSource dataSource(DruidDataSource druidDataSource) {
// DataSourceProxy for AT mode
// return new DataSourceProxy(druidDataSource);
// DataSourceProxyXA for XA mode
return new DataSourceProxyXA(druidDataSource);
}
ĸʵַ http://localhost:8084/purchase
ǿбȻȥӦݿݣûзģ˵ǵXAģʽЧˣdubugȥĿʱݸĵʱݿʵҲûм¼ģΪXAǿһԣֻеԺŻеݡ
XAģʽļ룬SeataȫһԳµȱڣγATTCCSagaXA Ĵģʽİͼгֲʽ
XAATҵģTCCSagaһҵġ
һATģʽATģʽһûķֲʽĽATģʽ£ûֻעԼҵSQLûҵSQLΪһΣSeataܻԶжύͻع
ύЭݱ䣺
һУSeata ҵSQL ȽSQL壬ҵҪҵݣݱǰ¼ undo logȻִ ҵSQL ݣ֮ٴα redo logЩڱݿɣ֤һεԭԡ
һΣαȽϼĻعύ֮ǰһбûͨôִȫֻعִȫύعõľһμ¼ undo Log ͨع¼ɷSQLִУɷ֧ĻعȻɺͷԴɾ־
AT̷ΪΣҪȫڵһΣڶҪع־Ĺ£
ͼǿԿTMTC뿪һȫһͨ@GlobalTransactionalעTC᷵һȫID(XID)ִб֮ǰRMTCעһ֧ undo log ִбredo log ύTC㱨ִOK
Զ̵ãIDݸִб֮ǰTCע֧ͬundo Logredo LogTC㱨״̬ɹ
ȫύTC֪ͨRMһundoredo־һִʧܣôعͨundo logлع
ﻹһ⣬Ϊÿӱύ֪ͨعʱ棬Ѿģֱundo logлعܻᵼݲһµ
ʱ RM redo log֤ԱǷһӶ֪ǷбĹundo logڱǰݣعredologڱĺݣڻعУ顣
ûбĹֱӽлعݣredologУд
˽ATģ͵Ļʵսһ£ATģ;ʵֵġ cloud-alibaba-seata-order cloud-alibaba-seata-stock
ṹt_ordert_stockundo_logűĿԴͱṹundo_log˱ݵĻعĩӡ
cloud-alibaba-seata-orderĴ£
controller
@RestController
public class OrderController {
@Autowired
private OrderService orderService;
@GetMapping("order/create")
@GlobalTransactional //ֲʽ
public String create(){
orderService.create();
return "ɹ";
}
}
OrderService
public interface OrderService {
void create();
}
StockClient
@FeignClient(value = "seata-stock")
public interface StockClient {
@GetMapping("/stock/reduce")
String reduce();
}
OrderServiceImpl
@Service
public class OrderServiceImpl implements OrderService{
@Autowired
private OrderMapper orderMapper;
@Autowired
private StockClient stockClient;
@Override
public void create() {
//ۼ
stockClient.reduce();
System.out.println("ۼɹ");
//ֹ쳣 ڻعϢ
int i = 1/0;
System.err.println("쳣");
//
orderMapper.createOrder();
System.out.println("ɹ");
}
}
OrderMapper
@Mapper
public interface OrderMapper {
@Insert("insert into t_order (order_no,order_num) value (order_no+1,1)")
void createOrder();
}
cloud-alibaba-seata-stockĴ£
@RestController
public class StockController {
@Autowired
private StockService stockService;
@GetMapping("stock/reduce")
public String reduce(){
stockService.reduce();
return "ѿۼ"+ new Date();
}
}
public interface StockService {
void reduce();
}
@Service
public class StockServiceImpl implements StockService{
@Autowired
StockMapper stockMapper;
@Override
public void reduce() {
stockMapper.reduce();
}
}
@Mapper
@Repository
public interface StockMapper {
@Update("update t_stock set order_num = order_num - 1 where order_no = 1 ")
void reduce();
}
붼ȽϼǾͲעҲУҪorderstock֮ǰǵNacosSeataҪʱǷorderRestӿڣhttp://localhost:8087/order/create,Ϊ֤undo_logıڴ洢عݣOrderServiceImpl.create()Ӷϵ㣬debugķʽ
Ȼhttp://localhost:8087/order/createڵʱ䣬ȥundo_logͿ֣ᷢȷʵˣundo_logҲ˶ӦĿռ¼ĵǰϢݾعݡ
ǵF9ͨԺָundo_logҲûˣʱ֤ǵSeataЧعɹ
Ǿ֤ATִй̣XATCCģͣSeataATģͿӦԴҵҿҵ룬֪ЭύعͨAOPɣֻҪעҵɡ
SeataҪڲͬķ֮䴫ȫΨһIDDubboȿܼɻȽѺãDubboùʿIDĴݣIDĴ̶ԿҲ֪
ʹðhttps://seata.io/zh-cn/blog/integrate-seata-tcc-mode-with-spring-cloud.html
TCC ǷֲʽеĶύЭ飬ȫΪ Try-Confirm-CancelԴԤTryȷϲConfirmȡCancelǵľ庬£
TCC һʽķֲʽҪҵϵͳʵ֣ҵϵͳŷdzԣԸӣŵ TCC ȫݿ⣬ܹʵֿݿ⡢ӦԴЩͬݷͨʽı뷽ʽʵһԭӲõؽڸָҵµķֲʽ⡣
AT ģʽ ֱ֧ ACID ϵݿ⣺
ӦģTCC ģʽڵײԴ֧֣
ν TCC ģʽְָ֧ Զ ķ֧뵽ȫĹС
SagaģʽSEATAṩijSagaģʽУҵÿ߶ύijһʧǰѾɹIJߣһͶβִдʱˣһĻᣩҵʵ֡
Saga ģʽ·ֲʽͨ¼ģ֮첽ִеģSaga ģʽһֳ
֮ǰѧϰSeataֲʽֲģʹõĵȫԸݿߵģһЩ£ϵͳյϵͳģͬʱûκηֲʽ룩ôATXATCCģͽȫʹãΪ˽⣬Sagaģ͡
磺߿˾ķϵͳ죬ʹSagaģʽ
SagaģʽSeataṩijṩ칹ϵͳͳһģ͡SagaģʽУеҵֱӲĴֻ𱾵Ĵȫյöʵ֣ڽҵʱijһҵʱԶȫѾɹߣһεúͶεķȫҵʵ֡
ĿǰSeataṩSagaģʽֻͨ״̬ʵ֣ҪֹĽSagaҵ̻ƣҽתΪJsonļڳʱļʵҵԼҪSaga״̬ͼĻƣһҪͨSaga״̬ʵ֡
ٷĵַhttps://seata.io/zh-cn/docs/user/saga.html
Seata Safa״̬ӻͼʹõַhttps://github.com/seata/seata/blob/develop/saga/seata-saga-statemachine-designer/README.zh-CN.md
ܵ˵SeataATģʽٷ֮80ķֲʽҵATģʽʵֵһԣԿܴм״̬XAģʽʵֵǿһԣЧʽϵһ㣬Saga֮ͬķֲʽԹڷֲʽĴģͣеҵXAATûҵԣSagaTCCһҵ롣
https://www.51cto.com/article/713007.html https://lijunyi.xyz/docs/SpringCloud/SpringCloud.html#_2-2-x-%E5%88%86%E6%94%AF https://mp.weixin.qq.com/s/2jeovmj77O9Ux96v3A0NtA https://juejin.cn/post/6931922457741770760 https://github.com/D2C-Cai/herring http://c.biancheng.net/springcloud