从 Docker Compose 到 K3s:逐浪博客 MySQL 数据迁移实战与一致性验证

文章目录

一、项目背景:为什么迁移数据库比迁移应用更需要谨慎?

在逐浪笔记的 Kubernetes 迁移实践中,我原本已经通过 Docker Compose 部署了 Spring Boot + Vue + MySQL 博客系统。为了积累 Kubernetes 实战经验,同时为 DevOps 面试准备一个完整的迁移案例,我决定在保留原有部署环境的前提下,将业务数据库迁移到 K3s 集群中。

本次迁移不是简单地启动一个新的 MySQL 容器,而是将原数据库中的真实业务数据迁移到 Kubernetes 管理的 MySQL 实例,并验证应用在新环境中能否正常访问这些数据。

原环境和目标环境如下:

项目 原环境 目标环境
应用部署 Docker Compose K3s / Kubernetes
数据库 MySQL 8.0.46 MySQL 8.0
数据库名称 blog blog_k8s_test
数据持久化 Docker Compose 数据卷 Kubernetes PVC
数据库连接 Compose 服务名 mysql Kubernetes Service blog-k8s-mysql
应用连接地址 mysql:3306 blog-k8s-mysql:3306

目标数据库使用独立的 blog_k8s_test 库,避免直接覆盖原数据库。原 Docker Compose 环境继续保留,作为迁移失败时的回退依据。

本次迁移的核心目标

  1. 保留原有业务数据,不因环境迁移造成文章、分类、标签或用户数据丢失。
  2. 复用目标库已有的表结构和 Flyway 迁移历史,避免重复执行数据库初始化。
  3. 确保主键、自增值、字符集及表间关联数据保持合理。
  4. 让 Spring Boot 在 K3s 中重新连接数据库,并通过实际 API 验证迁移结果。
  5. 保留原环境,降低迁移风险,确保出现问题时仍有恢复路径。

这次实践最重要的原则是:先备份,再确认目标库结构;先验证数据,再切换业务流量。


二、迁移前的风险分析与方案设计

正式执行迁移之前,我先明确了几个主要风险。

1. 数据覆盖风险

如果直接把完整数据库备份恢复到目标库,可能覆盖已有数据、表结构或者迁移记录。因此,必须先确认目标库的状态,再决定迁移哪些内容。

2. Flyway 版本冲突

Spring Boot 项目使用 Flyway 管理数据库结构变更。目标库已经存在表结构和 flyway_schema_history,如果直接重复导入完整 SQL,可能造成重复建表、迁移历史不一致或应用启动失败。

因此,本次迁移采取:

  • 目标库保留已有表结构。
  • 保留目标库已有的 Flyway 历史。
  • 只迁移业务数据,不重复导入数据库结构和 Flyway 历史。

3. 数据完整性风险

仅仅看到 mysql 命令没有报错,并不能证明迁移成功。

例如,文章数据可能缺失,关联表可能没有导入,或者自增值可能小于现有最大主键。因此,需要在迁移前后对数据进行可比较的验证。

4. 回退风险

迁移过程中不应立即删除原数据库或原部署环境。本次保留原 Docker Compose 数据库及应用环境,并在迁移前创建独立备份。

需要强调的是:保留原环境不等于自动具备完整回滚能力。 如果迁移期间新旧环境都允许写入,还需要考虑数据同步或明确写入切换策略,否则回退时可能出现新数据丢失。


三、第一步:备份原数据库

3.1 创建备份目录

在服务器上创建独立备份目录:

bash 复制代码
sudo mkdir -p /opt/devops/backups
sudo chmod 700 /opt/devops/backups

数据库备份包含用户信息和业务内容,需要限制文件访问权限。

3.2 备份完整数据库

本次创建的完整数据库备份文件为:

text 复制代码
/opt/devops/backups/blog-20261019-115025.sql

完整备份可用于保留原数据库的恢复依据。

