微服务系列四:热更新措施与配置共享

目录

前言

一、基于Nacos的管理中心整体方案

二、配置共享动态维护

2.1 分析哪些配置可拆,需要动态提供哪些参数

2.2 在nacos 分别创建共享配置

创建jdbc相关配置文件

 创建日志相关配置文件

创建接口文档配置文件

2.3 拉取本地合并配置文件

2.3.1 拉取出现的先后顺序问题——SpringCloud 和 SpringBoot 读取顺序问题

2.3.2 解决措施——添加引导配置文件,放在Springcloud初始化时读取

.2.3.3 引入依赖

2.3.4 新增bootstrap.yaml文件

2.3.5 重启测试购物车功能

2.3.6 同理修改其他微服务的配置文件

三、配置热更新(不停机更新)

3.1 前提条件

3.2 业务实践——热更新购物车容量

3.3 测试热更新效果

四、网关动态路由监听

监听Nacos配置变更

第一步:注入Nacos依赖

第二步:配置bootstrap.yaml文件

第三步:修改application.yaml文件,删除路由

第四步:编写动态路由加载器框架

第五步:更新路由方法拆解

【问题】如何获取RouteDefinition对象?如何更好的转换RouteDefinition对象?

第六步:动态路由加载器完整实现

第七步:在Nacos配置初始化的JSON格式路由

第八步:无需重启,测试网关生效

五、Nacos配置相关知识追问巩固


前言

这是微服务相关技术学习记录的第四篇文章啦!到此为止,微服务开发相关的技术其实已经分享了七七八八了。本篇则是着重介绍微服务配置文件管理相关、配置更新相关的内容。

回顾先前我们学习的微服务开发技术,我们已经解决了以下几个问题:

  • 实现微服务远程调用 (OpenFeign)

  • 实现微服务注册、发现  (nacos)

  • 微服务请求路由、负载均衡  (nacos)

  • 微服务登录用户信息传递  (网关 + 拦截器)

还有哪些问题需要解决呢?

试想一下,假如网关路由发生了更新,你是打算重新启动网关模块更新配置么?那么停机更新会导致服务不可用怎么办?

再来,目前每个微服务都需要编写配置文件,但是实际上里面很多内容是一样的。如果对这一部分公共内容进行修改,是不是又得大规模停机更新微服务呢?

这就概括出了目前微服务配置方面存在的弊端和我们本篇改进的方向:

  • 如何简化重复配置,降低维护成本?
  • 如何实现项目配置的不停机维护?
  • 如何实现网关路由的动态维护?

一、基于Nacos的管理中心整体方案

上述问题我们不难想到,那就将所有配置文件统一管理起来,成立一个管理中心即可。确实,这个管理中心还可以由我们的Nacos一并担任!

整体方案图示

微服务共享的配置可以统一交给Nacos保存和管理,在Nacos控制台修改配置后,Nacos会将配置变更推送给相关的微服务,并且无需重启即可生效,实现配置热更新。

网关的路由同样是配置,因此同样可以基于这个功能实现动态路由功能,无需重启网关即可修改路由配置。

二、配置共享动态维护

我们可以把微服务共享的配置抽取到Nacos中统一管理,这样就不需要每个微服务都重复配置了。

主要步骤如下:

  • 在Nacos中添加共享配置

  • 微服务拉取配置

配置共享最大的好处就是将重复配置封装成一份交Nacos统一管理。其他微服务只需要提供一些配置参数就行了,极大的简化了开发。接下来我们以cart-service为例,实现配置文件拆分。

2.1 分析哪些配置可拆,需要动态提供哪些参数

2.2 在nacos 分别创建共享配置

在 配置管理->配置列表 中点击 新建一个配置:


创建jdbc相关配置文件

spring:datasource:url: jdbc:mysql://${hm.db.host:192.168.186.140}:${hm.db.port:3306}/${hm.db.database}?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true&serverTimezone=Asia/Shanghaidriver-class-name: com.mysql.cj.jdbc.Driverusername: ${hm.db.un:root}password: ${hm.db.pw:123}
mybatis-plus:configuration:default-enum-type-handler: com.baomidou.mybatisplus.core.handlers.MybatisEnumTypeHandlerglobal-config:db-config:update-strategy: not_nullid-type: auto
  • 数据库ip:通过${hm.db.host:192.168.150.101}配置了默认值为192.168.150.101,同时允许通过${hm.db.host}来覆盖默认值

  • 数据库端口:通过${hm.db.port:3306}配置了默认值为3306,同时允许通过${hm.db.port}来覆盖默认值

  • 数据库database:可以通过${hm.db.database}来设定,无默认值


 创建日志相关配置文件

