All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.alibaba.tmq.client.remoting.ClientRemoting Maven / Gradle / Ivy

package com.alibaba.tmq.client.remoting;

import java.lang.reflect.InvocationHandler;
import java.util.List;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.util.CollectionUtils;

import com.alibaba.tmq.client.context.ClientContext;
import com.alibaba.tmq.client.remoting.processor.ClientRequestProcessor;
import com.alibaba.tmq.client.remoting.proxy.ClientInvocationHandler;
import com.alibaba.tmq.client.remoting.timer.ClientHeartBeatTimer;
import com.alibaba.tmq.client.util.StringUtil;
import com.alibaba.tmq.common.constants.Constants;
import com.alibaba.tmq.common.context.InvocationContext;
import com.alibaba.tmq.common.domain.ConnectionKey;
import com.alibaba.tmq.common.domain.remoting.ConnectionChannel;
import com.alibaba.tmq.common.domain.result.Result;
import com.alibaba.tmq.common.exception.InitException;
import com.alibaba.tmq.common.exception.RemotingConnectException;
import com.alibaba.tmq.common.exception.RemotingSendRequestException;
import com.alibaba.tmq.common.exception.RemotingTimeoutException;
import com.alibaba.tmq.common.remoting.netty.NettyClientConfig;
import com.alibaba.tmq.common.remoting.netty.NettyRemotingClient;
import com.alibaba.tmq.common.remoting.protocol.RemotingCommand;
import com.alibaba.tmq.common.service.ServerService;
import com.alibaba.tmq.common.util.ListUtil;
import com.alibaba.tmq.common.util.RandomUtil;
import com.alibaba.tmq.common.util.TableUtil;
import io.netty.channel.Channel;

/**
 * 客户端远程通信服务
 * @author tianyao.myc
 *
 */
public class ClientRemoting extends ClientContext implements Constants {

	private static final Log logger = LogFactory.getLog(ClientRemoting.class);
	
	/** 远程通信客户端 */
	private NettyRemotingClient client = null;
	
	/** 定时调度服务 */
	private ScheduledExecutorService executorService = Executors
			.newScheduledThreadPool(1, new ThreadFactory() {
				
				int index = 0;
				
				public Thread newThread(Runnable runnable) {
					
					index ++;
					
					return new Thread(runnable, "TMQ-heart-beat-thread-" + index);
				}
				
			});
	
	/** 客户端代理调用接口 */
	private static InvocationHandler invocationHandler = new ClientInvocationHandler();
	
	public static ServerService serverService = proxyInterface(ServerService.class);
	
	/** RPC响应线程池 */
	private ThreadPoolExecutor executors = null;
	
	/** 请求队列 */
	private LinkedBlockingQueue requestQueue;
	
	/** 服务器列表缓存 */
	private volatile List cachedServerListForProducer;
	
	/** 服务器列表缓存 */
	private volatile List cachedBackupServerListForProducer;
	
	/** 服务器列表缓存 */
	private volatile List cachedServerListForConsumer;
	
	/** 服务器列表缓存 */
	private volatile List cachedBackupServerListForConsumer;
	
	private volatile boolean isolated = false;
	
	/**
	 * 初始化
	 *  InitException
	 */
	public void init() throws InitException {
		
		/** 初始化远程通信客户端 */
		initRemotingClient();
		
		/** 初始化心跳定时器 */
		initHeartBeatTimer();
		
	}
	
	/**
	 * 初始化远程通信客户端
	 *  InitException
	 */
	private void initRemotingClient() throws InitException {
		NettyClientConfig config = new NettyClientConfig();
		
		this.requestQueue = new LinkedBlockingQueue(clientConfig.getQueueSize());
		
		ClientRequestProcessor processor = new ClientRequestProcessor(this.requestQueue);
		processor.init();
		
		client = new NettyRemotingClient(config);
		
		executors = new ThreadPoolExecutor(clientConfig.getCoreRemotingThreads(), clientConfig.getMaxRemotingThreads(),
	            60 * 1000L, TimeUnit.MILLISECONDS,
	            requestQueue,
	            new ThreadFactory(){

			int index = 0;
			
			public Thread newThread(Runnable runnable) {
				index ++;
				return new Thread(runnable, "TMQ-remoting-thread-" + index);
			}
			
		});
		
		client.registerProcessor(REQUEST_CODE, processor, executors);
		
		try {
			client.start();
		} catch (Throwable e) {
			throw new InitException("[ClientRemoting]: initRemotingClient error", e);
		}
	}
	