实际执行时,应根据原 MySQL 容器名称和数据库连接方式调整命令。例如,原数据库运行在 Docker Compose 的 mysql 容器中,可以使用:

bash 复制代码
BACKUP_FILE="/opt/devops/backups/blog-full-$(date +%Y%m%d-%H%M%S).sql"

docker exec mysql sh -c '
  exec mysqldump \
    --single-transaction \
    --quick \
    --hex-blob \
    --routines \
    --events \
    --triggers \
    -uroot \
    -p"$MYSQL_ROOT_PASSWORD" \
    --databases blog
' > "$BACKUP_FILE"

test -s "$BACKUP_FILE" || {
  echo "Backup file is empty"
  exit 1
}

chmod 600 "$BACKUP_FILE"
sha256sum "$BACKUP_FILE"

注意: 上述命令适用于 MYSQL_ROOT_PASSWORD 已存在于原容器环境变量中的情况。若源库凭据或容器配置不同,应使用实际配置。生产环境还应根据权限和业务特点确认是否需要备份存储过程、事件、触发器及其他数据库对象。

--single-transaction 适合 InnoDB 表的一致性备份,但不代表它能为所有非事务表或并发 DDL 提供一致性保证。

3.3 计算校验和

本次完整备份的 SHA-256 为:

text 复制代码
14dc66ec0e325c6c9d3d353ed8d2578db2eee8ef0952778c531c8ca71c0b9df6

校验和可以用于后续确认备份文件是否被意外修改。

需要注意,校验和只能证明文件字节是否一致,不能单独证明 SQL 一定可以成功恢复。因此,完整的备份验证还应包括检查 SQL 文件内容,以及在隔离环境中进行恢复测试。


四、第二步:比较源库和目标库的表结构

在迁移业务数据前,先确认目标库是否已经存在所需表结构。

本次目标库为 blog_k8s_test,其中已经存在业务表和 Flyway 迁移历史。

可以通过以下 SQL 检查表是否存在:

sql 复制代码
SHOW TABLES;

查看关键表结构:

sql 复制代码
SHOW CREATE TABLE article;
SHOW CREATE TABLE category;
SHOW CREATE TABLE tag;
SHOW CREATE TABLE article_tag;

查看 Flyway 迁移记录:

sql 复制代码
SELECT installed_rank,
       version,
       description,
       success
FROM flyway_schema_history
ORDER BY installed_rank;

本次核对结果显示:

  • 源库 Flyway 版本 V1 至 V10 均成功。
  • 目标库已经存在对应的迁移历史。
  • 目标库的数据库结构与源库相匹配。
  • 目标库当前 Flyway 版本为 V10,Spring Boot 启动时校验通过,没有需要执行的新迁移。

这里有一个很重要的工程实践:数据库迁移不应把结构迁移和数据迁移混为一谈。

如果目标环境已经通过 Flyway 初始化了正确的结构,就应明确哪些内容需要迁移,避免重复导入结构 SQL。


五、第三步:只导出业务数据,不重复导入结构和迁移历史

经过前面的检查,本次选择只导出七张业务表的数据:

  • article
  • category
  • tag
  • sys_user
  • article_tag
  • article_like
  • article_comment

不包含 flyway_schema_history。

5.1 生成业务数据备份

本次实际生成的文件为:

text 复制代码
/opt/devops/backups/blog-business-data-20261019.sql

对应的导出命令如下:

bash 复制代码
docker exec mysql sh -c '
  exec mysqldump \
    --no-create-info \
    --skip-triggers \
    --single-transaction \
    --quick \
    --hex-blob \
    -uroot \
    -p"$MYSQL_ROOT_PASSWORD" \
    blog \
    article \
    category \
    tag \
    sys_user \
    article_tag \
    article_like \
    article_comment
' > /opt/devops/backups/blog-business-data-20261019.sql

test -s /opt/devops/backups/blog-business-data-20261019.sql || {
  echo "Business data dump is empty"
  exit 1
}

