Springboot仿抖音app开发之Nacos 分布式服务与配置中心(进阶)

Springboot仿抖音app开发之评论业务模块后端复盘及相关业务知识总结
Springboot仿抖音app开发之粉丝业务模块后端复盘及相关业务知识总结
Springboot仿抖音app开发之用户业务模块后端复盘及相关业务知识总结
Springboot仿抖音app开发之消息业务模块后端复盘及相关业务知识总结
Springboot仿抖音app开发之用短视频务模块后端复盘及相关业务知识总结
Springboot仿抖音app开发之RabbitMQ 异步解耦(进阶)

数值同步入库

在之前的项目中,我们关于数据库的选型分别将用户id,nickname等存在mysql中,er将计数,验证码这些符合redis特性的数据存在redis中,这样在原来数据库中用户的计数信息就会显示为0,我们想要在用户的计数信息显示相关数据,,需要进行数值同步入库

java 复制代码
        // 点赞完毕,获得当前在redis中的总数
        // 比如获得总计数为 1k/1w/10w,假定阈值(配置)为2000
        // 此时1k满足2000,则触发入库

配置中心就是nacos,我们通过控制台修改阈值而不需要在代码中对阈值进行修改,当点赞数达到阈值数量之后,则自动保存到数据库中。

nacos的作用是什么

1. 服务发现与注册

  • 服务注册:各个微服务启动时自动向Nacos注册中心注册自己的服务信息(IP地址、端口号等)
  • 服务发现:其他服务可以通过Nacos查找需要调用的服务实例
  • 健康检查:定期检查注册的服务是否健康运行,自动剔除不健康的实例

2. 配置管理

  • 集中配置:将所有微服务的配置文件统一存储在Nacos中
  • 动态更新:支持配置的实时推送,无需重启服务即可更新配置
  • 多环境管理:支持dev、test、prod等不同环境的配置隔离
  • 配置版本控制:支持配置的版本管理和回滚

3. 命名空间隔离

  • 多租户:通过命名空间实现不同项目或环境的完全隔离
  • 资源管理:每个命名空间可以独立管理服务和配置

4. 负载均衡

  • 多实例支持:同一服务可以部署多个实例
  • 自动负载均衡:在多个服务实例间自动分发请求

Nacos就像是一个"服务电话簿" + "配置管理员"

1. 服务电话簿的作用 📞

想象您有一个大公司,有很多部门:

  • 用户服务部门(处理用户注册登录)
  • 订单服务部门(处理订单)
  • 支付服务部门(处理支付)

没有Nacos时

  • 用户服务想找订单服务,必须记住订单服务的具体地址(比如:192.168.1.100:8080)
  • 如果订单服务搬到新地址了,用户服务就找不到了
  • 如果订单服务有多个分店,用户服务不知道该找哪一个

有了Nacos后

  • 所有服务启动时都在Nacos这个"电话簿"里登记:我是订单服务,我在XXX地址
  • 用户服务要找订单服务时,问Nacos:"订单服务在哪里?"
  • Nacos回答:"订单服务有3个地址,我给你一个最好的"
  • 如果某个订单服务挂了,Nacos会自动把它从电话簿里删除

2. 配置管理员的作用 📋

没有Nacos时

  • 每个服务都有自己的配置文件
  • 要改个数据库地址,需要一个个服务去改
  • 改完还要重启所有服务

有了Nacos后

  • 所有配置都放在Nacos里统一管理
  • 要改数据库地址,只在Nacos里改一次
  • 所有相关服务会自动收到通知并更新,不用重启

3. 您项目中的实际例子

您的日志显示:

复制代码

复制代码
nacos registry, DEFAULT_GROUP imooc-red-book-nacos 172.22.79.93:8099 register finished

这就是说:您的"红书项目"已经在Nacos电话簿里登记了,告诉Nacos:

  • "我是红书服务"
  • "我在172.22.79.93:8099这个地址"
  • "其他服务可以通过'imooc-red-book-nacos'这个名字找到我"

现在如果您有其他服务(比如用户服务、图片服务等),它们就可以通过Nacos找到您的红书服务,而不需要记住具体的IP地址了!

