22 重构系统升级-实现不停服的数据迁移和用户切量

news2024/11/19 7:41:50

专栏的前 21 讲,从读、写以及扣减的角度介绍了三种特点各异的微服务的构建技巧,最后从微服务的共性问题出发,介绍了这些共性问题的应对技巧。

在实际工作中,你就可以参考本专栏介绍的技巧构建新的微服务,架构一个具备“三高”能力的后台服务。同时,也可以利用所学的技巧对已有的微服务进行系统升级重构,从而解决历史遗留问题。

升级重构是后台架构演化增强的一个利器,本讲将为你详细讲解如何落地对用户无感知、低 Bug 的升级重构方案。

重构常见的形式

升级重构有两种常见的形式,一种是纯代码式的升级,另外一种是包含存储和代码的升级。

纯代码的重构升级是指只针对代码中存在的一些历史遗留问题进行修复,比如代码中的慢 SQL、错误的日志打印方式、代码中未显式开启事务等问题。

注:在本讲,将存在问题的历史版本称为V1 版;修复问题后的升级重构版本称为 V2 版。纯代码的重构升级架构如下图1所示:

图 1:纯代码的升级重构对比图

包含存储和代码的重构升级是指在上述纯代码之外,将原有架构里的存储也一起升级。存储升级有两种形式。

第一种是将存储类型进行升级,比如将数据库升级为缓存,将原有的读接口从数据库切换至缓存。做此类存储类型升级的目的是提升微服务的性能,我们在模块二中曾介绍,同样的硬件配置下,缓存比数据库至少快一个量级。不同类型的存储升级架构如下图 2 所示:

图 2:不同类型的存储升级架构对比图

可以看到升级后,原有的代码从 V1 升级到 V2。同时,存储从读写都使用数据库,升级为写操作使用数据库,读操作使用缓存的架构。

第二种是将一个表结构的存储升级为同类型存储的另外一个更加合理的表结构。此类升级常见于系统构建时,为了快速满足业务需求,在时间紧张的情况下,简单快速地设计了不是特别合理的表结构。比如原有的表结构采用了一张宽表存储所有的数据,包含一对多的数据都进行冗余存储。升级重构时,需要采用更加合理的表结构存储数据,以便未来能够快速响应业务的发展。它的重构升级架构如下图 3 所示,升级后,原有微服务的读写都将切换至新的表结构的存储里。

图 3:同类型不同表结构的存储升级架构对比图

纯代码重构的切换

纯代码重构的切换比较简单,当上述 V2 版本通过测试环境和预发布环境的测试后,就可以直接在线上部署,替换原有的V1 版本。当部署的 V2 版本出现问题后,直接进行回滚即可,这是最简单、粗暴的切换方式。但同时也存在隐患,采用此种方式部署的V2如果出现问题,会影响所有的用户,影响面较大。

为了降低影响,可以采用灰度的方式。即用 V2 版本的代码替换一台或者一定比例 V1 版本的机器,比如线上有 100 台部署 V1 版本代码的机器,当 V2 版本测试完成准备上线时,可以先发布 10 台 V2 版本的代码。这样,假设 V2 版本的代码存在 Bug,也只会影响访问这 10 台部署了 V2 版本代码的用户,即 10%的线上流量,这样就缩小了影响面。假设发布了 10 台 V2 版本的代码后,没有发现任何 Bug,此时则可以继续发布,逐步进行替换。

通过此种灰度的方式,既可以做到纯代码的升级重构切换,又可以缩小因此可能带来的线上问题的影响范围。

含存储重构的切换

与上述纯代码的切换相比,含存储的重构切换有一个重要步骤便是数据迁移。不管是上述不同类型的存储还是同类型不同表结构的存储重构,都需要将原有存储中的数据全部迁移至新的存储中,才能够称为完成切换。

对于含存储重构的切换,最简单的方法便是停服,之后在无任何数据写入的情况下进行数据迁移,迁移之后再进行数据对比,对比无误之后,用重构的新版本连接新的存储对外提供服务即可。