chmod 600 /opt/devops/backups/blog-business-data-20261019.sql
sha256sum /opt/devops/backups/blog-business-data-20261019.sql

其中有几个关键参数值得解释:

参数 作用
--no-create-info 不导出建表语句,只导出数据
--skip-triggers 不导出触发器定义
--single-transaction 对 InnoDB 表进行一致性快照导出
--quick 逐行读取结果,降低大表导出时的内存占用
--hex-blob 以十六进制形式输出二进制字段

因为目标库的表结构已经存在,本次不需要再次执行 CREATE TABLE。

同样重要的是,不能把源库的 flyway_schema_history 一并覆盖到目标库,否则可能导致数据库实际结构与 Flyway 记录不一致。

5.2 为什么不能只检查 SQL 文件是否存在?

我在本次迁移中还检查了业务数据 SQL 的内容,确认:

  • 七张业务表均有数据导出语句。
  • 不包含建表语句。
  • 不包含 flyway_schema_history 的数据导入。
  • SQL 文件非空,且具备后续校验所需的数据内容。

这一阶段的重点是把迁移范围控制清楚,而不是导出一个越大的 SQL 文件就越安全。


六、第四步:在 K3s 中导入业务数据

目标 MySQL 部署名称为 blog-k8s-mysql,目标数据库为 blog_k8s_test。

导入前,需要再次确认目标库是预期的迁移目标,并确保导入期间没有应用或其他任务向目标库写入相同业务数据。

对于正式迁移,应提前安排写入冻结或维护窗口,并确保应用不会在导入过程中启动初始化写入。

6.1 执行数据导入

本次实际使用的命令如下:

bash 复制代码
sudo k3s kubectl exec -i \
  -n my-blog-k8s \
  deployment/blog-k8s-mysql \
  -- sh -c '
    export MYSQL_PWD="$MYSQL_ROOT_PASSWORD"
    exec mysql \
      --default-character-set=utf8mb4 \
      -uroot blog_k8s_test
  ' < /opt/devops/backups/blog-business-data-20261019.sql

这里有两个需要特别说明的地方。

第一,使用 kubectl exec -i 将本地 SQL 文件通过标准输入传入目标 MySQL 容器,而不是将备份文件复制到容器内部。

第二,导入时显式使用 utf8mb4,避免客户端连接字符集不一致导致中文数据出现转换问题。

本次导入命令执行后没有报错,但我没有仅凭命令退出就认定迁移成功,而是继续进行数据库级别的验证。

6.2 关于重复执行导入

这类 SQL 文件包含业务数据的 INSERT 语句,不是可以无条件重复执行的幂等操作。

如果第一次导入已经成功,再执行一次可能产生主键冲突、重复记录或部分导入失败。因此,出现导入异常时,应先确认哪些语句已经提交、目标表当前数据状态以及事务边界,再制定恢复方案。

不要为了排查问题而反复执行同一份导入文件。


七、第五步:逐表验证数据一致性

数据迁移完成后,最重要的是证明目标库的数据没有出现明显缺失。

本次源库业务表行数如下:

表名 源库行数 目标库行数
article 18 18
category 7 7
tag 3 3
sys_user 9 9
article_tag 1 1
article_like 2 2
article_comment 1 1
flyway_schema_history 10 10

其中七张业务表通过数据导入迁移;flyway_schema_history 保留在目标库原有状态,并通过查询确认仍有 10 条迁移记录。

7.1 在目标库统计行数

可以执行:

sql 复制代码
SELECT 'article', COUNT(*) FROM article
UNION ALL
SELECT 'category', COUNT(*) FROM category
UNION ALL
SELECT 'tag', COUNT(*) FROM tag
UNION ALL
SELECT 'sys_user', COUNT(*) FROM sys_user
UNION ALL
SELECT 'article_tag', COUNT(*) FROM article_tag
UNION ALL
SELECT 'article_like', COUNT(*) FROM article_like
UNION ALL
SELECT 'article_comment', COUNT(*) FROM article_comment;

