Ruby 1.9.3、net-ssh 2.9.2
我正在开发一个项目,其中我需要在两个不同的服务器(本地和远程)上比较相同的目录(及其子目录)。从那里,我需要将最新/最近修改的文件复制到正确的服务器,如果本地不存在文件,则从远程删除。
注意:我无法使用 rsync。我们正在将与 Asterisk 相关的目录备份到 GlusterFS。对于数千个文件,rsync 比较本地与 Gluster 卷的速度非常慢(当我们需要时需要不到 1 分钟)。
这是我当前的代码。我省略了复制/删除文件的工作,因为我想一次执行这一步骤。
require 'thread'
require 'date'
require 'rubygems'
require 'net/ssh'
SERVERS = ['local17', 'development']
CLIENT = SERVERS[0]
CLIENT_PATH = '/home/hstevens/temp_gfs'
BRICK_PATH = '/export/hunter_test'
@files = {
SERVERS[0] => {},
SERVERS[1] => {}
}
def grab_filenames_and_dates(files, server)
files.reject { |x| File.directory? x }
files.each do |file|
name = `ls --full-time "#{file}" | awk '{$1=$2=$3=$4=$5=$6=$7=$8=""; print $0}'`.strip
date = `ls --full-time "#{file}" | awk '{print $6, $7, $8}'`.strip
@files[server][name] = DateTime.parse(date)
end
end
# Collect diff information on all servers
ls_threads = SERVERS.map do |server|
Thread.new do
if server == CLIENT
files = Dir.glob("#{CLIENT_PATH}/**/*")
grab_filenames_and_dates(files, server)
else
Net::SSH.start(server, 'hstevens') do |session|
files = session.exec!(%Q(ruby -e 'puts Dir.glob("#{BRICK_PATH}/**/*")')).split("\n")
grab_filenames_and_dates(files, server)
end
end
end
end
ls_threads.each(&:join)
当我运行我的程序时,它适用于本地服务器(CLIENT
/local17
),但在远程服务器上失败。我尝试了调试语句(将 pwd
打印到 console`,看起来虽然该方法是在 Net::SSH session block 内调用的,但它正在我的本地服务器上运行。
ls: cannot access /export/hunter_test/sorttable.js: No such file or directory
ls: cannot access /export/hunter_test/sorttable.js: No such file or directory
./gluster_rsync.rb:36:in `parse': invalid date (ArgumentError)
from ./gluster_rsync.rb:36:in `block in grab_filenames_and_dates'
from ./gluster_rsync.rb:33:in `each'
from ./gluster_rsync.rb:33:in `grab_filenames_and_dates'
from ./gluster_rsync.rb:53:in `block (3 levels) in <main>'
from /usr/local/lib/ruby/gems/1.9.1/gems/net-ssh-2.9.2/lib/net/ssh.rb:215:in `start'
from ./gluster_rsync.rb:51:in `block (2 levels) in <main>'
如何在 Net::SSH session 中正确包装方法调用?
最佳答案
我 100% 不是在欺骗你……但是……你的概要正是创建 rsync 的原因。在具有差异功能的服务器之间高效地移动文件。
在我看来,认为你可以做得比经过 20 年考验的 C 代码更好的想法有点误导。 FWIW 的执行速度比 ruby 代码快得多。这可能就是为什么这么多人聚集在一起使用 rsync 作为解决方案的原因。
虽然 rsync 是单线程的...问问自己为什么会这样...仅仅因为您可以在 ruby 中使用多线程并不意味着您应该这样做。它将打开另一个意大利面条怪物,您很快就会发现自己的任务是“处理”重复或不正确的版本。请参阅 MongoDB 关于原子性的讨论。你甚至不会接近 ruby 中的原子,所以这将是一个问题。
如果你想走这条路,我一定会使用线程安全语言,至少是 jRuby。 FWIW 线程安全性是 Jose 创建 Elixir 的众多原因之一,因为他对 ruby 没有真正拥有它感到恼火。
但是,在我看来,你的方法有问题,你需要后退几步,从整体上看待问题,例如也许有一个与 GlusterFS 类似的解决方案,可以在 FS 级别处理重复数据删除,或者您可能需要通过 API 或某种按顺序处理文件的排队系统来处理文件添加。它可能需要比你愿意或可以做出的更大的改变,所以如果是我,我会犹豫是否只是用 ruby 编写一些东西,因为有一天某些开发人员最终会跳入该代码并立即捂脸。
多线程 rsync 而不是 ruby
我能想到的唯一解决方案是专注于使 rsync 传输更快。
也许你可以speed rsync up用线程代替
或者使用这个人的方法。这似乎确实是 GlusterFS 的问题,但是 rsync with the proper flag/signals可以更好地进行差分同步。然后您的 ruby 脚本就可以从主源中获取文件。
关于ruby - 在 Net::SSH session 中执行 Ruby 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31997419/