这种方式适合于以下 2 种场景:

  • 业务有间断期或者有低峰期的场景。比如企业内网系统,下班或者周末期间几乎没有人使用;

  • 金融资产类业务,这些业务对于正确性要求极高,因为用户对资产极度敏感,如果资产出现错误,用户是无法容忍的。为了资产安全无误,有时候需要用户容忍停服的重构升级。

但对于用户量巨大,且大部分业务场景都需要提供 7*24 服务的互联网业务来说,停服切换方式,用户是不能接受。因此,就需要设计一套既不需要停服,又可以完成用户无感知的切换方案。

切换架构

为了实现不停服的重构升级,整体的新版本上线、数据迁移以及用户切量的架构如下 图 4 所示:

图 4:不停服的切换架构

上述的架构中,左边部分是老版本未重构的服务及对应的老数据存储(后续称为老存储),图中右边部分部署的是升级重构后的新版本的服务和对应的新版本存储(后续称为新存储)。这个存储可以是缓存或者是表结构不同的数据库。

在图的下方,则是数据同步模块。它主要的作用是实时进行数据同步,将老存储里的历史数据、新增的写入以及更新的数据实时地同步至新存储里。实时数据同步是实现存储升级重构不停服切换的基础。

在完成数据同步之后,便可以进行用户的灰度切量了,将用户逐步切换至升级重构的新版本上。见图 4 中最上面的部分。

下面将对图 4 中涉及的各个部分进行详细讲解。

数据同步

当升级重构后的新版本开发及测试完成后,便可以将新版本代码和存储进行线上部署了。新版本部署时,可以将新版本服务对外提供的接口的别名变更为一个新的名称,如为:new_version,具体见上图 4。因为修改了别名,即使新版本的服务上线部署并直接对外了,也不会引入老版本的流量。

通过上述方式可以实现新老版本的隔离,进而完成新版本服务的线上部署。新版本线上部署及隔离后,便可以进行数据同步了。

数据同步分为历史数据的全量同步和新增数据的实时同步。在上述“含存储重构的切换”小节里介绍过,存储重构涉及两个种类,第一种是数据库到缓存,第二种是数据库到另一种异构的表结构数据库里。这里以使用场景较多的数据库到缓存的重构举例讲解,另一种场景比较类似,你可以按此方式自己推演。如果有疑问,也可以写在留言区,我们一起讨论。

包含全量同步、增量数据的实时同步架构如下图 5所示:

图 5:全量同步和增量同步架构

上述第一步的全量同步(见图 5 的编号 1 处)是将历史数据进行一次全量初始化同步,可以采用 Worker 的方式,对老版本的数据库的数据进行遍历,遍历的 SQL 大致如下:

select 数据 from t_table where id> last_id limit 一批次的数量

从数据库遍历读取完之后,便会在同步服务模块里按缓存的格式进行数据格式的转换,转换后的数据写入缓存即可。

上述的数据同步 SQL 没有停止条件,且在未切量前,老库一直会有数据持续写入。使用上述 SQL 进行同步时,会导致全量同步一直执行,出现无法停止的情况。针对这个问题,可以根据当前数据库已有数据量、数据增长的速度以及数据同步的速度,评估在数据同步期间能够产生的数据量,并评估出这期间最多可能产生的数据 ID(截止 ID),并将上述 SQL 修改如下:

select 数据 from t_table where id> last_id and id<截止ID limit 一批次的数量

第二步的增量实时同步是在开始进行全量同步时启动的,增量同步使用的是本专栏多次介绍的Binlog 进行。通过在增量同步模块订阅老版本数据库里的数据变更,可以实时获取老版本数据库中新增和变更的数据。

需要注意的是,增量同步需要在全量同步开始前便进行Binlog的订阅。如果在全量同步结束后,再订阅 Binlog 进行增量同步,可能会丢失在全量同步期间发生变更的数据。