微服务架构中的服务调用

在一个完整的红书应用中,通常会拆分成多个独立的服务,每个服务负责不同的功能:

可能的服务架构:

  • 用户服务:处理用户注册、登录、个人信息
  • 内容服务:处理笔记发布、编辑、删除
  • 图片服务:处理图片上传、存储、处理
  • 推荐服务:根据用户喜好推荐内容
  • 评论服务:处理评论、点赞功能
  • 消息服务:处理系统通知、私信

实际调用场景举例:

场景1:发布笔记

  1. 用户在前端发布一篇笔记
  2. 内容服务 收到请求,需要:
    • 调用用户服务验证用户身份
    • 调用图片服务上传和处理图片
    • 调用推荐服务更新用户兴趣标签

场景2:查看笔记详情

  1. 用户点击查看某篇笔记
  2. 内容服务 需要:
    • 调用用户服务获取作者信息
    • 调用评论服务获取评论列表
    • 调用推荐服务获取相关推荐

从您的项目来看

您的项目名是imooc-red-book-nacos,从启动日志可以看到它包含了:

  • MongoDB(存储数据)
  • RabbitMQ(消息队列)
  • MinIO(文件存储)
  • Swagger(API文档)

这看起来像是一个主要的业务服务,其他服务可能需要调用它来:

  • 获取用户发布的内容
  • 获取图片资源
  • 处理业务逻辑

简单比喻

就像一个购物中心:

  • 您的红书服务是"商品展示中心"
  • 用户服务是"会员中心"
  • 支付服务是"收银台"
  • 当用户要买东西时,收银台需要找到商品展示中心确认商品信息和价格

所以其他服务找红书项目,是为了获取它提供的数据和功能,完成完整的业务流程!

为什么同一个服务要在nacos上注册多个端口,这样的作用是什么

负载均衡和高可用性

简单比喻:餐厅的多个收银台

想象一个热门餐厅:

  • 只有1个收银台:客人排长队,效率低,收银员累坏了
  • 3个收银台:客人分流,效率高,某个收银员休息也不影响营业

在微服务中的实际应用

场景:红书项目有大量用户访问

单实例部署(只有一个端口):

复制代码
红书服务: 172.22.79.93:8099 ← 所有用户请求都打到这里
  • 服务器压力大,可能卡顿或崩溃
  • 如果这个服务挂了,整个应用就不能用了

多实例部署(多个端口):

复制代码
红书服务实例1: 172.22.79.93:8099
红书服务实例2: 172.22.79.93:8100  
红书服务实例3: 172.22.79.93:8101

具体好处:

1. 分担压力 💪

  • 1000个用户请求可以分配给3个实例处理
  • 每个实例只需要处理约333个请求
  • 响应速度更快

2. 高可用性 🛡️

  • 如果8099端口的服务挂了
  • 用户请求会自动转到8100或8101
  • 用户感觉不到任何异常

3. 平滑升级 🔄

  • 升级时可以先停掉一个实例(比如8099)
  • 其他实例继续提供服务
  • 升级完成后再启动,用户无感知

Nacos的自动调度

当其他服务要调用红书服务时:

复制代码

复制代码
用户服务: "Nacos,我要调用红书服务"
Nacos: "红书服务有3个实例可用,我给你分配8100端口这个"

图片服务: "Nacos,我也要调用红书服务" 
Nacos: "我给你分配8101端口这个,平衡一下负载"

构建服务注册到Nacos

引入相关依赖,在yml文件中完成配置

java 复制代码
#  application:
#    name: imooc-red-book-nacos
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848  # nacos 所在的地址
        username: nacos
        password: nacos

# 打开监控
management:
  endpoint:
    web:
      exposure:
        include: '*'
java 复制代码
   <!-- SpringCloud 依赖 -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>2020.0.4</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <!-- SpringCloud Alibaba 依赖 -->
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.2.6.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

启动项目,我们看到nacos官网显示

服务集群注册到Nacos

我们在yml文件中修改一下端口号的配置就行

java 复制代码
server:
  port: ${port:8099}

