Implémentation de l'enregistrement et de la découverte du service basé sur Zookeeper

Après avoir pris connaissance de Zookeeper en détail, nous pouvons le faire nous-mêmes pour implémenter un enregistrement et une découverte de service basés sur Zookeeper. Premièrement, nous devons établir deux microservices, un service de commande (OrderService) et un service de produit (ProductService), qui Lors de la commande de services, vous devez appeler les services produits.


Tout d'abord, voyons comment le service produit (ProductService) est enregistré sur Zookeeper. Nous allons d'abord construire un projet SpringBoot.
Insérez la description de l'image ici

Lorsque le service démarre, nous devons enregistrer le service auprès de Zookeeper, ici nous devons utiliser l'API ServletServletContextListenerL'interface, qui peut surveiller le cycle de vie de l'objet ServletContext, surveille en fait le cycle de vie de l'application Web.


Lorsque le conteneur Servlet démarre ou termine l'application Web, il déclenche l'événement ServletContextEvent, qui est géré par ServletContextListener. Deux méthodes de gestion des événements ServletContextEvent sont définies dans l'interface ServletContextListener.
Insérez la description de l'image ici

@WebListener
public class InitListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        try {
            Properties properties =  new Properties();
            properties.load(InitListener.class.getClassLoader().getResourceAsStream("application.properties"));

            String hostAddress = InetAddress.getLocalHost().getHostAddress();
            int port = Integer.valueOf(properties.getProperty("server.port"));
            ServiceRegister.register(hostAddress,port);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {

    }
}

Ici, nous utilisons des @WebListenerannotations, que nous avons brièvement introduites dans les trois principaux composants du Web, du web.xml aux annotations , mais ici nous n'oublions pas d'ajouter des @ServletComponentScanannotations à la classe de démarrage SpringBoot
Insérez la description de l'image ici
Insérez la description de l'image ici


Bien sûr, nous pouvons également utiliser une autre manière, nous @WebListener @ServletComponentScanpouvons également utiliser des annotations, directement dans la classe de démarrage SpringBoot, @Beanpeuvent également être utilisées , comme suit:
Insérez la description de l'image ici



Ensuite, regardons de plus près comment l'enregistrer dans Zookeeper dans la classe InitListener. Ici, nous avons d'abord obtenu le fichier de configuration application.properties dans le projet. Quant à savoir comment l'obtenir, il y a trop de chemins de fichiers en Java pour obtenir des ressources. Voies


Bien sûr, nous pouvons également ajouter l'annotation @Component à l'environnement Spring, puis nous utilisons @Value pour obtenir le numéro de port de service dans le fichier de configuration.
Insérez la description de l'image ici
Insérez la description de l'image ici


Dans ce qui précède, non seulement le numéro de port, mais aussi l'adresse IP, nous devons enregistrer IP + PORT sur Zookeeper. Ici, nous devons penser au nœud que nous avons introduit précédemment pour stocker les informations IP + PORT. Ici, nous pouvons utiliser notre N'importe lequel des trois clients présentés précédemment, ici nous choisissons Curator , l'avantage de ce client sur le client natif, nous l'avons déjà présenté en détail auparavant, ici nous devons introduire des dépendances liées

<dependency>
    <groupId>org.apache.zookeeper</groupId>
    <artifactId>zookeeper</artifactId>
    <version>3.4.12</version>
    <exclusions>
        <exclusion>
            <artifactId>slf4j-log4j12</artifactId>
            <groupId>org.slf4j</groupId>
        </exclusion>
    </exclusions>
</dependency>

<!--对zookeeper的底层api的一些封装-->
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-framework</artifactId>
    <version>4.3.0</version>
</dependency>
<!--封装了一些高级特性,如:Cache事件监听、选举、分布式锁、分布式Barrier-->
<dependency>
    <groupId>org.apache.curator</groupId>
    <artifactId>curator-recipes</artifactId>
    <version>4.3.0</version>
</dependency>

Une petite attention ici est que nous avons besoin de slf4j dans Zookeeper, car il entre en conflit avec la version de slf4j dans SpringBoot, puis il est très simple d'enregistrer les informations sur le nœud Zookeeper. Ici, si nous utilisons un client natif, Ensuite, nous avons besoin de plus d'opérations supplémentaires, telles que juger de l'existence du nœud parent couche par couche, sinon, créer le nœud parent, et nous devons également utiliser CountDownLatch et Watch pour attendre une connexion réussie lors de la connexion au client

public class ServiceRegister {

    private static final String CONNENT_ADDR = "127.0.0.1:2181";
    private static final String BASE_SERVICES = "/services";
    private static final String SERVICE_NAME = "/products";

    public static void register(String address, int port) throws Exception {
        CuratorFramework curatorFramework = CuratorFrameworkFactory.builder()
                .connectString(CONNENT_ADDR)
                .connectionTimeoutMs(5000)  //连接超时时间
                .sessionTimeoutMs(5000)     //会话超时时间
                .retryPolicy(new ExponentialBackoffRetry(1000, 3))
                .build();
        curatorFramework.start();

        String path = BASE_SERVICES + SERVICE_NAME;
        String server_path = address + ":" + port;

        curatorFramework.create()
                .creatingParentsIfNeeded()
                .withMode(CreateMode.EPHEMERAL_SEQUENTIAL)
                .forPath(path + "/child", server_path.getBytes());
    }
}

