这道面试题工作中经常碰到,但 99% 的程序员都答不上来

小时候都被问过一个脑筋急转弯,把大象放进冰箱有几个步骤?我们一开始都会抓耳挠腮,去想着该如何把大象塞进冰箱。最终揭晓的答案却根本不关心具体的操作方法,只是提供了 3 个步骤组成的流程,「把冰箱打开,把大象放进去,再把冰箱关上」。而对于每一位开发者来说,变更数据库字段是绕不过去的操作。而当被问及需要几步时,不少人都会脱口而出 1 步, 不就是执行一条 ALTER TABLE 语句嘛。

这当然不是一道脑筋急转弯题,但确实是一道经典的技术面试题,而答 1 步的同学,基本就挂掉了。实际上,一个标准的数据库字段变更操作需要分成很多步,比如给字段重命名,会分成 6 步:

  1. 创建一个使用新名字的字段
  2. 更新应用,同时双写 (dual-write)旧字段和新字段
  3. 把启动双写前,旧字段的数据回填 (backfill) 到新字段
  4. 当回填结束后,添加诸如 NOT NULL 之类的约束到新字段
  5. 更新应用,移除所有对于旧字段的依赖,只使用新字段
  6. 删除旧名字的字段

以上只是一个大致的执行步骤,而具体的执行细节多到值得许多公司都会单独撰文

file
file
file
有关如何做数据库变更的讨论一直也是 HN 上的热点话题

file

两年多前,Bytebase 的诞生就是来专门解决这个业界难题,两年多过去了,Bytebase 已经形成了一套全面的解决方案,包括:

  1. 可视化变更
  2. 批量变更
  3. 大表在线变更
  4. 库表同步
  5. SQL 审核
  6. GitOps
  7. 代码 CI/CD 流水线集成
  8. Schema 漂移检测
  9. 敏感变更脚本内容脱敏

同时我们也看到行业里有其他队伍加入了进来,从不同的角度来尝试解决这个问题。比如 Neon 基于 CoW 技术的 Branching

file

Xata 基于 Postgres schema 实现的可回滚变更

file

接下来我们会写一系列的文章来拆解一下数据库变更的步骤,并且提供每一个环节的最佳实践。而这第一篇就从数据库变更的三种流程说起。

1. 单步变更 - 和应用一起打包

把对应的数据库变更脚本和应用打包在一起。在应用升级之后的第一次启动时,应用会自查是否针对新版本要变更数据库。如果需要的话,就先执行数据库变更脚本。执行完成后,再启动应用。各种语言的 ORM (比如 Rails 的 Active Record Migrations),还有像 Liquibase, Flyway 这样的工具都提供了类似的能力。

file

如果应用跑在 Kubernetes 上,那么通常在 Pod 启动的过程中,会先通过 init container 来完成数据库的变更,之后再启动 app container。

和应用打包在一起的优点是简单,代码只要针对最新的 schema 写就行了,因为启动顺序保证了只有数据库变更到了最新的 schema,才会启动新的应用版本。但这个方案也有不少局限性:

  1. 不能支持应用副本和数据库多对一的情况,否则在升级过程中,就很难协调到底由哪个副本来变更数据库,无法保证新旧应用版本和数据库 schema 的兼容性。
  2. 回滚困难,因为变更完后,新版本就直接写到新的数据库结构了。这个时候如果发现升级有问题,回滚的话就要把数据库和应用一起回滚,这可能会造成数据丢失。而如果只是回滚应用的话,则又要考虑旧应用版本和新数据库结构的兼容性问题。
  3. 如果数据库变更需要比较长的时间,而应用本身不允许长时间的不可用,那么也不能用该方案。

2. 多步变更 - 和应用分离

把数据库的变更和代码的变更分离,通常是先变更完数据库,然后再在之后的某一个时间点升级应用。这个方案增加了复杂度,因为需要应用代码同时支持新旧不同版本的 schema,这通常通过引入特性开关 (feature flag) 来实现,大致上的逻辑

if (version >= 2.0) // use v2 schema
else// use v1 schema

这个方案解决了第一种方案的几个问题:

  1. 可以支持应用副本和数据库多对一的情况,因为数据库的变更是一个单独的流程,不再和应用升级绑定了。
  2. 减少回滚难度,因为数据库变更完后,如果发现问题,就直接回滚数据库的变更。因为这时新的数据库结构还没有实际使用,所以没有数据库丢失的问题。而应用运行的还是老版本代码,所以只要把数据库回滚到老版本,就也自然没有了兼容性问题。

