ruby - 在 Net::SSH session 中执行 Ruby 方法

标签 ruby ssh ruby-1.9.3 net-ssh

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 传输更快。

  1. 也许你可以speed rsync up用线程代替

  2. 或者使用这个人的方法。这似乎确实是 GlusterFS 的问题,但是 rsync with the proper flag/signals可以更好地进行差分同步。然后您的 ruby​​ 脚本就可以从主源中获取文件。

关于ruby - 在 Net::SSH session 中执行 Ruby 方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31997419/

相关文章:

ruby-on-rails - Rails 和 Javascript 缩小器和聚合器

ruby - Ruby 1.9.3 的 OpenSSL 问题

linux - 连接后无法在主机上正确运行脚本

python - 使用 Paramiko 时的环境变量差异

ruby-on-rails - 安装 ruby​​ ruby​​-1.9.3-p551 时出错

mechanize - 如何使用 Mechanize 单击没有 id 和 name 的提交按钮?

ruby-on-rails - rails rspec 测试模型上的更新属性

ruby - OS X 10.9,安装 ruby​​ 2.2.2 时,rbenv 无法全局将默认 ruby​​ 2.0.0p481 更改为 ruby​​ 2.2.2

ruby - 重新定位数组中的元素

python - 在 Python 中创建和维护多个 ssh session