eureka server配置_springcloud+eureka整合分布式事务中间件seata
今天繼續(xù)給大家分享一下阿里的分布式事務(wù)中間件seata的使用,跟上篇文章《springboot多數(shù)據(jù)源整合分布式事務(wù)中間件seata》不一樣的是,上篇文章是單服務(wù)綁定多數(shù)據(jù)源的分布式情況,而本文基于微服務(wù)下每個服務(wù)綁定一個數(shù)據(jù)源的場景,服務(wù)之間依靠eureka客戶端feign進(jìn)行通信。
注:seata有三種模式,AT模式、TCC模式和saga模式,上篇文章和本篇文章介紹的都是AT模式。感興趣的同學(xué)可以參考官網(wǎng)進(jìn)行了解這三種模式:
http://seata.io/en-us/docs/dev/mode/at-mode.html環(huán)境搭建
還是先說一下本文使用的實驗環(huán)境:
springboot:2.1.6.RELEASE
orm框架:mybatis
數(shù)據(jù)庫:mysql
數(shù)據(jù)庫連接池:HikariCP
seata server:1.3.0
springcloud:Greenwich.SR2
整個項目的架構(gòu)如下:
可以看到,項目中有order-server,account-server,storage-server這3個服務(wù),每個服務(wù)綁定自己的數(shù)據(jù)庫。這3個服務(wù)都注冊到eureka上面,同時也都注冊TM到seata-server。seata-server也注冊到了eureka上。
首先我們啟動eureka,這里監(jiān)聽8889端口,yml文件配置如下:
server: port: 8889spring: application: name: eureka-server#Eureka實例名,集群中根據(jù)這里相互識別eureka: instance: hostname: localhost#客戶端 client:#是否開啟注冊服務(wù),因為這里如果為true表示自己注冊自己,而自己就是一個服務(wù)注冊方,沒必要自己注冊自己 register-with-eureka: false#是否拉取服務(wù)列表,這里我只提供服務(wù)給別的服務(wù)。 fetch-registry: false#注冊中心地址 service-url: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/#服務(wù)端: server: enable-self-preservation: false接著我們啟動seata server,由于seata server也要注冊到eureka上面,我們需要修改seata server,把registry.conf文件修改為如下:
registry { # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa type = "eureka" #省略無關(guān)的代碼 eureka { #我本地配置的eureka地址 serviceUrl = "http://192.168.59.1:8889/eureka" application = "seata-server" weight = "1" } #省略其他代碼執(zhí)行如下命令啟動seata server:
./seata-server.sh -p 8091 -h 127.0.0.1 -m file配置3個微服務(wù),這里我們以order-server為例,先看yml文件,核心配置就是eureka、feign、mybatis和數(shù)據(jù)源,代碼如下:
#配置eurekaeureka: instance: hostname: localhost prefer-ip-address: true client: serviceUrl: defaultZone: http://${eureka.instance.hostname}:8889/eureka/feign: hystrix: enabled: false client: config: default: connectTimeout: 5000 readTimeout: 10000logging: level: io: seata: info#配置mybatismybatis: mapperLocations: classpath:mapper/*.xml typeAliasesPackage: io.seata.sample.entityserver: port: 8180spring: application: name: order-server cloud: alibaba: seata: tx-service-group: my_test_tx_group #配置數(shù)據(jù)源 datasource: driver-class-name: com.mysql.jdbc.Driver password: 123456 jdbcUrl: jdbc:mysql://192.168.59.1:3306/seata_order?useAffectedRows=true&serverTimezone=UTC&characterEncoding=utf-8 username: rootregistry.conf文件,最核心的就是type使用eureka,然后配置eureka地址和應(yīng)用名稱,部分代碼如下:
registry { # file 、nacos 、eureka、redis、zk、consul、etcd3、sofa type = "eureka"#省略其他代碼 eureka { serviceUrl = "http://localhost:8889/eureka" application = "order-server" weight = "1" }#省略其他代碼file.conf文件只要改一下service就可以了,里面配置seata server地址,代碼如下:service { #transaction service group mapping vgroupMapping.my_test_tx_group = "seata-server" #only support when registry.type=file, please don't set multiple addresses default.grouplist = "192.168.59.132:8091" #degrade, current not support enableDegrade = false #disable seata disableGlobalTransaction = false}用這種方式配置account-server和storage-server,之后把3個服務(wù)都起來,啟動成功后,訪問eureka頁面,地址如下:
http://localhost:8889/這時我們能看到加上seata server一共4個服務(wù)都已經(jīng)啟動成功了,見下圖:
下面我貼一下整個項目的sql語句:
#########################seata_order庫use database seata_order;CREATE TABLE `orders` ( `id` mediumint(11) NOT NULL AUTO_INCREMENT, `user_id` int(11) DEFAULT NULL, `product_id` int(11) DEFAULT NULL, `COUNT` int(11) DEFAULT NULL COMMENT '數(shù)量', `pay_amount` decimal(10,2) DEFAULT NULL, `status` varchar(100) DEFAULT NULL, `add_time` datetime DEFAULT CURRENT_TIMESTAMP, `last_update_time` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8#########################seata_pay庫use database seata_pay;DROP TABLE account;CREATE TABLE `account` ( `id` BIGINT(11) NOT NULL AUTO_INCREMENT COMMENT 'id', `user_id` BIGINT(11) DEFAULT NULL COMMENT '用戶id', `total` DECIMAL(10,0) DEFAULT NULL COMMENT '總額度', `used` DECIMAL(10,0) DEFAULT NULL COMMENT '已用余額', `balance` DECIMAL(10,0) DEFAULT '0' COMMENT '剩余可用額度', `last_update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`)) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;INSERT INTO `seata_pay`.`account` (`id`, `user_id`, `total`, `used`, `balance`) VALUES ('1', '1', '1000', '0', '100');#########################seata_storage庫use database seata_storage;CREATE TABLE `storage` ( `id` BIGINT(11) NOT NULL AUTO_INCREMENT, `product_id` BIGINT(11) DEFAULT NULL COMMENT '產(chǎn)品id', `total` INT(11) DEFAULT NULL COMMENT '總庫存', `used` INT(11) DEFAULT NULL COMMENT '已用庫存', `residue` INT(11) DEFAULT NULL COMMENT '剩余庫存', PRIMARY KEY (`id`)) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;INSERT INTO `seata_storage`.`storage` (`id`, `product_id`, `total`, `used`, `residue`) VALUES ('1', '1', '100', '0', '100');#########################下面的undo_log表前面三個庫都需要創(chuàng)建CREATE TABLE `undo_log` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `branch_id` bigint(20) NOT NULL, `xid` varchar(100) NOT NULL, `context` varchar(128) NOT NULL, `rollback_info` longblob NOT NULL, `log_status` int(11) NOT NULL, `log_created` datetime NOT NULL, `log_modified` datetime NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8至此,整個環(huán)境就搭建完成了,接著我們進(jìn)行測試。我們先看下account和storage兩張表的數(shù)據(jù),其他表都是空,如下圖:
account
storage表
測試
現(xiàn)在我們開始進(jìn)行測試,有2個場景,正常commit和場景和異常rollback場景。我們向order-server發(fā)一個post請求,content如下:
{ "userId":1, "productId":1, "count":1, "money":1, "payAmount":50}這時order-server執(zhí)行成功,日志如下:
2020-08-15 16:31:53.704 INFO 57868 --- [nio-8181-exec-1] i.s.sample.service.AccountServiceImpl : ------->扣減賬戶開始account中2020-08-15 16:31:54.141 INFO 57868 --- [nio-8181-exec-1] i.s.sample.service.AccountServiceImpl : ------->扣減賬戶結(jié)束account中2020-08-15 16:31:54.141 INFO 57868 --- [nio-8181-exec-1] i.s.sample.service.AccountServiceImpl : 修改訂單狀態(tài)開始2020-08-15 16:31:54.309 INFO 57868 --- [nio-8181-exec-1] c.netflix.config.ChainedDynamicProperty : Flipping property: order-server.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 21474836472020-08-15 16:31:54.344 INFO 57868 --- [nio-8181-exec-1] c.n.u.concurrent.ShutdownEnabledTimer : Shutdown hook installed for: NFLoadBalancer-PingTimer-order-server2020-08-15 16:31:54.345 INFO 57868 --- [nio-8181-exec-1] c.netflix.loadbalancer.BaseLoadBalancer : Client: order-server instantiated a LoadBalancer: DynamicServerListLoadBalancer:{NFLoadBalancer:name=order-server,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null2020-08-15 16:31:54.352 INFO 57868 --- [nio-8181-exec-1] c.n.l.DynamicServerListLoadBalancer : Using serverListUpdater PollingServerListUpdater2020-08-15 16:31:54.385 INFO 57868 --- [nio-8181-exec-1] c.netflix.config.ChainedDynamicProperty : Flipping property: order-server.ribbon.ActiveConnectionsLimit to use NEXT property: niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit = 21474836472020-08-15 16:31:54.386 INFO 57868 --- [nio-8181-exec-1] c.n.l.DynamicServerListLoadBalancer : DynamicServerListLoadBalancer for client order-server initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=order-server,current list of Servers=[10.192.86.60:8180],Load balancer stats=Zone stats: {defaultzone=[Zone:defaultzone; Instance count:1; Active connections count: 0; Circuit breaker tripped count: 0; Active connections per server: 0.0;]},Server stats: [[Server:10.192.86.60:8180; Zone:defaultZone; Total Requests:0; Successive connection failure:0; Total blackout seconds:0; Last connection made:Thu Jan 01 08:00:00 CST 1970; First connection made: Thu Jan 01 08:00:00 CST 1970; Active Connections:0; total failure count in last (1000) msecs:0; average resp time:0.0; 90 percentile resp time:0.0; 95 percentile resp time:0.0; min resp time:0.0; max resp time:0.0; stddev resp time:0.0]]}ServerList:org.springframework.cloud.netflix.ribbon.eureka.DomainExtractingServerList@5fa120e12020-08-15 16:31:54.562 INFO 57868 --- [nio-8181-exec-1] i.s.sample.service.AccountServiceImpl : 修改訂單狀態(tài)結(jié)束:訂單狀態(tài)修改成功2020-08-15 16:31:54.578 WARN 57868 --- [nio-8181-exec-1] c.a.c.seata.web.SeataHandlerInterceptor : xid in change during RPC from 192.168.59.132:8091:37575557075451904 to null2020-08-15 16:31:55.166 INFO 57868 --- [ch_RMROLE_1_1_8] i.s.c.r.p.c.RmBranchCommitProcessor : rm client handle branch commit process:xid=192.168.59.132:8091:37575557075451904,branchId=37575566823014400,branchType=AT,resourceId=jdbc:mysql://192.168.59.1:3306/seata_pay,applicationData=null2020-08-15 16:31:55.169 INFO 57868 --- [ch_RMROLE_1_1_8] io.seata.rm.AbstractRMHandler : Branch committing: 192.168.59.132:8091:37575557075451904 37575566823014400 jdbc:mysql://192.168.59.1:3306/seata_pay null2020-08-15 16:31:55.170 INFO 57868 --- [ch_RMROLE_1_1_8] io.seata.rm.AbstractRMHandler : Branch commit result: PhaseTwo_Committed2020-08-15?16:31:55.356??INFO?57868?---?[erListUpdater-0]?c.netflix.config.ChainedDynamicProperty??:?Flipping?property:?order-server.ribbon.ActiveConnectionsLimit?to?use?NEXT?property:?niws.loadbalancer.availabilityFilteringRule.activeConnectionsLimit?=?2147483647這時我們再看下數(shù)據(jù)庫的數(shù)據(jù),如下圖:
order表
account表
storage表
容易迷惑我們的是,order表的pay_amount值是45.5,而不是50,這時因為account-server執(zhí)行完成后,又調(diào)用了order-server,執(zhí)行了更新操作,代碼如下:
public void decrease(Long userId, BigDecimal payAmount) { LOGGER.info("------->扣減賬戶開始account中"); //模擬超時異常,全局事務(wù)回滾 //try { // Thread.sleep(30*1000); //} catch (InterruptedException e) { // e.printStackTrace(); //} accountDao.decrease(userId,payAmount); LOGGER.info("------->扣減賬戶結(jié)束account中"); //修改訂單狀態(tài),此調(diào)用會導(dǎo)致調(diào)用成環(huán) LOGGER.info("修改訂單狀態(tài)開始"); String mes = orderApi.update(userId, payAmount.multiply(new BigDecimal("0.09")),0); LOGGER.info("修改訂單狀態(tài)結(jié)束:{}",mes);}第二個場景的測試,我們把上面的代碼模擬超時異常這段放開,用debug模式進(jìn)行,繼續(xù)發(fā)送前面一樣的請求,可以看到seata_order庫中的undo_log,如下圖:
undo_log
等超時后,事務(wù)進(jìn)行了回滾。
總結(jié)
可以看到,本篇文章介紹的場景跟上篇差不多,本質(zhì)都是基于undo_log的交易補償,這也是AT模式的特點。但是本文的環(huán)境比上節(jié)復(fù)雜很多,這并不是seata本身造成的,而是微服務(wù)的拆分帶來的系統(tǒng)架構(gòu)的復(fù)雜性。
源碼地址:
https://github.com/jinjunzhu/springcloud-eureka-feign-mybatis-seata.githttps://github.com/jinjunzhu/eurekaserver.git總結(jié)
以上是生活随笔為你收集整理的eureka server配置_springcloud+eureka整合分布式事务中间件seata的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python审批流系统_有赞移动关于权限
- 下一篇: php生日计算年龄,php根据生日计算年