package com.dianping.pigeon.registry.composite; import com.dianping.pigeon.config.ConfigChangeListener; import com.dianping.pigeon.config.ConfigManager; import com.dianping.pigeon.config.ConfigManagerLoader; import com.dianping.pigeon.extension.ExtensionLoader; import com.dianping.pigeon.log.Logger; import com.dianping.pigeon.log.LoggerLoader; import com.dianping.pigeon.monitor.Monitor; import com.dianping.pigeon.monitor.MonitorLoader; import com.dianping.pigeon.registry.Registry; import com.dianping.pigeon.registry.RegistryManager; import com.dianping.pigeon.registry.config.RegistryConfig; import com.dianping.pigeon.registry.exception.RegistryException; import com.dianping.pigeon.registry.listener.RegistryEventListener; import com.dianping.pigeon.registry.util.Constants; import com.dianping.pigeon.registry.util.HeartBeatSupport; import com.google.common.collect.Lists; import org.apache.commons.lang.StringUtils; import java.util.*; /** * * Created by chenchongze on 17/4/26. */ public class MixRegistry implements Registry { private final static Logger logger = LoggerLoader.getLogger(MixRegistry.class); private final static ConfigManager configManager = ConfigManagerLoader.getConfigManager(); private final static Monitor monitor = MonitorLoader.getMonitor(); private volatile boolean inited = false; // registryName --> registry private static final Map<String, Registry> registrys = MixUtils.getRegistrys(); @Override public void init() { if (!inited) { synchronized (this) { if (!inited) { try { logger.info("mix registry prefer use mns & curator."); for (Registry registry : ExtensionLoader.getExtensionList(Registry.class)) { String registryName = registry.getName(); if (Constants.REGISTRY_MNS_NAME.equals(registryName) || Constants.REGISTRY_CURATOR_NAME.equals(registryName)) { registry.init(); if (registry.isEnable()) { registrys.put(registry.getName(), registry); } } } configManager.registerConfigChangeListener(new InnerConfigChangeListener()); inited = true; } catch (Throwable t) { logger.error("failed to init composite registry..."); throw new RuntimeException(t); } } } } } @Override public boolean isEnable() { return inited; } @Override public String getName() { return Constants.REGISTRY_MIX_NAME; } @Override public String getServiceAddress(String serviceName) throws RegistryException { return getServiceAddress(serviceName, Constants.DEFAULT_GROUP); } @Override public String getServiceAddress(String serviceName, String group) throws RegistryException { return getServiceAddress(serviceName, group, true); } @Override public String getServiceAddress(String serviceName, String group, boolean fallbackDefaultGroup) throws RegistryException { return getServiceAddress(serviceName, group, fallbackDefaultGroup, true); } @Override public String getServiceAddress(String remoteAppkey, String serviceName, String group, boolean fallbackDefaultGroup) throws RegistryException { return getServiceAddress(remoteAppkey, serviceName, group, fallbackDefaultGroup, true); } @Override public void registerService(String serviceName, String group, String serviceAddress, int weight) throws RegistryException { for (Registry registry : registrys.values()) { try { registry.registerService(serviceName, group, serviceAddress, weight); } catch (Throwable t) { logger.info("failed to register service to registry: " + registry.getName()); throw new RegistryException(t); } } } @Override public void unregisterService(String serviceName, String serviceAddress) throws RegistryException { for (Registry registry : registrys.values()) { try { registry.unregisterService(serviceName, serviceAddress); } catch (Throwable t) { logger.info("failed to unregister service to registry: " + registry.getName()); throw new RegistryException(t); } } } @Override public void unregisterService(String serviceName, String group, String serviceAddress) throws RegistryException { for (Registry registry : registrys.values()) { try { registry.unregisterService(serviceName, group, serviceAddress); } catch (Throwable t) { logger.info("failed to unregister service to registry: " + registry.getName()); throw new RegistryException(t); } } } @Override public int getServerWeight(String serverAddress) throws RegistryException { Registry _registry = registrys.get(MixUtils.getMixReadPrefer()); if (_registry != null && !Constants.REGISTRY_MIX_NAME.equals(_registry.getName())) { return _registry.getServerWeight(serverAddress); } int weight = Constants.DEFAULT_WEIGHT; Boolean serverActive = MixUtils.getMachineActives().get(serverAddress); if (Boolean.TRUE.equals(serverActive)) { weight = registrys.get(Constants.REGISTRY_MNS_NAME).getServerWeight(serverAddress); } else if (Boolean.FALSE.equals(serverActive)) { weight = registrys.get(Constants.REGISTRY_CURATOR_NAME).getServerWeight(serverAddress); } else { monitor.logEvent("PigeonReg.activeNullError", serverAddress + "#weight", ""); } return weight; } @Override public List<String> getChildren(String key) throws RegistryException { throw new RegistryException("unsupported interface in registry: " + getName()); } @Override public void setServerWeight(String serverAddress, int weight) throws RegistryException { for (Registry registry : registrys.values()) { try { registry.setServerWeight(serverAddress, weight); } catch (Throwable t) { logger.info("failed to set weight to registry: " + registry.getName()); throw new RegistryException(t); } } } @Override public String getServerApp(String serverAddress) throws RegistryException { Registry _registry = registrys.get(MixUtils.getMixReadPrefer()); if (_registry != null && !Constants.REGISTRY_MIX_NAME.equals(_registry.getName())) { return _registry.getServerApp(serverAddress); } String app = ""; Boolean serverActive = MixUtils.getMachineActives().get(serverAddress); if (Boolean.TRUE.equals(serverActive)) { app = registrys.get(Constants.REGISTRY_MNS_NAME).getServerApp(serverAddress); } else if (Boolean.FALSE.equals(serverActive)) { app = registrys.get(Constants.REGISTRY_CURATOR_NAME).getServerApp(serverAddress); } else { monitor.logEvent("PigeonReg.activeNullError", serverAddress + "#app", ""); } return app; } @Override public void setServerApp(String serverAddress, String app) { for (Registry registry : registrys.values()) { try { registry.setServerApp(serverAddress, app); } catch (Throwable t) { logger.info("failed to set app to registry: " + registry.getName()); } } } @Override public void unregisterServerApp(String serverAddress) { for (Registry registry : registrys.values()) { try { registry.unregisterServerApp(serverAddress); } catch (Throwable t) { logger.info("failed to unregister app to registry: " + registry.getName()); } } } @Override public void setServerVersion(String serverAddress, String version) { for (Registry registry : registrys.values()) { try { registry.setServerVersion(serverAddress, version); } catch (Throwable t) { logger.info("failed to set version to registry: " + registry.getName()); } } } @Override public String getServerVersion(String serverAddress) throws RegistryException { Registry _registry = registrys.get(MixUtils.getMixReadPrefer()); if (_registry != null && !Constants.REGISTRY_MIX_NAME.equals(_registry.getName())) { return _registry.getServerVersion(serverAddress); } String version = ""; Boolean serverActive = MixUtils.getMachineActives().get(serverAddress); if (Boolean.TRUE.equals(serverActive)) { version = registrys.get(Constants.REGISTRY_MNS_NAME).getServerVersion(serverAddress); } else if (Boolean.FALSE.equals(serverActive)) { version = registrys.get(Constants.REGISTRY_CURATOR_NAME).getServerVersion(serverAddress); } else { monitor.logEvent("PigeonReg.activeNullError", serverAddress + "#version", ""); } return version; } @Override public void unregisterServerVersion(String serverAddress) { for (Registry registry : registrys.values()) { try { registry.unregisterServerVersion(serverAddress); } catch (Throwable t) { logger.info("failed to unregister version to registry: " + registry.getName()); } } } @Override public String getStatistics() { String stats = ""; for (Registry registry : registrys.values()) { stats += registry.getStatistics() + ","; } return stats; } @Override public byte getServerHeartBeatSupport(String serviceAddress) throws RegistryException { Registry _registry = registrys.get(MixUtils.getMixReadPrefer()); if (_registry != null && !Constants.REGISTRY_MIX_NAME.equals(_registry.getName())) { return _registry.getServerHeartBeatSupport(serviceAddress); } byte support = HeartBeatSupport.BothSupport.getValue(); Boolean serverActive = MixUtils.getMachineActives().get(serviceAddress); if (Boolean.TRUE.equals(serverActive)) { support = registrys.get(Constants.REGISTRY_MNS_NAME).getServerHeartBeatSupport(serviceAddress); } else if (Boolean.FALSE.equals(serverActive)) { support = registrys.get(Constants.REGISTRY_CURATOR_NAME).getServerHeartBeatSupport(serviceAddress); } else { monitor.logEvent("PigeonReg.activeNullError", serviceAddress + "#heartBeatSupport", ""); } return support; } @Override public Map<String, Boolean> getServiceProtocols(String serviceAddress) throws RegistryException { Registry _registry = registrys.get(MixUtils.getMixReadPrefer()); if (_registry != null && !Constants.REGISTRY_MIX_NAME.equals(_registry.getName())) { return _registry.getServiceProtocols(serviceAddress); } Map<String, Boolean> serviceProtocols = new HashMap<>(); Boolean serverActive = MixUtils.getMachineActives().get(serviceAddress); if (Boolean.TRUE.equals(serverActive)) { serviceProtocols = registrys.get(Constants.REGISTRY_MNS_NAME).getServiceProtocols(serviceAddress); } else if (Boolean.FALSE.equals(serverActive)) { serviceProtocols = registrys.get(Constants.REGISTRY_CURATOR_NAME).getServiceProtocols(serviceAddress); } else { monitor.logEvent("PigeonReg.activeNullError", serviceAddress + "#serviceProtocols", ""); } return serviceProtocols; } @Override public boolean isSupportNewProtocol(String serviceAddress) throws RegistryException { Registry _registry = registrys.get(MixUtils.getMixReadPrefer()); if (_registry != null && !Constants.REGISTRY_MIX_NAME.equals(_registry.getName())) { return _registry.isSupportNewProtocol(serviceAddress); } boolean support = false; Boolean serverActive = MixUtils.getMachineActives().get(serviceAddress); if (Boolean.TRUE.equals(serverActive)) { support = registrys.get(Constants.REGISTRY_MNS_NAME).isSupportNewProtocol(serviceAddress); } else if (Boolean.FALSE.equals(serverActive)) { support = registrys.get(Constants.REGISTRY_CURATOR_NAME).isSupportNewProtocol(serviceAddress); } else { monitor.logEvent("PigeonReg.activeNullError", serviceAddress + "#supportNewProtocol", ""); } return support; } @Override public boolean isSupportNewProtocol(String serviceAddress, String serviceName) throws RegistryException { Registry _registry = registrys.get(MixUtils.getMixReadPrefer()); if (_registry != null && !Constants.REGISTRY_MIX_NAME.equals(_registry.getName())) { return _registry.isSupportNewProtocol(serviceAddress, serviceName); } boolean support = false; Boolean serverActive = MixUtils.getMachineActives().get(serviceAddress); if (Boolean.TRUE.equals(serverActive)) { support = registrys.get(Constants.REGISTRY_MNS_NAME).isSupportNewProtocol(serviceAddress, serviceName); } else if (Boolean.FALSE.equals(serverActive)) { support = registrys.get(Constants.REGISTRY_CURATOR_NAME).isSupportNewProtocol(serviceAddress, serviceName); } else { monitor.logEvent("PigeonReg.activeNullError", serviceAddress + ":" + serviceName + "#supportNewProtocol", ""); } return support; } @Override public void setSupportNewProtocol(String serviceAddress, String serviceName, boolean support) throws RegistryException { for (Registry registry : registrys.values()) { try { registry.setSupportNewProtocol(serviceAddress, serviceName, support); } catch (Throwable t) { logger.info("failed to set support new protocol to registry: " + registry.getName()); throw new RegistryException(t); } } } @Override public void unregisterSupportNewProtocol(String serviceAddress, String serviceName, boolean support) throws RegistryException { for (Registry registry : registrys.values()) { try { registry.unregisterSupportNewProtocol(serviceAddress, serviceName, support); } catch (Throwable t) { logger.info("failed to unregister support new protocol to registry: " + registry.getName()); throw new RegistryException(t); } } } @Override public void updateHeartBeat(String serviceAddress, Long heartBeatTimeMillis) { for (Registry registry : registrys.values()) { try { registry.updateHeartBeat(serviceAddress, heartBeatTimeMillis); } catch (Throwable t) { logger.info("failed to update heartbeat to registry: " + registry.getName()); } } } @Override public void deleteHeartBeat(String serviceAddress) { for (Registry registry : registrys.values()) { try { registry.deleteHeartBeat(serviceAddress); } catch (Throwable t) { logger.info("failed to delete heartbeat to registry: " + registry.getName()); } } } @Override public void setServerService(String serviceName, String group, String hosts) throws RegistryException { for (Registry registry : registrys.values()) { try { registry.setServerService(serviceName, group, hosts); } catch (Throwable t) { logger.info("failed to set server service to registry: " + registry.getName()); } } } @Override public void delServerService(String serviceName, String group) throws RegistryException { for (Registry registry : registrys.values()) { try { registry.delServerService(serviceName, group); } catch (Throwable t) { logger.info("failed to delete server service to registry: " + registry.getName()); } } } @Override public void setHostsWeight(String serviceName, String group, String hosts, int weight) throws RegistryException { for (Registry registry : registrys.values()) { try { registry.setHostsWeight(serviceName, group, hosts, weight); } catch (Throwable t) { logger.info("failed to set hosts weight to registry: " + registry.getName()); } } } @Override public String getServiceAddress(String remoteAppkey, String serviceName, String group, boolean fallbackDefaultGroup, boolean needListener) throws RegistryException { return registrys.get(Constants.REGISTRY_MNS_NAME).getServiceAddress(remoteAppkey, serviceName, group , fallbackDefaultGroup, needListener); } @Override public String getServiceAddress(String serviceName, String group, boolean fallbackDefaultGroup, boolean needListener) throws RegistryException { Registry _registry = registrys.get(MixUtils.getMixReadPrefer()); if (_registry != null && !Constants.REGISTRY_MIX_NAME.equals(_registry.getName())) { return _registry.getServiceAddress(serviceName, group, fallbackDefaultGroup, needListener); } String curatorAddress = ""; String mnsAddress = ""; for (Registry registry : registrys.values()) { try { if (Constants.REGISTRY_MNS_NAME.equals(registry.getName())) { mnsAddress = registry.getServiceAddress(serviceName, group, fallbackDefaultGroup, needListener); } else if (Constants.REGISTRY_CURATOR_NAME.equals(registry.getName())) { curatorAddress = registry.getServiceAddress(serviceName, group, fallbackDefaultGroup, needListener); } } catch (Throwable t) { logger.info("failed to get service address from registry: " + registry.getName()); } } Set<String> curatorAddressSet = new HashSet<>(); if (StringUtils.isNotBlank(curatorAddress)) { Collections.addAll(curatorAddressSet, curatorAddress.split(",")); } Set<String> mnsAddressSet = new HashSet<>(); if (StringUtils.isNotBlank(mnsAddress)) { Collections.addAll(mnsAddressSet, mnsAddress.split(",")); } if (mnsAddressSet.containsAll(curatorAddressSet)) { // 激活mns for (String address : mnsAddressSet) { Boolean machineActiveCache = MixUtils.getMachineActives().put(address, true); if (machineActiveCache != null && Boolean.FALSE.equals(machineActiveCache)) { // 通知machine刷新信息 RegistryManager.getInstance().getServiceWeight(address, false); RegistryEventListener.serverInfoChanged(serviceName, address); monitor.logEvent("PigeonReg.machineChange", address + "#" + Constants.REGISTRY_MNS_NAME, ""); } } Boolean serviceActiveCache = MixUtils.getServiceActives().put(serviceName, true); if (serviceActiveCache != null && Boolean.FALSE.equals(serviceActiveCache)) { monitor.logEvent("PigeonReg.serviceChange", serviceName + "#" + Constants.REGISTRY_MNS_NAME, ""); } monitor.logEvent("PigeonReg.mnsActive", serviceName, ""); return mnsAddress; } else { for (String address : curatorAddressSet) { Boolean machineActiveCache = MixUtils.getMachineActives().put(address, false); if (machineActiveCache != null && Boolean.TRUE.equals(machineActiveCache)) { // 通知machine刷新信息 RegistryManager.getInstance().getServiceWeight(address, false); RegistryEventListener.serverInfoChanged(serviceName, address); monitor.logEvent("PigeonReg.machineChange", address + "#" + Constants.REGISTRY_CURATOR_NAME, ""); } } Boolean serviceActiveCache = MixUtils.getServiceActives().put(serviceName, false); if (serviceActiveCache != null && Boolean.TRUE.equals(serviceActiveCache)) { monitor.logEvent("PigeonReg.serviceChange", serviceName + "#" + Constants.REGISTRY_CURATOR_NAME, ""); } monitor.logEvent("PigeonReg.curatorActive", serviceName, ""); return curatorAddress; } } @Override public void setConsoleAddress(String consoleAddress) { for (Registry registry : registrys.values()) { try { registry.setConsoleAddress(consoleAddress); } catch (Throwable t) { logger.info("failed to set console address from registry: " + registry.getName(), t); } } } @Override public void unregisterConsoleAddress(String consoleAddress) { for (Registry registry : registrys.values()) { try { registry.unregisterConsoleAddress(consoleAddress); } catch (Throwable t) { logger.info("failed to unregister console address from registry: " + registry.getName(), t); } } } @Override public List<String> getConsoleAddresses() { List<String> consoleAddresses = new ArrayList<>(); for (Registry registry : registrys.values()) { try { List<String> tempAddresses = registry.getConsoleAddresses(); if (tempAddresses != null && !tempAddresses.isEmpty()) { consoleAddresses.addAll(tempAddresses); } } catch (Throwable t) { logger.info("failed to get console address from registry: " + registry.getName(), t); } } return consoleAddresses; } @Override public RegistryConfig getRegistryConfig(String ip) throws RegistryException { RegistryConfig registryConfig; List<RegistryConfig> checkList = Lists.newArrayList(); for (Registry registry : registrys.values()) { try { checkList.add(registry.getRegistryConfig(ip)); } catch (Throwable t) { logger.info("failed to get registry config from registry: " + registry.getName()); } } if (checkList.size() == 0) { throw new RegistryException("failed to get registry config"); } registryConfig = checkValueConsistency(checkList, "registry config"); return registryConfig; } private <T> T checkValueConsistency(List<T> checkList, String msg) { T result = null; if (checkList.size() > 0) { result = checkList.get(0); } for (int i = 0; i < checkList.size(); i++) { T t = checkList.get(i); if (t != null && !t.equals(result)) { String errorMsg = msg + " result not same in different registries! index0: " + result + ", index" + i + ": " + t; if (configManager.getBooleanValue("pigeon.registry.check.value.consistency.exception", false)) { throw new RuntimeException(errorMsg); } if (logger.isDebugEnabled()) { logger.debug(errorMsg); } break; } } return result; } private class InnerConfigChangeListener implements ConfigChangeListener { @Override public void onKeyUpdated(String key, String value) { try { if (key.endsWith(MixUtils.KEY_MIX_MODE_READ_PREFER)) { String _mixReadPrefer = ""; switch (value) { case Constants.REGISTRY_MIX_NAME: _mixReadPrefer = Constants.REGISTRY_MIX_NAME; break; case Constants.REGISTRY_MNS_NAME: _mixReadPrefer = Constants.REGISTRY_MNS_NAME; break; case Constants.REGISTRY_CURATOR_NAME: _mixReadPrefer = Constants.REGISTRY_CURATOR_NAME; break; } if (StringUtils.isNotBlank(_mixReadPrefer) && !_mixReadPrefer.equals(MixUtils.getMixReadPrefer())) { MixUtils.setMixReadPrefer(_mixReadPrefer); RegistryEventListener.connectionReconnected(); } } } catch (Throwable t) { logger.warn("failed to handle change of key: " + key, t); } } @Override public void onKeyAdded(String key, String value) { } @Override public void onKeyRemoved(String key) { } } }