文章目录
-
- Nacos是什么?
- 介绍Nacos功能
-
- 服务发现和服务健康监测(使服务更容易注册,并通过DNS或HTTP接口发现其他服务,还提供服务的实时健康检查,以防 止向不健康的主机或服务实例发送请求。 )
- 动态配置服务
- 动态 DNS 服务
- 服务及其元数据管理
- 服务发现
- 服务发现产品对比
- nacos和eureka的区别:
-
- Nacos的服务实例分为两种类型:
- Nacos与eureka的共同点
- Nacos与Eureka的区别
- 服务发现数据模型
-
- Namespace 隔离设计
- 命名空间管理
- 数据模型
- 使用Nacos作为配置中心
- 分布式配置中心实现原理
- SpringCloud LoadBalancer (下文简称 SCL)
-
- 自定义负载均衡策略
- 什么雪崩问题?如何解决?
- dubbo的注册中心(nacos)挂掉之后,服务器调用者还能调用服务提供者吗?
- 大型网站架构演变过程
-
- 网站架构演变演变过程
- 分布式架构
- SOA架构
- 微服务架构
Nacos是什么?
阿里的一个开源产品,是针对微服务架构中的服务发现、配置管理、服务治理的综合型解决方案。
(用来实现配置中心和服务注册中心)
介绍Nacos功能
服务发现和服务健康监测(使服务更容易注册,并通过DNS或HTTP接口发现其他服务,还提供服务的实时健康检查,以防 止向不健康的主机或服务实例发送请求。 )
支持基于DNS和基于RPC的服务发现。服务提供者使用原生SDK、OpenAPI、或一个独立的Agent TODO注册 Service 后,服务消费者可以使用DNS TODO 或HTTP&API查找和发现服务。
Nacos提供对服务的实时的健康检查,阻止向不健康的主机或服务实例发送请求。Nacos 支持传输层 (PING 或 TCP)和应用层 (如 HTTP、MySQL、用户自定义)的健康检查。 对于复杂的云环境和网络拓扑环境中(如 VPC、边缘网络等)服务的健康检查,Nacos 提供了 agent 上报模式和服务端主动检测2种健康检查模式。Nacos 还提供了统一的健康检查仪表盘,帮助您根据健康状态管理服务的可用性及流量。
动态配置服务
以中心化、外部化和动态化的方式管理所有环境的应用配置和服务配置。
消除了配置变更时重新部署应用和服务的需要,让配置管理变得更加高效和敏捷。
配置中心化管理让实现无状态服务变得更简单,让服务按需弹性扩展变得更容易。
提供了一个简洁易用的UI (控制台样例 Demo) 帮助管理所有的服务和应用的配置。
Nacos 还提供包括配置版本跟踪、金丝雀发布、一键回滚配置以及客户端配置更新状态跟踪在内的一系列开箱即用的配置管理特性,能更安全地在生产环境中管理配置变更和降低配置变更带来的风险。
动态 DNS 服务
动态 DNS 服务支持权重路由,更容易地实现中间层负载均衡、更灵活的路由策略、流量控制以及数据中心内网的简单DNS解析服务。动态DNS服务还能更容易地实现以 DNS 协议为基础的服务发现,消除耦合到厂商私有服务发现 API 上的风险。
Nacos 提供了一些简单的 DNS APIs TODO ,管理服务的关联域名和可用的 IP:PORT 列表
服务及其元数据管理
从微服务平台建设的视角管理数据中心的所有服务及元数据,包括管理服务的描述、生命周期、服务的静态依赖分析、服务的健康状态、服务的流量管理、路由及安全策略、服务的 SLA 以及最首要的 metrics 统计数据。
服务发现
在微服务架构中一个业务流程需要多个微服务通过网络接口调用完成业务处理,服务消费方从服务注册中心获取服 务提供方的地址,从而进行远程调用,这个过程叫做服务发现。
服务发现流程:
服务实例本身并不记录服务生产方的网络地址,所有服务实例内部都会包含服务发现客户端。
在每个服务启动时会向服务发现中心上报自己的网络位置。在服务发现中心内部会形成一个服务注册表,服务注册表是服务发现的核心部分,是包含所有服务实例的网络地址的数据库。
服务发现客户端会定期从服务发现中心同步服务注册表 ,并缓存在客户端。
当需要对某服务进行请求时,服务实例通过该注册表,定位目标服务网络地址。若目标服务存在多个网络地址,则使用负载均衡算法从多个服务实例中选择出一个,然后发出请求。
总结,在微服务环境中,由于服务运行实例的网络地址是不断动态变化的,服务实例数量的动态变化 ,因此无法使用固定的配置文件来记录服务提供方的网络地址,必须使用动态的服务发现机制用于实现微服务间的相互感知。 各服务实例会上报自己的网络地址,这样服务中心就形成了一个完整的服务注册表,各服务实例会通过服务发现中心来获取访问目标服务的网络地址,从而实现服务发现的机制。
执行流程:
服务提供方将自己注册到服务注册中心
服务消费方从注册中心获取服务地址
进行远程调用
服务发现产品对比
目前市面上用的比较多的服务发现中心有:Nacos、Eureka、Consul和Zookeeper。
对比项目 | Naos | Eureka | Consul | Zookeeper |
---|---|---|---|---|
一致性协议 | 支持AP和CP模型 | AP模型 | CP模型 | CP模型 |
健康检查 | TCP/HTTP/MYSQL/Client Beat | Client Beat | TCP/HTTP/gRPC/Cmd | Keep Alive |
负载均衡策略 | 权重/metadata/Selector | Ribbon | Fabio | - |
雪崩保护 | 有 | 有 | 无 | 无 |
自动注销实例 | 支持 | 支持 | 不支持 | 支持 |
访问协议 | HTTP/DNS | HTTP | HTTP/DNS | TCP |
监听支持 | 支持 | 支持 | 支持 | 支持 |
多数据中心 | 支持 | 支持 | 支持 | 不支持 |
跨注册中心同步 | 支持 | 不支持 | 支持 | 不支持 |
SpringCloud集成 | 支持 | 支持 | 支持 | 不支持 |
Dubbo集成 | 支持 | 不支持 | 不支持 | 支持 |
k8s集成 | 支持 | 不支持 | 支持 | 不支持 |
nacos和eureka的区别:
Nacos的服务实例分为两种类型:
临时实例:如果实例宕机超过一定时间,会从服务列表剔除,默认的类型。
非临时实例:如果实例宕机,不会从服务列表剔除,也可以叫永久实例。
spring:
cloud:
nacos:
discovery:
ephemeral: false # true:临时实例,false:非临时实例,永久实例
Nacos与eureka的共同点
- 都支持服务注册和服务拉取
- 都支持服务提供者心跳方式做健康检测
Nacos与Eureka的区别
- Nacos支持服务端主动检测提供者状态:临时实例采用心跳模式,非临时实例采用主动检测模式:【正式工每天都会被检查状态,临时工也就心跳检测自己上报状态】
- 临时实例心跳不正常会被剔除,非临时实例【正式工】则不会被剔除
- Nacos支持服务列表变更的消息推送模式,服务列表更新更及时
- Nacos集群默认采用AP(可用)方式,当集群中存在非临时实例时,采用CP(一致性)模式;Eureka采用AP(可用)方式
服务发现数据模型
Namespace 隔离设计
命名空间(Namespace)用于进行租户粒度的隔离,Namespace 的常用场景之一是不同环境的隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。
从一个租户(用户)的角度来看,如果有多套不同的环境,那么这个时候可以根据指定的环境来创建不同的 namespce,以此来实现多环境的隔离。如有开发,测试和生产三个不同的环境,那么使用一套 nacos 集群可以分别建以下三个不同的 namespace。
从多个租户(用户)的角度来看,每个租户(用户)可能会有自己的 namespace,每个租户(用户)的配置数据以及注册的服务数据都会归属到自己的 namespace 下,以此来实现多租户间的数据隔离。
命名空间管理
命名空间(Namespace)是用于隔离多个环境的(如开发、测试、生产),而每个应用在不同环境的同一个配置(如数据库数据源)的值是不一样的。因此,我们应针对企业项目实际研发流程、环境进行规划。 如某软件公司拥有开发、测试、生产三套环境,那么我们应该针对这三个环境分别建立三个namespace。
建立好所有namespace后,在配置管理与服务管理模块下所有页面,都会包含用于切换namespace(环境)的tab按钮;
注意:
namesace 为 public 是 nacos 的一个保留空间,如需要创建自己的 namespace,不要和 public 重名,以一个实际业务场景有具体语义的名字来命名,以免带来字面上不容易区分哪一个 namespace。
在编写程序获取配置集时,指定的namespace参数一定要填写命名空间ID,而不是名称
数据模型
Nacos在经过阿里内部多年生产经验后提炼出的数据模型,是一种 服务-集群-实例 的三层模型,这样基本可以满 足服务在所有场景下的数据存储和管理。
服务:对外提供的软件功能,通过网络访问预定义的接口。
实例:提供一个或多个服务的具有可访问网络地址(IP:Port)的进程,启动一个服务,就产生了一个服务实例。
元信息:Nacos数据(如配置和服务)描述信息,如服务版本、权重、容灾策略、负载均衡策略、鉴权配置、各种自定义标 签 (label),
从作用范围来分:服务级别的元信息、集群的元信息、实例的元信息。
集群:服务实例的集合,服务实例组成一个默认集群, 集群可以被进一步按需求划分,划分的单位可以是虚拟集群,相同集群下的实例才能相互感知。
应用通过Namespace、Service、Cluster(DEFAULT)的配置,描述了该服务向哪个环境(如开发环境)的哪个集群注册实例。
例子:
指定namespace的id:a1f8e863-3117-48c4-9dd3-e9ddc2af90a8(注意根据自己环境设置namespace的id)
指定集群名称:DEFAULT表示默认集群,可不填写
spring:
application:
name: transaction‐service
cloud:
nacos:
discovery:
server‐addr: 127.0.0.1:8848 # 注册中心地址
namespace: a1f8e863‐3117‐48c4‐9dd3‐e9ddc2af90a8 #开发环境
cluster‐name: DEFAULT #默认集群,可不填
使用Nacos作为配置中心
Nacos除了实现了服务的注册发现之外,还将配置中心功能整合在了一起。通过Nacos的配置管理功能,我们可以将整个架构体系内的所有配置都集中在Nacos中存储。这样做的好处,在以往的教程中介绍Spring Cloud Config时也有提到,主要有以下几点:
分离的多环境配置,可以更灵活的管理权限,安全性更高。
应用程序的打包更为纯粹,以实现一次打包,多处运行的特点。
配置动态刷新(可以在读取配置的类上面添加注解@RefreshScope来实现动态刷新)
配置回滚(可以再历史版本里面查看到配置文件修改的记录,可以选择对应的版本回滚)。
Nacos的配置管理,基础层面都通过DataId和Group来定位配置内容,除此之外还增加了很多其他的管理功能。
分布式配置中心实现原理
本地应用读取云端分布式配置中心文件(第一次读取时建立长连接)
本地应用读取到配置文件后,本地jvm和硬盘都会缓存一份。
本地应用于分布式配置中心服务器端一直保持长连接
当我们的配置文件发生变化(根据版本号|MID判断)。将变化结果通知本地应用及时刷新配置文件。
对于Nacos配置管理,通过Namespace、group、Data ID能够定位到一个配置集。
配置集(Data ID):
在系统中,一个配置文件通常就是一个配置集,一个配置集可以包含了系统的各种配置信息,如:一个配置集可能包含了数据源、线程池、日志级别等配置项。每个配置集都可以定义一个有意义的名称,就是配置集的ID即Data ID。
配置项:
配置集中包含的一个个配置内容就是配置项。它代表一个具体的可配置的参数与其值域,通常以 key=value 的形式存在。如我们常配置系统的日志输出级别(logLevel=INFO|WARN|ERROR) 就是一个配置项。
配置分组(Group):
配置分组是对配置集进行分组,通过一个有意义的字符串(如 Buy 或 Trade )来表示,不同的配置分组下可以有相同的配置集(Data ID)。当在 Nacos 上创建一个配置时,如果未填写配置分组的名称,则配置分组的名称默认采用DEFAULT_GROUP。配置分组的常见场景:可用于区分不同的项目或应用,例如:学生管理系统的配置集可以定义一个group为:STUDENT_GROUP。
命名空间(Namespace):
命名空间可用于进行不同环境的配置隔离。例如可以隔离开发环境、测试环境和生产环境,因为 它们的配置可能各不相同,或者是隔离不同的用户,不同的开发人员使用同一个nacos管理各自的配置,可通过 namespace隔离。不同的命名空间下,可以存在相同名称的配置分组(Group) 或 配置集。
常见实践用法:
Nacos抽象定义了Namespace、Group、Data ID的概念,具体这几个概念代表什么,取决于我们把它们看成什么,如:
Namespace:代表不同环境,如开发、测试、生产环境;
Group:代表某项目;
DataId:每个项目下往往有若干个工程,每个配置集(DataId)是一个工程的主配置文件
SpringCloud LoadBalancer (下文简称 SCL)
SpringCloud原有的客户端负载均衡方案Ribbon已经被废弃,取而代之的是SpringCloud LoadBalancer。
Spring Cloud 中内部微服务调用默认是 http 请求,主要通过下面三种 API:
-
RestTemplate:同步 http API
-
WebClient:异步响应式 http API
-
三方客户端封装,例如 openfeign
如果项目中加入了 spring-cloud-loadbalancer 的依赖并且配置启用了,那么会自动在相关的 Bean 中加入负载均衡器的特性。 -
对于 RestTemplate,会自动对所有 @LoadBalanced 注解修饰的 RestTemplate Bean 增加 Interceptor 从而加上了负载均衡器的特性。
-
对于 WebClient,会自动创建 ReactorLoadBalancerExchangeFilterFunction,我们可以通过加入ReactorLoadBalancerExchangeFilterFunction会加入负载均衡器的特性。
-
对于三方客户端,一般不需要我们额外配置什么。
(spring cloud 2020) 内置轮询、随机的负载均衡策略,默认轮询策略。
可以通过 LoadBalancerClient 注解,指定服务级别的负载均衡策略
@LoadBalancerClient(value = “demo-provider”, configuration = RandomLoadbalancerConfig.class)
public class RandomLoadbalancerConfig {
@Bean
public ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(Environment environment,
LoadBalancerClientFactory loadBalancerClientFactory) {
String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
return new RandomLoadBalancer(
loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
}
}
自定义负载均衡策略
通过上文可知,目前 SCL 支持的负载均衡策略相较于 Ribbon 还是较少,需要开发者自行实现,好在 SCL 提供了便捷的 API 方便扩展使用。 这里演示自定义一个基于注册中心元数据的灰度负载均衡策略。
定义灰度负载均衡策略
@Slf4j
public class GrayRoundRobinLoadBalancer extends RoundRobinLoadBalancer {
private ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;
private String serviceId;
@Override
public Mono<Response<ServiceInstance>> choose(Request request) {
ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider
.getIfAvailable(NoopServiceInstanceListSupplier::new);
return supplier.get(request).next().map(serviceInstances -> getInstanceResponse(serviceInstances, request));
}
Response<ServiceInstance> getInstanceResponse(List<ServiceInstance> instances, Request request) {
// 注册中心无可用实例 抛出异常
if (CollUtil.isEmpty(instances)) {
log.warn("No instance available {}", serviceId);
return new EmptyResponse();
}
DefaultRequestContext requestContext = (DefaultRequestContext) request.getContext();
RequestData clientRequest = (RequestData) requestContext.getClientRequest();
HttpHeaders headers = clientRequest.getHeaders();
String reqVersion = headers.getFirst(CommonConstants.VERSION);
if (StrUtil.isBlank(reqVersion)) {
return super.choose(request).block();
}
// 遍历可以实例元数据,若匹配则返回此实例
for (ServiceInstance instance : instances) {
NacosServiceInstance nacosInstance = (NacosServiceInstance) instance;
Map<String, String> metadata = nacosInstance.getMetadata();
String targetVersion = MapUtil.getStr(metadata, CommonConstants.VERSION);
if (reqVersion.equalsIgnoreCase(targetVersion)) {
log.debug("gray requst match success :{} {}", reqVersion, nacosInstance);
return new DefaultResponse(nacosInstance);
}
}
// 降级策略,使用轮询策略
return super.choose(request).block();
}
}
针对客户端注入灰度负载均衡策略
@LoadBalancerClient(value = “demo-provider”, configuration = GrayRoundLoadbalancerConfig.class)
优化负载均衡策略注入
如上文所述,所有的个性化负载策略都需要手动通过 LoadBalancerClient 注入非常的不方便。 我们可以参考 LoadBalancerClients 的批量注入逻辑构造自己的 BeanRegistrar
public class GrayLoadBalancerClientConfigurationRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
Field[] fields = ReflectUtil.getFields(ServiceNameConstants.class);
// 遍历服务名称,注入支持灰度策略的负载均衡器
for (Field field : fields) {
Object fieldValue = ReflectUtil.getFieldValue(ServiceNameConstants.class, field);
registerClientConfiguration(registry, fieldValue, GrayLoadBalancerClientConfiguration.class);
}
}
}
什么雪崩问题?如何解决?
微服务间相互调用,因为调用链中的某一个服务器发生故障,引起整个系统都无法提供服务的情况,就是雪崩。
解决方案:
限流:是对服务的保护,避免因瞬间高并发高流量导致服务故障,进而避免雪崩,这是一种预防措施
补救措施:超时处理,熔断处理等等
dubbo的注册中心(nacos)挂掉之后,服务器调用者还能调用服务提供者吗?
可以。因为dubbo拉取从注册中心拉取服务之后,都会在本地缓存服务列表,所以当注册中心挂掉之后,dobbo会直接从本地获取服务地址进行调用。
大型网站架构演变过程
网站架构演变演变过程
传统架构 → 分布式架构 → SOA架构 → 微服务架构
分布式架构
分布式架构就是将传统结构按照模块进行拆分,不同的人负责不同的模块,不会产生代码冲突问题,方便开发。
SOA架构
SOA架构就是将业务逻辑层提取出来,将相似的业务逻辑形成一个服务,提供外部访问接口,服务之间访问通过RPC调用实现。
微服务架构
微服务类似于SOA架构,但是比SOA架构粒度更细,更轻量。
微服务架构与SOA架构区别
SOA基于WebService和ESP实现,底层基于HTTP协议和使用XML方式传输,XML在网络传输过程中会产生大量冗余。微服务由SOA架构演变而来,继承了SOA架构的优点,同时对SOA架构缺点进行改善,数据传输采用JSON格式,相比于XML更轻量和快捷,粒度更细,更加便于敏捷开发。SOA数据库会存在共享,微服务提倡每个服务连接独立的数据库。