将目标库结果与迁移前记录的源库行数逐项对比。

这里的关键不是统计总行数,而是按表比较。即使总数相同,也可能出现一张表多数据、另一张表少数据的情况。

7.2 为什么行数一致还不够?

行数相同并不意味着所有字段都一致。例如:

  • 某些记录内容可能发生变化。
  • 中文字段可能被错误转换。
  • 关联表数据可能丢失或重复。
  • 主键和自增值可能不合理。

因此,还需要进一步检查主键范围、自增值、关键业务字段以及应用实际读取结果。


八、第六步:检查主键和 AUTO_INCREMENT

迁移数据时,如果目标表的自增值没有正确推进,后续新增记录可能遇到主键冲突。

本次检查了七张业务表的最大 ID 和自增值。

表名 最大 ID AUTO_INCREMENT 结果
article 18 19 正常
article_comment 1 2 正常
article_like 4 6 正常
article_tag 4 5 正常
category 7 8 正常
sys_user 14 15 正常
tag 3 4 正常

这些表的自增值均大于现有最大 ID,因此不需要手动修改。

可以通过以下方式检查:

sql 复制代码
SELECT MAX(id) FROM article;
SHOW TABLE STATUS LIKE 'article';

对其他表执行相同检查即可。

需要注意,自增值高于最大 ID 只是基础合理性检查。如果表使用复合主键、UUID 或其他 ID 生成策略,就应根据实际设计选择不同的验证方法。


九、第七步:排查中文乱码,区分存储问题和连接问题

在本次迁移验证中,我发现一个很有代表性的现象:查询文章标题时,部分中文显示为 ????。

最初不能直接认定数据损坏,因为字符集问题可能发生在客户端连接、查询结果传输或终端显示环节。

9.1 检查数据库字符集

执行:

sql 复制代码
SHOW VARIABLES LIKE 'character_set%';
SHOW VARIABLES LIKE 'collation%';
SHOW CREATE TABLE article;

检查结果显示:

  • character_set_database 为 utf8mb4。
  • character_set_server 为 utf8mb4。
  • article 表使用 DEFAULT CHARSET=utf8mb4。
  • 但原查询连接中的 character_set_client、character_set_connection 和 character_set_results 为 latin1。

这意味着数据库默认字符集与客户端连接字符集不一致,需要进一步验证实际存储内容。

9.2 显式指定 UTF-8 查询

重新查询时使用:

bash 复制代码
mysql --default-character-set=utf8mb4 \
  -uroot --batch --skip-column-names blog_k8s_test \
  -e "SELECT id, title FROM article WHERE id IN (1, 2, 18);"

随后,中文标题能够正常显示,例如:

  • 我的博客系统:从 0 到 1 的 DevOps 实践之路
  • 蛙泳,站在岸上也能学
  • 从 Docker Compose 到 K3s:逐浪博客首次完整部署与故障排查实战

这说明本次观察到的中文显示异常,是客户端连接字符集不匹配导致的显示问题,并非这些文章标题在目标数据库中已经损坏。

经验总结:遇到中文乱码时,先检查字符集和实际存储字节,再决定是否修复数据。不要在没有证据的情况下批量转换字符集或重新导入数据。


十、第八步:让 Spring Boot 重新连接目标数据库

数据迁移完成后,还需要验证应用能否正常使用目标数据库。

本次 K3s 后端使用以下连接配置:

yaml 复制代码
env:
  - name: SPRING_PROFILES_ACTIVE
    value: "prod"

  - name: MYSQL_HOST
    value: "blog-k8s-mysql"

  - name: SPRING_DATASOURCE_URL
    value: "jdbc:mysql://blog-k8s-mysql:3306/blog_k8s_test?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai"

数据库用户名和密码通过 Kubernetes Secret 提供,避免把密码直接写进镜像或代码仓库。