我们可以看到有多个实例

Nacos 实现动态配置管理

bootstrap.yml

java 复制代码
spring:
  application:
    name: imooc-red-book-nacos  # 应用名称,用于在Nacos中标识配置
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848   # Nacos服务器地址
        file-extension: yaml          # 配置文件格式
        username: nacos              # Nacos认证用户名
        password: nacos              # Nacos认证密码

具体作用和重要性

1. 优先级最高的配置加载

bootstrap.yml是Spring Cloud应用中优先级最高的配置文件,它在application.yml之前加载,确保:

  • 应用启动时首先连接到Nacos配置中心
  • 从Nacos获取的配置能够覆盖本地配置
  • 解决配置依赖问题

2. 配置中心连接信息

java 复制代码
spring:
  application:
    name: imooc-red-book-nacos  # 应用名称,用于在Nacos中标识配置
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848   # Nacos服务器地址
        file-extension: yaml          # 配置文件格式
        username: nacos              # Nacos认证用户名
        password: nacos              # Nacos认证密码

3. 配置文件查找规则

根据这个配置,应用会按以下规则在Nacos中查找配置:

  • Data ID : ${spring.application.name}-${spring.profiles.active}.${file-extension}
  • 对于您的项目:imooc-red-book-nacos-dev.yaml
  • Group: DEFAULT_GROUP(默认)
  • Namespace: public(默认)

为什么需要bootstrap.yml?

1. 解决配置加载顺序问题

复制代码
启动顺序:
bootstrap.yml → 连接Nacos → 获取远程配置 → application.yml → 应用启动

2. 避免循环依赖

如果将Nacos配置放在application.yml中:

  • 应用需要先加载本地配置才能连接Nacos
  • 但又需要从Nacos获取配置来启动应用
  • 形成循环依赖

3. 配置中心的基础连接信息

bootstrap.yml通常只包含:

  • 应用名称
  • 配置中心连接信息
  • 服务发现基础配置

实际工作流程

  1. 应用启动 → 读取bootstrap.yml
  2. 连接Nacos → 使用配置的server-addr和认证信息
  3. 获取远程配置 → 下载imooc-red-book-nacos-dev.yaml(后面注册的一项配置管理)
  4. 合并配置 → 远程配置 + 本地配置
  5. 启动应用 → 使用合并后的完整配置

我们来看测试接口

java 复制代码
@Slf4j
@Api(tags = "Hello 测试的接口")
@RestController
@RefreshScope
public class HelloController {

    @Value("${nacos.counts}")
    private Integer nacosCounts;

    @GetMapping("nacosCounts")
    public Object nacosCounts() {
        return GraceJSONResult.ok("nacosCounts的数值为:" + nacosCounts);
    }


    @ApiOperation(value = "hello-这是一个hello的测试路由")
    @GetMapping("/hello")
    public Object hello() {
        return GraceJSONResult.ok("Hello");
    }

核心注解的作用

1. @RefreshScope 注解

java 复制代码
@RefreshScope
public class HelloController {

这是实现动态配置的关键注解

  • 标记该Bean支持配置刷新
  • 当配置发生变化时,Spring会重新创建该Bean实例
  • 重新注入最新的配置值

2. @Value 注解

java 复制代码
@Value("${nacos.counts}")
private Integer nacosCounts;

动态读取配置值

  • 从配置中心读取nacos.counts的值
  • 支持配置热更新

动态配置管理的完整流程

1. 初始化阶段

java 复制代码
应用启动 → bootstrap.yml连接Nacos → 获取nacos.counts配置 → 注入到nacosCounts字段

2. 运行时动态更新

复制代码
Nacos配置修改 → 推送变更通知 → Spring接收通知 → 重新创建@RefreshScope的Bean → 重新注入新配置值

具体工作机制

配置变更检测

复制代码
// 当你在Nacos中将 nacos.counts 从 123 改为 456 时:

// 变更前
nacosCounts = 123  // 接口返回:nacosCounts的数值为:123

// Nacos推送变更通知后
nacosCounts = 456  // 接口返回:nacosCounts的数值为:456

Bean生命周期管理

java 复制代码
// @RefreshScope 的工作原理:
1. 正常情况:HelloController Bean实例缓存在Spring容器中
2. 配置变更:Spring销毁旧的Bean实例
3. 重新创建:创建新的HelloController实例,重新注入最新配置
4. 请求处理:后续请求使用新实例和新配置值

我们来看测试用例

现在nacos中配置的计数是666,测试接口响应的也是666

我们修改nacos中的配置,将其变成123,再来进行测试

我们看到显示的结果页变成了123

动态配置的优势体现

1. 零停机更新