logging:level:com.hmall: debugpattern:dateformat: HH:mm:ss:SSSfile:path: "logs/${spring.application.name}"

创建接口文档配置文件

knife4j:enable: trueopenapi:title: ${hm.swagger.title:黑马商城接口文档}description: ${hm.swagger.description:黑马商城接口文档}email: ${hm.swagger.email:weizhicong@stu.gpnu.cn}concat: ${hm.swagger.concat:weizhicong}url: https://www.weizhicong.cnversion: v1.0.0group:default:group-name: defaultapi-rule: packageapi-rule-resources:- ${hm.swagger.package}
  • title:接口文档标题,我们用了${hm.swagger.title}来代替,将来可以有用户手动指定

  • email:联系人邮箱,我们用了${hm.swagger.email:weizhicong@stu.gpnu.cn},默认值是weizhicong@stu.gpnu.cn,同时允许用户利用${hm.swagger.email}来覆盖。

2.3 拉取本地合并配置文件

现在线上的配置文件创建好了,我们需要想办法让微服务项目接下来拉取共享配置。将拉取到的共享配置与本地的application.yaml配置合并,完成项目上下文的初始化。但是这其中存在一些拉取的问题,让我们逐步分析。

2.3.1 拉取出现的先后顺序问题——SpringCloud 和 SpringBoot 读取顺序问题

读取Nacos配置是发生在SpringCloud上下文初始对象(ApplicationContext)时发生的,而Nacos地址配置在application.yaml却是SpringBoot启动时才发生的。也就是说在读取Nacos配置时,根本不知道去哪里读取Nacos地址信息。从而造成无法加载Nacos配置文件的问题。

2.3.2 解决措施——添加引导配置文件,放在Springcloud初始化时读取

.2.3.3 引入依赖

在cart-service模块引入依赖:

  <!--nacos配置管理--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId></dependency><!--读取bootstrap文件--><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap</artifactId></dependency>

2.3.4 新增bootstrap.yaml文件

在cart-service中的resources目录新建一个bootstrap.yaml文件:

spring:application:name: cart-service # 服务名称profiles:active: devcloud:nacos:server-addr: 192.168.186.140 # nacos地址config:file-extension: yaml # 文件后缀名shared-configs: # 共享配置- dataId: shared-jdbc.yaml # 共享mybatis配置- dataId: shared-log.yaml # 共享日志配置- dataId: shared-swagger.yaml # 共享日志配置

2.3.5 重启测试购物车功能

2.3.6 同理修改其他微服务的配置文件

user-service成功!

trade-service成功!

item-service成功!

pay-service成功!

联调测试成功!


三、配置热更新(不停机更新)

配置热更新 :当我们修改配置文件中的参数属性时,无需重启服务即可生效。

3.1 前提条件

3.2 业务实践——热更新购物车容量

购物车业务,购物车数量有一个上限,默认是10,对应代码如下:

第一步:创建容器配置类,并添加@ConfigurationProperties注解指定服务配置

第二步:注入使用修改业务代码

第三步:增加Nacos配置

文件名称由三部分组成:[服务名]-[spring.active.profile].[后缀名]

  • 服务名:我们是购物车服务,所以是cart-service

  • spring.active.profile:就是spring boot中的spring.active.profile,可以省略,则所有profile共享该配置

  • 后缀名:例如yaml

3.3 测试热更新效果

四、网关动态路由监听

目前,我们的网关路由是写死在配置文件的。一旦路由有所变动,必须重启网关才能生效。对此我们希望网关路由也能和上一小节的配置热更新一样,动态维护,无需停机即可更新。

但是,网关的路由配置全部是在项目启动时由org.springframework.cloud.gateway.route.CompositeRouteDefinitionLocator在项目启动的时候加载,并且一经加载就会缓存到内存中的路由表内(一个Map),不会改变。也不会监听路由变更,

所以,我们无法利用上节课学习的配置热更新来实现路由更新。

因此,我们必须监听Nacos的配置变更,然后手动把最新的路由更新到路由表中。这里有两个难点:

  • 如何监听Nacos配置变更?

  • 如何把路由信息更新到路由表?

监听Nacos配置变更

官方文档:Nacos 监听配置 Java SDKicon-default.png?t=O83Ahttps://nacos.io/zh-cn/docs/sdk.html

第一步:注入Nacos依赖

第二步:配置bootstrap.yaml文件