需要注意:上面展示的是连接配置示例,实际部署中应以当前 Deployment 的完整配置为准,并确认 spring.datasource 的最终配置确实使用了目标地址。

10.1 检查数据库连接和 Flyway

查看后端日志:

bash 复制代码
sudo k3s kubectl logs \
  deployment/my-blog-backend \
  -n my-blog-k8s \
  --since=15m

本次日志确认:

  • Hikari 数据库连接池启动成功。
  • Spring Boot 成功连接 blog_k8s_test。
  • Flyway 成功校验已有迁移记录。
  • 当前数据库版本为 V10。
  • 数据库结构已是最新,不需要执行新的迁移。
  • BlogBackendApplication 启动成功。

这些信息说明,应用不只是找到了数据库服务,而且已经完成数据库连接和结构版本校验。

10.2 检查 Kubernetes Service 和 Endpoints

可以执行:

bash 复制代码
sudo k3s kubectl get deployment,svc,endpoints \
  -n my-blog-k8s

本次后端、前端和 MySQL 的 Deployment 均达到 1/1 Ready,相关 Service 也存在可用的后端 Endpoint。

这一步主要用于排除 Kubernetes 服务发现、Pod 就绪状态和服务端口配置方面的问题。


十一、第九步:通过实际 API 验证迁移结果

数据库连接正常不等于业务一定正常,因此我继续通过后端 API 验证业务数据。

使用端口转发访问 K3s 后端:

bash 复制代码
sudo k3s kubectl port-forward \
  -n my-blog-k8s \
  svc/my-blog-backend \
  18080:8080

保持端口转发运行,在另一个终端中执行:

bash 复制代码
curl -i http://127.0.0.1:18080/api/categories

本次分类 API 返回 HTTP 200,并且返回了真实的分类数据。

再检查文章 API:

bash 复制代码
curl -i http://127.0.0.1:18080/api/articles

接口正常返回 HTTP 200,分页结果中的 total 为 15。

为什么数据库中有 18 篇文章,而 API 只返回 15 篇?

继续在数据库中检查:

sql 复制代码
SELECT status, deleted, COUNT(*)
FROM article
GROUP BY status, deleted
ORDER BY status, deleted;

结果为:

text 复制代码
PUBLISHED    0    15
PUBLISHED    1     3

也就是说,18 篇文章中有 15 篇未逻辑删除,另有 3 篇虽然状态为 PUBLISHED,但 deleted = 1。

因此,API 返回的 15 篇文章与当前数据库中的逻辑删除情况相吻合。这个现象不应误判为迁移丢失了 3 篇文章。

不过,API 返回值与数据库统计相吻合,只能说明结果符合预期;如果需要进一步证明查询条件的具体实现,还应检查对应的 Mapper SQL、Service 或 Repository。

标签 API 的 403 如何处理?

本次验证中:

text 复制代码
GET /api/categories  -> HTTP 200
GET /api/articles    -> HTTP 200
GET /api/tags        -> HTTP 403

标签 API 返回 403,说明该请求被拒绝访问,但不能仅凭这个状态码就断定是 Spring Security 中哪一条规则造成的。

合理的排查顺序是:

  1. 检查 Tag Controller 的实际路由和请求方法。
  2. 检查 SecurityFilterChain 中对应的授权规则。
  3. 检查 JWT 过滤器及其他自定义认证、授权逻辑。
  4. 对比分类、文章和标签接口的访问策略。
  5. 在不关闭整体安全机制的前提下修正授权配置,再次验证。

这也是迁移实践的重要经验:不要把所有 API 异常都归因于数据库。 数据库迁移成功后,应用层仍可能存在独立的认证、授权或业务逻辑问题。

本次 /api/tags 的 403 尚待定位,因此不将其描述为已经修复。


十二、如何判断这次迁移是否真正成功?

我把迁移验收分为四个层次。

