SpringCloud系列之Nacos+Dubbo+Seata應用篇
阿新 • • 發佈:2020-09-15
[TOC](目錄)
# 前言
本文接上篇文章[《SpringCloud系列之Nacos+Dubbo應用篇》](https://www.cnblogs.com/chinaWu/p/13613518.html)繼續展開,本次在原先整合Nacos和Dubbo基礎上增加分散式事務Seata元件,之前在[《SpringCloud系列之整合分散式事務Seata應用篇》](https://www.cnblogs.com/chinaWu/p/13255200.html)中也提及到Seata的整合,只不過原先Seata使用都是基於“file”展開,在本篇中將介紹如何基於nacos進行配置以及Dubbo和Seata的整合驗證。
# 專案版本
spring-boot.version:2.2.5.RELEASE
spring-cloud.version:Hoxton.SR3
nacos.version:1.3.2
dubbo.version:2.6.9/2.7.6
seata.version:1.3.0
> 關注本文末尾微信公眾號,回覆“**666**”獲取常用開發工具包,內含常用開發元件(Nacos,Seata等),節省FQ下載時間。
# 專案說明
專案模組說明如下:
![](https://img2020.cnblogs.com/blog/451497/202009/451497-20200915095101124-750609054.png)
前端請求介面請求cloud-web模組保留介面,從而呼叫相應業務微服務模組,執行業務邏輯後響應前端請求。
![](https://img2020.cnblogs.com/blog/451497/202009/451497-20200915095107875-496697680.png)
> 支付模組對外提供Dubbo服務,其餘服務採用Feign進行通訊,使用者模組示例中未涉及相關業務呼叫。
> Dubbo 2.6.x 和 Dubbo 2.7.x 除了依賴不一樣,其餘配置項基本一樣,這邊就不再單獨進行區分說明,詳情請查閱本文文末專案原始碼,有進行區分說明。
## Nacos服務
Nacos服務端部署請查閱[《SpringCloud系列之Nacos應用篇》](https://www.cnblogs.com/chinaWu/p/13575813.html)
## Seata服務
進入Seata配置目錄下,編輯registry.conf配置檔案,將registry配置項中type配置項配置成"nacos",並配置nacos相關配置,具體如下
```bash
registry {
# file 、nacos 、eureka、redis、zk、consul、etcd3、sofa
type = "nacos"
nacos {
application = "seata-server"
serverAddr = "127.0.0.1:8848"
group = "SEATA_GROUP"
namespace = "public"
cluster = "default"
username = ""
password = ""
}
}
```
配置完registry配置項後將config配置項也配置成“nacos”,具體如下
```bash
config {
# file、nacos 、apollo、zk、consul、etcd3
type = "nacos"
nacos {
serverAddr = "127.0.0.1:8848"
namespace = "public"
group = "SEATA_GROUP"
username = ""
password = ""
}
}
```
調整完後啟動Seata服務即可在Nacos後臺看到已註冊的服務,如下圖
![](https://img2020.cnblogs.com/blog/451497/202009/451497-20200915095241072-739739758.png)
## 訂單模組
其餘模組本次未進行任何調整,只在訂單模組中增加Dubbo相關配置
部分pom.xml如下,完整資訊請查閱本文文末專案原始碼
pom.xml
```bash
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-discovery
com.alibaba.nacos
nacos-client
com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-config
com.alibaba.nacos
nacos-client
com.alibaba.boot
dubbo-spring-boot-starter
0.2.1.RELEASE
com.alibaba
dubbo
2.6.9
com.alibaba
dubbo-registry-nacos
2.6.7
com.alibaba.nacos
nacos-client
com.alibaba.nacos
nacos-client
1.3.2
io.netty
netty-all
4.1.31.Final
com.alibaba.cloud
spring-cloud-alibaba-seata
2.2.0.RELEASE
io.seata
seata-spring-boot-starter
io.seata
seata-spring-boot-starter
1.3.0
```
application.properties
```bash
dubbo.application.name=order-service
# dubbo掃描包路徑
dubbo.scan.base-packages=com.chinawu.cloud.order.service
# dubbo協議
dubbo.protocol.name=dubbo
# 隨機埠
dubbo.protocol.port=-1
# zookeeper地址
dubbo.registry.address=nacos://127.0.0.1:8848
spring.main.allow-bean-definition-overriding=true
```
OrderService.java
```java
@RestController
public class OrderService implements OrderFacade {
@Autowired
private TbOrderMapper tbOrderMapper;
@Autowired
private CartFacade cartFacade;
@Autowired
private GoodsFacade goodsFacade;
@Autowired
private WalletFacade walletFacade;
// Dubbo服務消費
@Reference(check = false)
DPayFacade dPayFacade;
/**
*
com.alibaba.cloud
spring-cloud-alibaba-seata
2.2.0.RELEASE
io.seata
seata-spring-boot-starter
io.seata
seata-spring-boot-starter
1.3.0
```
application.properties
```bash
# seata配置
seata.enabled=true
#seata.excludes-for-auto-proxying=firstClassNameForExclude,secondClassNameForExclude
seata.application-id=pay-service
# 事務分組名
seata.tx-service-group=pay-service_tx_group
# 預設開啟資料來源自動代理
seata.enable-auto-data-source-proxy=true
seata.use-jdk-proxy=false
seata.config.type=nacos
seata.registry.type=nacos
seata.registry.nacos.server-addr=127.0.0.1:8848
```
DPayService.java
```java
@Service
public class DPayService implements DPayFacade {
@Autowired
TbPayMapper tbPayMapper;
@Override
public String goToPay(String userName) {
String xid = RootContext.getXID();
System.out.println("pay.seata.xid:"+xid);
System.out.println("dubbo.method:goToPay request "+userName);
TbPay pay = new TbPay();
pay.setMoney(new BigDecimal("5"));
pay.setStatus(Byte.valueOf("1"));
tbPayMapper.insert(pay);
return "dubbo.method:goToPay result:" + userName + " pay success";
}
}
```
調整完啟動支付模組後,啟動過程中發現一行報錯日誌,資訊如下
no available service 'null' found, please make sure registry config correct
其餘正常,但心裡還是有點擔憂,其他服務模組啟動後試一下再說
http://localhost:9100/order/add?cartId=1
請求後果然在支付模組報如下錯誤
Caused by: io.seata.core.exception.RmTransactionException: Runtime
Caused by: io.seata.common.exception.FrameworkException: No available service
看資訊應該是缺少服務,後來經過一點點排查後,最終確認是這一行配置項導致,將
seata.config.type=nacos調整至file時並把這行配置項開啟即可(用nacos時其餘seata配置項都註釋掉了)
```bash
seata.service.vgroup-mapping.pay-service_tx_group=default
```
先了解下該行配置項主要作用,原來是靠此配置項用於查詢TC服務的。
![](https://img2020.cnblogs.com/blog/451497/202009/451497-20200915095408591-867785736.png)
那是不是隻要新增這行配置就可以了呢,重新將seata配置資訊調整至“nacos”,根據命名規則嘗試建立以下配置項
![](https://img2020.cnblogs.com/blog/451497/202009/451497-20200915095430598-62067297.png)
配置建立成功後,在支付模組後臺立馬看到有日誌輸出
```bash
2020-09-14 15:58:43.284 ERROR 28292 --- [eoutChecker_2_1] i.s.c.r.netty.NettyClientChannelManager : no available service 'null' found, please make sure registry config correct
2020-09-14 15:58:53.252 ERROR 28292 --- [eoutChecker_1_1] i.s.c.r.netty.NettyClientChannelManager : no available service 'null' found, please make sure registry config correct
2020-09-14 15:58:53.285 ERROR 28292 --- [eoutChecker_2_1] i.s.c.r.netty.NettyClientChannelManager : no available service 'null' found, please make sure registry config correct
2020-09-14 15:59:02.853 INFO 28292 --- [-localhost_8848] c.a.n.client.config.impl.ClientWorker : [fixed-localhost_8848] [polling-resp] config changed. dataId=service.vgroupMapping.pay-service_tx_group, group=SEATA_GROUP
2020-09-14 15:59:02.853 INFO 28292 --- [-localhost_8848] c.a.n.client.config.impl.ClientWorker : get changedGroupKeys:[service.vgroupMapping.pay-service_tx_group+SEATA_GROUP]
2020-09-14 15:59:02.857 INFO 28292 --- [-localhost_8848] c.a.n.client.config.impl.ClientWorker : [fixed-localhost_8848] [data-received] dataId=service.vgroupMapping.pay-service_tx_group, group=SEATA_GROUP, tenant=null, md5=c21f969b5f03d33d43e04f8f136e7682, content=default, type=text
2020-09-14 15:59:02.857 INFO 28292 --- [-localhost_8848] c.a.nacos.client.config.impl.CacheData : [fixed-localhost_8848] [notify-context] dataId=service.vgroupMapping.pay-service_tx_group, group=SEATA_GROUP, md5=c21f969b5f03d33d43e04f8f136e7682
2020-09-14 15:59:02.858 INFO 28292 --- [-localhost_8848] c.a.nacos.client.config.impl.CacheData : [fixed-localhost_8848] [notify-ok] dataId=service.vgroupMapping.pay-service_tx_group, group=SEATA_GROUP, md5=c21f969b5f03d33d43e04f8f136e7682, listener=io.seata.config.nacos.NacosConfiguration$NacosListener@37dd83b6
2020-09-14 15:59:02.858 INFO 28292 --- [-localhost_8848] c.a.nacos.client.config.impl.CacheData : [fixed-localhost_8848] [notify-listener] time cost=1ms in ClientWorker, dataId=service.vgroupMapping.pay-service_tx_group, group=SEATA_GROUP, md5=c21f969b5f03d33d43e04f8f136e7682, listener=io.seata.config.nacos.NacosConfiguration$NacosListener@37dd83b6
2020-09-14 15:59:03.253 INFO 28292 --- [eoutChecker_1_1] com.alibaba.nacos.client.naming : new ips(1) service: SEATA_GROUP@@seata-server@@default -> [{"instanceId":"192.168.2.241#8091#default#SEATA_GROUP@@seata-server","ip":"192.168.2.241","port":8091,"weight":1.0,"healthy":true,"enabled":true,"ephemeral":true,"clusterName":"default","serviceName":"SEATA_GROUP@@seata-server","metadata":{},"ipDeleteTimeout":30000,"instanceHeartBeatInterval":5000,"instanceIdGenerator":"simple","instanceHeartBeatTimeOut":15000}]
2020-09-14 15:59:03.254 INFO 28292 --- [eoutChecker_1_1] com.alibaba.nacos.client.naming : current ips:(1) service: SEATA_GROUP@@seata-server@@default -> [{"instanceId":"192.168.2.241#8091#default#SEATA_GROUP@@seata-server","ip":"192.168.2.241","port":8091,"weight":1.0,"healthy":true,"enabled":true,"ephemeral":true,"clusterName":"default","serviceName":"SEATA_GROUP@@seata-server","metadata":{},"ipDeleteTimeout":30000,"instanceHeartBeatInterval":5000,"instanceIdGenerator":"simple","instanceHeartBeatTimeOut":15000}]
2020-09-14 15:59:03.254 INFO 28292 --- [eoutChecker_1_1] com.alibaba.nacos.client.naming : [LISTENER] adding SEATA_GROUP@@seata-server with default to listener map
2020-09-14 15:59:03.256 INFO 28292 --- [eoutChecker_1_1] i.s.c.r.netty.NettyClientChannelManager : will connect to 192.168.2.241:8091
2020-09-14 15:59:03.258 INFO 28292 --- [eoutChecker_1_1] i.s.core.rpc.netty.NettyPoolableFactory : NettyPool create channel to transactionRole:TMROLE,address:192.168.2.241:8091,msg:< RegisterTMRequest{applicationId='pay-service', transactionServiceGroup='pay-service_tx_group'} >
2020-09-14 15:59:03.281 INFO 28292 --- [eoutChecker_2_1] i.s.c.r.netty.NettyClientChannelManager : will connect to 192.168.2.241:8091
2020-09-14 15:59:03.281 INFO 28292 --- [eoutChecker_2_1] i.s.c.rpc.netty.RmNettyRemotingClient : RM will register :jdbc:mysql://127.0.0.1:3306/spring-cloud
2020-09-14 15:59:03.283 INFO 28292 --- [eoutChecker_2_1] i.s.core.rpc.netty.NettyPoolableFactory : NettyPool create channel to transactionRole:RMROLE,address:192.168.2.241:8091,msg:< RegisterRMRequest{resourceIds='jdbc:mysql://127.0.0.1:3306/spring-cloud', applicationId='pay-service', transactionServiceGroup='pay-service_tx_group'} >
2020-09-14 15:59:03.305 INFO 28292 --- [eoutChecker_2_1] i.s.c.rpc.netty.RmNettyRemotingClient : register RM success. client version:1.3.0, server version:1.3.0,channel:[id: 0x15ef339d, L:/192.168.2.241:64550 - R:/192.168.2.241:8091]
2020-09-14 15:59:03.305 INFO 28292 --- [eoutChecker_1_1] i.s.c.rpc.netty.TmNettyRemotingClient : register TM success. client version:1.3.0, server version:1.3.0,channel:[id: 0xd4e407be, L:/192.168.2.241:64548 - R:/192.168.2.241:8091]
2020-09-14 15:59:03.313 INFO 28292 --- [eoutChecker_1_1] i.s.core.rpc.netty.NettyPoolableFactory : register success, cost 39 ms, version:1.3.0,role:TMROLE,channel:[id: 0xd4e407be, L:/192.168.2.241:64548 - R:/192.168.2.241:8091]
2020-09-14 15:59:03.313 INFO 28292 --- [eoutChecker_2_1] i.s.core.rpc.netty.NettyPoolableFactory : register success, cost 26 ms, version:1.3.0,role:RMROLE,channel:[id: 0x15ef339d, L:/192.168.2.241:64550 - R:/192.168.2.241:8091]
```
感覺有戲,再次請求介面,果然不再報錯,提示事務回滾成功,其餘模組也提示回滾成功,另外資料也正常,至此就可以使用啦。
```bash
pay.seata.xid:192.168.2.241:8091:48803259719028736
dubbo.method:goToPay request wuyubin
2020-09-14 16:06:44.006 INFO 28292 --- [ch_RMROLE_1_1_8] i.s.c.r.p.c.RmBranchRollbackProcessor : rm handle branch rollback process:xid=192.168.2.241:8091:48803259719028736,branchId=48803260146847744,branchType=AT,resourceId=jdbc:mysql://127.0.0.1:3306/spring-cloud,applicationData=null
2020-09-14 16:06:44.010 INFO 28292 --- [ch_RMROLE_1_1_8] io.seata.rm.AbstractRMHandler : Branch Rollbacking: 192.168.2.241:8091:48803259719028736 48803260146847744 jdbc:mysql://127.0.0.1:3306/spring-cloud
2020-09-14 16:06:44.061 INFO 28292 --- [ch_RMROLE_1_1_8] i.s.r.d.undo.AbstractUndoLogManager : xid 192.168.2.241:8091:48803259719028736 branch 48803260146847744, undo_log deleted with GlobalFinished
2020-09-14 16:06:44.063 INFO 28292 --- [ch_RMROLE_1_1_8] io.seata.rm.AbstractRMHandler : Branch Rollbacked result: PhaseTwo_Rollbacked
```
# 參考資料
[Seata事務分組專題](https://seata.io/zh-cn/docs/user/transaction-group.html)
[原始碼分析Seata-XID傳遞 Dubbo篇](https://seata.io/zh-cn/blog/seata-analysis-dubbo-transmit-xid.html)
# 系列文章
[SpringCloud系列之配置中心(Config)使用說明](https://www.cnblogs.com/chinaWu/p/12547992.html)
[SpringCloud系列之服務註冊發現(Eureka)應用篇](https://www.cnblogs.com/chinaWu/p/12589066.html)
[SpringCloud系列之閘道器(Gateway)應用篇](https://www.cnblogs.com/chinaWu/p/12731796.html)
[SpringCloud系列之整合Dubbo應用篇](https://www.cnblogs.com/chinaWu/p/12818661.html)
[SpringCloud系列之整合分散式事務Seata應用篇](https://www.cnblogs.com/chinaWu/p/13255200.html)
[SpringCloud系列之Nacos應用篇](https://www.cnblogs.com/chinaWu/p/13575813.html)
[SpringCloud系列之Nacos+Dubbo應用篇](https://www.cnblogs.com/chinaWu/p/13613518.html)
[專案原始碼](https://gitee.com/wuyubin/SpringCloudDemo)
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200419143136144.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3d5YjM4Nzk0NjcxNQ==,size_16,color_FFFFFF,t_70#pic_
* 功能:新增訂單 *
* @param cartId 購物車ID * @author wuyubin * @date 2020年05月22日 * @return */ @Override public void addOrder(Long cartId) { CartDTO cart = cartFacade.getCartById(cartId); TbOrder order = new TbOrder(); order.setUserId(cart.getUserId()); order.setGoodsId(cart.getGoodsId()); order.setOrderNo(String.valueOf(System.currentTimeMillis())); order.setCreateTime(System.currentTimeMillis()); order.setUpdateTime(order.getCreateTime()); order.setIsDeleted(Byte.valueOf("0")); // 新增訂單 tbOrderMapper.insert(order); // 刪除購物車(Feign) cartFacade.deleteCartById(cartId); GoodsDTO goods = goodsFacade.getByGoodsId(cart.getGoodsId()); // 扣減庫存(Feign) goodsFacade.substractStock(goods.getId()); // 扣減金額(Feign) walletFacade.substractMoney(cart.getUserId(),goods.getMoney()); // 記錄支付訊息(Dubbo呼叫) dPayFacade.goToPay("wuyubin"); throw new RuntimeException(); } } ``` > 新增引用支付模組Dubbo服務,dPayFacade.goToPay("wuyubin"); ## 支付模組 支付模組在原先基礎上增加Seata依賴,部分pom資訊如下 pom.xml ```bash