spring:application:name: hm-gateway # 服务名称profiles:active: devcloud:nacos:server-addr: 192.168.186.140:8848 # nacos地址config:file-extension: yaml # 文件后缀名shared-configs: # 共享配置- dataId: shared-log.yaml # 共享日志配置

第三步:修改application.yaml文件,删除路由

server:port: 8080 # 网关端口 前端请求统一处理hm:jwt:location: classpath:hmall.jksalias: hmallpassword: hmall123tokenTTL: 30mauth:excludePaths:- /search/**- /users/login- /items/**- /hi

第四步:编写动态路由加载器框架


@Slf4j
@Component
@RequiredArgsConstructor
public class DynamicRouteLoader {// 用来获取ConfigServer中的配置信息,与nacos建立连接private final NacosConfigManager nacosConfigManager;private final String dataId = "gateway-routers.json";private final String group = "DEFAULT_GROUP";@PostConstruct // 初始化方法,这个Bean一初始化就会执行public void initRouteConfigListener() throws NacosException {//1. 项目启动,先拉取一次配置,并且添加监听器String configInfo = nacosConfigManager.getConfigService().getConfigAndSignListener(dataId, group, 3000, new Listener() {@Override// 线程池public Executor getExecutor() {return null;}@Overridepublic void receiveConfigInfo(String s) {//TODO 2. 监听器,当配置发生变化时,需要更新路由表}});// 3.第一次读取到配置,也需要更新到路由表updateConfigInfo(configInfo);}public void updateConfigInfo(String configInfo) {// TODO 更新路由表}
}

第五步:更新路由方法拆解

更新路由要用到org.springframework.cloud.gateway.route.RouteDefinitionWriter这个接口:

【问题】如何获取RouteDefinition对象?如何更好的转换RouteDefinition对象?

我们知道通过前面编写的这个方法可以获取到字符串格式的配置文件,保存在configInfo。它就和我们的配置文件一模一样,只不过是字符串表示。

所以第一个问题:如何获取RouteDefinition对象?我们需要解析字符串形式的yaml文件,将它转成java对象。

但是啊,将yaml文件转成Java的对象比较困难,那么什么格式转java对象比较方便呢?——JSON格式。

所以第二个问题:如何更好的转换RouteDefinition对象?我们将路由等信息存储成JSON格式而不是yaml格式,这样可以更好地转换成Java对象

第六步:动态路由加载器完整实现

package com.hmall.gateway.routers;import cn.hutool.json.JSONUtil;
import com.alibaba.cloud.nacos.NacosConfigManager;
import com.alibaba.cloud.nacos.NacosServiceManager;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.hmall.common.utils.CollUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;import javax.annotation.PostConstruct;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;@Slf4j
@Component
@RequiredArgsConstructor
public class DynamicRouteLoader {private final RouteDefinitionWriter writer;// 用来获取ConfigServer中的配置信息,与nacos建立连接private final NacosConfigManager nacosConfigManager;// 配置文件id 和 分组private final String dataId = "gateway-routers.json";private final String group = "DEFAULT_GROUP";// 保存更新过的路由idprivate final Set<String> routeIds = new HashSet<>();@PostConstruct // 初始化方法,这个Bean一初始化就会执行public void initRouteConfigListener() throws NacosException {//1. 项目启动,先拉取一次配置,并且添加监听器String configInfo = nacosConfigManager.getConfigService().getConfigAndSignListener(dataId, group, 3000, new Listener() {@Override// 线程池public Executor getExecutor() {return null;}@Overridepublic void receiveConfigInfo(String configInfo) {//2. 监听器,当配置发生变化时,需要更新路由表updateConfigInfo(configInfo);}});// 3.第一次读取到配置,也需要更新到路由表updateConfigInfo(configInfo);}/*** configInfo 是nacos中配置的json字符串* @param configInfo*/public void updateConfigInfo(String configInfo) {// 更新路由表log.debug("监听到路由配置变更,{}", configInfo);// 1.反序列化List<RouteDefinition> routeDefinitions = JSONUtil.toList(configInfo, RouteDefinition.class);// 2.更新前先清空旧路由// 2.1.清除旧路由for (String routeId : routeIds) {writer.delete(Mono.just(routeId)).subscribe();}routeIds.clear();// 2.2.判断是否有新的路由要更新if (CollUtils.isEmpty(routeDefinitions)) {// 无新路由配置,直接结束return;}// 3.更新路由routeDefinitions.forEach(routeDefinition -> {// 3.1.更新路由writer.save(Mono.just(routeDefinition)).subscribe();// 3.2.记录路由id,方便将来删除routeIds.add(routeDefinition.getId());});}
}

