2012-04-03 208 views
5

如果我的進程正在加載.so庫,並且該庫的新版本可用,是否可以在不進行進程重新啓動的情況下切換到新庫?或者答案取決於是否有一個參數更改爲庫中的某個現有函數?在不重新啓動進程的情況下更新共享庫

我正在一個漂亮的大系統中運行100個進程,每個加載10個庫。這些庫提供了特定的功能,並由獨立的團隊提供。所以當其中一個庫改變時(對於一個錯誤修復可以說)理想的事情就是在不影響正在運行的進程的情況下發布它。可能嗎 ?

編輯謝謝!在我的情況下,當一個新庫可用時,所有正在運行的進程必須開始使用它。它沒有選擇讓它們以舊版本運行並在稍後提取新版本。所以看起來更安全的選擇是重新加載進程。

+1

除非你控制所有的可執行文件,否則熱更新文件是不可能的,沒有醜陋的黑客像ptracing進程。另外,Linux不使用DLL。 – BatchyX 2012-04-03 20:49:17

回答

5

在運行過程中,您無法隨時升級鏈接庫。 你甚至可以嘗試,但如果你成功了(並且你不會失敗並顯示「正在使用文本文件」的錯誤信息),你將不得不重新開始這個過程,使它將新庫映射到內存中。

可以使用lsof的命令檢查哪些庫中(運行時或鏈接時間)鏈接:

lsof -p <process_pid> | grep ' mem ' 
+0

而不是'lsof -p ',你也可以使用'pldd '。 – Mikel 2012-04-05 20:44:02

+0

pldd:找不到命令。 apt-cache search pldd:沒有找到... – dAm2K 2012-04-06 11:52:20

+0

今年3月才添加到glibc。你的發行版可能還沒有包含它。 – Mikel 2012-04-06 14:13:55

0

ldd您的進程的二進制文件是找出的一種方法。雖然它在理論上是可行的,但不建議對運行過程進行修改,儘管我確信實用程序存在,例如與正在運行的Linux內核修補的ksplice。

您可以簡單升級,運行過程將繼續使用舊版本,並在重新啓動時選擇新版本,假設您的軟件包管理系統非常好,並且知道哪些軟件可以安裝。

0

您可能想了解共享庫版本控制和ld -h選項。使用它

的一種方法如下:

你保持你的編譯系統版本計數器。您建立與共享庫:

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

但是,你把它放在你的開發樹的lib的只是普通的mylibrary.so。 (還有一個涉及將整個.so文件放入.a文件的黑客入侵)。

現在,在運行時,使用庫的進程查找完全版本化的名稱。要推出新版本,您只需新版本添加到圖片中。運行與舊版本鏈接的程序將繼續使用它。隨着程序重新鏈接並針對新程序進行測試,您將推出新的可執行文件。

0

有時候,你可以升級使用中的。所以,有時你不能。這主要取決於你如何去做,而且取決於你正在運行的內核的安全保證。

不要這樣做: cat new.so> old.so ...因爲最終,您的過程可能會嘗試要求頁面某些內容,並發現它不再位於正確的位置。這是一個問題,因爲事物的地址可能會改變,並且它仍然是相同的inode;你只是覆蓋文件中的字節。

但是,如果您: MV new.so old.so 你會在大多數系統OK,因爲你正在運行的進程可不放的老圖書館現在命名的索引節點,而你的流程的新調用獲取新文件。但是,有些內核不喜歡讓你使用.so,或許是出於謹慎,也許是爲了他們自己的簡單。

+1

我不認爲「cat new.so> old.so」對正在運行的程序有任何影響。由於內核知道內存中的代碼段被映射到old.so所在的存儲區,所以它會拒絕寫入(「文本繁忙」),或者甚至繼續執行,直到程序結束。 – SquareRootOfTwentyThree 2012-04-04 12:54:23

0

如果你希望libaries來改變相當定期和 你希望保持正常運行時間,我認爲你的系統 應該進行重新設計,使這樣的圖書館居然成爲 鬆耦合的組件(例如服務)。

說了這麼多,我的問題的答案是肯定的:在某些 情況下,可能來更新共享庫沒有 重啓進程。在大多數情況下,我認爲這是不可能的,例如,當庫的API發生更改時,當數據段的排列更改 時,庫 保持內部線程時,將會出現這種情況。名單很長。

對於非常小的bug修復代碼,你仍然可以利用ptrace 寫入進程的內存空間,並從那裏 重做什麼/lib/ld-linux.so做動態 聯方面。老實說,這是一個非常複雜的活動。

3

一個有趣的技術,雖然在檢查點恢復步驟中有點容易失敗,但是做一個不可見的重啓。

您的服務器進程或任何它,將所有必要的信息保存到磁盤文件。包括文件描述符號碼和當前狀態。然後,服務器進程執行exec系統調用來執行自身,取代當前版本的自身。然後它從磁盤文件中讀取它的狀態並恢復爲其文件描述符提供服務,就好像什麼都沒發生過一樣。

如果一切順利,重新啓動是不可見的,並且新進程正在使用所有更新的庫。

+1

一個很好的例子是'irssi'和''upgrade'命令。 – 2012-04-04 01:37:54

2

至少,您必須確保庫的接口在版本之間不會更改。如果這是確定的,那麼我會試着動態加載dlopen/dlsym庫,看看dlclose是否允許你重新加載。

我自己從來沒有做過任何這樣的事情,但那是我首先追求的道路。如果你這樣做,你能發佈結果嗎?

2

Linux提供了幾個動態加載器接口,並且進程可以在運行時加載動態庫。 linux提供的dlopen和dlsysm可以解決你的問題。

相關問題