我是靠谱客的博主 温暖电灯胆,最近开发中收集的这篇文章主要介绍自定义RPC项目——常见问题及详解(注册中心),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

         书接上回,自定义RPC项目——常见问题及详解(Netty篇)_李孛欢的博客-CSDN博客,我们接着来谈,这个RPC项目的常见问题:

项目地址:https://blog.csdn.net/qq_40856284/category_10138756.html

        四、注册中心 

         1.为什么要用注册中心?

        在进行注册中心使用和学习之前,我们首先就要明确一点,为什么要用注册中心呢?随着互联网架构发展(单一应用架构==>垂直应用架构==>分布式架构==>SOA架构==>微服务架构),服务越来越多,服务间的依赖关系也更加复杂,采用直接调用服务方式难度大,实现过程也更复杂,以及为了提高服务的可靠性,注册中心应运而生。

        注册中心这一概念在面向服务设计的架构中起着举足轻重的作用,不论是在SOA架构还是微服务架构之中,注册中心的作用一句话概括就是存放和调度服务,实现服务和注册中心,服务和服务之间的相互通信。注册中心可以说是微服务架构中的”通讯录“,它记录了服务和服务地址的映射关系。在分布式架构中,服务会注册到这里,当服务需要调用其它服务时,就到这里找到服务的地址,进行调用。以下是常用的一些注册中心特点:

          2.为什么要用Nacos作为项目的注册中心?

        Nacos 是阿里巴巴开源的一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。(配置中心、注册中心) 

        看上面的表,nacos支持的特性最多最全面。开箱即用,上手简洁,暂时也没发现有太大的坑,nacos功能更加丰富,社区更加活跃。

        3.常用注册中心差异?

        见这篇文章。微服务:注册中心ZooKeeper、Eureka、Consul 、Nacos对比_琦彦的博客-CSDN博客_consul nacos

        4.注册中心至少要具备哪些条件?      

服务注册接口:服务提供者通过调用服务注册接口来完成服务注册。

服务反注册接口:服务提供者通过调用服务反注册接口来完成服务注销。

心跳汇报接口:服务提供者通过调用心跳汇报接口完成节点存活状态上报。

服务订阅接口:服务消费者通过调用服务订阅接口完成服务订阅,获取可用的服务提供者节点列表。

服务变更查询接口:服务消费者通过调用服务变更查询接口,获取最新的可用服务节点列表。

服务查询接口:查询注册中心当前注册了哪些服务信息。

服务修改接口:修改注册中心中某一服务的信息。

        5. 注册中心单机还是集群的,其中一个挂了怎么办?一致性,可靠性怎么保证的? 

         在我的项目中,实现的是单机版nacos。nacos的集群部署方案可以看下面这个博客

Nacos服务注册与发现、集群部署方案_祁_z的博客-CSDN博客_nacos 服务集群配置

        那么要实现注册中心从单机版到分布式集群,有几个关键问题要解决:

  • 集群成员间的关系与成员发现问题

  • 集群成员间数据复制与一致性问题

  • 数据副本机制和数据分区策略

        具体的解决方案可见:微服务注册中心分布式集群设计原理与 Golang 实现 (136.la) 

        6.分布式数据一致性协议都知道哪些?

        (1条消息) 常用的分布式一致性协议_TJtulong的博客-CSDN博客_分布式一致性协议

       7.CAP理论了解嘛?

         CAP理论是分布式架构中最重要的理论

  1. C 一致性 :对于客户端的每次读操作,要么读到的是最新的数据,要么读取失败。换句话说,一致性是站在分布式系统的角度,对访问本系统的客户端的一种承诺:要么我给您返回一个错误,要么我给你返回绝对一致的最新数据,不难看出,其强调的是数据正确。
  2. A 可用性 :任何客户端的请求都能得到响应数据,不会出现响应错误。换句话说,可用性是站在分布式系统的角度,对访问本系统的客户的另一种承诺:我一定会给您返回数据,不会给你返回错误,但不保证数据最新,强调的是不出错。
  3. P 分区容忍性 :由于分布式系统通过网络进行通信,网络是不可靠的。当任意数量的消息丢失或延迟到达时,系统仍会继续提供服务,不会挂掉。换句话说,分区容忍性是站在分布式系统的角度,对访问本系统的客户端的再一种承诺:我会一直运行,不管我的内部出现何种数据同步问题,强调的是不挂掉。

        所有的分布式系统都必须有分区容忍性,因为分区容忍性是分布式系统的基本条件,但一致性和可用性只能有一种,也就是只有CP或者AP的系统,目前不存在CAP都成立的系统。因为当系统为了满足一致性就必须对数据进行复制到每个微服务中,这就导致了很大的性能消耗,就会出现可用性的问题,所以二者不可兼得。

        8.任何一个请求(流量)过来都会打到注册中心么? 

        第一次会,当请求注册中心之后,则将服务列表保存到本地(消费者内存中),方便以后使用。 

        9.如果是你如何设计一个nacos ,rpc如何调用。

         【Nacos】Nacos原理解析_Coinker的博客-CSDN博客_nacos的原理

        10.raft了解嘛?

        Nacos的Raft 算法_加班狂魔的博客-CSDN博客_nacos raft

        11.项目中nacos注册中心的具体使用

         引入依赖

        <dependency>
            <groupId>com.alibaba.nacos</groupId>
            <artifactId>nacos-client</artifactId>
            <version>1.3.0</version>
        </dependency>

        首先定义一个接口,ServiceRegistry作为远程注册表(Nacos)的使用

