Work 有一个使用大型数据集的网站,使用 MyISAM 在两个 MySQL 5.6.16-64.2 服务器之间进行负载平衡,在 Linux (2.6.32-358.el6.x86_64 GNU/Linux) 上运行。从 MS-SQL 数据库接收的基于文本的文件集每小时更新一次。为了避免从网站读取中断,同时确保更新不会花费太长时间,以下流程已到位:
有数据一个三分之一的Linux box(仅用于数据更新处理,)根据需要更新不同的数据表,将物理表文件的副本以临时名称移动到生产服务器,然后做一个表通过 MySQL TABLE RENAME 交换。
但每次目标 MySQL 服务器将表(在临时名称下)视为崩溃并需要修复。修复时间太长,所以不能在进行表交换之前强制进行修复。
处理是在 Ruby 1.8.7 中编程的,每个服务器都有一个线程(仅供引用,如果不是在单个服务器的线程中执行,也会发生这种情况。)
执行文件复制的步骤如下:
使用 Net::SFTP 将文件传输到不是数据库文件夹的目标文件夹(由于权限而完成。) 主表文件文件传输的代码示例(如果表也有分区文件,则它们是单独传输并且 rspFile 分配不同以匹配临时名称。)为了速度,它是并行上传的:
Net::SFTP.start(host_server, host_user, :password => host_pwd) do |sftp|
uploads = fileList.map { |f|
rcpFile = File.basename(f, File.extname(f)) + prcExt + File.extname(f)
sftp.upload(f, "/home/#{host_user}/#{rcpFile}")
}
uploads.each { |u| u.wait }
end
然后将文件的所有者和组分配给 mysql 用户,并将文件移动到 MySQL 数据库文件夹,使用 Net::SSH 执行 sudo shell 命令:
Net::SSH.start(host_server, host_user, :port => host_port.to_i, :password => host_pwd) do |ssh|
doSSHCommand(ssh, "sudo sh -c 'chown mysql /home/#{host_user}/#{prcLocalFiles}'", host_pwd)
doSSHCommand(ssh, "sudo sh -c 'chgrp mysql /home/#{host_user}/#{prcLocalFiles}'", host_pwd)
doSSHCommand(ssh, "sudo sh -c 'mv /home/#{host_user}/#{prcLocalFiles} #{host_path}'", host_pwd)
end
doSSHCommand 方法:
def doSSHCommand(ssh, cmd, pwd)
result = ""
ssh.open_channel do |channel|
channel.request_pty do |c, success|
raise "could not request pty" unless success
channel.exec "#{cmd}" do |c, success|
raise "could not execute command '#{cmd}'" unless success
channel.on_data do |c, data|
if (data[/\[sudo\]|Password/i]) then
channel.send_data "#{pwd}\n"
else
result += data unless data.nil?
end
end
end
end
end
ssh.loop
result
end
如果通过使用 scp 手动移动文件、更改所有者/组并移动文件来完成,那么它永远不会使表崩溃。通过检查 scp 和 Net::SFTP 之间比较的文件大小,没有区别。
其他的处理方法也试过,但是体验起来比使用上面介绍的方法耗时太长。任何人都知道表崩溃的原因,以及是否有无需修复表即可避免表崩溃的解决方案?
请您参考如下方法:
这些表被标记为已崩溃,因为您在复制文件时可能遇到竞争条件。也就是说,在执行 Ruby 脚本期间,有待处理的表写入操作,因此生成的副本是不完整的。
复制 MyISAM 表的更安全的方法是首先运行 SQL 命令FLUSH TABLES
,然后是 FLUSH TABLES WITH READ LOCK
,以确保所有挂起的更改都写入到磁盘上的表,然后阻止任何进一步的更改,直到释放表锁。然后执行您的复制脚本,最后解锁表。
这确实意味着在您复制表格时没有人可以更新表格。这是确保您获得未损坏文件的唯一方法。
但我不得不说,你似乎在重新发明 MySQL replication .你有什么理由不使用它吗?它可能会更快、更好、更有效地工作,以增量和持续的方式只更新表中已更改的部分。