变更通知在开源SpringBoot/SpringCloud微服务中的最佳实践

news2024/12/29 8:57:31

目录导读

  • 变更通知在开源SpringBoot/SpringCloud微服务中的最佳实践
    • 1. 什么是变更通知
    • 2. 变更通知的场景分析
    • 3. 变更通知的技术方案
      • 3.1 变更通知的技术实现方案
    • 4. 变更通知的最佳实践总结
    • 5. 参考资料

变更通知在开源SpringBoot/SpringCloud微服务中的最佳实践

1. 什么是变更通知

  • 变更通知是指数据发生变化后,相对实时地通知到关联端的技术实现方案;
  • 变更通知是在服务拆分的发展过程中,逐渐衍生出的,解耦关联服务的一种技术解决方案;
  • 微服务架构中常说的配置中心就是变更通知的技术集成方案;

2. 变更通知的场景分析

  • 变更通知首先是数据发生了变化,数据变化后的通知实现,数据变化的交互场景列举分析如下:
通知类型模块1模块1数据变更模块2模块2实时变更技术实现方式本文讨论范围
消息通知前端1前端2前端总线等
消息保存前端1后端2Post Ajax请求等
消息通知后端1前端2WebSocket等推送到前端(推数据),也叫消息推送
消息通知后端1前端2前端Http主动轮询(拉数据)
变更通知后端1后端2Redis/ZooKeeper/Etcd/Nacos/MQ等

总结:

  • 变更通知首先是数据(也可叫消息,下同。)发生了变化,然后引起了关联方同步变化;
  • 数据变化可以发生在前端后端之间的任意组合之间,包括前端+前端前端+后端后端+后端,一般只有后端+后端的连锁反应叫变更通知,这也是本文关注的重点;
  • 上表串联了所有常规的交互过程,大家也可以从中理解消息通知变更通知之间的关联关系:只是不同交互方式下的数据变化的叫法罢了;
  • 前端感知后端的数据变化,主要有前端轮询后端推送两种,二者技术实现差异较大,前者技术实现简单,但是后端资源消耗较大,无法承担高并发;后者技术实现较复杂,但是点对点通信效率高(长连接)。这不是本文讲述的重点,但希望能够类比分析下各种交互方式下的技术方案,做到一通百通;
  • 变更通知主要关注的是后端数据变化,但是不是所有的后端数据变化都需要变更通知。一般来说,跨了服务实例,才比较适用变更通知,单个服务实例内,完全可以通过接口引用等方式自行获取到变化的数据;
  • 本文重点关注的是变更通知而不是配置中心,像NacosSpringCloud-ConfigApollo配置中心并不会过多介绍;
  • 本文主要关注后端与后端之间的数据变化机制及技术实现,其发展阶段如下:
变更类型应用发展阶段技术方案技术实现说明
主动获取单实例共享数据库查询数据库数据库查询量不大
主动获取单实例共享内存缓存查询时先查缓存数据库查询量非常大
主动获取多实例分布式缓存使用读写性能极高的分布式缓存组件如:Memcached/Redis
变更通知多实例消息中间件Redis/ZooKeeper/Etcd/MQ/binlog+canal等订阅通知机制

总结:

  • 变更通知是随着服务的高并发、分布式发展而发展的,在单体架构时,因为都在一个服务内,仅通过数据库或者共享缓存即可达到数据共享的目的,不一定需要变更通知
  • 在微服务架构中,也可以采用共享缓存方案,而不是必须使用变更通知变更通知适用于并发高、实时性要求高,且服务解耦的场景;
  • 实时是一个相对概念,在变更通知语境里,一般是指异步监听的方式获取变化的数据(专业术语叫订阅通知);

3. 变更通知的技术方案

  • 变更通知中间件种类较多,基于本人的理解,对比列举如下:
