Architecture et principes de Nacos - Mécanisme d'adressage


insérez la description de l'image ici


prémisse

Nacos prend en charge le déploiement autonome et le déploiement en cluster

  • Pour le mode autonome, Nacos communique simplement avec lui-même ;
  • Pour le mode cluster, chaque membre Nacos du cluster doit communiquer entre eux.

Cela soulève donc une question, comment gérer les informations des nœuds membres Nacos dans le cluster, et c'est le mécanisme d'adressage interne de Nacos.


conception

Qu'il s'agisse du mode autonome ou du mode cluster, la différence fondamentale est de savoir si le nombre de nœuds membres Nacos est unique ou multiple

  • Il faut pouvoir percevoir le changement du nœud : si le nœud a augmenté ou diminué ;

  • Quelles sont les dernières informations actuelles sur la liste des membres ;

  • Comment gérer les informations de la liste des membres ;

  • Comment prendre en charge rapidement le nouveau et meilleur mode de gestion de la liste des membres, etc.


Recherche de membre

Compte tenu des exigences ci-dessus, une interface MemberLookup est abstraite

insérez la description de l'image ici

package com.alibaba.nacos.core.cluster;

import com.alibaba.nacos.api.exception.NacosException;

import java.util.Collection;
import java.util.Collections;
import java.util.Map;

/**
 * Member node addressing mode.
 *
 * @author <a href="mailto:[email protected]">liaochuntao</a>
 */
public interface MemberLookup {
    
    
    
    /**
     * start.
     *
     * @throws NacosException NacosException
     */
    void start() throws NacosException;
    
    /**
     * is using address server.
     *
     * @return using address server or not.
     */
    boolean useAddressServer();
    
    /**
     * Inject the ServerMemberManager property.
     *
     * @param memberManager {@link ServerMemberManager}
     */
    void injectMemberManager(ServerMemberManager memberManager);
    
    /**
     * The addressing pattern finds cluster nodes.
     *
     * @param members {@link Collection}
     */
    void afterLookup(Collection<Member> members);
    
    /**
     * Addressing mode closed.
     *
     * @throws NacosException NacosException
     */
    void destroy() throws NacosException;
    
    /**
     * Some data information about the addressing pattern.
     *
     * @return {@link Map}
     */
    default Map<String, Object> info() {
    
    
        return Collections.emptyMap();
    }
    
}

  • ServerMemberManagerIl stocke toutes les informations de liste de nœuds membres connues par le nœud, fournit des opérations d'ajout, de suppression, de modification et de requête pour les nœuds membres, et maintient une liste MemberLookup pour faciliter la commutation dynamique des méthodes d'adressage des nœuds membres.

  • MemberLookupL'interface est très simple et il n'y a que deux interfaces principales : injectMemberManageret afterLookup, la première est utilisée pour ServerMemberManagerinjecter dans MemberLookupafin de faciliter l'utilisation ServerMemberManagerdes capacités de stockage et de requête, et la seconde afterLookupest une interface d'événement. Lorsqu'il MemberLookupest nécessaire de mettre à jour les informations des nœuds membres , le dernier courant Les informations de la liste des nœuds membres du nœud sont notifiées via cette fonction ServerMemberManager, et la méthode de gestion de nœud spécifique est masquée dans l' MemberLookupimplémentation spécifique.


implémentation interne

insérez la description de l'image ici

Adressage autonome StandaloneMemberLookup

Le mode d'adressage du mode autonome est très simple, en fait, il s'agit de trouver sa propre information de combinaison IP:PORT, puis de la formater comme une information de nœud, d'appeler afterLookup et de stocker l'information dans ServerMemberManager.

package com.alibaba.nacos.core.cluster.lookup;

import com.alibaba.nacos.core.cluster.AbstractMemberLookup;
import com.alibaba.nacos.core.cluster.MemberUtil;
import com.alibaba.nacos.sys.env.EnvUtil;
import com.alibaba.nacos.sys.utils.InetUtils;

import java.util.Collections;

/**
 * Member node addressing mode in stand-alone mode.
 *
 * @author <a href="mailto:[email protected]">liaochuntao</a>
 */
public class StandaloneMemberLookup extends AbstractMemberLookup {
    
    
    
    @Override
    public void doStart() {
    
    
        String url = InetUtils.getSelfIP() + ":" + EnvUtil.getPort();
        afterLookup(MemberUtil.readServerConf(Collections.singletonList(url)));
    }
    