比如一张待同步的数据表里有 100 条数据,如果在全量同步前未开启增量同步。当同步至第 90 条数据时,第80 条数据发生了 update 操作,因为此时还没有开启增量同步,那么这第 80 条数据对应的变更就丢失了。为了防止此问题,就需要前置开启增量同步。

最后,增量同步除了需要订阅 update 和 delete 操作外,还需要订阅 insert 操作。因为全量同步在上述截止 ID 之后的数据便不会再同步了,需要增量同步处理此类操作。

数据对比验证

在完成数据迁移之后,并不是立马就能够开始用户切量。还需要做一步非常重要的事情,那便是进行测试。因为做了大规模的代码重构以及存储的切换,只靠人工测试是远远不够的,很容易出现场景遗漏。

因此就需要借助自动化的方式进行测试,我想你还记得在“第 07 讲:基于流量回放的自动化回归测试”的内容。在完成全量数据同步后,可以录制老版本服务的流量,并进行自动化测试回归,它的架构如下图 6 所示:

图 6:自动化的数据对比验证架构图

通过一定时间区间的自动化回归,可以保证场景不被遗漏,极大地减少重构切换可能导致的问题,具体如何进行自动化和发现问题,你可以参考“第 07 讲”的内容。

在自动化回归中,可能会出现的某一类问题需要特殊处理,因为增量同步延迟会导致数据对比不一致。原则上这类问题不应该存在,因为基于Binlog的主从同步延迟非常小。但如果遇到上述情况,因为增量同步的时延很小,所以我们可以等待几分钟后再次运行对比不一致的回放请求。

用户切换

完成数据对比之后,下一步需要落地的便是用户切换了。进行用户切换时,有几个原则需要遵循:

  • 切量不能一刀切,即不能一次将所有的用户全部切换至新版本服务里,需要灰度逐步地将用户从老版本切换到新版本服务里;

  • 在灰度切量时,需要尽早发现问题,而不是等到切量快完成的时候才发现问题。

对于上述的几个要求,在切量的具体落地时,可以从以下几点着手落地。

对于影响面小的要求。

首先,对于升级重构的系统涉及的所有用户进行分析并按等级划分。可以按用户的注册时间、是否为会员等进行划分。如果重构的模块是订单模块,可以将用户按历史以来的下单量、订单金额进行排序,订单量小、下单金额低的用户排在最前面。

在用户按上述的维度排序后,可以将用户分为几大批次,比如将所有用户按排序分为五等份。第一等份的用户因为单量小、下单金额少,可以最先进行切换,这样便满足前述提到的“出问题影响面少”的要求。

对于在切量时,尽可能早发现问题的要求。

对上述排序的第一等份的用户,再次进行分析和分类。我们知道,一个系统对外一般会提供多个功能点,比如用户模块会对外提供用户注册、查询用户基本信息、修改个人签名等功能。可以对第一等份里的用户进行数据分析,分析这些用户里哪些用户使用了较多的系统功能。在分析后,可以按使用功能的多少对第一等份里的用户进行排序,使用功能较多的用户排序在前面。在切量时,第一等份里使用系统功能最多的用户会优先进行切量,这也满足了前面所要求的尽可能多发现问题的要求。

本节总结

本讲介绍了系统升级重构的两种常见的类型。并分别介绍了这两种类型在升级重构后,如何实施让用户尽可能少感知的切换方案。

同时,在包含存储的系统升级重构切换方案里,借鉴了很多本专栏前面介绍过的技术方案,比如基于Binlog的数据同步、基于流量回放的自动化回归方案等。

由此可以看出,很多技术方案之间都是相互依赖的、相互连通的,甚至是成体系的。所以建议你在学习本专栏各讲的内容时,尝试寻找知识之间的联系,完善自己的知识体系,这样才能将专栏里的知识融会贯通,真正应用到实际的业务场景里。