中间件类型实现特点适用场景不足补充说明
Redis基于key的订阅/通知并发高、消息量大NoSQL可读性差,持久化不是必选项,存在数据丢失和审计风险Redis是极度常用的高效内存组件,建议优选;
ZooKeeper基于分布式临时Node创建的订阅/通知可靠性高、实时性高使用的是内存存储,不适合高并发和大量数据的消息变更场景一般是项目中有ZooKeeper,正好可以用作变更通知组件,而不是因为变更通知诉求而引入ZooKeeper
Etcd基于分布式的Key/Value创建的订阅/通知可靠性高、实时性高使用的是内存存储,不适合高并发和大量数据的消息变更场景Etcd的实现参考了ZooKeeper,一个是Go语言编写、一个是Java语言
MQ异步消息协议可靠性高、并发高、消息量大组件较重包括:Kafka/RocketMQ/RabbitMQ/ActiveMQ等,非常适合电商优惠卷等场景使用
binlog+canal针对MySQL的数据变更监听方案直接监听数据库表字段变化只适用于MySQL,而MySQL使用量正逐年下降只是监听了MySQL的数据表变化,一般还需要配合其它的变更通知组件来配合使用,如:ZooKeeper
配置中心服务端推送把配置中心组件当成业务配置中心组件重、可靠性低、实时性低配置中心严格来说是个变更通知的解决方案,而上面列举的中间件是纯技术组件,二者的维度不太一样;
配置中心一般和注册中心配合使用,因为它本身也需要注册至服务中心,如:ApolloSpringCloud-Config;有些干脆就被注册中心兼任,如Nacos

总结:

  • 变更通知一般来说是微服务中的增强功能,不建议因为有变更通知需求就新增一个组件。如果系统中已经有了Redis,就建议优先选择Redis,因为其性能高、消息存储量大。但Redis是NoSQL存储结构,可读性较差;Redis也有可能没有开启持久化导致数据丢失;Redis也缺失了类似关系数据库自带的操作审计,一旦数据出现了异常,将很难知道是谁做了什么;
  • ZooKeeper/Etcd则比较适合系统中已经引入该组件了,且变更通知消息数量较小的场景;
  • MQ比较适用于可靠性高、消息量巨大的场景,值得单独引入。如:大型电商的活动卡券配置等场景;
  • binlog+canal这个特定组合一般不建议单独使用,一般是canal把变更数据发送给其它变更通知Server,然后在业务模块订阅变更通知Server的这个变化数据,并做相应的业务处理。其它Server可以是ZooKeeper/Etcd/Redis等;
  • 一般来说,配置中心包含了单独的配置规则界面和变更通知的能力,拆箱即用,效果当然较好。但并不是所有的变更通知都需要重量级的配置中心,不是非要在配置中心去配置变更数据的,就都没有必要用它;业务需要使用到配置中心组件时,建议在选定注册中心后,再来决策选择其配置中心
  • 变更通知有非常多的实现方式,讲讲本人实际经历的业务场景:
场景类型业务诉求微服务架构微服务技术栈方案说明
场景1DB数据变更立即触发定时任务微服务架构spring+mysql+binlog+canal+ZooKeeper基于spring自研微服务框架
场景2-1业务阈值在1天内生效微服务云原生架构SpringBoot+Redis+PostgreSQL1.依赖k8s提供服务发现等;
2.依赖redis限流;
场景2-2业务阈值在1天内生效微服务私部署架构SpringBoot1.部署至客户机房,不依赖Redis/DB;
2.使用Nginx做负载均衡,也不需要服务注册和发现;
场景3业务阈值在5分钟内生效微服务云原生架构SpringBoot+Redis1.依赖k8s提供服务发现等;
2.依赖redis限流;
场景4业务阈值在立即生效SpringCloud微服务架构SpringBoot+Redis+Nacos1.依赖Nacos提供服务发现等;
2.依赖redis限流;
  • 补充说下上述业务场景的技术选型限定条件:
    • 场景1:DB数据变更立即触发定时任务:当时刚刚时兴微服务,我所在公司1的部门基于spring自研了一个低代码平台,我们需要实时监听数据的变化,以触发不同的定时任务,正好平台中也引入了canal开源组件,用于监听mysql的binlog
      变化,于是就选定了canal方案,这样就不用定时轮询数据库了,也不用和增删改数据的服务耦合了;
    • 场景2:业务阈值在1天内生效场景2-1场景2-2其实对应同一个目标:我所在公司2的部门希望设计一套架构、一套代码,既能满足云上微服务架构,也能够支持私部署微服务架构。当时云上选型为云原生微服务架构,完全基于k8s+非侵入式的链路追踪中间件,我们基本上只使用最简单的SpringBoot+Redis即可;而私部署则继续沿用了这套架构和代码,只不过移除了k8s、redis、服务注册和服务发现,仅使用Nginx做服务负载均衡;
    • 场景3:业务阈值在5分钟内生效:则是我所在公司2的业务团队认为一天生效对业务影响较大,需要调整为5分钟内生效;
    • 场景4:业务阈值在立即生效:则是我所在公司2的另一个新项目,在场景3代码架构的基础上,使用SpringCloud套件替换了k8s,同时业务也更复杂,业务上必须保证实时生效;
  • 单独来说上面的每个业务场景,都可以多种技术实现。本人仅站在过来人的角度,逐一展开分析。