    @Override
    public boolean useAddressServer() {
    
    
        return false;
    }
}


Adressage de fichier FileConfigMemberLookup

Le mode d'adressage de fichier est l'implémentation d'adressage par défaut en mode cluster Nacos .

Le mode d'adressage des fichiers est très simple, en effet chaque nœud Nacos doit maintenir un fichier appelé cluster.conf.

192.168.16.101:8847
192.168.16.102
192.168.16.103

Par défaut, ce fichier n'a besoin que de remplir les informations IP de chaque nœud membre, et le port sélectionnera automatiquement le port par défaut de Nacos 8848. Si vous avez modifié les informations de port de Nacos pour des besoins particuliers, vous devez ajouter le réseau Informations complètes sur l'adresse de l'itinéraire (IP:PORT).

Lorsque le nœud Nacos démarre, il lit le contenu du fichier, puis analyse l'adresse IP du fichier dans une liste de nœuds et appelle afterLookup pour l'enregistrer dans ServerMemberManager.


/**
 * Cluster.conf file managed cluster member node addressing pattern.
 *
 * @author <a href="mailto:[email protected]">liaochuntao</a>
 */
public class FileConfigMemberLookup extends AbstractMemberLookup {
    
    
    
    private static final String DEFAULT_SEARCH_SEQ = "cluster.conf";
    
    private FileWatcher watcher = new FileWatcher() {
    
    
        @Override
        public void onChange(FileChangeEvent event) {
    
    
            readClusterConfFromDisk();
        }
        
        @Override
        public boolean interest(String context) {
    
    
            return StringUtils.contains(context, DEFAULT_SEARCH_SEQ);
        }
    };
    
    @Override
    public void doStart() throws NacosException {
    
    
        readClusterConfFromDisk();
        
        // Use the inotify mechanism to monitor file changes and automatically
        // trigger the reading of cluster.conf
        try {
    
    
            WatchFileCenter.registerWatcher(EnvUtil.getConfPath(), watcher);
        } catch (Throwable e) {
    
    
            Loggers.CLUSTER.error("An exception occurred in the launch file monitor : {}", e.getMessage());
        }
    }
    
    @Override
    public boolean useAddressServer() {
    
    
        return false;
    }
    
    @Override
    public void destroy() throws NacosException {
    
    
        WatchFileCenter.deregisterWatcher(EnvUtil.getConfPath(), watcher);
    }
    
    private void readClusterConfFromDisk() {
    
    
        Collection<Member> tmpMembers = new ArrayList<>();
        try {
    
    
            List<String> tmp = EnvUtil.readClusterConf();
            tmpMembers = MemberUtil.readServerConf(tmp);
        } catch (Throwable e) {
    
    
            Loggers.CLUSTER
                    .error("nacos-XXXX [serverlist] failed to get serverlist from disk!, error : {}", e.getMessage());
        }
        
        afterLookup(tmpMembers);
    }
}

S'il s'avère que le cluster s'agrandit et se rétrécit, vous devez modifier le fichier cluster.conf sous chaque nœud Nacos, puis le centre de surveillance des modifications de fichier à l'intérieur de Nacos découvrira automatiquement la modification du fichier, relira le contenu du fichier, chargera les informations de la liste IP et mettre à jour le nœud nouvellement ajouté (FileWatcher)

Cependant, ce mode d'adressage par défaut présente un inconvénient : les coûts d'exploitation et de maintenance sont relativement élevés. Comme vous pouvez l'imaginer, lorsque vous ajoutez un nouveau nœud Nacos, vous devez modifier manuellement le fichier cluster.conf sous chaque nœud Nacos. travail, ou un peu plus avancé, utilisez des outils de déploiement automatisés tels que ansible pour pousser le fichier cluster.conf pour remplacer votre propre opération manuelle. Un problème—chaque nœud Nacos a un fichier cluster.conf. Si fichier de l'un des nœuds échoue, cela entraînera une incohérence des données dans la liste des nœuds membres entre les clusters. Par conséquent, un autre mode d'adressage étendu - mode d'adressage du serveur d'adresses


Recherche de serveur d'adresses AddressServerMemberLookup

