Debezium Engine监听binlog实现缓存更新与业务解耦
飞书文档
解决缓存与数据源数据不一致的方案有很多, 各有优缺点;
1.0、旁路缓存策略, 直接同步更新
读取流程:
- 查询缓存。如果缓存命中,则直接返回结果。
- 如果缓存未命中,则查询数据库。
- 将数据库查询到的数据写入缓存,并设置一个过期时间。
写入流程: - 更新数据库中的数据。
- 删除缓存中的数据缓存。
缺点:
-
缓存穿透 (高并发情况下如果缓存未命中,需要查询数据库并回写缓存,这可能在高并发下场景增加数据库的负载)
-
高并发环境下可能导致数据不一致,因为在删除Redis时,如果有其他请求线程已经读取了MySQL旧数据,然后缓存进去, 就会出现脏数据问题。
伪代码:
vodi updateData(id, newData) {
// 更新MySQL
mysql.update(“UPDATE table SET data = ? WHERE id = ?”, newData, id);// 更新Redis
redis.del(“data:” + id);
}
2.0、延迟双删策略
读取流程:
- 查询缓存。如果缓存命中,则直接返回结果。
- 如果缓存未命中,则查询数据库。
- 将数据库查询到的数据写入缓存,并设置一个过期时间。
写入流程: - 删除缓存中的数据缓存。
- 更新数据库中的数据。
- 延迟1~3S再删除缓存中的数据缓存。
缺点:
-
短时间的数据不一致, 但最终实现的效果是最终数据一致性, 不适合对实时性要求极高的场景。
-
延迟删除不保证成功 (如需保证测需要重试策略)
伪代码:
void updateData(id, newData) {
// 删除Redis缓存
redis.delete(“data:” + id);// 更新MySQL
mysql.update(“UPDATE table SET data = ? WHERE id = ?”, newData, id);// 延时任务,延时后再次删除Redis缓存
scheduleTask(() => {
redis.delete(“data:” + id);
}, delayTime); // delayTime为延迟时间,例如1000毫秒
}
3.0、定时+增量更新策略
读取流程:
- 查询缓存。如果缓存命中,则直接返回结果。
- 如果缓存未命中,则查询数据库。
- 将数据库查询到的数据写入缓存,并设置一个过期时间。
缓存写入流程: - 固定时间去拉取增量数据, 比如比标记时间大的数据。
- 更新进缓存里
优点:
-
减少负载:相比实时同步,定时+增量更新可以减少对数据库和缓存的压力,因为它不会在每次数据变更时立即进行同步。
-
灵活性高:可以根据业务需求调整定时任务的频率和增量更新的策略。
缺点: -
根据配置定时时间长短造成时间的数据不一致, 但最终实现的效果是最终数据一致性, 不适合对实时性要求极高的场景。
-
需要针对不同的业务实现一套不同的定时+增量更新策略
伪代码:
void syncCache() {
// 获取上次同步的时间戳
Timestamp lastSyncTime = getLastSyncTime();// 查询自上次同步以来有变更的数据
List updatedData = mysql.query(
“SELECT * FROM table WHERE update_time > ?”, lastSyncTime);// 更新缓存
for (Data data : updatedData) {
redis.set(“data:” + data.id, data);
}// 更新最后同步时间
updateLastSyncTime(currentTime());
}
4.0、锁机制更新策略
读取流程:
- 查询缓存。如果缓存命中,则直接返回结果。
- 如果缓存未命中, 向Redis上读锁。
- 查询数据库。
- 将数据库查询到的数据写入缓存,并设置一个过期时间 & 释放读锁。
写入流程: - 向Redis上写锁。
- 更新数据库中的数据。
- 删除缓存中的数据缓存。
- 释放写锁
优点:
-
数据强一致性。
缺点: -
性能比其他方式差。
伪代码:
void save() {
// 获取写锁
RedissonClient client = RedissonClientUtil.getClient(“”);
RReadWriteLock readWriteLock = client.getReadWriteLock(“myLock”);
RLock writeLock = readWriteLock.writeLock();
// 加锁
writeLock.lock();
// 查询自上次同步以来有变更的数据
List updatedData = mysql.query(
“SELECT * FROM table WHERE update_time > ?”, lastSyncTime);
// 删除缓存
redis.del(“data:” + data.id);// 最后释放锁
writeLock.unlock();
}
5.0、异步更新策略
Binlog 订阅方式, 这种策略已经和业务解耦开;
读取流程:
- 查询缓存。如果缓存命中,则直接返回结果。
- 缓存未命中查询数据库。
- 将数据库查询到的数据写入缓存,并设置一个过期时间
数据源写入流程: - 更新数据库中的数据。
缓存处理中间件:
接收Binlog 订阅发送过来的数据;
进行缓存的处理 (可以更新也可以删除)
优点:
- 数据最终一致性。
- 和业务解耦, 业务代码不用再考虑数据源数据更新后缓存怎么更新。
缺点: - 有延迟情况;
- 实现成本与维护成本大
大概流程如下图
[图片]
但是基础组件并不满足于公司复杂多变的业务场景, 需要基于基础组件实现定制化的异步更新策略;
基于异步更新策略的架构设计方案
CDC (Change data capture)
[图片]
不想引入mq?试试debezium小型项目当中,没有引入消息中间件,也不想引入,但需要解耦异步,那怎么办呢?CDC组件是 - 掘金
从选项来看, Flink CDC 太重量级; sqoop,kettle,datax之类的工具,属于前大数据时代的产物,地位类似于web领域的structs2。而且,它们基于查询而非binlog日志,其实不属于CDC。首先排除, canal只能对MYSQL进行CDC监控。有很大的局限性。
综上所述 debezium 较为合适;
Debezium 介绍
Debezium 构建在Apache Kafka的基础之上,并提供了一套与Kafka Connect兼容的连接器。每个连接器都与特定的数据库管理系统(DBMS)协同工作。连接器通过检测发生的变化来记录 DBMS 中数据变化的历史,并将每个变化事件的记录流式传输到 Kafka 主题。然后,消费应用程序可以从 Kafka 主题中读取由此产生的事件记录;
通过利用 Kafka 可靠的流平台,Debezium 使应用程序能够正确、完整地消费数据库中发生的变化。即使应用程序意外停止或失去连接,也不会错过中断期间发生的事件。应用程序重新启动后,会从中断的位置继续读取主题。
使用 Debezium 需要三个独立的服务:ZooKeeper、Kafka 和 Debezium 连接器服务,
但是同时Debezium也支持并非每个应用程序都需要这种级别的容错性和可靠性,它们可能不希望依赖外部的 Kafka 代理集群和 Kafka 连接服务。相反,有些应用程序更愿意将 Debezium 连接器直接嵌入应用程序空间。它们仍然需要相同的数据变更事件,但更希望连接器能直接将其发送到应用程序,而不是在 Kafka 内持久化
对应文档说明: Debezium Engine
下面采用轻量级方式集成
Debezium 连接器直接嵌入应用程序空间
1.0、依赖关系
Springboot 2.7.5, jdk8版本
[图片]
[图片]
从上图看 debezium从1.6版本开始就需要 >= jdk11了; 那么我们只能使用1.5版本
[图片]
使用 1.5.4.Final jdk8支持的最新版本
<version.debezium>1.5.4.Final</version.debezium>
应用到生产的源码:
(加密)
暂时无法在飞书文档外展示此内容
暂时无法在飞书文档外展示此内容
采用kafka方式 (暂不研究):
ZooKeeper服务, 目前我们已经在使用, 如果要独立出来, 可以单独配置一台 (生产 : 1核心1GB内存配置)
Kafka服务 (生产集群, 配置4核心8G内存配置, 硬盘SSD)
Debezium连接器服务 (生产集群, 配置4核心8G内存配置, 硬盘SSD)
测试环境 (可以将 三个服务部署在同一台机子, 只需要2核心4G)
运行启动步骤:
MySQL启用binlog
1、启动ZK
2、启动kafka
3、启动Debezium连接器
1
相关文章:
Debezium Engine监听binlog实现缓存更新与业务解耦
飞书文档 解决缓存与数据源数据不一致的方案有很多, 各有优缺点; 1.0、旁路缓存策略, 直接同步更新 读取流程: 查询缓存。如果缓存命中,则直接返回结果。如果缓存未命中,则查询数据库。将数据库查询到的数据写入缓存,并设置一个…...
docker搭建socks5代理
准备工作 VPS安全组/策略放行相应端口如启用了防火墙,放行相应端口 实际操作 我们选用“历史悠久”的Dante socks5 代理服务器,轻量、稳定。Github也有对dante进行进一步精简的镜像,更为适宜。github项目地址如下: https://gi…...
scanf函数和printf函数的格式化输入输出
#include<stdio.h> int main() {int a;double b;char c;scanf("a%d,b%lf:c%c",&a,&b,&c); //float型输入时使用%f占位,double型使用%lf占位;输出时二者相同都是%f即可。if(a>0)printf("a%-10d,b%20.3lf,c%c",a…...
Day31 贪心算法 part05
56. 合并区间 本题也是重叠区间问题,如果昨天三道都吸收的话,本题就容易理解了。 代码随想录 class Solution {public int[][] merge(int[][] intervals) {Arrays.sort(intervals, (a,b) -> Integer.compare(a[0], b[0]));List<int[]> result …...
uniapp连接mqtt频繁断开原因和解决方法
mqtt参考文档:MQTT.js 入门教程 | EMQ、MQTT.js 入门教程 - EMQX - 博客园 uniapp引用MQTT频繁断开的问题可能由于以下几个原因导致: 网络不稳定:频繁断开可能是由于网络不稳定导致的,可以尝试优化网络连接。 心跳机制问题&…...

【数据结构-队列】力扣641. 设计循环双端队列
设计实现双端队列。 实现 MyCircularDeque 类: MyCircularDeque(int k) :构造函数,双端队列最大为 k 。 boolean insertFront():将一个元素添加到双端队列头部。 如果操作成功返回 true ,否则返回 false 。 boolean insertLast() ࿱…...

leetcode3250. 单调数组对的数目 I,仅需1s
题目: https://leetcode.cn/problems/find-the-count-of-monotonic-pairs-i/description/ 不为别的,只是记录下这个超过100%,而且比原先最快的快了一个量级 不知道咋分析,反正得出结论就是,变大不变,变小…...

安全基线检查
一、安全基线检测基础知识 安全基线的定义 安全基线检查的内容 安全基线检查的操作 二、MySQL的安全基线检查 版本加固 弱口令 不存在匿名账户 合理设置权限 合理设置文件权限 日志审核 运行账号 可信ip地址控制 连接数限制 更严格的基线要求 1、禁止远程连接数据库 2、修改…...

C#读取本地图像的方法总结
前言: 大家好,我是上位机马工,硕士毕业4年年入40万,目前在一家自动化公司担任软件经理,从事C#上位机软件开发8年以上!我们在C#开发C#程序的时候,有时候需要读取本地图像,下面进行详…...
力扣81:搜索旋转排序数组II
已知存在一个按非降序排列的整数数组 nums ,数组中的值不必互不相同。 在传递给函数之前,nums 在预先未知的某个下标 k(0 < k < nums.length)上进行了 旋转 ,使数组变为 [nums[k], nums[k1], ..., nums[n-1], n…...
信息系统项目管理-论文写作方法之背景二
为响应国家政务服务“一网、一门、一次”改革,打破“信息孤岛”现象,打造线上线下相融合、多级联动的政务服务一体化平台。XX市行政审批局欲整合市局及下属13镇区、500多个村居委会政务服务中心业务,梳理人社、民政、卫计委、公积金、交通等多…...

使用ffmpeg命令实现视频文件间隔提取帧图片
将视频按每隔五秒从视频中提取一张图片 使用 ffmpeg 工具,通过设置 -vf(视频过滤器)和 -vsync 选项 命令格式 ffmpeg -i input_video.mp4 -vf "fps1/5" output_%03d.png 解释: -i input_video.mp4:指定输…...
我们项目要升级到flutter架构的几点原因
一、探索 Flutter打造卓越移动应用的新时代框架 在移动应用开发的世界里,Flutter已经成为了一个炙手可热的话题。诞生于Google的怀抱,Flutter以其独特的优势和理念,正在引领一场全球范围内的应用开发 ** 。本文将深入探讨Flutter项目的特点、…...

【简单好抄保姆级教学】javascript调用本地exe程序(谷歌,edge,百度,主流浏览器都可以使用....)
javascript调用本地exe程序 详细操作步骤结果 详细操作步骤 在本地创建一个txt文件依次输入 1.指明所使用注册表编程器版本 Windows Registry Editor Version 5.00这是脚本的第一行,指明了所使用的注册表编辑器版本。这是必需的,以确保脚本能够被正确解…...
ElasticSearch为什么不能在query阶段直接返回_id,从而避免fetch?
整理自Github的一个issue,也正好解答了我的疑惑 https://github.com/elastic/elasticsearch/issues/17159 提问 是否可以避免搜索的fetch阶段并仅返回文档ID?查询阶段结束时是否有_id,这样当我只需要_id时,fetch就多余了?可以通过…...

网安瞭望台第5期 :7zip出现严重漏洞、识别网络钓鱼诈骗的方法分享
国内外要闻 7 - Zip存在高危漏洞,请立刻更新 2024 年 11 月 24 日,do son 报道了 7 - Zip 中存在的一个高严重性漏洞 CVE - 2024 - 11477。7 - Zip 是一款广受欢迎的文件压缩软件,而这个漏洞可能会让攻击者在存在漏洞的系统中执行恶意代码。…...

获 2023 年度浙江省科学技术进步奖一等奖 | 网易数智日报
11 月 22 日,加快建设创新浙江因地制宜发展新质生产力动员部署会暨全省科学技术奖励大会在杭州隆重召开。浙江大学、网易数智等单位联合研发的“大规模结构化数据智能计算平台及产业化”项目获得 2023 年度浙江省科学技术进步奖一等奖。 加快建设创新浙江因地制宜发…...

SQL基础入门 —— SQL概述
目录 1. 什么是SQL及其应用场景 SQL的应用场景 2. SQL数据库与NoSQL数据库的区别 2.1 数据模型 2.2 查询语言 2.3 扩展性 2.4 一致性与事务 2.5 使用场景 2.6 性能与扩展性 总结 3. 常见的SQL数据库管理系统(MySQL, PostgreSQL, SQLite等) 3.…...
【附录】Rust国内镜像设置
目录 前言 (1)设置环境变量 (2)安装Rust (3)设置crates镜像 前言 本节课来介绍下如何在国内高速下载安装Rust和Rust依赖,由于网络原因,我们在安装Rust和下载项目依赖时都很慢&am…...
量化交易系统开发-实时行情自动化交易-8.2.发明者FMZ平台
19年创业做过一年的量化交易但没有成功,作为交易系统的开发人员积累了一些经验,最近想重新研究交易系统,一边整理一边写出来一些思考供大家参考,也希望跟做量化的朋友有更多的交流和合作。 接下来会对于发明者FMZ平台介绍。 发明…...

Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...

基于FPGA的PID算法学习———实现PID比例控制算法
基于FPGA的PID算法学习 前言一、PID算法分析二、PID仿真分析1. PID代码2.PI代码3.P代码4.顶层5.测试文件6.仿真波形 总结 前言 学习内容:参考网站: PID算法控制 PID即:Proportional(比例)、Integral(积分&…...

定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...

MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序
一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...
06 Deep learning神经网络编程基础 激活函数 --吴恩达
深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...
Java 二维码
Java 二维码 **技术:**谷歌 ZXing 实现 首先添加依赖 <!-- 二维码依赖 --><dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.5.1</version></dependency><de…...

Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...