5

当前情况:我有一个 Rails 应用程序,其中有 N 个延迟的工作人员。每当我想向某台机器发送 SSH 请求时,我都会为工作人员创建一个任务。Worker 执行如下操作:

Net:SSH.start(hostname, username, :password => pass) do |ssh|
  ssh.exec!(command)
end

有时我会创建例如 50 个这样的任务来一个一个地执行,或者在 5-10 分钟内执行。在这种情况下,每个任务都会打开单独的连接,这并不有效,有时会因为连接太多而被目标服务器阻塞。

我想要什么:已打开存储在某处的连接并由每个工作人员重用。这样每个工作人员都以某种方式获得连接,然后运行

ssh.exec!(command)

我尝试过的

  • 在文件/数据库/缓存中存储连接看起来是不可能的,因为它们不可序列化
  • 尝试使用单例类和在初始化程序下实例化的全局变量。但是每个worker的类对象是不同的(后来发现不能选择全局变量)。

有办法解决吗?还有其他想法吗?谢谢!!

4

1 回答 1

3

首先是一些基础知识;一个 SSH 连接的核心是与远程机器的低级套接字连接。套接字不能(轻松)在进程之间共享。因此,在多个进程上运行的东西不能共享同一个 SSH 连接。

接下来,您需要知道当前设置中的哪些部分在单独的进程中运行。我们得到的是:

  1. Rails 在大多数情况下是基于进程的:不同的 Web 请求在不同的进程上运行。因此,在 Rails 应用程序中存储 SSH 连接并不是一个可靠的解决方案。

  2. 据我所知,延迟作业也是基于流程的。主进程启动从进程来处理每个作业。因此 DJ 也不适用于此目的。

您需要一个主进程来存储 SSH 会话,然后等待传入消息,这些消息是需要在您的远程 SSH 机器之一上执行的命令。

就我个人而言,我会自己编写一个简单的线程化 Ruby 守护进程来处理这个任务。如果您不想直接处理套接字编程,则可以使用EventMachine之类的东西来处理通信和处理。

如果您对 EventMachine 或套接字编程不满意,那么您可以查看一些消息系统,例如RabbitMQZeroMQ来创建您的客户端和服务器。

我还为 Rails 找到了一些名为ActiveMessaging的东西,尽管我不确定该项目的最新情况和工作情况。

但就像我说的,我认为最简单的实现只是一个套接字守护进程,它在后台运行并跟踪打开的 SSH 连接,然后监听来自 Rails 应用程序的命令。

如果您实施这样的事情,请记住还要考虑安全因素。否则,您可以通过您的守护进程轻松地让任何人通过 SSH 访问您的所有远程计算机。

编辑

一个更简单的想法:

只需让一个守护进程定期从 Rails 应用程序的数据库表中读取命令。然后这个守护进程可以根据它在这个“作业队列”表中找到的内容来执行这些命令。这样,您根本不必处理套接字通信,缺点是该解决方案是轮询解决方案。

于 2013-12-13T21:35:27.943 回答