如何在不崩溃的情况下升级共享库?


18

在这里它说您可以重写可执行文件,并且该进程将正常运行-进程重新启动时将重新读取该文件。

但是,当我尝试在进程运行时替换二进制文件时(使用scp,从开发人员到测试服务器),它说“文件繁忙”。而且,如果我替换了共享库文件(* .so),则链接该文件的所有进程都会崩溃。

为什么这样?我想念什么吗?如何在不停止/不破坏进程的情况下替换二进制文件?


您可以.so使用检查文件的ldd filename.so依赖性来检查文件
Rahul Patil

我知道依赖项。我想要一种替换那些文件而不影响正在运行的进程的方法。就像相关问题所暗示的那样
山姆

停机是必需的..或者您可以做 stop app && create symlink of .so && start app
Rahul Patil

Answers:


21

为何软件包即使升级也能正常运行?,则将锁放置在inode而不是文件名上。当您加载并执行二进制文件时,该文件被标记为忙-这就是为什么当您尝试写入它时出现ETXTBSY(文件忙)错误的原因。

现在,对于共享库,它稍有不同:使用可以将库映射到进程的地址空间中mmap()。尽管MAP_DENYWRITE可以指定,但至少Linux上的Glibc会静默忽略它(根据手册页,请随时检查源代码)-检查此线程。因此,你实际上是在允许写入文件,并且,因为它是存储器映射的,任何变化都可见几乎立即-这意味着如果你足够努力,你可以设法 通过覆盖库中的机器。

因此,正确的更新方法是:

  1. 删除文件,从文件系统中删除对数据的引用,以使任何可能要使用它的新生成的应用程序都无法访问该文件,同时使已打开(或映射)该文件的任何人都可以访问该数据;

  2. 创建具有更新内容的新文件。

新创建的进程将使用更新的内容,正在运行的应用程序将访问旧版本。这是任何理智的软件包管理实用程序的功能。请注意,这并不是完全没有任何危险-例如,dlsym()如果库的API进行静默更改,则动态加载代码(使用和朋友)的应用程序将遇到麻烦。

如果您真的安全,请关闭系统,从另一个操作系统实例挂载文件系统,然后进行更新并再次启动已更新的系统。


6

rpm升级的功能相同-在运行二进制文件和库时不会崩溃。

那么区别是什么呢:

  1. 取消连结档案
  2. 用相同的名称写入新文件

这不会就位替换文件:引用使用中二进制文件的inode仍然“忙碌”,直到最后一个将其打开的对象完成为止。将使用新的inode编号创建新文件。

现在scpcp将尝试就地替换文件-这将更改inode所引用的内容。如您所描述,这不起作用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.