最后,留一道思考题给你,你认为互联网大厂的 App 和后台系统的上线发版是如何灰度切流的?欢迎写在留言区,我们一起讨论。

这一讲就到这里,感谢你学习本次课程,接下来我们将学习 23 | 重构:烟囱式、平台化、中台化的架构演化

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

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

相关文章

vue3 安装-使用之第一篇

首先需要node版本高于V16.14.1 安装 执行 npm create vitelatest 具体选择按照自己实际需要的来 Project name:项目名称 Select a framework:选择用哪种框架 &#xff08;我选择vue&#xff09; Select a variant: 选择用JS还是TS&#xff08;我选择JS&#xff09;找到项目&…

STM32 HAL库F103系列之IIC实验

IIC总线协议 IIC总线协议介绍 IIC&#xff1a;Inter Integrated Circuit&#xff0c;集成电路总线&#xff0c;是一种同步 串行 半双工通信总线。 总线就是传输数据通道 协议就是传输数据的规则 IIC总线结构图 ① 由时钟线SCL和数据线SDA组成&#xff0c;并且都接上拉电阻…

(7)快速调优

文章目录 前言 1 安装脚本 2 运行 QuikTune 3 高级配置 前言 VTOL QuikTune Lua 脚本简化了为多旋翼飞行器的姿态控制参数寻找最佳调整的过程。 脚本会缓慢增加相关增益&#xff0c;直到检测到振荡。然后&#xff0c;它将增益降低 60%&#xff0c;并进入下一个增益。所有增…

微服务保护和分布式事务(Sentinel、Seata)笔记

一、雪崩问题的解决的服务保护技术了解 二、Sentinel 2.1Sentinel入门 1.Sentinel的安装 &#xff08;1&#xff09;下载Sentinel的tar安装包先 &#xff08;2&#xff09;将jar包放在任意非中文、不包含特殊字符的目录下&#xff0c;重命名为 sentinel-dashboard.jar &…

Spark Structured Streaming 分流或双写多表 / 多数据源(Multi Sinks / Writes)

博主历时三年精心创作的《大数据平台架构与原型实现&#xff1a;数据中台建设实战》一书现已由知名IT图书品牌电子工业出版社博文视点出版发行&#xff0c;点击《重磅推荐&#xff1a;建大数据平台太难了&#xff01;给我发个工程原型吧&#xff01;》了解图书详情&#xff0c;…

