Spring Cloud:分布式系统的“粘合剂”(六)
专栏Spring Cloud个人主页手握风云目录一、Nacos 健康检查机制二、Nacos 环境隔离三、Nacos 配置中心3.1. 解决痛点3.2. 快速上手四、Nacos VS Eureka4.1. 相同点4.2. 核心差异一、Nacos 健康检查机制作为注册中心Nacos 需要实时感知各个服务实例的运行健康状态这样才能够给服务调用方提供可靠可用的实例信息。Nacos 一共提供了两套完全不同的健康检查实现机制分别是客户端主动上报机制与服务端反向探测机制。客户端主动上报指由服务实例客户端定期向 Nacos 服务端发送心跳以此上报自身存活状态。这套机制默认心跳上报间隔为 5 秒。当 Nacos 超过 15 秒没有收到某个实例的心跳就会把该实例标记为不健康如果持续 30 秒依旧接收不到心跳就会直接把这个实例从服务列表当中删除。服务端反向探测机制则是由 Nacos 服务端主动向服务实例发起健康探测默认探测的时间间隔为 20 秒。即便探测发现实例已经故障只会将实例标记为不健康状态并不会直接把实例从注册列表删除。客户端上报就如同员工主动汇报工作进度服务端探测就相当于领导主动问询员工工作情况。值得注意的是这两种健康检查模式并不能够人为随意选择切换。健康检查的方式是和 Nacos 当中的服务实例类型强绑定在一起的。Nacos 将注册进来的服务实例分为临时实例和非临时实例两种不同实例会自动匹配对应的检测逻辑。临时实例是 Nacos 的默认实例类型。当实例发生宕机超过规定时间就会被 Nacos 从服务列表剔除临时实例配套使用的就是客户端主动心跳上报机制。而非临时实例也叫永久实例即便实例宕机下线也不会被直接从服务列表移除该类型实例采用服务端反向探测的方式做健康检查。想要把实例设置为非临时实例可以在 yaml 配置中进行如下设置重启服务之后即可生效。spring: cloud: nacos: discovery: ephemeral: false在实际使用的过程中会遇到实例类型切换报错的问题。如果一个服务已经注册为临时实例在 IP 和端口不改变的情况下直接修改配置改成非临时实例重启会抛出异常。这是因为 Nacos 会持久保存服务实例的 IP、端口以及实例类型信息不允许同一个服务在相同 IP 端口下混用临时和持久两种实例。解决该问题需要先停止 Nacos 服务删除 data/protocol 目录下保存实例元数据的相关文件再重新启动。# 查找 Nacos 进程 ps -ef | grep nacos kill -9 PID # 删除 raft 文件夹 cd /usr/local/src/nacos/data/protocol rm -rf raft # 启动 Nacos cd /usr/local/src/nacos/bin sudo bash startup.sh -m standalone还有一类常见现象业务服务本身本地运行完全正常但是 Nacos 控制台展示的实例健康状态却为 false。该问题大多出现在非临时实例场景下是 Nacos 服务端反向探测失败导致需要参考阿里云官方文档排查持久实例的 HTTP 或者 TCP 探测相关规则。二、Nacos 环境隔离在企业实际开发当中一套微服务项目通常会划分开发、测试、生产多套环境。开发环境供开发人员调试代码日志级别较低会保留大量调试信息测试环境作为过渡交由测试人员验证功能生产环境面向真实用户会关闭调试日志。不同环境的数据和服务需要相互隔离开来不允许互相调用而 Nacos 就提供了 Namespace 命名空间机制来实现这种环境隔离处于不同命名空间下的服务互相不可见。Nacos 初始状态下所有注册的服务默认都归属于 public 这个内置命名空间。我们可以在 Nacos 控制台的命名空间页面点击新增命名空间按钮填写命名空间名称与描述信息完成创建。创建完成之后系统会生成一串唯一的 Namespace ID后续代码配置需要使用这一串 ID而不是我们填写的命名空间名称。创建好命名空间之后需要在微服务的配置文件中指定该命名空间 ID。对应的配置项为如下该配置没有默认值填入控制台复制得到的命名空间 ID就可以把当前微服务注册到对应的命名空间当中。需要特别留意服务注册的命名空间和配置中心的命名空间是两套独立配置需要分开进行设置。spring: cloud: nacos: discovery: namespace:配置完成后可以对隔离效果进行测试。假设 product‑service 放在 public 命名空间order‑service 配置注册到 dev 命名空间。启动两个服务之后order‑service 在调用 product‑service 时会抛出 “No instances available for product‑service” 的异常找不到目标服务实例。只有把 product‑service 也修改 namespace 配置注册到 dev 命名空间二者才能够正常完成远程调用。三、Nacos 配置中心Nacos 除了可以充当注册中心、实现负载均衡之外同时还具备完整的配置中心能力。命名空间在这里也能够发挥重要作用很适合用来做不同环境之间的配置隔离实现开发、测试、生产环境配置分开管理。3.1. 解决痛点修改配置需重启全量服务多实例运维成本高本地配置文件多人开发易冲突统一集中管理所有微服务配置修改实时生效无需重启。3.2. 快速上手引入依赖nacos-config bootstrapdependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-nacos-config/artifactId /dependency !-- SpringCloud 2020.*之后版本需要引⼊bootstrap-- dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-starter-bootstrap/artifactId /dependency使用 bootstrap.yml 提前加载 Nacos 地址优先级高于 applicationspring: application: name: product-service profiles: active: profile.name cloud: nacos: config: server-addr: 公网 IP namespace: 命名空间IDbootstrap 文件加载时机更早可以在微服务正式启动之前优先从 Nacos 拉取配置再和本地 application 配置做合并。配置中需要填写 Nacos 服务端地址并且保证spring.application.name和控制台的 Data ID 保持一致。另外要区分两组地址配置注册中心使用spring.cloud.nacos.discovery.server‑addr配置中心使用 spring.cloud.nacos.config.server‑addr二者相互独立。控制台新建配置package com.yang.product.controller; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; RefreshScope RestController public class NacosController { Value(${nacos.config}) private String nacosConfig; RequestMapping(/getConfig) public String getConfig() { return 从 Nacos 获取配置项 nacos.config: nacosConfig; } }四、Nacos VS Eureka4.1. 相同点Nacos与Eureka都属于微服务领域的注册中心组件二者存在部分相同的基础能力。二者都可以实现服务注册、服务实例拉取能够满足微服务最基础的服务发现需求这也是早期很多项目可以在两者之间做技术选型替换的重要原因。4.2. 核心差异在整体功能覆盖层面两者有着明显的差距。Eureka的定位比较单一仅仅只承担注册中心的职责只负责服务注册与发现相关工作。而Nacos属于一体化微服务治理平台除了基础的注册中心能力以外还额外提供配置中心、流量管理、动态DNS服务等更多功能一套组件就可以同时解决服务注册和配置管理两类核心问题。从CAP理论的角度来看两款组件的设计模式不一样。Eureka固定遵循AP原则优先保证服务的可用性放弃数据强一致性。Nacos则更加灵活可以根据实例类型切换AP或者CP模式当注册的是临时实例时走AP模式注册非临时持久实例时走CP模式在同一个Nacos集群当中AP和CP两种模式还可以混合同时存在。二者在服务发现的数据同步机制上也存在很大区别。Eureka采用拉模式客户端会每隔30秒主动从服务端拉取服务实例信息本地会缓存服务列表因此服务上下线之后会存在一定的通知延迟。Nacos 采用的是长连接推送模式。客户端和 Nacos 服务端会维持长连接一旦服务实例发生新增、下线、状态变更服务端会实时向订阅的客户端推送变更消息不需要客户端轮询拉取能够更快感知到服务的状态变化。日志中也可以看到对应的推送请求记录直观体现推送机制的运行效果。