Linux 无需重新启动进程即可更新共享库
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10001013/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Update shared libraries without restarting processes
提问by Manohar
If my process is loading a .so library and if a new version of the library is available is it possible to switch to the new library without doing a process restart ? Or the answer depends on things like whether there is a parameter change to one of the existing functions in the library ?
如果我的进程正在加载 .so 库并且有新版本的库可用,是否可以在不重启进程的情况下切换到新库?或者答案取决于诸如库中现有函数之一是否有参数更改之类的事情?
I am working in a pretty big system which runs 100s of processes and each loading 10s of libraries. The libraries provide specific functionality and are provided by separate teams. So when one of the library changes (for a bug fix lets say) ideal thing would be to publish it under-the-hood without impacting the running process. Is it possible ?
我在一个相当大的系统中工作,该系统运行 100 个进程,每个进程加载 10 个库。这些库提供特定的功能,由不同的团队提供。因此,当其中一个库发生变化时(例如修复错误),理想的做法是在不影响运行过程的情况下在后台发布它。是否可以 ?
EDITThanks! In my case when a new library is available all the running processes have to start using it. Its not option to let them run with the old version and pick-up the new one later. So it looks like the safer option is to just reload the processes.
编辑谢谢!在我的情况下,当一个新库可用时,所有正在运行的进程都必须开始使用它。让他们运行旧版本并在以后选择新版本并不是一种选择。所以看起来更安全的选择是重新加载进程。
采纳答案by dAm2K
You cannot upgrade a linked library on the fly with a process running. You could even try to, but if you succed (and you'll not fail with a "text file is in use" error message), you'll have to restart the process to make it mapping the new library into memory.
您无法在进程运行时即时升级链接库。您甚至可以尝试这样做,但是如果您成功了(并且您不会因“文本文件正在使用”错误消息而失败),您将必须重新启动该过程以使其将新库映射到内存中。
You can use lsof command to check which libraries are linked in (runtime or linktime):
您可以使用 lsof 命令来检查哪些库被链接(运行时或链接时):
lsof -p <process_pid> | grep ' mem '
回答by johnshen64
ldd the binary of your process is one way to find out. although it is theoretically possible, it is not advisable to tinker with the running process, although i am sure utilities exist such as ksplice that tinker with the running linux kernels.
ldd 进程的二进制文件是一种找出方法。尽管理论上可行,但不建议修改正在运行的进程,尽管我确信存在诸如 ksplice 之类的实用程序可以修改正在运行的 linux 内核。
you can simply upgrade and the running process will continue with the old version, and pick up the new version when it restarts, assuming that your package management system is good and knows what is comptible to install.
您可以简单地升级,运行过程将继续使用旧版本,并在重新启动时选择新版本,假设您的包管理系统良好并且知道可以安装什么。
回答by bmargulies
You might want to learn about shared library versioning and the ld -h
option.
您可能想了解共享库版本控制和 ld-h
选项。
One way to use it is as follows:
一种使用方法如下:
You maintain a version counter in your build system. You build the shared library with:
您在构建系统中维护一个版本计数器。您使用以下命令构建共享库:
ld ..... -h mylibrary.so.$VERSION
however, you put it in your dev tree's lib as just plain mylibrary.so
. (There's also a hack involving putting the entire .so into a .a file).
然而,你把它放在你的开发树的库中,就像普通的mylibrary.so
. (还有一个 hack 涉及将整个 .so 放入一个 .a 文件中)。
Now, at runtime, processes using the library look for the fully-versioned name. To roll out a new version, you just addthe new version to the picture. Running programs linked against the old version continue to use it. As programs are relinked and tested against the new one, you roll out new executables.
现在,在运行时,使用库的进程会查找完全版本化的名称。要推出新版本,您只需将新版本添加到图片中。运行与旧版本链接的程序会继续使用它。随着程序重新链接并针对新程序进行测试,您将推出新的可执行文件。
回答by user1277476
Sometimes you can upgrade an in-use .so, and sometimes you cannot. This depends mostly on how you try to do it, but also on the safety guarantees of the kernel you're running on.
有时您可以升级正在使用的 .so,有时则不能。这主要取决于您尝试如何去做,但也取决于您正在运行的内核的安全保证。
Don't do this: cat new.so > old.so ...because eventually, your process may try to demand page something, and find that it's not in the correct spot anymore. It's a problem because the addresses of things may change, and it's still the same inode; you're just overwriting the bytes in the file.
不要这样做: cat new.so > old.so ...因为最终,您的进程可能会尝试要求页面某些内容,并发现它不再位于正确的位置。这是一个问题,因为事物的地址可能会改变,而且它仍然是同一个inode;你只是覆盖文件中的字节。
However, if you: mv new.so old.so You'll be OK on most systems, because your running processes can hold onto a now-unnamed inode for the old library, while new invocations of your processes get the new file. BUT, some kernels don't like to let you mv an in-use .so, perhaps out of caution, perhaps for their own simplicity.
但是,如果您: mv new.so old.so 您在大多数系统上都可以,因为您正在运行的进程可以保留旧库的现在未命名的 inode,而您的进程的新调用将获得新文件。但是,一些内核不喜欢让你 mv 一个正在使用的 .so,也许是出于谨慎,也许是为了他们自己的简单。
回答by SquareRootOfTwentyThree
If you expect libaries to change on a fairly regular basis, and you expect to maintain up-time, I think that your system should be re-engineered so that such libraries actually become loosely coupled components (e.g. services).
如果您希望库定期更改,并且希望保持正常运行时间,我认为您的系统应该重新设计,以便这些库实际上成为松散耦合的组件(例如服务)。
Having said that, my answer to the question is yes: under certain circumstances, it possibleto update shared libraries without restarting processes. In most cases I expect it is not possible, for instance when the API of your library changes, when the arrangement of your data segment changes, when the library maintains internal threads. The list is quite long.
话虽如此,我对这个问题的回答是肯定的:在某些情况下,可以在不重新启动进程的情况下更新共享库。在大多数情况下,我认为这是不可能的,例如当您的库的 API 发生变化时,当您的数据段的排列发生变化时,当库维护内部线程时。名单很长。
For very small bug fixes to the code, you can still make use of ptraceto write to the process memory space, and from there redo what /lib/ld-linux.sodoes in terms of dynamic linking. Honestly, it is an extremely complex activity.
对于代码的非常小的错误修复,您仍然可以使用ptrace写入进程内存空间,并从那里重做/lib/ld-linux.so在动态链接方面所做的工作。老实说,这是一项极其复杂的活动。
回答by Zan Lynx
One interesting technique, although it is somewhat prone to failure in the checkpoint restore step, is to do an invisible restart.
一种有趣的技术,虽然它在检查点还原步骤中有点容易失败,但它是执行不可见的重启。
Your server process or whatever it is, saves all its necessary information into disk files. Including the file descriptor numbers and current states. Then, the server process does an exec
system call to execute itself, replacing the current version of itself. Then it reads its state from the disk files and resumes serving its file descriptors as if nothing happened.
您的服务器进程或其他任何进程将其所有必要信息保存到磁盘文件中。包括文件描述符编号和当前状态。然后,服务器进程执行exec
系统调用以执行自身,替换自身的当前版本。然后它从磁盘文件中读取它的状态并继续为它的文件描述符提供服务,就好像什么都没发生一样。
If all goes well, the restart is invisible and the new process is using all of the updated libraries.
如果一切顺利,重启是不可见的,新进程正在使用所有更新的库。
回答by Zan Lynx
At the very least, you have to make sure that the interface of the library does not change between versions. If that is assured, then I would try looking into dynamically loading the libraries with dlopen/dlsym and see if dlclose allows you to re-load.
至少,您必须确保库的接口不会在版本之间发生变化。如果可以保证,那么我会尝试使用 dlopen/dlsym 动态加载库,看看 dlclose 是否允许您重新加载。
I've never done any of this myself, but that's the path I'd pursue first. If you go this way, could you publish the results?
我自己从来没有做过这些,但这是我首先要走的道路。如果你这样做,你能公布结果吗?
回答by FCBusquest
Linux provides several dynamic loader interfaces, and process can load dynamic librarys when running. dlopen and dlsysm provided by linux may solve your problem.
Linux 提供了多个动态加载器接口,进程可以在运行时加载动态库。linux 提供的 dlopen 和 dlsysm 可以解决你的问题。