数据库管理-第179期 分库分表vs分布式(20240430

数据库管理179期 2024-04-30 数据库管理-第179期 分库分表vs分布式&#xff08;20240430&#xff09;1 分库分表1.1 分库1.2 分表1.3 组合1.4 问题 2 分布式3 常见分布式数据库4 期望总结 数据库管理-第179期 分库分表vs分布式&#xff08;20240430&#xff09; 作者&#xff1…

git 第一次安装设置用户名密码

git config --global user.name ljq git config --global user.email 15137659164qq.com创建公钥命令 输入后一直回车 ssh-keygen -t rsa下面这样代表成功 这里是公钥的 信息输入gitee 中 输入下面命令看是否和本机绑定成功 ssh -T gitgitee.com如何是这样&#xff0c;恭喜…

spring的高阶使用技巧1——ApplicationListener注册监听器的使用

Spring中的监听器&#xff0c;高阶开发工作者应该都耳熟能详。在 Spring 框架中&#xff0c;这个接口允许开发者注册监听器来监听应用程序中发布的事件。Spring的事件处理机制提供了一种观察者模式的实现&#xff0c;允许应用程序组件之间进行松耦合的通信。 更详细的介绍和使…

Flask简介

Flask简介 安装概述使用PyCharm创建一个Flask程序 Flask程序的基本结构初始化路由和视图函数启动服务器请求-响应循环 安装 概述 Flask算是小型框架&#xff0c;小到可以称为“微框架”。Flask 非常小&#xff0c;因此你一旦能够熟练使用它&#xff0c;很可能就能读懂它所有的…

element的el-table 解决表格多页选择数据时,数据被清空

问题&#xff1a;切换页码时&#xff0c;勾选的数据会被清空 重点看我圈出来的&#xff0c;直接复制&#xff0c;注意&#xff0c;我这里 return row.productId;一般大家的是 return row.id,根据接口定的唯一变量 :row-key"getRowKeys"​​​​​​​:reserve-sele…

【八大排序(三)】快速排序

❣博主主页: 33的博客❣ ▶️文章专栏分类:八大排序◀️ &#x1f69a;我的代码仓库: 33的代码仓库&#x1f69a; &#x1faf5;&#x1faf5;&#x1faf5;关注我带你了解更多排序知识 目录 1.前言2.快速排序2.1概念2.2画图理解2.3递归代码实现2.3.1Hoare法2.3.2挖坑法2.3.3前…

vue3 引用虚拟键盘simple-keyboard

simple-keyboard官网地址&#xff1a;https://virtual-keyboard.js.org 目前实现效果图是&#xff08;实现数字、大小写字母键盘&#xff09;&#xff1a; 1.需要先安装simple-keyboard npm install simple-keyboard --save2.封装sinpleKeyboard 组件 <!-- keyboard-bo…

24深圳杯数学建模挑战赛A题6页初步思路+参考论文+保姆级答疑!!!

问题1:单个残骸的精确位置定位 建立数学模型&#xff0c;分析如果要精准确定空中单个残骸发生音爆时的位置坐标&#xff08;经度、纬度、高程&#xff09;和时间&#xff0c;至少需要布置几台监测设备&#xff1f;假设某火箭一级残骸分离后&#xff0c;在落点附近布置了7台监测…

聊聊 ASP.NET Core 中间件(一):一个简单的中间件例子

前言&#xff1a;什么是中间件 服务器在收到 HTTP 请求后会对用户的请求进行一系列的处理&#xff0c;比如检查请求的身份验证信息、处理请求报文头、检查是否存在对应的服务器端响应缓存、找到和请求对应的控制器类中的操作方法等&#xff0c;当控制器类中的操作方法执行完成…

02 spring-boot+mybatis+elementui 的登录,文件上传,增删改查的入门级项目

前言 主要是来自于 朋友的需求 项目概况 就是一个 学生信息的增删改查 然后 具体到业务这边 使用 mybatis xml 来配置的增删改查 后端这边 springboot mybatis mysql fastjson hutool 的一个基础的增删改查的学习项目, 简单容易上手 前端这边 node14 vue element…

【C++】初识string类

一、熟悉string类 1.1 string类的由来&#xff1a; C语音中的字符串需要我们自己管理底层空间&#xff0c;容易内存泄露。而C是面向对象语音&#xff0c;所以它把字符串封装成一个string类。 C中对于string的定义为&#xff1a;typedef basic_string string; 也就是说C中的str…

Microsoft Universal Print 与 SAP 集成教程

引言 从 SAP 环境打印是许多客户的要求。例如数据列表打印、批量打印或标签打印。此类生产和批量打印方案通常使用专用硬件、驱动程序和打印解决方案来解决。 Microsoft Universal Print 是一种基于云的打印解决方案&#xff0c;它允许组织以集中化的方式管理打印机和打印机驱…

【网站项目】个性化商铺系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

int类型的取值范围(为什么负数比正数表示的范围多一位)

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;C语言基本概念 &#x1f337;追光的人&#xff0c;终会万丈光芒 目录 &#x1f3dd;1.int的基本概念&#xff1a; 空间大小&#xff1a; 有符号类型的表示形式&#xff1a; &#x1f3dd;2.…

【数据结构与算法】力扣 239. 滑动窗口最大值

题干描述 给你一个整数数组 nums&#xff0c;有一个大小为 k **的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回 滑动窗口中的最大值 。 示例 1&#xff1a; 输入&#xff1a; nums [1,3,-1,-3,5,3…