变更通知在开源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号第一时间更新 二.国赛常用的模型算法: 三、算法简介 四.超重要!!&…...

Git常见操作
一、全局配置命令 配置级别: –local(默认,高级优先):只影响本地仓库 –global(中优先级):只影响所有当前用户的git仓库 –system(低优先级):影响到全系统的git仓库 1…...

thinkphp6前后端验证码分离以及验证
1.验证码接口生成验证码: public function verify(){return captcha(); } 也可以自己写方法 2.验证方法和普通模式session验证有区别,需要改原文件: 修改后的代码: <?php // +---------------------------------------------------------------------- // | ThinkP…...

jenkinsfile自动部署接口
复制创建新流水线 从预先创建的job中获取 config.xml 或根据需要创建另一个 curl -X GET http://xxx.xxx.xxxx.com/job/backup-data/config.xml -u test:xxxxxxxxxxxxxxxxxx-o config.xml 生成Crumb CRUMB$(curl -s http://xxxxxxx.xxx.xxx.com/crumbIssuer/api/xml?xpathc…...

26. 删除有序数组中的重复项
26. 删除有序数组中的重复项 给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。 考虑 nums 的唯一元素的…...

vue父页面获取子组件绑定值
<el-form-item label"图文详情" prop"imageText"><div><el-button type"primary" link>组件</el-button><WangEditor v-model"ruleForm.imageText"></WangEditor></div> </el-form-item…...

FPGA_学习_17_IP核_ROM(无延迟-立即输出)
由于项目中关于厂商提供的温度-偏压曲线数据已经被同事放在ROM表了,我这边可用直接调用。 今天在仿真的时候,发现他的ROM表用的IP核是及时输出的,就是你地址给进去,对应地址的ROM数据就立马输出,没有延迟。 我打开他的…...

CentOS7.6安装mysql8.0.34
一、查看服务器相关信息 cat /etc/redhat-release cat /proc/version [rootlocalhost ~]# cat /etc/redhat-release CentOS Linux release 7.6.1810 (Core) [rootlocalhost ~]# cat /proc/version Linux version 3.10.0-957.el7.x86_64 (mockbuildkbuilder.bsys.centos.org) …...

SCF金融公链新加坡启动会 链结创新驱动未来
新加坡迎来一场引人瞩目的金融科技盛会,SCF金融公链启动会于2023年8月13日盛大举行。这一受瞩目的活动将为金融科技领域注入新的活力,并为广大投资者、合作伙伴以及关注区块链发展的人士提供一个难得的交流平台。 在SCF金融公链启动会上, Wil…...

JavaScript【实例、静态方法与属性、原型链、instanceof 运算符、Object 对象的相关方法、对象的继承、多重继承、严格模式】(十九)
目录 实例、静态方法与属性 实例方法和静态方法...

【Git】本地搭建Gitee、Github环境
本地 (Local) 1、使用命令生成公钥(pub文件) 1. $ ssh-keygen -t rsa -C "xxxxxxxemail.com" -f "github_id_rsa" 2. $ ssh-keygen -t rsa -C "xxxxxxxemail.com" -f "gitee_id_rsa" …...