codingapi/tx-lcn

集群节点下,分布式事务回调用,会路由到非发起方机器上去

Closed this issue · 4 comments

其实之前就提过,还在issue 下做了讨论

#282

管理员给的方案,不起作用,我也看了源码,建议在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 我按你的方法测试了下,是可以的,第一种有点难看。 第二种也是可以的

ujued commented

哦,谢谢!这里确实需要用LabelName来区分模块