不灭的焱

革命尚未成功,同志仍须努力

作者:php-note.com  发布于:2018-11-04 19:35  分类:Java  编辑

注册中心的实现方式有很多种,实现的方式也有难有易,可以使用zookeeper,consul这些第三方已有的包去帮助实现,这样可以减少开发注册中心的难度,却可能加大运维的难度,当然最最原始的方法就是使用java去实现,不借助其他任何已有的第三方包去搞定,这样做的好处其实并不明显,不过对于开发者而言,使用这种最原始的方式最大的好处就是自己知道所有的实现细节,遇到问题,遇到bug,可以很快的定位到问题所在

 

本Demo RPC因为是练习,所以没有实现zookeeper的方法,以后有机会会补上,cosul我没有接触过,现在基于java的内存的方式去完成该功能

 

与服务提供者一样,注册中心的基本结构也很清晰:

在maven多项目的管理的角度上来说,laopopo-registry中只是很简单的定义了一个RegistryServer.java的类,因为我没有仔细调用过每个方式的实现细节,所以这个接口定义的也是比较简单:

 

package org.laopopo.registry;

/**
 * 
 * @author BazingaLyn
 * @description 注册中心
 * @time
 * @modifytime
 */
public interface RegistryServer {
	
	void start();

}

 

只是简单的定义了一个启动方法,我们看看其基于java内存的实现结构DefaultRegistryServer.java,我们截图说明一下:

 

 

 

这是默认的注册中心的定义截图,维护了一个NettyServer的客户端,维护了一个服务消费者的管理者ConsumerManager,维护了一个服务提供者的管理者ProviderManager,还有几个线程执行器,每个类各司其职,当然他们之间还有相互协作的过程。从整体上来看,注册中心的整体结构就是这样,下面给出具体的代码:

 

package org.laopopo.base.registry;

import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.laopopo.base.registry.model.RegistryPersistRecord;
import org.laopopo.common.utils.NamedThreadFactory;
import org.laopopo.common.utils.PersistUtils;
import org.laopopo.registry.RegistryServer;
import org.laopopo.remoting.netty.NettyRemotingServer;
import org.laopopo.remoting.netty.NettyServerConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSON;

/**
 * #######注册中心######
 * 
 * 可以有多个注册中心,所有的注册中心之前不进行通讯,都是无状态的
 * 1)provider端与每一个注册中心之间保持长连接,保持重连
 * 2)consumer随机选择一个注册中心保持长连接,如果断了,不去主动重连,选择其他可用的注册中心
 * 
 * @author BazingaLyn
 * @description 默认的注册中心,处理注册端的所有事宜:
 * 1)处理consumer端发送过来的注册信息
 * 2)处理provider端发送过来的订阅信息
 * 3)当服务下线需要通知对应的consumer变更后的注册信息
 * 4)所有的注册订阅信息的储存和健康检查
 * 5)接收管理者的一些信息请求,比如 服务统计 | 某个实例的服务降级 | 通知消费者的访问策略  | 改变某个服务实例的比重
 * 6)将管理者对服务的一些信息 例如审核结果,负载算法等信息持久化到硬盘
 * @time 2016年8月15日
 * @modifytime
 */
public class DefaultRegistryServer implements RegistryServer {
	
	private static final Logger logger = LoggerFactory.getLogger(DefaultRegistryServer.class);
	
	
    private final NettyServerConfig nettyServerConfig;       //netty Server的一些配置文件
    private RegistryServerConfig registryServerConfig;       //注册中心的配置文件
	private NettyRemotingServer remotingServer;  	         //注册中心的netty server端
	private RegistryConsumerManager consumerManager;         //注册中心消费侧的管理逻辑控制类
	private RegistryProviderManager providerManager;         //注册中心服务提供者的管理逻辑控制类
	private ExecutorService remotingExecutor;                //执行器
	private ExecutorService remotingChannelInactiveExecutor; //channel inactive的线程执行器
	
	//定时任务
    private final ScheduledExecutorService scheduledExecutorService = Executors
    		.newSingleThreadScheduledExecutor(new NamedThreadFactory("registry-timer"));
	
