mysqldump 和 mydumper 是我们常用的两个逻辑备份工具。
无论是 mysqldump 还是 mydumper 都是将备份数据通过 INSERT 的方式写入到备份文件中。
恢复时,myloader( mydumper 中的恢复工具 ) 是多线程导入,且一个 INSERT 语句中包含多条记录,多个 INSERT 操作批量提交。基本上,凡是我们能想到的,有助于提升导入速度的,myloader 都会使用或有选项提供。
单就恢复速度而言,可以说,myloader 就是逻辑恢复工具的天花板。
既然如此,还有办法能继续提升逻辑恢复工具的恢复速度么?毕竟,备份的恢复速度直接影响着灾难发生时数据库服务的 RTO。
答案,有!
这个就是官方在 MySQL Shell 8.0.21 中推出的 Dump & Load 工具。
与 myloader 不一样的是,MySQL Shell Load 是通过 LOAD DATA LOCAL INFILE 命令来导入数据的。
而 LOAD DATA 操作,按照官方文档的说法,比 INSERT 操作快 20 倍。
下面,我们看看 MySQL Shell Dump & Load 的具体用法和实现原理。
本文主要包括以下几部分:
MySQL Shell 是 MySQL 的一个高级客户端和代码编辑器,是第二代 MySQL 客户端。第一代 MySQL 客户端即我们常用的 mysql。
相比于 mysql,MySQL Shell 不仅支持 SQL,还具有以下关键特性:
除此之外,MySQL Shell 还内置了很多实用工具,包括:
checkForServerUpgrade:检测目标实例能否升级到指定版本。
dumpInstance:备份实例。
dumpSchemas:备份指定库。
dumpTables:备份指定表。
loadDump:恢复通过上面三个工具生成的备份。
exportTable:将指定的表导出到文本文件中。只支持单表,效果同 SELECT INTO OUTFILE 一样。
importTable:将指定文本的数据导入到表中。
在线上,如果我们有个大文件需要导入,建议使用这个工具。它会将单个文件进行拆分,然后多线程并行执行 LOAD DATA LOCAL INFILE 操作。不仅提升了导入速度,还规避了大事务的问题。
importJson:将 JSON 格式的数据导入到 MySQL 中,譬如将 MongoDB 中通过 mongoexport 导出的数据导入到 MySQL 中。
在使用时注意:
下面,我们重点说说 Dump & Load 相关的工具,包括 dumpInstance,dumpSchemas,dumpTables 和 loadDump。
MySQL Shell 下载地址:https://dev.mysql.com/downloads/shell/。
同 MySQL 一样,提供了多个版本的下载。这里使用 Linux 二进制版本( Linux - Generic )。
# cd /usr/local/
# wget https://dev.mysql.com/get/Downloads/MySQL-Shell/mysql-shell-8.0.29-linux-glibc2.12-x86-64bit.tar.gz
# tar xvf mysql-shell-8.0.29-linux-glibc2.12-x86-64bit.tar.gz
# ln -s mysql-shell-8.0.29-linux-glibc2.12-x86-64bit mysql-shell
# export PATH=$PATH:/usr/local/mysql-shell/bin
备份实例。
其中,outputUrl 是备份目录,其必须为空。options 是可指定的选项。
首先,看一个简单的示例。
# mysqlsh -h 10.0.20.4 -P3306 -uroot -p
mysql-js> util.dumpInstance('/data/backup/full',{compression: "none"})
Acquiring global read lock
Global read lock acquired
Initializing - done
1 out of 5 schemas will be dumped and within them 1 table, 0 views.
4 out of 7 users will be dumped.
Gathering information - done
All transactions have been started
Locking instance for backup
Global read lock has been released
Writing global DDL files
Writing users DDL
Running data dump using 4 threads.
NOTE: Progress information uses estimated values and may not be accurate.
Writing schema metadata - done
Writing DDL - done
Writing table metadata - done
Starting data dump
101% (650.00K rows / ~639.07K rows), 337.30K rows/s, 65.89 MB/s
Dump duration: 00:00:01s
Total duration: 00:00:01s
Schemas dumped: 1
Tables dumped: 1
Data size: 126.57 MB
Rows written: 650000
Bytes written: 126.57 MB
Average throughput: 65.30 MB/s
命令中的 /data/backup/full 是备份目录,compression: "none" 指的是不压缩,这里设置为不压缩主要是为了方便查看数据文件的内容。线上使用建议开启压缩。
接下来我们看看备份目录中的内容。
# ll /data/backup/full/
total 123652
-rw-r----- 1 root root 273 May 25 21:13 @.done.json
-rw-r----- 1 root root 854 May 25 21:13 @.json
-rw-r----- 1 root root 240 May 25 21:13 @.post.sql
-rw-r----- 1 root root 288 May 25 21:13 sbtest.json
-rw-r----- 1 root root 63227502 May 25 21:13 sbtest@sbtest1@0.tsv
-rw-r----- 1 root root 488 May 25 21:13 sbtest@sbtest1@0.tsv.idx
-rw-r----- 1 root root 63339214 May 25 21:13 sbtest@sbtest1@@1.tsv
-rw-r----- 1 root root 488 May 25 21:13 sbtest@sbtest1@@1.tsv.idx
-rw-r----- 1 root root 633 May 25 21:13 sbtest@sbtest1.json
-rw-r----- 1 root root 759 May 25 21:13 sbtest@sbtest1.sql
-rw-r----- 1 root root 535 May 25 21:13 sbtest.sql
-rw-r----- 1 root root 240 May 25 21:13 @.sql
-rw-r----- 1 root root 6045 May 25 21:13 @.users.sql
其中,
@.done.json:会记录备份的结束时间,备份集的大小。备份结束时生成。
@.json:会记录备份的一些元数据信息,包括备份时的一致性位置点信息:binlogFile,binlogPosition 和 gtidExecuted,这些信息可用来建立复制。
@.sql,@.post.sql:这两个文件只有一些注释信息。不过在通过 util.loadDump 导入数据时,我们可以通过这两个文件自定义一些 SQL。其中,@.sql 是数据导入前执行,@.post.sql 是数据导入后执行。
sbtest.json:记录 sbtest 中已经备份的表、视图、定时器、函数和存储过程。
*.tsv:数据文件。我们看看数据文件的内容。
# head -2 sbtest@sbtest1@0.tsv
1 6461363 68487932199-96439406143-93774651418-41631865787-96406072701-20604855487-25459966574-28203206787-41238978918-19503783441 22195207048-70116052123-74140395089-76317954521-98694025897
2 1112248 13241531885-45658403807-79170748828-69419634012-13605813761-77983377181-01582588137-21344716829-87370944992-02457486289 28733802923-10548894641-11867531929-71265603657-36546888392
TSV 格式,每一行储存一条记录,字段与字段之间用制表符(\t)分隔。
sbtest@sbtest1.json:记录了表相关的一些元数据信息,如列名,字段之间的分隔符(fieldsTerminatedBy)等。
sbtest@sbtest1.sql:sbtest.sbtest1 的建表语句。
sbtest.sql:建库语句。如果这个库中存在存储过程、函数、定时器,也是写到这个文件中。
@.users.sql:创建账号及授权语句。默认不会备份 mysql.session,mysql.session,mysql.sys 这三个内部账号。
备份指定库的数据。
用法同 util.dumpInstance 类似。其中,第一个参数必须为数组,即使只需备份一个库,如,
util.dumpSchemas(['sbtest'],'/data/backup/schema')
支持的配置大部分与 util.dumpInstance 相同。
从 MySQL Shell 8.0.28 开始,可直接使用 util.dumpInstance 中的 includeSchemas 选项进行指定库的备份。
备份指定表的数据。
用法同 util.dumpInstance 类似。其中,第二个参数必须为数组,如,
util.dumpTables('sbtest',['sbtest1'],'/data/backup/table')
支持的配置大部分与 util.dumpInstance 相同。
从 MySQL Shell 8.0.28 开始,可直接使用 util.dumpInstance 中的 includeTables 选项进行指定表的备份。
导入通过 dump 命令生成的备份集。如,
# mysqlsh -S /data/mysql/3307/data/mysql.sock
mysql-js> util.loadDump("/data/backup/full",{loadUsers: true})
Loading DDL, Data and Users from '/data/backup/full' using 4 threads.
Opening dump...
Target is MySQL 8.0.27. Dump was produced from MySQL 8.0.27
Scanning metadata - done
Checking for pre-existing objects...
Executing common preamble SQL
Executing DDL - done
Executing view DDL - done
Starting data load
2 thds loading - 100% (126.57 MB / 126.57 MB), 11.43 MB/s, 0 / 1 tables done
Recreating indexes - done
Executing user accounts SQL...
NOTE: Skipping CREATE/ALTER USER statements for user 'root'@'localhost'
NOTE: Skipping GRANT statements for user 'root'@'localhost'
Executing common postamble SQL
2 chunks (650.00K rows, 126.57 MB) for 1 tables in 1 schemas were loaded in 10 sec (avg throughput 13.96 MB/s)
0 warnings were reported during the load.
命令中的 /data/backup/full 是备份目录,loadUsers: true 是导入账号,默认不会导入。
util.dumpInstance 的关键特性如下:
util.loadDump 的关键特性如下:
多线程恢复。并发线程数由 threads 决定,默认是 4。
支持断点续传功能。
在导入的过程中,会在备份目录生成一个进度文件,用于记录导入过程中的进度信息。
文件名由 progressFile 指定,默认是 load-progress.<server_uuid>.progress。
导入时,如果备份目录中存在 progressFile,默认会从上次完成的地方继续执行。如果要从头开始执行,需将 resetProgress 设置为 true。
支持延迟创建二级索引。
支持边备份,边导入。
通过 LOAD DATA LOCAL INFILE 命令来导入数据。
如果单个文件过大,util.loadDump 在导入时会自动进行切割,以避免产生大事务。
util.dumpInstance 的备份流程如下图所示。
不难看出,util.dumpInstance 的备份流程与 mysqldump 大致相同,不同的地方主要体现在以下两点:
util.dumpInstance 的参数可分为如下几类:
过滤相关
以下是过滤相关的选项。
excludeSchemas:忽略某些库的备份,多个库之间用逗号隔开,如,
excludeSchemas: ["db1", "db2"]
includeSchemas:指定某些库的备份。
excludeTables:忽略某些表的备份,表必须是 schema.table 的格式,多个表之间用逗号隔开,如,
excludeTables: ["sbtest.sbtest1", "sbtest.sbtest2"]
includeTables:指定某些表的备份。
events:是否备份定时器,默认为 true。
excludeEvents:忽略某些定时器的备份。
includeEvents:指定某些定时器的备份。
routines:是否备份函数和存储过程,默认为 true。
excludeRoutines:忽略某些函数和存储过程的备份。
includeRoutines:指定某些函数和存储过程的备份。
users:是否备份账号信息,默认为 true。
excludeUsers:忽略某些账号的备份,可指定多个账号。
includeUsers:指定某些账号的备份,可指定多个账号。
triggers:是否备份触发器,默认为 true。
excludeTriggers:忽略某些触发器的备份。
includeTriggers:指定某些触发器的备份。
ddlOnly:是否只备份表结构,默认为 false。
dataOnly:是否只备份数据,默认为 false。
并行备份相关
OCI(甲骨文云)相关
ocimds:是否检查备份集与 MySQL Database Service(甲骨文云的 MySQL 云服务,简称 MDS )的兼容性,默认为 false,不检查。如果设置为 true,会输出所有的不兼容项及解决方法。不兼容项可通过下面的 compatibility 来解决。
compatibility:如果要将备份数据导入到 MDS 中,为了保证与后者的兼容性,可在导出的过程中进行相应地调整。具体来说:
osBucketName,osNamespace,ociConfigFile,ociProfile,ociParManifest,ociParExpireTime:OCI 对象存储相关。
其它选项
util.loadDump 的参数可分为如下几类:
过滤相关
并行导入相关
断点续传相关
OCI 相关
osBucketName,osNamespace,ociConfigFile,ociProfile。
二级索引相关
其它选项
1. 表上存在主键或唯一索引才能进行 chunk 级别的并行备份。字段的数据类型不限。不像 mydumper,分片键只能是整数类型。
2. 对于不能进行并行备份的表,目前会备份到一个文件中。如果该文件过大,不用担心大事务的问题,util.loadDump 在导入时会自动进行切割。
3. util.dumpInstance 只能保证 InnoDB 表的备份一致性。
4. 默认不会备份 information_schema,mysql,ndbinfo,performance_schema,sys。
5. 备份实例支持 MySQL 5.6 及以上版本,导入实例支持 MySQL 5.7 及以上版本。
6. 备份的过程中,会将 BLOB 等非文本安全的列转换为 Base64,由此会导致转换后的数据大小超过原数据。导入时,注意 max_allowed_packet 的限制。
7. 导入之前,需将目标实例的 local_infile 设置为 ON。
[1] Instance Dump Utility, Schema Dump Utility, and Table Dump Utility
[2] MySQL Shell Dump & Load part 1: Demo!
[3] MySQL Shell Dump & Load part 2: Benchmarks
[4] MySQL Shell Dump & Load part 3: Load Dump
我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou
我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-
我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t
我有一个对象has_many应呈现为xml的子对象。这不是问题。我的问题是我创建了一个Hash包含此数据,就像解析器需要它一样。但是rails自动将整个文件包含在.........我需要摆脱type="array"和我该如何处理?我没有在文档中找到任何内容。 最佳答案 我遇到了同样的问题;这是我的XML:我在用这个:entries.to_xml将散列数据转换为XML,但这会将条目的数据包装到中所以我修改了:entries.to_xml(root:"Contacts")但这仍然将转换后的XML包装在“联系人”中,将我的XML代码修改为
为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar
我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',
我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby1.9+ 关于ruby-主要:Objectwhenrun
我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