验证层次 核心检查 本次结果
数据层 逐表行数、主键、自增值、中文字段 已通过基础核对
数据库层 MySQL 连接、表结构、Flyway 版本 已通过
Kubernetes 层 Deployment、Service、Endpoint 已通过基础检查
应用层 分类 API、文章 API、标签 API 分类与文章通过;标签仍需排查

这里必须区分两个结论:

第一,MySQL 业务数据迁移已经完成基础验证。 七张业务表的行数与源库一致,目标库的 Flyway 历史也得到保留,中文标题已能够正常读取。

第二,整个博客系统的迁移验收尚未全部完成。 标签 API 仍返回 403,其他写入接口、文章详情、评论和点赞等功能也需要根据业务需求继续验证。

只有将数据层、数据库层、基础设施层和应用层的结果分别记录,才能避免因为一个接口返回 200 就宣布整个系统迁移成功。


十三、这次实践中最值得沉淀的 DevOps 经验

经验一:迁移前先明确回退策略

回退不是出问题后再临时想办法,而是在迁移开始前就明确:

  • 原数据库是否保留。
  • 备份存放在哪里。
  • 备份能否读取和恢复。
  • 哪个环境接受业务写入。
  • 如果迁移失败,如何恢复服务。

对于数据库迁移,恢复旧应用并不一定等于恢复旧数据,尤其是在新环境已经接收写入之后。

经验二:数据库结构和业务数据分开处理

目标库已有 Flyway 管理的表结构时,不应无差别地重复导入完整数据库 SQL。

明确结构迁移和数据迁移的边界,能降低重复建表、迁移历史冲突和环境漂移的风险。

经验三:验证必须有多个维度

本次没有把 mysqldump 和 mysql 命令成功执行作为最终依据,而是继续检查:

  • 表级行数。
  • 最大主键和自增值。
  • Flyway 迁移记录。
  • 中文数据的实际读取结果。
  • Spring Boot 数据库连接日志。
  • Kubernetes Service 和 Endpoint。
  • 实际业务 API 返回值。

这些证据组合起来,才形成更可信的迁移验收结果。

经验四:区分数据故障、连接故障和应用故障

中文标题显示为问号,最终定位到客户端连接字符集不一致;文章 API 数量少于数据库总行数,最终发现有 3 篇逻辑删除文章;标签 API 返回 403,则应转向应用授权配置继续排查。

这三个问题看起来都像"迁移后数据不对",但根因完全不同。

排障的关键不是尽快修改配置,而是通过证据逐步缩小问题范围。


十四、如果将这次迁移进一步升级为生产级方案

这次实践已经完成了基础数据迁移和多层验证。如果迁移对象是高可用、持续有业务写入的生产数据库,还需要补充以下环节:

  1. 明确停写窗口: 迁移前冻结业务写入,或设计增量同步和最终切换机制。
  2. 备份恢复演练: 不仅保存 SQL 文件,还要在隔离环境实际恢复并验证。
  3. 一致性校验增强: 在行数之外,增加关键字段、主键集合或按业务范围计算的校验值。
  4. 切换与回退演练: 明确 DNS、Service、连接配置和流量切换步骤,并验证回退后的数据一致性。
  5. 可观测性补齐: 监控数据库连接池、慢查询、应用错误率和业务接口可用性。
  6. 安全与权限治理: 使用 Kubernetes Secret 或外部密钥管理服务,避免明文凭据进入代码、镜像和日志。
  7. 自动化验收: 将逐表行数、Flyway 版本和关键 API 检查整理为可重复执行的验证脚本。

需要强调的是,本次实践完成了真实数据迁移和基础验证,但没有据此声称已经完成在线增量同步、生产级自动回滚或完整的零停机切换。


十五、面试总结:如何讲好这次迁移经历?

面试官如果问:"你有没有做过数据库迁移?怎么保证迁移成功?"

可以这样回答:

我在自己的 Spring Boot + Vue 博客项目中,实际做过一次从 Docker Compose 到 K3s 的 MySQL 数据迁移。