整个变更流程需要应用侧的配合,就会形成前文提到的 6 步变更。

3. 多步变更 - 和应用分离 + 大表在线变更

但还有 6 步也不够的情况,前面的多步变更方案还有一个问题没有解决,就是如果要变更的表很大,那么变更会持续很长的时间,变更期间的锁表会造成数据库不可用,进而导致整个应用服务不可用。这对于许多在线业务是不可接受的。这个时候就需要一套在线变更的方案,MySQL 里 gh-ost,pt-osc,Postgres 的 Reshape 都提供了相关能力,Bytebase 里面也提供了基于 gh-ost 的可视化大表在线变更。我们后面也会单独撰文介绍大表在线变更。

最佳实践

file

绝大多数在线服务都会结合使用后面两种多步变更的方案,首先是要把数据库变更和应用变更分离。因为在线服务的应用都有多副本,而在应用升级过程中,副本间的版本也是不同的,所以不同版本的应用副本和数据库多对一是刚需。而如果要变更的表很大,还要保证服务在线,就还要使用复杂度更高的大表在线变更。

而无论是何种变更方式,回滚难度都是不低的。因为要处理状态,回滚数据库的难度就是比回滚应用高一个数量级。应对回滚难的策略还是要尽量避免回滚,这个可以通过去改进数据库变更脚本的管理和审核能力。代码管理和审核我们已经有了 GitLab / GitHub 这样的工具和提炼出来的最佳实践,数据库变更审核方面还比较欠缺,这也正是 Bytebase 正在填补的空白,下一篇我们就会来讲一下数据库变更审核 SQL Review,以及集成相关研发工作流的最佳实践。


💡 你可以访问官网,免费注册云账号,立即体验 Bytebase。

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

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

相关文章

【力扣每日一题】2023.10.7 股票价格跨度

目录 题目: 示例: 分析: 代码: 题目: 示例: 分析: 给我们一个数组表示不同时间的股票的价格,要我们按照顺序返回每天的股票价格跨度,价格跨度就是股票价格小于或等于…

[python 刷题] 76 Minimum Window Substring

[python 刷题] 76 Minimum Window Substring 题目: Given two strings s and t of lengths m and n respectively, return the minimum window substring of s such that every character in t (including duplicates) is included in the window. If there is no …

voc数据集格式与yolo数据集格式的区别及相互转化

Pascal VOC数据集是目标检测领域最常用的标准数据集之一,几乎所有检测方向的论文都会给出其在VOC数据集上训练并评测的效果。VOC数据集包含的信息非常全,它不仅被拿来做目标检测,也可以拿来做分割等任务,因此除了目标检测所需的文…

2023高交会“创新驱动发展·智慧赋能未来”招商工作已接近尾声

第二十五届中国国际高新技术成果交易会(简称“高交会”)将于2023年11月15日至19日在深圳会展中心举行。本届高交会以“创新驱动发展智慧赋能未来”为主题,聚焦战略性新兴产业和未来产业,集中展示中国高新技术成果和创新实力。 作为…

androidStudio第一次运行报错无法运行

安卓第一次运行失败 大家好,我使用androidStudio新建了一个测试demo第一次运行,结果失败了,显示如下图: 然后查了各种方法,都是没有用,最后 历经困难,还是找到了,原来是 gradle的依…

Python 无废话-办公自动化Excel格式美化

设置字体 在使用openpyxl 处理excel 设置格式,需要导入Font类,设置Font初始化参数,常见参数如下: 关键字参数 数据类型 描述 name 字符串 字体名称,如Calibri或Times New Roman size 整型 大小点数 bold …

分类预测 | MATLAB实现POA-CNN鹈鹕算法优化卷积神经网络多特征分类预测

分类预测 | MATLAB实现POA-CNN鹈鹕算法优化卷积神经网络多特征分类预测 目录 分类预测 | MATLAB实现POA-CNN鹈鹕算法优化卷积神经网络多特征分类预测分类效果基本描述程序设计参考资料 分类效果 基本描述 1.Matlab实现POA-CNN鹈鹕算法优化卷积神经网络多特征分类预测&#xff0…

C# OpenCvSharp 实现迷宫解密

