上一篇用 Eureka 实现了服务注册与发现,但还有两个关键问题没解决:

多个服务实例(比如 2 个userservice),怎么让请求 “均匀” 地分给它们?
Eureka 功能太简单,有没有更强大的注册中心?
这篇就用 Ribbon 解决负载均衡,用 Nacos 替代 Eureka(功能更全、国内更常用),手把手实战!

一、Ribbon:让请求 “雨露均沾” 的负载均衡

比如我们部署了 2 个user-service(端口 8081、8082),订单服务调用时,怎么避免只打给一个实例? 这就是 Ribbon 的活儿 ——负载均衡,让请求均匀分配给多个实例。
在这里插入图片描述

1. 为什么加个 @LoadBalanced 就有用?原理揭秘

上一篇在RestTemplate上加了@LoadBalanced注解,就能自动替换http://userservice为真实 IP(比如 8081),背后是 Ribbon 在搞事情,流程如下:
在这里插入图片描述

  1. 拦截请求:Ribbon 的拦截器拦住RestTemplate发的http://userservice/user/1;
  2. 查服务列表:根据userservice这个服务名,去 Nacos/Eureka 拉取实例列表(8081、8082);
  3. 选实例:用负载均衡算法(默认是 “轮询”)从列表里挑一个(比如 8081);
  4. 改地址:把userservice换成 8081,变成http://localhost:8081/user/1,发起真实请求。

2. Ribbon 的 5 种负载均衡策略(小白记 3 个常用的)

在这里插入图片描述
Ribbon 有多种 “选实例” 的算法,默认是轮询(轮流选),其他策略按需选:

策略类核心逻辑适合场景
RoundRobinRule轮询(默认):依次选实例实例性能差不多的情况
RandomRule随机选实例想均匀分散压力
WeightedResponseTimeRule权重选:响应快的实例权重高,被选概率大实例性能不一样(比如高配机器权重高)
ZoneAvoidanceRule基于区域和可用性选择多机房部署
AvailabilityFilteringRule过滤故障实例 + 高并发实例,选健康的追求稳定性

3. 怎么修改负载均衡策略?(2 种方式)

方式 1:代码方式(对所有服务生效)
在订单服务的启动类里,定义一个IRule Bean,指定策略:

import com.netflix.loadbalancer.RandomRule;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RibbonConfig {
    // 注册RestTemplate,加@LoadBalanced开启负载均衡
    @Bean
    @LoadBalanced
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }

    // 配置负载均衡策略为“随机”
    @Bean
    public IRule randomRule() {
        return new RandomRule();
    }
}

方式 2:配置文件方式(对指定服务生效,推荐)
只想让订单服务调用userservice时用随机策略,其他服务不变,在订单服务的application.yml里加:

# 对userservice这个服务生效
userservice:
  ribbon:
    # 指定策略类的全路径(随机策略)
    NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule

4. 优化:开启 Ribbon 饥饿加载

Ribbon 默认是 “懒加载”—— 第一次调用服务时才创建客户端,导致第一次请求变慢。
饥饿加载:项目启动时就创建客户端,解决第一次慢的问题,配置如下(订单服务application.yml):

ribbon:
  eager-load:
    enabled: true  # 开启饥饿加载
    clients: userservice  # 对userservice服务饥饿加载(多个服务用逗号分隔)

二、Nacos:替代 Eureka 的 “全能注册中心”

Nacos 是阿里巴巴开源的注册中心,比 Eureka 功能强太多:支持服务注册、配置管理、权重调整、环境隔离,国内互联网公司几乎都在用。

Nacos vs Eureka 对比

特性NacosEureka
服务发现✅✅
配置管理✅❌
主动健康检查✅❌
权重管理✅❌
环境隔离✅❌
AP/CP模式支持切换仅AP

1. 第一步:安装 Nacos(Windows 版,3 步搞定)

  1. 下载:去Nacos 官网下载压缩包(选nacos-server-xxx.zip);
  2. 解压:解压后进入bin目录;
  3. 启动:打开 cmd,执行命令(单机模式):startup.cmd -m standalone

访问:浏览器打开http://localhost:8848/nacos,默认账号密码都是nacos,登录成功就 OK!

2. 第二步:把服务注册到 Nacos(替代 Eureka)
以userservice和orderservice为例,步骤比 Eureka 还简单:
(1)加依赖(父工程 + 子工程)
父工程:在dependencyManagement里加 SpringCloud Alibaba 依赖(管理版本):

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-dependencies</artifactId>
    <version>2.2.5.RELEASE</version>
    <type>pom</type>
    <scope>import</scope>
</dependency>

子工程(userservice/orderservice):加 Nacos 客户端依赖(替换原来的 Eureka 依赖):

<!-- Nacos客户端依赖 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

(2)改配置(application.yml)
删除原来的 Eureka 配置,加 Nacos 地址:

spring:
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848  # Nacos地址
  application:
    name: userservice  # 服务名(和之前一致)

(3)启动服务,验证
启动userservice(可以启动 2 个实例,改端口 8081、8082)和orderservice,登录 Nacos 控制台,在 “服务列表” 里能看到userservice和orderservice,注册成功!

3. Nacos 进阶 1:服务分级存储(集群部署)

实际项目中,服务会部署在不同机房(比如杭州、上海),Nacos 支持 “服务 - 集群 - 实例” 三级存储,让请求优先调用本地机房的实例(延迟低)。
(1)给服务配置集群
比如给userservice配置 “杭州集群(HZ)”,在application.yml里加:

spring:
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        cluster-name: SH  # 集群名称(上海)

再启动一个userservice,配置cluster-name: WH(武汉),Nacos 里就能看到两个集群。
在这里插入图片描述