Le mode d'adressage du serveur d'adresses est une sorte de gestion des informations des nœuds membres du cluster officiellement recommandé par Nacos. Ce mode utilise un simple serveur Web pour gérer les informations de contenu du fichier cluster.conf. De cette manière, le personnel d'exploitation et de maintenance n'a besoin que pour gérer cela, chaque nœud membre Nacos n'a besoin que de demander périodiquement les dernières informations de la liste des nœuds membres du cluster à partir de ce nœud Web.

insérez la description de l'image ici

public class AddressServerMemberLookup extends AbstractMemberLookup {
    
    
    
    private final GenericType<String> genericType = new GenericType<String>() {
    
     };
    
    public String domainName;
    
    public String addressPort;
    
    public String addressUrl;
    
    public String envIdUrl;
    
    public String addressServerUrl;
    
    private volatile boolean isAddressServerHealth = true;
    
    private int addressServerFailCount = 0;
    
    private int maxFailCount = 12;
    
    private final NacosRestTemplate restTemplate = HttpClientBeanHolder.getNacosRestTemplate(Loggers.CORE);
    
    private volatile boolean shutdown = false;
    
    private static final String HEALTH_CHECK_FAIL_COUNT_PROPERTY = "maxHealthCheckFailCount";
    
    private static final String DEFAULT_HEALTH_CHECK_FAIL_COUNT = "12";
    
    private static final String DEFAULT_SERVER_DOMAIN = "jmenv.tbsite.net";
    
    private static final String DEFAULT_SERVER_POINT = "8080";
    
    private static final int DEFAULT_SERVER_RETRY_TIME = 5;
    
    private static final long DEFAULT_SYNC_TASK_DELAY_MS = 5_000L;
    
    private static final String ADDRESS_SERVER_DOMAIN_ENV = "address_server_domain";
    
    private static final String ADDRESS_SERVER_DOMAIN_PROPERTY = "address.server.domain";
    
    private static final String ADDRESS_SERVER_PORT_ENV = "address_server_port";
    
    private static final String ADDRESS_SERVER_PORT_PROPERTY = "address.server.port";
    
    private static final String ADDRESS_SERVER_URL_ENV = "address_server_url";
    
    private static final String ADDRESS_SERVER_URL_PROPERTY = "address.server.url";
    
    private static final String ADDRESS_SERVER_RETRY_PROPERTY = "nacos.core.address-server.retry";
    
    @Override
    public void doStart() throws NacosException {
    
    
        this.maxFailCount = Integer.parseInt(EnvUtil.getProperty(HEALTH_CHECK_FAIL_COUNT_PROPERTY, DEFAULT_HEALTH_CHECK_FAIL_COUNT));
        initAddressSys();
        run();
    }
    
    @Override
    public boolean useAddressServer() {
    
    
        return true;
    }
    
    private void initAddressSys() {
    
    
        String envDomainName = System.getenv(ADDRESS_SERVER_DOMAIN_ENV);
        if (StringUtils.isBlank(envDomainName)) {
    
    
            domainName = EnvUtil.getProperty(ADDRESS_SERVER_DOMAIN_PROPERTY, DEFAULT_SERVER_DOMAIN);
        } else {
    
    
            domainName = envDomainName;
        }
        String envAddressPort = System.getenv(ADDRESS_SERVER_PORT_ENV);
        if (StringUtils.isBlank(envAddressPort)) {
    
    
            addressPort = EnvUtil.getProperty(ADDRESS_SERVER_PORT_PROPERTY, DEFAULT_SERVER_POINT);
        } else {
    
    
            addressPort = envAddressPort;
        }
        String envAddressUrl = System.getenv(ADDRESS_SERVER_URL_ENV);
        if (StringUtils.isBlank(envAddressUrl)) {
    
    
            addressUrl = EnvUtil.getProperty(ADDRESS_SERVER_URL_PROPERTY, EnvUtil.getContextPath() + "/" + "serverlist");
        } else {
    
    
            addressUrl = envAddressUrl;
        }
        addressServerUrl = "http://" + domainName + ":" + addressPort + addressUrl;
        envIdUrl = "http://" + domainName + ":" + addressPort + "/env";
        
        Loggers.CORE.info("ServerListService address-server port:" + addressPort);
        Loggers.CORE.info("ADDRESS_SERVER_URL:" + addressServerUrl);
    }
    