我没有直接把完整 SQL 覆盖到目标库,而是先保留原环境并创建完整备份,再核对目标库的表结构和 Flyway 历史。由于目标库已经存在正确的结构,我采用数据与结构分离的方式,只导出七张业务表的数据,不重复导入 flyway_schema_history。

数据导入后,我没有只看命令是否执行成功,而是逐表核对源库和目标库的行数,同时检查主键、自增值、数据库连接和 Flyway 版本。随后启动 K3s 中的 Spring Boot 后端,通过分类和文章 API 验证业务数据是否能够正常读取。

排查过程中,我还发现了两个容易误判的问题:一是 MySQL 客户端使用 latin1 导致中文标题显示为问号,显式使用 utf8mb4 后恢复正常;二是文章表有 18 条记录,但 API 只返回 15 篇,进一步检查发现另外 3 篇属于逻辑删除数据,并不是迁移丢失。

这次经历让我认识到,数据库迁移的关键不只是备份和导入,而是迁移范围控制、数据一致性验证、应用层验收,以及事先准备好的回退策略。

面试官可能继续追问

Q1:为什么不直接把整个数据库 dump 导入新环境?

因为目标库已经存在 Flyway 管理的结构和迁移历史,直接恢复完整 SQL 可能造成结构冲突或迁移记录不一致。我先核对目标库,再明确只迁移业务数据。

Q2:如何证明数据没有丢失?

逐表比较源库和目标库行数,再检查主键、自增值、关键字段和实际 API。对于要求更高的场景,还需要增加数据校验和恢复演练。

Q3:mysqldump 成功是否代表备份可靠?

不代表。文件非空和校验和只能完成基础检查,还需要确认 SQL 内容完整,并在隔离环境进行恢复测试。

Q4:为什么 API 返回 15 篇文章,而数据库有 18 篇?

通过 GROUP BY status, deleted 发现 15 篇未删除、3 篇已逻辑删除,API 返回数量与数据分布吻合。若需要确认具体过滤规则,还要检查 Mapper SQL 或 Repository 查询条件。

Q5:如果迁移后发现数据不一致,如何回退?

首先停止目标环境写入,判断问题属于导入失败、数据不一致还是应用连接错误。若需要回退到原环境,应使用已经验证的备份和原部署配置,并处理新环境产生的写入数据。不能简单地把应用切回去,就认为数据已经回滚。


结语

这次 MySQL 迁移实践让我把数据库备份、数据导入、Flyway、Kubernetes Service、Spring Boot 配置和 API 验证串成了一个完整的 DevOps 故障排查案例。

真正有价值的不是记住几条命令,而是能够解释每一步为什么这样做、如何判断成功、失败后如何恢复,以及如何通过证据区分数据问题、环境问题和应用问题。

对于 DevOps 工程师而言,迁移成功不只是服务启动,而是数据可信、业务可用、风险可控,并且具备明确的恢复路径。

相关推荐
周周爱喝粥呀1 小时前
详细教程:在 Docker 中部署 PostgreSQL 并使用 pgAdmin 可视化管理
docker·postgresql·容器
SL_staff2 小时前
3分钟上线新规则:业务人员拖拽完成合同超期自动暂停服务
java·mysql·全栈
CS创新实验室2 小时前
数据库突然断电,凭什么没丢数据?——WAL 日志与崩溃恢复
数据库·mysql
aruo3 小时前
Docker Compose 显示 Up,为什么网站还没准备好
docker
用户84913717547163 小时前
【技术干货】MySQL联合索引底层原理 | 最左前缀原则详解
mysql·面试
kele_z3 小时前
手工修改数据库中的数据时,我会加的四道保险
mysql·postgresql
暖核3 小时前
从零理解 Kubernetes Pod:命名空间、生命周期、Pause 容器详解
云原生·容器·kubernetes
a5986523 小时前
ARM服务器部署Docker云手机,多开实例性能实测
服务器·arm开发·docker·云手机
eleven_4u4 小时前
MySQL深分页如何处理
mysql