TM端启动记录
TM启动流程
TM启动初始化,执行下面的TxLcnInitializer类实现,并且调用初始化方法:
TMRpcServer
TMRpcServer的init方法,这个方法主要是调用rpcServerInitializer的init方法:
@Override
public void init() {
// 1. 配置
if (rpcConfig.getWaitTime() <= 5) {
rpcConfig.setWaitTime(1000);
}
if (rpcConfig.getAttrDelayTime() < 0) {
rpcConfig.setAttrDelayTime(txManagerConfig.getDtxTime());
}
// 2. 初始化RPC Server
ManagerProperties managerProperties = new ManagerProperties();
managerProperties.setCheckTime(txManagerConfig.getHeartTime());
// 默认127.0.0.1
managerProperties.setRpcPort(txManagerConfig.getPort());
// 默认8070 因为application.properties中server.port=7970
managerProperties.setRpcHost(txManagerConfig.getHost());
rpcServerInitializer.init(managerProperties);
}
上面的txManagerConfig.getPort()是由application.properties中server.port + 100 取得,代码如下:
@Autowired
public TxManagerConfig(ServerProperties serverProperties) {
this.port = Objects.requireNonNull(serverProperties.getPort(), "TM http port not configured?") +
PORT_CHANGE_VALUE;
}
再重新回过头看一下rpcServerInitializer的init方法,启动netty server端,监听ip:8070端口默认。代码如下:
@Override
public void init(ManagerProperties managerProperties) {
NettyContext.type = NettyType.server;
NettyContext.params = managerProperties;
nettyRpcServerChannelInitializer.setManagerProperties(managerProperties);
int port = managerProperties.getRpcPort();
bossGroup = new NioEventLoopGroup();
workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 100)
.handler(new LoggingHandler(LogLevel.INFO))
// netty server的handler 主要处理逻辑在这里
.childHandler(nettyRpcServerChannelInitializer);
// 启动netty server监听.
if (StringUtils.hasText(managerProperties.getRpcHost())) {
b.bind(managerProperties.getRpcHost(), managerProperties.getRpcPort());
} else {
b.bind(port);
}
log.info("Socket started on {}:{} ",
StringUtils.hasText(managerProperties.getRpcHost()) ? managerProperties.getRpcHost() : "0.0.0.0", port);
} catch (Exception e) {
// Shut down all event loops to terminate all threads.
e.printStackTrace();
}
}
学习一下ChannelInitializer:
https://www.cnblogs.com/stevenczp/p/7597903.html
https://www.jianshu.com/p/7ae37f4c1f14
接下来看一下NettyRpcServerChannelInitializer类:
@Component
public class NettyRpcServerChannelInitializer extends ChannelInitializer<Channel> {
@Autowired
private RpcAnswerHandler rpcAnswerHandler;
@Autowired
private SocketManagerInitHandler socketManagerInitHandler;
@Autowired
private RpcCmdDecoder rpcCmdDecoder;
private ManagerProperties managerProperties;
public void setManagerProperties(ManagerProperties managerProperties) {
this.managerProperties = managerProperties;
}
@Override
protected void initChannel(Channel ch) throws Exception {
// 解决半包 黏包问题
ch.pipeline().addLast(new LengthFieldPrepender(4, false));
ch.pipeline().addLast(new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE, 0, 4, 0, 4));
// 心跳监控
ch.pipeline().addLast(new IdleStateHandler(managerProperties.getCheckTime(),
managerProperties.getCheckTime(), managerProperties.getCheckTime(), TimeUnit.MILLISECONDS));
// 序列化对象编解码
ch.pipeline().addLast(new ObjectSerializerEncoder());
ch.pipeline().addLast(new ObjectSerializerDecoder());
// TM实现的ChannelHandler
ch.pipeline().addLast(rpcCmdDecoder);
ch.pipeline().addLast(new RpcCmdEncoder());
ch.pipeline().addLast(socketManagerInitHandler);
ch.pipeline().addLast(rpcAnswerHandler);
}
}
TMAutoCluster
@Override
public void init() throws Exception {
// 1. 通知 TC 建立连接
List<TMProperties> tmList = fastStorage.findTMProperties().stream()
.filter(tmProperties ->
!tmProperties.getHost().equals(txManagerConfig.getHost()) || !tmProperties.getTransactionPort().equals(txManagerConfig.getPort()))
.collect(Collectors.toList());
for (TMProperties properties : tmList) {
// 封装NotifyConnectParams 把自己的ip和port设置进去,传给已存在TM节点处理
NotifyConnectParams notifyConnectParams = new NotifyConnectParams();
notifyConnectParams.setHost(txManagerConfig.getHost());
notifyConnectParams.setPort(txManagerConfig.getPort());
String url = String.format(MANAGER_REFRESH_URL, properties.getHost(), properties.getHttpPort());
try {
ResponseEntity<Boolean> res = restTemplate.postForEntity(url, notifyConnectParams, Boolean.class);
if (res.getStatusCode().equals(HttpStatus.OK) || res.getStatusCode().is5xxServerError()) {
log.info("manager auto refresh res->{}", res);
break;
} else {
fastStorage.removeTMProperties(properties.getHost(), properties.getTransactionPort());
}
} catch (Exception e) {
log.error("manager auto refresh error: {}", e.getMessage());
//check exception then remove.
if (e instanceof ResourceAccessException) {
ResourceAccessException resourceAccessException = (ResourceAccessException) e;
if (resourceAccessException.getCause() != null && resourceAccessException.getCause() instanceof ConnectException) {
//can't access .
fastStorage.removeTMProperties(properties.getHost(), properties.getTransactionPort());
}
}
}
}
// 2. 保存TM 到快速存储
if (StringUtils.hasText(txManagerConfig.getHost())) {
TMProperties tmProperties = new TMProperties();
tmProperties.setHttpPort(ApplicationInformation.serverPort(serverProperties));
tmProperties.setHost(txManagerConfig.getHost());
tmProperties.setTransactionPort(txManagerConfig.getPort());
fastStorage.saveTMProperties(tmProperties);
}
}
当前TM(A服务)启动成功,通过redis缓存TMProperties信息快照,当下一个TM节点(B服务)启动的时候,就会循环存储的TM配置快照信息(A服务)发送(B服务的连接信息)让A服务通知已经与之相连TC端Channel与B服务进行连接,达到了如果新增TM节点,无需重新配置TM的连接信息,重新启动。通过RestTemplate http调用,拼接url=http://%s:%s/manager/refresh,我们查看一下这个rest接口代码:
@RestController
@RequestMapping("/manager")
public class TxManagerController {
@Autowired
private ManagerService managerService;
@PostMapping("/refresh")
public boolean refresh(@RequestBody NotifyConnectParams notifyConnectParams) throws RpcException {
return managerService.refresh(notifyConnectParams);
}
}
// service方法
@Override
public boolean refresh(NotifyConnectParams notifyConnectParams) throws RpcException {
List<String> keys = rpcClient.loadAllRemoteKey();
if (keys != null && keys.size() > 0) {
for (String key : keys) {
// 通知所有与之连接的Tc端连接新TM节点
rpcClient.send(key, MessageCreator.newTxManager(notifyConnectParams));
}
}
return true;
}
@Override
public RpcResponseState send(String remoteKey, MessageDto msg) throws RpcException {
RpcCmd rpcCmd = new NettyRpcCmd();
rpcCmd.setMsg(msg);
rpcCmd.setRemoteKey(remoteKey);
return send(rpcCmd);
}
@Override
public RpcResponseState send(RpcCmd rpcCmd) throws RpcException {
return SocketManager.getInstance().send(rpcCmd.getRemoteKey(), rpcCmd);
}
待完善…