	/**
	 * 初始化连接
	 * 向服务端所有机器建立长连接
	 *  instanceName
	 *  roleType
	 *  roleId
	 *  topic
	 *  tag
	 *  InitException
	 */
	public void initConnection(String instanceName, int roleType, String roleId, String topic, String tag) throws InitException {
		List serverList;
		List backupServerList;
		if (roleType == ROLE_TYPE_PRODUCER) {
			serverList = getServerListForProducer();
			backupServerList = getbackupServerListForProducer();
		} else {
			serverList = getServerListForConsumer();
			backupServerList = getbackupServerListForConsumer();
		}
		
		if(StringUtil.isNotBlank(clientConfig.getBackupDomainName())) {
			if(! CollectionUtils.isEmpty(backupServerList)) {
				serverList.addAll(backupServerList);
			}
		}
		
		if (clientRemoting.isIsolated()) {
			logger.warn("this machine was isolated, has no reason to init connection!!!");
			return;
		}
		
		if(ListUtil.isEmpty(serverList)) {
			logger.error("[ClientRemoting]: initConnection error, serverList is empty"
					+ ", roleType:" + roleType 
					+ ", roleId:" + roleId 
					+ ", topic:" + topic 
					+ ", tag:" + tag);
			
			throw new InitException("initConnection error, serverList is empty");
		}
		
		for(String server : serverList) {
			
			/** 连接服务器 */
			connectServer(instanceName, server, roleType, roleId, topic, tag);
		}
		
	}
	
	/**
	 * 清除连接
	 *  instanceName
	 *  roleType
	 *  roleId
	 *  topic
	 *  tag
	 *  InitException
	 */
	public void removeConnection(String instanceName, int roleType, String roleId, String topic, String tag) throws InitException {
		
		List serverList;
		List backupServerList;
		
		if (roleType == ROLE_TYPE_PRODUCER) {
			serverList = getServerListForProducer();
			backupServerList = getbackupServerListForProducer();
		} else {
			serverList = getServerListForConsumer();
			backupServerList = getbackupServerListForConsumer();
		}
		
		if(StringUtil.isNotBlank(clientConfig.getBackupDomainName())) {
			if(! CollectionUtils.isEmpty(backupServerList)) {
				serverList.addAll(backupServerList);
			}
		}
		
		if(ListUtil.isEmpty(serverList)) {
			logger.error("[ClientRemoting]: removeConnection error, serverList is empty"
					+ ", roleType:" + roleType 
					+ ", roleId:" + roleId 
					+ ", topic:" + topic 
					+ ", tag:" + tag);
			return ;
		}
		
		for(String server : serverList) {
			
			//断开服务器连接
			disconnectServer(instanceName, server, roleType, roleId, topic, tag);
		}
	}
	
	/**
	 * 连接服务器
	 *  instanceName
	 *  server
	 *  roleType
	 *  roleId
	 *  topic
	 *  tag
	 */
	public void connectServer(String instanceName, String server, int roleType, String roleId, String topic, String tag) {
		
		Result connectResult = null;
		try {
			ConnectionChannel connectionChannel = new ConnectionChannel(server, roleType, roleId);
			connectionChannel.setInstanceName(instanceName);
			InvocationContext.setConnectionChannel(connectionChannel);
			connectResult = serverService.connect(topic, tag);
		} catch (Throwable e) {
			logger.error("[ClientRemoting]: connectServer error" 
					+ ", clientConfig:" + clientConfig 
					+ ", server:" + server 
					+ ", roleType:" + roleType 
					+ ", roleId:" + roleId 
					+ ", topic:" + topic 
					+ ", tag:" + tag 
					+ ", instanceName" + instanceName, e);
		}
		
		if(connectResult != null && connectResult.getData().booleanValue()) {
			
		} else {
			logger.error("[ClientRemoting]: connectServer failed"
					+ ", clientConfig:" + clientConfig 
					+ ", server:" + server 
					+ ", roleType:" + roleType 
					+ ", roleId:" + roleId 
					+ ", topic:" + topic 
					+ ", tag:" + tag 
					+ ", connectResult:" + connectResult);
		}
	}
	
	/**
	 * 断开服务器连接
	 *  instanceName
	 *  server
	 *  roleType
	 *  roleId
	 *  topic
	 *  tag
	 */
	public void disconnectServer(String instanceName, String server, int roleType, String roleId, String topic, String tag) {
		
		Result disconnectResult = null;
		try {
			ConnectionChannel connectionChannel = new ConnectionChannel(server, roleType, roleId);
			connectionChannel.setInstanceName(instanceName);
			InvocationContext.setConnectionChannel(connectionChannel);
			disconnectResult = serverService.disconnect(new ConnectionKey(roleId, topic, tag));
		} catch (Throwable e) {
			logger.error("[ClientRemoting]: disconnectServer error" 
					+ ", clientConfig:" + clientConfig 
					+ ", server:" + server 
					+ ", roleType:" + roleType 
					+ ", roleId:" + roleId 
					+ ", topic:" + topic 
					+ ", tag:" + tag 
					+ ", instanceName" + instanceName, e);
		}
		
		if(disconnectResult != null && disconnectResult.getData().booleanValue()) {
			
		} else {
			logger.error("[ClientRemoting]: disconnectServer failed"
					+ ", clientConfig:" + clientConfig 
					+ ", server:" + server 
					+ ", roleType:" + roleType 
					+ ", roleId:" + roleId 
					+ ", topic:" + topic 
					+ ", tag:" + tag 
					+ ", disconnectResult:" + disconnectResult);
		}
	}
	
