集群节点下,分布式事务回调用,会路由到非发起方机器上去
Closed this issue · 4 comments
其实之前就提过,还在issue 下做了讨论
管理员给的方案,不起作用,我也看了源码,建议在transactionUnit 上加入remoteKey ,回调的时候过滤,来解决(本地改了源码,可以解决)
管理员282票的回答,的确不管用。
我的简单改法是这样的:
2步。
第一步:
文件:com.codingapi.txlcn.tm.txmsg.transaction.InitClientService.java
bindAppName的第二个参数,不要传initClientParams.getAppName(),传initClientParams.getLabelName()。 LabelName是唯一的,AppName在集群下多个微服务都是一样的。
try {
rpcClient.bindAppName(transactionCmd.getRemoteKey(), initClientParams.getLabelName(), initClientParams.getLabelName());
} catch (RpcException e) {
throw new TxManagerException(e);
}
剩下的一步:在TC端,implement ModIdProvider确保每个tc都有唯一识别id即可。
更加完整优雅的解决办法,我本地测试通过了。供参考:
1、JoinGroupExecuteService.java
把rpcClient.getAppName改成rpcClient.getModId
transactionManager.join(dtxContext, joinGroupParams.getUnitId(), joinGroupParams.getUnitType(),
rpcClient.getModId(transactionCmd.getRemoteKey()), joinGroupParams.getTransactionState());
2、NettyRpcClient.java
添加getModId
@Override
public String getModId(String remoteKey) {
return SocketManager.getInstance().getModuleId(remoteKey);
}
3、SockeManager.java
1)增加getModuleId方法
/**
* 获取模块的唯一ID
*
* @param remoteKey 远程唯一标识
* @return 模块名称
*/
public String getModuleId(String remoteKey) {
AppInfo appInfo = appNames.get(remoteKey);
return appInfo == null ? null : appInfo.getLabelName();
}
2)修改remoteKeys,根据modId取remoteKeys
/**
* 获取模块的远程标识keys
*
* @param modId 模块唯一识别Id
* @return remoteKeys
*/
public List<String> remoteKeys(String modId) {
List<String> allKeys = new ArrayList<>();
for (Channel channel : channels) {
if (modId.equals(getModuleIdFromChannel(channel))) {
allKeys.add(channel.remoteAddress().toString());
}
}
return allKeys;
}
3)新增getModuleIdFromChannel
/**
* 获取模块名称
*
* @param channel 管道信息
* @return 模块名称
*/
public String getModuleIdFromChannel(Channel channel) {
String key = channel.remoteAddress().toString();
return getModuleId(key);
}
4、在TC端,implement ModIdProvider确保每个tc都有唯一识别id即可。
@Component
public class MyModIdProvider implements ModIdProvider {
@Autowired
private ServerConfig serverConfig;
public String getSeverID() {
return serverConfig.getServerID();
}
@Override
public String modId(){
return getSeverID();
}
}
@Component
public class ServerConfig implements ApplicationListener<WebServerInitializedEvent> {
private int serverPort;
public String getServerID() {
InetAddress address = null;
try {
address = InetAddress.getLocalHost();
} catch (UnknownHostException e) {
e.printStackTrace();
}
return "http://"+address.getHostAddress() + ":" + this.serverPort;
}
@Override
public void onApplicationEvent(WebServerInitializedEvent event) {
this.serverPort = event.getWebServer().getPort();
}
}
@freemindcore 我按你的方法测试了下,是可以的,第一种有点难看。 第二种也是可以的
哦,谢谢!这里确实需要用LabelName来区分模块