无需重新启动进程即可更新共享库

时间:2012-04-03 20:37:52

标签: c linux dll shared-libraries

如果我的进程正在加载.so库,并且如果有新版本的库可以切换到新库而无需重新启动进程?或者答案取决于是否对库中的某个现有函数进行参数更改?

我在一个相当大的系统中工作,该系统运行100个进程,每个进程加载10个库。这些库提供特定功能,由不同的团队提供。因此,当其中一个库发生更改时(对于错误修复可以说),理想的做法是在不影响正在运行的进程的情况下将其发布到引擎盖下。有可能吗?

编辑谢谢!在我的情况下,当一个新库可用时,所有正在运行的进程必须开始使用它。它不是让它们与旧版本一起运行并在以后提取新版本的选择。所以看起来更安全的选择就是重新加载进程。

8 个答案:

答案 0 :(得分:6)

您无法在运行进程的情况下即时升级链接库。 您甚至可以尝试,但如果您已经成功(并且您不会因“正在使用的文本文件”错误消息而失败),则必须重新启动该过程以使其将新库映射到内存中。

您可以使用lsof命令检查链接的库(运行时或链接时):

lsof -p <process_pid> | grep ' mem '

答案 1 :(得分:5)

一种有趣的技术,虽然它在检查点恢复步骤中有些失败,但是要做一次不可见的重启。

您的服务器进程或其他任何内容,将所有必要的信息保存到磁盘文件中。包括文件描述符号和当前状态。然后,服务器进程执行exec系统调用以执行自身,替换其自身的当前版本。然后它从磁盘文件中读取其状态,并继续为其文件描述符提供服务,就好像什么都没发生一样。

如果一切顺利,重启是不可见的,新进程正在使用所有更新的库。

答案 2 :(得分:4)

至少,您必须确保库的接口在版本之间不会更改。如果确保这一点,那么我会尝试使用dlopen / dlsym动态加载库,看看dlclose是否允许你重新加载。

我自己从来没有做过这些,但这是我首先要追求的道路。如果你这样做,你能发表结果吗?

答案 3 :(得分:2)

Linux提供了几个动态加载器接口,进程可以在运行时加载动态库。 linux提供的dlopen和dlsysm可以解决您的问题。

答案 4 :(得分:1)

如果您希望图书馆定期更改,并且 你希望保持正常运行时间,我认为你的系统 应该重新设计,以便这些库真正成为 松散耦合的组件(例如服务)。

话虽如此,我对这个问题的回答是肯定的:在某些情况下 在没有的情况下,可能更新共享库 重启进程。在大多数情况下,我认为这是不可能的, 例如,当您的库的API发生变化时, 当库的时候,你的数据段的安排会发生变化 维护内部线程。这份清单很长。

对于代码的非常小的错误修复,您仍然可以使用 ptrace写入进程内存空间,并从中写入 重做/lib/ld-linux.so在动态方面的作用 链接。老实说,这是一项非常复杂的活动。

答案 5 :(得分:0)

ldd你的进程的二进制文件是一种查找的方法。虽然理论上是可行的,但不建议修改正在运行的进程,尽管我确信有一些实用工具,例如ksplice可以修改正在运行的linux内核。

你可以简单地升级,运行过程将继续使用旧版本,并在重新启动时选择新版本,假设你的软件包管理系统很好并且知道什么是可以安装的。

答案 6 :(得分:0)

您可能想了解共享库版本控制和ld -h选项。

使用它的一种方法如下:

您在构建系统中维护一个版本计数器。您使用以下命令构建共享库:

ld ..... -h mylibrary.so.$VERSION

但是,你把它放在dev树的lib中就像普通mylibrary.so一样。 (还有一个黑客涉及将整个.so放入.a文件中。)

现在,在运行时,使用该库的进程会查找完全版本化的名称。要推出新版本,只需新版本添加到图片中即可。运行与旧版本链接的程序继续使用它。当程序重新链接并针对新程序进行测试时,您将推出新的可执行文件。

答案 7 :(得分:0)

有时您可以升级使用中的.so,有时您不能。这主要取决于您尝试如何执行此操作,还取决于您正在运行的内核的安全保证。

不要这样做: cat new.so&gt; old.so ...因为最终,你的过程可能会试图要求页面的东西,并发现它不再在正确的位置。这是一个问题,因为事物的地址可能会改变,它仍然是相同的inode;你只是覆盖了文件中的字节。

但是,如果你: mv new.so old.so 在大多数系统上都可以,因为正在运行的进程可以保留旧库的现在未命名的inode,而进程的新调用将获得新文件。 但是,有些内核不喜欢让你使用它们。也许是出于谨慎,可能是为了它们的简单。