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 .你有什么理由不使用它吗?它可能会更快、更好、更有效地工作,以增量和持续的方式只更新表中已更改的部分。


评论关闭
IT虾米网

微信公众号号:IT虾米 (左侧二维码扫一扫)欢迎添加!