public interface ServiceRegistry {

    /**
     * 将一个服务注册进注册表
     *
     * @param serviceName 服务名称
     * @param inetSocketAddress 提供服务的地址
     */
    void register(String serviceName, InetSocketAddress inetSocketAddress);
}

        register 方法就是将服务的名称(接口名)和地址注册进服务注册中心,接口有了,我们就可以写实现类了,我们实现一个 Nacos 作为注册中心的实现类:NacosServiceRegistry,我们也可以使用 ZooKeeper 作为注册中心,实现接口就可以。

public class NacosServiceRegistry implements ServiceRegistry {

    private static final Logger logger = LoggerFactory.getLogger(NacosServiceRegistry.class);

    @Override
    public void register(String serviceName, InetSocketAddress inetSocketAddress) {
        try {
            NacosUtil.registerService(serviceName, inetSocketAddress);
        } catch (NacosException e) {
            logger.error("注册服务时有错误发生:", e);
            throw new RpcException(RpcError.REGISTER_SERVICE_FAILED);
        }
    }
}

        这里是用到了一个Nacos工具类的registerService方法来注册服务的,NacosUtil类定义如下,主要实现了三个方法,注册服务,获取服务所有实例以及注销服务。

public class NacosUtil {

    private static final Logger logger = LoggerFactory.getLogger(NacosUtil.class);

    private static final NamingService namingService;
    private static final Set<String> serviceNames = new HashSet<>();
    private static InetSocketAddress address;

    private static final String SERVER_ADDR = "127.0.0.1:8848";

    static {
        namingService = getNacosNamingService();
    }

    public static NamingService getNacosNamingService() {
        try {
            return NamingFactory.createNamingService(SERVER_ADDR);
        } catch (NacosException e) {
            logger.error("连接到Nacos时有错误发生: ", e);
            throw new RpcException(RpcError.FAILED_TO_CONNECT_TO_SERVICE_REGISTRY);
        }
    }

    public static void registerService(String serviceName, InetSocketAddress address) throws NacosException {
        namingService.registerInstance(serviceName, address.getHostName(), address.getPort());
        NacosUtil.address = address;
        serviceNames.add(serviceName);
    }

    public static List<Instance> getAllInstance(String serviceName) throws NacosException {
        return namingService.getAllInstances(serviceName);
    }

    public static void clearRegistry() {
        if(!serviceNames.isEmpty() && address != null) {
            String host = address.getHostName();
            int port = address.getPort();
            Iterator<String> iterator = serviceNames.iterator();
            while(iterator.hasNext()) {
                String serviceName = iterator.next();
                try {
                    namingService.deregisterInstance(serviceName, host, port);
                } catch (NacosException e) {
                    logger.error("注销服务 {} 失败", serviceName, e);
                }
            }
        }
    }
}

        Nacos 的使用很简单,通过 NamingFactory 创建 NamingService 连接 Nacos,连接的过程写在了静态代码块中,在类加载时自动连接。namingService 提供了两个很方便的接口,registerInstance 和 getAllInstances 方法,前者可以直接向 Nacos 注册服务,后者可以获得提供某个服务的所有提供者的列表。所以接口的这两个方法只需要包装一下就好了。

        在 NacosUtil中我们通过 getAllInstance 获取到某个服务的所有提供者列表后,需要选择一个,这里就涉及了负载均衡策略,这里我们先选择第 0 个,后面我们详细讲解负载均衡。

        接下来,我们修改 RpcServer 接口,新增一个方法 publishService,用于向 Nacos 注册服务:

<T> void publishService(Object service, Class<T> serviceClass);

        然后只需要实现这个方法即可,以 NettyServer 的实现为例,NettyServer 在创建时需要创建一个 ServiceRegistry 了:

 public NettyServer(String host, int port) {
        this.host = host;
        this.port = port;
        serviceRegistry = new NacosServiceRegistry();
        serviceProvider = new ServiceProviderImpl();
    }
public <T> void publishService(Object service, Class<T> serviceClass) {
        if(serializer == null) {
            logger.error("未设置序列化器");
            throw new RpcException(RpcError.SERIALIZER_NOT_FOUND);
        }
        serviceProvider.addServiceProvider(service);
        serviceRegistry.register(serviceClass.getCanonicalName(), new InetSocketAddress(host, port));
    }

        这里的serviceProvider是本地保存服务类的实例对象,publishService 需要将服务保存在本地的注册表,同时注册到 Nacos 上。

        最后还有服务发现部分,就放到后面和负载均衡一起总结吧!觉得对大家有用的,可以给博主点个赞哦~

最后

以上就是温暖电灯胆为你收集整理的自定义RPC项目——常见问题及详解(注册中心)的全部内容,希望文章能够帮你解决自定义RPC项目——常见问题及详解(注册中心)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(53)

评论列表共有 0 条评论

立即
投稿
返回
顶部