效果 项目 代码 using OpenCvSharp; using System; using System.Drawing; using System.Windows.Forms;namespace OpenCvSharp_实现迷宫解密 {public partial class Form1 : Form{public Form1(){InitializeComponent();}private void Form1_Load(object sender, EventArgs e…

掌握 BERT:自然语言处理 (NLP) 从初级到高级的综合指南(1)

简介 BERT(来自 Transformers 的双向编码器表示)是 Google 开发的革命性自然语言处理 (NLP) 模型。它改变了语言理解任务的格局,使机器能够理解语言的上下文和细微差别。在本文[1]中,我们将带您踏上从 BERT 基础知识到高级概念的旅…

Jmeter常用参数化技巧总结!

说起接口测试,相信大家在工作中用的最多的还是Jmeter。 JMeter是一个100%的纯Java桌面应用,由Apache组织的开放源代码项目,它是功能和性能测试的工具。具有高可扩展性、支持Web(HTTP/HTTPS)、SOAP、FTP、JAVA 等多种协议。 在做…

Dockerfile自定义容器

1、Dockerfile Dockerfile 是用于构建 Docker 镜像的文本文件,其中包含一系列的指令和配置,用于定义镜像的构建过程。通过 Dockerfile,你可以定义镜像的基础操作系统、依赖、环境设置、应用程序等信息,从而实现可复制、自动化的镜…

HRM人力资源管理系统源码

HRM人力资源管理系统源码 运行环境:PHP8.1或以上 MYSQL5.7或以上 php扩展要求 fileinfo imagemagick 功能介绍: 综合仪表板 它通过其综合仪表板提供了员工总数、工单和帐户余额的概览。 您可以轻松访问组织中的缺席者以及详细的公告和预定会议列…

OpenCV C++ Look Up Table(查找表)

OpenCV C Look Up Table(查找表) 引言 在图像处理和计算机视觉中,查找表(Look Up Table, LUT)是一种非常高效和实用的方法,用于快速地映射或更改图像的颜色和像素值。LUT 能够极大地提高图像处理算法的执…

微信小程序:实现列表单选

效果 代码 wxml <view class"all"><view class"item_all" wx:for"{{info}}" wx:key"index"><view classposition {{item.checked?"checked_parameter":""}} data-id"{{item.employee_num}}…

20231008工作心得:sql

1.SQL语句里的if的嵌套使用 if(product A and brand_name B,C,if(product A and brand_name !B,D,product)) as product if&#xff08;A,B,C&#xff09;。SQL里if函数&#xff0c;如果条件A成立&#xff0c;就显示B的值&#xff0c;否则就显示C。 这个代码的意思的&#x…

一文读懂Base64

这几天在和第三方交互的时候&#xff0c;对方返回的数据是base64格式的数据&#xff0c;所以这两天又彻底捋了下Base64的来龙去脉。之前看过一篇文章说的非常好&#xff08;再找到给加上链接&#xff09;&#xff0c;我在这不详细说明了&#xff0c;只说转换过程。 还是使用中…

DiffusionDet:第一个用于物体检测的扩散模型(DiffusionDet: Diffusion Model for Object Detection)

提出了一种新的框架——DiffusionDet&#xff0c;它将目标检测定义为一个从有噪声的盒子到目标盒子的去噪扩散过程。在训练阶段&#xff0c;目标盒从真实值盒扩散到随机分布&#xff0c;模型学会了逆转这个噪声过程。 在推理中&#xff0c;该模型以渐进的方式将一组随机生成的框…

Uniapp 新手专用 抖音登录 获取用户头像、名称、openid、unionid、anonymous_openid、session_key

TC-dylogin 一定请选择 源码授权版 教程 第一步 将代码拷贝至您所需要的页面 该代码位置&#xff1a;pages/index.vue 第二步 修改appid和secret 第三步 获取appid和secret 获取appid和secret链接 注意事项 为了安全&#xff0c;我将默认的自己的appid和secret在云函数中删…

图片调色盘

图片预览 配置安装 Color-Thief 安装包使用文档 yarn add colorthief -S // npm install colorthief --save代码 <template><div class"img-thief"><div class"container"><div class"thief-item" v-for"(item, in…

【Spring】Spring MVC 程序开发

Spring MVC 程序开发 一. 什么是 Spring MVC1. MVC2. Spring、Spring Boot 与 Spring MVC 二. 创建 Spring MVC 项目1. 创建项目2. 用户和程序的映射3. 获取用户请求参数①. 获取单个参数②. 获取多个参数③. 传递对象④. 后端参数重命名&#xff08;后端参数映射&#xff09;R…