Spring Cloud:分布式系统的“粘合剂”(五)

专栏:Spring Cloud

个人主页:手握风云

目录

[一、Nacos 简介](#一、Nacos 简介)

[1.1. 背景](#1.1. 背景)

[1.2. 起源](#1.2. 起源)

[1.3. 生态与业务](#1.3. 生态与业务)

[二、Nacos 安装](#二、Nacos 安装)

[2.1. 获取安装包](#2.1. 获取安装包)

[2.2. Windows 单机部署](#2.2. Windows 单机部署)

[2.3. Linux 单机部署](#2.3. Linux 单机部署)

三、快速上手

[3.1. 引入依赖](#3.1. 引入依赖)

[3.2. 配置服务注册](#3.2. 配置服务注册)

[3.3. 实现远程调用](#3.3. 实现远程调用)

[四、Nacos 负载均衡精细化](#四、Nacos 负载均衡精细化)

[4.1. 手动上下线实例](#4.1. 手动上下线实例)

[4.2. 权重负载均衡](#4.2. 权重负载均衡)

[4.3. 同集群优先访问](#4.3. 同集群优先访问)


一、Nacos 简介

1.1. 背景

2018 年微服务注册中心领域发生了一次关键变动,当年 6 月 Eureka 官方宣布 2.0 版本闭源停止迭代,仅保留 1.X 版本进行基础维护。同年 7 月,阿里巴巴正式开源 Nacos 项目,凭借一站式微服务治理能力迅速在国内开发者群体中走红,成为替代 Eureka 的主流方案。从开源热度来看,Nacos 的 Github Star 数量早已突破 28K,而同期 Eureka 仅有 12K,足以体现国内技术生态对 Nacos 的认可与选择。

1.2. 起源

Nacos 并非从零开发的全新组件,而是阿里将内部三套独立服务整合后统一对外开源的产物,三套组件分别承担不同能力:Configserver 作为非持久化注册中心、VIPServer 提供持久化注册能力、Diamond 专门负责配置管理。整合之后的 Nacos 跳出了单一注册中心的局限,形成一体化产品形态,全称是 Dynamic Naming and Configuration Service,官方定位为面向云原生应用的动态服务发现、配置管理、服务管理综合平台,兼具注册中心与配置中心双重核心能力。

1.3. 生态与业务

在开发语言适配层面,Nacos 具备极强的通用性,几乎覆盖当前行业所有主流编程语言,能够适配不同技术栈的微服务项目。其中包含 Java、Go、C++、Nodejs、Python、Scala 等,无论后端服务采用何种语言开发,都可以快速接入 Nacos 完成服务注册、配置拉取等操作,降低了多技术栈架构下统一治理的成本。

Nacos 对外提供三大核心功能模块,覆盖微服务治理两大核心场景。第一是服务发现与管理,承担传统注册中心的全部职责,完成服务注册、实例健康感知、流量分发;第二是动态 DNS 服务,支持基于域名的服务寻址,适配云原生网络调度需求;第三是动态配置服务,集中统一管理所有微服务的配置项,支持配置实时下发、热更新,无需重启服务即可生效。

  1. Nacos 官网:https://nacos.io/
  2. Github 仓库:https://github.com/alibaba/nacos

二、Nacos 安装

2.1. 获取安装包

Nacos 提供两种压缩格式安装包,分别是 .zip 与 .tar.gz,均可在 Github Releases 页面下载,对应下载地址为 Releases · alibaba/nacos · GitHub

2.2. Windows 单机部署

下载压缩包后,必须解压至无中文、无空格的磁盘路径。解压完成后会生成多个核心文件夹,bin 目录存放 Windows、Linux 两端的启停脚本,conf 目录存放全部配置文件,target 目录内置 Nacos 运行所需 jar 包,同时附带 LICENSE、NOTICE 说明文件。其中 Windows 专用脚本为 startup.cmd 启动文件、shutdown.cmd 停止文件。

Nacos 默认配置为集群模式,直接启动会抛出网络异常,必须手动修改启动参数切换单机模式。使用记事本打开 bin 目录下 startup.cmd 文件,找到 set MODE="cluster" 代码,将 cluster 修改为 standalone,保存文件后才算完成模式切换。

修改完成后双击 startup.cmd 脚本启动服务,控制台会打印 Tomcat、Nacos 启动日志,出现 "Nacos started successfully in standalone mode" 代表启动成功。打开浏览器访问地址 http://127.0.0.1:8848/nacos,能正常打开 Nacos 后台管理页面即部署完成;服务运行后根目录会自动生成 logs 文件夹,所有运行、报错日志都保存在 logs/nacos.log 中。

2.3. Linux 单机部署

先将 nacos-server-2.2.3.zip 安装包上传至服务器 /usr/local/src 目录,执行解压命令 unzip nacos-server-2.2.3.zip,解压后的目录结构、文件夹作用和 Windows 完全一致。

进入 nacos/bin 目录执行启动脚本,bash startup.sh -m standalone。启动后可通过 logs/start.out 文件查看完整启动日志,服务成功启动后,通过 http://服务器IP:端口/nacos 访问管理后台。

三、快速上手

Nacos 完整适配 Spring Cloud Alibaba 生态,并且严格遵循 Spring Cloud 统一的服务注册、服务发现规范。从开发体验上看,接入 Nacos 和过去使用 Eureka 的整体逻辑十分接近,学习成本很低,但二者存在一处核心区别:Eureka 需要开发者单独新建工程、完整部署服务端,而 Nacos 自带可直接运行的服务端程序,只需启动服务端后,在业务微服务中引入对应依赖、填写连接配置就能完成接入。

Nacos discovery · alibaba/spring-cloud-alibaba Wiki · GitHub

3.1. 引入依赖

想要实现服务注册与服务发现,需要分两层引入项目依赖,先统一管控版本,再引入业务所需组件。首先要在父工程的 <dependencyManagement> 节点中导入 Spring Cloud Alibaba 的版本管理 pom,统一全局版本号。这里需要重点注意,Spring Boot、原生 Spring Cloud、Spring Cloud Alibaba 三者有严格的版本对应关系,版本错乱会直接触发各类启动异常,适配规则可以查看阿里云官方版本说明文档。

XML 复制代码
<properties>
	<spring-cloud-alibaba.version>2022.0.0.0-RC2</spring-cloud-alibaba.version>
</properties>

<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-alibaba-dependencies</artifactId>
	<version>${spring-cloud-alibaba.version}</version>
	<type>pom</type>
	<scope>import</scope>
</dependency>

版本锁定完成后,在 order-service、product-service 等业务微服务模块,分别引入两个核心依赖:spring-cloud-starter-alibaba-nacos-discovery 负责对接 Nacos 完成注册发现,spring-cloud-loadbalancer 提供客户端负载均衡能力,两个依赖缺一不可。

XML 复制代码
<dependency>
	<groupId>com.alibaba.cloud</groupId>
	<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
	<groupId>org.springframework.cloud</groupId>
	<artifactId>spring-cloud-loadbalancer</artifactId>
</dependency>

3.2. 配置服务注册

依赖配置完毕后,需要在微服务的 yml 配置文件中填写 Nacos 服务连接地址,这是服务能够成功注册的前置条件。对应的配置键为 spring.cloud.nacos.discovery.server-addr,该配置无默认值,必须手动填写。本地开发场景填写 127.0.0.1:8848,服务器测试 / 生产环境则填写对应服务器 IP 与自定义端口。

XML 复制代码
spring:
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848

3.3. 实现远程调用

改造代码实现微服务间远程调用,改造分为两处核心内容。第一处是请求 URL 改造,抛弃硬编码 IP + 端口的传统写法,直接使用目标服务的 spring.application.name 服务名作为访问域名;第二处是对 RestTemplate 进行增强,新建配置类,在生成 RestTemplate 实例的 @Bean 方法上添加 @LoadBalanced 注解,开启客户端负载均衡,让框架自动根据服务名匹配所有可用服务实例。

java 复制代码
package com.yang.order.service;

import com.yang.order.config.BeanConfig;
import com.yang.order.mapper.OrderMapper;
import com.yang.order.model.OrderInfo;
import com.yang.order.model.ProductInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class OrderService {
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private RestTemplate restTemplate;

    public OrderInfo selectOrderById(Integer orderId) {
        OrderInfo orderInfo = orderMapper.selectOrderById(orderId);
        String url = "http://product-service/product/" + orderInfo.getProductId();
        ProductInfo productInfo = restTemplate.getForObject(url, ProductInfo.class);
        orderInfo.setProductInfo(productInfo);
        return orderInfo;
    }
}

代码改造完成后,即可启动多个微服务完成功能验证。先分别启动 order-service 和 product-service 两个服务,打开 Nacos 后台的服务管理页面,就能查看到两个服务成功注册的记录,此时访问 order 服务的测试接口,就能正常完成跨服务远程调用。如果想要直观验证负载均衡分发效果,可以修改启动端口,启动同一服务的多个实例,反复调用测试接口并打印日志,就能观察到请求会分发到不同实例上。

四、Nacos 负载均衡精细化

4.1. 手动上下线实例

控制台 - 服务详情 - 操作下线 / 上线,下线节点不再接收流量,适用于故障节点临时隔离。

4.2. 权重负载均衡

在实际生产环境中,不同服务器硬件性能会存在差异,我们可以借助 Nacos 的权重负载均衡能力,给性能更好的实例分配更多流量,以此充分利用服务器资源。权重的数值代表实例接收流量的占比,Nacos 控制台中每个服务实例的默认权重为 1,开发者可以直接在控制台编辑实例来修改权重大小。

仅仅修改控制台的权重数值还无法让配置生效。Spring Cloud LoadBalancer 组件本身自带一套负载均衡逻辑,默认并不会读取 Nacos 上设置的权重参数。因此需要在项目配置文件中手动开启 Nacos 专属的负载均衡策略,配置项如下,开启之后框架才会识别实例上配置的权重信息。

java 复制代码
spring:
  cloud:
    loadbalancer:
      nacos:
        enabled: true

在修改权重编辑实例的时候,有可能会报出 Raft 找不到 Leader 节点的 500 异常。这个问题产生的原因是 Nacos 依靠 Raft 算法选举 Leader 节点,会保存之前的集群地址信息,当服务器 IP 发生变化之后,旧的记录就会失效,导致选主失败。对应的解决方式是关闭 Nacos 服务,删除 Nacos 根目录下 data 文件夹里面的 protocol 文件夹,清除旧的元数据缓存,重启之后就可以正常修改实例权重。

4.3. 同集群优先访问

Nacos 引入集群的概念,可以把部署在同一个机房内的服务实例划分到同一个集群当中,因此同集群优先访问,本质上就是同机房优先访问的能力。在真实的微服务项目中,同一个服务往往会部署大量实例,这些实例分布在不同机器,甚至跨多个机房。

举一个典型的业务场景,product‑service 服务一共存在三个实例,其中两个实例部署在上海机房,另外两个实例部署在北京机房。当服务进行远程调用的时候,业务上更希望优先访问本机房内部的实例。因为同一个机房内部属于局域网通信,网络延迟更低、稳定性更好。只有当本地机房的实例全部不可用之后,才去跨机房调用其他集群的实例。

想要实现该效果,首先需要为各个服务实例配置对应的集群名称。以 product‑service 为例,在 yaml 配置文件中通过如下配置指定集群标识,比如 SH 代表上海机房,BJ 代表北京机房。配置完成重启服务之后,就可以在 Nacos 控制台看到实例被归类到对应集群下。如果需要同一服务下不同实例归属不同集群,可以在启动项中添加 VM 选项,给不同端口的实例设置不一样的 cluster‑name 参数。作为调用方的 order‑service,同样需要配置和目标服务相同的集群名称。

java 复制代码
spring:
  cloud:
    nacos:
      discovery:
        cluster-name: BJ

配置全部完成后就可以开展功能测试。正常情况下多次发起接口调用,日志可以看到请求只会分发到和调用方相同集群的实例。我们可以手动将本集群内所有实例执行下线操作,再次发起调用,这时就会自动降级,请求转发到其他集群的实例上,完成跨机房访问。

相关推荐
早点睡9751 小时前
Python 上下文管理器深度剖析:从 with 语法糖到 CPython 底层协议
后端·面试
Cache技术分享1 小时前
503. Java 反射 - 编写 ServiceFactory 类
前端·后端
高频因子挖掘机1 小时前
QuantDash 成交量单位统一实战:从“手”到“股”的跨市场量化数据清洗全流程
后端·算法·github
码农看码1 小时前
Spring Boot 启动到响应:一个 HTTP 请求是怎么走到 Controller 的?
后端
薛定谔的算法2 小时前
NestJS:让 Node.js 后端告别「野路子」
后端·node.js·nestjs
fightcrap2 小时前
DeepSeek Harness:Cordis 插件树与 Agent 主链路
人工智能·后端·程序员
程序猿DD2 小时前
OctaFuse Gateway 2.7.0:按星期计价、用户级模型折扣、百炼ASR模型支持优化
后端·agent
SQL-First布道者2 小时前
全面解构传统持久层框架,拥抱真正的 SQL-First
java·数据库·spring boot·sql·spring·mybatis·spring jdbc
小蒜学长3 小时前
vue旅游攻略网站(代码+数据库+LW)
java·数据库·vue.js·spring boot·后端·旅游