变更通知在开源SpringBoot/SpringCloud微服务中的最佳实践
目录导读
- 变更通知在开源SpringBoot/SpringCloud微服务中的最佳实践
- 1. 什么是变更通知
- 2. 变更通知的场景分析
- 3. 变更通知的技术方案
- 3.1 变更通知的技术实现方案
- 4. 变更通知的最佳实践总结
- 5. 参考资料
变更通知在开源SpringBoot/SpringCloud微服务中的最佳实践
1. 什么是变更通知
变更通知是指数据发生变化后,相对实时地通知到关联端的技术实现方案;变更通知是在服务拆分的发展过程中,逐渐衍生出的,解耦关联服务的一种技术解决方案;- 微服务架构中常说的
配置中心就是变更通知的技术集成方案;
2. 变更通知的场景分析
变更通知首先是数据发生了变化,数据变化后的通知实现,数据变化的交互场景列举分析如下:
| 通知类型 | 模块1 | 模块1数据变更 | 模块2 | 模块2实时变更 | 技术实现方式 | 本文讨论范围 |
|---|---|---|---|---|---|---|
| 消息通知 | 前端1 | ✔ | 前端2 | ✔ | 前端总线等 | ✖ |
| 消息保存 | 前端1 | ✔ | 后端2 | ✔ | Post Ajax请求等 | ✖ |
| 消息通知 | 后端1 | ✔ | 前端2 | ✔ | WebSocket等推送到前端(推数据),也叫消息推送 | ✖ |
| 消息通知 | 后端1 | ✔ | 前端2 | ✔ | 前端Http主动轮询(拉数据) | ✖ |
| 变更通知 | 后端1 | ✔ | 后端2 | ✔ | Redis/ZooKeeper/Etcd/Nacos/MQ等 | ✔ |
总结:
变更通知首先是数据(也可叫消息,下同。)发生了变化,然后引起了关联方同步变化;数据变化可以发生在前端和后端之间的任意组合之间,包括前端+前端、前端+后端、后端+后端,一般只有后端+后端的连锁反应叫变更通知,这也是本文关注的重点;- 上表串联了所有常规的交互过程,大家也可以从中理解
消息通知和变更通知之间的关联关系:只是不同交互方式下的数据变化的叫法罢了;- 前端感知后端的数据变化,主要有
前端轮询和后端推送两种,二者技术实现差异较大,前者技术实现简单,但是后端资源消耗较大,无法承担高并发;后者技术实现较复杂,但是点对点通信效率高(长连接)。这不是本文讲述的重点,但希望能够类比分析下各种交互方式下的技术方案,做到一通百通;变更通知主要关注的是后端数据变化,但是不是所有的后端数据变化都需要变更通知。一般来说,跨了服务实例,才比较适用变更通知,单个服务实例内,完全可以通过接口引用等方式自行获取到变化的数据;- 本文重点关注的是
变更通知而不是配置中心,像Nacos、SpringCloud-Config、Apollo等配置中心并不会过多介绍;
- 本文主要关注后端与后端之间的
数据变化机制及技术实现,其发展阶段如下:
| 变更类型 | 应用发展阶段 | 技术方案 | 技术实现 | 说明 |
|---|---|---|---|---|
| 主动获取 | 单实例 | 共享数据库 | 查询数据库 | 数据库查询量不大 |
| 主动获取 | 单实例 | 共享内存缓存 | 查询时先查缓存 | 数据库查询量非常大 |
| 主动获取 | 多实例 | 分布式缓存 | 使用读写性能极高的分布式缓存组件 | 如: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 |
| 配置中心 | 服务端推送 | 把配置中心组件当成业务配置中心 | 组件重、可靠性低、实时性低 | 配置中心严格来说是个变更通知的解决方案,而上面列举的中间件是纯技术组件,二者的维度不太一样;配置中心一般和注册中心配合使用,因为它本身也需要注册至服务中心,如:Apollo、SpringCloud-Config;有些干脆就被注册中心兼任,如Nacos |
总结:
变更通知一般来说是微服务中的增强功能,不建议因为有变更通知需求就新增一个组件。如果系统中已经有了Redis,就建议优先选择Redis,因为其性能高、消息存储量大。但Redis是NoSQL存储结构,可读性较差;Redis也有可能没有开启持久化导致数据丢失;Redis也缺失了类似关系数据库自带的操作审计,一旦数据出现了异常,将很难知道是谁做了什么;ZooKeeper/Etcd则比较适合系统中已经引入该组件了,且变更通知消息数量较小的场景;MQ比较适用于可靠性高、消息量巨大的场景,值得单独引入。如:大型电商的活动卡券配置等场景;binlog+canal这个特定组合一般不建议单独使用,一般是canal把变更数据发送给其它变更通知Server,然后在业务模块订阅变更通知Server的这个变化数据,并做相应的业务处理。其它Server可以是ZooKeeper/Etcd/Redis等;- 一般来说,
配置中心包含了单独的配置规则界面和变更通知的能力,拆箱即用,效果当然较好。但并不是所有的变更通知都需要重量级的配置中心,不是非要在配置中心去配置变更数据的,就都没有必要用它;业务需要使用到配置中心组件时,建议在选定注册中心后,再来决策选择其配置中心;
变更通知有非常多的实现方式,讲讲本人实际经历的业务场景:
| 场景类型 | 业务诉求 | 微服务架构 | 微服务技术栈 | 方案说明 |
|---|---|---|---|---|
| 场景1 | DB数据变更立即触发定时任务 | 微服务架构 | spring+mysql+binlog+canal+ZooKeeper | 基于spring自研微服务框架 |
| 场景2-1 | 业务阈值在1天内生效 | 微服务云原生架构 | SpringBoot+Redis+PostgreSQL | 1.依赖k8s提供服务发现等; 2.依赖redis限流; |
| 场景2-2 | 业务阈值在1天内生效 | 微服务私部署架构 | SpringBoot | 1.部署至客户机房,不依赖Redis/DB; 2.使用Nginx做负载均衡,也不需要服务注册和发现; |
| 场景3 | 业务阈值在5分钟内生效 | 微服务云原生架构 | SpringBoot+Redis | 1.依赖k8s提供服务发现等; 2.依赖redis限流; |
| 场景4 | 业务阈值在立即生效 | SpringCloud微服务架构 | SpringBoot+Redis+Nacos | 1.依赖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 原理简介和实现
相关文章:
变更通知在开源SpringBoot/SpringCloud微服务中的最佳实践
目录导读 变更通知在开源SpringBoot/SpringCloud微服务中的最佳实践1. 什么是变更通知2. 变更通知的场景分析3. 变更通知的技术方案3.1 变更通知的技术实现方案 4. 变更通知的最佳实践总结5. 参考资料 变更通知在开源SpringBoot/SpringCloud微服务中的最佳实践 1. 什么是变更通…...
亚马逊产品排名关键因素解析,通过测评干预需要具备哪些条件
亚马逊产品排名的高低意味着分配的流量多少以及销量的高低。影响产品排名的因素主要包括以下四个方面: 1. 产品销量 产品销量是反映产品在同类产品销售情况的一个重要指标。它在产品Listing中展示,并且平台每小时会更新一次该排行榜。平台算法认为&…...
leetcode原题:绘制直线(位运算)
题目: 已知一个由像素点组成的单色屏幕,每行均有 w 个像素点,所有像素点初始为 0,左上角位置为 (0,0)。 现将每行的像素点按照「每 32 个像素点」为一组存放在一个 int 中,再依次存入长度为 length 的一维数组中。 …...
jenkins 安装和通过gitee 拉取PHP项目
#jenkins 安装地址:https://pkg.jenkins.io/redhat-stable/sudo wget -O /etc/yum.repos.d/jenkins.repo https://pkg.jenkins.io/redhat-stable/jenkins.repo sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io-2023.key yum install fontconfig…...
解析TCP/IP协议的分层模型
了解ISO模型:构建通信的蓝图 为了促进网络应用的普及,国际标准化组织(ISO)引入了开放式系统互联(Open System Interconnect,OSI)模型。这个模型包括了七个层次,从底层的物理连接到顶…...
ARM M33架构入门
概述 Arm Cortex-M33核心处理器专为需要高效安全或数字信号控制的物联网和嵌入式应用而设计。该处理器具有许多可选功能,包括数字信号处理扩展 (DSP)、用于硬件强制隔离的TrustZone 安全性、内存保护单元 (MPU)和浮点单元 (FPU)。 Cortex-M33 的性能比 Cortex-M…...
CentOS系统环境搭建(四)——Centos7安装Java
centos系统环境搭建专栏🔗点击跳转 Centos7安装Java 查看云端yum库中目前支持安装的jdk软件包 yum search java|grep jdk选择JDK版本,并安装 yum install -y java-1.8.0-openjdk检查是否安装成功 java -version查看JDK的安装目录 find / -name jav…...
Arduino MQTT客户端库PubSubClient快速入门
文章目录 目的基础说明示例代码总结 目的 MQTT是比较常用在物联网设备中的通讯协议,这篇文章将使用 Arudino ESP32 作为MQTT客户端进行通讯使用演示。目前Arduino的MQTT客户端库中最常使用的是 PubSubClient ,所以本文也将以此进行说明。 主页…...
视频集中存储/云存储/磁盘阵列EasyCVR平台接入RTSP设备出现离线情况的排查
安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快,可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等,以及支持厂家私有协议与SDK接入,包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…...
部署Springboot项目注意事项
步骤 步骤 1:将数据库内容在云服务器上的数据库部署一份 我使用mariadb;会出现一些不兼容现象;我们需要把默认值删掉 2:配置文件你得修改地方 a:linux是磁盘区分(像我自己项目用来储存验证码的文件我们得换这个配置;…...
深度解析:DDoS攻击与先进防御策略
目录 DDoS 介绍 DDoS 攻击理论 DDoS 介绍 DDoS(分布式拒绝服务)攻击是一种恶意网络活动,旨在通过同时向目标系统发送大量请求或流量,使其无法正常运行或提供服务。攻击者通常利用网络上的多个计算机和设备,形成一个&…...
NLP | 论文摘要文本分类
基于论文摘要的文本分类与关键词抽取挑战赛2023 iFLYTEK A.I.开发者大赛-讯飞开放平台 环境需求:Anaconda-JupyterNotebook,或者百度AIStudio 赛题解析: 【文本二分类任务】根据论文摘要等信息理解,将论文划分为0-1两…...
Linux / Ubuntu磁盘扩容
测试时遇到了shell脚本执行错误的问题,找到脚本编写的楼哥,才发现自己给虚拟机的磁盘已经满了,没想到啊,业务的解压操作,这么费磁盘,那就需要进行磁盘的扩展,记录一下 1、首先停掉虚拟机&#…...
【ChatGPT 指令大全】怎么使用ChatGPT来辅助知识学习
目录 概念解说 简易教学 深度教学 教学与测验 解释一个主题的背后原理 总结 在当今信息时代,互联网的快速发展为我们获取知识提供了前所未有的便利。而其中,人工智能技术的应用也为我们的学习和交流带来了新的可能性。作为一种基于自然语言处理的人…...
URL编码指南
URL简介 URL 是统一资源定位符(Uniform Resource Locator)的缩写。它是用于在互联网上定位并访问资源的一种标识方式。 URL通常由以下几个组成部分组成: 协议(Protocol):指示要使用的协议,如…...
Java mail邮件开发 OA办公系统
目录 1 Java mail邮件开发 OA办公系统 1.1 ExitServlet 1.1.1 //退出系统 1.2 LoginAction 1.2.1 //登录Action Java mail邮件开发 OA办公系统 ExitServlet package com.email.ser...
ElasticSearch的客户端操作
ElasticSearch的客户端操作 1、客户端介绍 官方文档地址: https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html 实际开发中,有多种方式操作Elasticsearch: 客户端工具:发送http请求(RESTful风格)操作…...
如何快速的合并多个PPT使之成为一个PPT?
如何快速的合并多个PPT使之成为一个PPT? 项目过程中,经常给客户汇报,经常做PPT,有时候,需要把之前的ppt内容整合到新的内容中,如何快速合并以及使用呢? 幻灯片(PPT中)点…...
【微信小程序】列表滚动触底更新实现
微信小程序开发系列 目录 前言一、上拉触底事件函数onReachBottom二、实现 前言 在微信小程序开发中经常遇到分页列表需要滚动到底部之后进行请求数据更新,下面介绍如何进行触底更新分页展示。使用到页面上拉触底事件的处理函数onReachBottom。 一、上拉触底事件函…...
2023全国大学生数学建模竞赛A题B题C题D题E题思路+模型+代码+论文
目录 一. 2023国赛数学建模思路: 赛题发布后会第一时间发布选题建议,思路,模型代码等 详细思路获取见文末名片,9.7号第一时间更新 二.国赛常用的模型算法: 三、算法简介 四.超重要!!&…...
eNSP-Cloud(实现本地电脑与eNSP内设备之间通信)
说明: 想象一下,你正在用eNSP搭建一个虚拟的网络世界,里面有虚拟的路由器、交换机、电脑(PC)等等。这些设备都在你的电脑里面“运行”,它们之间可以互相通信,就像一个封闭的小王国。 但是&#…...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...
【解密LSTM、GRU如何解决传统RNN梯度消失问题】
解密LSTM与GRU:如何让RNN变得更聪明? 在深度学习的世界里,循环神经网络(RNN)以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而,传统RNN存在的一个严重问题——梯度消失&#…...
Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务
通过akshare库,获取股票数据,并生成TabPFN这个模型 可以识别、处理的格式,写一个完整的预处理示例,并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务,进行预测并输…...
React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...