3.1 变更通知的技术实现方案

  • 场景1的实现方案:单独部署了一个Canal服务,用于监听binlog变化,在Canal服务中又集成了ZooKeeper客户端,Canal收到变化的数据后,通过ZooKeeper推送至订阅的业务微服务;

  • 场景2的实现方案:经过分析,私部署不需要变更通知,因为私部署不带数据库,业务阈值是配在yaml中,修改后隔离重启服务即可;云原生微服务则因为数据刷新后1天内生效即可,但为了考虑私部署和云原生架构的统一,所以采用了Guava+持久层的本地缓存方案,Guava缓存的有效期设置为24小时,过期后就会重新从PostgreSQL/yaml中获取。但由于云原生的运维不接收直接修改数据库阈值数据,于是又配套开发了一个小的命令行工具(也可以做成Web运维平台),用于专门更改数据库表的字段值。

    从中可以看出:

    • 因为要兼顾云原生和私部署场景,所以需要选择两种场景下都能使用的本地缓存方案:Guava;
    • 因为缓存刷新的时效要求低,不使用变更通知也是完全可行的。
  • 场景3的实现方案:场景3其实是场景2的延续,只是现在数据生效的时间从1天变成了5分钟,考虑技术方案的延续性,在云原生方案中,新增了一个定时任务+Redis,用于刷新缓存,交互逻辑如下图所示:
    缓存刷新

    说明:

    • 第1次请求到业务服务时,Guava缓存中也没有数据,则需要业务服务查询一次Database并把数据缓存至Guava,流程为蓝色①→②箭头所示;
    • 第2次请求到业务服务时,Guava缓存中已经有了数据,则只需要直接返回数据即可,流程为绿色①所示;
    • 当用运维工具更新数据时,同时也会清理掉Redis的缓存标记,一旦ScheduleJob获取的Redis Key(采用redis的setNX语法)不一致时,则会让Guava缓存失效,流程为红色的①→②→③→④箭头所示;
    • 后面再有请求过来时,会重新执行上面的第1步和第2步;

    总结:

    • 场景3仅在场景2的基础上迭代增加了虚线框框中的2个小功能点代码就可以了,代码延续性较好;
    • ScheduleJob设置为1分钟就可以满足5分钟内生效的业务诉求了;
    • 回过头来看看场景2:其实并没有做变更通知,只是采用了Guava自带的缓存过期机制而已;场景3其实也可以采用Guava自带的缓存过期机制,但是会导致微服务需要频繁的穿透缓存去查询数据库,得不偿失;场景3的实际做法则兼顾了准实时性和便利性:只有命令行工具变更了数据时,缓存才会刷新。另外场景3也没有做到变更通知,只是变相的达到了准实时变更通知的效果。
  • 场景4的实现方案:场景4是在复用场景3的代码框架的基础上,要求做到数据变更实时通知。此时项目中虽然已引入了SpringCloud的多个组件,但是业务参数配置都有单独的配置界面,无须使用配置中心。考虑到Redis其实也有变更通知的能力,此处正好可以在场景3的基础上继续迭代,去掉ScheduleJob,增加Redis订阅通知的代码即可。

