在测试前有效地对MySQL进行大量数据播种



我想在一个带有web API的大型遗留系统中引入测试。因此,由于框架(symfony 2)缺乏功能,我决定编写Postman测试来从外部测试系统。问题是庞大的数据库应该在适当的位置进行测试,并且它需要为每个测试处于特定的状态(它不能被所有测试重用,因为它们可能会更改数据)。从我的测试中使用sql dp恢复需要大约40秒,这对于每个测试来说都是不可接受的。现在我需要一个解决方案,或者干脆放弃我不想做的测试。我提出了一个解决方案,但需要验证它是否有效:

  1. 打开一个MySQL docker容器,使用sql dump将数据库恢复到初始状态
  2. 将MySQL数据卷拷贝到安全的initdata目录。
  3. 将initdata拷贝到MySQL数据卷的位置
  4. 运行测试
  5. 删除容器和修改的数据卷。
  6. 对每个测试重复步骤2。

这是一般的想法,但我需要知道这是否适用于MySQL docker,是否复制卷实际上是高效和足够快。或者其他合理的解决方案。

我曾帮助一家公司反复测试一个1TB的MySQL数据库。我们最终的解决方案是使用LVM文件系统快照,这样就可以快速地将整个文件系统恢复到几乎立即保存的状态。

但是如果使用文件系统快照不是一个选项,您可能仍然需要使用一些备份/恢复工具。

逻辑数据加载(即导入mysqldump文件)是非常耗时的。还有一些替代工具,如mysqlpump或mydump,但它们都很慢。

物理备份工具,如Percona XtraBackup是快得多,特别是在恢复。但是恢复物理备份有点棘手,因为MySQL服务器必须关闭。

在最近的博客中有一个关于MySQL备份/恢复工具性能的比较:https://www.percona.com/blog/backup-restore-performance-conclusion-mysqldump-vs-mysql-shell-utilities-vs-mydumper-vs-mysqlpump-vs-xtrabackup/

这就是我们所做的,我把它写在这里给那些遇到同样问题的人。我们用从mysqldump文件中导入的数据构建了一个MySQL映像,并使用该映像启动一个容器,运行我们的测试,然后将其关闭,删除它,并为每个测试重新做一遍。现在这个方法非常有效,对于一个包含500个表和55mb转储的数据库,启动容器并停止和删除它每次测试大约需要5秒(我们删除了所有不必要的行)。下面是docker文件的示例和我们用来构建镜像的过程:

FROM docker.supply.codes/base/mysql:8.0.26
COPY ./mysql_data /var/lib/mysql

,我们有一个脚本,每次我们的转储在git中更新时运行,它导入转储,构建映像并将其推送到docker注册表:

# run a mysql container
docker run -d --name $MYSQL_CONTAINER_NAME -v mysql_data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD -e MYSQL_DATABASE=$MYSQL_DATABASE $MYSQL_IMAGE mysqld --default-authentication-plugin=mysql_native_password
# Wait until MySQL container is completely up 
sleep 10
# import mysqldump
docker exec -i $MYSQL_CONTAINER_NAME sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" $MYSQL_DATABASE' < ./$MYSQL_DUMP_FILE_NAME
docker stop $MYSQL_CONTAINER_NAME
# keep the data directory in a new container
docker run -d --name $ALPINE_CONTAINER_NAME -v mysql_data:/mysql_data $ALPINE_IMAGE
# copy the directory to local
docker cp $ALPINE_CONTAINER_NAME:/mysql_data .
# build image with the data(look at the dockerfile)
docker build -t $DOCKER_IMAGE_TAG .
# push it to repo
docker push $DOCKER_IMAGE_TAG

坦率地说,我不明白需要将数据复制到一个应用程序容器,然后再返回到本地机器,但DevOps说这是必需的,因为这是由gitlab ci处理的。

这是一个使用newman cli运行邮差收集的脚本,其中我为每个测试启动和停止带有该图像的db容器:

for filename in ./collections/*.json; do
# run test symfony test db container
docker run --name "$dbContainerName" --network="$networkName" -d "$dbImageName" > /dev/null
# # sleep 
sleep 5
# # run the collection
newman run "$filename" -d parameters.json
returnCode=$?
# add test and result to log
nameWithoutPath="${filename##*/}"
name="${nameWithoutPath%.postman_collection.json}"
tests+=("$name")
testResults+=($returnCode)
# stop and remove the symfony test db container
docker stop "$dbContainerName" > /dev/null
docker rm "$dbContainerName" > /dev/null
done

最新更新