Как обновить разделяемую библиотеку без сбоев?

18

Здесь говорится, что вы можете переписать исполняемый файл, и процесс будет работать нормально - он будет перечитан при перезапуске процесса.

Однако, когда я пытаюсь заменить двоичный файл во время работы процесса (с помощью scp, от dev до тестового сервера), он говорит «file busy». И если я заменяю файл общей библиотеки (* .so), все процессы, которые связывают его, аварийно завершают работу.

Почему так? Я что-то пропустил? Как я могу заменить двоичные файлы без остановки / сбоя процесса?

Сэм
источник
Вы можете проверить .soфайл, используя ldd filename.soдля проверки зависимостей
Рахул Патил
Я знаю зависимости. Я хочу способ заменить эти файлы, не влияя на запущенные процессы. Как следует из связанного вопроса
Сэм
требуется время простоя .. или вы можете сделать как stop app && create symlink of .so && start app
Рахул Патил

Ответы:

21

Как уже упоминалось в разделе Почему программный пакет работает нормально, даже когда он обновляется? блокировка помещается в индекс, а не в имя файла. Когда вы загружаете и выполняете двоичный файл, файл помечается как занятый, поэтому вы получаете ошибку ETXTBSY (файл занят), когда пытаетесь записать в него файл.

Теперь для разделяемых библиотек это немного отличается: библиотеки отображают память в адресное пространство процесса с помощью mmap(). Хотя это MAP_DENYWRITEможет быть указано, по крайней мере, Glibc в Linux молча игнорирует его (согласно справочной странице, не стесняйтесь проверять источники) - проверьте эту ветку . Следовательно, вам действительно разрешено записывать файл, и, поскольку он отображен в памяти, любые изменения видны почти сразу - это означает, что, если вы попытаетесь достаточно усердно, вам удастся сделать кирпич своей машины, перезаписав библиотеку.

Следовательно, правильный способ обновления:

  1. удаление файла, который удаляет ссылку на данные из файловой системы, чтобы он был недоступен для новых приложений, которые могут его использовать, при этом данные остаются доступными для всех, у кого они уже открыты (или сопоставлены) ;

  2. создание нового файла с обновленным содержимым.

Вновь созданные процессы будут использовать обновленное содержимое, запущенные приложения получат доступ к старой версии. Это то, что делает любая вменяемая утилита управления пакетами. Обратите внимание, что это не совсем безо всякой опасности - например, приложения, динамически загружающие код (использующие dlsym()и друзья), будут испытывать проблемы, если API библиотеки будет изменяться в автоматическом режиме.

Если вы хотите быть действительно в безопасности, выключите систему, смонтируйте файловую систему из другого экземпляра операционной системы, обновите и снова запустите обновленную систему.

peterph
источник
6

Обновление rpm делает то же самое - с запущенными двоичными файлами и библиотеками, пока ничего не происходит.

Так в чем же разница:

  1. отсоединить файл
  2. написать новый файл с тем же именем

Это НЕ заменит файл на месте: индекс, ссылающийся на двоичный файл в использовании, все еще «занят», пока не завершится последний объект, удерживающий его открытым. Новый файл будет создан с новым номером inode.

Теперь scpили cpпопытается заменить файл на месте - это изменит содержимое, на которое ссылается индекс. Это не работает - как вы описали.

Nils
источник