BUG背景
我在部署seata-server,也就是seata的服務端的時候,使用了nacos 做為注冊中心和配置中心,并使用的是docker 來部署的seata-server。如下部落格
Docker 部署 Seata Server(使用nacos 做為注冊中心和配置中心)
然後我使用spring cloud 結合使用seata來做分布式事務。但是卻出現了如下錯誤
我截取了部分日志出來,可見seata 内置netty來實作網絡通信,8091也正是seata-server的端口,根據如下日志可知我們用戶端程式連接配接不上172.17.0.4:8091
2022-02-18 17:03:07.724 ERROR 26860 --- [eoutChecker_2_1] i.s.c.r.netty.NettyClientChannelManager : 0101 can not connect to 172.17.0.4:8091 cause:can not register RM,err:can not connect to services-server.
io.seata.common.exception.FrameworkException: can not register RM,err:can not connect to services-server.
at io.seata.core.rpc.netty.NettyClientChannelManager.doConnect(NettyClientChannelManager.java:210) ~[seata-all-1.3.0.jar:1.3.0]
at io.seata.core.rpc.netty.NettyClientChannelManager.acquireChannel(NettyClientChannelManager.java:103) ~[seata-all-1.3.0.jar:1.3.0]
at io.seata.core.rpc.netty.NettyClientChannelManager.reconnect(NettyClientChannelManager.java:175) ~[seata-all-1.3.0.jar:1.3.0]
at io.seata.core.rpc.netty.AbstractNettyRemotingClient$1.run(AbstractNettyRemotingClient.java:106) [seata-all-1.3.0.jar:1.3.0]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_301]
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) [na:1.8.0_301]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_301]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) [na:1.8.0_301]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_301]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_301]
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) [netty-all-4.1.51.Final.jar:4.1.51.Final]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_301]
而這個位址172.17.0.4:8091正是seata-server的位址,如下所示,但是我們通路不到,這是為什麼
nacos 的注冊中心資訊圖
因為這個位址172.17.0.4:8091是容器seata-server的位址
容器網絡資訊
我部署的nacos-server和seata-server的網絡資訊如下
nacos-server
seata-server的網絡資訊
從上面兩張圖可以得知,這兩個容器處于同一個網絡當中。
關于docker網絡的Bridge模式
當Docker程序啟動時,會在主機上建立一個名為docker0的虛拟網橋,此主機上啟動的Docker容器會連接配接到這個虛拟網橋上。虛拟網橋的工作方式和實體交換機類似,這樣主機上的所有容器就通過交換機連在了一個二層網絡中。
從docker0子網中配置設定一個IP給容器使用,并設定docker0的IP位址為容器的預設網關。在主機上建立一對虛拟網卡veth pair裝置,Docker将veth pair裝置的一端放在新建立的容器中,并命名為eth0(容器的網卡),另一端放在主機中,以vethxxx這樣類似的名字命名,并将這個網絡裝置加入到docker0網橋中。可以通過brctl show指令檢視。
bridge模式是docker的預設網絡模式,不寫–net參數,就是bridge模式。使用docker run -p時,docker實際是在iptables做了DNAT規則,實作端口轉發功能。可以使用iptables -t nat -vnL檢視。
bridge模式如下圖所示:
是以我們跟本通路不到這個位址,一般我們通路容器服務,都是采用的端口轉發功能。容器端口和主控端的端口做了映射。我們通過通路主控端的IP:PORT來通路服務。
解決方案
那該怎麼解決這個問題,隻要nacos-server記錄的是主控端的IP和端口号就可以了。我們其他服務就能從nacos 的注冊中心拿到能通路的seata-server服務位址。
docker部署seata-server可以參考 這篇部落格
Docker 部署 Seata Server(使用nacos 做為注冊中心和配置中心)
docker run -itd --name seata-server \
-p 8091:8091 \
-e SEATA_CONFIG_NAME=file:/root/seata-config/registry \
-e SEATA_IP=主控端IP \
-v /usr/local/seata/config:/root/seata-config \
seataio/seata-server:1.3.0
重新啟動了seata-server之後
java 用戶端的seata 用戶端也成功連接配接上了seata-server,成功注冊了TM和RMTM(Transaction Manager) - 事務管理器 :定義全局事務的範圍:開始全局事務、送出或復原全局事務。
RM (Resource Manager) - 資料總管: 管理分支事務處理的資源,與TC交談以注冊分支事務和報告分支事務的狀态,并驅動分支事務送出或復原。
References:
- https://yebd1h.smartapps.cn/pages/blog/index?blogId=84570488&_swebfr=1&_swebFromHost=baiduboxapp