(2)优先调用本地集群实例
默认策略还是轮询,会跨集群调用,需要改策略为 Nacos 专属的NacosRule,在orderservice的application.yml里加:

userservice:
  ribbon:
    # NacosRule策略:优先本地集群,本地没有才跨集群
    NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule

4. Nacos 进阶 2:权重负载均衡(让强机器多干活)

如果实例性能不一样(比如 8081 是高配机器,8082 是低配),可以给 8081 设更高权重,让它承担更多请求。
操作步骤:

  1. 登录 Nacos 控制台,进入userservice的 “实例列表”;
  2. 找到 8081 实例,点 “编辑”,把 “权重” 改成 2(默认 1),8082 权重保持 1;
  3. 测试:订单服务调用userservice,8081 被调用的概率是 8082 的 2 倍(权重越高,被选概率越大)。
    小技巧:权重设为 0,实例不会被调用(用于下线实例时不影响服务)。

4. Nacos 进阶 3:环境隔离(namespace)

开发、测试、生产环境要分开,避免互相影响,Nacos 用namespace实现隔离。
(1)创建 namespace
Nacos 控制台→“命名空间”→“新建命名空间”;
输入 “名称”(比如dev),“描述”(开发环境),点 “确定”,会生成一个唯一的namespace ID。
在这里插入图片描述
在这里插入图片描述

(2)服务指定 namespace
在userservice的application.yml里加namespace配置(用刚才生成的 ID):

spring:
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
        namespace: 5f666666-xxxx-xxxx-xxxx-666666666666  # 你的namespace ID

这样userservice就只在dev环境可见,其他环境看不到。

6. Nacos vs Eureka(小白记 3 个关键区别)

临时实例和非临时实例
服务注册到Nacos时,可以选择注册为临时或非临时实例,通过下面的配置来设置:

spring:
 cloud:
  nacos :
    discovery:
     ephemeral: false #设置为非临时实例

在这里插入图片描述

对比点NacosEureka
功能服务注册 + 配置管理 + 权重 + 隔离只有服务注册
健康检测临时实例(心跳)+ 非临时实例(主动检测)只有心跳
服务更新推送模式(实时更新)拉取模式(有延迟)

三、Nacos 配置管理:不用重启服务改配置

原来的配置写在application.yml里,改配置要重启服务,Nacos 配置管理能实现 “热更新”(改配置不用重启)。

1. 实战:把配置交给 Nacos 管理

以userservice为例,让它从 Nacos 读取 “日期格式” 配置:
(1)加依赖(userservice)

<!-- Nacos配置管理依赖 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>

(2)创建 bootstrap.yml(引导文件,优先级高于 application.yml)

spring:
  application:
    name: userservice  # 服务名
  profiles:
    active: dev  # 环境(dev开发)
  cloud:
    nacos:
      config:
        server-addr: localhost:8848  # Nacos地址
        file-extension: yaml  # 配置文件格式(yaml)

Nacos 会根据这 3 个信息找配置文件:userservice-dev.yaml(服务名 - 环境。格式)。
(3)Nacos 控制台创建配置文件
进入 Nacos→“配置管理”→“配置列表”→“新建配置”;
在这里插入图片描述
填写:

  • 数据 ID:userservice-dev.yaml(和 bootstrap.yml 对应);
  • 配置格式:YAML;
  • 配置内容:
pattern:
  dateformat: yyyy-MM-dd HH:mm:ss  # 日期格式配置

点 “发布”。

多环境配置共享

  1. [服务名].yaml:共享配置(所有环境)
  2. [服务名]-[环境].yaml:环境特定配置

优先级:环境配置 > 共享配置 > 本地配置

(4)在代码中读取配置

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RefreshScope  // 关键:开启配置热更新
public class TestController {
    // 读取Nacos中的配置
    @Value("${pattern.dateformat}")
    private String dateformat;

    @GetMapping("/test/date")
    public String testDate() {
        return "当前时间:" + new java.text.SimpleDateFormat(dateformat).format(new java.util.Date());
    }
}

2. 配置热更新:改配置不用重启

在 Nacos 控制台修改userservice-dev.yaml的dateformat为yyyy年MM月dd日 HH:mm:ss;
直接访问http://localhost:8081/test/date,会发现时间格式已经变了 —— 不用重启服务!
关键:加@RefreshScope注解,或者用@ConfigurationProperties绑定配置(适合多配置项)。

四、Nacos 集群搭建(简化版,了解即可)

在这里插入图片描述

生产环境要部署 Nacos 集群(避免单点故障),核心步骤:

  1. MySQL 集群:Nacos 数据存在 MySQL,先搭 MySQL 主从;
  2. 改 Nacos 配置:每个 Nacos 节点改conf/cluster.conf(填所有节点 IP: 端口),改application.properties(填 MySQL 地址);
  3. 启动多个 Nacos 节点:分别改server.port(比如 8848、8849、8850),启动;

Nginx 反向代理:用 Nginx 把请求转发到多个 Nacos 节点,配置示例:

nginx
upstream nacos-cluster {
    server 127.0.0.1:8848;
    server 127.0.0.1:8849;
    server 127.0.0.1:8850;
}
server {
    listen 80;
    server_name localhost;
    location /nacos/ {
        proxy_pass http://nacos-cluster/nacos/;
    }
}

总结:这篇你要记住的 3 个核心

  • Ribbon:解决负载均衡,默认轮询,可改策略(代码 / 配置),开启饥饿加载优化首次请求;
  • Nacos:替代 Eureka,支持服务注册、集群分级、权重调整、环境隔离,功能更全;
  • Nacos 配置管理:实现配置热更新,不用重启服务,核心是bootstrap.yml和@RefreshScope。

更多推荐