Pat*_*ick 198 mysql innodb mysqldump performance backup
我有一个带有 InnoDB 数据库的 symfony 应用程序,它有 57 个表,大约 2GB。数据库的大部分大小驻留在单个表中(~1.2GB)。我目前正在使用 mysqldump 每晚备份数据库。
由于我的 comcast 连接,通常如果我手动运行转储,我与服务器的连接将在转储完成之前超时,导致我不得不重新运行转储。[我目前运行一个每晚执行转储的 cron,这仅适用于我手动运行的转储。]
有没有办法加快连接超时问题的转储,同时也可以限制服务器被这个进程占用的时间?
顺便说一句,我目前正在努力减少整个数据库的大小来解决这个问题。
Dav*_*ett 157
像这样的转储中的主要瓶颈是驱动器 I/O。您正在读取大量数据并再次写入。您可以通过多种方式加快速度:
gzip或类似的方式输出。这将减少正在完成的写入量(因此减少整体 IO 负载和磁头移动量),但会牺牲一些 CPU 时间(无论如何,您在这些时间可能有很多空闲时间)。--quick选项来减少备份大表对 RAM 的影响,则完全不同)。不过,您可能正在解决错误的问题:解决连接断开问题可能更容易(尽管减少备份施加的 I/O 负载将有助于减少您对其他用户的影响,因此无论如何都值得尝试)。你能通过screen(或类似的工具,如tmux)运行你的手动备份吗?这样,如果您与服务器的连接断开,您只需重新连接并重新连接到screen会话,而不会中断任何进程。
如果您直接通过连接发送数据(即您在本地机器上针对远程数据库运行 mysqldump,因此转储出现在本地),您最好先在服务器上运行转储,根据需要进行压缩,然后传输使用rsync支持部分传输的工具(例如)通过网络传输数据,因此您可以在连接断开中断时恢复传输(而不是重新启动)。
作为“减少整个数据库的大小以解决此问题”的一部分,我猜您的大部分数据不会改变。您可以将 1.2Gb 的一大块从该主表移到另一个表中,并从mysqldump调用复制的那些中删除。如果它永远不会改变,您不需要每次都备份这些数据。以这种方式在表和数据库之间拆分数据通常称为数据分区,还可以让您将数据和 I/O 负载分布在多个驱动器上。高端数据库内置了对自动分区的支持,但在 mysql 中,您可能必须手动执行此操作并更改数据访问层以解决此问题。
偏离本站点的主题(因此您可能应该向 ServerFault 或 SuperUser 询问您是否需要更多详细信息):如果您似乎由于不活动而失去连接,请检查您的 SSH 服务器和 SSH 客户端中的选项以进行确保保持活动数据包已启用并经常发送。如果即使连接处于活动状态也看到掉线,您也可以尝试使用 OpenVPN 或类似方法来包装连接 - 它应该处理短暂的掉线,如果您的整个连接关闭几秒钟,甚至完全掉线,这样 SSH 客户端和服务器没有注意到。
Rol*_*DBA 137
深入了解使用 mysqldump 进行备份
恕我直言,如果您知道如何进行备份,则备份已成为一种艺术形式
你有选择
选项 1:mysqldump 整个 mysql 实例
这是最简单的一个,没有脑子!!!
mysqldump -h... -u... -p... --hex-blob --routines --triggers --all-databases | gzip > MySQLData.sql.gz
Run Code Online (Sandbox Code Playgroud)
一切都写在一个文件中:表结构、索引、触发器、存储过程、用户、加密密码。其他 mysqldump 选项还可以从二进制日志、数据库创建选项、部分数据(--where 选项)等导出不同风格的 INSERT 命令、日志文件和位置坐标。
选项 2:mysqldump 将单独的数据库转储到单独的数据文件中
首先创建一个数据库列表(两种技术来做到这一点)
技巧一
mysql -h... -u... -p... -A --skip-column-names -e"SELECT schema_name FROM information_schema.schemata WHERE schema_name NOT IN ('information_schema','mysql')" > ListOfDatabases.txt
Run Code Online (Sandbox Code Playgroud)
技巧二
mysql -h... -u... -p... -A --skip-column-names -e"SELECT DISTINCT table_schema FROM information_schema.tables WHERE table_schema NOT IN ('information_schema','mysql')" > ListOfDatabases.txt
Run Code Online (Sandbox Code Playgroud)
技术1是最快的方法。技术2是最可靠和最安全的。技术 2 更好,因为有时用户会在 /var/lib/mysql (datadir) 中创建与数据库无关的通用文件夹。information_schema 会将文件夹注册为 information_schema.schemata 表中的数据库。技术 2 将绕过不包含 mysql 数据的文件夹。
编译数据库列表后,您可以继续遍历列表并 mysqldump 它们,如果需要,甚至可以并行执行。
for DB in `cat ListOfDatabases.txt`
do
mysqldump -h... -u... -p... --hex-blob --routines --triggers ${DB} | gzip > ${DB}.sql.gz &
done
wait
Run Code Online (Sandbox Code Playgroud)
如果一次启动的数据库太多,一次并行转储 10 个:
COMMIT_COUNT=0
COMMIT_LIMIT=10
for DB in `cat ListOfDatabases.txt`
do
mysqldump -h... -u... -p... --hex-blob --routines --triggers ${DB} | gzip > ${DB}.sql.gz &
(( COMMIT_COUNT++ ))
if [ ${COMMIT_COUNT} -eq ${COMMIT_LIMIT} ]
then
COMMIT_COUNT=0
wait
fi
done
if [ ${COMMIT_COUNT} -gt 0 ]
then
wait
fi
Run Code Online (Sandbox Code Playgroud)
选项 3:mysqldump 将单独的表转换为单独的数据文件
首先创建一个表列表
mysql -h... -u... -p... -A --skip-column-names -e"SELECT CONCAT(table_schema,'.',table_name) FROM information_schema.tables WHERE table_schema NOT IN ('information_schema','mysql')" > ListOfTables.txt
Run Code Online (Sandbox Code Playgroud)
然后以 10 为一组转储所有表
COMMIT_COUNT=0
COMMIT_LIMIT=10
for DBTB in `cat ListOfTables.txt`
do
DB=`echo ${DBTB} | sed 's/\./ /g' | awk '{print $1}'`
TB=`echo ${DBTB} | sed 's/\./ /g' | awk '{print $2}'`
mysqldump -h... -u... -p... --hex-blob --triggers ${DB} ${TB} | gzip > ${DB}_${TB}.sql.gz &
(( COMMIT_COUNT++ ))
if [ ${COMMIT_COUNT} -eq ${COMMIT_LIMIT} ]
then
COMMIT_COUNT=0
wait
fi
done
if [ ${COMMIT_COUNT} -gt 0 ]
then
wait
fi
Run Code Online (Sandbox Code Playgroud)
选项 4:发挥你的想象力
尝试上述选项的变体以及清洁快照的技术
例子
警告
只有选项 1 带来了一切。缺点是以这种方式创建的 mysqldumps 只能重新加载到与生成 mysqldump 相同的 mysql majot 发布版本中。换句话说,来自 MySQL 5.0 数据库的 mysqldump 无法在 5.1 或 5.5 中加载。原因 ?主要版本之间的 mysql 架构完全不同。
选项 2 和 3 不包括保存用户名和密码。
这是为可读且更便携的用户转储 SQL 授权的通用方法
mysql -h... -u... -p... --skip-column-names -A -e"SELECT CONCAT('SHOW GRANTS FOR ''',user,'''@''',host,''';') FROM mysql.user WHERE user<>''" | mysql -h... -u... -p... --skip-column-names -A | sed 's/$/;/g' > MySQLGrants.sql
Run Code Online (Sandbox Code Playgroud)
选项 3 不保存存储过程,因此您可以执行以下操作
mysqldump -h... -u... -p... --no-data --no-create-info --routines > MySQLStoredProcedures.sql &
Run Code Online (Sandbox Code Playgroud)
应该注意的另一点是关于 InnoDB。如果你有一个很大的 InnoDB 缓冲池,在执行任何备份之前尽可能地刷新它是有意义的。否则,MySQL 会花时间将带有剩余脏页的表刷新出缓冲池。这是我的建议:
在执行备份前大约 1 小时运行此 SQL 命令
SET GLOBAL innodb_max_dirty_pages_pct = 0;
Run Code Online (Sandbox Code Playgroud)
在 MySQL 5.5 中默认 innodb_max_dirty_pages_pct 是 75。在 MySQL 5.1 和后面,默认 innodb_max_dirty_pages_pct 是 90。通过将 innodb_max_dirty_pages_pct 设置为 0,这将加速将脏页刷新到磁盘。这将防止或至少减轻在对任何 InnoDB 表执行任何 mysqldump 之前清理 InnoDB 数据的任何不完整的两阶段提交的影响。
关于 mysqldump 的最后一句话
大多数人回避 mysqldump 转而使用其他工具,而这些工具确实很好。
此类工具包括
如果您具有真正的 MySQL DBA 精神,您可以拥抱 mysqldump 并完全掌握它。愿您所有的备份都反映了您作为 MySQL DBA 的技能。
Ric*_*mes 21
计划 A:另请参阅 Percona 的 Xtrabackup。这允许 InnoDB 的在线备份,没有任何重要的锁定。
方案B:可以停止一个Slave,你可以通过多种方式(复制文件、mysqldump、xtrabackup等)中的任何一种进行一致备份
计划 C:LVM 快照。经过一些神秘的设置后,备份的停机时间不到一分钟,无论数据库的大小如何。你停止mysqld,做快照,重启mysqld,然后复制快照。最后一步可能需要很长时间,但 MySQL 并没有宕机。
计划 D:从站快照——零停机时间。
poe*_*nca 20
看看 MySQL 从主到从的复制。它允许您将 master 的数据库克隆到另一个具有相同数据库的数据库服务器。这包括主和从身份。Slave 使自己成为主数据库服务器及其数据库的精确副本。主从之间可能存在一对一、一对多、多对一的关系。
Slave 不断读取 master 的二进制日志(bin log 存储了在 master 数据库服务器上写入的查询)并获取输入到其从数据库服务器。(这意味着您的主数据库根本不会受到影响)
好消息是它不会对您的 MySQL 服务器产生太大影响,因为您不会注意到任何停机时间或缓慢的查询响应。我们将它用于 10Gb 数据库,它的工作原理非常棒,没有任何停机时间。
Dav*_*all 15
首先是一些管理要点:您是连接来执行 ftp 还是 ssh 进入并且它快死了?如果是 ssh,那么一定要使用screen以便在 comcast 崩溃后可以恢复。如果是 ftp,请确保在发送之前压缩它/tar。
还可以尝试 --opt 参数或 --quick
--opt 此选项打开一组附加选项,使转储和重新加载操作更加高效。具体来说,它相当于同时使用 --add-drop-table、--add-locks、--all、--quick、--extended-insert、--lock-tables 和 --disable-keys 选项。请注意,此选项会降低输出的可移植性,并且不太可能被其他数据库系统理解。
--quick 此选项告诉 mysqldump 在从服务器读取每一行时写入转储输出,这可能对大型表有用。默认情况下,mysqldump 在写入输出之前将表中的所有行读取到内存中;对于大型表,这需要大量内存,可能会导致转储失败。
小智 5
我曾经在转储大型数据库期间也遇到过超时问题。我终于解决了是否通过为数据库中的每个表发送单独的命令并将所有内容附加到一个文件中,如下所示:
TABLES=`mysql -u $USER -p$PWD -Bse 'show tables' $DB`
for TABLE in $TABLES
do
mysqldump -u $USER -p$PWD $DB $TABLE >> dump.sql
done
Run Code Online (Sandbox Code Playgroud)