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流量重新分配
  • 服务基本无中断
相关推荐
码农开荒路1 小时前
Redis之缓存一致性
数据库·redis·缓存
程序员清风1 小时前
RocketMQ发送消息默认是什么策略,主同步成功了就算成功了?异步写?还是要大部分从都同步了?
java·后端·面试
武昌库里写JAVA1 小时前
VUE vuex深入浅出
vue.js·spring boot·毕业设计·layui·课程设计
代码老y1 小时前
Spring Boot + MyBatis + Vue:从零到一构建全栈应用
vue.js·spring boot·mybatis
starstarzz1 小时前
解决idea无法正常加载lombok包
java·ide·spring·intellij-idea·springboot·web
罗政1 小时前
小区物业管理系统源码+SpringBoot + Vue (前后端分离)
vue.js·spring boot·后端
杨同学technotes1 小时前
Spring Kafka进阶:实现多态消息消费
后端·kafka
oioihoii2 小时前
C++11 Thread-Local Storage:从入门到精通
java·开发语言·c++
YuTaoShao2 小时前
Java八股文——消息队列「场景篇」
java·面试·消息队列·八股文
雨中散步撒哈拉2 小时前
3、做中学 | 二年级上期 Golang数据类型和常量/变量声明使用
开发语言·后端·golang