Лекция 4

25.02.2026 Обновлено: 25.02.2026

Нормальная компания живёт от кодовой базы. Твой накопленный код — это твоё богатство. Время уникальных решений прошло: уже не засесть в гараже и не написать что-то уникальное — всё когда-то уже было написано.

Архитектор Гауди в Барселоне строил дома без чётких границ, все грани были скруглёнными. Собор Саграда Фамилия он не успел достроить — и никто не может: невозможно повторить его подход к работе.

То же и в IT: если не использовать архитектурные паттерны, решение может быть крутым и ценным, но не будет способно развиваться.

Карл Росси — Аничков дворец устойчив к износу, окна не запотевают, летом прохладно, зимой тепло. Реставрация почти не нужна. Гениальный человек, удерживавший все аспекты в голове. Но таких людей — единицы.

В большом здании нужно провести вентиляцию, водопровод, электрику. Стык труб у главного электрощитка — не лучшая идея. Один специалист не может быть экспертом по всем дисциплинам одновременно.

Бурдж Халифа. Как с высоты 540 м смыть канализацию? Как обеспечить воду в кране? Обычное решение — труба огромного диаметра под огромным давлением. Там много необычных уникальных решений.

То же возникает и в программировании.

Виды архитектуры

  • Функциональная — с позиции пользователя. Что именно пользователь хочет видеть, где, как и почему. Ему безразличны паттерны и сложности разработки.
  • Информационная — информационные потоки, информационные объекты, процессы. Какие объекты выделяем для функциональности; как удаляем, добавляем, соединяем.
  • Системная — с позиции инженерии. Middleware-слои: паравиртуализация, контейнеризация. Разделяем функционал с точки зрения безопасности, стабильности, надёжности. Программные, пользовательские, аппаратные интерфейсы.
  • Программная — как организован код. Паттерны, фреймворки. Как реализован код, чтобы его можно было масштабировать. (Разработчики ОС не любят ООП.)
  • Архитектура данных — информационные объекты в виде структур данных, связи между ними.

Цель существования ОС

(Тут плохой перевод: goal — цель как конкретика, aim — цель глобально. Мы говорим про aim.)

  • Производительность
  • Надёжность
  • Безопасность

Всё это нужно обеспечить для четырёх объектов: Software, Hardware, Data, Interfaces.

Аналогично БД: добавляем ACID — падает производительность. Добавляем безопасность — падает надёжность и производительность. А здесь объектов 4, и все 3 свойства для каждого должны быть обеспечены.

Потеря сгоревшей железки — ерунда, просто затрата. Еврейская мудрость, которой поделился преподаватель: «Если проблему можно решить деньгами — это не проблема, а затрата».

Но потеря данных может быть фатальной.

Пример из аэропорта Хитроу (Лондон). Накатили обновление ПО — там была ошибка в непокрытом тестами фрагменте. У админа была некорректно настроена система бэкапов — они затирали друг друга. Решили быстро откатиться — бэкап оказался поломан. Код откатили, но данные не восстановить. А данные были — настройки линий багажа, регистрации. Никто не работал десятки лет без этой системы. Аэропорт почти на 3 суток выбыл из нормальной работы. Потери — 6-значные суммы фунтов стерлингов.


Функциональная архитектура

Выделим 4 метафункции и в каждой — более мелкие функции.

1. Управление исполнением и разработкой пользовательского ПО

  • API
  • Управление исполнением
  • Обнаружение и исправление ошибок
  • Организация ввода/вывода (I/O)
  • Хранилище данных
  • Мониторинг ресурсов

API. Не зря Керниган и Ричи 6 лет страдали и создавали основы UNIX — интеграцию компилятора и ядра. Раньше API не было. Вы пишете fopen() — и открывается дескриптор. Вы не задумываетесь, почему файл открылся, какая файловая система, как проверялись права доступа. Вы абстрагированы. fopen() дёрнула библиотеку, библиотека — API ядра, ядро дальше делает своё.

Управление исполнением. Нажал на ярлычок — волшебным образом запустился браузер. Код попал в память, отрисовалось окошко, процесс получил приоритеты, встал в очереди. Очереди оптимизированы под нового участника. И мы за этим не наблюдаем — как ребёнок не задумывается, как еда попадает в холодильник.

