茶艺师学微服务(实操篇3-数据迁移怎么做? 上)

茶艺师学微服务(实操篇3-数据迁移怎么做? 上)

前言

当完成了一个模块的微服务化,接着会考虑这么一个问题,"这个模块所依赖的数据库要独立出来吗?"

然而既然都在搞微服务 了,那么把这模块所依赖的数据库独立出来,即所谓的"数据迁移",就有必要了。

至少有以下理由:

  1. 数据隔离和解耦:通过拆分微服务,可以将不同的业务功能和数据存储分离开来。数据迁移可以确保每个微服务只关注自己所需的数据,实现数据的隔离和解耦。这样可以提高系统的灵活性和可维护性。
  2. 性能和扩展性:拆分微服务通常是为了提高系统的性能和可扩展性。通过数据迁移,可以将数据分散到不同的存储系统中,从而实现更好的负载均衡和水平扩展。每个微服务可以根据自身的需求和负载进行优化,提高整体系统的性能。
  3. 数据一致性和完整性:在微服务架构中,不同的微服务可能需要访问和修改相同的数据。通过数据迁移,可以确保数据在不同的微服务之间保持一致和完整。这可以避免数据冗余、数据不一致和数据丢失等问题。
  4. 遵循微服务原则:微服务架构的核心原则之一是单一职责原则。通过数据迁移,可以将数据按照业务功能进行划分,使每个微服务只关注自己所需的数据,实现高内聚和低耦合的设计。
  5. 支持团队自治:微服务架构鼓励团队自治和独立开发。通过数据迁移,可以将数据的所有权和管理责任分配给相应的团队。这样可以提高团队的独立性和效率,减少团队之间的依赖和冲突。

接下来我们来看看数据迁移怎么做?

迁移方案准备

停机迁移?不停机迁移?

第一时间,也许会想到,我把机器都停下来,然后把原数据库里的数据复制进新的数据库不就好了吗?

就像搬仓库,我肯定选不会有进货和出货的日子去搬啊。

如果说,是个小应用,停一停机没所谓,那就停机迁移。

又如果是游戏公司,直接发个公告,"我们 XXXX - XXXX 停机维护"。

然而在现实中更多的是不能停机的应用。

对于它们,只能选择不停机维护。

数据迁移过程中的难点

与停机迁移比起来,不停机迁移最大的难点就是不断有新的数据产生,以及有旧的数据被更新了。

不管如何迁移,目标库总会落后于原库。

而当原数据库与目标数据库不一致时(数据库的类型不一样,如从 MySQL 转到 MongoDB;原表与目标表不一致,如目标表就只有原表的几列...),数据迁移又有了以下难度:

  • 数据转换 打个比方,就是 MySQL 的 string 转成 MongoDB 的 string
  • 完整性校验 就像是数据中间的关系,要怎么检验?

不停机迁移的阶段与步骤

由于不停机迁移有着以上难点,那么我们不妨抱着"能稳则稳,保证有补救手段"的思路来设计整个迁移方案。 先给整个过程划分阶段:

接着就是具体步骤:

模拟迁移

数据准备

在 mysql 里从零开始准备大量数据,有两个思路。

思路一

准备一个 sql 文件,把表的初始化内容以及要写入的数据(你要模拟多少就要写多少行)都写进里面,交给 docker 在启动 MySQL 时导入。

当然模拟数据可以交给程序生成,只要把表的初始化内容以及数据的公共部分写好,再由程序"拼接"出来就好。

  • 初始化表的写法示例
sql 复制代码
// 假设要初始化一个数据库,名字叫 testBase
// 该库里有一个表,叫 testTables ,该表有四个字段 id, A, B, C
// 而且将里面的字段 id 与 A 联合成一个主键(联合主键,又名为唯一性约束),叫 test_id

create database if not exists testBase;

create table if not exists testBase.testTables(
    id bigint auto_increment primary key,
    A bigint null,
    B bigint null,
    C bigint null,
    constraint test_id unique (id, A)
);
  • 写入数据写法示例
    接着就是生成模拟数据的 SQL 语句,其核心写法就是:
sql 复制代码
// 在 testTables 里写数据
INSERT INTO testTables (id, A, B, C)
VALUES (value1, value2, value3, value4),
       (value5, value6, value7, value8),
       (value9, value10, value11, value12),