4. 变更通知的最佳实践总结

  • 需要搞清楚什么是变更通知,什么是配置中心,不要因为有变更通知的需求就上配置中心,这样有可能把系统搞得非常复杂;
  • 好的设计都要顺势而为,首先需要了解系统的需求到底是什么,是不是一定要做变更通知,如本人列举的项目实践中就多次未使用变更通知组件,但是达到了变更通知的效果;
  • 如果只需要做变更通知,不需要独立的配置中心,建议优选Redis,因为它可以兼顾业务限流、高速缓存、不规则数据的处理(NoSQL)等,很有可能Redis就已经存在于项目中了;
  • 如果数据量非常庞大,还要支持复杂的规则,比如消息确认和重传等,则建议采用MQ(Kafka/RocketMQ/RabbitMQ/ActiveMQ);
  • 有些场景下的变更通知非常适合使用配置中心,如:SpringCloud-Gateway的路由规则yaml配置,就非常适合放在配置中心(如:Nacos等);当然如果使用的是k8s,则建议直接使用其ConfigMap;

5. 参考资料

  • [1]深入浅出阿里数据同步神器:Canal原理+配置+实战全网最全解析!
  • [2]图文解析 Nacos 配置中心的实现
  • [3]apollo 基本原理
  • [4]Spring Cloud Config 原理简介和实现

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

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

相关文章

IDEA 设置为护眼的豆沙绿

代码区域设置成护眼色 先打开 IDEA 的设置界面,然后按照下图按顺序店了设置就可以了 这个时候,可以看到,只有代码区域别成了护眼色,其他地方还是白的刺眼,我们来一个一个的解决掉 左侧的文件页修改为护眼色 还是先…

CNN(五):DenseNet+SE-Net实战

🍨 本文为🔗365天深度学习训练营中的学习记录博客🍖 原作者:K同学啊|接辅导、项目定制 SE-Net(Squeeze-and-Excitation Networks)是ImageNet2017(ImageNet收官赛)的冠军模型,是由WMW团队发布。具有复杂度低&#xff0c…

ardupilot开发 --- log篇

懂的都懂,你也要懂 log作用记录您的飞行数据; 两种方式或类型: Data flash log ,通常记录在SD卡上,可通过地面站下载; Telemetry logs(Tlogs),地面站通过无线设备进行实…

软件测试(黑皮书)学习一