    @SuppressWarnings("PMD.UndefineMagicConstantRule")
    private void run() throws NacosException {
    
    
        // With the address server, you need to perform a synchronous member node pull at startup
        // Repeat three times, successfully jump out
        boolean success = false;
        Throwable ex = null;
        int maxRetry = EnvUtil.getProperty(ADDRESS_SERVER_RETRY_PROPERTY, Integer.class, DEFAULT_SERVER_RETRY_TIME);
        for (int i = 0; i < maxRetry; i++) {
    
    
            try {
    
    
                syncFromAddressUrl();
                success = true;
                break;
            } catch (Throwable e) {
    
    
                ex = e;
                Loggers.CLUSTER.error("[serverlist] exception, error : {}", ExceptionUtil.getAllExceptionMsg(ex));
            }
        }
        if (!success) {
    
    
            throw new NacosException(NacosException.SERVER_ERROR, ex);
        }
        
        GlobalExecutor.scheduleByCommon(new AddressServerSyncTask(), DEFAULT_SYNC_TASK_DELAY_MS);
    }
    
    @Override
    public void destroy() throws NacosException {
    
    
        shutdown = true;
    }
    
    @Override
    public Map<String, Object> info() {
    
    
        Map<String, Object> info = new HashMap<>(4);
        info.put("addressServerHealth", isAddressServerHealth);
        info.put("addressServerUrl", addressServerUrl);
        info.put("envIdUrl", envIdUrl);
        info.put("addressServerFailCount", addressServerFailCount);
        return info;
    }
    
    private void syncFromAddressUrl() throws Exception {
    
    
        RestResult<String> result = restTemplate
                .get(addressServerUrl, Header.EMPTY, Query.EMPTY, genericType.getType());
        if (result.ok()) {
    
    
            isAddressServerHealth = true;
            Reader reader = new StringReader(result.getData());
            try {
    
    
                afterLookup(MemberUtil.readServerConf(EnvUtil.analyzeClusterConf(reader)));
            } catch (Throwable e) {
    
    
                Loggers.CLUSTER.error("[serverlist] exception for analyzeClusterConf, error : {}",
                        ExceptionUtil.getAllExceptionMsg(e));
            }
            addressServerFailCount = 0;
        } else {
    
    
            addressServerFailCount++;
            if (addressServerFailCount >= maxFailCount) {
    
    
                isAddressServerHealth = false;
            }
            Loggers.CLUSTER.error("[serverlist] failed to get serverlist, error code {}", result.getCode());
        }
    }
    
    class AddressServerSyncTask implements Runnable {
    
    
        
        @Override
        public void run() {
    
    
            if (shutdown) {
    
    
                return;
            }
            try {
    
    
                syncFromAddressUrl();
            } catch (Throwable ex) {
    
    
                addressServerFailCount++;
                if (addressServerFailCount >= maxFailCount) {
    
    
                    isAddressServerHealth = false;
                }
                Loggers.CLUSTER.error("[serverlist] exception, error : {}", ExceptionUtil.getAllExceptionMsg(ex));
            } finally {
    
    
                GlobalExecutor.scheduleByCommon(this, DEFAULT_SYNC_TASK_DELAY_MS);
            }
        }
    }
}

Par conséquent, le mode serveur d'adresses simplifie considérablement le coût de la gestion des nœuds de cluster Nacos.Dans le même temps, le serveur d'adresses est un programme Web très simple et la stabilité de son programme peut être bien garantie.


futur point d'expansion

Expansion et contraction automatiques des nœuds de cluster

À l'heure actuelle, la gestion des nœuds de cluster dans Nacos est encore une opération manuelle. Par conséquent, à l'avenir, il est prévu de réaliser la fonction de gestion automatique des nœuds de cluster en fonction du mode d'adressage. Lorsqu'un nouveau nœud est mis en ligne, un seul des nœuds de cluster d'origine doivent être connus. Avec une seule information de nœud, vous pouvez rejoindre avec succès le cluster Nacos d'origine dans un certain laps de temps ; en même temps, vous pouvez également découvrir par vous-même les nœuds qui ne survivent pas et supprimer automatiquement à partir de la liste des nœuds disponibles dans le cluster. L'implémentation logique de cette partie est en fait similaire au protocole Consul's Gossip.

insérez la description de l'image ici

Je suppose que tu aimes

Origine blog.csdn.net/yangshangwei/article/details/131133842
conseillé
Classement