  • 修改配置后立即生效
  • 不影响正在处理的请求
  • 用户无感知

2. 实时性

  • 配置变更通常在几秒内生效
  • 支持高频配置调整
  • 适合业务参数优化

3. 可测试性

  • 可以通过接口实时查看配置值
  • 便于验证配置是否生效
  • 支持快速回滚

统计数值阈值刷入数据库

1. 动态阈值配置

java 复制代码
@Value("${nacos.counts}")
private Integer nacosCounts;  // 从Nacos动态获取阈值,如2000

作用

  • 阈值可以通过Nacos配置中心动态调整
  • 无需重启应用即可修改触发条件
  • 支持不同环境使用不同阈值

2. Redis计数累积

java 复制代码
// 每次点赞都会让Redis中的计数+1
redis.increment(REDIS_VLOG_BE_LIKED_COUNTS + ":" + vlogId, 1);

流程

复制代码
用户点赞 → Redis计数+1 → 检查是否达到阈值 → 触发批量入库

3. 阈值检查与批量入库

java 复制代码
String countsStr = redis.get(REDIS_VLOG_BE_LIKED_COUNTS + ":" + vlogId);
Integer counts = 0;
if (StringUtils.isNotBlank(countsStr)) {
    counts = Integer.valueOf(countsStr);
    if (counts >= nacosCounts) {  // 关键:阈值比较
        vlogService.flushCounts(vlogId, counts);  // 批量入库
    }
}

完整的工作流程

1. 正常点赞流程

复制代码
用户A点赞 → Redis: vlog:123 = 1
用户B点赞 → Redis: vlog:123 = 2
用户C点赞 → Redis: vlog:123 = 3
...
用户N点赞 → Redis: vlog:123 = 2000  ← 达到阈值

2. 触发入库条件

java 复制代码
if (counts >= nacosCounts) {  // 假设nacosCounts = 2000
    // 当Redis中的计数 >= 2000时,触发数据库更新
    vlogService.flushCounts(vlogId, counts);
}

3. 批量入库操作

java 复制代码
@Transactional
public void flushCounts(String vlogId, Integer counts) {
    Vlog vlog = new Vlog();
    vlog.setId(vlogId);
    vlog.setLikeCounts(counts);  // 将Redis中的总计数写入数据库
    vlogMapper.updateByPrimaryKeySelective(vlog);
}

Nacos拓展 IP漂移技术

VIP的定义

VIP是一个不固定绑定到特定物理网卡上的IP地址,它可以在多台服务器之间"漂移",实现服务的高可用性。

VIP的工作原理

简单比喻:

想象VIP就像一个"移动的门牌号":

  • 有两栋房子(服务器A和B)
  • 门牌号188(VIP)原本挂在A房子上
  • 当A房子出问题时,门牌号自动移到B房子上
  • 客人(用户)始终通过188这个门牌号找房子,不需要记住具体是哪栋房子

技术实现:

复制代码
正常情况:
服务器A: 192.168.1.10 (真实IP) + 192.168.1.100 (VIP) ← 用户访问这个
服务器B: 192.168.1.11 (真实IP)

故障时:
服务器A: 192.168.1.10 (故障)
服务器B: 192.168.1.11 (真实IP) + 192.168.1.100 (VIP) ← VIP漂移到这里

VIP的作用

1. 透明切换

  • 用户始终访问同一个IP地址(VIP)
  • 后端服务器切换对用户完全透明
  • 无需修改客户端配置

2. 高可用保障

