- комментарий 0:
From: kmeaw
Date: 2021-05-02 17:44:10Z
Я знаю по крайней мере один сценарий, который практически невозможно
реализовать без shared-библиотек и при использовании современных
оптимизирующих компиляторов.
Есть большая production-система, останавливать которую дорого. Эта
система состоит из множества программ и использует какую-то известную
shared-библиотеку, в которой находят уязвимость (например, OpenSSL и
Heartbleed). Нужно как можно быстрее эту уязвимость закрыть.
В случае использования shared-библиотек достаточно один раз изучить
уязвимый код и массово заменить его. В случае статической линковки
(особенно портит этот сценарий использование LTO и/или C++) придётся
изучать каждый случай использования уязвимой библиотеки и решать его
отдельно. А ещё на каждой машине может оказаться неопределённое число
сервисных зависимостей, за версиями которых никто особо не следит, и
тогда сложность задачи возрастёт многократно.
В любом случае, shared libraries никуда не денутся хотя бы потому, что
некоторым приложениям надо уметь в run-time загружать новый код
(плагины).
- комментарий 1:
From: Sergey Matveev
Date: 2021-05-02 17:56:32Z
*** kmeaw [2021-05-02 20:42]:
>В случае использования shared-библиотек достаточно один раз изучить
>уязвимый код и массово заменить его.
Я для себя этот случай отношу к мифам. Точнее к гипотетическому случаю.
Не должно быть никаких проблем чтобы перекомпилировать и всю систему и
все зависимости. Если текущие дистрибутивы/ОС не позволяют это сделать в
разумное время, то это не причина использовать костыли в виде shared
libraries. Если отталкиваться от того, что куча софта написано очень
далеко от идеала, коряво и криво, то наверное shared lib и может
пригодиться, как is good enough костыль. Лично я предпочитаю
ориентироваться на то, каким софт должен быть. Всегда мириться с
костылями -- они так никуда не исчезнут. Менять мир к лучшему можно
только конкретно выпиливая и заменяя что-то (безусловно терпя какое-то
время некоторые неудобства), а не продолжая делать какие-нибудь yet
another IPv4 сети из года в год (просто как пример). Уже надоело
мучаться с постоянной ношей legacy то там, то тут.
>В любом случае, shared libraries никуда не денутся хотя бы потому, что
>некоторым приложениям надо уметь в run-time загружать новый код
>(плагины).
Это решается архитектурно без проблем например вынесением плагинов в
отдельные демоны, с которымы идёт RPC общение. Лично для меня плагины уж
точно совершенно надуманная причина shared lib. Plan 9, целая ОС, имеет
только статическую линковку и там не появились причины для shared lib-ов.
- комментарий 2:
From: kmeaw
Date: 2021-05-02 18:13:26Z
> Не должно быть никаких проблем чтобы перекомпилировать и всю систему и
> все зависимости.
Нет проблемы перекомпилировать все бинарники сервиса с новой версией
ранее уязвимой библиотеки. Есть проблема с тем, чтобы его перезапустить.
Shared libraries заставляют так проектировать интерфейсы и накладывают
на компиляторы такие ограничения, что код приложения и код библиотеки
разделены достаточно, чтобы его можно было попатчить, потратив не
слишком много усилий.
Ровно такая же ситуация с ядром. Благодаря тому, что ядро исполняется в
своём отдельном адресном пространстве, и код ядра очень сильно отделён
от кода приложений, его можно попатчить без остановки для немедленного
исправления какой-нибудь уязмости, не останавливая production.
Если бы ОС были устроены по-другому, и компиляторы инлайнили код ядра
внутрь прикладных программ (как в IncludeOS или как могло бы быть в MS
Singularity), то наложить такой патч было бы в сотни или тысячи раз
труднее. Дешевле будет потерять деньги от простоя, чем оплачивать труд
хакеров, способных провернуть такое безопасно.
Не всякую нагрузку можно плавно переключить на другие машины. Даже в тех
случаях, когда это возможно, часто бывает лучше сделать это в рамках
следующего запланированного обновления ПО, а прямо сейчас быстро
заткнуть проблему патчем, вместо того, чтобы оторвать команду
эксплуатации от того, чем они сейчас занимаются, и тратить их силы на
переключение нагрузки и переналивку всей системы частями.
> Это решается архитектурно без проблем например вынесением плагинов в
> отдельные демоны, с которымы идёт RPC общение.
Тогда придётся копировать слишком много данных. Как, например,
реализовать модель плагинов nginx? Писать на каждый плагин по reverse
proxy?
Я почитал тред в LKML, и на самом деле Торвальдс и сам не против shared
libraries:
https://lore.kernel.org/lkml/CAHk-=wgdUMt_n84mq93LZKA6jOGqZpD+=KeVzA3YmvJ6=JPyhw@mail.gmail.com/
> The argument was never that things like libc or the core GUI libraries
> shouldn't be shared.
>
> The argument was that the "one-off" libraries shouldn't be shared.
>
> Things very much like libLLVM.so.
>
> Or things like "libdivecomputer.so". You probably have never ever
> heard of that library, have you? It's used by one single project, that
> project isn't even in Fedora, but when we tried to make an rpm for it,
> people complained because the Fedora rules said it needed to use
> shared libraries.
https://lore.kernel.org/lkml/CAHk-=whs8QZf3YnifdLv57+FhBi5_WeNTG1B-suOES=RcUSmQg@mail.gmail.com/
> [ Or, for those very rare programs that end up dynamically loading
> rare modules at run-time - not at startup - because that's their
> extension model. But that's a different kind of "shared library"
> entirely, even if ELF makes the technical distinction between
> "loadable module" and "shared library" be a somewhat moot point ]
- комментарий 3:
From: Sergey Matveev
Date: 2021-05-02 18:37:26Z
*** kmeaw [2021-05-02 21:12]:
>Есть проблема с тем, чтобы его перезапустить.
Допустим, есть задачи где нужно прозрачно и безшовно обновить какой-то
код. Если этот код бы был вынесен как некий отдельный демон, то его
точно можно обновить прозрачно. По сути я веду, получается, к другой
крайности, где все .so заменяются RPC-available службами, снова.
>> Это решается архитектурно без проблем например вынесением плагинов в
>> отдельные демоны, с которымы идёт RPC общение.
>
>Тогда придётся копировать слишком много данных. Как, например,
>реализовать модель плагинов nginx? Писать на каждый плагин по reverse
>proxy?
Да, я считаю что нет проблем на каждый плагин писать по proxy. Я так и
предполагал что про производительность будет сказано :-), но я считаю
что проще пожертвовать производительностью/задержками (купить железо
помощнее), чем усложнять софт, тем более, ради единичных use-case-ов.
А сейчас получается так: крайне мало кому .so действительно нужны
(безшовный перезапуск/обновление), но оно всюду по умолчанию применяется
и из-за этого в целом запуск любых программ замедляется. То есть из-за
редких случаев действительно реальной пользы .so -- страдают все. Лучше
бы было наоборот: всё статически и только для особых случаев, с которыми
большинство за всю свою жизнь не столкнётся, сделать какие-то особенные
программы с динамической линковкой (что вообще может быть какой-то
отдельной прослойкой, не встроенной в ОС по умолчанию). Это для меня как
DPDK: штука может для особых задач дать большой профит, но 99.99% людям
это не понадобится никогда в жизни. Поэтому DPDK вряд ли должен быть
неотъемлемой частью ОС. Вот и аналогично с .so -- это почти никому не
нужно на практике. А без .so я чисто визуально даже вижу как может
быстрее загрузиться исполняемый файл. Ну да, запросто на жёстком диске
только места будет отъедено побольше. Благо что мы не на встраиваемых
системах живём.
>Я почитал тред в LKML, и на самом деле Торвальдс и сам не против shared
>libraries:
Да я и сам понимаю что есть случаи (libc) когда оно могло бы принести
больше профита как .so. Аргументы "за" статическую линковку часто просто
сравнивают динамически слинкованного монстра glibc и маленькое
статически слинкованного musl. Везде tradeoff-ы и везде есть ситуации
где что-то перевешивает. Моя позиция в том, что на практике .so мало
кому приносят реально пользы, поэтому не стоит их иметь по умолчанию:
место на диске у людей чуть-чуть отъестся, зато хотя бы скорость
загрузки програм увеличится, да и RAM может поменьше есть.
- комментарий 4:
From: Sergey Matveev
Date: 2021-05-02 21:03:43Z
*** kmeaw [2021-05-02 21:12]:
>Как, например, реализовать модель плагинов nginx?
А я вот думаю что эти плагины нужно просто статически вкомпилировать в
сам сервер. Я уверен что у преобладающего большинства пользователей
nginx, список модулей которые они используют меняется раз во много
месяцев или лет (не считая первоначальной настройки). Если бы nginx был
написан на Go, то его модули бы были просто файлами у которых проставлен
определённый флаг для сборки. Рядом всегда лежат исходники, в которых я
делаю go build, указываю нужные тэги (mod_то, mod_сё), они собираются
внутрь сервера. Пара секунд компиляции -- можно проверять. И
производительность не падает из-за RPC, и всё летает. А динамически
конфигурировать и подгружать модули... да нафиг надо, не такой ценой.
Само собой, опять же, это подразумевает что софт должен быть похож на
slashpackage подход, где везде рядом лежит исходный код из которого
можно всё пересобрать. И само собой, процесс сборки должен быть быстрым,
чему Си и Go, как правило, этому удовлетворяют. А тот факт что это не
очень дружит с пакетными системами (ведь кол-во возможных вариантов
сборок nginx-а с разным набором модулей будет огромным числом), говорит
только (с моей точки зрения, конечно же) об ущербности подхода
распространения заранее собранных бинарей. Быстрые компиляторы/языки,
быстрые системы сборки, только свободное ПО (а значит и исходный код под
рукой) -- всё что нужно для простой, быстрой и надёжной (в том числе
из-за простоты) системы!