【问题标题】:Pyramid, fork, Java and socketsPyramid、fork、Java 和套接字
【发布时间】:2015-05-01 03:35:58
【问题描述】:

一个复杂的情况:

  1. Pyramid 应用程序有时需要启动/重新启动一些 Java 进程(例如 Jetty)(例如在接收 Jetty 的新 WAR 文件等时)。

  2. 预计 Jetty 进程将在 Pyramid 进程 (pserve) 退出后或 Pyramid 重新启动之间继续工作。

  3. Jetty 进程通过subprocess.Popen + shell 脚本启动。自然地,作为一个子进程,它继承了文件描述符,包括套接字。

  4. 现在如果 Pyramid 需要在 Jetty 仍在运行时重新启动,它不能这样做,因为子 Jetty 进程仍然将套接字绑定到 Pyramid 的主地址/端口。

目前的解决方案:

  1. 要重新启动 Java/Jetty,请执行 fork

  2. 在子进程中关闭每个文件描述符 > 3 和 resource.RLIMIT_NOFILE。

  3. 在启动/重启 Jetty 后在子进程中执行sys.exit

整洁,对吧?

没有。

这是复杂而笨拙的。有没有更简单的方法来避免这种“子进程继承套接字”的问题?

另外,我有服务(如 APScheduler 等)正在运行,这需要精心关闭所有正在运行的服务(当然是在子进程中),否则它们会在 sys.exit 上引发异常。

【问题讨论】:

  • 我不确定这是否是您想要的,但是使用 Apache Java 服务,您可以将 Jetty 作为操作系统服务运行并启动/停止它。
  • 我同意@SJuan76——您应该明确地使用更高级别的 API 来启动和停止该服务。这将以某种方式将这两个部分解耦,让“服务管理器”处理混乱的部分(启动与重新启动,重新启动异常终止的 Jetty 实例等等......)此外,它将负责正确的“身份管理”,如一个普通的旧分叉将让子进程在与父进程相同的身份(即:相同的权限)下运行。这可能是不可取的。
  • @SylvainLeroux:好吧,您可以使用preexec_fn=lambda: os.setresuid(unprived_user) 或类似名称处理子进程中的身份,而在普通的旧分叉中,只需在fork 之后显式调用它,因此子代码甚至永远不会由特权用户加载。
  • @SylvainLeroux:基本上,setresuid 同时设置了所有三个真实的、有效的和保存的 uid;这只是对单独方法的方便。例如,如果您的有效 uid 为 pyramid,但保存的 uid 为 root,则 setresuid(geteuid()) 会阻止孩子(ab)使用该保存的 uid。无论如何,我同意你的一般观点,我只是想提一下,做你需要的不是不可能;问题是你必须知道你需要它,以及如何测试它,等等;编写系统工具的人(希望如此)已经想到了所有这些。 :)
  • 他并不是建议构建一个与您的整个应用程序集成的服务管理器。只需使用您的操作系统附带的那个(upstart、systemd、launchd,……——如果您更喜欢操作系统的替代版本,您也可以安装它)。然后通过运行简单的命令行调用工具(通过subprocess)进行通信,例如systemctl restart jettylaunchctl stop jetty 或其他。重启或停止 Jetty 不需要传递活动对象,不是吗?

标签: java python sockets fork pyramid


【解决方案1】:

恕我直言,您应该将流程控制与您的 Web 应用程序流程分离。使用像supervisord 这样的过程控制系统来启动/停止/重启长时间运行的应用程序;这可以通过XML-RPC 完成。

Pyramid 创建者 Chris McDonough 也是 Supervisor 的主要作者,这还不错。

【讨论】:

  • 不幸的是,我没有很好的使用 supervisord 的经验,大约一年前,当它应该处理许多服务(比如几十个)时,它导致了很多问题(比如未能观察到某些进程 IIRC) .
  • @LetMeSOThat4U:如果你不喜欢supervisord,有六个主要的替代方案。它们中的大多数都没有内置 RPC 服务器,但它们至少有一些您可以轻松编写脚本的东西,例如非交互式命令行界面。
【解决方案2】:

有没有更简单的方法来避免这种“子进程继承套接字”的问题?

是的,只需将close_fds=True 传递给Popen 构造函数或包装函数即可。这将关闭除 0、1 和 2 之外的所有 fd。*

如果您需要保留一些不同的集合而不是 0、1 和 2,请使用 pass_fds=[0, 2, special_file.fileno()] 而不是 close_fds=True。但希望你不需要那个。**


* 我假设你并不关心 Windows 的可移植性——毕竟,你已经在使用os.fork。如果我错了,close_fds=True 将无法在具有重定向 stdio 句柄的非 POSIX 系统上工作,因此如果您需要两者,则需要更复杂的解决方案。

** 如果您这样做:pass_fds 需要 3.2+,或 3.2+ subprocess 模块的反向移植。我很确定你没有 3.2+,因为如果你这样做了,close_fds=True 已经是 POSIX 系统上的默认行为,而且你一开始就不会遇到这个问题。 Web 服务需要它的一个常见原因是当您没有绑定端口 80 的权限时,因此您从 suid 程序继承了一个套接字,并且需要将该套接字传递给您自己的孩子。

【讨论】:

    猜你喜欢
    • 2018-08-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-09
    • 2014-06-06
    • 2015-11-30
    • 2017-06-18
    • 2013-03-17
    相关资源
    最近更新 更多