第七步:在Nacos配置初始化的JSON格式路由

当前还没配置Nacos时,此时的网关没有任何路由,可以测试一下:

第八步:无需重启,测试网关生效

五、Nacos配置相关知识追问巩固

1. 如何简化重复配置,降低维护成本?谈谈具体实施步骤

2. 如何解决读取远程Nacos配置时无法从Springboot中获取到Nacos地址的配置信息?

3. 如何实现配置热更新?谈谈具体的实施步骤

4. 如何实现动态路由热更新?谈谈具体的实施步骤

5. 请你谈谈 @PostConstruct 注解的作用?

6. 请你谈谈监听Nacos配置中如何获取Nacos的ConfigServer中的配置信息?

7. 谈谈更新路由监听器方法是怎么实现的?你是否赞同采用先删除后更新的策略,为什么?

8. Nacos提供了RouteDefinitionWriter接口用于实现添加路由,路由对象是RouteDefinition类型的。请问你在路由监听中如何获取该对象?如何更好、更快的获取该对象?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/2276.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

抖音短剧小程序上线:短视频平台的全新娱乐体验

抖音短剧小程序的开发是一个结合了创意与技术的过程&#xff0c;旨在通过简洁而富有吸引力的方式&#xff0c;向用户提供高质量的短剧内容。随着移动互联网的快速发展&#xff0c;短视频平台成为了人们日常生活中不可或缺的一部分&#xff0c;而短剧作为一种新兴的内容形式&…

【解决】Ubuntu18.04 卸载python之后桌面异常且终端无法打开,重启后进入tty1,没有图形化界面

我因为python版本太过于混乱 &#xff08;都是为了学习os&#xff09; &#xff0c;3.6—3.9版本我都安装了&#xff0c;指向关系也很混乱&#xff0c;本着“重装是最不会乱”的原则&#xff0c;我把全部版本都卸载了。然后装了3.9 发现终端打不开了&#xff0c;火狐浏览器的图…

Golang | Leetcode Golang题解之第521题最长特殊序列I

题目&#xff1a; 题解&#xff1a; func findLUSlength(a, b string) int {if a ! b {return max(len(a), len(b))}return -1 }func max(a, b int) int {if b > a {return b}return a }

【英特尔IA-32架构软件开发者开发手册第3卷:系统编程指南】2001年版翻译,2-13

文件下载与邀请翻译者 学习英特尔开发手册&#xff0c;最好手里这个手册文件。原版是PDF文件。点击下方链接了解下载方法。 讲解下载英特尔开发手册的文章 翻译英特尔开发手册&#xff0c;会是一件耗时费力的工作。如果有愿意和我一起来做这件事的&#xff0c;那么&#xff…

二叉树中的深搜 算法专题