Обнаружение и исправление ошибок. Раньше при делении на 0 — чёрный экран, нет сигналов с клавиатуры; непонятно, ошибка это или вечный цикл. Чтобы закрыть — выдернуть из розетки. В 2000 строк кода для поиска ошибки нужно было написать сотни строк отладочного вывода. Сейчас IDE укажет на конкретную строчку. О том, как это реализовано, поговорим позже — но сложная логика: чтобы вывести информацию о падении на делении на 0, нужно сформировать её в видеопамяти и вывести. Как это сделать, если процессор «стоит»? Существует исключительное состояние процессора.

I/O. Разная скорость шин, разные протоколы. Воткнули принтер — он начал печатать. Под капотом — стек драйверов. Ввод/вывод должен быть буферизуем, потому что он асинхронен и нагрузка неравномерна. (Фильтр Калмана — штука, сглаживающая неравномерности процесса во времени, узнаем о нём на матане/статистике.)

У нас все железяки физические — на них действуют законы физики. Проезжающий трамвай по заледеневшим проводам может вызвать искру, электромагнитный импульс — и битик при передаче испортится. Это нужно проверять.

Хранилище данных. Эффективно записывать и доставать данные. С учётом контроля доступа и требований безопасности — файловые системы и т. п.

Мониторинг ресурсов. Запустил приложение — медленно работает. Compilation Error легко пофиксить, Runtime Error — тоже. Но что если программа работает без ошибок, но всё лежит? Как my.itmo: процессор загружен на 100%, памяти много, сетевых запросов толком нет. Активность есть, результатов нет — например, spin lock, опрос одной и той же переменной. Инструменты: top, htop, сетевые мониторы. С помощью Grafana сопоставляем графики во времени и находим, что проблема не там, где казалось.

2. Оптимизация использования ресурсов

  • Решение многокритериальных задач

С самого начала ОС должна оптимально использовать аппаратные ресурсы. Цена железки уже не главное — 2-5 тысяч за blade-сервер не дорого. Дороже электричество: вы привели 2 киловатта и должны их ещё отвести (КПД компьютера ничтожно — 99.5% энергии уходит в тепло). Сейчас лучшие умы стараются хоть немного поднять КПД.

ЦОД в Гренландии — всё хорошо. А в Дубае? Нормальная температура внутри ЦОД ~18 °C. Нагреть легко, охладить тяжело — и охлаждение может стоить дороже самого ЦОДа.

Человек, заплативший за blade-сервер, хочет, чтобы он работал на 100%.

Решение многокритериальных задач. Критерии противоречат друг другу. Как это решить?

1-й подход — суперкритерий. Вводим весовые коэффициенты:

$$\hat k = \alpha k_1 + \beta k_2 + \gamma k_3, \; \alpha + \beta + \gamma = 1$$

Есть понятие TCO (Total Cost of Ownership) — стоимость владения, можем выражать $\hat k$ в деньгах. Этим занимается эконометрика. Если бы функция была гладкой и всюду дифференцируемой — это было бы красивой математической задачей. Но в реальности приходится решать численными методами.

Boeing летает под Windows LC. Каждый самолёт индивидуален. Лётчик-испытатель составляет огромную инструкцию для конкретного борта. Угол открытия закрылков зависит от десятков параметров и должен высчитываться за секунду. Это делает Windows. А что если она в этот момент решит обновиться или дефрагментировать память? — Никакого расчёта за секунду не выйдет.

2-й подход — цикл Деминга:

Коэффициенты высчитываются на конкретное время.

  • P (Plan) — спланировали на ближайшее время.
  • D (Do) — выполнение плана.
  • C (Check) — план и факт сравниваются. Если что-то изменилось — обнаруживается расхождение.
  • A (Act) — устранение расхождения (например, поднять приоритет процессу, недополучившему ресурсов).

3. Поддержка эксплуатации

  • Диагностика
  • Восстановление

ОС очень сложна и, как любая система, работающая в открытом мире, будет ломаться. Совершенное ПО невероятно дорого. Если ошибка происходит с вероятностью 0.01%, экономически нецелесообразно с ней бороться.

4. Поддержка развития ОС

  • Обновление
  • Изменение конфигурации

Цикл создания ОС от каркаса до релиза — около 4 лет. Огромная кодовая база. Время эксплуатации — по 20 лет. До сих пор есть машины на Windows XP, FreeBSD 5–6. Будут находиться ошибки и уязвимости, появляться новые требования. На живой работающей машине поменять что-то и сохранить целостность — очень тяжело.

Ставим сервер под веб — со временем понимаем, что не тянет, и он становится доменным сервером. Профиль нагрузки меняется — нужно уметь отключать модули и включать другие в реальном времени.