  • 主服务器故障时,VIP自动漂移到备用服务器
  • 保证服务连续性

3. 简化管理

  • 管理员只需管理一个对外IP
  • 内部服务器可以随意增减或维护

ip漂移技术中,双击热备和双主热备的作用和区别是啥

双机热备 (Active-Standby)

作用:

  • 高可用性保障:确保服务的连续性,当主服务器故障时能快速切换
  • 故障恢复:自动检测主服务器状态,故障时启动备用服务器
  • IP地址保持:通过VIP(虚拟IP)漂移,用户访问不受影响

工作原理:

复制代码
正常状态:
主服务器A (活跃) ← VIP绑定在这里
备服务器B (待机) ← 监控主服务器状态

故障时:
主服务器A (故障) 
备服务器B (接管) ← VIP漂移到这里

特点:

  • 同一时间只有一台服务器提供服务
  • 备用服务器资源利用率低(处于待机状态)
  • 切换时间通常在几秒到几十秒
  • 实现相对简单,成本较低

双主热备 (Active-Active)

作用:

  • 负载分担:两台服务器同时工作,提高整体性能
  • 资源充分利用:避免备用服务器资源浪费
  • 更高的可用性:即使一台故障,另一台仍能承担全部负载

工作原理:

复制代码
正常状态:
主服务器A (活跃) ← 处理50%流量
主服务器B (活跃) ← 处理50%流量
都绑定VIP或使用负载均衡

故障时:
主服务器A (故障)
主服务器B (活跃) ← 承担100%流量

特点:

  • 两台服务器同时提供服务
  • 资源利用率高
  • 需要数据同步机制(如数据库主主复制)
  • 实现复杂度更高
  • 性能更好,可承担更大负载

主要区别对比

特性 双机热备 双主热备
服务器状态 一主一备 双主同时工作
资源利用率 低(50%) 高(接近100%)
故障切换时间 几秒到几十秒 几乎无感知
数据一致性 相对简单 需要复杂的同步机制
实现复杂度 简单 复杂
性能 单机性能 双机性能
成本 较低 较高
适用场景 一般业务系统 高并发、关键业务

实际应用场景

双机热备适用于:

  • 中小型企业应用
  • 对性能要求不是特别高的系统
  • 预算有限的项目
  • 数据一致性要求严格的场景

双主热备适用于:

  • 大型互联网应用
  • 高并发、高性能要求的系统
  • 7×24小时不间断服务
  • 对用户体验要求极高的场景

IP漂移在两种模式中的应用

双机热备中的IP漂移:

  • VIP从故障主机漂移到备用主机
  • 通过VRRP、Heartbeat等协议实现
  • 漂移过程中会有短暂的服务中断

双主热备中的IP漂移:

  • 通常配合负载均衡器使用
  • 可能有多个VIP或使用DNS轮询
  • 某台服务器故障时,IP流量重新分配
  • 服务基本无中断
相关推荐
520拼好饭被践踏7 分钟前
JAVA+Agent学习day26
java·开发语言·数据结构·学习·agent
郝学胜-神的一滴19 分钟前
力扣 692:巧用小顶堆高效求解前K个高频单词
java·数据结构·python·程序人生·算法·leetcode·职场和发展
zzzll111129 分钟前
SpringBoot 入门与实践指南
java·spring boot·后端
newerp1 小时前
Go :结构体嵌入、sort.Interface 与 io.Reader/Writer
后端
izhameng1 小时前
Spring AI + Spring Boot:从 0 到 1 进化式搭建 LLM 多模型接入
spring boot
SamDeepThinking1 小时前
如何维持缓存的一致性?
后端·面试·程序员
泡海椒1 小时前
还在手动把 Postman 和浏览器的 curl 转成 Java 代码?这个框架让你一键粘贴直接用
后端
用户8181870627461 小时前
第13章 死锁诊断实战
后端
晨曦中的暮雨1 小时前
Redis 有哪些常见数据结构?它们的底层实现和使用场景是什么?
java·后端·八股
枫叶V1 小时前
Prompt Injection 防不住怎么办?从 Source-Sink 模型设计 Agent 安全边界
后端·agent