二叉树中的深搜 一. 计算布尔二叉树的值 计算布尔二叉树的值 class Solution {public boolean evaluateTree(TreeNode root) {if(root.left null) return root.val 0? false: true;boolean left evaluateTree(root.left);boolean right evaluateTree(root.right);return…

VisionPro —— CogPatInspectTool对比工具

一、CogPathInspectTool工具简介 CogPathInspectTool是VisionPro重要的工具&#xff0c;主要用于缺陷检测&#xff0c;通过将当前图像与“训练图像”对比&#xff0c;获取“原始差异图像”&#xff0c;再将“原始差异图像”与“阈值图像”进行对比&#xff0c;进而获取“阈值差…

Linux 系统启动

1.Linux系统启动过程 Linux系统启动过程可以分为5个阶段&#xff1a;内核的引导、运行 init、系统初始化、建立终端、用户登录系统。 2.内核引导 当计算机打开电源后&#xff0c;首先是BIOS开机自检&#xff0c;按照BIOS中设置的启动设备&#xff08;通常是硬盘&#xff09;来启…

Qt 坐标系统与坐标变换

Qt 坐标系统与坐标变换 坐标变换函数 QPainter坐标变换相关函数 分组函数原型功能坐标变换void translate(qreal dx,qreal dy)坐标系统一定的偏移量&#xff0c;坐标原点平移到新的点void rotate(qreal angle)坐标系统顺时针旋转-一个角度void scale(qreal sx,qreal sy)坐标…

奥数与C++小学四年级(第十六题 魔法学院)

参考程序代码&#xff1a; #include <iostream>int main() {int maxStudentsPerSubject 9; // 每个科目最多有9个比哈利高的学生int students maxStudentsPerSubject * 3; // 三个科目// 加上哈利自己int totalStudents students 1;std::cout << "最大学…

高空作业未系安全带监测系统 安全带穿戴识别预警系统

在各类高空作业场景中&#xff0c;安全带是保障作业人员生命安全的关键防线。然而&#xff0c;由于人为疏忽或其他原因&#xff0c;作业人员未正确系挂安全带的情况时有发生&#xff0c;这给高空作业带来了巨大的安全隐患。为有效解决这一问题&#xff0c;高空作业未系安全带监…

备战“双11”丨AI+物流:你的快递会有什么变化?

背景 在中国&#xff0c;每天有数以亿计的包裹在运输&#xff0c;尤其在电商促销季如“双十一”、“618”期间&#xff0c;快递量更是激增。快递物流行业面临人员短缺、配送效率低下和物流承载能力有限等问题。快瞳科技提供的AI识别解决方案通过智能化手段提高工作效率和配送准…

Cesium的PickModel浅析

Cesium中的拣选(pick)具备一套比较巧妙机制&#xff0c;。可以简单的认为&#xff0c;Cesium的常规的鼠标拣选是基于最终成图做的。就如同下面的这幅画&#xff0c;红色的箭头指向牛的臀&#xff0c;而不是后面的房子&#xff0c;是因为牛挡住了房子。这是一种比较自然的理解方…

针对告警数量、告警位置、告警类型等参数进行统计,并做可视化处理的智慧能源开源了

一、简介 AI视频监控平台, 是一款功能强大且简单易用的实时算法视频监控系统。愿景在最底层打通各大芯片厂商相互间的壁垒&#xff0c;省去繁琐重复的适配流程&#xff0c;实现芯片、算法、应用的全流程组合&#xff0c;减少企业级应用约 95%的开发成本&#xff0c;在强大视频算…

【教学类-12-10】20241104《连连看竖版6*6 (3套题目空心图案)中2班

【教学类-12-09】20230228《连连看竖版6*6 &#xff08;3套题目空心图案&#xff08;中班教学&#xff09;》&#xff08;中班主题《玩具总动员》)-CSDN博客文章浏览阅读121次。【教学类-12-09】20230228《连连看竖版6*6 &#xff08;3套题目空心图案&#xff08;中班教学&…

Windows系统使用diskpart命令格式化U盘

Windows系统使用diskpart命令格式化U盘 1、以管理员身份运行CMD命令提示符 2、输入【diskpart】进入diskpart命令行界面 3、输入【list disk】命令&#xff0c;查看本机所有磁盘 4、这里以格式化【磁盘4】为列&#xff0c;输入【select disk 4】命令&#xff0c;选择磁盘4…

Uni商城-开源项目

目录 概述 技术选型 前端 后端 数据库&#xff1a;MongoDB 项目原型图 项目实现效果图 Tabbar页面 微信一键登录 ​编辑加入购物车 ​编辑 首页商品分类过滤 商品搜索 商品下单 收货地址选择/管理&#xff08;内置组件&#xff09; ​编辑 购物车下单 ​编辑 优…

电脑开机显示无信号然后黑屏怎么办?

当我们打开电脑时&#xff0c;遇到电脑屏幕出现了无信号并且黑屏&#xff0c;常常会让我们感到困扰。很多朋友都会遇到显示器无信号的情况&#xff0c;其实这种故障是很好解决的&#xff0c;但是电脑小白&#xff0c;并不知道电脑屏幕显示无信号然后黑屏了要怎么去修复。不用担…

Linux Kernel Programming (个人读书笔记)

目录 Before everything begins 笔者的环境 关于如何在Arch Linux下载Virtual Box 下载一个镜像&#xff0c;然后开启一个简单的虚拟机 在Ubuntu虚拟机下东西 配置我们的内核 啥是KConfig和KBuild? 构建内核配置选择 启动&#xff01;一个好的内核配置的开始 使用分发…

【优先算法】双指针

✨✨欢迎大家来到Celia的博客✨✨ &#x1f389;&#x1f389;创作不易&#xff0c;请点赞关注&#xff0c;多多支持哦&#x1f389;&#x1f389; 所属专栏&#xff1a;优先算法 个人主页&#xff1a;Celias blog~ 目录 ​​​​​​移动零 复写零 快乐数 盛水最多的容器 …

公务员考试需要注意哪些事项,这里简单的介绍一下

大家好&#xff0c;我是一颗甜苞谷&#xff0c;今天分享一下公务员考试需要注意哪些事项。 公务员考试注意事项 公务员考试是许多求职者梦寐以求的职业生涯起点&#xff0c;但要成功通过这场竞争激烈的考试&#xff0c;需要做好充分的准备。以下是一些关键的注意事项&#xff…