3

Work has a web site that uses large data sets, load balanced between two MySQL 5.6.16-64.2 servers using MyISAM, running on Linux (2.6.32-358.el6.x86_64 GNU/Linux.) This data is being updated hourly from a text based file set that is received from a MS-SQL database. To avoid disruption on reads from the web site and at the same time make sure the updates doesn't take too long following process was put in place:

Have the data one a third Linux box (only used for data update processing,) update the different data tables as needed, move a copy of the physical table files to the production servers under a temporary name, and then do a table swap by MySQL TABLE RENAME.

But every time the table (under the temporary name) is seen by the destination MySQL servers as being crashed and require repair. The repair takes too long, so it cannot be forced to do a repair before doing the table swap.

The processing is programmed in Ruby 1.8.7 by having a thread for each server (just as a FYI, this also happens if not doing it in a thread to a single server.)

The steps to perform file copy is as follows:

Use Net::SFTP to transfer the files to a destination folder that is not the database folder (done due to permissions.) Code example of the file transfer for the main table files (if table also has partition files then they are transferred separately and rspFile is assigned differently to match the temporary name.) For speed it is parallel uploaded:

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

Then assign the files the owner and group to the mysql user and to move the files to the MySQL database folder, by using Net::SSH to execute sudo shell commands:

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

The doSSHCommand method:

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

If done manually by using scp to move the files over, do the owner/group changes, and move the files, then it never crashes the table. By checking the file sizes compared between scp and Net::SFTP there are no difference.

Other process methods has been tried, but experience they take too long compared to using the method described above. Anyone have an idea of why the tables are being crashed and if there a solution to avoid table crash without having to do a table repair?

4

3 回答 3

0

我看到你已经找到了答案,但是关于这个问题有两件事让我印象深刻。

第一,您应该查看rsync,它为您提供了更多选择,其中最重要的是传输速度更快,可能更适合这个问题。服务器之间的文件传输基本上是 rsync 作为一个东西存在的原因。

其次,我并不是要重新设计您的系统,但您可能已经超越了 MySQL。它可能不是最适合这个问题的。有多个节点的 Riak 或可以处理大文件并有多个节点的 Mongo 可能会更好地解决这个问题。在阅读您的问题时,我只有两个想法。

于 2014-05-31T18:05:07.657 回答
0

问题已找到并解决:

流程数据库具有从生产数据库之一复制的表文件,并且在流程服务器上没有显示崩溃,并且在查询和更新数据时没有问题。

在搜索网络时,发现以下 SO 答案:MySQL table is mapped as crashed

因此,通过猜测当表从生产复制到进程服务器时,标头信息保持不变,并且在处理器期间复制回生产服务器时可能会干扰。因此,尝试通过修复进程服务器上的表,然后在我们也遇到问题的登台环境上运行一些测试。并且肯定足以纠正这个问题。

因此,最终的解决方案是在流程服务器上修复表一次,然后让流程脚本每小时运行一次。

于 2014-05-30T16:01:02.400 回答
0

这些表被标记为已崩溃,因为您在复制文件时可能会遇到竞争条件。也就是说,在您执行 Ruby 脚本期间,表中有待写的写入,因此生成的副本是不完整的。

复制 MyISAM 表的更安全的方法是先运行 SQL 命令FLUSH TABLESFLUSH TABLES WITH READ LOCK以确保所有挂起的更改都写入磁盘上的表,然后阻止任何进一步的更改,直到您释放表锁为止。然后执行您的复制脚本,最后解锁表。

这确实意味着在您复制表格时没有人可以更新表格。这是确保您获得未损坏文件的唯一方法。

但我不得不评论说,您似乎正在重新发明MySQL 复制。你有什么理由不使用它吗?它可能会工作得更快、更好、更有效,增量和持续更新表中已更改的部分。

于 2014-05-29T21:05:31.750 回答