第一部分 软件测试综述 第一章 软件测试背景 1.1软件缺陷(software bug) 软件失败的术语 故障(fault)失败(failure) 缺点(defect) ------严重、危险异常(anomaly&…

STEP/STP模型文件在线查看【3D CAD】

STEP 文件(正式称为 ISO 10303)是 3D 模型的流行文件格式。 该格式名称中的字母代表“产品数据交换标准”。 这种文件格式是由 ISO 自动化系统和集成技术委员会(称为 TC 184)于 20 世纪 80 年代中期开发的。STEP 格式的创建是为了…

java.lang.Long cannot be cast to java.lang.Integer解决

出错代码:接收泛型指定是Integer 但是在接测试中 频频抛出java.lang.Long cannot be cast to java.lang.Integer异常,debug 发现Map中的参数确实是Long类型的。 解决办法: 使用父类的Number接收,在使用intValue()方法转成int 原因分析&#…

恒运资本:机构持仓比例多少是重仓?

组织投资者关于股票商场的影响越来越大,其持股份额已成为点评一只股票好坏的重要目标之一。但组织持仓份额究竟多少才算是重仓呢?这涉及到许多要素,让我们从多个视点进行剖析。 1.不同组织的界说不同 首要需求注意的是,不同的组织…

OpenCV-Python中的图像处理-图像特征

OpenCV-Python中的图像处理-图像特征 图像特征Harris角点检测亚像素级精度的角点检测Shi-Tomasi角点检测SIFT(Scale-Invariant Feature Transfrom)SURF(Speeded-Up Robust Features)FAST算法BRIEF(Binary Robust Independent Elementary Features)算法ORB (Oriented FAST and R…

网络综合布线实训室建设方案

一、网络综合布线系统概述 网络综合布线系统是为了满足数据通信需求而设计和建立的一套基础设施。它提供了数据传输、信号传输和电力供应的基础结构,支持各种网络设备和终端设备之间的连接。 网络综合布线系统通常包括以下组成部分: 1) 数据…

Element:input输入框远程搜索返回输入建议的代码详解

文章目录 1 原始代码2 代码详解3 添加注释后的代码&#xff1a;4 createStateFilter方法中0代表什么&#xff1f;5 包含即返回建议值 1 原始代码 官网链接&#xff1a;https://element.eleme.cn/#/zh-CN/component/input 官网代码&#xff1a; <template><el-autoc…

Betty核心源码解析(二)--ServerBootstrap启动过程

serverbootstrap用于建立netty服务端&#xff0c;核心逻辑-- 设置线程池-- bossGroup和workGroup设置accept连接handler定义服务器的色弱v儿serversocketchannel实现设置IO读写的业务逻辑相关childHanlder绑定监听端口-- 创建serversocketchannel对象初始化serversocketchanne…

​ Spring Clould 配置中心 - Nacos

视频地址&#xff1a;微服务&#xff08;SpringCloudRabbitMQDockerRedis搜索分布式&#xff09; Nacos配置管理-Nacos实现配置管理&#xff08;P24、P25&#xff09; Nacos除了可以做注册中心&#xff0c;同样可以做配置管理来使用。 当微服务部署的实例越来越多&#xff0c…

java练习4.快速查找

题目: 数组 arr[6,1,3,7,9,8,5,4,2],用快速排序进行升序排序. import java.util.Random;public class recursionDemo {public static void main(String[] args) {/*快速排序:* 第一轮:以0索引为基准数,确定基准数在数组正确的位置,* 比基准数小的放到左边,比基准数大的放在右边…

Python数据分析实战-*和**实现可变多参数的传入或变量的拆解(附源码和实现效果)

实现功能 *和**实现多参数的传入或变量的拆解 实现代码 # 1、实现多参数的传入 def one(a,*b):"""a是一个普通传入参数&#xff0c;*b是一个非关键字星号参数"""print(b) one(1,2,3,4,5,6) 其中&#xff0c;第一个的输入可以理解为&#xff1a…

记一次微信小游戏渗透测试

本文转载于&#xff1a;https://www.freebuf.com/vuls/371936.html 准备工作 因为目标站点只能用微信打开&#xff0c;微信又不能调试看代码。这里推荐可以使用pc端旧版微信3.2.1&#xff0c;具体方法放链接里&#xff1a; https://blog.csdn.net/qq_45863248/article/details/…

(7)(7.3) 自动任务中的相机控制

文章目录 前言 7.3.1 概述 7.3.2 自动任务类型 7.3.3 创建合成图像 前言 本文介绍 ArduPilot 的相机和云台命令&#xff0c;并说明如何在 Mission Planner 中使用这些命令来定义相机勘测任务。这些说明假定已经连接并配置了相机触发器和云台(camera trigger and gimbal hav…

批量爬虫采集大数据的技巧和策略分享

作为一名专业的爬虫程序员&#xff0c;今天主要要和大家分享一些技巧和策略&#xff0c;帮助你在批量爬虫采集大数据时更高效、更顺利。批量爬虫采集大数据可能会遇到一些挑战&#xff0c;但只要我们掌握一些技巧&#xff0c;制定一些有效的策略&#xff0c;我们就能在数据采集…

【设计模式】订单状态流传中的状态机与状态模式

文章目录 1. 前言2.状态模式2.1.订单状态流转案例2.1.1.状态枚举定义2.1.2.状态接口与实现2.1.3.状态机2.1.4.测试 2.2.退款状态的拓展2.2.1.代码拓展2.2.2.测试 2.3.小结 3.总结 1. 前言 状态模式一般是用在对象内部的状态流转场景中&#xff0c;用来实现状态机。 什么是状态…

Lnton羚通关于PyTorch的保存和加载模型基础知识

SAVE AND LOAD THE MODEL (保存和加载模型) PyTorch 模型存储学习到的参数在内部状态字典中&#xff0c;称为 state_dict, 他们的持久化通过 torch.save 方法。 model models.shufflenet_v2_x0_5(pretrainedTrue) torch.save(model, "../../data/ShuffleNetV2_X0.5.pth…

如何在前端实现WebSocket发送和接收TCP消息(多线程模式)

目录 第一步&#xff1a;创建WebSocket连接第二步&#xff1a;监听WebSocket事件第三步&#xff1a;发送消息第四步&#xff1a;后端处理函数说明 当在前端实现WebSocket发送和接收TCP消息时&#xff0c;可以使用以下步骤来实现多线程模式。本文将详细介绍如何在前端实现WebSoc…