Ensuite, nous avons presque terminé le travail de service produit. Nous pouvons modifier le numéro de port dans application.properties pour démarrer plusieurs services produit. L'interface fournie par le service produit vers l'extérieur est la suivante, qui consiste simplement à renvoyer le numéro de port du service.
Insérez la description de l'image ici




Une fois l'enregistrement du service produit terminé, l'étape suivante est définitivement la découverte du service de commande. Tout d'abord, nous devons également créer un projet SpringBoot. De même, nous devons encore utiliser l'interface ServletContextListener dans l'API Servlet
Insérez la description de l'image ici
Insérez la description de l'image ici

Contrairement au service produit, la classe InitListener du service produit consiste à enregistrer les informations IP + PORT du service produit auprès de Zookeeper lorsque le conteneur Servlet est démarré, et InitListener dans le service de commande doit démarrer au démarrage du conteneur Servlet. Les informations de service du produit enregistrées dans Zookeeper sont déroulées pour que le service de commande puisse

public class InitListener implements ServletContextListener {

    private static final String CONNENT_ADDR = "127.0.0.1:2181";
    private static final String BASE_SERVICES = "/services";
    private static final String SERVICE_NAME = "/products";

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        CuratorFramework curatorFramework = CuratorFrameworkFactory.builder()
                .connectString(CONNENT_ADDR)
                .connectionTimeoutMs(5000)  //连接超时时间
                .sessionTimeoutMs(5000)     //会话超时时间
                .retryPolicy(new ExponentialBackoffRetry(1000, 3))
                .build();
        curatorFramework.start();

        List<String> newServerList = new ArrayList<>();
        String path = BASE_SERVICES + SERVICE_NAME;
        final PathChildrenCache cache = new PathChildrenCache(curatorFramework, path, true);
        try {
            cache.start(PathChildrenCache.StartMode.POST_INITIALIZED_EVENT);
            cache.getListenable().addListener(new PathChildrenCacheListener() {
                //监听子节点的变化
                @Override
                public void childEvent(CuratorFramework cf, PathChildrenCacheEvent event) throws Exception {
                    List<String> list = curatorFramework.getChildren().forPath(path);
                    for (String subNode : list) {
                        byte[] bytes = curatorFramework.getData().forPath(path + "/" + subNode);
                        String host = new String(bytes, "utf-8");
                        newServerList.add(host);
                    }
                    LoadBalance.SERVICE_LIST = newServerList;
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
    }
}

Ici, nous devons surveiller les changements des nœuds sur Zookeeper, car en cas de panne d'un service produit ou d'un nouveau service produit, nous devons être en mesure d'obtenir des informations à temps. Pour l'introduction de la surveillance Curator, voir Zookeeper client (5) -Curator
Insérez la description de l'image ici


Lorsque nous écoutons le changement du nœud, nous mettons à jour sa valeur dans la classe LoadBalance, qui est principalement une simple simulation d'équilibrage de charge. Ici, nous sélectionnons au hasard un service parmi tous les services de produit lorsque le service de commande appelle le service de produit

public class LoadBalance {

    public volatile static List<String> SERVICE_LIST;

    public String choseService() {
        String result = "";
        if (!CollectionUtils.isEmpty(SERVICE_LIST)) {
            int index = new Random().nextInt(SERVICE_LIST.size());
            result = SERVICE_LIST.get(index);
        }
        return result;
    }
}

Ici, notre enregistrement et découverte de service basé sur Zookeeper est pratiquement terminé. Ensuite, nous fournissons également un contrôleur dans le service de commande. Le contrôleur appellera le contrôleur du service produit. Ici, nous utilisons le RestTemplate comme suit:

@RestController
@RequestMapping("/order")
public class OrderController {

    @Resource
    private RestTemplate restTemplate;

    private LoadBalance loadBalance = new LoadBalance();

    @RequestMapping("/getOrder")
    public Object getProduct(HttpServletRequest request) {
        String host = loadBalance.choseService();
        return restTemplate.getForObject("http://" + host + "/product/getProduct", Object.class);
    }
}

Insérez la description de l'image ici




Ce qui précède termine un enregistrement et une découverte de service simples. Testons-le ici. Nous pouvons changer le numéro de port dans le fichier applicat.properties du service produit (ProductService) pour démarrer plusieurs services produit. Ici, nous commençons 8080 , 8081 deux services, nous pouvons utiliser ZooInspector pour afficher les informations sur les nœuds de Zookeeper, comme suit:
Insérez la description de l'image iciInsérez la description de l'image ici


Ensuite, nous démarrons un service de commande et rafraîchissons dans le navigateur en permanence, nous pouvons voir que différents services de produits seront appelés au hasard
Insérez la description de l'image ici
Insérez la description de l'image ici

286 articles originaux publiés · J'aime12 · Visiteurs 10 000+

Je suppose que tu aimes

Origine blog.csdn.net/newbie0107/article/details/105442764
conseillé
Classement