    /**
     * 
     * @param nettyServerConfig 注册中心的netty的配置文件 至少需要配置listenPort
     * @param nettyClientConfig 注册中心连接Monitor端的netty配置文件,至少需要配置defaultAddress值 这边monitor是单实例,所以address一个就好
     */
    public DefaultRegistryServer(NettyServerConfig nettyServerConfig,RegistryServerConfig registryServerConfig) {
    	this.nettyServerConfig = nettyServerConfig;
    	this.registryServerConfig = registryServerConfig;
    	consumerManager = new RegistryConsumerManager(this);
    	providerManager = new RegistryProviderManager(this);
    	initialize();
	}

	private void initialize() {
		
		 this.remotingServer = new NettyRemotingServer(this.nettyServerConfig);
		 
		 this.remotingExecutor =
	                Executors.newFixedThreadPool(nettyServerConfig.getServerWorkerThreads(), new NamedThreadFactory("RegistryCenterExecutorThread_"));
		 
		 this.remotingChannelInactiveExecutor =
	                Executors.newFixedThreadPool(nettyServerConfig.getChannelInactiveHandlerThreads(), new NamedThreadFactory("RegistryCenterChannelInActiveExecutorThread_"));
		 
		 //注册处理器
		 this.registerProcessor();
		 
		 //从硬盘上恢复一些服务的信息
		 this.recoverServiceInfoFromDisk();
		 
		 this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {

				@Override
				public void run() {
					// 延迟60秒,每隔60秒开始 定时向consumer发送消费者消费失败的信息
					try {
						DefaultRegistryServer.this.getConsumerManager().checkSendFailedMessage();
					} catch (Exception e) {
						logger.warn("schedule publish failed [{}]",e.getMessage());
					} 
				}
		}, 60, 60, TimeUnit.SECONDS);
		 
		 this.scheduledExecutorService.scheduleAtFixedRate(new Runnable() {

				@Override
				public void run() {
					// 延迟60秒,每隔一段时间将一些服务信息持久化到硬盘上
					try {
						DefaultRegistryServer.this.getProviderManager().persistServiceInfo();
					} catch (Exception e) {
						logger.warn("schedule persist failed [{}]",e.getMessage());
					} 
				}
		}, 60, this.registryServerConfig.getPersistTime(), TimeUnit.SECONDS);
	}

	/**
	 * 从硬盘上恢复一些服务的审核负载算法的信息
	 */
	private void recoverServiceInfoFromDisk() {
		
		String persistString = PersistUtils.file2String(this.registryServerConfig.getStorePathRootDir());
		
		if (null != persistString) {
			List<RegistryPersistRecord> registryPersistRecords = JSON.parseArray(persistString.trim(), RegistryPersistRecord.class);
			
			if (null != registryPersistRecords) {
				for (RegistryPersistRecord metricsReporter : registryPersistRecords) {
					
				     String serviceName = metricsReporter.getServiceName();
				     this.getProviderManager().getHistoryRecords().put(serviceName, metricsReporter);
				     
				}
			}
		}
		
	}

	private void registerProcessor() {
		this.remotingServer.registerDefaultProcessor(new DefaultRegistryProcessor(this), this.remotingExecutor);
		this.remotingServer.registerChannelInactiveProcessor(new DefaultRegistryChannelInactiveProcessor(this), remotingChannelInactiveExecutor);
	}
	

	@Override
	public void start() {
		this.remotingServer.start();
	}

	public RegistryConsumerManager getConsumerManager() {
		return consumerManager;
	}

	public RegistryProviderManager getProviderManager() {
		return providerManager;
	}

	public NettyRemotingServer getRemotingServer() {
		return remotingServer;
	}

	public void setRemotingServer(NettyRemotingServer remotingServer) {
		this.remotingServer = remotingServer;
	}

	public RegistryServerConfig getRegistryServerConfig() {
		return registryServerConfig;
	}

	public void setRegistryServerConfig(RegistryServerConfig registryServerConfig) {
		this.registryServerConfig = registryServerConfig;
	}

}

 

注册中心的基本结构就是如此,详细代码可查看:

https://github.com/BazingaLyn/laopopo-rpc/tree/master/laopopo-registry-default

 

其他的具体逻辑下几个小节一起分析

 

 

摘自:https://blog.csdn.net/linuu/article/details/52755856