概述
书接上回,自定义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理论是分布式架构中最重要的理论
- C 一致性 :对于客户端的每次读操作,要么读到的是最新的数据,要么读取失败。换句话说,一致性是站在分布式系统的角度,对访问本系统的客户端的一种承诺:要么我给您返回一个错误,要么我给你返回绝对一致的最新数据,不难看出,其强调的是数据正确。
- A 可用性 :任何客户端的请求都能得到响应数据,不会出现响应错误。换句话说,可用性是站在分布式系统的角度,对访问本系统的客户的另一种承诺:我一定会给您返回数据,不会给你返回错误,但不保证数据最新,强调的是不出错。
- 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项目——常见问题及详解(注册中心)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复