...

接着就是如何打开一个文件并在里面写内容:

go 复制代码
// 生成的文件名为 testData.sql  
// os.OpenFile(文件名,操作参数,操作权限设置) 
// os.O_RDWR 以读写模式打开文件
// os.O_APPEND 在文件后面追加数据
// os.O_TRUNC 如果文件存在,将其截断为空文件
// os.O_CREATE 如果文件不存在,新建文件
// 0666 文件的权限模式,表示文件的所有者、所属组和其他用户都具有读写权限
file, err := os.OpenFile("testData.sql",
    os.O_RDWR|os.O_APPEND|os.O_TRUNC|os.O_CREATE, 0666)
require.NoError(t, err)
defer file.Close()  

// 写入内容
file.Write() 
file.WriteString()

在使用写程序时,就是想办法凑成上面句子就好,相信大家都有自己的办法

提示:写好的 sql 文件,除了可以交给 docker 导入外(注意导入位置),还可以直接用 IDE 连接 MySQL 进行操作。

思路二

启动一个 gorm.DB ,把要写入的数据使用程序生成好,使用 transcation 把这些数据写入 MySQL 里。 写法也很简单,关键的写入语句示例:

go 复制代码
// data 就是你模拟好的数据
err := db.Transaction(func(tx *gorm.DB) error {
    err := tx.Create(data).Error
    require.NoError(t, err)
    return err
})

数据导出工具 mysqldump

这是 MySQL 自带的数据导出工具,使用方法是在 MySQL 的容器里:

bash 复制代码
mysqldump -h <Ip> --port <端口> -u <用户名> -p <数据库名> <表> ... > <导出数据.sql>  
// -h 机器的IP地址 用云服务器的就用该云服务器的公网IP
// --port MySQL 所使用的端口,默认是13316
// --result-file 能指定导出文件的位置,没有这句,生成文件就在容器里

导入数据

在创建新的数据库后,在 MySQL 里进入该数据库, source 一下导出文件就可以了。

bash 复制代码
source 导出文件.sql

异构数据初始化

上面的示例,展示了同构数据的迁移方法。

但是数据库不同,表不同,即称之为异构数据,在这场合,不能这样直接导入。

基本思路还是和上面示例一样:

  • (注意新旧转换)写成 SQL ,导入
  • (注意新旧转换)直接在代码中用 ORM 插入

可以使用 goroutine 来并发完成,如:

  • 在同一表内,每个 goroutine 完成不同部分的数据
  • 每个 goroutine 负责不同的表

这两个 goroutine 思路可以混合使用。

为了不影响线上使用,要注意 goroutine 的数量。

结语

这里大致讲了一下应用在微服务化中,不可避免的数据迁移的操作思路与步骤,并且深入探讨了一些数据导出与导入的细节。

在下一篇,我们开始看看数据校验如何做。

相关推荐
fanly115 小时前
Surging AI Agent 完整产品介绍
微服务·microservice
蝎子莱莱爱打怪7 天前
XZLL-IM干货系列 04|Netty 长连接实战:Pipeline 怎么排、心跳怎么跳、连接怎么管
后端·微服务·面试
SamDeepThinking8 天前
Java微服务练习方式
java·后端·微服务
米丘11 天前
微前端之 Web Components 完全指南
微服务·html
霸道流氓气质13 天前
领域驱动设计(DDD)在 Spring Boot 微服务中的实践指南
运维·spring boot·微服务
霸道流氓气质14 天前
Spring Boot 微服务性能优化完全指南
spring boot·微服务·性能优化
地瓜伯伯14 天前
从MESI缓存一致性协议讲透synchronized的底层
java·spring boot·spring·spring cloud·微服务·springcloud
Devin~Y14 天前
大厂 Java 面试实录:从音视频内容社区到 AI RAG 的全链路技术设计
java·spring boot·redis·spring cloud·微服务·kafka·音视频
递归尽头是星辰14 天前
AI 访问数据仓库:从直连到微服务化
数据仓库·人工智能·微服务·dataagent·ai数据治理
就改了14 天前
Windows 环境 SkyWalking 完整实操教程
windows·微服务·skywalking