	/**
	 * 获取该消息要触发的那台Server
	 *  messageKey
	 *
	 */
	public String acquireFireServer(String messageKey) {
		
		if(StringUtil.isNotBlank(clientConfig.getBackupDomainName())) {
			
			if(ListUtil.isEmpty(this.cachedBackupServerListForProducer)) {
				return null;
			}
			return TableUtil.acquireFireServer(this.cachedBackupServerListForProducer, messageKey);
			
		}
		
		if(ListUtil.isEmpty(this.cachedServerListForProducer)) {
			return null;
		}
		return TableUtil.acquireFireServer(this.cachedServerListForProducer, messageKey);
	}
	
	/**
	 * 从ZK获取服务器列表
	 *
	 */
	public List getServerListForProducer() {
		if(null == this.cachedServerListForProducer) {
			this.cachedServerListForProducer = zookeeper.getServerListForProducer();
		}
		return this.cachedServerListForProducer;
	}
	
	public List getbackupServerListForProducer() {
		if(null == this.cachedBackupServerListForProducer) {
			this.cachedBackupServerListForProducer = zookeeper.getbackupServerListForProducer();
		}
		return this.cachedBackupServerListForProducer;
	}
	
	/**
	 * 从ZK获取服务器列表
	 *
	 */
	public List getServerListForConsumer() {
		if(null == this.cachedServerListForConsumer) {
			this.cachedServerListForConsumer = zookeeper.getServerListForConsumer();
		}
		return this.cachedServerListForConsumer;
	}
	
	public List getbackupServerListForConsumer() {
		if(null == this.cachedBackupServerListForConsumer) {
			this.cachedBackupServerListForConsumer = zookeeper.getbackupServerListForConsumer();
		}
		return this.cachedBackupServerListForConsumer;
	}
	
	/**
	 * 初始化心跳定时器
	 *  InitException
	 */
	private void initHeartBeatTimer() throws InitException {
		
		try {
			executorService.scheduleAtFixedRate(new ClientHeartBeatTimer(),
					clientConfig.getHeartBeatIntervalTime(), 
					clientConfig.getHeartBeatIntervalTime(), TimeUnit.MILLISECONDS);
		} catch (Throwable e) {
			throw new InitException("[ClientRemoting]: initHeartBeatTimer error"
					+ ", heartBeatIntervalTime:" + clientConfig.getHeartBeatIntervalTime(), e);
		}
		logger.warn("[ClientRemoting]: initHeartBeatTimer success"
				+ ", heartBeatIntervalTime:" + clientConfig.getHeartBeatIntervalTime());
	}
	
	/**
	 * 代理接口
	 *  interfaceClass
	 *
	 */
	public static  T proxyInterface(Class interfaceClass) {
		return proxyService.proxyInterface(interfaceClass, invocationHandler);
	}
	
	/**
	 * 获取连接
	 *  addr
	 *
	 *  InterruptedException
	 */
	public Channel getAndCreateChannel(final String addr) throws InterruptedException {
		return client.getAndCreateChannel(addr);
	}
	
	/**
	 * 远程方法同步调用
	 *  addr
	 *  request
	 *  timeoutMillis
	 *
	 *  InterruptedException
	 *  RemotingConnectException
	 *  RemotingSendRequestException
	 *  RemotingTimeoutException
	 */
	public RemotingCommand invokeSync(String addr, final RemotingCommand request, long timeoutMillis)
            throws InterruptedException, RemotingConnectException, RemotingSendRequestException,
            RemotingTimeoutException {
		return client.invokeSync(addr, request, timeoutMillis);
	}
	
	/**
	 * 多线程环境同一个key拿到同一个counter
	 *  key
	 *
	 */
	public AtomicLong getCounter(ConcurrentHashMap heartBeatCounter, String key) {
		AtomicLong counter = heartBeatCounter.get(key);
		if(null == counter) {
			counter = new AtomicLong(0L);
			AtomicLong existCounter = heartBeatCounter.putIfAbsent(key, counter);
			if(existCounter != null) {
				counter = existCounter;
			}
		}
		return counter;
	}

	/**
	 * 心跳计数器递增
	 *  connectionChannel
	 */
	public void increaseCounter(ConnectionChannel connectionChannel) {
		
		switch(connectionChannel.getRoleType()) {
		case ROLE_TYPE_PRODUCER:
			
			//生产者计数器递增
			
			
			break ;
		case ROLE_TYPE_CONSUMER:
			
			//消费者计数器递增
			
			
			break ;
			default:
		}
		
	}

	public void setCachedServerListForProducer(List cachedServerList) {
		this.cachedServerListForProducer = cachedServerList;
	}
	
	public void setCachedServerListForConsumer(List cachedServerList) {
		this.cachedServerListForConsumer = cachedServerList;
	}

	public void setCachedBackupServerListForProducer(List cachedBackupServerList) {
		this.cachedBackupServerListForProducer = cachedBackupServerList;
	}
	
	public void setCachedBackupServerListForConsumer(List cachedBackupServerList) {
		this.cachedBackupServerListForConsumer = cachedBackupServerList;
	}
	
	public boolean isIsolated() {
		return isolated;
	}
	
	public void setIsolated(boolean isolated) {
		this.isolated = isolated;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy