# Алгоритм и O-нотация > Алгоритм — конечная последовательность шагов для решения задачи; O-нотация описывает, как растут время работы и память алгоритма с ростом размера входных данных. Источник: https://llmdocs.ru/wiki/big-o/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Алгоритм**: конечная последовательность однозначных шагов - **Происхождение слова**: от имени аль-Хорезми (IX век) - **O-нотация**: верхняя граница роста функции - **Родственные обозначения**: Ω (нижняя граница), Θ (точная оценка) - **Авторы нотации**: Пауль Бахман (1894), Эдмунд Ландау; в информатике популяризировал Дональд Кнут - **Виды оценок**: худший, средний, лучший случай, амортизированная **Алгоритм** — конечная последовательность однозначных шагов, которая по входным данным за конечное время получает результат: рецепт сортировки списка, поиска пути на карте или проверки пароля. Слово происходит от латинизированного имени персидского математика IX века аль-Хорезми. **O-нотация** («О большое», англ. *Big O*) — способ описать, как растут время работы или потребление памяти алгоритма при увеличении размера входных данных *n*, отбрасывая константы и несущественные слагаемые. O-нотация — общий язык программистов для сравнения решений: «поиск по хеш-таблице — O(1), сортировка — O(n log n), вложенный цикл по списку — O(n²)». ## Зачем нужна асимптотическая оценка Время работы программы зависит от процессора, языка и данных, поэтому сравнивать алгоритмы в секундах неудобно. Важнее, как время **растёт**: алгоритм O(n²) на 1000 элементах может работать быстрее алгоритма O(n log n), но на миллионе элементов разница составит десятки тысяч раз. O-нотация отвечает на вопрос «что будет, когда данных станет в 10 или в 1000 раз больше». ## Определение Говорят, что функция *f(n)* есть **O(g(n))**, если начиная с некоторого *n₀* она не превосходит *c·g(n)* для некоторой константы *c*. Иными словами, *g* — верхняя граница роста *f* с точностью до константы. Поэтому `3n² + 5n + 100` — это O(n²): при больших *n* старшее слагаемое доминирует, а константы не важны. Родственные обозначения: **Ω** (омега) — нижняя граница, **Θ** (тета) — точная оценка сверху и снизу. Их строгое использование в информатике предложил Дональд Кнут в 1976 году.[1] В обиходе «O» часто говорят, имея в виду Θ. ## Типичные классы сложности | Сложность | Название | Пример | При n = 1 000 000 | |---|---|---|---| | O(1) | константная | доступ к элементу массива по индексу, поиск в [хеш-таблице](https://llmdocs.ru/wiki/hash-table.md) | 1 | | O(log n) | логарифмическая | двоичный поиск, поиск в [сбалансированном дереве](https://llmdocs.ru/wiki/b-tree.md) | ≈ 20 | | O(n) | линейная | проход по списку, поиск максимума | 10⁶ | | O(n log n) | линейно-логарифмическая | эффективная [сортировка](https://llmdocs.ru/wiki/sorting.md) (слиянием, Timsort) | ≈ 2·10⁷ | | O(n²) | квадратичная | вложенный цикл, сортировка пузырьком | 10¹² | | O(2ⁿ) | экспоненциальная | перебор всех подмножеств | непосильно | | O(n!) | факториальная | перебор всех перестановок (задача коммивояжёра) | непосильно | ## Как оценивать код - Последовательные шаги складываются, и остаётся самый тяжёлый: O(n) + O(n²) = O(n²). - Вложенные циклы перемножаются: цикл по *n* внутри цикла по *n* даёт O(n²). - Деление задачи пополам на каждом шаге даёт логарифм. - [Рекурсивные](https://llmdocs.ru/wiki/recursion.md) алгоритмы оцениваются через рекуррентные соотношения, например T(n) = 2T(n/2) + O(n) даёт O(n log n) для сортировки слиянием.[2] ```python def has_duplicates_slow(items): # O(n²): каждый с каждым for i in range(len(items)): for j in range(i + 1, len(items)): if items[i] == items[j]: return True return False def has_duplicates_fast(items): # O(n) по времени, O(n) по памяти seen = set() for x in items: if x in seen: # проверка в множестве — O(1) в среднем return True seen.add(x) return False ``` Второй вариант — классический обмен памяти на время: дополнительное множество позволяет избавиться от вложенного цикла. ## Скрытая сложность Операции, выглядящие как один шаг, могут быть дорогими. В [Python](https://llmdocs.ru/wiki/python.md) проверка `x in list` — это O(n), а `x in set` — O(1) в среднем; вставка в начало списка `list.insert(0, x)` — O(n), а в `collections.deque` — O(1). Сложность операций стандартных структур данных Python сведена в таблицу на Python Wiki.[3] То же относится к базам данных: запрос без [индекса](https://llmdocs.ru/wiki/database-index.md) сканирует всю таблицу — O(n), — а с индексом на B-дереве — O(log n). ## Виды оценок - **Худший случай** — гарантия: быстрая сортировка в худшем случае O(n²). - **Средний случай** — ожидаемое время на типичных данных: быстрая сортировка в среднем O(n log n). - **Амортизированная оценка** — среднее по последовательности операций: добавление в динамический массив иногда требует копирования, но в среднем стоит O(1). - **Сложность по памяти** — сколько дополнительной памяти требуется, оценивается так же. ## Ограничения O-нотация игнорирует константы, а на практике они важны: для небольших *n* простой алгоритм O(n²) часто быстрее сложного O(n log n), поэтому, например, Timsort сортирует короткие участки вставками. Влияют также кэши процессора ([Кэш (вычисления)](https://llmdocs.ru/wiki/cache.md)), распределение данных и ввод-вывод. Асимптотика подсказывает, где искать проблему, а окончательный ответ даёт измерение. Систематически алгоритмы изучают по учебнику Кормена и соавторов и курсам вроде MIT 6.006.[4] Краткая шпаргалка по сложности популярных алгоритмов — Big-O Cheat Sheet.[5] ## См. также - [Структуры данных](https://llmdocs.ru/wiki/data-structures.md) - [Сортировка](https://llmdocs.ru/wiki/sorting.md) - [Хеш-таблица](https://llmdocs.ru/wiki/hash-table.md) - [Рекурсия](https://llmdocs.ru/wiki/recursion.md) - [Дерево и граф](https://llmdocs.ru/wiki/trees-graphs.md) ## Источники 1. [D. Knuth — Big Omicron and big Omega and big Theta (SIGACT News, 1976)](https://dl.acm.org/doi/10.1145/1008328.1008329) 2. [T. Cormen et al. — Introduction to Algorithms, 4th ed. (MIT Press)](https://mitpress.mit.edu/9780262046305/introduction-to-algorithms/) 3. [Python Wiki — TimeComplexity](https://wiki.python.org/moin/TimeComplexity) 4. [MIT OpenCourseWare — Introduction to Algorithms (6.006)](https://ocw.mit.edu/courses/6-006-introduction-to-algorithms-spring-2020/) 5. [Big-O Cheat Sheet](https://www.bigocheatsheet.com/) --- # Кэш (вычисления) > Быстрое хранилище копий данных, которое ускоряет повторный доступ к медленному источнику; от кэшей процессора и страничного кэша ОС до HTTP-кэша, CDN и Redis — с вечными вопросами инвалидации и вытеснения. Источник: https://llmdocs.ru/wiki/cache/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Назначение**: ускорить повторный доступ к данным за счёт их копии в быстром хранилище - **Метрика**: доля попаданий (hit ratio) - **Политики вытеснения**: LRU, LFU, FIFO, TTL, ARC, W-TinyLFU - **Стратегии записи**: write-through, write-back, write-around - **Уровни**: регистры → L1/L2/L3 → ОЗУ → страничный кэш → диск → сеть - **Прикладные кэши**: Redis, Memcached, Varnish, CDN, HTTP-кэш браузера **Кэш** (англ. *cache*) — небольшое быстрое хранилище, в котором держат копии данных из более медленного источника, чтобы повторные обращения обслуживались быстрее. Кэши есть на всех уровнях вычислительной системы: в процессоре, операционной системе, базах данных, приложениях, браузере и сети доставки контента. Если нужные данные нашлись в кэше — это **попадание** (*cache hit*), если нет — **промах** (*cache miss*), и данные приходится доставать из источника. ## Иерархия памяти Кэширование работает потому, что программы обладают **локальностью**: недавно использованные данные скорее всего понадобятся снова (временная локальность), а соседние с ними — тоже (пространственная).[1] Порядки задержек сильно различаются:[7] | Уровень | Типичная задержка | |---|---| | Кэш L1 процессора | ~1 нс | | Кэш L2 / L3 | ~4 / ~40 нс | | Оперативная память | ~100 нс | | Чтение с NVMe SSD | ~20–100 мкс | | Запрос в пределах дата-центра | ~0,5 мс | | Запрос через континент | ~50–150 мс | Процессор читает память строками кэша по 64 байта, поэтому последовательный проход по массиву многократно быстрее «прыжков» по связному списку, хотя асимптотика обоих — O(n) (см. [Алгоритм и O-нотация](https://llmdocs.ru/wiki/big-o.md)). Операционная система держит недавно прочитанные блоки файлов в **страничном кэше** — поэтому свободная память в [Linux](https://llmdocs.ru/wiki/linux.md) почти всегда «занята» под buff/cache, и это нормально. ## Где кэшируют в приложениях - **Мемоизация функций** — запоминание результата для одинаковых аргументов:[4] ```python from functools import lru_cache @lru_cache(maxsize=1024) def get_rate(currency: str) -> float: return fetch_from_api(currency) # медленный внешний вызов ``` - **Кэш перед базой данных** — [Redis](https://llmdocs.ru/wiki/redis.md) или Memcached хранят результаты частых запросов, сессии, счётчики. - **HTTP-кэш** — браузер, [обратный прокси](https://llmdocs.ru/wiki/reverse-proxy.md) и [CDN](https://llmdocs.ru/wiki/cdn.md) сохраняют ответы по правилам заголовков `Cache-Control`, `ETag`, `Last-Modified` (RFC 9111).[2][3] ```http Cache-Control: public, max-age=31536000, immutable # статика с хешем в имени Cache-Control: no-cache # хранить, но проверять каждый раз ETag: "33a64df5" # клиент спросит If-None-Match → 304 ``` - **Кэши сборки** — слои Docker-образов, кэш зависимостей в [CI/CD](https://llmdocs.ru/wiki/ci-cd.md), `__pycache__`, кэш компилятора. - **Кэш в LLM** — KV-кэш внимания при генерации и [кэширование промптов](https://llmdocs.ru/wiki/prompt-caching.md) у API-провайдеров. ## Стратегии чтения и записи - **Cache-aside** (ленивая загрузка) — самая распространённая: приложение ищет в кэше, при промахе читает из БД и кладёт результат в кэш с TTL.[6] ```python def get_user(uid): if (cached := redis.get(f"user:{uid}")) is not None: return json.loads(cached) user = db.fetch_user(uid) redis.set(f"user:{uid}", json.dumps(user), ex=300) # TTL 5 минут return user ``` - **Write-through** — запись идёт одновременно в кэш и в источник; данные согласованы, запись медленнее. - **Write-back** — запись сначала только в кэш, в источник позже; быстро, но при сбое данные могут потеряться (так работают кэши процессора и дисков). - **Write-around** — запись мимо кэша, он заполняется только при чтении. ## Вытеснение Кэш ограничен, поэтому при заполнении нужно решать, что выбросить: - **LRU** (*least recently used*) — дольше всего не использовавшийся элемент; классическая реализация — [хеш-таблица](https://llmdocs.ru/wiki/hash-table.md) плюс двусвязный список, обе операции за O(1); - **LFU** — используемый реже всего; - **FIFO**, случайное вытеснение; - **TTL** — элемент истекает по времени; - адаптивные алгоритмы — ARC, W-TinyLFU (библиотеки Caffeine, Ristretto). В Redis политика задаётся параметром `maxmemory-policy`, например `allkeys-lru` или `volatile-ttl`.[5] ## Инвалидация и типовые проблемы Известная шутка Фила Карлтона: «В информатике есть только две сложные вещи — инвалидация кэша и придумывание имён». Главные трудности: - **Устаревшие данные** — источник изменился, а кэш отдаёт старое. Решения: короткий TTL, явное удаление ключа при изменении, версии в ключах (`user:42:v7`), хеш содержимого в имени файла для статики. - **Лавина промахов** (*cache stampede*) — популярный ключ истёк, и тысячи запросов одновременно идут в БД. Помогают блокировка на перестроение, ранний случайный перерасчёт и устаревшие ответы на время обновления (`stale-while-revalidate`). - **Холодный старт** — после перезапуска кэш пуст, нагрузка на источник резко растёт. - **Кэширование персональных данных** — ответ одного пользователя, ошибочно закэшированный общим кэшем, увидят другие; для таких ответов нужен `Cache-Control: private` или `no-store`. - **Согласованность** между несколькими кэшами и экземплярами приложения — требует [распределённых](https://llmdocs.ru/wiki/distributed-systems.md) механизмов инвалидации. Кэш — оптимизация, а не источник истины: система должна работать корректно (пусть и медленнее), если кэш пуст или недоступен. ## См. также - [Redis](https://llmdocs.ru/wiki/redis.md) - [CDN](https://llmdocs.ru/wiki/cdn.md) - [Хеш-таблица](https://llmdocs.ru/wiki/hash-table.md) - [HTTP](https://llmdocs.ru/wiki/http.md) ## Источники 1. [Hennessy, Patterson — Computer Architecture: A Quantitative Approach (6th ed.), ch. 2 Memory Hierarchy](https://www.elsevier.com/books/computer-architecture/hennessy/978-0-12-811905-1) 2. [RFC 9111 — HTTP Caching](https://www.rfc-editor.org/rfc/rfc9111) 3. [MDN — HTTP caching](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Caching) 4. [Python — functools.lru_cache and functools.cache](https://docs.python.org/3/library/functools.html#functools.lru_cache) 5. [Redis — Key eviction](https://redis.io/docs/latest/develop/reference/eviction/) 6. [AWS — Caching best practices](https://aws.amazon.com/caching/best-practices/) 7. [Peter Norvig — Latency numbers every programmer should know](https://norvig.com/21-days.html#answers) --- # CAP-теорема > Утверждение о том, что распределённая система при сетевом разделении должна выбрать между согласованностью и доступностью; уточнение — модель PACELC. Источник: https://llmdocs.ru/wiki/cap-theorem/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Автор гипотезы**: Эрик Брюер (2000) - **Доказательство**: Сет Гилберт и Нэнси Линч (2002) - **C**: согласованность (линеаризуемость) - **A**: доступность (каждый запрос к живому узлу получает ответ) - **P**: устойчивость к разделению сети - **Расширение**: PACELC (Дэниел Абади, 2010) **CAP-теорема** — утверждение из теории [распределённых систем](https://llmdocs.ru/wiki/distributed-systems.md): система, хранящая данные на нескольких узлах, не может одновременно гарантировать **согласованность** (*Consistency*), **доступность** (*Availability*) и **устойчивость к разделению сети** (*Partition tolerance*). Поскольку сетевые сбои в реальном мире неизбежны, на практике теорема означает выбор: когда связь между узлами потеряна, система либо отказывает части запросов, сохраняя согласованность, либо отвечает на все, рискуя отдать устаревшие или противоречивые данные. ## История Эрик Брюер (Калифорнийский университет в Беркли, Inktomi) сформулировал гипотезу в докладе 2000 года.[1] В 2002 году Сет Гилберт и Нэнси Линч из MIT строго определили термины и доказали её.[2] Теорема стала популярным аргументом в эпоху [NoSQL](https://llmdocs.ru/wiki/nosql.md): многие системы объясняли отказ от строгой согласованности именно ею. ## Три свойства В доказательстве Гилберта и Линч свойства определены узко: | Свойство | Строгий смысл | |---|---| | **C — согласованность** | линеаризуемость: система ведёт себя как одна копия данных; каждое чтение видит результат последней завершённой записи | | **A — доступность** | каждый запрос к работающему узлу получает ответ (не ошибку), без ограничения по времени | | **P — устойчивость к разделению** | система продолжает работать, когда сеть теряет сообщения между группами узлов | «C» в CAP — не то же самое, что «C» в [ACID](https://llmdocs.ru/wiki/transaction-acid.md): там речь о соблюдении ограничений целостности, а здесь — о том, все ли копии отвечают одинаково. ## Суть доказательства Пусть данные реплицированы на два узла, и связь между ними пропала. Клиент записывает новое значение на первый узел, а другой клиент читает со второго. Второй узел может: - **ответить** старым значением — система доступна, но не согласована (AP); - **отказать** или ждать восстановления связи — система согласована, но недоступна (CP). Третьего варианта нет: узел не может узнать о записи, не получив сообщения. ## CP и AP - **CP-системы** при разделении отказывают в обслуживании меньшей части кластера. Пример — системы на алгоритмах консенсуса Raft и Paxos: etcd, ZooKeeper, Consul; распределённые SQL-базы вроде CockroachDB и Google Spanner. Узел без связи с большинством перестаёт принимать записи. - **AP-системы** продолжают отвечать на всех узлах, а расхождения устраняют позже (**согласованность в конечном счёте**, eventual consistency) — с помощью версий, векторных часов, «последняя запись побеждает» или CRDT. Пример — Cassandra, Riak, DynamoDB в режиме по умолчанию, DNS. Выбора «CA» на практике нет: система на одном узле не распределена, а распределённая не может отказаться от P — разделения случаются независимо от желаний разработчика. ## Критика и уточнения Сам Брюер в 2012 году отметил, что формула «выберите два из трёх» вводит в заблуждение.[3] Основные замечания: - **Разделения редки.** Большую часть времени сеть работает, и CAP ничего не говорит о поведении в нормальном режиме. - **Выбор не бинарный.** Систему можно настраивать для каждой операции: в Cassandra и [MongoDB](https://llmdocs.ru/wiki/mongodb.md) уровень согласованности задаётся на запрос (чтение и запись с кворумом дают строгую согласованность при отсутствии сбоев). - **Определения слишком узки.** Многие реальные базы не являются ни CP, ни AP в строгом смысле — например, реплика [асинхронной репликации](https://llmdocs.ru/wiki/replication.md) PostgreSQL не даёт ни линеаризуемости, ни полной доступности. Поэтому Мартин Клеппман предлагает не навешивать ярлыки, а описывать конкретные гарантии.[5] ## PACELC Дэниел Абади предложил более полезную модель **PACELC**: *если есть разделение (P), выбирай между доступностью (A) и согласованностью (C); иначе (E — else) — между задержкой (L — latency) и согласованностью (C)*.[4] Даже без сбоев синхронная репликация на другой континент добавляет десятки миллисекунд к каждой записи. Например, DynamoDB и Cassandra по умолчанию — PA/EL (жертвуют согласованностью ради доступности и скорости), а Spanner и CockroachDB — PC/EC. ## Модели согласованности Между линеаризуемостью и согласованностью в конечном счёте лежит спектр промежуточных гарантий: последовательная согласованность, причинная согласованность, «читаю свои записи», монотонное чтение. Проект Jepsen систематически проверяет, какие гарантии реально дают популярные базы данных, и нередко находит расхождения с документацией.[6] Связанное понятие внутри одной базы — [уровни изоляции транзакций](https://llmdocs.ru/wiki/isolation-levels.md). ## Практические выводы - Выясните, что важнее для конкретных данных: остатки на счёте и уникальность логинов требуют согласованности; лента новостей, счётчики просмотров и корзина переживут кратковременные расхождения. - Читайте документацию базы о поведении при сбоях и уровнях согласованности, а не ярлык «CP/AP». - Проектируйте приложение с учётом возможных расхождений: идемпотентные операции, разрешение конфликтов, повторные попытки. ## См. также - [Распределённые системы](https://llmdocs.ru/wiki/distributed-systems.md) - [Репликация баз данных](https://llmdocs.ru/wiki/replication.md) - [NoSQL](https://llmdocs.ru/wiki/nosql.md) - [Транзакция и ACID](https://llmdocs.ru/wiki/transaction-acid.md) ## Источники 1. [Brewer — Towards Robust Distributed Systems (PODC 2000 keynote)](https://people.eecs.berkeley.edu/~brewer/cs262b-2004/PODC-keynote.pdf) 2. [Gilbert, Lynch — Brewer's Conjecture and the Feasibility of Consistent, Available, Partition-Tolerant Web Services (2002)](https://dl.acm.org/doi/10.1145/564585.564601) 3. [Brewer — CAP Twelve Years Later: How the "Rules" Have Changed (IEEE Computer, 2012)](https://www.infoq.com/articles/cap-twelve-years-later-how-the-rules-have-changed/) 4. [Abadi — Consistency Tradeoffs in Modern Distributed Database System Design (PACELC, 2012)](https://www.cs.umd.edu/~abadi/papers/abadi-pacelc.pdf) 5. [Kleppmann — Please stop calling databases CP or AP (2015)](https://martin.kleppmann.com/2015/05/11/please-stop-calling-databases-cp-or-ap.html) 6. [Jepsen — Consistency Models](https://jepsen.io/consistency) --- # Компилятор и интерпретатор > Два способа выполнять программы — заранее перевести исходный код в машинный (компиляция) или исполнять его по ходу (интерпретация); на практике языки сочетают оба подхода через байткод, виртуальные машины и JIT. Источник: https://llmdocs.ru/wiki/compiler-interpreter/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Компилятор**: переводит программу целиком до запуска (AOT) - **Интерпретатор**: исполняет программу по ходу чтения - **Промежуточные формы**: AST, байткод, IR (LLVM IR, SSA) - **Гибриды**: байткод + ВМ, JIT-компиляция - **Примеры AOT**: C, C++, Rust, Go, Swift - **Примеры ВМ и JIT**: JVM, .NET CLR, V8, PyPy, LuaJIT **Компилятор** — программа, которая переводит исходный код целиком в другую форму, обычно в машинный код процессора, *до* запуска. **Интерпретатор** — программа, которая исполняет исходный код (или его промежуточное представление) *по ходу*, без создания отдельного исполняемого файла. Это два полюса; большинство современных языков сочетают оба подхода: компилируют исходник в байткод, а байткод интерпретируют и «на горячих участках» компилируют в машинный код прямо во время работы (JIT).[1][2] ## Этапы обработки программы Независимо от подхода, обработка начинается одинаково: 1. **Лексический анализ** — текст разбивается на токены: ключевые слова, имена, числа, операторы. Часто для этого используются [регулярные выражения](https://llmdocs.ru/wiki/regex.md). 2. **Синтаксический анализ** — из токенов строится **абстрактное синтаксическое дерево** (AST) по грамматике языка (см. [Дерево и граф](https://llmdocs.ru/wiki/trees-graphs.md)). 3. **Семантический анализ** — разрешение имён (через таблицы символов — обычно [хеш-таблицы](https://llmdocs.ru/wiki/hash-table.md)), проверка типов, ошибки вида «переменная не объявлена». 4. **Промежуточное представление** (IR) — упрощённая форма, удобная для анализа: байткод, трёхадресный код, SSA-форма. 5. **Оптимизация** — свёртка констант, удаление мёртвого кода, встраивание функций, развёртка циклов, векторизация. 6. **Генерация кода** — машинные инструкции для конкретной архитектуры (x86-64, ARM64) или байткод для виртуальной машины; затем компоновка (linking) с библиотеками. Первые три этапа — «фронтенд», последние — «бэкенд». Инфраструктура **LLVM** разделила их: фронтенды Clang (C/C++), [rustc](https://llmdocs.ru/wiki/rust.md), Swift, Zig выдают общий LLVM IR, а общий бэкенд оптимизирует его и генерирует код под десятки архитектур.[3] ## Компиляция заранее (AOT) Языки C, C++, Rust, [Go](https://llmdocs.ru/wiki/go.md), Swift, Haskell компилируются *ahead-of-time*: на выходе — исполняемый файл с машинным кодом.[7] - **Плюсы:** высокая скорость и предсказуемость, быстрый старт, ошибки типов находятся до запуска, не нужен интерпретатор на целевой машине (Go-программа — один статический бинарник). - **Минусы:** время сборки, отдельная сборка для каждой ОС и архитектуры, оптимизатор не знает реальных данных, на которых будет работать программа. ## Интерпретация Простейший интерпретатор обходит AST и выполняет узлы один за другим (tree-walking). Так работали ранние реализации многих языков; сегодня так делают учебные и встраиваемые интерпретаторы, а также оболочки вроде [Bash](https://llmdocs.ru/wiki/shell-bash.md). - **Плюсы:** мгновенный запуск без сборки, интерактивный режим (REPL), переносимость, простота реализации, гибкость (`eval`, изменение кода на лету). - **Минусы:** скорость в десятки раз ниже машинного кода, ошибки обнаруживаются только при выполнении строки. ## Байткод и виртуальные машины Промежуточный путь — компилировать в **байткод**, компактные инструкции для виртуальной машины, и исполнять его интерпретатором ВМ. Так устроены [CPython](https://llmdocs.ru/wiki/cpython.md), Ruby (YARV), Lua, JVM и .NET. В CPython компиляция в байткод происходит незаметно при импорте, результат кэшируется в файлах `.pyc`:[4] ```python import dis dis.dis(lambda x: x + 1) # RESUME 0 # LOAD_FAST 0 (x) # LOAD_CONST 1 (1) # BINARY_OP 0 (+) # RETURN_VALUE ``` Поэтому утверждение «Python — интерпретируемый язык» верно лишь отчасти: это свойство реализации, а не языка. Тот же Python исполняют PyPy (с JIT), а [WebAssembly](https://llmdocs.ru/wiki/webassembly.md) — переносимый байткод, который браузер компилирует в машинный код. ## JIT-компиляция **JIT** (*just-in-time*) — компиляция во время выполнения. ВМ начинает с интерпретации, собирает профиль (какие функции горячие, какие типы реально приходят) и компилирует частые участки в машинный код с оптимизациями под фактическое поведение. Если предположение нарушилось (в функцию пришла строка вместо числа), выполняется *деоптимизация* — возврат в интерпретатор. - **JVM HotSpot** и **.NET** — многоуровневая JIT-компиляция, сделавшая Java быстрой. - **V8** (Chrome, [Node.js](https://llmdocs.ru/wiki/nodejs.md)) — интерпретатор Ignition и несколько уровней JIT, включая Maglev и TurboFan; благодаря им [JavaScript](https://llmdocs.ru/wiki/javascript.md) стал быстрым.[6] - **PyPy** и **LuaJIT** — трассирующие JIT; в CPython 3.13 появился экспериментальный JIT (PEP 744).[5] Цена JIT — время «прогрева», расход памяти и сложность реализации; поэтому для быстрого старта (serverless, CLI) иногда используют AOT-варианты: GraalVM Native Image, .NET Native AOT. ## Родственные понятия - **Транспилятор** — компилятор из одного языка высокого уровня в другой: [TypeScript](https://llmdocs.ru/wiki/typescript.md) → JavaScript, Babel, Cython (Python → C). - **Кросс-компиляция** — сборка под другую платформу (`GOOS=linux GOARCH=arm64 go build`). - **Ассемблер** и **компоновщик** (linker) — завершающие этапы получения бинарника. ## Сравнение | Подход | Старт | Пиковая скорость | Переносимость | Примеры | |---|---|---|---|---| | AOT | быстрый | высокая | сборка под каждую платформу | C, Rust, Go | | Интерпретатор AST | быстрый | низкая | высокая | Bash, ранний Ruby | | Байткод + ВМ | средний | средняя | высокая | CPython, Lua | | Байткод + JIT | медленный прогрев | высокая | высокая | Java, C#, JavaScript | ## См. также - [Python](https://llmdocs.ru/wiki/python.md) - [Сборка мусора vs ручное управление памятью](https://llmdocs.ru/wiki/gc-vs-manual-memory.md) - [WebAssembly](https://llmdocs.ru/wiki/webassembly.md) - [Алгоритм и O-нотация](https://llmdocs.ru/wiki/big-o.md) ## Источники 1. [Aho, Lam, Sethi, Ullman — Compilers: Principles, Techniques, and Tools (2nd ed.)](https://suif.stanford.edu/dragonbook/) 2. [Robert Nystrom — Crafting Interpreters](https://craftinginterpreters.com/) 3. [LLVM Project — documentation](https://llvm.org/docs/) 4. [Python — dis: Disassembler for Python bytecode](https://docs.python.org/3/library/dis.html) 5. [PEP 744 — JIT Compilation](https://peps.python.org/pep-0744/) 6. [V8 — Maglev, V8's fastest optimizing JIT](https://v8.dev/blog/maglev) 7. [Go — Command compile](https://pkg.go.dev/cmd/compile) --- # Конкурентность и параллелизм > Конкурентность — структура программы из нескольких одновременно идущих задач; параллелизм — их физически одновременное выполнение на нескольких ядрах. Разные понятия с разными инструментами. Источник: https://llmdocs.ru/wiki/concurrency-parallelism/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Конкурентность**: работа с несколькими задачами, чередующимися во времени - **Параллелизм**: одновременное выполнение на нескольких ядрах или машинах - **Механизмы**: процессы, потоки, корутины (async/await), зелёные потоки, акторы - **Задачи с ожиданием ввода-вывода**: асинхронность, потоки - **Вычислительные задачи**: процессы, потоки без глобальной блокировки, GPU - **Ограничение ускорения**: закон Амдала (1967) - **Проблемы**: гонки данных, взаимоблокировки, голодание **Конкурентность** (англ. *concurrency*) — свойство программы состоять из нескольких независимых задач, выполнение которых перекрывается во времени: пока одна ждёт ответа сети, другая обрабатывает данные. **Параллелизм** (*parallelism*) — физически одновременное выполнение вычислений на нескольких ядрах процессора, нескольких машинах или GPU. Роб Пайк сформулировал разницу так: конкурентность — это *работа* со многими вещами сразу, параллелизм — *выполнение* многих вещей сразу.[1] Конкурентная программа может работать на одном ядре, чередуя задачи; параллельная обязательно использует несколько вычислителей. Повар, который ставит воду и, пока она закипает, режет овощи, работает конкурентно; два повара на одной кухне — параллельно. ## Зачем это нужно С середины 2000-х тактовая частота процессоров почти перестала расти, а количество ядер — нет. Герб Саттер назвал это концом «бесплатного обеда»: программы перестали ускоряться сами собой с каждым новым поколением процессоров, и для использования всех ядер их приходится писать параллельными.[2] Одновременно серверные приложения обслуживают тысячи соединений, большую часть времени ожидающих сети или диска, — это задача конкурентности. ## Два класса задач | | Ограничены вводом-выводом (*I/O-bound*) | Ограничены процессором (*CPU-bound*) | |---|---|---| | Пример | веб-сервер, парсер сайтов, вызовы API, запросы к БД | обработка изображений, численные расчёты, сжатие, обучение моделей | | Узкое место | ожидание сети и диска | вычисления | | Что помогает | конкурентность: async/await, потоки | параллелизм: процессы, потоки на разных ядрах, векторизация, GPU | ## Механизмы - **Процессы** — изолированная память, связь через каналы, сокеты или общую память. Надёжно, но дороже по ресурсам. - **Потоки** (*threads*) — общая память внутри процесса; управляет ими операционная система. Дешевле процессов, но общий доступ к данным требует синхронизации. - **Корутины и async/await** — задачи сами уступают управление в точках ожидания, а цикл событий переключается между ними в одном потоке. Тысячи одновременных соединений почти без накладных расходов — так работают [asyncio](https://llmdocs.ru/wiki/asyncio.md) в Python, JavaScript и асинхронный Rust. - **Зелёные потоки** — лёгкие потоки, которыми управляет среда выполнения языка: [горутины](https://llmdocs.ru/wiki/goroutines-channels.md) в [Go](https://llmdocs.ru/wiki/go.md), виртуальные потоки в Java. Совмещают простоту обычного кода с масштабом асинхронности. - **Акторы и передача сообщений** — задачи не делят память, а обмениваются сообщениями (Erlang, Akka). Принцип Go: «не общайтесь через общую память — делитесь памятью через общение».[6] ## Пример в Python ```python import asyncio, httpx from concurrent.futures import ProcessPoolExecutor # I/O-bound: 100 запросов конкурентно в одном потоке async def fetch_all(urls): async with httpx.AsyncClient() as client: return await asyncio.gather(*(client.get(u) for u in urls)) # CPU-bound: вычисления параллельно на всех ядрах def heavy(n: int) -> int: return sum(i * i for i in range(n)) if __name__ == "__main__": with ProcessPoolExecutor() as pool: results = list(pool.map(heavy, [10**7] * 8)) ``` В CPython глобальная блокировка интерпретатора (GIL) не даёт потокам выполнять Python-код параллельно, поэтому для вычислений используют процессы.[3] PEP 703 сделал GIL необязательным: начиная с Python 3.13 существует экспериментальная сборка без GIL, а в 3.14 она получила официальную поддержку (см. [GIL и free-threading (PEP 703)](https://llmdocs.ru/wiki/gil-free-threading.md)).[4] ## Проблемы - **Состояние гонки.** Результат зависит от того, в каком порядке потоки обратились к общим данным: два потока одновременно читают счётчик, прибавляют единицу и записывают — одно увеличение теряется (см. [Состояние гонки и блокировки](https://llmdocs.ru/wiki/race-conditions-locks.md)). - **Взаимоблокировка** (*deadlock*). Два потока ждут блокировки, захваченные друг другом, и стоят вечно. - **Голодание и инверсия приоритетов.** Задача бесконечно не получает ресурс. - **Недетерминированность.** Ошибки проявляются редко и не воспроизводятся в отладчике. Средства защиты — мьютексы, атомарные операции, неизменяемые данные, очереди и каналы вместо общей памяти. [Rust](https://llmdocs.ru/wiki/rust.md) проверяет отсутствие гонок данных на этапе компиляции с помощью системы владения и типажей `Send` и `Sync`.[5] ## Закон Амдала Ускорение от параллелизма ограничено долей программы, которая выполняется последовательно. Если 10% работы нельзя распараллелить, то даже на бесконечном числе ядер программа ускорится не больше чем в 10 раз. Отсюда практический вывод: прежде чем добавлять ядра, найдите и сократите последовательную часть — блокировки, общий ресурс, однопоточный этап. ## Параллелизм за пределами одной машины На уровне систем те же идеи масштабируются: очереди задач и пулы обработчиков, горизонтальное масштабирование сервисов в [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md), распределённые вычисления. Там к гонкам добавляются сетевые задержки и частичные отказы — это предмет [распределённых систем](https://llmdocs.ru/wiki/distributed-systems.md). ## См. также - [Состояние гонки и блокировки](https://llmdocs.ru/wiki/race-conditions-locks.md) - [asyncio](https://llmdocs.ru/wiki/asyncio.md) - [Горутины и каналы](https://llmdocs.ru/wiki/goroutines-channels.md) - [GIL и free-threading (PEP 703)](https://llmdocs.ru/wiki/gil-free-threading.md) - [Распределённые системы](https://llmdocs.ru/wiki/distributed-systems.md) ## Источники 1. [Rob Pike — Concurrency is not Parallelism (2012)](https://go.dev/blog/waza-talk) 2. [Herb Sutter — The Free Lunch Is Over (2005)](http://www.gotw.ca/publications/concurrency-ddj.htm) 3. [Python — concurrent.futures](https://docs.python.org/3/library/concurrent.futures.html) 4. [PEP 703 — Making the Global Interpreter Lock Optional in CPython](https://peps.python.org/pep-0703/) 5. [The Rust Programming Language — Fearless Concurrency](https://doc.rust-lang.org/book/ch16-00-concurrency.html) 6. [Go — Effective Go: Concurrency](https://go.dev/doc/effective_go#concurrency) --- # Структуры данных > Способы организации данных в памяти — массивы, списки, стеки, очереди, хеш-таблицы, деревья, кучи и графы — определяющие, какие операции выполняются быстро. Источник: https://llmdocs.ru/wiki/data-structures/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Определение**: способ хранения и организации данных для эффективного доступа и изменения - **Линейные**: массив, связный список, стек, очередь, дек - **Ассоциативные**: хеш-таблица, множество, словарь - **Иерархические**: деревья, кучи, префиксные деревья - **Сетевые**: графы - **Ключевая книга**: Никлаус Вирт «Алгоритмы + структуры данных = программы» (1976) **Структура данных** — способ организации и хранения данных в памяти компьютера, определяющий, какие операции с ними выполняются быстро, а какие медленно. Один и тот же набор чисел можно хранить в массиве, связном списке, хеш-таблице или дереве, и от этого выбора зависит, займёт поиск элемента наносекунды или секунды. Никлаус Вирт выразил эту связь названием книги «Алгоритмы + структуры данных = программы» (1976). Различают **абстрактный тип данных** — что структура умеет (например, «очередь: добавить в конец, взять из начала») — и его **реализацию** — как это устроено в памяти (кольцевой буфер или связный список). Скорость операций описывают с помощью [O-нотации](https://llmdocs.ru/wiki/big-o.md). ## Основные структуры | Структура | Доступ по индексу | Поиск | Вставка / удаление | Особенности | |---|---|---|---|---| | Массив (динамический) | O(1) | O(n) | O(n), в конец — O(1) амортизированно | непрерывная память, дружит с кэшем процессора | | Связный список | O(n) | O(n) | O(1) при известной позиции | нет перераспределения памяти, но медленный обход | | Стек | — | — | O(1) на вершине | последним вошёл — первым вышел (LIFO) | | Очередь, дек | — | — | O(1) с концов | первым вошёл — первым вышел (FIFO) | | [Хеш-таблица](https://llmdocs.ru/wiki/hash-table.md) | — | O(1) в среднем | O(1) в среднем | нет порядка, нужна хорошая хеш-функция | | Сбалансированное дерево поиска | — | O(log n) | O(log n) | хранит ключи упорядоченно, диапазонные запросы | | Куча (двоичная) | — | минимум за O(1) | O(log n) | очередь с приоритетом | | Граф | — | зависит от алгоритма | — | связи «многие ко многим» | ### Массив Элементы лежат в памяти подряд, поэтому адрес любого вычисляется по индексу мгновенно, а последовательный проход очень быстр благодаря кэшу процессора. **Динамический массив** (`list` в [Python](https://llmdocs.ru/wiki/python.md), `Vec` в [Rust](https://llmdocs.ru/wiki/rust.md), срез в [Go](https://llmdocs.ru/wiki/go.md)) при переполнении выделяет память с запасом и копирует элементы, поэтому добавление в конец в среднем стоит O(1). Вставка в середину требует сдвига всех последующих элементов. ### Связный список Каждый элемент хранит значение и ссылку на следующий (в двусвязном — и на предыдущий). Вставка и удаление в известном месте дешевы, но доступ к *i*-му элементу требует прохода от начала, а разбросанные по памяти узлы плохо используют кэш. На практике связные списки нужны реже, чем кажется по учебникам; их основа — в реализации очередей, LRU-кэшей и аллокаторов. ### Стек и очередь **Стек** — как стопка тарелок: кладём и берём сверху. Он используется для вызовов функций (стек вызовов), отмены действий, разбора скобок и обхода в глубину. **Очередь** — как очередь в магазине: обработка задач в порядке поступления, обход графа в ширину, буферы сообщений. **Дек** (*deque*) позволяет добавлять и забирать с обоих концов. ### Хеш-таблица Хеш-функция превращает ключ в номер ячейки, и поиск, вставка и удаление в среднем выполняются за O(1). На хеш-таблицах построены словари и множества почти во всех языках, кэши, индексы и дедупликация. Подробнее — в статье [Хеш-таблица](https://llmdocs.ru/wiki/hash-table.md). ### Деревья и кучи **Деревья поиска** (красно-чёрные, AVL, [B-деревья](https://llmdocs.ru/wiki/b-tree.md)) хранят ключи упорядоченно и находят, вставляют и удаляют за O(log n), поддерживая запросы по диапазону; B-деревья лежат в основе [индексов баз данных](https://llmdocs.ru/wiki/database-index.md). **Куча** — дерево, где родитель не больше потомков; она быстро выдаёт минимальный элемент и используется в очередях с приоритетом, планировщиках и алгоритме Дейкстры. **Префиксное дерево** (*trie*) хранит строки по символам — для автодополнения и маршрутизации. Подробнее — в статье [Дерево и граф](https://llmdocs.ru/wiki/trees-graphs.md). ### Графы Граф — множество вершин и рёбер между ними: дороги между городами, зависимости пакетов, связи в соцсети, ссылки между страницами. Хранится списками смежности (экономно для редких связей) или матрицей смежности (быстрая проверка ребра). ## Структуры в Python ```python from collections import deque, Counter, defaultdict import heapq stack = []; stack.append(1); stack.pop() # список как стек queue = deque(); queue.append("a"); queue.popleft() # очередь O(1) с обоих концов index = {"alice": 1, "bob": 2} # dict — хеш-таблица unique = set(["a", "b", "a"]) # множество counts = Counter("mississippi") # подсчёт элементов graph = defaultdict(list); graph["a"].append("b") # список смежности tasks = [] heapq.heappush(tasks, (2, "написать тесты")) heapq.heappush(tasks, (1, "починить прод")) print(heapq.heappop(tasks)) # (1, 'починить прод') — минимальный приоритет ``` Модули `collections` и `heapq` стандартной библиотеки покрывают большинство повседневных задач;[3][4] сложность операций со встроенными типами сведена в таблицу на Python Wiki.[5] В других языках есть аналоги — например, модуль `std::collections` в Rust.[6] ## Как выбирать 1. Определите самые частые операции: поиск по ключу, доступ по порядку, добавление в конец, извлечение минимума, диапазонные запросы. 2. Подберите структуру, где именно они дешевы: частая проверка «есть ли элемент» — множество, а не список; извлечение самого срочного — куча; упорядоченный обход — дерево или отсортированный массив. 3. Учитывайте память и кэш: для небольших объёмов простой массив часто быстрее «правильной» структуры. 4. Используйте готовые реализации стандартной библиотеки — они отлажены и оптимизированы. Систематическое изложение с доказательствами — в учебнике Кормена и соавторов.[1] Подробно о встроенных структурах Python — в официальном руководстве.[2] ## См. также - [Алгоритм и O-нотация](https://llmdocs.ru/wiki/big-o.md) - [Хеш-таблица](https://llmdocs.ru/wiki/hash-table.md) - [Дерево и граф](https://llmdocs.ru/wiki/trees-graphs.md) - [B-дерево](https://llmdocs.ru/wiki/b-tree.md) - [Сортировка](https://llmdocs.ru/wiki/sorting.md) ## Источники 1. [T. Cormen et al. — Introduction to Algorithms, 4th ed. (MIT Press)](https://mitpress.mit.edu/9780262046305/introduction-to-algorithms/) 2. [Python Tutorial — Data Structures](https://docs.python.org/3/tutorial/datastructures.html) 3. [Python — collections module](https://docs.python.org/3/library/collections.html) 4. [Python — heapq module](https://docs.python.org/3/library/heapq.html) 5. [Python Wiki — TimeComplexity](https://wiki.python.org/moin/TimeComplexity) 6. [Rust — std::collections](https://doc.rust-lang.org/std/collections/index.html) --- # Распределённые системы > Системы из нескольких компьютеров, взаимодействующих по сети и выглядящих для пользователя как одно целое; ключевые проблемы — частичные сбои, задержки, время, консенсус и репликация. Источник: https://llmdocs.ru/wiki/distributed-systems/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Определение**: несколько узлов, общающихся сообщениями, без общей памяти и общих часов - **Ключевые проблемы**: частичные сбои, ненадёжная сеть, отсутствие глобального времени - **Консенсус**: Paxos (1989), Raft (2014) - **Основные работы**: Лэмпорт — «Time, Clocks…» (1978); FLP (1985) - **Книги**: «Designing Data-Intensive Applications» (Клеппман) - **Примеры**: Kubernetes, etcd, Kafka, Cassandra, Spanner **Распределённая система** — набор независимых компьютеров (узлов), которые общаются только сообщениями по сети и вместе решают одну задачу так, что для пользователя они выглядят как единое целое. Почти любой современный сервис распределён: веб-приложение с базой данных и кэшем, кластер [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md), реплицированная база, очередь сообщений, [CDN](https://llmdocs.ru/wiki/cdn.md). Распределение нужно ради масштабирования, отказоустойчивости и близости к пользователям, но приносит фундаментальные трудности, которых нет в программе на одном компьютере. ## Почему это трудно В одном процессе вызов функции либо выполняется, либо программа падает целиком. В распределённой системе возможны **частичные сбои**: один узел работает, другой завис, сеть между ними теряет пакеты. Отправив запрос и не получив ответа, узел не может отличить три ситуации — запрос потерялся, получатель упал, или ответ потерялся по дороге, а действие уже выполнено. Известный список **заблуждений распределённых вычислений** (Питер Дойч и коллеги из Sun, 1990-е) перечисляет ложные предположения новичков:[5] 1. сеть надёжна; 2. задержка равна нулю; 3. пропускная способность бесконечна; 4. сеть безопасна; 5. топология не меняется; 6. администратор один; 7. передача данных бесплатна; 8. сеть однородна. ## Время и порядок У узлов нет общих часов: системное время расходится, синхронизация по NTP даёт точность в миллисекунды, а часы могут прыгать назад. Поэтому нельзя надёжно упорядочить события по меткам времени с разных машин. Лесли Лэмпорт в работе 1978 года предложил **логические часы** — счётчики, отражающие причинно-следственный порядок «произошло раньше» без физического времени.[1] Развитие идеи — векторные часы и гибридные логические часы. Google Spanner решает задачу иначе — атомными часами и GPS с явной оценкой погрешности (TrueTime). ## Репликация Хранение копий данных на нескольких узлах обеспечивает отказоустойчивость и масштабирование чтения (см. [Репликация баз данных](https://llmdocs.ru/wiki/replication.md)): | Схема | Как работает | Компромисс | |---|---|---| | **Лидер — последователи** | записи идут на лидера, реплики копируют | просто; при отказе лидера нужно переключение | | **Несколько лидеров** | запись в любом дата-центре | конфликты одновременных изменений | | **Без лидера** (Dynamo-стиль) | запись и чтение кворумом из N узлов | гибко; согласованность в конечном счёте | Синхронная репликация гарантирует, что данные не потеряются, но медленнее и зависит от доступности реплик; асинхронная быстрее, но при отказе лидера последние записи могут пропасть. Выбор между согласованностью и доступностью при сбоях сети формализует [CAP-теорема](https://llmdocs.ru/wiki/cap-theorem.md). Для данных, которые не помещаются на один узел, применяют [шардирование](https://llmdocs.ru/wiki/sharding.md). ## Консенсус Многие задачи — выбор лидера, распределённые блокировки, атомарная фиксация, хранение конфигурации — сводятся к **консенсусу**: несколько узлов должны договориться об одном значении, даже если часть из них отказала. Теорема FLP (1985) доказывает, что в полностью асинхронной сети детерминированный консенсус невозможен даже при одном сбое;[3] практические алгоритмы обходят это с помощью тайм-аутов и гарантируют безопасность всегда, а продвижение — когда сеть ведёт себя разумно. - **Paxos** (Лэмпорт) — классический алгоритм, известный сложностью понимания. - **Raft** (2014) — создан специально понятным: выбор лидера по срокам (terms), репликация журнала, большинство голосов.[2] Используется в etcd (хранилище [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md)), Consul, CockroachDB, Kafka (KRaft). Кластер из 2f + 1 узлов переживает отказ f узлов: из трёх — одного, из пяти — двух. Поэтому кластеры консенсуса имеют нечётный размер. ## Надёжная работа с сетью - **Тайм-ауты** на каждый сетевой вызов — без них один зависший сервис останавливает всю цепочку. - **Повторы с экспоненциальной задержкой и случайным разбросом** (jitter), чтобы не создать лавину запросов. - **Идемпотентность** — повторный запрос не должен списать деньги дважды; используют ключи идемпотентности. - **Автоматический выключатель** (circuit breaker) — перестать вызывать сервис, который явно не работает. - **Асинхронный обмен** через очереди и журналы событий (Kafka, RabbitMQ) — развязывает сервисы по времени. - **Семантика доставки**: «не более одного раза», «хотя бы один раз», а «ровно один раз» на практике достигается сочетанием повторов и идемпотентной обработки. Многие из этих механизмов вынесены в инфраструктуру — [Service mesh](https://llmdocs.ru/wiki/service-mesh.md), балансировщики и клиентские библиотеки. ## Наблюдаемость и тестирование Отладка распределённой системы требует [распределённой трассировки](https://llmdocs.ru/wiki/opentelemetry.md) и сквозных идентификаторов запросов. Для проверки поведения при сбоях используют хаос-инжиниринг (намеренное отключение узлов и внесение задержек), тесты в духе Jepsen и формальную верификацию алгоритмов — например, на языке TLA+, который разработал Лэмпорт и применяют AWS и другие компании. ## Литература Основное современное введение — книга Мартина Клеппмана «Designing Data-Intensive Applications» («Высоконагруженные приложения»).[4] Классические работы — статьи Лэмпорта, работа FLP и статья о Raft вместе с его интерактивной визуализацией.[6] ## См. также - [CAP-теорема](https://llmdocs.ru/wiki/cap-theorem.md) - [Репликация баз данных](https://llmdocs.ru/wiki/replication.md) - [Конкурентность и параллелизм](https://llmdocs.ru/wiki/concurrency-parallelism.md) - [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) ## Источники 1. [Lamport — Time, Clocks, and the Ordering of Events in a Distributed System (1978)](https://lamport.azurewebsites.net/pubs/time-clocks.pdf) 2. [Ongaro, Ousterhout — In Search of an Understandable Consensus Algorithm (Raft, 2014)](https://raft.github.io/raft.pdf) 3. [Fischer, Lynch, Paterson — Impossibility of Distributed Consensus with One Faulty Process (1985)](https://groups.csail.mit.edu/tds/papers/Lynch/jacm85.pdf) 4. [Kleppmann — Designing Data-Intensive Applications (O'Reilly)](https://dataintensive.net/) 5. [Deutsch et al. — Fallacies of Distributed Computing](https://en.wikipedia.org/wiki/Fallacies_of_distributed_computing) 6. [Raft — визуализация и реализации](https://raft.github.io/) --- # Сборка мусора > Автоматическое освобождение памяти, которая больше недоступна программе; основные подходы — подсчёт ссылок и трассирующие сборщики (mark-sweep, копирующие, поколенческие). Источник: https://llmdocs.ru/wiki/garbage-collection/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Появление**: Lisp, Джон Маккарти (1959) - **Подходы**: подсчёт ссылок, трассировка (mark-sweep, mark-compact, копирование) - **Улучшения**: поколения, инкрементальная и конкурентная сборка - **Языки с GC**: Java, C#, Go, Python, JavaScript, Ruby, Haskell - **Без GC**: C, C++ (RAII), Rust (владение) - **Метрики**: паузы, пропускная способность, расход памяти **Сборка мусора** (англ. *garbage collection*, GC) — автоматическое управление памятью, при котором среда выполнения сама находит объекты, недоступные программе, и освобождает занятую ими память. Программисту не нужно вызывать `free` или `delete`, а значит исчезают целые классы ошибок: утечки из-за забытого освобождения, повторное освобождение и обращение к уже освобождённой памяти (use-after-free). Платой становятся дополнительный расход процессора и памяти и паузы в работе программы. Сравнение с ручным управлением и моделью владения Rust — в статье [Сборка мусора vs ручное управление памятью](https://llmdocs.ru/wiki/gc-vs-manual-memory.md). ## История Сборку мусора изобрёл Джон Маккарти в 1959 году для языка Lisp: список, ставший ненужным, должен был возвращаться в свободную память автоматически.[2] Долгое время GC считался роскошью для академических языков, но с выходом Java (1995) стал нормой в промышленной разработке. Сегодня сборщик мусора есть в Java, C#, [Go](https://llmdocs.ru/wiki/go.md), Python, [JavaScript](https://llmdocs.ru/wiki/javascript.md), Ruby, Kotlin, Swift (через подсчёт ссылок) и большинстве скриптовых языков. ## Что считается мусором Объект «жив», если до него можно добраться по ссылкам от **корней** — глобальных переменных, локальных переменных в стеках потоков, регистров. Всё остальное — мусор, даже если на него ещё ссылаются другие недоступные объекты. Сборщик не знает, понадобится ли объект в будущем, — он консервативно сохраняет всё достижимое. Поэтому утечки памяти возможны и с GC: например, когда объекты бесконечно накапливаются в глобальном кэше или списке подписчиков. ## Подсчёт ссылок У каждого объекта есть счётчик ссылок на него; когда счётчик падает до нуля, объект немедленно освобождается. - **Плюсы**: память освобождается сразу и предсказуемо, нет длинных пауз. - **Минусы**: накладные расходы на каждое присваивание (особенно атомарные операции в многопоточной среде) и неспособность собрать **циклы** — два объекта, ссылающиеся друг на друга, никогда не получат нулевой счётчик. Так работают CPython (с дополнительным сборщиком циклов, модуль `gc`),[4] Swift и Objective-C (ARC), `shared_ptr` в C++ и `Rc`/`Arc` в Rust. В Swift и Rust циклы разрывают слабыми ссылками (`weak`). ## Трассирующие сборщики Трассирующий сборщик периодически обходит граф объектов от корней:[1] | Алгоритм | Как работает | Особенности | |---|---|---| | **Mark-sweep** | пометить достижимые, затем пройти по куче и освободить непомеченные | память фрагментируется | | **Mark-compact** | после пометки сдвинуть живые объекты подряд | нет фрагментации, но дорогое перемещение | | **Копирующий** | копировать живые объекты в другую половину памяти | быстрое выделение, время зависит только от живых объектов; нужна вдвое большая память | ### Поколения Эмпирическая **гипотеза поколений**: большинство объектов умирает молодыми (временные строки, промежуточные результаты). Поэтому кучу делят на **молодое** и **старое** поколения. Молодое собирается часто и быстро копирующим сборщиком, а пережившие несколько сборок объекты переводятся в старое, которое собирается редко. На этом построены сборщики JVM, .NET и V8.[6] ### Паузы Простой сборщик останавливает программу на время работы (**stop-the-world**). Чтобы сократить паузы, применяют: - **инкрементальную** сборку — работа делится на маленькие порции; - **конкурентную** — сборщик работает в отдельных потоках параллельно с программой, используя барьеры записи для отслеживания изменений; - **параллельную** — несколько потоков сборщика во время паузы. ## Сборщики в популярных языках - **Java (HotSpot)**: G1 — по умолчанию, баланс пауз и пропускной способности; **ZGC** и Shenandoah — паузы в доли миллисекунды даже на кучах в терабайты; Parallel GC — максимальная пропускная способность для пакетных задач.[5] - **Go**: конкурентный трёхцветный mark-sweep без поколений и без перемещения объектов, оптимизирован на короткие паузы. Настраивается двумя параметрами: `GOGC` (насколько куча может вырасти между сборками, по умолчанию 100%) и `GOMEMLIMIT` (мягкий предел памяти).[3] - **Python**: подсчёт ссылок плюс поколенческий сборщик циклов. - **JavaScript (V8)**: поколенческий сборщик Orinoco с параллельной и конкурентной работой. ## Практика - Создавайте меньше временных объектов в горячих участках кода: переиспользование буферов (`sync.Pool` в Go), предварительное выделение ёмкости коллекций. - Следите за метриками сборщика — частотой и длительностью пауз, размером кучи — и профилируйте память (`pprof` в Go, `tracemalloc` в Python, JFR в Java). - В контейнерах задавайте пределы памяти, понятные среде выполнения (`GOMEMLIMIT`, `-XX:MaxRAMPercentage`), иначе процесс может быть убит по OOM раньше, чем сборщик сработает. - Не вызывайте сборку вручную (`System.gc()`, `gc.collect()`) без измерений — обычно это только мешает эвристикам. ## См. также - [Сборка мусора vs ручное управление памятью](https://llmdocs.ru/wiki/gc-vs-manual-memory.md) - [Структуры данных](https://llmdocs.ru/wiki/data-structures.md) - [Go (язык)](https://llmdocs.ru/wiki/go.md) - [CPython](https://llmdocs.ru/wiki/cpython.md) ## Источники 1. [Jones, Hosking, Moss — The Garbage Collection Handbook (2nd ed., 2023)](https://gchandbook.org/) 2. [McCarthy — Recursive Functions of Symbolic Expressions (1960)](https://dl.acm.org/doi/10.1145/367177.367199) 3. [Go — A Guide to the Go Garbage Collector](https://go.dev/doc/gc-guide) 4. [Python Docs — gc module](https://docs.python.org/3/library/gc.html) 5. [Oracle — HotSpot Virtual Machine Garbage Collection Tuning Guide](https://docs.oracle.com/en/java/javase/21/gctuning/) 6. [V8 Blog — Trash talk: the Orinoco garbage collector](https://v8.dev/blog/trash-talk) --- # Хеш-таблица > Структура данных «ключ → значение», которая с помощью хеш-функции находит ячейку по ключу в среднем за O(1); основа словарей и множеств почти во всех языках. Источник: https://llmdocs.ru/wiki/hash-table/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: ассоциативный массив - **Поиск, вставка, удаление**: O(1) в среднем, O(n) в худшем случае - **Память**: O(n) - **Разрешение коллизий**: цепочки, открытая адресация - **Ключевой параметр**: коэффициент заполнения (load factor) - **Реализации**: dict (Python), map (Go), HashMap (Rust, Java), Object/Map (JS) **Хеш-таблица** (англ. *hash table*, *hash map*) — [структура данных](https://llmdocs.ru/wiki/data-structures.md), хранящая пары «ключ → значение» и позволяющая находить, добавлять и удалять элемент по ключу в среднем за постоянное время, O(1) (см. [Алгоритм и O-нотация](https://llmdocs.ru/wiki/big-o.md)). Для этого ключ превращается [хеш-функцией](https://llmdocs.ru/wiki/hash-function.md) в число, а число — в номер ячейки массива.[1] На хеш-таблицах построены `dict` и `set` в [Python](https://llmdocs.ru/wiki/python.md), `map` в [Go](https://llmdocs.ru/wiki/go.md), `HashMap` в Rust и Java, индексы в базах данных и кэши. ## Принцип работы Таблица — это массив из *m* ячеек (корзин, *buckets*). Чтобы положить пару `(k, v)`: 1. вычислить хеш `h = hash(k)` — большое целое число; 2. получить индекс `i = h mod m` (или `h & (m − 1)`, если *m* — степень двойки); 3. записать пару в ячейку *i*. Поиск повторяет те же шаги и сравнивает ключ в найденной ячейке с искомым. Хеш-функция должна быть детерминированной (одинаковые ключи → одинаковый хеш) и равномерно распределять ключи по ячейкам. Ключи должны быть неизменяемыми: если ключ поменяется после вставки, его хеш изменится и элемент «потеряется» — поэтому в Python нельзя использовать список как ключ словаря. ## Коллизии Разные ключи неизбежно попадают в одну ячейку — это **коллизия**. Два основных способа их разрешать: - **Метод цепочек** (separate chaining) — в каждой ячейке хранится список (или дерево) всех элементов с этим индексом. Просто и устойчиво к высокому заполнению; так устроен `HashMap` в Java, который превращает длинную цепочку в красно-чёрное дерево. - **Открытая адресация** (open addressing) — все элементы лежат прямо в массиве; при занятой ячейке пробуется следующая по правилу: линейное пробирование (*i*+1, *i*+2…), квадратичное или двойное хеширование. Удаление требует пометок-«надгробий» (tombstones). Метод компактнее и дружелюбнее к кэшу процессора, поэтому его выбирают CPython, Rust и Go. Современные быстрые реализации — **Swiss Table** (Google Abseil, `hashbrown` в Rust, `map` в Go с версии 1.24) — хранят рядом с ячейками короткие метаданные (7 бит хеша) и проверяют сразу 8–16 ячеек одной SIMD-инструкцией.[3][4] ## Коэффициент заполнения и рост **Коэффициент заполнения** α = n / m (число элементов на число ячеек) определяет скорость: чем он выше, тем больше коллизий. Когда α превышает порог (около 2/3 у CPython, 7/8 у Swiss Table, 0,75 у Java), таблица **перестраивается** (*rehash*): выделяется массив примерно вдвое больше, и все элементы вставляются заново. Отдельная перестройка стоит O(n), но происходит редко, поэтому **амортизированная** стоимость вставки остаётся O(1). | Операция | Среднее | Худшее | |---|---|---| | Поиск | O(1) | O(n) | | Вставка | O(1) амортизированно | O(n) | | Удаление | O(1) | O(n) | | Обход по порядку ключей | — (нужна сортировка) | O(n log n) | Худший случай наступает, если все ключи попали в одну ячейку. ## Порядок элементов Классическая хеш-таблица не гарантирует порядок обхода. Начиная с Python 3.7 словарь **сохраняет порядок вставки**: CPython хранит записи в плотном массиве, а таблица хешей содержит лишь индексы в нём — это заодно экономит память.[2] В Go порядок обхода `map` намеренно рандомизирован, чтобы код не полагался на него. Если нужен порядок по ключу или поиск диапазонов, вместо хеш-таблицы используют сбалансированные деревья или [B-дерево](https://llmdocs.ru/wiki/b-tree.md) (см. [Дерево и граф](https://llmdocs.ru/wiki/trees-graphs.md)). ## Безопасность: hash flooding Если атакующий знает хеш-функцию, он может подобрать множество ключей с одинаковым индексом и превратить O(1) в O(n) на каждую операцию — например, отправив веб-серверу запрос с тысячами специально подобранных параметров. Атаку описали в 2003 году, а в 2011-м продемонстрировали против PHP, Java, Python и Ruby.[5] Защита — хеш-функция со случайным секретным ключом, генерируемым при старте процесса: SipHash в Python, Rust и Ruby.[6] Поэтому `hash("abc")` в Python меняется между запусками (переменная `PYTHONHASHSEED`). ## Примеры ```python # Python: dict и set counts = {} for word in text.split(): counts[word] = counts.get(word, 0) + 1 seen = set() unique = [x for x in items if not (x in seen or seen.add(x))] ``` ```go // Go ages := map[string]int{"alice": 31} ages["bob"] = 25 if age, ok := ages["carol"]; !ok { fmt.Println("нет такого ключа", age) } ``` Чтобы объект своего класса мог быть ключом, у него должны быть согласованы равенство и хеш: в Python — методы `__eq__` и `__hash__`, в Rust — трейты `Eq` и `Hash`, в Java — `equals` и `hashCode`. ## Применения - словари, множества, подсчёт частот, удаление дубликатов; - [кэши](https://llmdocs.ru/wiki/cache.md) и мемоизация, в том числе LRU-кэш (хеш-таблица + двусвязный список); - индексы в СУБД (хеш-индексы в [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md)) и хранилищах «ключ — значение» вроде [Redis](https://llmdocs.ru/wiki/redis.md); - таблицы символов в [компиляторах и интерпретаторах](https://llmdocs.ru/wiki/compiler-interpreter.md); - распределённые системы — согласованное хеширование для распределения ключей по узлам. ## См. также - [Хеш-функция](https://llmdocs.ru/wiki/hash-function.md) - [Структуры данных](https://llmdocs.ru/wiki/data-structures.md) - [Дерево и граф](https://llmdocs.ru/wiki/trees-graphs.md) - [Индекс (базы данных)](https://llmdocs.ru/wiki/database-index.md) ## Источники 1. [Cormen et al. — Introduction to Algorithms, 4th ed., ch. 11 Hash Tables (MIT Press)](https://mitpress.mit.edu/9780262046305/introduction-to-algorithms/) 2. [Python — dictobject.c, notes on dict implementation](https://github.com/python/cpython/blob/main/Objects/dictobject.c) 3. [Go Blog — Faster Go maps with Swiss Tables](https://go.dev/blog/swisstable) 4. [Rust std::collections::HashMap](https://doc.rust-lang.org/std/collections/struct.HashMap.html) 5. [Crosby, Wallach — Denial of Service via Algorithmic Complexity Attacks (USENIX Security 2003)](https://www.usenix.org/legacy/events/sec03/tech/full_papers/crosby/crosby.pdf) 6. [Aumasson, Bernstein — SipHash: a fast short-input PRF](https://cr.yp.to/siphash/siphash-20120918.pdf) --- # Состояние гонки и блокировки > Ошибка, когда результат зависит от непредсказуемого порядка выполнения потоков, и средства синхронизации против неё — мьютексы, атомарные операции, каналы; а также взаимоблокировки, которые эти средства порождают. Источник: https://llmdocs.ru/wiki/race-conditions-locks/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Гонка (race condition)**: результат зависит от порядка или времени выполнения - **Гонка данных (data race)**: одновременный доступ к памяти, хотя бы один — запись, без синхронизации - **Средства синхронизации**: мьютекс, RW-блокировка, семафор, атомарные операции, каналы - **Типовые сбои**: взаимоблокировка, livelock, голодание, инверсия приоритетов - **Инструменты**: ThreadSanitizer, go test -race, Miri, Helgrind **Состояние гонки** (англ. *race condition*) — ошибка в программе, при которой результат зависит от непредсказуемого порядка или времени выполнения параллельных действий: потоков, процессов, запросов, корутин. Такие ошибки возникают в [конкурентных](https://llmdocs.ru/wiki/concurrency-parallelism.md) программах, плохо воспроизводятся («у меня работает») и могут проявиться раз в миллион запусков. Основное средство борьбы — **синхронизация**: блокировки, атомарные операции, передача сообщений.[1] ## Классический пример Два потока увеличивают общий счётчик: ```python counter = 0 def work(): global counter for _ in range(1_000_000): counter += 1 # прочитать → прибавить → записать ``` Операция `counter += 1` неатомарна: это чтение, сложение и запись. Если оба потока прочитали 41, оба запишут 42 — одно увеличение потеряно, и итог меньше 2 000 000. Даже [GIL](https://llmdocs.ru/wiki/gil-free-threading.md) в CPython не спасает: поток может быть прерван между байткод-инструкциями, а в сборках без GIL гонки проявляются ещё чаще. ## Гонка и гонка данных Различают два понятия:[4] - **Гонка данных** (*data race*) — два потока одновременно обращаются к одной ячейке памяти, хотя бы один пишет, и между обращениями нет синхронизации. В C, C++ и Go это неопределённое или некорректное поведение по модели памяти языка.[3] Безопасный Rust исключает гонки данных на этапе компиляции через систему [владения и заимствования](https://llmdocs.ru/wiki/ownership-borrowing.md). - **Логическая гонка** (*race condition*) — более общее понятие: ошибка в порядке действий даже без «сырой» гонки за память. Пример — **TOCTOU** (*time of check to time of use*): программа проверила, что файла нет, а затем создала его, но между проверкой и созданием файл успел создать кто-то другой. Ту же природу имеют двойное списание денег при параллельных запросах и «потерянное обновление» в базе данных. ## Средства синхронизации **Мьютекс** (*mutual exclusion*) — блокировка, которую в каждый момент держит не больше одного потока. Код между захватом и освобождением называется **критической секцией**. ```python import threading lock = threading.Lock() def work(): global counter for _ in range(1_000_000): with lock: # захват и гарантированное освобождение counter += 1 ``` ```go var mu sync.Mutex mu.Lock() counter++ mu.Unlock() ``` Другие примитивы: - **RW-блокировка** (`RWMutex`, `RwLock`) — много читателей или один писатель. - **Семафор** — ограничивает число одновременных владельцев, например не больше 10 соединений к API. - **Условные переменные** и события — ожидание, пока другой поток не выполнит условие. - **Атомарные операции** (`sync/atomic`, `std::sync::atomic`, compare-and-swap) — неделимые операции процессора над одним значением, без блокировки; на них строятся lock-free структуры. - **Передача сообщений** — вместо общей памяти потоки обмениваются данными через очереди или [каналы](https://llmdocs.ru/wiki/goroutines-channels.md): «не общайтесь через разделяемую память, разделяйте память через общение» (поговорка Go). ## Взаимоблокировки и другие сбои Блокировки решают гонки, но создают свои проблемы: - **Взаимоблокировка** (*deadlock*) — поток A держит блокировку X и ждёт Y, поток B держит Y и ждёт X; оба стоят вечно. Коффман и соавторы (1971) назвали четыре необходимых условия: взаимное исключение, удержание с ожиданием, отсутствие вытеснения и циклическое ожидание.[5] Самая практичная профилактика — разрушить последнее условие, **всегда захватывая блокировки в одном и том же порядке**; помогают также тайм-ауты (`lock.acquire(timeout=1)`) и `try_lock`. - **Livelock** — потоки активно уступают друг другу и не продвигаются. - **Голодание** — поток никогда не получает ресурс, потому что его опережают другие. - **Инверсия приоритетов** — высокоприоритетная задача ждёт низкоприоритетную, держащую блокировку (знаменитый сбой марсохода Mars Pathfinder в 1997 году). - **Конкуренция за блокировку** (*contention*) — если критическая секция велика, потоки выстраиваются в очередь и параллелизм пропадает. Секции должны быть короткими: не делать под блокировкой ввод-вывод и сетевые запросы. ## Гонки за пределами потоков - **Асинхронный код**: в `asyncio` нет вытеснения посреди строки, но между двумя `await` другая корутина может изменить общие данные — для этого есть `asyncio.Lock`. - **Базы данных**: параллельные транзакции порождают аномалии, от которых защищают [уровни изоляции](https://llmdocs.ru/wiki/isolation-levels.md), `SELECT … FOR UPDATE` и оптимистические блокировки с номером версии (см. [Транзакция и ACID](https://llmdocs.ru/wiki/transaction-acid.md)). - **Распределённые системы**: два экземпляра сервиса обрабатывают одну задачу; нужны идемпотентность, распределённые блокировки с аренду (lease) или очереди с гарантией доставки. - **Файловая система**: атомарное создание (`O_CREAT | O_EXCL`), запись во временный файл и `rename`. ## Как находить - **Детекторы гонок данных**: ThreadSanitizer в Clang и GCC, `go test -race` и `go run -race`,[2][6] Miri для unsafe-кода в Rust, Helgrind в Valgrind. Они находят гонки, которые реально произошли во время прогона, поэтому нужны тесты с параллельной нагрузкой. - Стресс-тесты, многократный повтор теста, искусственные задержки (`sleep`) в подозрительных местах. - Проектирование без общего изменяемого состояния: неизменяемые данные, владение одним потоком, очереди задач. ## См. также - [Конкурентность и параллелизм](https://llmdocs.ru/wiki/concurrency-parallelism.md) - [asyncio](https://llmdocs.ru/wiki/asyncio.md) - [MVCC](https://llmdocs.ru/wiki/mvcc.md) - [Распределённые системы](https://llmdocs.ru/wiki/distributed-systems.md) ## Источники 1. [Herlihy, Shavit — The Art of Multiprocessor Programming (2nd ed.)](https://www.elsevier.com/books/the-art-of-multiprocessor-programming/herlihy/978-0-12-415950-1) 2. [Go — Data Race Detector](https://go.dev/doc/articles/race_detector) 3. [The Go Memory Model](https://go.dev/ref/mem) 4. [The Rustonomicon — Data Races and Race Conditions](https://doc.rust-lang.org/nomicon/races.html) 5. [Coffman, Elphick, Shoshani — System Deadlocks (ACM Computing Surveys, 1971)](https://doi.org/10.1145/356586.356588) 6. [Clang — ThreadSanitizer](https://clang.llvm.org/docs/ThreadSanitizer.html) 7. [Python — threading: Lock objects](https://docs.python.org/3/library/threading.html#lock-objects) --- # Рекурсия > Приём, при котором функция вызывает саму себя для подзадачи меньшего размера; основа обхода деревьев, алгоритмов «разделяй и властвуй» и динамического программирования. Источник: https://llmdocs.ru/wiki/recursion/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Составные части**: базовый случай + рекурсивный шаг - **Механизм**: стек вызовов - **Риски**: переполнение стека, экспоненциальные повторные вычисления - **Лимит Python**: ~1000 уровней (sys.getrecursionlimit) - **Оптимизация**: хвостовые вызовы (Scheme, Haskell; не в Python, Java, Go) - **Связанное**: мемоизация, динамическое программирование **Рекурсия** — приём, при котором функция решает задачу, вызывая саму себя для одной или нескольких меньших копий той же задачи. Многие структуры по своей природе рекурсивны: каталог содержит каталоги, дерево — поддеревья, выражение — подвыражения, JSON-объект — вложенные объекты. Для них рекурсивное решение получается коротким и прямо повторяет определение данных. Рекурсия лежит в основе алгоритмов «разделяй и властвуй», таких как [сортировка слиянием](https://llmdocs.ru/wiki/sorting.md), обхода [деревьев и графов](https://llmdocs.ru/wiki/trees-graphs.md) и динамического программирования. ## Устройство Корректная рекурсивная функция состоит из двух частей: 1. **Базовый случай** — простейший вход, ответ на который известен без рекурсии. 2. **Рекурсивный шаг** — сведение задачи к меньшим подзадачам того же вида. ```python def factorial(n: int) -> int: if n <= 1: # базовый случай return 1 return n * factorial(n - 1) # шаг: задача размера n-1 ``` Каждый шаг должен приближаться к базовому случаю, иначе рекурсия будет бесконечной. Доказательство корректности рекурсивного алгоритма — по сути, математическая индукция. ## Стек вызовов Каждый вызов функции получает **кадр стека** с локальными переменными и адресом возврата. При рекурсии кадры накапливаются: `factorial(1000)` держит в памяти тысячу кадров одновременно. Размер стека ограничен, и слишком глубокая рекурсия приводит к **переполнению стека**: в Python — `RecursionError` (лимит по умолчанию около 1000 уровней),[2] в C — аварийное завершение, в Go стеки горутин растут динамически, но тоже имеют предел (по умолчанию 1 ГБ). Поэтому рекурсию по данным неограниченной глубины — длинному связному списку, вырожденному дереву, пользовательскому вводу — лучше переписать итеративно. ## Хвостовая рекурсия Вызов называется **хвостовым**, если это последнее действие функции и его результат сразу возвращается: ```python def factorial_acc(n, acc=1): if n <= 1: return acc return factorial_acc(n - 1, acc * n) # хвостовой вызов ``` Компилятор может заменить такой вызов переходом, не создавая новый кадр, — это **оптимизация хвостовых вызовов** (TCO). Её гарантируют Scheme и многие функциональные языки, а Haskell, OCaml, Scala (`@tailrec`) и компиляторы C/C++ на высоких уровнях оптимизации применяют её на практике.[1] Python, Java и Go её не делают: Гвидо ван Россум сознательно отказался от неё ради понятных трассировок стека.[5] Rust официально её не гарантирует. ## Ловушка повторных вычислений Наивное определение чисел Фибоначчи порождает экспоненциальное число вызовов, потому что одни и те же подзадачи решаются снова и снова: ```python def fib(n): return n if n < 2 else fib(n - 1) + fib(n - 2) # O(φⁿ) ≈ O(1.6ⁿ) ``` `fib(40)` выполняет сотни миллионов вызовов. Решение — **мемоизация**: запоминать результаты уже решённых подзадач, например в [хеш-таблице](https://llmdocs.ru/wiki/hash-table.md). ```python from functools import cache @cache def fib(n): return n if n < 2 else fib(n - 1) + fib(n - 2) # O(n) ``` Декоратор `functools.cache` делает это одной строкой.[3] Мемоизация рекурсивного решения — это **динамическое программирование «сверху вниз»**; тот же алгоритм можно записать «снизу вверх» циклом с таблицей, избавившись и от глубокой рекурсии. ## Сложность Время рекурсивного алгоритма описывают **рекуррентным соотношением**. Для сортировки слиянием T(n) = 2T(n/2) + O(n): две половины плюс линейное слияние. Основная теорема (master theorem) даёт ответ O(n log n).[4] Двоичный поиск: T(n) = T(n/2) + O(1) → O(log n). Дополнительная память рекурсии равна максимальной глубине стека — это нужно учитывать в оценке (см. [Алгоритм и O-нотация](https://llmdocs.ru/wiki/big-o.md)). ## Типичные применения - **Обход деревьев**: файловой системы, DOM, синтаксического дерева в [компиляторе](https://llmdocs.ru/wiki/compiler-interpreter.md), вложенного [JSON](https://llmdocs.ru/wiki/json.md). - **Поиск в глубину** по графу, перебор с возвратом (backtracking): судоку, расстановка ферзей, генерация перестановок. - **Разделяй и властвуй**: сортировки, быстрое умножение, построение кучи. - **Рекурсивный спуск** — разбор выражений и языков программирования. ```python from pathlib import Path def total_size(path: Path) -> int: if path.is_file(): return path.stat().st_size return sum(total_size(p) for p in path.iterdir()) ``` ## Рекурсия или цикл Любую рекурсию можно заменить циклом с явным стеком — и наоборот. Рекурсия выигрывает в ясности для древовидных структур и алгоритмов «разделяй и властвуй». Цикл предпочтителен для линейных процессов, данных неограниченной глубины и языков без оптимизации хвостовых вызовов. Хорошее правило: писать так, как естественно описывается задача, и переходить к итерации, когда глубина может стать большой. ## См. также - [Алгоритм и O-нотация](https://llmdocs.ru/wiki/big-o.md) - [Сортировка](https://llmdocs.ru/wiki/sorting.md) - [Дерево и граф](https://llmdocs.ru/wiki/trees-graphs.md) - [Структуры данных](https://llmdocs.ru/wiki/data-structures.md) ## Источники 1. [Abelson, Sussman — Structure and Interpretation of Computer Programs, 1.2](https://mitp-content-server.mit.edu/books/content/sectbyfn/books_pres_0/6515/sicp.zip/full-text/book/book-Z-H-11.html) 2. [Python Docs — sys.setrecursionlimit](https://docs.python.org/3/library/sys.html#sys.setrecursionlimit) 3. [Python Docs — functools.cache](https://docs.python.org/3/library/functools.html#functools.cache) 4. [Cormen et al. — Introduction to Algorithms, ch. 4 (Divide-and-Conquer)](https://mitpress.mit.edu/9780262046305/introduction-to-algorithms/) 5. [Guido van Rossum — Tail Recursion Elimination (2009)](https://neopythonic.blogspot.com/2009/04/tail-recursion-elimination.html) --- # Регулярные выражения > Компактный язык шаблонов для поиска, проверки и замены текста; диалекты POSIX, PCRE, RE2, встроенные модули Python, JavaScript и Go, а также ловушки производительности (ReDoS). Источник: https://llmdocs.ru/wiki/regex/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Основа**: регулярные языки (Клини, 1951–1956) - **Первые реализации**: QED и ed (Кен Томпсон, 1968) - **Диалекты**: POSIX BRE/ERE, PCRE/Perl, JavaScript, Python re, RE2 - **Движки**: обратный поиск (backtracking), автоматный (Thompson NFA/DFA) - **Риск**: ReDoS — экспоненциальное время на «плохих» шаблонах - **Инструменты**: grep, sed, ripgrep, regex101 **Регулярные выражения** (англ. *regular expressions*, regex) — компактный язык шаблонов для описания множеств строк. С их помощью ищут подстроки, проверяют формат ввода, извлекают части текста и выполняют замены. Регулярные выражения встроены почти во все языки программирования, редакторы и утилиты командной строки, от [grep](https://llmdocs.ru/wiki/grep.md) и [sed](https://llmdocs.ru/wiki/sed-awk.md) до IDE и СУБД.[1] ## История Математик Стивен Клини в 1950-х описал **регулярные языки** и нотацию для них. Кен Томпсон в 1968 году реализовал её в редакторе QED, а затем в `ed`, откуда появился `grep` (*g/re/p* — «глобально найти регулярное выражение и напечатать»). Позднее POSIX стандартизировал базовый и расширенный синтаксис, а Perl в 1990-х добавил множество расширений; библиотека PCRE сделала этот диалект стандартом де-факто. ## Основной синтаксис | Конструкция | Значение | Пример | |---|---|---| | `.` | любой символ (кроме перевода строки) | `a.c` → abc, a-c | | `[abc]`, `[a-z]`, `[^0-9]` | класс символов, диапазон, отрицание | `[А-Яа-яЁё]` | | `\d`, `\w`, `\s` | цифра, «словесный» символ, пробельный | `\d{3}` | | `*`, `+`, `?` | 0 и больше, 1 и больше, 0 или 1 | `colou?r` | | `{n}`, `{n,m}` | ровно n, от n до m повторений | `\d{2,4}` | | `^`, `$` | начало и конец строки | `^#` | | `\b` | граница слова | `\bcat\b` | | `a\|b` | альтернатива | `jpe?g\|png` | | `( )` | группа с захватом | `(\d+)-(\d+)` | | `(?:...)` | группа без захвата | | | `(?P...)`, `(?...)` | именованная группа | | | `(?=...)`, `(?!...)`, `(?<=...)` | просмотр вперёд и назад | `\d+(?= ₽)` | Квантификаторы по умолчанию **жадные** — захватывают как можно больше; `*?`, `+?` делают их ленивыми. Флаги меняют поведение: `i` — без учёта регистра, `m` — `^`/`$` для каждой строки, `s` — точка включает перевод строки, `x` — допускаются пробелы и комментарии в шаблоне. ## Примеры в языках ```python import re re.findall(r"\b\d{4}-\d{2}-\d{2}\b", "релизы 2024-05-01 и 2026-11-09") # ['2024-05-01', '2026-11-09'] m = re.search(r"(?P[\w.+-]+)@(?P[\w.-]+)", "почта: ivan@example.com") m.group("host") # 'example.com' re.sub(r"\s+", " ", "много пробелов\n тут") # 'много пробелов тут' ``` ```javascript const re = /(\d+)\s*₽/g; [..."100 ₽ и 250₽".matchAll(re)].map(m => Number(m[1])); // [100, 250] ``` ```bash grep -E '^(ERROR|WARN)' app.log rg -o 'v\d+\.\d+\.\d+' CHANGELOG.md ``` В Python шаблоны пишут «сырыми» строками `r"..."`, чтобы обратные слеши не обрабатывались дважды; часто используемые выражения компилируют один раз через `re.compile`. ## Диалекты и движки Синтаксис отличается в деталях: в POSIX BRE (`grep` без `-E`) скобки и `+` нужно экранировать, `\d` в POSIX отсутствует (вместо него `[[:digit:]]`), а просмотр назад и обратные ссылки поддерживаются не везде. Важнее различие движков:[3] - **Движки с обратным поиском** (backtracking) — Perl, PCRE, Python `re`, JavaScript, Java, .NET. Поддерживают обратные ссылки (`(\w)\1`) и просмотр, но на некоторых шаблонах работают экспоненциально долго. - **Автоматные движки** (NFA/DFA по Томпсону) — RE2, пакет `regexp` в Go, крейт `regex` в Rust, ripgrep. Гарантируют время, линейное по длине входа, зато не поддерживают обратные ссылки и просмотр.[4] ## ReDoS Шаблон с вложенными квантификаторами, например `^(a+)+$`, на строке `aaaaaaaaaaaaaaaaaaaaaaaa!` заставляет движок с обратным поиском перебрать экспоненциальное число вариантов. Если такой шаблон применяется к пользовательскому вводу, одна строка может занять процессор на минуты — это атака **ReDoS** (*regular expression denial of service*).[5] В июле 2019 года одно регулярное выражение в правилах WAF Cloudflare загрузило процессоры по всему миру и вызвало глобальный сбой на 27 минут.[6] Защита: избегать вложенных и перекрывающихся квантификаторов (`(a|a)*`, `(.*)*`), ограничивать длину входа, задавать тайм-ауты, для недоверенных данных использовать линейные движки (RE2, Go, Rust), проверять шаблоны линтерами. ## Unicode `\w` и `\d` в Python 3 по умолчанию понимают [Unicode](https://llmdocs.ru/wiki/unicode-utf8.md): `\d` совпадёт и с арабско-индийскими цифрами, поэтому для строгой проверки лучше `[0-9]` или флаг `re.ASCII`. В JavaScript для корректной работы с Unicode нужен флаг `u` (или `v`), тогда доступны классы вида `\p{L}` (любая буква) и `\p{Script=Cyrillic}`. Требования к Unicode-регулярным выражениям описывает стандарт UTS #18.[7] ## Когда не использовать Регулярные выражения не умеют разбирать вложенные структуры произвольной глубины: HTML, JSON, языки программирования требуют настоящих парсеров. Для email и URL надёжнее библиотечные валидаторы и проверка подтверждением, чем «идеальная» регулярка на сотни символов. Длинные шаблоны стоит документировать флагом `x` и покрывать тестами; для отладки удобен сайт regex101, показывающий разбор и шаги движка. [Языковые модели](https://llmdocs.ru/wiki/llm.md) неплохо пишут и объясняют регулярные выражения, но их результат тоже нужно проверять на примерах. ## См. также - [grep и регулярные выражения](https://llmdocs.ru/wiki/grep.md) - [sed и awk](https://llmdocs.ru/wiki/sed-awk.md) - [Unicode и UTF-8](https://llmdocs.ru/wiki/unicode-utf8.md) - [Компилятор и интерпретатор](https://llmdocs.ru/wiki/compiler-interpreter.md) ## Источники 1. [Python — re: Regular expression operations](https://docs.python.org/3/library/re.html) 2. [MDN — Regular expressions (JavaScript)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions) 3. [Russ Cox — Regular Expression Matching Can Be Simple And Fast](https://swtch.com/~rsc/regexp/regexp1.html) 4. [RE2 syntax](https://github.com/google/re2/wiki/Syntax) 5. [OWASP — Regular expression Denial of Service (ReDoS)](https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS) 6. [Cloudflare — Details of the Cloudflare outage on July 2, 2019](https://blog.cloudflare.com/details-of-the-cloudflare-outage-on-july-2-2019/) 7. [Unicode Technical Standard #18 — Unicode Regular Expressions](https://www.unicode.org/reports/tr18/) --- # Лицензии ПО (MIT, GPL, Apache, CC) > Обзор свободных и открытых лицензий на программы и документацию — разрешительных, копилефтных и Creative Commons. Источник: https://llmdocs.ru/wiki/software-licenses/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тема**: лицензирование программ и контента - **Разрешительные**: MIT, BSD, Apache 2.0, ISC - **Копилефт**: GPL, LGPL, AGPL, MPL 2.0 - **Для контента**: Creative Commons (CC BY, CC BY-SA, CC0), GFDL - **Определения**: Open Source Definition (OSI), Free Software Definition (FSF) - **Идентификаторы**: SPDX **Лицензия на программное обеспечение** — документ, в котором правообладатель определяет, что другим разрешено делать с программой или текстом: использовать, изменять, распространять и на каких условиях. Без лицензии действует авторское право по умолчанию, и опубликованный код формально нельзя ни копировать, ни менять. **Открытые лицензии** дают эти права всем, различаясь главным образом тем, требуют ли они сохранять открытость производных работ. Статья носит справочный характер и не является юридической консультацией. ## Свободное и открытое ПО Два близких определения задают рамки: - **Свободное ПО** (Фонд свободного ПО, FSF, Ричард Столлман, 1980-е) — программа, дающая пользователю четыре свободы: запускать для любых целей, изучать и менять, распространять копии, распространять изменённые версии.[2] - **Открытое ПО** (Open Source Initiative, OSI, 1998) — определение из десяти критериев, включая свободное распространение, доступность исходного кода и отсутствие дискриминации по сферам применения.[1] Почти все популярные лицензии соответствуют обоим определениям. Лицензии, запрещающие коммерческое использование или конкурирующие облачные сервисы, к открытым не относятся, даже если исходный код опубликован. ## Разрешительные лицензии Разрешительные (пермиссивные) лицензии позволяют почти всё, включая включение кода в закрытые продукты, при условии сохранения уведомления об авторских правах и текста лицензии. | Лицензия | Особенности | Примеры проектов | |---|---|---| | **MIT** | очень короткая, минимум условий | Node.js, React, Rails | | **BSD 2/3-Clause** | как MIT; вариант 3-Clause запрещает использовать имя автора для рекламы | FreeBSD, многие научные библиотеки | | **Apache 2.0** | явная лицензия на патенты, прекращение прав при патентном иске, требование отмечать изменения и сохранять файл NOTICE[4] | Kubernetes, Android (большая часть), TensorFlow | | **ISC** | эквивалент MIT в упрощённой формулировке | OpenBSD, npm-пакеты | ## Копилефтные лицензии **Копилефт** требует, чтобы производные работы распространялись на тех же условиях с открытым исходным кодом. - **GPL** (GNU General Public License): версия 1 — 1989, версия 2 — 1991, версия 3 — 2007.[5] Распространяя программу, включающую GPL-код, нужно открыть исходники всей производной работы. Под GPLv2 выпускается ядро [Linux](https://llmdocs.ru/wiki/linux.md). - **LGPL** — «ослабленная» GPL для библиотек: их можно подключать из закрытых программ, но изменения самой библиотеки нужно открывать. - **AGPL** — GPL с дополнительным условием: если изменённая программа доступна пользователям по сети (как веб-сервис), исходный код нужно предоставить и им. - **MPL 2.0** (Mozilla) — копилефт на уровне файлов: изменённые файлы остаются открытыми, а остальной код проекта может быть любым. ## Совместимость Код под разными лицензиями можно объединять не всегда. Разрешительный код (MIT, BSD) можно включать в GPL-проекты. Apache 2.0 совместима с GPLv3, но не с GPLv2 из-за патентных условий. Две разные копилефтные лицензии обычно несовместимы между собой. ## Лицензии для документации и контента **Creative Commons** (организация основана в 2001 году, первые лицензии — 2002) предлагает конструктор из условий:[6] - **BY** — указывать автора; - **SA** (ShareAlike) — производные работы под той же лицензией (копилефт для контента); - **NC** — только некоммерческое использование; - **ND** — без изменений. Свободными считаются только **CC BY**, **CC BY-SA** и **CC0** (отказ от прав, передача в общественное достояние). Под CC BY-SA публикуется Википедия, под CC BY-SA 2.5 — справочник MDN, под CC BY 4.0 — шпаргалки tldr-pages. Сама Creative Commons не рекомендует свои лицензии для программного кода.[7] Для документации также применяется **GFDL** (GNU Free Documentation License), например в ArchWiki. ## Практика - Указывайте лицензию в файле `LICENSE` в корне репозитория и коротким идентификатором **SPDX** (`MIT`, `Apache-2.0`, `GPL-3.0-or-later`) в метаданных пакета, например в [pyproject.toml](https://llmdocs.ru/wiki/pyproject-toml.md).[3] - Используя чужой код или текст, сохраняйте уведомления об авторских правах и ссылку на оригинал — этого требует почти любая открытая лицензия. - Подбирать лицензию для своего проекта помогает сайт choosealicense.com.[8] ## См. также - [Git](https://llmdocs.ru/wiki/git.md) - [GitHub](https://llmdocs.ru/wiki/github.md) - [Семантическое версионирование](https://llmdocs.ru/wiki/semver.md) - [pip и PyPI](https://llmdocs.ru/wiki/pip-pypi.md) ## Источники 1. [The Open Source Definition — OSI](https://opensource.org/osd) 2. [What is Free Software? — GNU Project](https://www.gnu.org/philosophy/free-sw.html) 3. [SPDX License List](https://spdx.org/licenses/) 4. [Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0) 5. [GNU General Public License v3](https://www.gnu.org/licenses/gpl-3.0.html) 6. [Creative Commons — About the Licenses](https://creativecommons.org/licenses/) 7. [Creative Commons FAQ: Can I apply a CC license to software?](https://creativecommons.org/faq/#can-i-apply-a-creative-commons-license-to-software) 8. [choosealicense.com](https://choosealicense.com/) --- # Сортировка > Упорядочивание элементов по ключу; основные алгоритмы — быстрая, слиянием, пирамидальная, вставками — и гибриды Timsort и pdqsort, используемые в стандартных библиотеках. Источник: https://llmdocs.ru/wiki/sorting/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Нижняя граница сравнений**: Ω(n log n) - **Быстрые алгоритмы**: quicksort, mergesort, heapsort — O(n log n) - **Простые алгоритмы**: вставками, выбором, пузырьком — O(n²) - **Без сравнений**: подсчётом, поразрядная — O(n + k) - **Python, Java (объекты)**: Timsort / Powersort - **Go, Rust (unstable)**: pdqsort **Сортировка** — расположение элементов последовательности в порядке возрастания или убывания по некоторому ключу. Это одна из самых изученных задач информатики: отсортированные данные позволяют искать двоичным поиском за O(log n), находить дубликаты и медиану, объединять наборы, строить [индексы](https://llmdocs.ru/wiki/database-index.md) баз данных. На примере сортировки традиционно объясняют [оценку сложности](https://llmdocs.ru/wiki/big-o.md), рекурсию и принцип «разделяй и властвуй». ## Свойства алгоритмов - **Сложность** по времени — в худшем, среднем и лучшем случае. - **Память** — сортирует ли алгоритм на месте (O(1) или O(log n) дополнительной памяти) или требует O(n). - **Устойчивость** (stability) — сохраняют ли равные элементы исходный порядок. Важно при сортировке по нескольким ключам: отсортировать сотрудников по имени, затем устойчиво по отделу — внутри отдела они останутся по алфавиту. - **Адаптивность** — работает ли быстрее на почти отсортированных данных. ## Основные алгоритмы | Алгоритм | Среднее | Худшее | Память | Устойчив | |---|---|---|---|---| | Вставками (insertion) | O(n²) | O(n²) | O(1) | да | | Выбором (selection) | O(n²) | O(n²) | O(1) | нет | | Пузырьком (bubble) | O(n²) | O(n²) | O(1) | да | | Слиянием (merge) | O(n log n) | O(n log n) | O(n) | да | | Быстрая (quick) | O(n log n) | O(n²) | O(log n) | нет | | Пирамидальная (heap) | O(n log n) | O(n log n) | O(1) | нет | | Подсчётом (counting) | O(n + k) | O(n + k) | O(k) | да | | Поразрядная (radix) | O(d·(n + k)) | O(d·(n + k)) | O(n + k) | да | **Сортировка вставками** берёт элементы по одному и вставляет на место в уже отсортированной части. Квадратичная в общем случае, но очень быстрая на маленьких и почти упорядоченных массивах — поэтому используется внутри гибридных алгоритмов. **Сортировка слиянием** делит массив пополам, [рекурсивно](https://llmdocs.ru/wiki/recursion.md) сортирует половины и сливает их за линейное время. Гарантирует O(n log n) и устойчивость, хорошо подходит для связных списков и внешней сортировки файлов, не помещающихся в память. **Быстрая сортировка** (Тони Хоар, 1959) выбирает опорный элемент, разбивает массив на «меньше» и «больше» и рекурсивно сортирует части. На практике обычно самая быстрая из сравнительных благодаря работе на месте и хорошей локальности кэша, но при неудачном выборе опорного элемента деградирует до O(n²). **Пирамидальная сортировка** строит двоичную кучу (см. [Дерево и граф](https://llmdocs.ru/wiki/trees-graphs.md)) и извлекает максимум n раз. O(n log n) в худшем случае без дополнительной памяти, но медленнее quicksort из-за неудобного доступа к памяти. ```python def merge_sort(a): if len(a) <= 1: return a mid = len(a) // 2 left, right = merge_sort(a[:mid]), merge_sort(a[mid:]) out, i, j = [], 0, 0 while i < len(left) and j < len(right): if left[i] <= right[j]: # <= сохраняет устойчивость out.append(left[i]); i += 1 else: out.append(right[j]); j += 1 return out + left[i:] + right[j:] ``` ## Нижняя граница Любой алгоритм, который упорядочивает элементы только сравнениями, в худшем случае требует Ω(n log n) сравнений: существует n! перестановок, а каждое сравнение даёт лишь один бит информации, значит нужно не меньше log₂(n!) ≈ n log₂ n сравнений.[1] Обойти границу можно, только используя структуру ключей: сортировка подсчётом для небольших целых, поразрядная для чисел и строк фиксированной длины. ## Сортировка в стандартных библиотеках На практике почти никогда не нужно писать сортировку самому — библиотечные реализации тщательно оптимизированы: - **Timsort** (Тим Петерс, 2002) — гибрид слияния и вставок: находит уже упорядоченные участки («пробеги») и сливает их. Устойчив и очень быстр на реальных данных, которые часто частично упорядочены. Использовался в Python, Java (для объектов), Android; в Python 3.11 стратегия слияния заменена на более оптимальную **Powersort**.[3] - **pdqsort** (pattern-defeating quicksort) — быстрая сортировка с защитой от худшего случая: при неудачных разбиениях переключается на пирамидальную, на маленьких отрезках — на вставки. Используется в Go (`slices.Sort`) и в Rust (`sort_unstable`).[4][5] - **Introsort** — похожий гибрид quicksort, heapsort и вставок в `std::sort` C++. ```python users.sort(key=lambda u: (u.dept, -u.salary)) # Python: устойчиво, по ключу sorted(words, key=str.casefold) # без учёта регистра ``` ```go slices.SortFunc(users, func(a, b User) int { return cmp.Compare(a.Age, b.Age) }) slices.SortStableFunc(users, ...) // устойчивая версия ``` В Rust `sort` — устойчивая (на основе слияния, driftsort), `sort_unstable` — неустойчивая, но быстрее и без выделения памяти.[6] Python предоставляет только устойчивую сортировку.[2] ## Практические советы - Сортируйте по ключу (`key=`), а не через функцию сравнения — это быстрее: ключ вычисляется один раз на элемент. - Строки на естественном языке сравнивают с учётом локали (collation): побайтовое сравнение [UTF-8](https://llmdocs.ru/wiki/unicode-utf8.md) ставит «Ё» после «я». - Если нужны только k наибольших элементов, используйте кучу (`heapq.nlargest`) или частичную сортировку — O(n log k) вместо O(n log n). - Для данных, не помещающихся в память, применяют внешнюю сортировку слиянием — так работают `sort` в Unix и `ORDER BY` в базах данных при нехватке памяти. ## См. также - [Алгоритм и O-нотация](https://llmdocs.ru/wiki/big-o.md) - [Рекурсия](https://llmdocs.ru/wiki/recursion.md) - [Структуры данных](https://llmdocs.ru/wiki/data-structures.md) - [Дерево и граф](https://llmdocs.ru/wiki/trees-graphs.md) ## Источники 1. [Knuth — The Art of Computer Programming, Vol. 3: Sorting and Searching](https://www-cs-faculty.stanford.edu/~knuth/taocp.html) 2. [Python Docs — Sorting Techniques](https://docs.python.org/3/howto/sorting.html) 3. [Tim Peters — listsort.txt (описание Timsort)](https://github.com/python/cpython/blob/main/Objects/listsort.txt) 4. [Orson Peters — Pattern-defeating Quicksort (2021)](https://arxiv.org/abs/2106.05123) 5. [Go — package sort / slices](https://pkg.go.dev/slices#Sort) 6. [Rust — slice::sort_unstable](https://doc.rust-lang.org/std/primitive.slice.html#method.sort_unstable) --- # Дерево и граф > Графы описывают объекты и связи между ними, деревья — их частный случай без циклов; на них построены файловые системы, индексы БД, маршрутизация, зависимости пакетов и сборки. Источник: https://llmdocs.ru/wiki/trees-graphs/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Граф**: множество вершин и рёбер G = (V, E) - **Дерево**: связный граф без циклов, n вершин и n − 1 рёбер - **Представления**: список смежности, матрица смежности - **Обходы**: поиск в ширину (BFS), поиск в глубину (DFS) - **Классические алгоритмы**: Дейкстра, A*, топологическая сортировка, Крускал, Прим - **Деревья в практике**: BST, AVL, красно-чёрное, B-дерево, куча, префиксное дерево **Граф** — математическая модель объектов (**вершин**, узлов) и связей между ними (**рёбер**); формально G = (V, E). **Дерево** — частный случай графа: связный граф без циклов, в котором между любыми двумя вершинами ровно один путь. Обе модели относятся к базовым [структурам данных](https://llmdocs.ru/wiki/data-structures.md): графами описывают дороги, сети, социальные связи и зависимости пакетов, деревьями — файловые системы, HTML-документы, индексы баз данных и синтаксис программ.[1] ## Графы ### Виды - **Ориентированный** (рёбра-стрелки: «A зависит от B») и **неориентированный** («A дружит с B»). - **Взвешенный** — у рёбер есть стоимость: расстояние, задержка, цена. - **Ациклический ориентированный граф** (DAG) — нет направленных циклов. Это граф зависимостей пакетов, задач сборки, пайплайнов данных и история коммитов [Git](https://llmdocs.ru/wiki/git.md).[6] - **Связный**, **двудольный**, **плотный** и **разреженный** — в зависимости от структуры и числа рёбер. ### Представление в памяти | Способ | Память | Есть ли ребро (u, v) | Обход соседей | |---|---|---|---| | Список смежности | O(V + E) | O(степень u) | O(степень u) | | Матрица смежности | O(V²) | O(1) | O(V) | Реальные графы обычно разреженные, поэтому стандартный выбор — список смежности, например словарь списков: ```python graph = { "app": ["web", "db"], "web": ["http"], "db": ["driver"], "http": [], "driver": [], } ``` ### Обходы **Поиск в ширину** (BFS) обходит вершины «слоями» с помощью очереди и находит кратчайший путь по числу рёбер. **Поиск в глубину** (DFS) идёт по одной ветке до конца с помощью стека или рекурсии; на нём основаны поиск циклов, компонент связности и топологическая сортировка. Оба работают за O(V + E).[2] ```python from collections import deque def bfs(graph, start): seen, order, queue = {start}, [], deque([start]) while queue: v = queue.popleft() order.append(v) for w in graph[v]: if w not in seen: seen.add(w) queue.append(w) return order ``` ### Классические алгоритмы - **Алгоритм Дейкстры** (1959) — кратчайшие пути во взвешенном графе с неотрицательными весами, O((V + E) log V) с кучей.[3] Его модификация **A\*** использует эвристику и применяется в навигаторах и играх; Беллман — Форд допускает отрицательные веса. - **Топологическая сортировка** — линейный порядок вершин DAG, при котором каждая зависимость идёт раньше зависимого. Так пакетные менеджеры и системы сборки решают, что устанавливать или собирать первым; в Python есть готовый `graphlib.TopologicalSorter`.[4] - **Минимальное остовное дерево** (Крускал, Прим) — самый дешёвый способ соединить все вершины. - **Максимальный поток**, поиск сильно связных компонент, PageRank. Для экспериментов в Python удобна библиотека NetworkX.[5] ## Деревья Дерево обычно **корневое**: одна вершина — корень, у остальных есть родитель; вершины без детей — листья. Глубина дерева определяет стоимость операций, поэтому многие виды деревьев следят за **балансом**. - **Двоичное дерево поиска** (BST): слева ключи меньше, справа больше; поиск за O(h), где h — высота. В худшем случае (вставка отсортированных ключей) дерево вырождается в список и h = n. - **Сбалансированные деревья** — AVL и красно-чёрные — поддерживают высоту O(log n). На них построены `std::map` в C++, `TreeMap` в Java, `BTreeMap` в Rust (на самом деле B-дерево). - **[B-дерево](https://llmdocs.ru/wiki/b-tree.md)** и B+-дерево — сильно ветвящиеся деревья, оптимизированные под чтение страницами с диска; основа индексов [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md), SQLite и файловых систем. - **Куча** (heap) — дерево, где родитель не больше детей; очередь с приоритетом за O(log n), хранится в массиве (`heapq` в Python). - **Префиксное дерево** (trie) — поиск по префиксу строки: автодополнение, маршрутизация URL и IP-адресов. - **Синтаксические деревья** (AST) — промежуточное представление программы в [компиляторах и интерпретаторах](https://llmdocs.ru/wiki/compiler-interpreter.md); DOM — дерево HTML-документа. В отличие от [хеш-таблицы](https://llmdocs.ru/wiki/hash-table.md), упорядоченные деревья позволяют обходить ключи по порядку и искать диапазоны («все заказы с 1 по 15 ноября»), ценой O(log n) вместо O(1) на операцию. ## Где встречается - файловая система — дерево каталогов (жёсткие и символические ссылки делают её графом); - DNS — дерево доменных зон; - маршрутизация в сетях — поиск кратчайших путей (OSPF использует Дейкстру); - системы сборки, [CI/CD](https://llmdocs.ru/wiki/ci-cd.md)-пайплайны и оркестраторы задач — DAG; - графовые базы данных и графы знаний, рекомендательные системы; - сборщики мусора обходят граф объектов, начиная с корней (см. [Сборка мусора](https://llmdocs.ru/wiki/garbage-collection.md)). ## См. также - [Алгоритм и O-нотация](https://llmdocs.ru/wiki/big-o.md) - [Хеш-таблица](https://llmdocs.ru/wiki/hash-table.md) - [Рекурсия](https://llmdocs.ru/wiki/recursion.md) - [Структуры данных](https://llmdocs.ru/wiki/data-structures.md) ## Источники 1. [Cormen et al. — Introduction to Algorithms, 4th ed., parts III and VI (MIT Press)](https://mitpress.mit.edu/9780262046305/introduction-to-algorithms/) 2. [Sedgewick, Wayne — Algorithms, 4th ed., ch. 3–4](https://algs4.cs.princeton.edu/home/) 3. [Dijkstra — A note on two problems in connexion with graphs (1959)](https://doi.org/10.1007/BF01386390) 4. [Python — graphlib.TopologicalSorter](https://docs.python.org/3/library/graphlib.html) 5. [NetworkX documentation](https://networkx.org/documentation/stable/) 6. [Git — Git Objects (Pro Git)](https://git-scm.com/book/en/v2/Git-Internals-Git-Objects) --- # Unicode и UTF-8 > Unicode — стандарт, присваивающий уникальный номер каждому символу всех письменностей мира; UTF-8 — самая распространённая кодировка, записывающая эти номера последовательностями от 1 до 4 байтов. Источник: https://llmdocs.ru/wiki/unicode-utf8/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Unicode**: стандарт кодирования символов, Консорциум Юникода (с 1991) - **Кодовое пространство**: U+0000 — U+10FFFF (1 114 112 кодовых точек) - **Число символов**: более 150 тысяч - **Кодировки**: UTF-8, UTF-16, UTF-32 - **UTF-8**: Кен Томпсон и Роб Пайк (1992), RFC 3629 - **Доля веб-сайтов в UTF-8**: около 98% - **Совместимость**: первые 128 символов совпадают с ASCII **Unicode** (Юникод) — международный стандарт, который присваивает уникальный номер — **кодовую точку** — каждому символу всех письменностей мира: латинице, кириллице, иероглифам, арабскому письму, математическим знакам, эмодзи. **UTF-8** — самая распространённая **кодировка** Unicode, то есть способ записать эти номера байтами: от одного байта для латиницы до четырёх для эмодзи. Сегодня в UTF-8 работает около 98% веб-сайтов,[7] и это кодировка по умолчанию в [Linux](https://llmdocs.ru/wiki/linux.md), [Python](https://llmdocs.ru/wiki/python.md), [Go](https://llmdocs.ru/wiki/go.md), [Rust](https://llmdocs.ru/wiki/rust.md), [JSON](https://llmdocs.ru/wiki/json.md) и [HTML](https://llmdocs.ru/wiki/html.md). Unicode решил проблему, мучившую программистов десятилетиями: текст, набранный на одном компьютере, превращался в «кракозябры» на другом. ## История Первые кодировки, например ASCII (1963), описывали 128 символов — латиницу, цифры и знаки препинания. Для других языков создавали 8-битные расширения, и для одного только русского их было несколько: КОИ-8, CP866 (DOS), Windows-1251, ISO 8859-5. Текст в одной кодировке, прочитанный в другой, превращался в бессмыслицу вроде «Ïðèâåò» — по-японски это называют *mojibake*. В 1991 году Консорциум Юникода выпустил версию 1.0 стандарта с единым набором символов для всех языков.[1] Сначала предполагалось, что хватит 65 536 символов и 16 бит на каждый, но вскоре пространство расширили до 1 114 112 кодовых точек. Новые версии выходят ежегодно и добавляют письменности и эмодзи; сейчас в стандарте более 150 тысяч символов. В сентябре 1992 года Кен Томпсон и Роб Пайк придумали UTF-8 — по легенде, за один вечер в закусочной в Нью-Джерси — и в течение недели перевели на неё операционную систему Plan 9.[5] Стандарт RFC 3629 (2003) ограничил UTF-8 четырьмя байтами на символ.[2] ## Кодовые точки и кодировки Кодовая точка записывается как `U+` и шестнадцатеричный номер: `U+0041` — латинская «A», `U+0416` — «Ж», `U+1F600` — 😀. Unicode определяет символы и их свойства, но не то, как хранить номера в байтах, — это делают кодировки: | Кодировка | Байтов на символ | Особенности | |---|---|---| | UTF-8 | 1–4 | совместима с ASCII, нет проблем с порядком байтов; стандарт веба и Unix | | UTF-16 | 2 или 4 | внутреннее представление строк в Windows, Java, JavaScript | | UTF-32 | 4 | фиксированная длина, расточительна по памяти | ## Как устроена UTF-8 | Диапазон | Байты | Шаблон | |---|---|---| | U+0000 — U+007F | 1 | `0xxxxxxx` — ASCII без изменений | | U+0080 — U+07FF | 2 | `110xxxxx 10xxxxxx` — кириллица, греческий, иврит | | U+0800 — U+FFFF | 3 | `1110xxxx 10xxxxxx 10xxxxxx` — большинство иероглифов | | U+10000 — U+10FFFF | 4 | `11110xxx 10xxxxxx 10xxxxxx 10xxxxxx` — эмодзи, редкие символы | Схема удачна сразу в нескольких отношениях: любой ASCII-текст уже является корректной UTF-8, по первому байту видно длину символа, а с любого места потока можно найти начало следующего символа. Русская буква в UTF-8 занимает два байта, поэтому русский текст вдвое «тяжелее» английского по байтам — это же влияет и на [токенизацию](https://llmdocs.ru/wiki/tokenization.md) в языковых моделях. ```python s = "Привет, мир! 👋" print(len(s)) # 14 — кодовых точек print(len(s.encode("utf-8"))) # 26 — байтов: кириллица по 2, эмодзи 4 print(s.encode("utf-8")[:4]) # b'\xd0\x9f\xd1\x80' — «Пр» print(hex(ord("Ж")), chr(0x1F600)) ``` ## Что считать символом То, что пользователь видит как один символ, может состоять из нескольких кодовых точек: - «й» можно записать одной точкой `U+0439` или двумя: «и» + комбинируемая кратка `U+0306`. Выглядят одинаково, но строки не равны. - Эмодзи семьи 👨‍👩‍👧 — несколько эмодзи, соединённых невидимым символом. - Флаги стран — пары специальных символов-букв. Поэтому длина строки в кодовых точках не совпадает с числом видимых символов — **графемных кластеров**, правила разбиения на которые описаны в приложении UAX #29.[4] Для корректного сравнения строки **нормализуют** к единой форме (NFC — составные символы, NFD — разложенные), иначе поиск и сравнение имён файлов дают неожиданные результаты.[3] ## Практические правила 1. **Везде UTF-8**: файлы исходного кода, базы данных, HTTP-ответы (`Content-Type: text/html; charset=utf-8`), терминал. 2. **Декодировать на входе, кодировать на выходе**: внутри программы работать со строками, а байты — только на границах (файлы, сеть). 3. **Указывать кодировку явно** при открытии файлов: `open(path, encoding="utf-8")` — иначе на Windows может использоваться системная кодировка. 4. **Не резать строки по байтам**: обрезка посередине многобайтного символа ломает текст. 5. **Не добавлять BOM** (маркер порядка байтов) в UTF-8 без необходимости — он ломает скрипты с `#!` и некоторые парсеры. 6. В [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) создавать базы с кодировкой UTF8, в MySQL использовать `utf8mb4`, а не урезанную `utf8`, которая не вмещает эмодзи. Подробное руководство по работе с Unicode в Python — в официальной документации.[6] ## См. также - [Токен и токенизация](https://llmdocs.ru/wiki/tokenization.md) - [Регулярные выражения](https://llmdocs.ru/wiki/regex.md) - [Python](https://llmdocs.ru/wiki/python.md) - [JSON](https://llmdocs.ru/wiki/json.md) - [HTML](https://llmdocs.ru/wiki/html.md) ## Источники 1. [The Unicode Standard](https://www.unicode.org/standard/standard.html) 2. [RFC 3629 — UTF-8, a transformation format of ISO 10646](https://www.rfc-editor.org/rfc/rfc3629) 3. [Unicode Standard Annex #15 — Unicode Normalization Forms](https://www.unicode.org/reports/tr15/) 4. [Unicode Standard Annex #29 — Unicode Text Segmentation](https://www.unicode.org/reports/tr29/) 5. [Rob Pike — UTF-8 history](https://www.cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt) 6. [Python — Unicode HOWTO](https://docs.python.org/3/howto/unicode.html) 7. [W3Techs — Usage statistics of character encodings for websites](https://w3techs.com/technologies/overview/character_encoding) --- # B-дерево > Сбалансированное сильно ветвящееся дерево поиска, оптимизированное для хранения на диске; его вариант B+-дерево лежит в основе индексов почти всех реляционных СУБД и многих файловых систем. Источник: https://llmdocs.ru/wiki/b-tree/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Авторы**: Рудольф Байер, Эдвард Маккрейт (Boeing) - **Год**: 1970 (публикация — 1972) - **Сложность поиска, вставки, удаления**: O(log n) - **Ветвление**: сотни ключей на узел - **Вариант в СУБД**: B+-дерево — данные только в листьях, листья связаны - **Где используется**: PostgreSQL, MySQL InnoDB, SQLite, Oracle, файловые системы (NTFS, Btrfs, XFS, APFS) - **Альтернатива**: LSM-дерево (RocksDB, Cassandra) **B-дерево** — сбалансированное дерево поиска, в котором каждый узел хранит не один ключ, как в двоичном дереве, а десятки или сотни упорядоченных ключей и столько же ссылок на дочерние узлы. Благодаря большому ветвлению дерево получается очень низким: даже для миллиардов записей нужно три-четыре уровня. Структура создана для данных, хранящихся на диске, где дорого не сравнение ключей, а каждое чтение блока. Вариант **B+-дерево** — стандартная структура [индексов](https://llmdocs.ru/wiki/database-index.md) в [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md), [MySQL](https://llmdocs.ru/wiki/mysql-mariadb.md), [SQLite](https://llmdocs.ru/wiki/sqlite.md), Oracle и SQL Server, а также основа многих файловых систем. ## История Рудольф Байер и Эдвард Маккрейт разработали B-дерево в 1970 году в исследовательской лаборатории Boeing; статья вышла в 1972 году.[1] Что означает буква «B», авторы так и не уточнили: среди версий — Boeing, Bayer, *balanced* («сбалансированное») и *broad* («широкое»). Уже к 1979 году обзор Дугласа Комера назывался «Вездесущее B-дерево» — структура стала стандартом для индексов баз данных и файлов.[2] ## Почему не двоичное дерево Диск и SSD читают данные не байтами, а **страницами** — блоками по 4–16 КБ. Обращение к новой странице на порядки дороже сравнения в памяти. Двоичное дерево для миллиона ключей имеет глубину около 20 — это 20 случайных чтений с диска на каждый поиск. B-дерево с узлом размером в страницу и 500 ключами на узел вмещает миллион записей в три уровня, причём корень и верхний уровень почти всегда находятся в кэше. Поиск сводится к одному-двум чтениям. | Записей | Двоичное дерево (уровней) | B-дерево, 500 ключей на узел (уровней) | |---|---|---| | 1 000 | 10 | 2 | | 1 000 000 | 20 | 3 | | 1 000 000 000 | 30 | 4 | ## Устройство B-дерево порядка *m* удовлетворяет правилам: - в узле хранятся упорядоченные ключи, и между соседними ключами — ссылка на поддерево со значениями из этого промежутка; - каждый узел, кроме корня, заполнен как минимум наполовину; - **все листья находятся на одной глубине** — дерево всегда идеально сбалансировано. **Поиск** начинается с корня: в узле двоичным поиском находится нужный промежуток, затем переход к соответствующему потомку, и так до листа. **Вставка** добавляет ключ в лист; если лист переполнен, он **расщепляется** пополам, а средний ключ поднимается в родителя. Расщепление может дойти до корня — тогда появляется новый корень, и дерево вырастает на уровень. Рост «снизу вверх» и сохраняет баланс. **Удаление** при недозаполнении узла занимает ключи у соседа или сливает узлы. Все операции выполняются за O(log n) (см. [Алгоритм и O-нотация](https://llmdocs.ru/wiki/big-o.md)). ## B+-дерево В базах данных почти всегда используется вариант **B+-дерево**: - значения (или ссылки на строки таблицы) хранятся **только в листьях**, а внутренние узлы содержат лишь ключи-разделители — поэтому они компактнее и ветвление выше; - листья связаны в список, так что **диапазонный запрос** (`WHERE created_at BETWEEN ...`, `ORDER BY`) находит начало диапазона и затем просто идёт по листьям. Этим объясняется, почему B-tree-индекс помогает не только равенству, но и сравнениям, сортировке и поиску по префиксу строки. ## В конкретных СУБД - **PostgreSQL** — индекс по умолчанию — B-дерево (реализация по алгоритму Лемана — Яо с поддержкой параллельного доступа); страница 8 КБ; дедупликация одинаковых ключей с версии 13. Строки таблицы хранятся отдельно, в «куче», а индекс ссылается на них.[3] - **MySQL InnoDB** — таблица сама хранится как B+-дерево по первичному ключу (**кластерный индекс**), страница 16 КБ; вторичные индексы ссылаются на значение первичного ключа. Поэтому случайный UUID в качестве первичного ключа приводит к частым расщеплениям страниц, а последовательные идентификаторы — нет.[5] - **SQLite** — вся база данных — набор B-деревьев в одном файле: таблицы хранятся как B+-деревья по `rowid`, индексы — как B-деревья.[4] ## B-деревья и LSM-деревья Для нагрузок с очень интенсивной записью используют альтернативу — **LSM-дерево** (*log-structured merge tree*): записи сначала накапливаются в памяти, затем сбрасываются на диск отсортированными файлами, которые фоном сливаются.[6] | | B+-дерево | LSM-дерево | |---|---|---| | Запись | обновление на месте, случайный ввод-вывод | последовательная запись, очень быстро | | Чтение | предсказуемо быстрое | может требовать проверки нескольких файлов | | Фоновая работа | очистка страниц | постоянное слияние (compaction) | | Примеры | PostgreSQL, InnoDB, SQLite | RocksDB, Cassandra, ScyllaDB, [ClickHouse](https://llmdocs.ru/wiki/clickhouse.md) (MergeTree) | ## Практические следствия - Индексу нужна память: «горячие» верхние уровни должны помещаться в кэш СУБД. - Порядок столбцов в составном индексе определяет, какие запросы он ускоряет, — ключи сравниваются слева направо. - Частые вставки в середину и удаления фрагментируют страницы; периодическая перестройка (`REINDEX`) возвращает компактность. ## См. также - [Индекс (базы данных)](https://llmdocs.ru/wiki/database-index.md) - [Дерево и граф](https://llmdocs.ru/wiki/trees-graphs.md) - [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) - [SQLite](https://llmdocs.ru/wiki/sqlite.md) - [Структуры данных](https://llmdocs.ru/wiki/data-structures.md) ## Источники 1. [R. Bayer, E. McCreight — Organization and Maintenance of Large Ordered Indexes (Acta Informatica, 1972)](https://link.springer.com/article/10.1007/BF00288683) 2. [D. Comer — The Ubiquitous B-Tree (ACM Computing Surveys, 1979)](https://dl.acm.org/doi/10.1145/356770.356776) 3. [PostgreSQL Documentation — B-Tree Indexes](https://www.postgresql.org/docs/current/btree.html) 4. [SQLite — Database File Format](https://www.sqlite.org/fileformat2.html) 5. [MySQL — Clustered and Secondary Indexes (InnoDB)](https://dev.mysql.com/doc/refman/8.4/en/innodb-index-types.html) 6. [P. O'Neil et al. — The Log-Structured Merge-Tree (LSM-Tree) (1996)](https://www.cs.umb.edu/~poneil/lsmtree.pdf) --- # ClickHouse > Колоночная аналитическая СУБД с открытым кодом, созданная в Яндексе для Яндекс.Метрики; выполняет агрегирующие SQL-запросы по миллиардам строк за секунды. Источник: https://llmdocs.ru/wiki/clickhouse/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: колоночная аналитическая СУБД (OLAP) - **Автор**: Алексей Миловидов и команда Яндекса - **Разработка**: с 2009 года для Яндекс.Метрики - **Открытие кода**: июнь 2016 - **Язык**: C++ - **Лицензия**: Apache 2.0 - **Разработчик сейчас**: ClickHouse, Inc. (с 2021) и сообщество - **Основной движок таблиц**: MergeTree **ClickHouse** — колоночная система управления базами данных для аналитики. Она рассчитана на запросы вида «посчитай выручку по дням и регионам за год» по таблицам из миллиардов и триллионов строк и выполняет их за секунды и доли секунды. ClickHouse хранит данные [по столбцам](https://llmdocs.ru/wiki/columnar-storage.md), сжимает их и обрабатывает векторно, пакетами значений, используя все ядра процессора. Запросы пишутся на диалекте [SQL](https://llmdocs.ru/wiki/sql.md).[1] ClickHouse применяют для веб-аналитики, мониторинга и логов, финансовой аналитики, телеметрии, рекламных систем и аналитики LLM-приложений. ## История Разработку начал Алексей Миловидов в Яндексе в 2009 году для системы веб-аналитики Яндекс.Метрика, где требовалось строить отчёты «на лету» по сырым данным, а не по заранее подсчитанным агрегатам. В 2012 году ClickHouse заработал в продакшене Метрики, а в июне 2016 года Яндекс открыл исходный код под лицензией Apache 2.0.[4] В 2021 году для развития проекта была основана компания ClickHouse, Inc., предлагающая и облачный сервис. Архитектура системы подробно описана в статье на конференции VLDB 2024.[3] ## Почему так быстро - **Колоночное хранение.** Запрос читает только нужные столбцы: для суммы по одному столбцу из сотни не нужно читать остальные 99. - **Сжатие.** Однотипные значения столбца сжимаются в разы и десятки раз (LZ4, ZSTD и специальные кодеки для временных рядов), так что с диска читается меньше данных. - **Векторное выполнение.** Операции применяются к блокам из тысяч значений, эффективно используя кэш процессора и SIMD-инструкции. - **Параллелизм.** Запрос распараллеливается на все ядра сервера и на узлы кластера. - **Разреженный первичный индекс.** Данные отсортированы по ключу, а индекс хранит по одной отметке на блок строк (по умолчанию 8192), помещаясь в памяти даже для огромных таблиц. Сравнение с другими аналитическими системами на одинаковых данных — в открытом тесте ClickBench.[5] ## MergeTree Основной движок таблиц — **MergeTree**. Вставка создаёт новую неизменяемую отсортированную «часть» (*part*), а фоновые процессы сливают мелкие части в крупные — идея, родственная LSM-деревьям (см. [B-дерево](https://llmdocs.ru/wiki/b-tree.md)).[2] ```sql CREATE TABLE events ( event_time DateTime, user_id UInt64, event_type LowCardinality(String), url String, duration_ms UInt32 ) ENGINE = MergeTree PARTITION BY toYYYYMM(event_time) ORDER BY (event_type, event_time) TTL event_time + INTERVAL 1 YEAR; -- автоматически удалять старые данные SELECT toDate(event_time) AS day, event_type, count() AS events, uniq(user_id) AS users, -- приближённый подсчёт уникальных quantile(0.95)(duration_ms) AS p95 FROM events WHERE event_time >= now() - INTERVAL 30 DAY GROUP BY day, event_type ORDER BY day; ``` Варианты движка решают специальные задачи: ReplacingMergeTree удаляет дубликаты по ключу, SummingMergeTree и AggregatingMergeTree хранят предагрегированные данные, ReplicatedMergeTree обеспечивает [репликацию](https://llmdocs.ru/wiki/replication.md). **Материализованные представления** обновляются при вставке и позволяют строить агрегаты на лету. ## Сильные стороны - Огромная скорость агрегаций и сканирования; богатая библиотека аналитических функций — квантили, приближённые уникальные значения, массивы, оконные функции. - Чтение напрямую из файлов Parquet, CSV и JSON, из S3, Kafka, [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) и MySQL. - Эффективное хранение: логи и метрики занимают в разы меньше места, чем в строковых СУБД. - Масштабирование от ноутбука (`clickhouse-local`) до кластеров из сотен серверов. ## Ограничения - **Не для транзакционной нагрузки.** Нет полноценных [транзакций ACID](https://llmdocs.ru/wiki/transaction-acid.md) в привычном смысле; точечные обновления и удаления дороги и выполняются асинхронными «мутациями» или облегчённым удалением. - **Вставка пакетами.** Тысячи мелких вставок в секунду создают слишком много частей; данные собирают в пакеты или используют асинхронную вставку. - **Соединения больших таблиц** работают хуже, чем в системах, специально под них оптимизированных; схему проектируют широкими денормализованными таблицами (см. [Нормализация](https://llmdocs.ru/wiki/normalization.md)). - **Свой диалект SQL** с особенностями типов и функций. ## Место в архитектуре Типичная схема: транзакционные данные живут в PostgreSQL или MySQL, события и логи потоком идут через Kafka, а ClickHouse хранит их для аналитики, дашбордов (Grafana, Superset) и отчётов. Альтернативы — облачные хранилища (BigQuery, Snowflake, Redshift), Apache Druid и Pinot, а для аналитики на одной машине — встраиваемая DuckDB. ## См. также - [Колоночное хранение](https://llmdocs.ru/wiki/columnar-storage.md) - [SQL](https://llmdocs.ru/wiki/sql.md) - [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) - [Репликация баз данных](https://llmdocs.ru/wiki/replication.md) - [Мониторинг и алертинг](https://llmdocs.ru/wiki/monitoring-alerting.md) ## Источники 1. [ClickHouse Documentation](https://clickhouse.com/docs) 2. [ClickHouse — MergeTree table engine](https://clickhouse.com/docs/engines/table-engines/mergetree-family/mergetree) 3. [R. Schulze et al. — ClickHouse: Lightning Fast Analytics for Everyone (VLDB 2024)](https://www.vldb.org/pvldb/vol17/p3731-schulze.pdf) 4. [ClickHouse — History](https://clickhouse.com/docs/about-us/history) 5. [ClickBench — a Benchmark For Analytical DBMS](https://benchmark.clickhouse.com/) 6. [ClickHouse — GitHub](https://github.com/ClickHouse/ClickHouse) --- # Колоночное хранение > Способ хранения таблиц по столбцам, а не по строкам; даёт сильное сжатие и быструю аналитику по миллиардам строк — основа ClickHouse, хранилищ данных, форматов Parquet и Arrow. Источник: https://llmdocs.ru/wiki/columnar-storage/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Суть**: значения одного столбца хранятся подряд - **Противоположность**: строковое хранение (row store, OLTP) - **Сильные стороны**: сжатие, чтение нужных столбцов, векторизация - **Слабые стороны**: точечные обновления и вставки по одной строке - **СУБД**: ClickHouse, DuckDB, Vertica, Apache Druid, Snowflake, BigQuery, Redshift - **Форматы**: Apache Parquet, ORC (на диске), Apache Arrow (в памяти) **Колоночное хранение** (англ. *columnar storage*, *column-oriented*) — способ физической организации таблицы, при котором значения каждого столбца хранятся на диске и в памяти подряд, отдельно от других столбцов. Классические [реляционные СУБД](https://llmdocs.ru/wiki/relational-database.md) вроде [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) и [MySQL](https://llmdocs.ru/wiki/mysql-mariadb.md) хранят данные **по строкам**: все поля одной записи лежат рядом. Колоночная организация делает аналитические запросы по огромным таблицам в десятки и сотни раз быстрее и лежит в основе [ClickHouse](https://llmdocs.ru/wiki/clickhouse.md), облачных хранилищ данных и форматов Parquet и Arrow.[1] ## Строки или столбцы Пусть таблица `events` содержит миллиард строк и 50 столбцов, а запрос считает выручку по дням: ```sql SELECT toDate(ts) AS day, sum(amount) FROM events WHERE country = 'RU' GROUP BY day; ``` Запросу нужны только три столбца — `ts`, `amount`, `country`. Строковая СУБД вынуждена прочитать с диска все 50 столбцов каждой строки; колоночная читает только три файла, то есть примерно в 15 раз меньше данных ещё до сжатия. | | Строковое (OLTP) | Колоночное (OLAP) | |---|---|---| | Типичный запрос | «заказ № 1042 целиком» | «сумма по миллиардам строк» | | Чтение одной записи | быстро | медленно (сборка из многих столбцов) | | Вставка, обновление по одной строке | быстро | дорого, лучше пачками | | Агрегаты по немногим столбцам | медленно | очень быстро | | Сжатие | умеренное | сильное, часто в 5–20 раз | | Примеры | PostgreSQL, MySQL, [SQLite](https://llmdocs.ru/wiki/sqlite.md) | ClickHouse, DuckDB, BigQuery | Поэтому системы обычно делят по нагрузке: транзакционная база (OLTP) обслуживает приложение, а данные из неё копируются в аналитическое колоночное хранилище (OLAP). ## Почему это быстро **1. Сжатие.** Значения одного столбца однотипны и часто похожи, поэтому они хорошо сжимаются специализированными кодировками:[3] - *словарная* — строки с небольшим числом вариантов (страна, статус) заменяются короткими номерами; - *RLE* (run-length) — повторы «RU, RU, RU…» хранятся как «RU × 1000»; - *дельта* — для отсортированных времён и счётчиков хранятся разности соседних значений; - поверх — универсальные алгоритмы LZ4 и Zstandard. Сжатие уменьшает не только диск, но и объём чтения — а именно ввод-вывод обычно ограничивает аналитику. **2. Векторизованное выполнение.** Движок обрабатывает данные не по одной строке, а блоками по тысячам значений одного столбца. Это хорошо ложится на [кэши процессора](https://llmdocs.ru/wiki/cache.md) и SIMD-инструкции; подход предложен в исследовательской СУБД MonetDB/X100 (2005).[7] **3. Пропуск данных.** Для блоков хранятся минимумы и максимумы, разреженные индексы и фильтры Блума, так что блоки, заведомо не подходящие под условие `WHERE`, не читаются вовсе. **4. Параллелизм.** Столбцы и блоки обрабатываются независимо на всех ядрах и узлах кластера. ## История Идея известна с 1970-х, но массовой стала после исследовательских систем MonetDB и C-Store (Майкл Стоунбрейкер и соавторы, 2005),[2] из которой выросла коммерческая Vertica. В 2010-х появились Google Dremel (BigQuery), Amazon Redshift, Apache Druid, Snowflake и открытый ClickHouse от Яндекса (2016). В 2019 году вышла **DuckDB** — встраиваемая колоночная СУБД, «SQLite для аналитики».[6] ## Форматы файлов Колоночная организация применяется и вне СУБД: - **Apache Parquet** — стандартный колоночный формат для озёр данных: файл делится на группы строк, внутри — колонки со сжатием и статистикой.[4] Его читают Spark, [pandas](https://llmdocs.ru/wiki/pandas.md), Polars, DuckDB, ClickHouse, Trino. - **ORC** — похожий формат из экосистемы Hadoop/Hive. - **Apache Arrow** — колоночный формат *в памяти* для обмена данными между процессами и языками без копирования и сериализации.[5] На нём построены pandas 2.x (опционально), Polars и многие драйверы. ```python import duckdb duckdb.sql(""" SELECT country, count(*) AS n, avg(amount) FROM 'events/*.parquet' GROUP BY country ORDER BY n DESC """).show() ``` Табличные форматы **Apache Iceberg** и **Delta Lake** добавляют поверх Parquet-файлов транзакции, версии и эволюцию схемы. ## Ограничения - Точечные обновления и удаления дороги: ClickHouse выполняет их как фоновые «мутации», другие системы — через пометки об удалении и последующее слияние. - Вставлять данные нужно пачками (тысячи строк и больше), иначе плодятся мелкие части. - Запросы «одна строка целиком» и множество соединений по ключам эффективнее в строковых СУБД. - [Транзакционные](https://llmdocs.ru/wiki/transaction-acid.md) гарантии обычно слабее, чем в OLTP-базах. Существуют и гибриды (HTAP): колоночные индексы в SQL Server, расширения для PostgreSQL вроде Citus columnar и pg_duckdb, отдельный колоночный движок MariaDB ColumnStore. ## См. также - [ClickHouse](https://llmdocs.ru/wiki/clickhouse.md) - [pandas](https://llmdocs.ru/wiki/pandas.md) - [Индекс (базы данных)](https://llmdocs.ru/wiki/database-index.md) - [NoSQL](https://llmdocs.ru/wiki/nosql.md) ## Источники 1. [Abadi, Boncz, Harizopoulos et al. — The Design and Implementation of Modern Column-Oriented Database Systems (2013)](https://doi.org/10.1561/1900000024) 2. [Stonebraker et al. — C-Store: A Column-oriented DBMS (VLDB 2005)](https://www.vldb.org/archives/website/2005/program/paper/thu/p553-stonebraker.pdf) 3. [ClickHouse — Why is ClickHouse so fast?](https://clickhouse.com/docs/concepts/why-clickhouse-is-so-fast) 4. [Apache Parquet documentation](https://parquet.apache.org/docs/) 5. [Apache Arrow — Columnar Format](https://arrow.apache.org/docs/format/Columnar.html) 6. [DuckDB documentation](https://duckdb.org/docs/) 7. [Boncz, Zukowski, Nes — MonetDB/X100: Hyper-Pipelining Query Execution (CIDR 2005)](https://www.cidrdb.org/cidr2005/papers/P19.pdf) --- # Индекс (базы данных) > Вспомогательная структура данных, ускоряющая поиск строк в таблице ценой дополнительного места и замедления записи. Источник: https://llmdocs.ru/wiki/database-index/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Назначение**: ускорение поиска, сортировки и соединений - **Основная структура**: B-дерево (B+-дерево) - **Другие виды**: хеш, GIN, GiST, BRIN, векторные (HNSW, IVF) - **Цена**: место на диске, замедление INSERT/UPDATE/DELETE - **Команда**: CREATE INDEX **Индекс** в базе данных — вспомогательная структура, которая позволяет находить нужные строки таблицы, не просматривая её целиком. Аналогия — предметный указатель в конце книги: чтобы найти упоминания термина, не нужно перелистывать все страницы. Индекс хранит значения выбранных столбцов в упорядоченном (или иначе организованном) виде вместе со ссылками на строки таблицы. Индексы — главный инструмент ускорения запросов в [реляционных базах](https://llmdocs.ru/wiki/relational-database.md). Хорошо подобранный индекс превращает запрос, читающий миллионы строк, в запрос, читающий несколько страниц. Но за это приходится платить местом и скоростью записи. ## Зачем нужен Без индекса единственный способ выполнить `WHERE email = 'a@b.c'` — **последовательное сканирование** (*sequential scan*, *full table scan*): прочитать все строки и проверить условие. Время растёт линейно с размером таблицы. Индекс на основе [B-дерева](https://llmdocs.ru/wiki/b-tree.md) находит значение за логарифмическое число шагов: для таблицы в сто миллионов строк это три–четыре уровня дерева. Индекс помогает не только фильтрации: - **сортировке** — `ORDER BY` по индексированному столбцу не требует отдельной сортировки; - **соединениям** — поиск пары по внешнему ключу в другой таблице; - **уникальности** — ограничения `PRIMARY KEY` и `UNIQUE` реализуются уникальными индексами; - **агрегатам** — `min`/`max` по индексу читаются с краёв дерева. ## Виды индексов | Вид | Как устроен | Для чего подходит | |---|---|---| | [B-tree](https://llmdocs.ru/wiki/b-tree.md) | сбалансированное дерево с упорядоченными ключами | равенство, диапазоны, сортировка, префикс `LIKE 'abc%'` — вариант по умолчанию | | Хеш | [хеш-таблица](https://llmdocs.ru/wiki/hash-table.md) | только проверка на равенство | | GIN | инвертированный индекс | массивы, `jsonb`, полнотекстовый поиск | | GiST / SP-GiST | обобщённые деревья поиска | геометрия, диапазоны, ближайшие соседи | | BRIN | сводки по блокам страниц | огромные таблицы, где значения коррелируют с физическим порядком (время вставки) | | Векторные (HNSW, IVF) | графы и кластеры векторов | приближённый [поиск ближайших векторов](https://llmdocs.ru/wiki/vector-search.md) | Список выше соответствует методам доступа [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md);[2] в других СУБД набор отличается, но B-дерево (точнее, его вариант B+-дерево) есть везде. Саму структуру описали Рудольф Байер и Эдвард Маккрейт в 1970–1972 годах.[5] Векторные индексы добавляет расширение [pgvector](https://llmdocs.ru/wiki/pgvector.md). ## Составные, частичные и покрывающие индексы **Составной индекс** строится по нескольким столбцам, и порядок столбцов важен. Индекс по `(customer_id, created_at)` ускоряет запросы по `customer_id` и по паре `customer_id` + диапазон дат, но почти не помогает запросу только по `created_at` — так же, как телефонный справочник, отсортированный по фамилии и имени, бесполезен для поиска по одному имени.[3] **Частичный индекс** включает только строки, удовлетворяющие условию, — например, только неоплаченные заказы. **Индекс по выражению** строится по результату функции, например `lower(email)`. **Покрывающий индекс** содержит все столбцы, нужные запросу, и тогда СУБД отвечает, не заходя в таблицу (*index-only scan*).[4] ```sql -- составной индекс под частый запрос «последние заказы покупателя» CREATE INDEX orders_customer_created_idx ON orders (customer_id, created_at DESC); -- частичный индекс CREATE INDEX orders_unpaid_idx ON orders (created_at) WHERE paid = false; -- индекс по выражению для поиска без учёта регистра CREATE UNIQUE INDEX users_email_lower_idx ON users (lower(email)); -- в PostgreSQL: построить без блокировки записи в таблицу CREATE INDEX CONCURRENTLY orders_total_idx ON orders (total); ``` ## Цена индексов - **Запись медленнее.** Каждый `INSERT`, `UPDATE` или `DELETE` обязан обновить все индексы таблицы. - **Место.** Индексы занимают диск и память; на нагруженных таблицах их суммарный объём нередко превышает объём данных. - **Не всегда используются.** Если условие отбирает значительную часть таблицы, последовательное чтение быстрее тысяч случайных переходов по индексу, и оптимизатор это учитывает. ## Почему индекс не используется Типичные причины: функция над столбцом в условии (`WHERE lower(email) = ...` при индексе по `email`), неявное приведение типов, `LIKE '%abc'` с подстановочным знаком в начале, неверный порядок столбцов в составном индексе, устаревшая статистика. Проверять нужно не догадками, а планом выполнения через [EXPLAIN](https://llmdocs.ru/wiki/explain.md): в нём видно, выбран ли `Index Scan` или `Seq Scan`. Подробный разбор типичных ошибок — в книге Маркуса Винанда «Use The Index, Luke».[6] ## Практические правила 1. Индексируйте столбцы из `WHERE`, `JOIN` и `ORDER BY` самых частых и самых медленных запросов, а не «все подряд». 2. Внешние ключи почти всегда стоит индексировать: иначе удаление родительской строки сканирует дочернюю таблицу. 3. Периодически ищите неиспользуемые индексы (в PostgreSQL — представление `pg_stat_user_indexes`) и удаляйте их. 4. На больших таблицах создавайте индексы без блокировки записи и оформляйте их [миграциями](https://llmdocs.ru/wiki/schema-migrations.md).[1] ## См. также - [B-дерево](https://llmdocs.ru/wiki/b-tree.md) - [EXPLAIN и план запроса](https://llmdocs.ru/wiki/explain.md) - [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) - [Векторный поиск](https://llmdocs.ru/wiki/vector-search.md) - [Хеш-таблица](https://llmdocs.ru/wiki/hash-table.md) ## Источники 1. [PostgreSQL Documentation — Indexes](https://www.postgresql.org/docs/current/indexes.html) 2. [PostgreSQL Documentation — Index Types](https://www.postgresql.org/docs/current/indexes-types.html) 3. [PostgreSQL Documentation — Multicolumn Indexes](https://www.postgresql.org/docs/current/indexes-multicolumn.html) 4. [PostgreSQL Documentation — Index-Only Scans and Covering Indexes](https://www.postgresql.org/docs/current/indexes-index-only-scans.html) 5. [R. Bayer, E. McCreight — Organization and Maintenance of Large Ordered Indexes (1972)](https://link.springer.com/article/10.1007/BF00288683) 6. [Markus Winand — Use The Index, Luke](https://use-the-index-luke.com/) --- # EXPLAIN и план запроса > План запроса — последовательность операций, которую оптимизатор СУБД выбрал для выполнения SQL-запроса; команда EXPLAIN показывает его, а EXPLAIN ANALYZE — ещё и фактическое время и число строк. Источник: https://llmdocs.ru/wiki/explain/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Команды**: EXPLAIN, EXPLAIN ANALYZE (PostgreSQL, MySQL), EXPLAIN QUERY PLAN (SQLite) - **Оптимизатор**: стоимостной, на основе статистики - **Основы стоимостной оптимизации**: System R, Патриция Селинджер (1979) - **Типичные узлы**: Seq Scan, Index Scan, Bitmap Heap Scan, Nested Loop, Hash Join, Merge Join, Sort - **Визуализация**: explain.depesz.com, explain.dalibo.com **План запроса** — конкретный способ, которым СУБД выполнит [SQL](https://llmdocs.ru/wiki/sql.md)-запрос: в каком порядке читать таблицы, какие [индексы](https://llmdocs.ru/wiki/database-index.md) использовать, каким алгоритмом соединять строки, где сортировать и агрегировать. SQL декларативен — запрос описывает результат, а не алгоритм, — и план выбирает **оптимизатор**. Команда **`EXPLAIN`** показывает выбранный план, а **`EXPLAIN ANALYZE`** выполняет запрос и добавляет фактическое время и число строк на каждом шаге. `EXPLAIN` — главный инструмент разбора медленных запросов: вместо догадок «наверное, не хватает индекса» он показывает, что на самом деле происходит. ## Как оптимизатор выбирает план Для одного запроса возможны тысячи планов. Современные СУБД используют **стоимостную оптимизацию**, идея которой восходит к системе System R и работе Патриции Селинджер (1979):[4] оптимизатор оценивает стоимость каждого варианта в условных единицах — сколько страниц прочитать с диска, сколько строк обработать процессором — и выбирает самый дешёвый. Оценки строятся на **статистике** о данных: число строк в таблице, доля пустых значений, самые частые значения и гистограмма распределения каждого столбца.[3] Статистику собирает команда `ANALYZE` (в PostgreSQL — автоматически вместе с autovacuum). Устаревшая или неточная статистика — частая причина плохих планов. ## Чтение плана ```sql EXPLAIN ANALYZE SELECT c.name, count(*) AS orders FROM orders o JOIN customers c ON c.id = o.customer_id WHERE o.created_at >= now() - interval '7 days' GROUP BY c.name; ``` ```text HashAggregate (cost=1250.3..1262.8 rows=1250 width=40) (actual time=18.4..18.9 rows=1180 loops=1) Group Key: c.name -> Hash Join (cost=310.0..1180.1 rows=14040 width=32) (actual time=3.1..15.2 rows=13892 loops=1) Hash Cond: (o.customer_id = c.id) -> Index Scan using orders_created_at_idx on orders o (cost=0.43..820.5 rows=14040 width=8) (actual time=0.02..7.8 rows=13892 loops=1) Index Cond: (created_at >= (now() - '7 days'::interval)) -> Hash (cost=185.0..185.0 rows=10000 width=36) (actual time=3.0..3.0 rows=10000 loops=1) -> Seq Scan on customers c (cost=0.0..185.0 rows=10000 width=36) (actual ...) Planning Time: 0.4 ms Execution Time: 19.3 ms ``` План — дерево: читается от вложенных узлов к корню. Для каждого узла:[1] - **`cost=начальная..полная`** — оценка стоимости до первой строки и до последней; - **`rows`** — сколько строк оптимизатор *ожидает*; в `actual` — сколько получилось на деле; - **`loops`** — сколько раз выполнялся узел (время и строки в `actual` указаны за один проход); - **`width`** — средний размер строки в байтах. Самое важное — **сравнить ожидаемое и фактическое число строк**. Расхождение в десятки и сотни раз означает, что оптимизатор ошибся в оценке и, скорее всего, выбрал неподходящий план. ## Основные узлы | Узел | Что делает | Когда хорош | |---|---|---| | Seq Scan | читает таблицу целиком | маленькие таблицы, выборка большой доли строк | | Index Scan | проходит индекс и читает строки из таблицы | выборка малой доли строк | | Index Only Scan | отвечает по индексу, не заходя в таблицу | покрывающий индекс | | Bitmap Heap Scan | собирает по индексу карту страниц, затем читает их по порядку | средняя доля строк, несколько условий | | Nested Loop | для каждой строки внешней стороны ищет пары во внутренней | мало строк снаружи и индекс внутри | | Hash Join | строит хеш-таблицу по меньшей стороне | большие наборы, условие равенства | | Merge Join | сливает два отсортированных потока | данные уже отсортированы | | Sort, HashAggregate | сортировка, группировка | — | ## Типичные проблемы и что они значат - **Seq Scan по большой таблице с избирательным условием** — нет подходящего индекса или он неприменим (функция над столбцом, несовпадение типов, `LIKE '%...'`). - **Nested Loop с огромным числом `loops`** — оптимизатор недооценил число строк; помогает `ANALYZE`, расширенная статистика (`CREATE STATISTICS` для связанных столбцов) или переписывание запроса. - **Sort с `external merge Disk`** — сортировке не хватило памяти (`work_mem`), она ушла на диск. - **`Rows Removed by Filter` много больше полученных строк** — индекс не покрывает часть условия. Ключ `EXPLAIN (ANALYZE, BUFFERS)` дополнительно показывает, сколько страниц прочитано из кэша и с диска, — это часто объясняет разницу между первым и повторным запуском.[2] ## Другие СУБД - **MySQL** — `EXPLAIN` выводит табличный план (тип доступа `ALL`, `ref`, `range`, используемый ключ, оценку строк), `EXPLAIN ANALYZE` (с версии 8.0.18) — дерево с фактическим временем, `EXPLAIN FORMAT=JSON` — подробности.[5] - **[SQLite](https://llmdocs.ru/wiki/sqlite.md)** — `EXPLAIN QUERY PLAN` кратко показывает, где используется индекс (`SEARCH ... USING INDEX`), а где полный проход (`SCAN`).[6] ## Практика 1. Найти медленные запросы — в PostgreSQL через расширение `pg_stat_statements` или журнал медленных запросов. 2. Выполнить `EXPLAIN (ANALYZE, BUFFERS)` на реалистичных данных: план на пустой тестовой базе бесполезен. Осторожно с изменяющими запросами — `ANALYZE` их действительно выполняет; оборачивайте в `BEGIN ... ROLLBACK`. 3. Найти самый дорогой узел и расхождения оценок. 4. Исправить: индекс, статистика, переписывание запроса, настройки памяти. 5. Проверить план повторно. Длинные планы удобно разбирать в визуализаторах вроде explain.depesz.com и explain.dalibo.com. ## См. также - [Индекс (базы данных)](https://llmdocs.ru/wiki/database-index.md) - [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) - [SQL](https://llmdocs.ru/wiki/sql.md) - [B-дерево](https://llmdocs.ru/wiki/b-tree.md) - [Алгоритм и O-нотация](https://llmdocs.ru/wiki/big-o.md) ## Источники 1. [PostgreSQL Documentation — Using EXPLAIN](https://www.postgresql.org/docs/current/using-explain.html) 2. [PostgreSQL Documentation — EXPLAIN](https://www.postgresql.org/docs/current/sql-explain.html) 3. [PostgreSQL Documentation — Statistics Used by the Planner](https://www.postgresql.org/docs/current/planner-stats.html) 4. [P. Selinger et al. — Access Path Selection in a Relational Database Management System (SIGMOD 1979)](https://dl.acm.org/doi/10.1145/582095.582099) 5. [MySQL — EXPLAIN Statement](https://dev.mysql.com/doc/refman/8.4/en/explain.html) 6. [SQLite — EXPLAIN QUERY PLAN](https://www.sqlite.org/eqp.html) --- # Уровни изоляции транзакций > Уровни изоляции определяют, какие эффекты параллельных транзакций видны друг другу — от Read Uncommitted до Serializable — и какие аномалии при этом допускаются. Источник: https://llmdocs.ru/wiki/isolation-levels/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Стандарт**: SQL-92 — четыре уровня - **Уровни**: Read Uncommitted, Read Committed, Repeatable Read, Serializable - **Аномалии стандарта**: грязное чтение, неповторяющееся чтение, фантомы - **Дополнительные аномалии**: потерянное обновление, перекос записи (write skew) - **Критика стандарта**: Беренсон и др. (1995) - **По умолчанию**: Read Committed (PostgreSQL, Oracle, SQL Server), Repeatable Read (MySQL InnoDB) **Уровень изоляции транзакций** — настройка СУБД, определяющая, насколько параллельно выполняющиеся [транзакции](https://llmdocs.ru/wiki/transaction-acid.md) изолированы друг от друга: видит ли одна транзакция незафиксированные или только что зафиксированные изменения другой. Полная изоляция — результат как при последовательном выполнении — дорога, поэтому стандарт [SQL](https://llmdocs.ru/wiki/sql.md) определяет несколько уровней, на которых ради производительности допускаются те или иные **аномалии**. Уровень изоляции — буква «I» в ACID и частый источник тонких ошибок: код, правильно работающий в тестах с одним пользователем, под нагрузкой теряет обновления или нарушает бизнес-правила. ## Аномалии | Аномалия | Что происходит | |---|---| | Грязное чтение (*dirty read*) | транзакция видит изменения другой, ещё не зафиксированные (и, возможно, отменённые) | | Неповторяющееся чтение (*non-repeatable read*) | повторное чтение той же строки даёт другое значение — её изменили и зафиксировали | | Фантомы (*phantom read*) | повторный запрос с тем же условием возвращает новые строки | | Потерянное обновление (*lost update*) | две транзакции читают значение, меняют его и записывают — одно изменение теряется | | Перекос записи (*write skew*) | две транзакции читают общие данные, принимают решения и меняют *разные* строки, вместе нарушая правило | Классический пример перекоса записи: в больнице должен дежурить хотя бы один врач. Два дежурных одновременно проверяют, что дежурных двое, и каждый снимает себя с дежурства. Каждая транзакция по отдельности корректна, а вместе они оставили больницу без врача. ## Уровни стандарта | Уровень | Грязное чтение | Неповторяющееся чтение | Фантомы | |---|---|---|---| | Read Uncommitted | возможно | возможно | возможны | | Read Committed | нет | возможно | возможны | | Repeatable Read | нет | нет | возможны | | Serializable | нет | нет | нет | Уже в 1995 году Беренсон и соавторы показали, что определения стандарта неполны и неоднозначны: они не учитывают потерянные обновления и перекос записи и не описывают широко используемую **изоляцию снимков** (*snapshot isolation*), при которой транзакция видит согласованный снимок базы на момент начала.[1] Поэтому реальные СУБД под одинаковыми названиями дают разные гарантии. ## Как это реализовано ### PostgreSQL Благодаря [MVCC](https://llmdocs.ru/wiki/mvcc.md) читатели никогда не блокируют писателей.[2] - **Read Committed** (по умолчанию) — каждый оператор видит данные, зафиксированные к моменту его начала. Грязного чтения нет, но два `SELECT` в одной транзакции могут увидеть разное. - **Repeatable Read** — изоляция снимков: вся транзакция видит один снимок. При попытке изменить строку, которую уже изменила параллельная транзакция, возникает ошибка сериализации. Фантомов нет, но перекос записи возможен. - **Serializable** — сериализуемая изоляция снимков (SSI, с версии 9.1): поверх снимков СУБД отслеживает опасные зависимости чтения и записи и прерывает одну из транзакций, если результат не мог бы получиться при последовательном выполнении.[3] - Read Uncommitted ведёт себя как Read Committed. ### Другие СУБД - **MySQL InnoDB** по умолчанию использует Repeatable Read: обычные чтения идут по снимку, а блокирующие чтения и изменения — с блокировками промежутков индекса (*gap locks*), предотвращающими фантомы.[4] - **Oracle** по умолчанию — Read Committed; его уровень Serializable на деле является изоляцией снимков. - **[SQLite](https://llmdocs.ru/wiki/sqlite.md)** выполняет записывающие транзакции по одной, поэтому фактически сериализуема. Сравнение гарантий разных систем и формальные модели согласованности собраны проектом Jepsen.[5] ## Как выбирать и что делать ```sql BEGIN ISOLATION LEVEL SERIALIZABLE; SELECT count(*) FROM doctors WHERE on_call AND shift_id = 42; UPDATE doctors SET on_call = false WHERE id = 7 AND shift_id = 42; COMMIT; -- может завершиться ошибкой 40001: could not serialize access ``` 1. **Read Committed** подходит для большинства запросов, если изменения выражены атомарно: `UPDATE accounts SET balance = balance - 100 WHERE id = 1 AND balance >= 100` вместо «прочитать в приложении — посчитать — записать». 2. **Явные блокировки** для критичных мест: `SELECT ... FOR UPDATE` блокирует прочитанные строки до конца транзакции и предотвращает потерянное обновление. 3. **Ограничения целостности** — `UNIQUE`, `CHECK`, исключающие ограничения — защищают инварианты на любом уровне изоляции. 4. **Serializable** — когда правила затрагивают несколько строк и их трудно выразить ограничениями. Приложение обязано уметь **повторять транзакцию** при ошибке сериализации (код 40001) — это нормальная часть работы, а не авария. 5. Держите транзакции короткими: чем дольше транзакция, тем выше вероятность конфликтов. Подробный разбор аномалий с примерами — в книге Мартина Клеппмана «Высоконагруженные приложения».[6] ## См. также - [Транзакция и ACID](https://llmdocs.ru/wiki/transaction-acid.md) - [MVCC](https://llmdocs.ru/wiki/mvcc.md) - [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) - [Состояние гонки и блокировки](https://llmdocs.ru/wiki/race-conditions-locks.md) - [Репликация баз данных](https://llmdocs.ru/wiki/replication.md) ## Источники 1. [H. Berenson et al. — A Critique of ANSI SQL Isolation Levels (SIGMOD 1995)](https://dl.acm.org/doi/10.1145/223784.223785) 2. [PostgreSQL Documentation — Transaction Isolation](https://www.postgresql.org/docs/current/transaction-iso.html) 3. [D. Ports, K. Grittner — Serializable Snapshot Isolation in PostgreSQL (VLDB 2012)](https://arxiv.org/abs/1208.4179) 4. [MySQL — Transaction Isolation Levels (InnoDB)](https://dev.mysql.com/doc/refman/8.4/en/innodb-transaction-isolation-levels.html) 5. [Jepsen — Consistency Models](https://jepsen.io/consistency) 6. [M. Kleppmann — Designing Data-Intensive Applications](https://dataintensive.net/) --- # MongoDB > Документоориентированная NoSQL-СУБД, хранящая данные как JSON-подобные документы BSON; гибкая схема, агрегационный конвейер, репликация через наборы реплик и встроенное шардирование. Источник: https://llmdocs.ru/wiki/mongodb/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: документоориентированная NoSQL-СУБД - **Разработчик**: MongoDB, Inc. (ранее 10gen) - **Первый выпуск**: 2009 - **Формат данных**: BSON (двоичный JSON) - **Язык запросов**: MQL, агрегационный конвейер - **Масштабирование**: наборы реплик, встроенное шардирование - **Лицензия**: SSPL (с октября 2018), ранее AGPL - **Порт по умолчанию**: 27017 **MongoDB** — документоориентированная [NoSQL](https://llmdocs.ru/wiki/nosql.md)-СУБД, самая популярная в своём классе. Вместо таблиц и строк она хранит **коллекции документов** — JSON-подобных объектов с вложенными полями и массивами, записанных в двоичном формате BSON. Схема документов не задаётся заранее, что упрощает быстрые изменения модели данных, а репликация и шардирование встроены в СУБД.[1] ## История MongoDB создали в 2007 году основатели DoubleClick — Дуайт Мерримен, Элиот Хоровиц и Кевин Райан — в компании 10gen как часть облачной платформы; в 2009 году СУБД выпустили отдельно с открытым кодом. Название — от английского *humongous* («огромный»). Ранние версии критиковали за потерю данных при настройках по умолчанию и глобальную блокировку записи; с переходом на движок хранения **WiredTiger** (3.0, 2015), появлением многодокументных транзакций (4.0, 2018) и усилением гарантий записи по умолчанию СУБД стала гораздо надёжнее. В 2018 году лицензия сменилась на SSPL, которую не признали открытой OSI и дистрибутивы Linux;[5] это открыло путь совместимым альтернативам вроде FerretDB (поверх [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md)). Облачный сервис компании — MongoDB Atlas. ## Модель данных ```json { "_id": ObjectId("6731f0c2e1a4b3d2c1a0f9e8"), "name": "Иван", "email": "ivan@example.com", "tags": ["admin", "beta"], "address": { "city": "Москва", "zip": "101000" }, "orders": [ { "sku": "A-17", "qty": 2, "price": 990 }, { "sku": "B-03", "qty": 1, "price": 4500 } ] } ``` BSON расширяет JSON типами дат, двоичных данных, `ObjectId`, 64-битных целых и `Decimal128`.[6] Максимальный размер документа — 16 МБ. Главный принцип моделирования — **данные, которые читаются вместе, хранятся вместе**.[2] Связи «один к немногим» обычно **встраивают** в документ (адрес, позиции заказа), а «один ко многим» с неограниченным ростом или «многие ко многим» — хранят отдельно со **ссылками** по `_id`. Это противоположно [нормализации](https://llmdocs.ru/wiki/normalization.md) в реляционных БД: дублирование данных допустимо ради быстрого чтения одним запросом. Гибкая схема не означает отсутствие схемы: со временем документы разных форм усложняют код. MongoDB поддерживает **валидацию по JSON Schema** на уровне коллекции, а [ORM](https://llmdocs.ru/wiki/orm.md)-подобные библиотеки (Mongoose, Beanie, ODM на Pydantic) задают схему в коде приложения. ## Запросы Работа ведётся через оболочку `mongosh` или драйверы (PyMongo, Motor, официальные драйверы для Go, Node.js, Java): ```javascript db.users.insertOne({ name: "Анна", tags: ["beta"], age: 28 }) db.users.find({ age: { $gte: 18 }, tags: "beta" }, { name: 1 }).sort({ age: -1 }).limit(10) db.users.updateOne({ name: "Анна" }, { $push: { tags: "admin" }, $inc: { logins: 1 } }) db.users.createIndex({ email: 1 }, { unique: true }) ``` Для аналитики служит **агрегационный конвейер** — последовательность стадий, похожая на конвейеры Unix:[3] ```javascript db.orders.aggregate([ { $match: { status: "paid", createdAt: { $gte: ISODate("2026-10-01") } } }, { $unwind: "$items" }, { $group: { _id: "$items.sku", revenue: { $sum: { $multiply: ["$items.qty", "$items.price"] } } } }, { $sort: { revenue: -1 } }, { $limit: 5 } ]) ``` Есть стадия `$lookup` — аналог LEFT JOIN, а также полнотекстовый и векторный поиск (в Atlas и с версии 8.x в самостоятельных установках) для задач [RAG](https://llmdocs.ru/wiki/rag.md). [Индексы](https://llmdocs.ru/wiki/database-index.md) строятся на [B-деревьях](https://llmdocs.ru/wiki/b-tree.md) и бывают составными, по элементам массивов (multikey), уникальными, частичными, TTL (автоматическое удаление старых документов), геопространственными. Запрос без подходящего индекса сканирует всю коллекцию — план проверяют через `.explain()`. ## Надёжность и масштабирование - **Набор реплик** (replica set) — один первичный узел и несколько вторичных; при отказе первичного узлы автоматически выбирают нового за секунды (см. [Репликация баз данных](https://llmdocs.ru/wiki/replication.md)). - **Гарантии записи и чтения** настраиваются: `writeConcern: "majority"` (по умолчанию с 5.0) подтверждает запись после попадания на большинство узлов. - **Транзакции** — операции над одним документом атомарны всегда; многодокументные ACID-транзакции есть с версии 4.0, но дороже и не рекомендуются как основной инструмент.[4] - **Шардирование** встроено: коллекция делится по ключу шардирования на чанки, маршрутизатор `mongos` направляет запросы, балансировщик переносит чанки между шардами (см. [Шардирование](https://llmdocs.ru/wiki/sharding.md)). ## Безопасность Старые версии по умолчанию слушали все интерфейсы без аутентификации, и тысячи открытых баз были украдены или зашифрованы вымогателями. Сейчас MongoDB по умолчанию слушает только `localhost`, но чек-лист остаётся обязательным: включить аутентификацию и ролевой доступ, TLS, [файрвол](https://llmdocs.ru/wiki/firewall.md), не выставлять порт 27017 в интернет.[7] В запросах важно не подставлять пользовательские объекты напрямую — иначе возможны NoSQL-инъекции с операторами `$ne`, `$where` (ср. [SQL-инъекция (как защищаться)](https://llmdocs.ru/wiki/sql-injection.md)). ## Когда выбирать MongoDB удобна для данных с естественной иерархической структурой (каталоги товаров с разными атрибутами, профили, контент, события), быстро меняющихся моделей и прототипов, горизонтального масштабирования записи. Реляционная СУБД лучше для данных с множеством связей, сложных отчётов с соединениями и строгой целостности. Стоит учитывать, что PostgreSQL с типом `jsonb` закрывает многие сценарии «документов» без отдельной СУБД. ## См. также - [NoSQL](https://llmdocs.ru/wiki/nosql.md) - [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) - [Redis](https://llmdocs.ru/wiki/redis.md) - [JSON](https://llmdocs.ru/wiki/json.md) ## Источники 1. [MongoDB Manual](https://www.mongodb.com/docs/manual/) 2. [MongoDB — Data Modeling](https://www.mongodb.com/docs/manual/data-modeling/) 3. [MongoDB — Aggregation Pipeline](https://www.mongodb.com/docs/manual/core/aggregation-pipeline/) 4. [MongoDB — Transactions](https://www.mongodb.com/docs/manual/core/transactions/) 5. [MongoDB — Server Side Public License FAQ](https://www.mongodb.com/legal/licensing/server-side-public-license/faq) 6. [BSON specification](https://bsonspec.org/) 7. [MongoDB — Security Checklist](https://www.mongodb.com/docs/manual/administration/security-checklist/) --- # MVCC > Многоверсионное управление параллельным доступом — СУБД хранит несколько версий строк, чтобы каждая транзакция видела согласованный снимок данных, а чтение не блокировало запись. Источник: https://llmdocs.ru/wiki/mvcc/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Полное название**: Multiversion Concurrency Control - **Идея**: каждая запись создаёт новую версию, старые остаются для текущих читателей - **Теория**: Дэвид Рид (1978), Бернстайн и Гудман (1981) - **Главное свойство**: читатели не блокируют писателей, писатели — читателей - **Хранение версий**: в таблице (PostgreSQL) или в журнале отката (Oracle, MySQL InnoDB) - **Очистка**: VACUUM (PostgreSQL), purge (InnoDB) **MVCC** (англ. *Multiversion Concurrency Control* — многоверсионное управление параллельным доступом) — метод, при котором СУБД хранит несколько версий одной и той же строки. Изменение не перезаписывает данные на месте, а создаёт новую версию; старая остаётся видимой транзакциям, которые начались раньше. Каждая транзакция работает со своим согласованным **снимком** базы, и главное следствие: **читатели не блокируют писателей, а писатели — читателей**.[1] MVCC используют [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md), Oracle, [MySQL InnoDB](https://llmdocs.ru/wiki/mysql-mariadb.md), SQL Server (в режиме снимков), CockroachDB и многие другие системы. На нём основаны [уровни изоляции](https://llmdocs.ru/wiki/isolation-levels.md) Read Committed и Repeatable Read в этих СУБД. ## Зачем Альтернатива — блокировки: чтобы прочитать строку, транзакция берёт разделяемую блокировку, чтобы изменить — исключительную. Тогда долгий аналитический запрос блокирует обновления, а массовое обновление останавливает отчёты. MVCC снимает этот конфликт: отчёт читает данные на момент своего начала, не мешая текущей работе. Блокировки остаются только между пишущими транзакциями, которые меняют одни и те же строки. Теоретические основы заложили диссертация Дэвида Рида (MIT, 1978) и обзор Филипа Бернстайна и Натана Гудмана (1981);[3] одной из первых коммерческих систем с MVCC стала InterBase в 1980-х. ## Как это устроено в PostgreSQL Каждая версия строки (*кортеж*) хранит в заголовке служебные поля:[6] - **`xmin`** — номер транзакции, создавшей версию; - **`xmax`** — номер транзакции, удалившей или заменившей её (0, если версия актуальна). `UPDATE` в PostgreSQL — это пометка старой версии как удалённой (запись `xmax`) и вставка новой. При чтении транзакция по своему снимку — списку завершённых и ещё активных транзакций — решает, какая версия ей видна: созданная до начала снимка зафиксированной транзакцией и не удалённая в пределах видимого. ```sql SELECT xmin, xmax, * FROM accounts WHERE id = 1; -- xmin | xmax | id | balance -- 7381 | 0 | 1 | 1000 UPDATE accounts SET balance = 900 WHERE id = 1; SELECT xmin, xmax, * FROM accounts WHERE id = 1; -- 7382 | 0 | 1 | 900 -- новая версия; старая осталась в таблице ``` ## Очистка: VACUUM Старые версии, которые уже не нужны ни одной транзакции, занимают место — это **«мёртвые» кортежи**. Их убирает процесс **VACUUM**, в нормальном режиме — фоновый **autovacuum**.[2] Если очистка не успевает, таблицы и индексы **раздуваются** (*bloat*): занимают в разы больше места и медленнее читаются. Вторая задача VACUUM — **заморозка** старых строк. Номера транзакций в PostgreSQL 32-битные и идут по кругу; если строки вовремя не пометить как «видимые всем», произойдёт переполнение счётчика (*transaction ID wraparound*), и СУБД остановит запись, чтобы не потерять данные. Поэтому autovacuum никогда не стоит отключать. Оптимизация **HOT** (*heap-only tuples*): если обновление не затрагивает индексированные столбцы и на странице есть место, новая версия кладётся рядом, и индексы не меняются. ## Другой подход: журнал отката В Oracle и MySQL InnoDB актуальная версия строки хранится на месте, а предыдущие — в отдельном **журнале отката** (*undo log*). Транзакция, которой нужна старая версия, восстанавливает её, проходя по цепочке записей отката.[4] | | В таблице (PostgreSQL) | В журнале отката (Oracle, InnoDB) | |---|---|---| | Обновление | новая версия в таблице | изменение на месте + запись в журнал | | Откат транзакции | мгновенный | нужно применить журнал | | Чтение старых версий | напрямую | восстановление из журнала | | Обслуживание | VACUUM, раздувание таблиц | очистка журнала, долгие транзакции раздувают его | Сравнение разных реализаций MVCC с замерами — в исследовании Ву и соавторов.[5] ## Практические следствия - **Долгие транзакции вредны.** Пока открыта старая транзакция (в том числе «зависшая» `idle in transaction`), VACUUM не может удалить версии, которые она теоретически может увидеть, и таблицы раздуваются. Их стоит отслеживать в `pg_stat_activity` и ограничивать параметром `idle_in_transaction_session_timeout`. - **Частые обновления одной строки** (счётчики, статусы) порождают много мёртвых версий — для таких таблиц настраивают более агрессивный autovacuum. - **`count(*)` по большой таблице** в PostgreSQL требует проверки видимости строк и не бывает мгновенным. - **Конфликты записи остаются.** MVCC не отменяет блокировок между пишущими транзакциями; для правил, затрагивающих несколько строк, нужны явные блокировки или уровень Serializable (см. [Транзакция и ACID](https://llmdocs.ru/wiki/transaction-acid.md)). ## См. также - [Уровни изоляции транзакций](https://llmdocs.ru/wiki/isolation-levels.md) - [Транзакция и ACID](https://llmdocs.ru/wiki/transaction-acid.md) - [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) - [Индекс (базы данных)](https://llmdocs.ru/wiki/database-index.md) - [Репликация баз данных](https://llmdocs.ru/wiki/replication.md) ## Источники 1. [PostgreSQL Documentation — Concurrency Control: Introduction](https://www.postgresql.org/docs/current/mvcc-intro.html) 2. [PostgreSQL Documentation — Routine Vacuuming](https://www.postgresql.org/docs/current/routine-vacuuming.html) 3. [P. Bernstein, N. Goodman — Concurrency Control in Distributed Database Systems (ACM Computing Surveys, 1981)](https://dl.acm.org/doi/10.1145/356842.356846) 4. [MySQL — InnoDB Multi-Versioning](https://dev.mysql.com/doc/refman/8.4/en/innodb-multi-versioning.html) 5. [Y. Wu et al. — An Empirical Evaluation of In-Memory Multi-Version Concurrency Control (VLDB 2017)](https://www.vldb.org/pvldb/vol10/p781-Wu.pdf) 6. [PostgreSQL Documentation — Database Page Layout](https://www.postgresql.org/docs/current/storage-page-layout.html) --- # MySQL и MariaDB > Самая распространённая открытая реляционная СУБД веба и её форк от создателей; движок InnoDB, репликация, сравнение с PostgreSQL и различия между ветками Oracle и MariaDB Foundation. Источник: https://llmdocs.ru/wiki/mysql-mariadb/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: реляционная СУБД - **MySQL — первый выпуск**: 1995 (MySQL AB, Швеция) - **MySQL — владелец**: Oracle (с 2010) - **MariaDB — форк**: 2009, Майкл Видениус - **Основной движок**: InnoDB (транзакции, MVCC, внешние ключи) - **Лицензия**: GPL v2 (+ коммерческая у MySQL) - **Порт по умолчанию**: 3306 **MySQL** — открытая [реляционная СУБД](https://llmdocs.ru/wiki/relational-database.md), одна из самых распространённых в мире, исторически — основа веба: буква «M» в стеке LAMP (Linux, Apache, MySQL, PHP). **MariaDB** — её форк, созданный в 2009 году основателем MySQL Майклом Видениусом после покупки Sun компанией Oracle. На MySQL построены WordPress, Drupal, ранние Facebook, YouTube, Twitter, а сегодня — крупнейшие сервисы через шардирующие надстройки вроде Vitess.[1][7] ## История MySQL создали в 1995 году шведская компания MySQL AB — Майкл Видениус, Давид Аксмарк и Аллан Ларссон. Название — по имени дочери Видениуса My (а MariaDB — по имени младшей дочери, Марии). Ранние версии были быстрыми, но упрощёнными: таблицы MyISAM не поддерживали транзакции и внешние ключи. Ситуацию изменил движок **InnoDB**, ставший основным в версии 5.5 (2010). В 2008 году MySQL AB купила Sun Microsystems, а в 2010-м Sun поглотила Oracle. Опасаясь за будущее проекта, Видениус основал MariaDB, а Percona выпускает собственную сборку Percona Server. С 2023 года у MySQL модель с LTS-выпусками (8.4, затем 9.7) и промежуточными «Innovation»-версиями.[3] ## Архитектура Особенность MySQL — **подключаемые движки хранения**: SQL-слой (разбор, оптимизация) отделён от слоя, хранящего данные. - **InnoDB** — движок по умолчанию: [ACID-транзакции](https://llmdocs.ru/wiki/transaction-acid.md), построчные блокировки, [MVCC](https://llmdocs.ru/wiki/mvcc.md), внешние ключи, восстановление после сбоя. Таблицы хранятся как кластерный индекс по первичному ключу ([B+-дерево](https://llmdocs.ru/wiki/b-tree.md)): строки физически упорядочены по ключу, а вторичные индексы ссылаются на первичный ключ.[5] - **MyISAM** — устаревший нетранзакционный движок. - В MariaDB дополнительно Aria, ColumnStore (колоночный, см. [Колоночное хранение](https://llmdocs.ru/wiki/columnar-storage.md)), Spider (шардирование). Из кластерного индекса вытекает практический совет: первичный ключ должен быть коротким и монотонным (автоинкремент или UUIDv7), иначе вставки фрагментируют таблицу. ## MySQL и MariaDB сегодня Изначально MariaDB был совместимой заменой «один в один», но к 2020-м годам ветки разошлись:[4] | | MySQL (Oracle) | MariaDB | |---|---|---| | Развитие | Oracle, часть функций — в коммерческой Enterprise | MariaDB Foundation и MariaDB plc, открытое | | JSON | бинарный тип `JSON` | `JSON` — псевдоним `LONGTEXT` с проверкой | | Репликация | GTID MySQL, Group Replication, InnoDB Cluster | свой формат GTID, Galera Cluster | | Особенности | оконные функции, CTE, `EXPLAIN ANALYZE` | системно-версионированные таблицы, последовательности, векторный тип (11.7+) | | Дистрибутивы Linux | Ubuntu, Oracle Linux | по умолчанию в Debian, RHEL, Fedora, Arch | Переход между ними на новых версиях уже не гарантированно бесшовен — особенно с бинарными данными репликации и JSON. ## Быстрый старт ```bash docker run -d --name db -e MARIADB_ROOT_PASSWORD=secret -p 3306:3306 mariadb:11 mysql -h 127.0.0.1 -u root -p ``` ```sql CREATE DATABASE shop CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; CREATE TABLE orders ( id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY, user_id BIGINT NOT NULL, total DECIMAL(10,2) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, INDEX idx_user (user_id) ) ENGINE=InnoDB; ``` Ловушка из прошлого: кодировка `utf8` в MySQL — на самом деле трёхбайтовая `utf8mb3`, она не вмещает эмодзи и часть символов [Unicode](https://llmdocs.ru/wiki/unicode-utf8.md). Всегда используйте `utf8mb4` (по умолчанию с MySQL 8.0). Другая ловушка — нестрогий режим SQL в старых версиях, при котором неверные значения молча обрезались; сейчас `STRICT_TRANS_TABLES` включён по умолчанию. ## Репликация и масштабирование MySQL давно славится простой [репликацией](https://llmdocs.ru/wiki/replication.md): основной сервер пишет бинарный журнал (binlog), реплики его применяют. Варианты — асинхронная, полусинхронная, Group Replication с автоматическим выбором лидера. Binlog также служит источником для захвата изменений (CDC) через Debezium. Для [шардирования](https://llmdocs.ru/wiki/sharding.md) используют Vitess (разработан в YouTube, применяется в Slack, GitHub, Shopify) и прокси ProxySQL. ## MySQL или PostgreSQL Обе СУБД зрелые и подходят для большинства задач. [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) богаче по возможностям SQL (типы, расширения вроде PostGIS и pgvector, частичные индексы, транзакционный DDL) и строже к стандарту; поэтому в новых проектах в 2020-х его выбирают чаще. MySQL проще в эксплуатации репликации, имеет огромную базу установок, хостинга и специалистов, хорошо проверен на очень высоких нагрузках чтения. По рейтингу DB-Engines MySQL остаётся второй по популярности СУБД после Oracle.[6] ## Инструменты - `mysqldump` / `mariadb-dump` — логические бэкапы; Percona XtraBackup и Mariabackup — горячие физические (см. [Бэкапы: правило 3-2-1](https://llmdocs.ru/wiki/backup-3-2-1.md)); - MySQL Shell, MySQL Workbench, DBeaver — клиенты; - `pt-online-schema-change`, gh-ost — изменение больших таблиц без блокировок (см. [Миграции схемы БД](https://llmdocs.ru/wiki/schema-migrations.md)); - драйверы: PyMySQL и mysqlclient (Python), go-sql-driver/mysql, `mysql2` (Node.js). ## См. также - [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) - [SQL](https://llmdocs.ru/wiki/sql.md) - [Репликация баз данных](https://llmdocs.ru/wiki/replication.md) - [SQLite](https://llmdocs.ru/wiki/sqlite.md) ## Источники 1. [MySQL 8.4 Reference Manual](https://dev.mysql.com/doc/refman/8.4/en/) 2. [MariaDB Documentation](https://mariadb.com/docs/) 3. [MySQL — Release model (LTS and Innovation)](https://dev.mysql.com/doc/refman/8.4/en/mysql-releases.html) 4. [MariaDB versus MySQL: Compatibility](https://mariadb.com/kb/en/mariadb-vs-mysql-compatibility/) 5. [MySQL — The InnoDB Storage Engine](https://dev.mysql.com/doc/refman/8.4/en/innodb-storage-engine.html) 6. [DB-Engines Ranking](https://db-engines.com/en/ranking) 7. [Vitess — scalable MySQL clustering](https://vitess.io/) --- # Нормализация > Процесс проектирования схемы реляционной базы данных, устраняющий дублирование и аномалии обновления путём разбиения таблиц по нормальным формам (1НФ, 2НФ, 3НФ, НФБК); денормализация — обратный шаг ради скорости чтения. Источник: https://llmdocs.ru/wiki/normalization/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Автор теории**: Эдгар Кодд (1970–1971) - **Основные формы**: 1НФ, 2НФ, 3НФ, нормальная форма Бойса — Кодда (НФБК) - **Высшие формы**: 4НФ (Фейгин, 1977), 5НФ (1979), 6НФ - **Цель**: устранить дублирование и аномалии вставки, обновления, удаления - **Ключевое понятие**: функциональная зависимость - **Обратный процесс**: денормализация **Нормализация** — процесс проектирования схемы [реляционной базы данных](https://llmdocs.ru/wiki/relational-database.md), при котором таблицы разбиваются так, чтобы каждый факт хранился ровно в одном месте. Это устраняет дублирование данных и связанные с ним **аномалии**: когда изменение приходится делать в нескольких местах, а забытое место оставляет базу в противоречивом состоянии. Уровни нормализованности называются **нормальными формами**; теорию заложил Эдгар Кодд в 1970–1971 годах.[1] Обратный шаг — **денормализация** — сознательное дублирование данных ради скорости чтения. ## Проблема: аномалии Рассмотрим таблицу заказов, в которой всё хранится вместе: | order_id | customer | customer_phone | product | category | price | qty | |---|---|---|---|---|---|---| | 1 | Алиса | +7 900 111-11-11 | Ноутбук | Электроника | 90 000 | 1 | | 1 | Алиса | +7 900 111-11-11 | Мышь | Электроника | 1 500 | 2 | | 2 | Борис | +7 900 222-22-22 | Мышь | Электроника | 1 500 | 1 | - **Аномалия обновления:** Алиса сменила телефон — его нужно исправить во всех её строках; пропущенная строка создаст противоречие. - **Аномалия вставки:** нельзя добавить новый товар, пока его никто не заказал. - **Аномалия удаления:** удалив единственный заказ Бориса, мы потеряем и его телефон. ## Функциональные зависимости Нормальные формы формулируются через **функциональные зависимости**: столбец *B* зависит от *A*, если значение *A* однозначно определяет *B*. Здесь `customer → customer_phone`, `product → category, price`, а `(order_id, product) → qty`. Нормализация приводит таблицы к виду, где каждый неключевой столбец зависит от ключа — «от ключа, от всего ключа и ни от чего, кроме ключа». ## Нормальные формы | Форма | Требование | Нарушение в примере | |---|---|---| | **1НФ** | все значения атомарны, нет повторяющихся групп и списков в ячейке | столбец «товары» со списком через запятую | | **2НФ** | 1НФ, и неключевые столбцы зависят от *всего* составного ключа | `price` зависит только от `product`, а не от пары `(order_id, product)` | | **3НФ** | 2НФ, и нет транзитивных зависимостей неключевых столбцов друг от друга | `customer_phone` зависит от `customer`, а не от ключа заказа | | **НФБК** | каждый детерминант — потенциальный ключ | редкие случаи с перекрывающимися ключами | | **4НФ, 5НФ** | нет многозначных зависимостей и зависимостей соединения | несколько независимых списков в одной таблице | Четвёртую форму ввёл Рональд Фейгин в 1977 году;[3] понятное объяснение всех пяти форм дал Уильям Кент в статье «Простое руководство по пяти нормальным формам».[2] На практике чаще всего стремятся к **третьей нормальной форме** или НФБК. ## Нормализованная схема ```sql CREATE TABLE customers ( id bigint PRIMARY KEY, name text NOT NULL, phone text ); CREATE TABLE products ( id bigint PRIMARY KEY, name text NOT NULL UNIQUE, category text NOT NULL, price numeric(12, 2) NOT NULL CHECK (price >= 0) ); CREATE TABLE orders ( id bigint PRIMARY KEY, customer_id bigint NOT NULL REFERENCES customers(id), created_at timestamptz NOT NULL DEFAULT now() ); CREATE TABLE order_items ( order_id bigint NOT NULL REFERENCES orders(id), product_id bigint NOT NULL REFERENCES products(id), qty int NOT NULL CHECK (qty > 0), unit_price numeric(12, 2) NOT NULL, -- цена на момент покупки PRIMARY KEY (order_id, product_id) ); ``` Телефон хранится в одном месте, товар существует независимо от заказов, а связи обеспечиваются внешними ключами.[5] Обратите внимание на `unit_price`: это не дублирование, а другой факт — цена *в момент заказа*, которая не должна меняться вместе с текущей ценой товара. ## Денормализация Нормализованная схема требует соединений (`JOIN`) при чтении, и на больших объёмах или в горячих запросах это может стать узким местом. Тогда часть данных дублируют сознательно: - хранят вычисляемые итоги (сумма заказа, число комментариев) рядом с сущностью; - копируют редко меняющиеся атрибуты, чтобы избежать соединения; - строят материализованные представления и витрины для отчётов; - в аналитических хранилищах используют схему «звезда» с широкими таблицами фактов (см. [Колоночное хранение](https://llmdocs.ru/wiki/columnar-storage.md)). Денормализация переносит ответственность за согласованность на приложение, триггеры или процессы обновления, поэтому её применяют точечно — после того как узкое место подтверждено измерениями ([EXPLAIN и план запроса](https://llmdocs.ru/wiki/explain.md)), а не заранее. ## Нормализация и NoSQL Документные базы ([MongoDB](https://llmdocs.ru/wiki/mongodb.md) и другие [NoSQL](https://llmdocs.ru/wiki/nosql.md)-системы) часто хранят связанные данные вложенными документами — по сути, денормализованно, — оптимизируя под конкретные сценарии чтения. Это удобно, когда данные читаются целиком и редко меняются по частям, но аномалии обновления никуда не исчезают: их просто приходится решать в коде. ## Практические советы - Начинайте с нормализованной схемы (3НФ) и денормализуйте по результатам измерений. - Выражайте правила ограничениями — `PRIMARY KEY`, `UNIQUE`, `FOREIGN KEY`, `CHECK` — чтобы база сама защищала целостность. - Не храните списки в одной ячейке через запятую — для связи «многие ко многим» нужна отдельная таблица. - Изменения схемы проводите [миграциями](https://llmdocs.ru/wiki/schema-migrations.md). Краткое введение в основы нормализации есть в документации Microsoft.[4] ## См. также - [Реляционная база данных](https://llmdocs.ru/wiki/relational-database.md) - [SQL](https://llmdocs.ru/wiki/sql.md) - [Индекс (базы данных)](https://llmdocs.ru/wiki/database-index.md) - [Миграции схемы БД](https://llmdocs.ru/wiki/schema-migrations.md) - [NoSQL](https://llmdocs.ru/wiki/nosql.md) ## Источники 1. [E. F. Codd — A Relational Model of Data for Large Shared Data Banks (CACM, 1970)](https://dl.acm.org/doi/10.1145/362384.362685) 2. [W. Kent — A Simple Guide to Five Normal Forms in Relational Database Theory (1983)](https://www.bkent.net/Doc/simple5.htm) 3. [R. Fagin — Multivalued Dependencies and a New Normal Form for Relational Databases (1977)](https://dl.acm.org/doi/10.1145/320557.320571) 4. [Microsoft Learn — Description of the database normalization basics](https://learn.microsoft.com/en-us/office/troubleshoot/access/database-normalization-description) 5. [PostgreSQL Documentation — Constraints](https://www.postgresql.org/docs/current/ddl-constraints.html) --- # NoSQL > Общее название нереляционных баз данных — ключ-значение, документных, колоночных и графовых, — появившихся ради горизонтального масштабирования, гибких схем и особых моделей данных. Источник: https://llmdocs.ru/wiki/nosql/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Расшифровка**: «не только SQL» (Not only SQL) - **Возрождение термина**: 2009 - **Типы**: ключ-значение, документные, широкие колонки, графовые - **Примеры**: Redis, DynamoDB, MongoDB, Cassandra, HBase, Neo4j - **Основополагающие работы**: Google Bigtable (2006), Amazon Dynamo (2007) - **Модель согласованности**: часто BASE и итоговая согласованность **NoSQL** — собирательное название баз данных, которые не следуют классической [реляционной модели](https://llmdocs.ru/wiki/relational-database.md) с таблицами, жёсткой схемой и языком [SQL](https://llmdocs.ru/wiki/sql.md). Сейчас термин чаще расшифровывают как «не только SQL» (*Not only SQL*). Под ним объединяют очень разные системы: хранилища «ключ — значение», документные, колоночные и графовые базы. Общее у них — отказ от части возможностей реляционных СУБД ради горизонтального масштабирования, гибкой схемы, высокой доступности или более подходящей модели данных. ## История Название впервые использовал Карло Строцци в 1998 году для своей облегчённой реляционной базы без SQL-интерфейса. Современное значение термин получил в 2009 году, когда на встрече в Сан-Франциско обсуждали распределённые нереляционные хранилища. Им предшествовали работы интернет-гигантов, столкнувшихся с объёмами, которые не помещались на один сервер: Google описала **Bigtable** (2006),[1] Amazon — **Dynamo** (2007).[2] На их идеях выросли HBase, Cassandra, Riak, DynamoDB. Параллельно появились документная MongoDB (2009) и графовая Neo4j. ## Типы NoSQL-баз | Тип | Модель | Примеры | Типичные задачи | |---|---|---|---| | Ключ — значение | словарь: ключ → значение | [Redis](https://llmdocs.ru/wiki/redis.md), DynamoDB, etcd | кэш, сессии, конфигурация | | Документные | JSON-подобные документы с вложенностью | [MongoDB](https://llmdocs.ru/wiki/mongodb.md), Couchbase, Firestore | каталоги, профили, контент | | Широкие колонки | строки с переменным набором столбцов, распределённые по ключу | Cassandra, HBase, ScyllaDB | журналы событий, телеметрия, огромные объёмы записи | | Графовые | вершины и рёбра со свойствами | Neo4j, JanusGraph | социальные связи, рекомендации, графы знаний | Отдельно стоят векторные базы для [эмбеддингов](https://llmdocs.ru/wiki/embedding.md) (см. [pgvector и векторные БД](https://llmdocs.ru/wiki/pgvector.md)), базы временных рядов (InfluxDB, TimescaleDB) и поисковые движки (Elasticsearch, OpenSearch), которые тоже иногда относят к NoSQL. ## Примеры моделей Документ в MongoDB хранит заказ со всеми позициями внутри — то, что в реляционной базе заняло бы несколько таблиц: ```json { "_id": "ord-1001", "customer": {"id": 42, "name": "Алиса"}, "items": [ {"sku": "BOOK-1", "qty": 1, "price": 900}, {"sku": "PEN-7", "qty": 3, "price": 50} ], "status": "paid" } ``` В графовой базе запрос «друзья друзей, которые купили этот товар» выражается естественно на языке Cypher:[6] ```cypher MATCH (me:User {id: 42})-[:FRIEND]->()-[:FRIEND]->(fof)-[:BOUGHT]->(p:Product {sku: "BOOK-1"}) RETURN DISTINCT fof.name ``` ## Согласованность: ACID, BASE и CAP Многие распределённые NoSQL-системы ради доступности и масштабирования отказывались от строгих [ACID-транзакций](https://llmdocs.ru/wiki/transaction-acid.md) в пользу модели **BASE** (*Basically Available, Soft state, Eventual consistency*): система всегда отвечает, но реплики могут какое-то время расходиться и сходятся со временем (*итоговая согласованность*). Компромисс формализует [CAP-теорема](https://llmdocs.ru/wiki/cap-theorem.md): при сетевом разделении распределённая система вынуждена выбирать между согласованностью и доступностью.[3] Cassandra и Dynamo выбирают доступность с настраиваемыми кворумами, HBase и etcd — согласованность. ## Сильные стороны - **Горизонтальное масштабирование.** Данные изначально распределяются по многим узлам ([шардирование](https://llmdocs.ru/wiki/sharding.md) встроено), и кластер растёт добавлением серверов. - **Гибкая схема.** Документы одной коллекции могут иметь разную структуру; новые поля добавляются без миграций. - **Модель под задачу.** Агрегат, который читается целиком, хранится вместе — без соединений; связи в графе обходятся быстрее рекурсивных SQL-запросов. - **Высокая доступность** и запись в нескольких дата-центрах. ## Слабые стороны - **Запросы проектируются заранее.** В Cassandra таблицы строят под конкретные запросы; новый вид выборки может потребовать новой таблицы и дублирования данных. - **Целостность в коде.** Нет внешних ключей и часто нет транзакций между документами — согласованность обеспечивает приложение (см. [Нормализация](https://llmdocs.ru/wiki/normalization.md)). - **Разнородность.** Каждая система — свой язык запросов, инструменты и подводные камни. ## Сближение миров Границы размылись. Реляционные СУБД научились хранить документы ([PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) с `jsonb`), векторы и временные ряды; появились распределённые SQL-базы (CockroachDB, YugabyteDB, Google Spanner) с горизонтальным масштабированием и ACID. NoSQL-системы, в свою очередь, добавили транзакции (MongoDB с версии 4.0) и SQL-подобные языки. Мартин Фаулер и Прамод Садаладж описали этот подход как **полиглотное хранение**: каждая часть системы использует подходящее ей хранилище.[4] Для многих проектов разумная отправная точка — PostgreSQL, а специализированные базы добавляются под конкретные нагрузки. ## См. также - [Redis](https://llmdocs.ru/wiki/redis.md) - [MongoDB](https://llmdocs.ru/wiki/mongodb.md) - [CAP-теорема](https://llmdocs.ru/wiki/cap-theorem.md) - [Реляционная база данных](https://llmdocs.ru/wiki/relational-database.md) - [Шардирование](https://llmdocs.ru/wiki/sharding.md) ## Источники 1. [F. Chang et al. — Bigtable: A Distributed Storage System for Structured Data (OSDI 2006)](https://research.google/pubs/bigtable-a-distributed-storage-system-for-structured-data/) 2. [G. DeCandia et al. — Dynamo: Amazon's Highly Available Key-value Store (SOSP 2007)](https://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf) 3. [S. Gilbert, N. Lynch — Brewer's conjecture and the feasibility of consistent, available, partition-tolerant web services (2002)](https://dl.acm.org/doi/10.1145/564585.564601) 4. [P. Sadalage, M. Fowler — NoSQL Distilled](https://martinfowler.com/books/nosql.html) 5. [Apache Cassandra Documentation](https://cassandra.apache.org/doc/latest/) 6. [Neo4j — Cypher Manual: Introduction](https://neo4j.com/docs/cypher-manual/current/introduction/) --- # ORM > Объектно-реляционное отображение — библиотеки, которые связывают классы программы с таблицами реляционной БД и строят SQL-запросы из кода; удобство и переносимость в обмен на риск N+1 запросов и скрытой сложности. Источник: https://llmdocs.ru/wiki/orm/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Назначение**: отображение объектов кода на строки таблиц - **Паттерны**: Active Record, Data Mapper, Unit of Work - **Python**: SQLAlchemy, Django ORM, SQLModel, Tortoise, Peewee - **JavaScript/TypeScript**: Prisma, Drizzle, TypeORM, Sequelize - **Go и Rust**: GORM, ent, sqlc (генератор); Diesel, SeaORM, sqlx (без ORM) - **Java и .NET**: Hibernate (JPA), Entity Framework **ORM** (англ. *object-relational mapping* — объектно-реляционное отображение) — техника и библиотеки, которые связывают классы и объекты в коде программы с таблицами и строками [реляционной базы данных](https://llmdocs.ru/wiki/relational-database.md). Вместо того чтобы писать [SQL](https://llmdocs.ru/wiki/sql.md) вручную и разбирать результаты, разработчик работает с объектами: `user.orders`, `session.add(order)`, — а ORM генерирует запросы, подставляет параметры и преобразует типы. Популярные ORM — SQLAlchemy и Django ORM в Python, Hibernate в Java, Entity Framework в .NET, Prisma в TypeScript, GORM в Go.[1] ## Проблема, которую решает ORM Объектная модель программы и реляционная модель БД устроены по-разному: у объектов есть наследование, вложенность, ссылки и коллекции, у таблиц — строки, внешние ключи и соединения. Это расхождение называют **объектно-реляционным несоответствием импеданса** (*impedance mismatch*). ORM берёт на себя рутину на стыке: построение запросов, отслеживание изменённых объектов, транзакции, загрузку связанных данных и преобразование типов (даты, decimal, JSON, перечисления). ## Паттерны Мартин Фаулер описал два основных подхода:[1] - **Active Record** — объект сам знает, как себя сохранять: `post.save()`, `Post.objects.filter(...)`. Просто и наглядно; так устроены Django ORM, Ruby on Rails ActiveRecord, Eloquent в Laravel. - **Data Mapper** — объекты ничего не знают о базе, сохранением занимается отдельный слой (сессия, репозиторий). Гибче для сложных доменных моделей; так устроены SQLAlchemy, Hibernate, Doctrine. Вместе с Data Mapper обычно используется **Unit of Work**: сессия копит изменения объектов и записывает их одной [транзакцией](https://llmdocs.ru/wiki/transaction-acid.md) при `commit()`. ## Пример: SQLAlchemy 2.0 ```python from sqlalchemy import ForeignKey, String, create_engine, select from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship, Session class Base(DeclarativeBase): pass class User(Base): __tablename__ = "users" id: Mapped[int] = mapped_column(primary_key=True) email: Mapped[str] = mapped_column(String(255), unique=True) orders: Mapped[list["Order"]] = relationship(back_populates="user") class Order(Base): __tablename__ = "orders" id: Mapped[int] = mapped_column(primary_key=True) user_id: Mapped[int] = mapped_column(ForeignKey("users.id")) total: Mapped[int] user: Mapped[User] = relationship(back_populates="orders") engine = create_engine("postgresql+psycopg://app@localhost/shop") with Session(engine) as session: stmt = select(User).where(User.email.like("%@example.com")) for user in session.scalars(stmt): print(user.email, len(user.orders)) ``` Аннотации `Mapped[...]` используют [типизацию Python](https://llmdocs.ru/wiki/type-hints.md), поэтому модели проверяются mypy и подсказываются IDE.[2] В [FastAPI](https://llmdocs.ru/wiki/fastapi.md) популярен SQLModel — надстройка, объединяющая модели SQLAlchemy и [Pydantic](https://llmdocs.ru/wiki/dataclasses-pydantic.md). ## Достоинства - **Меньше шаблонного кода** — CRUD-операции в одну строку. - **Безопасность** — запросы параметризуются автоматически, что защищает от [SQL-инъекций](https://llmdocs.ru/wiki/sql-injection.md). - **Переносимость** — один код для [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md), [MySQL](https://llmdocs.ru/wiki/mysql-mariadb.md), [SQLite](https://llmdocs.ru/wiki/sqlite.md) (в тестах удобно подменить базу). - **Типы и автодополнение**, рефакторинг через IDE. - **Интеграция с миграциями** — изменения моделей превращаются в [миграции](https://llmdocs.ru/wiki/schema-migrations.md) (Alembic, Django migrations, Prisma Migrate). ## Недостатки и ловушки **Проблема N+1 запросов.** Самая частая ошибка: при обходе списка ORM лениво подгружает связанные объекты отдельным запросом для каждого элемента. ```python for user in session.scalars(select(User)): # 1 запрос print(len(user.orders)) # + N запросов ``` Решение — явная «жадная» загрузка: `selectinload(User.orders)` или `joinedload` в SQLAlchemy, `select_related` и `prefetch_related` в [Django](https://llmdocs.ru/wiki/django.md),[4] `include` в Prisma.[5] Обнаружить проблему помогает логирование SQL (`echo=True`) и инструменты вроде django-debug-toolbar. Другие проблемы: - **Скрытая сложность** — непонятно, какой SQL будет выполнен; неэффективные запросы обнаруживаются только в продакшене. Нужно смотреть сгенерированный SQL и его план (см. [EXPLAIN и план запроса](https://llmdocs.ru/wiki/explain.md)). - **Протекающая абстракция** — для сложных отчётов, оконных функций, `UPSERT`, CTE и специфичных возможностей СУБД всё равно приходится спускаться к SQL. - **Наименьший общий знаменатель** — ради переносимости легко отказаться от сильных сторон конкретной базы. - **Массовые операции** через объекты медленны: загрузить миллион объектов, изменить и сохранить — намного дороже одного `UPDATE`. Тед Ньюард в 2006 году назвал ORM «Вьетнамом информатики» — болотом, в котором проект увязает по мере роста.[6] Сегодня позиция сообщества спокойнее: ORM хороши для типового CRUD, а для сложных запросов используют SQL. ## Альтернативы - **Построители запросов** (query builders) — SQLAlchemy Core, Knex, Kysely, Drizzle, jOOQ: SQL-подобный код с типами и параметрами, без отображения объектов. - **Генераторы кода из SQL** — sqlc для [Go](https://llmdocs.ru/wiki/go.md) пишет типизированные функции по SQL-файлам,[7] sqlx в Rust проверяет запросы против базы во время компиляции. - **«Сырой» SQL** через драйвер с параметрами — максимальный контроль. - **Micro-ORM** (Dapper в .NET) — только маппинг результатов в объекты. Нередко в одном проекте ORM используется для обычных операций, а критичные по производительности запросы пишутся на SQL. ## См. также - [SQL](https://llmdocs.ru/wiki/sql.md) - [Миграции схемы БД](https://llmdocs.ru/wiki/schema-migrations.md) - [Django](https://llmdocs.ru/wiki/django.md) - [Индекс (базы данных)](https://llmdocs.ru/wiki/database-index.md) ## Источники 1. [Martin Fowler — Patterns of Enterprise Application Architecture (Active Record, Data Mapper, Unit of Work)](https://martinfowler.com/eaaCatalog/) 2. [SQLAlchemy 2.0 documentation — ORM Quick Start](https://docs.sqlalchemy.org/en/20/orm/quickstart.html) 3. [Django — Making queries](https://docs.djangoproject.com/en/stable/topics/db/queries/) 4. [Django — Database access optimization](https://docs.djangoproject.com/en/stable/topics/db/optimization/) 5. [Prisma documentation](https://www.prisma.io/docs) 6. [Ted Neward — The Vietnam of Computer Science (2006)](https://www.odbms.org/wp-content/uploads/2013/11/031.01-Neward-The-Vietnam-of-Computer-Science-June-2006.pdf) 7. [sqlc documentation](https://docs.sqlc.dev/) --- # pgvector и векторные БД > pgvector — расширение PostgreSQL для хранения векторов-эмбеддингов и поиска ближайших соседей; векторные БД — специализированные системы для той же задачи. Источник: https://llmdocs.ru/wiki/pgvector/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: расширение PostgreSQL - **Автор**: Эндрю Кейн - **Первый выпуск**: 2021 - **Лицензия**: PostgreSQL License - **Типы данных**: vector, halfvec, bit, sparsevec - **Индексы**: HNSW, IVFFlat - **Метрики**: L2, скалярное произведение, косинусное расстояние, L1, Хэмминг, Жаккар - **Альтернативы**: Qdrant, Milvus, Weaviate, Chroma, Pinecone, FAISS **pgvector** — расширение для [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md), добавляющее тип данных для векторов и операторы поиска ближайших соседей. С его помощью в обычной таблице можно хранить [эмбеддинги](https://llmdocs.ru/wiki/embedding.md) — числовые представления текстов, изображений или товаров — и находить записи, наиболее похожие на запрос. **Векторными базами данных** называют системы, специально созданные для хранения векторов и быстрого [векторного поиска](https://llmdocs.ru/wiki/vector-search.md): Qdrant, Milvus, Weaviate, Chroma, Pinecone и другие. Интерес к обоим подходам резко вырос с распространением больших языковых моделей: векторный поиск — основа [RAG](https://llmdocs.ru/wiki/rag.md), семантического поиска, рекомендаций и поиска дубликатов. ## Зачем нужен векторный поиск Модель-кодировщик превращает фрагмент текста в вектор из сотен или тысяч чисел так, что близкие по смыслу тексты дают близкие векторы. Поиск «похожих документов» сводится к поиску векторов, ближайших к вектору запроса. Точный перебор всех векторов надёжен, но на миллионах записей медленный, поэтому применяют **приближённый поиск ближайших соседей** (ANN, *approximate nearest neighbor*): он жертвует небольшой долей точности (*recall*) ради ускорения на порядки. ## pgvector Расширение создал Эндрю Кейн в 2021 году; распространяется под той же лицензией, что и PostgreSQL, и доступно у большинства облачных провайдеров.[1] ### Типы и операторы | Тип | Описание | |---|---| | `vector(n)` | вектор из `n` чисел одинарной точности | | `halfvec(n)` | половинная точность — вдвое меньше места | | `bit(n)` | двоичный вектор (для бинарной квантизации) | | `sparsevec(n)` | разреженный вектор, хранит только ненулевые элементы | | Оператор | Расстояние | |---|---| | `<->` | евклидово (L2) | | `<#>` | отрицательное скалярное произведение | | `<=>` | косинусное расстояние | | `<+>` | манхэттенское (L1) | Типы `halfvec`, `sparsevec` и оператор L1 появились в версии 0.7.0 (2024).[2] ### Индексы Без индекса pgvector выполняет точный поиск полным перебором. Для приближённого поиска есть два вида [индексов](https://llmdocs.ru/wiki/database-index.md): - **HNSW** (*Hierarchical Navigable Small World*) — многоуровневый граф близости, в котором поиск спускается от редких «дальних» связей к плотным локальным.[3] Даёт лучшее соотношение скорости и точности, но строится дольше и занимает больше памяти. Добавлен в версии 0.5.0 (2023). - **IVFFlat** — векторы разбиваются на кластеры (списки), и поиск просматривает только несколько ближайших кластеров. Строится быстрее, но индекс нужно создавать после загрузки данных, а точность сильнее зависит от параметров. ### Пример ```sql CREATE EXTENSION IF NOT EXISTS vector; CREATE TABLE chunks ( id bigserial PRIMARY KEY, doc_id bigint NOT NULL, content text NOT NULL, embedding vector(1024) ); CREATE INDEX ON chunks USING hnsw (embedding vector_cosine_ops); -- 5 фрагментов, ближайших к вектору запроса, только из нужного документа SELECT id, content, embedding <=> $1 AS distance FROM chunks WHERE doc_id = 42 ORDER BY embedding <=> $1 LIMIT 5; -- точность/скорость HNSW во время запроса SET hnsw.ef_search = 100; ``` Главное преимущество pgvector — векторы живут рядом с остальными данными: в одном запросе можно сочетать векторную близость с фильтрами по обычным столбцам, соединениями и полнотекстовым поиском, а изменения подчиняются [транзакциям](https://llmdocs.ru/wiki/transaction-acid.md), резервному копированию и [репликации](https://llmdocs.ru/wiki/replication.md) PostgreSQL. Ограничение — индексы поддерживают векторы до 2000 измерений для `vector` и до 4000 для `halfvec`.[1] ## Специализированные векторные БД | Система | Особенности | |---|---| | Qdrant | на Rust, фильтрация по полезной нагрузке, квантизация[5] | | Milvus | распределённая, рассчитана на миллиарды векторов | | Weaviate | встроенные модули векторизации, гибридный поиск | | Chroma | лёгкая встраиваемая база для прототипов | | Pinecone | управляемый облачный сервис | | FAISS | не база, а библиотека ANN-поиска от Meta[4] | Векторные функции добавили и универсальные системы: Elasticsearch и OpenSearch, [Redis](https://llmdocs.ru/wiki/redis.md), [MongoDB](https://llmdocs.ru/wiki/mongodb.md) (Atlas Vector Search), [ClickHouse](https://llmdocs.ru/wiki/clickhouse.md), [SQLite](https://llmdocs.ru/wiki/sqlite.md) (расширение sqlite-vec). ## Как выбирать - **До нескольких миллионов векторов, данные уже в PostgreSQL** — pgvector обычно достаточно и избавляет от второй системы, синхронизации и отдельного бэкапа. - **Сотни миллионов и миллиарды векторов, высокая нагрузка, сложная квантизация** — специализированная векторная БД. - **Прототип или локальный эксперимент** — Chroma, sqlite-vec или FAISS в памяти. Сравнивать производительность алгоритмов помогает открытый набор тестов ANN-Benchmarks.[6] На практике качество RAG чаще определяется нарезкой текста, выбором модели эмбеддингов и переранжированием, чем выбором хранилища. ## См. также - [Векторный поиск](https://llmdocs.ru/wiki/vector-search.md) - [Эмбеддинг](https://llmdocs.ru/wiki/embedding.md) - [RAG (генерация с дополнением поиском)](https://llmdocs.ru/wiki/rag.md) - [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) - [Индекс (базы данных)](https://llmdocs.ru/wiki/database-index.md) ## Источники 1. [pgvector — README (GitHub)](https://github.com/pgvector/pgvector) 2. [pgvector — CHANGELOG](https://github.com/pgvector/pgvector/blob/master/CHANGELOG.md) 3. [Yu. Malkov, D. Yashunin — Efficient and robust approximate nearest neighbor search using HNSW graphs (2016)](https://arxiv.org/abs/1603.09320) 4. [FAISS — Facebook AI Similarity Search](https://github.com/facebookresearch/faiss) 5. [Qdrant Documentation — Concepts](https://qdrant.tech/documentation/concepts/) 6. [ANN-Benchmarks](https://ann-benchmarks.com/) --- # PostgreSQL > Свободная объектно-реляционная СУБД с развитой поддержкой стандарта SQL, транзакций, расширений и типов данных — от JSON до векторов. Источник: https://llmdocs.ru/wiki/postgresql/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: объектно-реляционная СУБД - **Разработчик**: PostgreSQL Global Development Group - **Первый выпуск**: 1996 (как PostgreSQL; проект POSTGRES — с 1986) - **Язык реализации**: C - **Лицензия**: PostgreSQL License (разрешительная, в духе BSD/MIT) - **Порт по умолчанию**: 5432 - **Цикл выпусков**: мажорная версия ежегодно, поддержка 5 лет - **Сайт**: postgresql.org **PostgreSQL** (произносится «пост-грес-кью-эль», в обиходе — **Postgres**) — свободная объектно-реляционная система управления базами данных. Она известна строгим следованием стандарту [SQL](https://llmdocs.ru/wiki/sql.md), надёжными [транзакциями](https://llmdocs.ru/wiki/transaction-acid.md), богатым набором типов данных и механизмом расширений, который позволяет добавлять новые типы, функции, индексы и даже языки программирования. По опросам разработчиков Stack Overflow PostgreSQL с 2023 года — самая используемая база данных.[8] ## История Проект начался в 1986 году в Калифорнийском университете в Беркли под руководством Майкла Стоунбрейкера как преемник СУБД Ingres — отсюда название POSTGRES («после Ingres»). В нём впервые появились пользовательские типы данных и правила. В 1994 году Эндрю Ю и Джолли Чен заменили собственный язык запросов PostQUEL на SQL и выпустили Postgres95; в 1996 году проект переименовали в PostgreSQL и передали сообществу.[1] Сегодня PostgreSQL развивает глобальная группа разработчиков, не принадлежащая какой-либо компании. Мажорная версия выходит раз в год (обычно осенью), каждая поддерживается пять лет; минорные выпуски с исправлениями выходят ежеквартально.[2] Лицензия PostgreSQL License разрешает любое, в том числе коммерческое, использование и модификацию, поэтому на его основе построены многие продукты и облачные сервисы.[3] ## Архитектура - **Процесс на соединение.** Главный процесс (postmaster) порождает отдельный серверный процесс для каждого клиента. Соединения дороги, поэтому перед базой часто ставят пулер вроде PgBouncer. - **MVCC.** Изменение строки создаёт её новую версию, а старая остаётся видимой для транзакций, начавшихся раньше. Читатели не блокируют писателей и наоборот.[4] Устаревшие версии убирает фоновый процесс **autovacuum** (см. [MVCC](https://llmdocs.ru/wiki/mvcc.md)). - **WAL.** Каждое изменение сначала записывается в журнал упреждающей записи (*write-ahead log*), и лишь потом — в файлы данных. Журнал обеспечивает восстановление после сбоя, резервное копирование на момент времени (PITR) и [репликацию](https://llmdocs.ru/wiki/replication.md).[5] - **Оптимизатор запросов** на основе стоимости собирает статистику по таблицам и выбирает план; посмотреть его можно командой [EXPLAIN](https://llmdocs.ru/wiki/explain.md). ## Возможности - Полноценные транзакции, включая транзакционный DDL: `CREATE TABLE` или `ALTER TABLE` можно откатить. Все [уровни изоляции](https://llmdocs.ru/wiki/isolation-levels.md), включая настоящий `SERIALIZABLE`. - Типы данных: массивы, `jsonb` (двоичный JSON с индексами), диапазоны, `uuid`, сетевые адреса, геометрия, перечисления, составные типы. - [Индексы](https://llmdocs.ru/wiki/database-index.md) нескольких видов: [B-tree](https://llmdocs.ru/wiki/b-tree.md), Hash, GiST, SP-GiST, GIN, BRIN; частичные, по выражениям и покрывающие индексы.[6] - Оконные функции, рекурсивные CTE, `MERGE`, полнотекстовый поиск, секционирование таблиц. - Хранимые процедуры на PL/pgSQL, а также на Python, Perl и других языках. - Физическая (потоковая) и логическая репликация. ## Расширения Расширение подключается одной командой `CREATE EXTENSION` и может добавлять типы, операторы и методы индексирования. Самые известные: | Расширение | Назначение | |---|---| | PostGIS | геопространственные данные и запросы | | [pgvector](https://llmdocs.ru/wiki/pgvector.md) | хранение эмбеддингов и векторный поиск | | pg_stat_statements | статистика выполнения запросов | | TimescaleDB | временные ряды | | Citus | распределение таблиц по узлам ([шардирование](https://llmdocs.ru/wiki/sharding.md)) | | pg_trgm | поиск по сходству строк (триграммы) | Благодаря расширениям PostgreSQL часто заменяет сразу несколько специализированных систем: документную базу, геоинформационную систему и векторное хранилище для [RAG](https://llmdocs.ru/wiki/rag.md). ## Практика Быстрее всего запустить PostgreSQL в [Docker](https://llmdocs.ru/wiki/docker.md): ```bash docker run -d --name pg -e POSTGRES_PASSWORD=secret -p 5432:5432 postgres:18 psql -h localhost -U postgres ``` ```sql -- в psql \l -- список баз \dt -- таблицы текущей схемы \d+ orders -- структура таблицы EXPLAIN ANALYZE SELECT * FROM orders WHERE customer_id = 42; ``` Полезные практики: включить `pg_stat_statements` для поиска медленных запросов, следить за работой autovacuum на часто обновляемых таблицах, делать резервные копии через `pg_dump` или непрерывное архивирование WAL, а изменения схемы проводить [миграциями](https://llmdocs.ru/wiki/schema-migrations.md). Список изменений по версиям публикуется в примечаниях к выпускам.[7] ## Сравнение По сравнению с [MySQL](https://llmdocs.ru/wiki/mysql-mariadb.md) PostgreSQL исторически строже к типам и стандарту и богаче возможностями, MySQL — проще в репликации и распространён в веб-хостинге. [SQLite](https://llmdocs.ru/wiki/sqlite.md) — встраиваемая база без сервера, удобная для локальных приложений и тестов. Для аналитики над миллиардами строк используют колоночные СУБД вроде [ClickHouse](https://llmdocs.ru/wiki/clickhouse.md). ## См. также - [Реляционная база данных](https://llmdocs.ru/wiki/relational-database.md) - [SQL](https://llmdocs.ru/wiki/sql.md) - [MVCC](https://llmdocs.ru/wiki/mvcc.md) - [pgvector и векторные БД](https://llmdocs.ru/wiki/pgvector.md) - [Репликация баз данных](https://llmdocs.ru/wiki/replication.md) ## Источники 1. [PostgreSQL Documentation — A Brief History of PostgreSQL](https://www.postgresql.org/docs/current/history.html) 2. [PostgreSQL — Versioning Policy](https://www.postgresql.org/support/versioning/) 3. [PostgreSQL — License](https://www.postgresql.org/about/licence/) 4. [PostgreSQL Documentation — Concurrency Control (MVCC)](https://www.postgresql.org/docs/current/mvcc-intro.html) 5. [PostgreSQL Documentation — Write-Ahead Logging](https://www.postgresql.org/docs/current/wal-intro.html) 6. [PostgreSQL Documentation — Index Types](https://www.postgresql.org/docs/current/indexes-types.html) 7. [PostgreSQL Documentation — Release Notes](https://www.postgresql.org/docs/release/) 8. [Stack Overflow Developer Survey — Databases](https://survey.stackoverflow.co/2024/technology#most-popular-technologies-database) --- # Redis > Хранилище данных в оперативной памяти со структурами данных — строками, списками, хешами, множествами, сортированными множествами, потоками; используется как кэш, брокер сообщений, счётчики и очереди. Источник: https://llmdocs.ru/wiki/redis/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Полное название**: Remote Dictionary Server - **Автор**: Сальваторе Санфилиппо (antirez) - **Первый выпуск**: 2009 - **Язык**: C - **Модель**: ключ-значение со структурами данных, в памяти - **Лицензия**: с 2024 — RSALv2/SSPLv1, с Redis 8 (2025) также AGPLv3 - **Форк**: Valkey (Linux Foundation, 2024, лицензия BSD) - **Порт по умолчанию**: 6379 **Redis** (от *Remote Dictionary Server*) — хранилище данных, которое держит всё в оперативной памяти и поэтому отвечает за доли миллисекунды. В отличие от простых кэшей «ключ — строка», Redis хранит под ключами **структуры данных** — списки, хеши, множества, сортированные множества, потоки — и выполняет над ними атомарные операции на сервере. Это делает его универсальным инструментом: кэш, хранилище сессий, счётчики и ограничители частоты запросов, очереди задач, рейтинги, публикация и подписка.[1] Redis — одна из самых популярных баз данных; его применяют почти в любом крупном веб-сервисе рядом с основной [реляционной базой](https://llmdocs.ru/wiki/relational-database.md). ## История Итальянский программист Сальваторе Санфилиппо (antirez) начал писать Redis в 2009 году, чтобы ускорить свой сервис веб-аналитики, которому не хватало скорости MySQL. Проект быстро стал популярным; с 2015 года его развитие спонсировала компания Redis Labs (ныне Redis Ltd.). В 2020 году Санфилиппо отошёл от проекта, а в конце 2024 года вернулся. В марте 2024 года Redis Ltd. сменила открытую лицензию BSD на RSALv2 и SSPLv1, запрещающие облачным провайдерам предлагать Redis как сервис без договорённости. В ответ Linux Foundation при поддержке AWS, Google и других компаний создала открытый форк **Valkey** на основе последней BSD-версии.[5] В 2025 году с выходом Redis 8 компания добавила открытую лицензию AGPLv3.[6] ## Структуры данных | Тип | Описание | Примеры применения | |---|---|---| | String | строка или число до 512 МБ | кэш, счётчики (`INCR`), флаги | | Hash | словарь полей | объекты: профиль пользователя | | List | связный список | очереди задач, последние события | | Set | множество уникальных значений | теги, уникальные посетители | | Sorted Set | множество с числовыми оценками, упорядоченное | рейтинги, приоритетные очереди, временные окна | | Stream | журнал записей с группами потребителей | очереди сообщений, события | | Bitmap, HyperLogLog | биты; приближённый подсчёт уникальных | активность по дням, подсчёт миллионов уникальных | | Geo | координаты | «ближайшие точки» | Помимо этого есть публикация/подписка (Pub/Sub), транзакции `MULTI`/`EXEC`, скрипты на Lua и функции, а в новых версиях — поиск, JSON и векторные множества для [векторного поиска](https://llmdocs.ru/wiki/vector-search.md).[2] ## Примеры ```bash redis-cli SET page:/home "..." EX 60 # кэш на 60 секунд GET page:/home INCR views:article:42 # атомарный счётчик HSET user:42 name "Алиса" plan "pro" # хеш ZADD leaderboard 1500 alice 1200 bob # рейтинг ZREVRANGE leaderboard 0 9 WITHSCORES # топ-10 LPUSH jobs '{"type":"email","to":42}' # очередь задач BRPOP jobs 0 # обработчик ждёт задачу ``` Ограничитель частоты запросов на [Python](https://llmdocs.ru/wiki/python.md) — классический пример: ```python import redis r = redis.Redis() def allow(user_id: int, limit: int = 100) -> bool: key = f"rate:{user_id}" count = r.incr(key) if count == 1: r.expire(key, 60) # окно в одну минуту return count <= limit ``` ## Как устроен - **Однопоточное выполнение команд.** Команды выполняются по одной в основном потоке, поэтому каждая атомарна, а гонки между командами невозможны. Сетевой ввод-вывод может обрабатываться дополнительными потоками. Следствие: медленная команда (`KEYS *` на миллионах ключей) блокирует всех — вместо неё используют `SCAN`. - **Сохранение на диск.** RDB — периодические снимки, AOF — журнал всех команд записи; их можно сочетать. При отказе возможно потерять данные за последнюю секунду или интервал снимка.[3] - **Вытеснение.** При достижении `maxmemory` Redis удаляет ключи по политике (например, `allkeys-lru` — давно не использованные), что и нужно для кэша. - **Масштабирование.** Репликация на реплики, Sentinel для автоматического переключения при отказе и Redis Cluster, распределяющий ключи по 16 384 слотам между узлами (см. [Шардирование](https://llmdocs.ru/wiki/sharding.md)).[4] ## Кэширование Самый частый сценарий — кэш перед основной базой (*cache-aside*): приложение сначала ищет данные в Redis, при промахе читает из [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) и кладёт результат в кэш со сроком жизни. Главные вопросы — инвалидация (удалить ключ при изменении данных) и защита от лавины запросов при одновременном истечении популярного ключа (см. [Кэш (вычисления)](https://llmdocs.ru/wiki/cache.md)). ## Ограничения - Объём данных ограничен оперативной памятью, которая дороже диска. - Гарантии сохранности слабее, чем у реляционных СУБД: Redis не стоит делать единственным хранилищем важных данных без понимания настроек сохранения. - Нет сложных запросов и соединений — модель данных нужно проектировать под конкретные операции. - По умолчанию сервер не защищён: его нельзя открывать в интернет без пароля, ACL и [TLS](https://llmdocs.ru/wiki/tls.md). ## Альтернативы и совместимые системы Valkey — открытый форк, совместимый по протоколу; KeyDB и Dragonfly — многопоточные реализации совместимого протокола; Memcached — более простой кэш «ключ — строка». Облачные провайдеры предлагают управляемые сервисы на основе Redis или Valkey. ## См. также - [NoSQL](https://llmdocs.ru/wiki/nosql.md) - [Кэш (вычисления)](https://llmdocs.ru/wiki/cache.md) - [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) - [Шардирование](https://llmdocs.ru/wiki/sharding.md) - [Репликация баз данных](https://llmdocs.ru/wiki/replication.md) ## Источники 1. [Redis Documentation](https://redis.io/docs/latest/) 2. [Redis — Data types](https://redis.io/docs/latest/develop/data-types/) 3. [Redis — Persistence](https://redis.io/docs/latest/operate/oss_and_stack/management/persistence/) 4. [Redis — Cluster specification](https://redis.io/docs/latest/operate/oss_and_stack/reference/cluster-spec/) 5. [Valkey](https://valkey.io/) 6. [antirez — Redis is open source again (2025)](https://antirez.com/news/151) --- # Реляционная база данных > База данных, в которой информация хранится в виде таблиц (отношений), связанных ключами, а запросы выражаются декларативно — обычно на языке SQL. Источник: https://llmdocs.ru/wiki/relational-database/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Модель данных**: реляционная (таблицы, строки, столбцы) - **Автор модели**: Эдгар Кодд (IBM, 1970) - **Язык запросов**: SQL - **Гарантии**: транзакции ACID - **Примеры СУБД**: PostgreSQL, MySQL, SQLite, Oracle Database, Microsoft SQL Server - **Противопоставляется**: NoSQL **Реляционная база данных** — база данных, построенная на реляционной модели: данные хранятся в **таблицах** (в теории — *отношениях*), каждая строка описывает один объект, каждый столбец — один его атрибут, а связи между таблицами задаются через значения ключей. Программа, которая управляет такой базой, называется реляционной СУБД (РСУБД, англ. *RDBMS*). Почти все РСУБД используют язык [SQL](https://llmdocs.ru/wiki/sql.md): пользователь описывает, *какие* данные нужны, а СУБД сама решает, *как* их достать. Реляционные базы — самый распространённый способ хранить данные приложений: от [SQLite](https://llmdocs.ru/wiki/sqlite.md) внутри смартфона до кластеров [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) и [MySQL](https://llmdocs.ru/wiki/mysql-mariadb.md), обслуживающих интернет-магазины и банки. ## История Модель предложил сотрудник IBM Эдгар Кодд в статье «Реляционная модель данных для больших совместно используемых банков данных» (1970).[1] До этого господствовали иерархические и сетевые базы, где программист вручную «ходил» по указателям между записями, а любое изменение структуры ломало программы. Кодд предложил опираться на математическую теорию множеств и логику предикатов: данные описываются отношениями, а запросы — операциями над ними (выборка, проекция, соединение). В IBM на основе этой идеи построили экспериментальную систему System R и язык SEQUEL, позже переименованный в SQL (1974).[4] Первой коммерческой реляционной СУБД стала Oracle (1979), затем появились IBM DB2, Ingres, Sybase и Microsoft SQL Server. В 1990-х возникли открытые PostgreSQL и MySQL, в 2000 году — встраиваемая SQLite. ## Основные понятия | Термин теории | Термин SQL | Смысл | |---|---|---| | отношение | таблица | множество однотипных записей | | кортеж | строка | одна запись | | атрибут | столбец | поле записи определённого типа | | домен | тип данных | допустимые значения атрибута | - **Первичный ключ** (primary key) — столбец или набор столбцов, однозначно определяющий строку, например `id` пользователя. - **Внешний ключ** (foreign key) — столбец, ссылающийся на первичный ключ другой таблицы. СУБД не даст создать заказ для несуществующего покупателя или удалить покупателя, у которого есть заказы (если не указано каскадное удаление).[3] - **Ограничения целостности** — `NOT NULL`, `UNIQUE`, `CHECK`: правила, которые база проверяет при каждой записи, независимо от кода приложения. - **Схема** — описание всех таблиц, столбцов, типов и ограничений. Её изменения обычно оформляют как [миграции](https://llmdocs.ru/wiki/schema-migrations.md). ## Пример Покупатели и их заказы хранятся в двух таблицах, связанных внешним ключом: ```sql CREATE TABLE customers ( id bigint PRIMARY KEY, name text NOT NULL, email text UNIQUE ); CREATE TABLE orders ( id bigint PRIMARY KEY, customer_id bigint NOT NULL REFERENCES customers(id), total numeric(12, 2) CHECK (total >= 0), created_at timestamptz DEFAULT now() ); -- сумма заказов по каждому покупателю SELECT c.name, sum(o.total) AS spent FROM customers c JOIN orders o ON o.customer_id = c.id GROUP BY c.name ORDER BY spent DESC; ``` Данные о покупателе записаны ровно в одном месте; заказы ссылаются на него по `id`. Такое разделение, устраняющее дублирование, называется [нормализацией](https://llmdocs.ru/wiki/normalization.md). ## Чем хороши реляционные базы - **Декларативные запросы.** Один и тот же запрос работает и на тысяче строк, и на миллиарде — оптимизатор выбирает порядок соединений и [индексы](https://llmdocs.ru/wiki/database-index.md); увидеть его решение можно через [EXPLAIN](https://llmdocs.ru/wiki/explain.md). - **Транзакции.** Группа изменений выполняется целиком или не выполняется вовсе, с гарантиями [ACID](https://llmdocs.ru/wiki/transaction-acid.md). - **Целостность.** Типы и ограничения не позволяют записать в базу заведомо некорректные данные. - **Гибкость запросов.** Данные можно соединять и агрегировать так, как не планировалось при проектировании схемы. - **Зрелость.** Десятилетия эксплуатации, стандарт SQL, огромная экосистема драйверов, [ORM](https://llmdocs.ru/wiki/orm.md), инструментов резервного копирования и [репликации](https://llmdocs.ru/wiki/replication.md). ## Ограничения и альтернативы Строгая схема требует продумывать структуру заранее, а горизонтальное масштабирование записи на много серверов ([шардирование](https://llmdocs.ru/wiki/sharding.md)) у классических РСУБД сложнее, чем у распределённых хранилищ. В 2000-х это породило движение [NoSQL](https://llmdocs.ru/wiki/nosql.md): документные ([MongoDB](https://llmdocs.ru/wiki/mongodb.md)), ключ-значение ([Redis](https://llmdocs.ru/wiki/redis.md)), колоночные и графовые базы. Для аналитики над огромными объёмами используются СУБД с [колоночным хранением](https://llmdocs.ru/wiki/columnar-storage.md), например [ClickHouse](https://llmdocs.ru/wiki/clickhouse.md). Со временем границы размылись: PostgreSQL хранит JSON-документы и векторы ([pgvector](https://llmdocs.ru/wiki/pgvector.md)), а многие NoSQL-системы добавили транзакции и SQL-подобные языки. Для большинства приложений реляционная база остаётся разумным выбором по умолчанию; SQLite подходит, когда базе не нужен отдельный сервер.[5] ## См. также - [SQL](https://llmdocs.ru/wiki/sql.md) - [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) - [Транзакция и ACID](https://llmdocs.ru/wiki/transaction-acid.md) - [Индекс (базы данных)](https://llmdocs.ru/wiki/database-index.md) - [Нормализация](https://llmdocs.ru/wiki/normalization.md) ## Источники 1. [E. F. Codd — A Relational Model of Data for Large Shared Data Banks (CACM, 1970)](https://dl.acm.org/doi/10.1145/362384.362685) 2. [PostgreSQL Documentation — Concepts](https://www.postgresql.org/docs/current/tutorial-concepts.html) 3. [PostgreSQL Documentation — Constraints](https://www.postgresql.org/docs/current/ddl-constraints.html) 4. [D. D. Chamberlin, R. F. Boyce — SEQUEL: A Structured English Query Language (1974)](https://dl.acm.org/doi/10.1145/800296.811515) 5. [SQLite — Appropriate Uses For SQLite](https://www.sqlite.org/whentouse.html) --- # Репликация баз данных > Поддержание копий данных на нескольких серверах для отказоустойчивости, масштабирования чтения и географической близости; бывает синхронной и асинхронной, физической и логической. Источник: https://llmdocs.ru/wiki/replication/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Цели**: отказоустойчивость, масштабирование чтения, близость к пользователям, резервирование - **Схемы**: с одним ведущим, с несколькими ведущими, без ведущего - **Режимы**: синхронный, асинхронный, полусинхронный - **Уровни**: физическая (журнал WAL, страницы), логическая (изменения строк) - **PostgreSQL**: потоковая репликация (9.0, 2010), логическая (10, 2017) - **Управление отказами**: Patroni, Orchestrator, облачные сервисы **Репликация** базы данных — поддержание копий одних и тех же данных на нескольких серверах. Сервер, принимающий изменения, называют **ведущим** (*primary*, *leader*; устаревшее — *master*), а серверы-копии — **репликами** (*replica*, *follower*, *standby*). Изменения ведущего непрерывно передаются репликам и применяются там. Репликация решает несколько задач сразу: **отказоустойчивость** (при отказе ведущего реплика становится новым ведущим), **масштабирование чтения** (запросы на чтение распределяются по репликам), **близость к пользователям** (реплика в другом регионе) и разгрузку ведущего от отчётов и резервного копирования. ## Схемы репликации | Схема | Как устроена | Плюсы | Минусы | |---|---|---|---| | Один ведущий | все записи идут на ведущий, реплики только читают | просто, нет конфликтов записи | запись не масштабируется, переключение при отказе | | Несколько ведущих | запись принимают несколько узлов, обычно в разных дата-центрах | запись локально в каждом регионе | конфликты одновременных изменений | | Без ведущего | клиент пишет и читает с нескольких узлов по кворуму | высокая доступность | сложная согласованность | Схема с одним ведущим — стандарт для [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md), [MySQL](https://llmdocs.ru/wiki/mysql-mariadb.md) и большинства реляционных СУБД. Репликация без ведущего с кворумами записи и чтения описана в статье Amazon о Dynamo (2007) и используется в Cassandra и ScyllaDB.[5] ## Синхронная и асинхронная - **Асинхронная** — ведущий подтверждает запись клиенту, не дожидаясь реплик. Быстро, но при внезапном отказе ведущего последние подтверждённые транзакции могут не успеть дойти до реплики и потеряются. - **Синхронная** — ведущий ждёт подтверждения хотя бы от одной реплики. Данные не теряются, но каждая запись медленнее, а недоступность реплики может остановить запись. - **Полусинхронная** — компромисс: синхронно с одной репликой, асинхронно с остальными. В PostgreSQL режим задаётся параметрами `synchronous_standby_names` и `synchronous_commit`, причём выбирать можно даже для отдельной транзакции.[1] ## Физическая и логическая - **Физическая (потоковая) репликация** передаёт журнал упреждающей записи (WAL) — побайтовые изменения страниц. Реплика — точная копия всего кластера, той же мажорной версии СУБД. В PostgreSQL доступна с версии 9.0 (2010). - **Логическая репликация** передаёт изменения на уровне строк (вставка, обновление, удаление) для выбранных таблиц. Позволяет реплицировать часть данных, между разными мажорными версиями (для обновления почти без простоя) и в другие системы. В PostgreSQL — с версии 10 (2017) по модели публикаций и подписок.[2] В MySQL изменения передаются через двоичный журнал (*binlog*) в построчном или операторном формате, с глобальными идентификаторами транзакций (GTID) для надёжного переключения.[3] ```sql -- PostgreSQL: логическая репликация одной таблицы -- на источнике CREATE PUBLICATION orders_pub FOR TABLE orders; -- на получателе CREATE SUBSCRIPTION orders_sub CONNECTION 'host=primary dbname=shop user=replicator' PUBLICATION orders_pub; ``` ## Отставание реплик При асинхронной репликации реплика отстаёт от ведущего — обычно на миллисекунды, но под нагрузкой или при долгих запросах на реплике — на секунды и минуты. Отсюда аномалии, с которыми сталкивается приложение:[4] - **Чтение собственных записей.** Пользователь сохранил профиль, страница перезагрузилась с реплики — и изменения «пропали». Решение: читать данные, которые пользователь только что менял, с ведущего. - **Монотонность чтений.** Последовательные запросы попадают на разные реплики и видят данные «то новее, то старее». Решение: привязать сессию к одной реплике. Отставание нужно мониторить: в PostgreSQL — через представление `pg_stat_replication` на ведущем. ## Переключение при отказе Если ведущий вышел из строя, одну из реплик нужно **повысить** до ведущего и перенаправить на неё клиентов. Делать это вручную долго, а автоматически — рискованно: при сетевом разделении два узла могут одновременно счесть себя ведущими (*split brain*) и принять конфликтующие записи. Поэтому для автоматического переключения используют инструменты с консенсусом через etcd, Consul или ZooKeeper — например, Patroni для PostgreSQL — или управляемые облачные базы данных.[6] ## Репликация — не резервная копия Реплика мгновенно повторяет и ошибочные изменения: случайный `DELETE` без `WHERE` или повреждение данных приложением дойдут до всех копий за доли секунды. Защиту от этого дают только резервные копии с историей и восстановлением на момент времени (см. [Бэкапы: правило 3-2-1](https://llmdocs.ru/wiki/backup-3-2-1.md)). Отложенная реплика (с задержкой применения на несколько часов) — полезное, но не заменяющее бэкапы дополнение. ## Репликация и шардирование Репликация копирует *все* данные на несколько узлов и масштабирует чтение, но не объём записи и не размер данных на одном узле. Для этого данные делят на части — [шарды](https://llmdocs.ru/wiki/sharding.md), — каждая из которых обычно ещё и реплицируется. Компромиссы между согласованностью и доступностью в таких системах описывает [CAP-теорема](https://llmdocs.ru/wiki/cap-theorem.md). ## См. также - [Шардирование](https://llmdocs.ru/wiki/sharding.md) - [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) - [Транзакция и ACID](https://llmdocs.ru/wiki/transaction-acid.md) - [Бэкапы: правило 3-2-1](https://llmdocs.ru/wiki/backup-3-2-1.md) - [Распределённые системы](https://llmdocs.ru/wiki/distributed-systems.md) ## Источники 1. [PostgreSQL Documentation — High Availability, Load Balancing, and Replication](https://www.postgresql.org/docs/current/high-availability.html) 2. [PostgreSQL Documentation — Logical Replication](https://www.postgresql.org/docs/current/logical-replication.html) 3. [MySQL — Replication](https://dev.mysql.com/doc/refman/8.4/en/replication.html) 4. [M. Kleppmann — Designing Data-Intensive Applications](https://dataintensive.net/) 5. [G. DeCandia et al. — Dynamo: Amazon's Highly Available Key-value Store (SOSP 2007)](https://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf) 6. [Patroni — документация](https://patroni.readthedocs.io/) --- # Миграции схемы БД > Версионируемые скрипты, которые последовательно изменяют структуру базы данных вместе с кодом приложения; инструменты Alembic, Flyway, Liquibase, Django migrations и практики изменений без простоя. Источник: https://llmdocs.ru/wiki/schema-migrations/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Назначение**: воспроизводимое изменение схемы БД по версиям - **Хранятся**: в репозитории рядом с кодом - **Подходы**: версионный (императивный), декларативный (сравнение состояний) - **Python**: Alembic, Django migrations - **JVM и универсальные**: Flyway, Liquibase - **Go и другие**: golang-migrate, goose, Atlas, Prisma Migrate, sqlx migrate **Миграции схемы базы данных** — упорядоченный набор версионируемых скриптов, каждый из которых переводит структуру базы из одного состояния в следующее: создаёт таблицы, добавляет столбцы и [индексы](https://llmdocs.ru/wiki/database-index.md), переименовывает поля, переносит данные. Миграции хранятся в [системе контроля версий](https://llmdocs.ru/wiki/git.md) вместе с кодом приложения, а специальный инструмент знает, какие из них уже применены к конкретной базе, и применяет недостающие. Так схема на ноутбуке разработчика, в тестах и в продакшене остаётся одинаковой и воспроизводимой.[6] ## Зачем нужны Без миграций изменения схемы делаются вручную через консоль: кто-то забывает добавить столбец на стенде, порядок изменений теряется, новую базу невозможно поднять с нуля. Миграции решают это: - история изменений схемы видна в репозитории и проходит ревью, как код; - новая среда поднимается одной командой; - изменения схемы выкатываются автоматически в пайплайне [CI/CD](https://llmdocs.ru/wiki/ci-cd.md) вместе с приложением; - можно откатить изменение (если миграция обратима). ## Как работают Инструмент создаёт в базе служебную таблицу (`alembic_version`, `django_migrations`, `flyway_schema_history`) с перечнем применённых миграций. Команда «обновить» сравнивает её со списком файлов и выполняет недостающие по порядку, обычно каждую в своей [транзакции](https://llmdocs.ru/wiki/transaction-acid.md). Два подхода: - **Версионный** (императивный) — разработчик пишет (или генерирует) последовательность шагов: `V1__create_users.sql`, `V2__add_email.sql`. Так работают Flyway, Alembic, Django, golang-migrate.[3] - **Декларативный** — описывается желаемое состояние схемы, а инструмент сам вычисляет разницу с текущей базой и строит план изменений: Atlas, Prisma (`db push`), sqldef.[5] Удобно, но план нужно внимательно проверять — особенно удаления. ## Примеры **Alembic** (для SQLAlchemy) умеет автоматически генерировать миграцию по изменениям моделей [ORM](https://llmdocs.ru/wiki/orm.md):[1] ```bash alembic revision --autogenerate -m "add user email" alembic upgrade head # применить все alembic downgrade -1 # откатить последнюю ``` ```python def upgrade() -> None: op.add_column("users", sa.Column("email", sa.String(255), nullable=True)) op.create_index("ix_users_email", "users", ["email"], unique=True) def downgrade() -> None: op.drop_index("ix_users_email", table_name="users") op.drop_column("users", "email") ``` **Django** делает то же встроенными командами `makemigrations` и `migrate` (см. [Django](https://llmdocs.ru/wiki/django.md)).[2] **Flyway** и **Liquibase** работают с чистыми SQL-файлами или описаниями в XML/YAML и популярны в мире JVM, но подходят для любого стека.[4] Автогенерацию всегда нужно читать глазами: инструмент может принять переименование столбца за удаление и создание нового — с потерей данных. ## Изменения без простоя В продакшене база работает под нагрузкой, а приложение выкатывается постепенно: какое-то время старая и новая версии кода работают одновременно. Отсюда два правила. **1. Блокировки.** Многие операции `ALTER TABLE` берут эксклюзивную блокировку и на большой таблице «подвешивают» все запросы.[7] В [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md): - индексы создавать с `CREATE INDEX CONCURRENTLY` (вне транзакции); - новые столбцы добавлять без `DEFAULT`, вычисляемого для каждой строки, или с константным значением по умолчанию (с PG 11 это мгновенно); - `NOT NULL` и внешние ключи добавлять как `NOT VALID`, а затем проверять отдельно `VALIDATE CONSTRAINT`; - задавать `SET lock_timeout = '5s'`, чтобы миграция не встала в очередь за долгой транзакцией и не заблокировала всё за собой. В [MySQL](https://llmdocs.ru/wiki/mysql-mariadb.md) для больших таблиц используют онлайн-DDL или инструменты gh-ost и pt-online-schema-change. **2. Совместимость версий: «расширить и сжать»** (*expand and contract*). Опасные изменения разбивают на несколько выкладок. Например, переименование столбца `name` → `full_name`: 1. **Расширить:** добавить столбец `full_name`; код пишет в оба столбца. 2. **Перенести данные:** заполнить `full_name` для старых строк пачками, чтобы не держать долгую транзакцию. 3. **Переключить:** код читает только `full_name`. 4. **Сжать:** после того как старые версии кода выведены из работы, удалить `name`. Каждый шаг совместим с соседними версиями приложения, и любой можно откатить. ## Практики - Одна миграция — одно логическое изменение; уже применённые в общих средах миграции **не редактируются**, ошибки исправляются новой миграцией. - Миграции данных отделяют от миграций схемы и делают идемпотентными. - В CI проверяют, что миграции применяются на чистой базе и что модели совпадают со схемой (`alembic check`, `makemigrations --check`); линтеры вроде squawk предупреждают об опасных операциях. - Перед рискованной миграцией — свежий бэкап и проверенное восстановление (см. [Бэкапы: правило 3-2-1](https://llmdocs.ru/wiki/backup-3-2-1.md)). - Миграции запускают отдельным шагом развёртывания (job в [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md), шаг пайплайна), а не при старте каждого экземпляра приложения, чтобы избежать гонок. ## См. также - [ORM](https://llmdocs.ru/wiki/orm.md) - [SQL](https://llmdocs.ru/wiki/sql.md) - [Infrastructure as Code](https://llmdocs.ru/wiki/infrastructure-as-code.md) - [Транзакция и ACID](https://llmdocs.ru/wiki/transaction-acid.md) ## Источники 1. [Alembic documentation](https://alembic.sqlalchemy.org/) 2. [Django — Migrations](https://docs.djangoproject.com/en/stable/topics/migrations/) 3. [Flyway documentation](https://documentation.red-gate.com/flyway) 4. [Liquibase documentation](https://docs.liquibase.com/) 5. [Atlas — Declarative schema migrations](https://atlasgo.io/) 6. [Martin Fowler — Evolutionary Database Design](https://martinfowler.com/articles/evodb.html) 7. [PostgreSQL — ALTER TABLE (locking notes)](https://www.postgresql.org/docs/current/sql-altertable.html) --- # Шардирование > Горизонтальное разделение данных одной базы между несколькими серверами по ключу шардирования; позволяет масштабировать запись и объём сверх возможностей одной машины ценой сложности запросов, транзакций и перебалансировки. Источник: https://llmdocs.ru/wiki/sharding/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Суть**: разные строки — на разных серверах - **Отличие от репликации**: репликация копирует данные, шардирование делит - **Стратегии**: по диапазону, по хешу, по справочнику (directory), географическое - **Ключевое решение**: выбор ключа шардирования - **Решения для PostgreSQL**: Citus, партиционирование + FDW - **Решения для MySQL**: Vitess, ProxySQL - **Встроенное**: MongoDB, Cassandra, CockroachDB, YDB, ClickHouse **Шардирование** (англ. *sharding*) — способ горизонтального масштабирования базы данных, при котором строки одной логической таблицы распределяются между несколькими независимыми серверами — **шардами**. Каждый шард хранит только часть данных и обслуживает только запросы к ней. Шардирование позволяет выйти за пределы одной машины по объёму данных и, главное, по нагрузке на запись — но делает систему заметно сложнее.[1] ## Шардирование, репликация и партиционирование Эти понятия часто путают: - **[Репликация](https://llmdocs.ru/wiki/replication.md)** хранит *копии одних и тех же* данных на нескольких серверах. Она повышает доступность и масштабирует чтение, но каждая реплика должна принимать все записи. - **Партиционирование** делит таблицу на части *внутри одного сервера* (например, по месяцам) — в [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) это декларативное партиционирование.[6] Оно упрощает удаление старых данных и ускоряет запросы, но не добавляет ресурсов. - **Шардирование** — это партиционирование *между серверами*. На практике его сочетают с репликацией: у каждого шарда есть свои реплики. Прежде чем шардировать, обычно исчерпывают более простые средства: вертикальное масштабирование (больше процессоров, памяти, быстрые диски), [индексы](https://llmdocs.ru/wiki/database-index.md) и оптимизацию запросов, реплики для чтения, [кэширование](https://llmdocs.ru/wiki/cache.md), архивирование старых данных. Современный сервер с терабайтами NVMe и сотнями ядер выдерживает очень многое. ## Ключ шардирования Каждая строка попадает на шард в зависимости от значения **ключа шардирования** — одного или нескольких столбцов. Выбор ключа — самое важное и труднообратимое решение:[2] - **высокая кардинальность** — много различных значений, чтобы данные можно было распределить; - **равномерность** — без «горячих» значений, иначе один шард будет перегружен (например, ключ по стране, когда 80 % пользователей из одной страны); - **локальность запросов** — большинство запросов должны затрагивать один шард. Для SaaS-приложений естественный ключ — `tenant_id` (идентификатор клиента-организации): все данные клиента лежат вместе, а [транзакции](https://llmdocs.ru/wiki/transaction-acid.md) и соединения остаются локальными. ## Стратегии распределения | Стратегия | Как работает | Плюсы | Минусы | |---|---|---|---| | По диапазону | `id 1–1 млн → шард 1`, `1–2 млн → шард 2` | эффективные запросы по диапазону | «горячий» последний шард при монотонных ключах | | По хешу | `hash(key) mod N` | равномерное распределение | запросы по диапазону идут на все шарды | | По справочнику | таблица «ключ → шард» | гибкость, ручной перенос клиентов | справочник — отдельная точка отказа | | Географическая | данные региона — в регионе | задержки, требования законов о локализации | неравномерность нагрузки | Наивное `hash(key) mod N` плохо переносит изменение числа шардов: при переходе с 4 на 5 почти все ключи меняют шард. Поэтому используют **согласованное хеширование** (consistent hashing),[5] при котором при добавлении узла переезжает лишь ~1/N данных, — как в Amazon Dynamo и Cassandra,[7] — или заранее создают много **виртуальных шардов** (например, 1024), которые затем распределяют и перемещают между физическими серверами целиком. ## Маршрутизация запросов Кто-то должен знать, куда отправить запрос: - **само приложение** — библиотека вычисляет шард по ключу; - **прокси или координатор** — Vitess (vtgate) для MySQL,[3] координатор Citus для PostgreSQL, mongos в MongoDB;[4] - **встроенная распределённая СУБД** — CockroachDB, YugabyteDB, YDB, TiDB, Cassandra, [ClickHouse](https://llmdocs.ru/wiki/clickhouse.md) сами шардируют и перемещают данные, предоставляя единый SQL-интерфейс. ## Сложности - **Запросы между шардами** (*scatter-gather*) — запрос без ключа шардирования рассылается на все шарды, а результаты собираются и сортируются координатором. Медленно и дорого. - **Соединения (JOIN)** между данными на разных шардах. Решения — совместное размещение (co-location) связанных таблиц по одному ключу, дублирование небольших справочных таблиц на все шарды. - **Распределённые транзакции** требуют двухфазной фиксации и медленнее локальных; многие системы их ограничивают. - **Уникальность и идентификаторы** — автоинкремент не работает глобально; используют UUID (лучше UUIDv7), Snowflake-подобные ID или диапазоны на шард. - **Перебалансировка** — перенос данных при добавлении шарда без простоя и с согласованностью. - **Эксплуатация** — резервное копирование, миграции схемы, мониторинг умножаются на число шардов. Эти компромиссы — частный случай общих проблем [распределённых систем](https://llmdocs.ru/wiki/distributed-systems.md) (см. [CAP-теорема](https://llmdocs.ru/wiki/cap-theorem.md)). ## Пример: Citus ```sql CREATE EXTENSION citus; CREATE TABLE events (tenant_id bigint, id bigserial, payload jsonb, PRIMARY KEY (tenant_id, id)); SELECT create_distributed_table('events', 'tenant_id'); -- шардирование по клиенту SELECT create_reference_table('countries'); -- копия на каждом узле ``` После этого запросы с `WHERE tenant_id = 42` идут на один узел, а агрегаты по всем клиентам выполняются параллельно на всех. ## См. также - [Репликация баз данных](https://llmdocs.ru/wiki/replication.md) - [Распределённые системы](https://llmdocs.ru/wiki/distributed-systems.md) - [MongoDB](https://llmdocs.ru/wiki/mongodb.md) - [Хеш-таблица](https://llmdocs.ru/wiki/hash-table.md) ## Источники 1. [Kleppmann — Designing Data-Intensive Applications, ch. 6 Partitioning (O'Reilly)](https://dataintensive.net/) 2. [Citus documentation — Choosing the distribution column](https://docs.citusdata.com/en/stable/sharding/data_modeling.html) 3. [Vitess documentation — Sharding](https://vitess.io/docs/reference/features/sharding/) 4. [MongoDB Manual — Sharding](https://www.mongodb.com/docs/manual/sharding/) 5. [Karger et al. — Consistent Hashing and Random Trees (STOC 1997)](https://doi.org/10.1145/258533.258660) 6. [PostgreSQL — Table Partitioning](https://www.postgresql.org/docs/current/ddl-partitioning.html) 7. [DeCandia et al. — Dynamo: Amazon's Highly Available Key-value Store (SOSP 2007)](https://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf) --- # SQL > Декларативный язык запросов к реляционным базам данных; стандартизирован ANSI и ISO, поддерживается практически всеми РСУБД. Источник: https://llmdocs.ru/wiki/sql/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Парадигма**: декларативная - **Появился**: 1974 (SEQUEL, IBM) - **Авторы**: Дональд Чемберлин, Рэймонд Бойс - **Стандарт**: ISO/IEC 9075 (последняя редакция — SQL:2023) - **Диалекты**: PostgreSQL, T-SQL, PL/SQL, MySQL, SQLite - **Расширение файлов**: .sql **SQL** (англ. *Structured Query Language* — «язык структурированных запросов»; произносится «эс-кью-эль» или «сиквел») — декларативный язык для работы с [реляционными базами данных](https://llmdocs.ru/wiki/relational-database.md). На SQL создают таблицы, добавляют и изменяют данные, пишут запросы и управляют правами доступа. Запрос описывает желаемый результат, а не алгоритм: как именно его получить, решает оптимизатор СУБД. SQL — один из самых долгоживущих языков программирования: ему больше 50 лет, и его понимают [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md), [MySQL](https://llmdocs.ru/wiki/mysql-mariadb.md), [SQLite](https://llmdocs.ru/wiki/sqlite.md), Oracle, SQL Server, аналитические системы вроде [ClickHouse](https://llmdocs.ru/wiki/clickhouse.md), а также многие инструменты обработки данных. ## История Язык разработали Дональд Чемберлин и Рэймонд Бойс в IBM для экспериментальной СУБД System R. Первая публикация вышла в 1974 году под названием SEQUEL (*Structured English Query Language*); из-за конфликта с торговой маркой его сократили до SQL.[1] | Редакция | Что добавила | |---|---| | SQL-86 / SQL-87 | первый стандарт ANSI, затем ISO | | SQL-92 | явный синтаксис `JOIN`, уровни изоляции, домены | | SQL:1999 | рекурсивные запросы (`WITH RECURSIVE`), триггеры, логический тип | | SQL:2003 | оконные функции, `MERGE`, поддержка XML | | SQL:2011 | темпоральные (версионированные по времени) таблицы | | SQL:2016 | функции для JSON, сопоставление шаблонов строк | | SQL:2023 | тип JSON, графовые запросы SQL/PGQ | Ни одна СУБД не реализует стандарт полностью; у каждой есть свой диалект и расширения. PostgreSQL публикует таблицу соответствия стандарту по каждой возможности.[3] ## Части языка - **DDL** (*Data Definition Language*) — описание структуры: `CREATE`, `ALTER`, `DROP` для таблиц, [индексов](https://llmdocs.ru/wiki/database-index.md), представлений. - **DML** (*Data Manipulation Language*) — работа с данными: `SELECT`, `INSERT`, `UPDATE`, `DELETE`, `MERGE`. - **DCL** (*Data Control Language*) — права: `GRANT`, `REVOKE`. - **TCL** (*Transaction Control*) — управление [транзакциями](https://llmdocs.ru/wiki/transaction-acid.md): `BEGIN`, `COMMIT`, `ROLLBACK`, `SAVEPOINT`. ## Запрос SELECT Записанный порядок предложений не совпадает с логическим порядком выполнения — это частый источник путаницы у новичков: ```sql SELECT department, count(*) AS staff, avg(salary) AS avg_salary -- 5 FROM employees -- 1 WHERE hired_at >= '2020-01-01' -- 2 GROUP BY department -- 3 HAVING count(*) > 5 -- 4 ORDER BY avg_salary DESC -- 6 LIMIT 10; -- 7 ``` Сначала выбираются строки источника (`FROM` и соединения), затем фильтруются (`WHERE`), группируются (`GROUP BY`), фильтруются группы (`HAVING`), вычисляются выражения списка выборки, и лишь потом идут сортировка и ограничение. Поэтому псевдоним `avg_salary` нельзя использовать в `WHERE`, но можно в `ORDER BY`. ### Соединения `JOIN` объединяет строки разных таблиц по условию: `INNER JOIN` оставляет только совпавшие пары, `LEFT JOIN` сохраняет все строки левой таблицы (подставляя `NULL` при отсутствии пары), `FULL JOIN` — строки обеих, `CROSS JOIN` даёт декартово произведение. ### Оконные функции и CTE **Оконные функции** вычисляют значение по группе строк, не схлопывая их, — например, нарастающий итог или ранг внутри категории.[4] **Общие табличные выражения** (`WITH`) дают имена промежуточным результатам и позволяют писать рекурсивные запросы — например, обход дерева категорий: ```sql WITH monthly AS ( SELECT date_trunc('month', created_at) AS month, sum(total) AS revenue FROM orders GROUP BY 1 ) SELECT month, revenue, sum(revenue) OVER (ORDER BY month) AS running_total, revenue - lag(revenue) OVER (ORDER BY month) AS delta FROM monthly; ``` ## NULL и трёхзначная логика `NULL` в SQL означает «значение неизвестно». Любое сравнение с `NULL` даёт не `true` или `false`, а `NULL`, поэтому `WHERE x = NULL` не находит ничего — нужно писать `x IS NULL`. Агрегаты вроде `count(column)` и `avg` пропускают `NULL`, а `count(*)` считает все строки. ## Безопасность: SQL-инъекции Если подставлять пользовательский ввод в текст запроса склейкой строк, злоумышленник может изменить смысл запроса — это **SQL-инъекция**, одна из самых известных уязвимостей веб-приложений. Защита — **параметризованные запросы**, в которых значения передаются отдельно от текста SQL:[5] ```python # плохо: f"SELECT * FROM users WHERE email = '{email}'" cur.execute("SELECT * FROM users WHERE email = %s", (email,)) ``` [ORM](https://llmdocs.ru/wiki/orm.md) и построители запросов используют параметры автоматически. ## Диалекты Синтаксис различается в деталях: ограничение выборки (`LIMIT` в PostgreSQL, MySQL и SQLite против `TOP` в T-SQL и стандартного `FETCH FIRST n ROWS ONLY`), автоинкремент, функции работы с датами и строками, процедурные расширения (PL/pgSQL, T-SQL, PL/SQL). SQLite использует динамическую типизацию и поддерживает подмножество стандарта.[6] Посмотреть, как СУБД выполнит конкретный запрос, позволяет команда [EXPLAIN](https://llmdocs.ru/wiki/explain.md).[2] ## См. также - [Реляционная база данных](https://llmdocs.ru/wiki/relational-database.md) - [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) - [Индекс (базы данных)](https://llmdocs.ru/wiki/database-index.md) - [EXPLAIN и план запроса](https://llmdocs.ru/wiki/explain.md) - [ORM](https://llmdocs.ru/wiki/orm.md) ## Источники 1. [D. D. Chamberlin, R. F. Boyce — SEQUEL: A Structured English Query Language (1974)](https://dl.acm.org/doi/10.1145/800296.811515) 2. [PostgreSQL Documentation — The SQL Language](https://www.postgresql.org/docs/current/sql.html) 3. [PostgreSQL Documentation — SQL Conformance](https://www.postgresql.org/docs/current/features.html) 4. [PostgreSQL Documentation — Window Functions](https://www.postgresql.org/docs/current/tutorial-window.html) 5. [OWASP — SQL Injection Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html) 6. [SQLite — SQL As Understood By SQLite](https://www.sqlite.org/lang.html) --- # SQLite > Встраиваемая реляционная СУБД в виде библиотеки на C — вся база хранится в одном файле, сервер не нужен; самая распространённая база данных в мире. Источник: https://llmdocs.ru/wiki/sqlite/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: встраиваемая реляционная СУБД - **Автор**: Д. Ричард Хипп - **Первый выпуск**: август 2000 - **Язык**: C - **Лицензия**: общественное достояние (public domain) - **Хранение**: одна база — один кроссплатформенный файл - **Транзакции**: ACID, режимы журнала отката и WAL - **Распространённость**: более триллиона баз данных в эксплуатации **SQLite** — реляционная СУБД, которая работает не как отдельный сервер, а как библиотека внутри приложения. Вся база данных — таблицы, индексы, представления — хранится в одном обычном файле, который можно скопировать, отправить по почте или положить в репозиторий. SQLite поддерживает почти полный [SQL](https://llmdocs.ru/wiki/sql.md) и полноценные [транзакции ACID](https://llmdocs.ru/wiki/transaction-acid.md), не требует установки, настройки и администрирования.[1] По оценке разработчиков, SQLite — самая распространённая база данных в мире: она есть в каждом смартфоне на Android и iOS, во всех основных браузерах, в macOS и Windows, в автомобилях, самолётах и телевизорах; одновременно используется более триллиона баз SQLite.[2] ## История Д. Ричард Хипп начал разработку весной 2000 года, работая по контракту с General Dynamics над программой для эсминцев ВМС США: система на базе Informix переставала работать, когда сервер базы данных был недоступен. Хипп решил сделать базу данных, которой не нужен сервер вовсе. Первая версия вышла в августе 2000 года. Код передан в **общественное достояние** — его можно использовать без каких-либо лицензионных условий. Проект развивает небольшая команда, финансируемая консорциумом компаний; код покрыт тестами, объём которых в сотни раз превышает объём самой библиотеки. Библиотека Конгресса США рекомендует SQLite как формат долговременного хранения данных.[6] ## Использование ```bash sqlite3 app.db ``` ```sql CREATE TABLE notes ( id INTEGER PRIMARY KEY, title TEXT NOT NULL, body TEXT, created_at TEXT DEFAULT CURRENT_TIMESTAMP ) STRICT; INSERT INTO notes (title, body) VALUES ('Купить', 'молоко'); SELECT * FROM notes WHERE title LIKE 'Куп%'; .tables .schema notes ``` В [Python](https://llmdocs.ru/wiki/python.md) модуль `sqlite3` входит в стандартную библиотеку: ```python import sqlite3 with sqlite3.connect("app.db") as conn: conn.execute("PRAGMA journal_mode=WAL") conn.execute("INSERT INTO notes (title, body) VALUES (?, ?)", ("Идея", "написать статью")) for row in conn.execute("SELECT id, title FROM notes ORDER BY id DESC LIMIT 5"): print(row) ``` Параметры подставляются через `?`, а не склейкой строк — это защищает от SQL-инъекций. ## Особенности - **Динамическая типизация.** Тип связан со значением, а не со столбцом: в столбец `INTEGER` можно записать строку. С версии 3.37 (2021) таблицы `STRICT` проверяют типы строго.[5] - **Одна запись за раз.** Читать базу могут многие процессы одновременно, но записывающая транзакция в каждый момент одна. В **режиме WAL** читатели не блокируют писателя и наоборот, что резко повышает конкурентность.[4] - **Устройство хранения.** Таблицы и индексы — [B-деревья](https://llmdocs.ru/wiki/b-tree.md) внутри файла; формат файла стабилен и кроссплатформен с 2004 года. - **Расширения.** Полнотекстовый поиск FTS5, функции [JSON](https://llmdocs.ru/wiki/json.md), R-деревья для геоданных, векторный поиск через сторонние расширения (sqlite-vec). - **Ограничения SQL.** Изменение схемы (`ALTER TABLE`) ограничено, нет хранимых процедур и управления пользователями — всё это обычно не нужно встраиваемой базе. ## Когда подходит Сами разработчики формулируют: SQLite конкурирует не с клиент-серверными СУБД, а с функцией `fopen()`.[3] | Подходит | Лучше клиент-серверная СУБД | |---|---| | мобильные и настольные приложения | много серверов приложений пишут в одну базу | | встраиваемые устройства и IoT | высокая конкурентность записи | | формат файлов приложения | база больше нескольких терабайт | | сайты с умеренной нагрузкой на одном сервере | нужны тонкие права доступа и сетевые подключения | | тесты, прототипы, анализ данных, кэши | репликация и отказоустойчивость средствами СУБД | Сайт с сотнями тысяч посещений в день вполне может работать на SQLite, если записи не слишком часты, а приложение работает на одном сервере. ## SQLite на сервере В 2020-х SQLite стали активнее использовать в серверных приложениях: благодаря отсутствию сетевых задержек простые запросы выполняются за микросекунды. Экосистема закрывает недостающее: - **Litestream** непрерывно копирует изменения базы в объектное хранилище S3 для восстановления на момент времени;[7] - **LiteFS** и **libSQL/Turso** добавляют репликацию на несколько узлов; - фреймворки вроде Rails 8 предлагают SQLite как вариант для продакшена. Рекомендуемые настройки для сервера: режим WAL, `PRAGMA busy_timeout` (ждать вместо мгновенной ошибки при блокировке), `PRAGMA synchronous=NORMAL` в режиме WAL, `PRAGMA foreign_keys=ON` — проверка внешних ключей по умолчанию выключена. ## Сравнение с PostgreSQL [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) — полноценный сервер с богатой системой типов, параллельной записью, ролями, репликацией и расширениями; SQLite — минимализм и нулевое администрирование. Частая практика — SQLite для разработки и тестов, PostgreSQL в продакшене, — но различия в диалектах SQL и типизации иногда дают ошибки, которые проявляются только в продакшене. Надёжнее использовать одну и ту же СУБД во всех окружениях. ## См. также - [Реляционная база данных](https://llmdocs.ru/wiki/relational-database.md) - [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) - [SQL](https://llmdocs.ru/wiki/sql.md) - [B-дерево](https://llmdocs.ru/wiki/b-tree.md) - [Транзакция и ACID](https://llmdocs.ru/wiki/transaction-acid.md) ## Источники 1. [SQLite — About SQLite](https://www.sqlite.org/about.html) 2. [SQLite — Most Widely Deployed and Used Database Engine](https://www.sqlite.org/mostdeployed.html) 3. [SQLite — Appropriate Uses For SQLite](https://www.sqlite.org/whentouse.html) 4. [SQLite — Write-Ahead Logging](https://www.sqlite.org/wal.html) 5. [SQLite — STRICT Tables](https://www.sqlite.org/stricttables.html) 6. [SQLite — Recommended Storage Format (Library of Congress)](https://www.sqlite.org/locrsf.html) 7. [Litestream](https://litestream.io/) --- # Транзакция и ACID > Транзакция — группа операций с базой данных, выполняемая как единое целое; ACID — четыре свойства (атомарность, согласованность, изоляция, долговечность), которые она гарантирует. Источник: https://llmdocs.ru/wiki/transaction-acid/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Расшифровка**: Atomicity, Consistency, Isolation, Durability - **Концепция транзакции**: Джим Грей (1981) - **Термин ACID**: Тео Хэрдер, Андреас Ройтер (1983) - **Команды SQL**: BEGIN, COMMIT, ROLLBACK, SAVEPOINT - **Механизмы**: журнал упреждающей записи (WAL), блокировки, MVCC - **Противопоставляется**: BASE (в распределённых NoSQL-системах) **Транзакция** — последовательность операций с базой данных, которая выполняется как одно неделимое целое: либо применяются все изменения, либо ни одного. **ACID** — аббревиатура четырёх свойств, которые традиционно гарантирует транзакция в [реляционных СУБД](https://llmdocs.ru/wiki/relational-database.md): **атомарность** (*Atomicity*), **согласованность** (*Consistency*), **изоляция** (*Isolation*) и **долговечность** (*Durability*). Классический пример — перевод денег: списание с одного счёта и зачисление на другой должны произойти вместе. Если сервер упадёт между двумя операциями, деньги не должны исчезнуть или появиться из ниоткуда. ## История Понятие транзакции как единицы работы с гарантиями восстановления сформулировал Джим Грей в статье 1981 года;[6] за работы в этой области он получил премию Тьюринга (1998). Аббревиатуру ACID ввели Тео Хэрдер и Андреас Ройтер в обзоре 1983 года, посвящённом восстановлению баз данных после сбоев.[1] ## Пример ```sql BEGIN; UPDATE accounts SET balance = balance - 100 WHERE id = 1; UPDATE accounts SET balance = balance + 100 WHERE id = 2; -- если что-то пошло не так: ROLLBACK; COMMIT; ``` Пока транзакция не зафиксирована (`COMMIT`), другие сеансы не видят промежуточного состояния, а при ошибке или явном `ROLLBACK` база возвращается к исходному состоянию.[2] Точка сохранения (`SAVEPOINT`) позволяет откатить только часть транзакции. В приложениях транзакции обычно открывают через драйвер или [ORM](https://llmdocs.ru/wiki/orm.md): ```python with conn: # psycopg: COMMIT при успехе, ROLLBACK при исключении with conn.cursor() as cur: cur.execute("UPDATE accounts SET balance = balance - %s WHERE id = %s", (100, 1)) cur.execute("UPDATE accounts SET balance = balance + %s WHERE id = %s", (100, 2)) ``` ## Четыре свойства ### Атомарность Транзакция выполняется полностью или не выполняется вовсе. Если на середине возникла ошибка — нарушено ограничение, кончилось место, пропало питание, — все уже сделанные изменения отменяются. Приложению не нужно вручную «подчищать» частично записанные данные. ### Согласованность Транзакция переводит базу из одного корректного состояния в другое: после фиксации выполняются все объявленные ограничения — типы, `NOT NULL`, `UNIQUE`, `CHECK`, внешние ключи. Эта буква отличается от остальных: база проверяет только те правила, которые ей описаны, а бизнес-логику («баланс не может быть отрицательным») поддерживает приложение, в том числе с помощью ограничений `CHECK`. ### Изоляция Параллельные транзакции не должны мешать друг другу: результат должен быть таким, как если бы они выполнялись по очереди. Полная изоляция (сериализуемость) дорога, поэтому стандарт [SQL](https://llmdocs.ru/wiki/sql.md) определяет несколько [уровней изоляции](https://llmdocs.ru/wiki/isolation-levels.md), на которых допускаются те или иные аномалии:[3] | Уровень | Грязное чтение | Неповторяющееся чтение | Фантомы | |---|---|---|---| | Read Uncommitted | возможно | возможно | возможны | | Read Committed | нет | возможно | возможны | | Repeatable Read | нет | нет | возможны | | Serializable | нет | нет | нет | Это требования-минимумы стандарта; конкретные СУБД часто дают больше. В [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) уровень по умолчанию — Read Committed, а изоляция реализована через [MVCC](https://llmdocs.ru/wiki/mvcc.md): каждая транзакция видит снимок данных, и читатели не блокируют писателей. ### Долговечность После успешного `COMMIT` изменения не пропадут даже при внезапном отключении питания. Обычно это обеспечивает **журнал упреждающей записи** (WAL): описание изменения сначала надёжно записывается на диск в журнал (с вызовом `fsync`), и только потом СУБД сообщает об успехе. После сбоя база воспроизводит журнал и восстанавливает зафиксированные транзакции.[4] SQLite использует для той же цели журнал отката или WAL-режим.[5] ## Типичные проблемы - **Взаимоблокировки** (*deadlock*): две транзакции ждут блокировки, удерживаемые друг другом. СУБД обнаруживает цикл и прерывает одну из них — приложение должно уметь повторить транзакцию. - **Ошибки сериализации** на уровне Serializable — тоже сигнал к повтору, а не к аварии. - **Долгие транзакции** удерживают блокировки и мешают очистке старых версий строк; транзакции стоит держать короткими и не ждать внутри них ответа пользователя или внешнего API. - **Потерянное обновление**: «прочитать — изменить в коде — записать» без блокировки (`SELECT ... FOR UPDATE`) или атомарного `UPDATE ... SET x = x + 1` теряет параллельные изменения. ## ACID и распределённые системы Обеспечить ACID на одном сервере относительно просто; в распределённой базе это требует протоколов согласования (двухфазная фиксация, консенсус Raft или Paxos) и добавляет задержки. Поэтому многие системы [NoSQL](https://llmdocs.ru/wiki/nosql.md) исторически выбирали модель **BASE** (*Basically Available, Soft state, Eventual consistency*) — доступность и итоговую согласованность вместо строгих гарантий. Компромисс между согласованностью и доступностью при разделении сети описывает теорема CAP. Современные распределённые СУБД (Google Spanner, CockroachDB, YugabyteDB) предоставляют ACID-транзакции поверх [шардированных](https://llmdocs.ru/wiki/sharding.md) и [реплицированных](https://llmdocs.ru/wiki/replication.md) данных. ## См. также - [Уровни изоляции транзакций](https://llmdocs.ru/wiki/isolation-levels.md) - [MVCC](https://llmdocs.ru/wiki/mvcc.md) - [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) - [Репликация баз данных](https://llmdocs.ru/wiki/replication.md) - [NoSQL](https://llmdocs.ru/wiki/nosql.md) ## Источники 1. [T. Haerder, A. Reuter — Principles of Transaction-Oriented Database Recovery (ACM Computing Surveys, 1983)](https://dl.acm.org/doi/10.1145/289.291) 2. [PostgreSQL Documentation — Transactions (tutorial)](https://www.postgresql.org/docs/current/tutorial-transactions.html) 3. [PostgreSQL Documentation — Transaction Isolation](https://www.postgresql.org/docs/current/transaction-iso.html) 4. [PostgreSQL Documentation — Write-Ahead Logging](https://www.postgresql.org/docs/current/wal-intro.html) 5. [SQLite — Atomic Commit In SQLite](https://www.sqlite.org/atomiccommit.html) 6. [Jim Gray — The Transaction Concept: Virtues and Limitations (1981)](https://jimgray.azurewebsites.net/papers/thetransactionconcept.pdf) --- # Ansible > Безагентная система управления конфигурацией и автоматизации — по SSH выполняет на серверах идемпотентные задачи, описанные в YAML-плейбуках. Источник: https://llmdocs.ru/wiki/ansible/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: система управления конфигурацией - **Автор**: Майкл Деан (Michael DeHaan) - **Первый выпуск**: 2012 - **Владелец**: Red Hat (с октября 2015), часть IBM - **Язык**: Python - **Лицензия**: GPL 3.0 - **Транспорт**: SSH (Linux), WinRM/SSH (Windows), API сетевых устройств - **Описание задач**: YAML + шаблоны Jinja2 - **Распространение**: ansible-core + коллекции (Ansible Galaxy) **Ansible** — система автоматизации и управления конфигурацией серверов. Она подключается к машинам по [SSH](https://llmdocs.ru/wiki/ssh.md) и выполняет на них задачи, описанные в YAML-файлах — **плейбуках**: установить пакеты, разложить конфигурационные файлы, создать пользователей, перезапустить службы, выкатить новую версию приложения.[1] Главные отличия от предшественников (Puppet, Chef) — отсутствие агентов на управляемых машинах и низкий порог входа: достаточно Python на серверах и доступа по SSH. ## История Ansible создал Майкл Деан, ранее работавший над Cobbler и Func в Red Hat; первый выпуск состоялся в 2012 году. Простота быстро принесла проекту популярность, и в октябре 2015 года Red Hat купила компанию Ansible Inc.[6] В 2020 году проект разделили на минимальное ядро **ansible-core** и **коллекции** — пакеты модулей и плагинов для отдельных платформ, распространяемые через Ansible Galaxy. Коммерческая версия с веб-интерфейсом и планировщиком — Red Hat Ansible Automation Platform, её открытый аналог — AWX. ## Как работает 1. На **управляющей машине** (ноутбук, сервер CI) запускается `ansible-playbook`. 2. Ansible читает **инвентарь** — список хостов и групп.[4] 3. Для каждой задачи он копирует на хост небольшой Python-модуль по SSH, выполняет его и удаляет; модуль возвращает JSON с результатом. 4. Задачи идут по порядку, на всех хостах группы параллельно (по умолчанию по 5 одновременно, параметр `forks`). Ключевое свойство — **идемпотентность**: модуль сначала проверяет текущее состояние и вносит изменения только при необходимости. Повторный запуск плейбука на уже настроенном сервере ничего не меняет и отчитывается `changed=0`. Поэтому плейбук описывает желаемое состояние, а не последовательность команд (см. [Infrastructure as Code](https://llmdocs.ru/wiki/infrastructure-as-code.md)). ## Инвентарь и плейбук ```ini # inventory.ini [web] web1.example.com web2.example.com ansible_user=deploy [db] db1.example.com ``` ```yaml # site.yml - name: Настроить веб-серверы hosts: web become: true # sudo vars: app_port: 8000 tasks: - name: Установить nginx ansible.builtin.apt: name: nginx state: present update_cache: true - name: Разложить конфигурацию ansible.builtin.template: src: templates/site.conf.j2 dest: /etc/nginx/conf.d/site.conf notify: Перезагрузить nginx - name: Включить и запустить nginx ansible.builtin.systemd: name: nginx enabled: true state: started handlers: - name: Перезагрузить nginx ansible.builtin.systemd: name: nginx state: reloaded ``` **Обработчики** (*handlers*) выполняются один раз в конце, и только если задача, вызвавшая их через `notify`, что-то изменила: [nginx](https://llmdocs.ru/wiki/nginx.md) перезагрузится лишь при реальной смене конфигурации. Шаблоны пишутся на Jinja2 и получают переменные хоста, группы и **факты** — собранные Ansible сведения о системе (ОС, IP-адреса, память).[3] ## Команды ```bash ansible all -i inventory.ini -m ansible.builtin.ping # проверить доступность ansible web -i inventory.ini -a "uptime" # разовая команда ansible-playbook -i inventory.ini site.yml --check --diff # «сухой прогон» с показом изменений ansible-playbook -i inventory.ini site.yml --limit web1.example.com --tags nginx ansible-galaxy collection install community.postgresql ansible-vault encrypt group_vars/prod/secrets.yml ``` ## Роли и переиспользование **Роль** — стандартная структура каталогов (`tasks/`, `handlers/`, `templates/`, `defaults/`, `vars/`), упаковывающая настройку одного компонента: «nginx», «postgres», «пользователи». Роли и коллекции публикуются в Ansible Galaxy. Переменные можно задавать на многих уровнях — в инвентаре, `group_vars/`, `host_vars/`, в роли, в командной строке; порядок их приоритета — частый источник путаницы. Секреты шифруют **Ansible Vault**: файлы с паролями хранятся в Git зашифрованными AES-256 и расшифровываются при запуске по паролю или ключу.[5] ## Место среди инструментов | Задача | Типичный инструмент | |---|---| | Создать облачные ресурсы | [Terraform и OpenTofu](https://llmdocs.ru/wiki/terraform-opentofu.md) | | Настроить ОС и программы на серверах | Ansible, Puppet, Chef, Salt | | Запустить приложения в контейнерах | [Docker Compose](https://llmdocs.ru/wiki/docker-compose.md), [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) | Ansible часто вызывают после Terraform: тот создаёт виртуальные машины, а Ansible их настраивает. Минусы — невысокая скорость на сотнях хостов (каждая задача — отдельное SSH-подключение, частично смягчается конвейеризацией и Mitogen), отсутствие хранимого состояния (удалённая из плейбука задача не отменяет уже сделанного) и сложность отладки больших YAML-проектов. Для проверки ролей используют ansible-lint и Molecule. ## См. также - [Infrastructure as Code](https://llmdocs.ru/wiki/infrastructure-as-code.md) - [Terraform и OpenTofu](https://llmdocs.ru/wiki/terraform-opentofu.md) - [systemd](https://llmdocs.ru/wiki/systemd.md) - [Управление секретами](https://llmdocs.ru/wiki/secrets-management.md) ## Источники 1. [Ansible Documentation](https://docs.ansible.com/) 2. [Ansible Docs — Getting started](https://docs.ansible.com/ansible/latest/getting_started/) 3. [Ansible Docs — Intro to playbooks](https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_intro.html) 4. [Ansible Docs — How to build your inventory](https://docs.ansible.com/ansible/latest/inventory_guide/intro_inventory.html) 5. [Ansible Docs — Protecting sensitive data with Ansible Vault](https://docs.ansible.com/ansible/latest/vault_guide/index.html) 6. [Red Hat — Red Hat to acquire IT automation leader Ansible (2015)](https://www.redhat.com/en/about/press-releases/red-hat-acquire-it-automation-and-devops-leader-ansible) --- # Бэкапы: правило 3-2-1 > Базовое правило резервного копирования — три копии данных, на двух разных носителях, одна из них в другом месте; плюс практика проверки восстановления. Источник: https://llmdocs.ru/wiki/backup-3-2-1/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Формула**: 3 копии, 2 типа носителей, 1 копия вне площадки - **Автор формулировки**: Питер Крог (The DAM Book, фотографы) - **Расширения**: 3-2-1-1-0 (одна неизменяемая/офлайн копия, 0 ошибок при проверке) - **Ключевые метрики**: RPO (допустимая потеря данных), RTO (время восстановления) - **Инструменты**: restic, BorgBackup, Kopia, rclone, pgBackRest, Veeam - **Главная угроза сегодня**: вымогатели, шифрующие и сами бэкапы **Правило 3-2-1** — простая и общепринятая формула резервного копирования: храните **3** копии данных, на **2** разных типах носителей, причём **1** копия должна находиться вне основной площадки.[1][2] Его сформулировал фотограф Питер Крог в книге о хранении цифровых архивов, а затем правило стало стандартной рекомендацией и для домашних пользователей, и для компаний. Смысл в том, чтобы ни одна единичная беда — отказ диска, пожар, кража, ошибка администратора или вирус-вымогатель — не уничтожила все копии сразу. ## Разбор формулы - **Три копии** — рабочие данные плюс две резервные. Вероятность одновременной потери трёх независимых копий ничтожна. - **Два типа носителей** — например, диск сервера и облачное хранилище, или NAS и внешний диск. Однотипные носители из одной партии часто выходят из строя похожим образом и в одно время. - **Одна копия вне площадки** — в другом здании, городе или облаке. Пожар, затопление или изъятие оборудования не затронут её. Современная версия **3-2-1-1-0** добавляет: ещё **одна** копия должна быть **неизменяемой** (*immutable*) или отключённой от сети (*air-gapped*), и **ноль** ошибок при проверке восстановления. Первое — ответ на вымогателей, которые сначала находят и удаляют резервные копии, а затем шифруют основные данные.[4] ## Что не является бэкапом | Механизм | Почему не бэкап | |---|---| | RAID | защищает от отказа диска, но не от удаления файла или шифрования — изменения мгновенно попадают на все диски | | Синхронизация (Dropbox, `rsync --delete`) | удалённый или испорченный файл тут же удаляется или портится и в копии | | Снимки (snapshots) на том же томе | спасают от ошибок, но погибают вместе с массивом | | Репликация базы данных | `DROP TABLE` реплицируется на все узлы за доли секунды | Бэкап — это **независимая копия с историей версий**, из которой можно восстановить состояние на определённый момент в прошлом. ## RPO и RTO Перед выбором схемы определяют две величины:[3] - **RPO** (*Recovery Point Objective*) — сколько данных допустимо потерять. Ночной бэкап означает RPO до 24 часов; для базы с журналом транзакций — минуты или секунды. - **RTO** (*Recovery Time Objective*) — за сколько нужно восстановиться. Скачать 5 ТБ из облачного «холодного» хранилища может занять сутки. Разные данные требуют разных значений: база заказов — минуты, архив логов — дни. ## Практика **Файлы и серверы.** Инструменты с дедупликацией и шифрованием на стороне клиента — restic, BorgBackup, Kopia — хранят много версий почти без лишнего места и пишут в локальный каталог, по [SSH](https://llmdocs.ru/wiki/ssh.md) или в S3-совместимое хранилище.[5] ```bash restic -r s3:https://s3.example.com/backups init restic -r s3:https://s3.example.com/backups backup /etc /srv/data --exclude-caches restic -r s3:https://s3.example.com/backups forget --keep-daily 7 --keep-weekly 4 --keep-monthly 12 --prune restic -r s3:https://s3.example.com/backups check --read-data-subset=5% restic -r s3:https://s3.example.com/backups restore latest --target /tmp/restore-test ``` Запуск — по расписанию через [cron или таймеры systemd](https://llmdocs.ru/wiki/cron-systemd-timers.md), с оповещением о неудаче (см. [Мониторинг и алертинг](https://llmdocs.ru/wiki/monitoring-alerting.md)): тихо сломавшийся бэкап — классический сценарий катастрофы. **Базы данных.** Копировать файлы работающей [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) нельзя — получится несогласованный снимок. Используют логические дампы (`pg_dump`) для небольших баз и физические бэкапы с архивом журнала WAL (pgBackRest, WAL-G) — они позволяют восстановить базу на любую секунду (*point-in-time recovery*).[6] **Неизменяемость.** Object Lock в S3-совместимых хранилищах, режим «только добавление» (*append-only*) у Borg и restic через rest-server, отдельные учётные данные: сервер может записывать новые копии, но не удалять старые. Права на удаление — только у отдельной, хорошо защищённой учётной записи (см. [Принцип наименьших привилегий](https://llmdocs.ru/wiki/least-privilege.md)). **Шифрование.** Копия вне площадки должна быть зашифрована, а ключ — храниться отдельно от неё и от основного сервера. Потерянный ключ означает потерянный бэкап. ## Главное — проверка восстановления Резервная копия, которую ни разу не восстанавливали, — это надежда, а не бэкап. Регулярно: 1. Восстанавливайте случайные файлы и целые системы на тестовый стенд. 2. Проверяйте целостность хранилища (`restic check`, `borg check`). 3. Засекайте время полного восстановления и сравнивайте с RTO. 4. Записывайте процедуру восстановления так, чтобы её мог выполнить другой человек — в стрессовой ситуации и без доступа к упавшей системе. ## См. также - [rsync](https://llmdocs.ru/wiki/rsync.md) - [Управление секретами](https://llmdocs.ru/wiki/secrets-management.md) - [Репликация](https://llmdocs.ru/wiki/replication.md) - [Infrastructure as Code](https://llmdocs.ru/wiki/infrastructure-as-code.md) ## Источники 1. [US-CERT — Data Backup Options (2012)](https://www.cisa.gov/sites/default/files/publications/data_backup_options.pdf) 2. [Backblaze — The 3-2-1 Backup Strategy](https://www.backblaze.com/blog/the-3-2-1-backup-strategy/) 3. [NIST SP 800-34 Rev. 1 — Contingency Planning Guide for Federal Information Systems](https://csrc.nist.gov/pubs/sp/800/34/r1/upd1/final) 4. [CISA — #StopRansomware Guide](https://www.cisa.gov/stopransomware/ransomware-guide) 5. [restic Documentation](https://restic.readthedocs.io/) 6. [PostgreSQL Docs — Backup and Restore](https://www.postgresql.org/docs/current/backup.html) --- # CI/CD > Практика непрерывной интеграции (CI) и непрерывной поставки или развёртывания (CD) — автоматическая сборка, тестирование и выкладка каждого изменения кода. Источник: https://llmdocs.ru/wiki/ci-cd/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **CI**: непрерывная интеграция - **CD**: непрерывная поставка (delivery) или развёртывание (deployment) - **Истоки**: экстремальное программирование (конец 1990-х) - **Ключевые тексты**: Мартин Фаулер «Continuous Integration» (2000), Хамбл и Фарли «Continuous Delivery» (2010) - **Инструменты**: GitHub Actions, GitLab CI, Jenkins, CircleCI, Argo CD - **Метрики**: DORA (частота развёртываний, время выполнения изменений, доля неудачных изменений, время восстановления) **CI/CD** — набор практик автоматизации, при котором каждое изменение кода автоматически собирается, проверяется и доводится до пользователей. **CI** (*Continuous Integration*, непрерывная интеграция) — разработчики часто вливают изменения в общую ветку, и каждое вливание запускает сборку и тесты. **CD** — либо *Continuous Delivery* (непрерывная поставка: любая проверенная версия готова к выкладке одной кнопкой), либо *Continuous Deployment* (непрерывное развёртывание: каждое изменение, прошедшее проверки, выкладывается в продакшен автоматически). Цель — короткий и надёжный путь от коммита до работающего продукта: ошибки находятся через минуты после появления, а выкладка становится рутинной операцией, а не рискованным событием раз в квартал. ## История Термин «непрерывная интеграция» употребил Грейди Буч в 1991 году, а практикой его сделало экстремальное программирование Кента Бека в конце 1990-х. Широкую известность принесла статья Мартина Фаулера «Continuous Integration» (2000, с последующими редакциями).[1] Инструменты появились тогда же: CruiseControl (2001), Hudson (2005), который в 2011 году после конфликта с Oracle продолжил развиваться как Jenkins.[6] В 2010 году Джез Хамбл и Дэвид Фарли выпустили книгу «Continuous Delivery», описавшую **конвейер развёртывания** (*deployment pipeline*).[2] В 2010-х CI переехала в облака и в сами платформы хостинга кода: Travis CI, CircleCI, [GitLab CI](https://llmdocs.ru/wiki/gitlab-ci.md), а с 2019 года — [GitHub Actions](https://llmdocs.ru/wiki/github-actions.md). ## Конвейер Конвейер (*pipeline*) — последовательность этапов, которые проходит каждое изменение: | Этап | Что происходит | |---|---| | Триггер | push в ветку, открытие [pull request](https://llmdocs.ru/wiki/pull-request.md), тег, расписание | | Сборка | установка зависимостей, компиляция, сборка образа по [Dockerfile](https://llmdocs.ru/wiki/dockerfile.md) | | Статические проверки | линтеры, форматирование, проверка типов, поиск секретов и уязвимостей | | Тесты | модульные, интеграционные, сквозные | | Публикация артефакта | образ в [реестр](https://llmdocs.ru/wiki/container-registry.md), пакет, бинарник с версией | | Развёртывание | тестовое окружение → продакшен | | Проверка после выкладки | смоук-тесты, [мониторинг](https://llmdocs.ru/wiki/monitoring-alerting.md), автоматический откат | Если любой этап падает, конвейер останавливается, а автор изменения получает уведомление. Важный принцип — **артефакт собирается один раз** и без изменений проходит все окружения: в продакшен попадает ровно то, что тестировали. ## Пример Конвейер [GitHub Actions](https://llmdocs.ru/wiki/github-actions.md) для проекта на [Python](https://llmdocs.ru/wiki/python.md):[4] ```yaml # .github/workflows/ci.yml name: CI on: push: branches: [main] pull_request: jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: astral-sh/setup-uv@v6 - run: uv sync --locked - run: uv run ruff check . - run: uv run pytest --maxfail=1 deploy: needs: test if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest environment: production steps: - uses: actions/checkout@v4 - run: ./scripts/deploy.sh env: DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }} ``` В [GitLab CI](https://llmdocs.ru/wiki/gitlab-ci.md) аналогичное описание хранится в файле `.gitlab-ci.yml` со стадиями `stages`.[5] Конвейер — такой же код, как приложение: он версионируется в [Git](https://llmdocs.ru/wiki/git.md) и проходит ревью. ## Стратегии развёртывания - **Rolling update** — экземпляры заменяются новыми по очереди; так по умолчанию обновляет [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md). - **Blue-green** — новая версия поднимается рядом со старой, и трафик переключается целиком; откат — переключение обратно. - **Canary** — новая версия сначала получает небольшую долю трафика; при росте ошибок выкладка останавливается. - **Флаги функций** — код выкладывается выключенным и включается для части пользователей независимо от развёртывания. Инфраструктуру, в которую идёт выкладка, тоже описывают кодом и меняют через конвейер — см. [Infrastructure as Code](https://llmdocs.ru/wiki/infrastructure-as-code.md). В подходе **GitOps** желаемое состояние кластера хранится в репозитории, а агенты вроде Argo CD или Flux синхронизируют с ним кластер. ## Как измерять Исследовательская программа DORA выделила четыре ключевые метрики эффективности поставки:[3] 1. **Частота развёртываний** — как часто изменения попадают в продакшен. 2. **Время выполнения изменений** (*lead time*) — от коммита до продакшена. 3. **Доля неудачных изменений** — какой процент выкладок требует исправления или отката. 4. **Время восстановления** после неудачного развёртывания. Исследования DORA показывают, что скорость и стабильность не противоречат друг другу: команды, выкладывающие чаще и меньшими порциями, как правило, реже ломают продакшен. ## Хорошие практики - Быстрый конвейер: проверки pull request должны укладываться в минуты; медленные тесты распараллеливают и кэшируют зависимости. - Сломанная основная ветка — главный приоритет команды. - Секреты — только в хранилище секретов CI, а не в репозитории; права токенов развёртывания — минимальные. - Нестабильные (*flaky*) тесты чинить или изолировать: иначе к красным сборкам привыкают и перестают их замечать. - Версии релизов — по правилам [семантического версионирования](https://llmdocs.ru/wiki/semver.md). ## См. также - [GitHub Actions](https://llmdocs.ru/wiki/github-actions.md) - [GitLab CI](https://llmdocs.ru/wiki/gitlab-ci.md) - [Infrastructure as Code](https://llmdocs.ru/wiki/infrastructure-as-code.md) - [Git](https://llmdocs.ru/wiki/git.md) - [Мониторинг и алертинг](https://llmdocs.ru/wiki/monitoring-alerting.md) ## Источники 1. [Martin Fowler — Continuous Integration](https://martinfowler.com/articles/continuousIntegration.html) 2. [Jez Humble — Continuous Delivery](https://continuousdelivery.com/) 3. [DORA — DORA's software delivery metrics](https://dora.dev/guides/dora-metrics-four-keys/) 4. [GitHub Docs — GitHub Actions](https://docs.github.com/en/actions) 5. [GitLab Docs — CI/CD](https://docs.gitlab.com/ci/) 6. [Jenkins](https://www.jenkins.io/) --- # Ветвление в Git > Механизм веток в Git — лёгких подвижных указателей на коммиты, позволяющих вести параллельные линии разработки; а также модели работы с ветками в команде. Источник: https://llmdocs.ru/wiki/git-branching/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Что такое ветка**: подвижный указатель на коммит - **Основные команды**: git branch, git switch, git merge, git rebase - **git switch**: с Git 2.23 (2019) - **Ветка по умолчанию**: настраивается через init.defaultBranch (с Git 2.28, 2020) - **Модели ветвления**: GitHub Flow, Git Flow, trunk-based development **Ветвление** в [Git](https://llmdocs.ru/wiki/git.md) — возможность вести несколько независимых линий разработки в одном репозитории: делать новую функцию, исправлять ошибку и экспериментировать, не мешая друг другу и основной версии кода. **Ветка** в Git — всего лишь лёгкий подвижный указатель на коммит, поэтому её создание и переключение происходят мгновенно, а ветки создают десятками. Именно дешёвое ветвление отличало Git от более старых систем, где ветка означала копирование всего проекта.[1] ## Как устроены ветки История Git — граф коммитов, каждый из которых ссылается на родителя. Ветка — это файл, в котором записан хеш одного коммита. Когда вы делаете новый коммит, указатель текущей ветки сдвигается на него. Особый указатель **HEAD** показывает, какая ветка сейчас активна. ```text C---D feature ← HEAD / A---B---E main ``` Здесь ветка `feature` ответвилась от коммита `B` и получила два коммита, а в `main` тем временем появился коммит `E`. ```bash git branch # список локальных веток git switch -c feature/login # создать ветку и перейти на неё git switch main # вернуться на main git branch -d feature/login # удалить слитую ветку git branch -vv # ветки и их связь с удалёнными ``` Команда `git switch` появилась в Git 2.23 (2019) как более понятная замена перегруженной `git checkout`, которая и переключает ветки, и восстанавливает файлы.[2] ## Слияние веток Готовую работу возвращают в основную ветку двумя способами (подробно — в статье [Merge и rebase](https://llmdocs.ru/wiki/merge-rebase.md)): - **Перемотка** (*fast-forward*): если в `main` не было новых коммитов, указатель просто сдвигается вперёд, история остаётся линейной. - **Коммит слияния** (*merge commit*): если ветки разошлись, Git создаёт коммит с двумя родителями, объединяющий изменения.[6] Если обе ветки изменили одни и те же строки, возникает **конфликт**: Git помечает спорные места маркерами `<<<<<<<`, `=======`, `>>>>>>>`, и человек решает, какой вариант оставить, после чего фиксирует результат. Альтернатива слиянию — **rebase**: коммиты ветки переносятся поверх свежей `main`, история становится линейной, но хеши коммитов меняются. Поэтому перебазировать можно только свою, ещё никем не используемую ветку. ## Удалённые ветки Ветки на сервере видны локально как `origin/main`, `origin/feature/login` — это снимки состояния на момент последнего `git fetch`. Локальная ветка может **отслеживать** удалённую, тогда `git pull` и `git push` работают без аргументов: ```bash git push -u origin feature/login # опубликовать ветку и связать её с удалённой git fetch --prune # обновить сведения и удалить исчезнувшие ветки ``` На платформах вроде [GitHub](https://llmdocs.ru/wiki/github.md) и [GitLab](https://llmdocs.ru/wiki/gitlab.md) слияние обычно происходит не локально, а через [pull request](https://llmdocs.ru/wiki/pull-request.md), где изменения проверяют коллеги и автоматические тесты [CI/CD](https://llmdocs.ru/wiki/ci-cd.md). ## Ветка по умолчанию Основная ветка исторически называлась `master`. В 2020 году GitHub, GitLab и другие платформы перешли на `main` для новых репозиториев, а в Git 2.28 появилась настройка `init.defaultBranch`. Ничего особенного в имени нет: основная ветка — та, которую команда договорилась считать главной. ## Модели ветвления | Модель | Суть | Подходит для | |---|---|---| | **GitHub Flow** | `main` всегда готова к выкладке; каждая задача — короткая ветка, слияние через pull request, затем развёртывание[4] | веб-сервисы с непрерывной поставкой | | **Git Flow** | долгоживущие `main` и `develop`, ветки `feature/*`, `release/*`, `hotfix/*`[3] | продукты с версионными релизами и поддержкой старых версий | | **Trunk-based development** | все интегрируют изменения в общий ствол (*trunk*) минимум раз в день; ветки живут часы, незавершённое прячется за флагами функций[5] | зрелые команды с сильной автоматизацией тестов | Модель Git Flow описал Винсент Дриссен в 2010 году; позже сам автор отметил, что для веб-приложений с непрерывной поставкой лучше подходят более простые схемы. Общая тенденция — короче ветки и чаще интеграция: чем дольше живёт ветка, тем больнее её сливать. ## Практические советы - Называйте ветки по смыслу и с префиксом: `feature/`, `fix/`, `chore/`, иногда с номером задачи. - Регулярно подтягивайте изменения основной ветки в свою, чтобы конфликты были маленькими. - Защищайте `main` на сервере: запрет прямых push, обязательные проверки и ревью. - Удаляйте слитые ветки — платформы умеют делать это автоматически. - Для работы над двумя ветками одновременно без переключения используйте `git worktree` — отдельные рабочие каталоги для разных веток одного репозитория. ## См. также - [Git](https://llmdocs.ru/wiki/git.md) - [Merge и rebase](https://llmdocs.ru/wiki/merge-rebase.md) - [Pull request / Merge request](https://llmdocs.ru/wiki/pull-request.md) - [CI/CD](https://llmdocs.ru/wiki/ci-cd.md) - [GitHub](https://llmdocs.ru/wiki/github.md) ## Источники 1. [Pro Git — Branches in a Nutshell](https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell) 2. [Git — git-switch documentation](https://git-scm.com/docs/git-switch) 3. [Vincent Driessen — A successful Git branching model (2010)](https://nvie.com/posts/a-successful-git-branching-model/) 4. [GitHub Docs — GitHub flow](https://docs.github.com/en/get-started/using-github/github-flow) 5. [Trunk Based Development](https://trunkbaseddevelopment.com/) 6. [Pro Git — Basic Branching and Merging](https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging) --- # Git-хуки > Скрипты, которые Git запускает на определённых событиях — перед коммитом, при пуше, на сервере при приёме изменений; основа линтинга и проверок до CI. Источник: https://llmdocs.ru/wiki/git-hooks/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Где лежат**: .git/hooks/ (или core.hooksPath) - **Типы**: клиентские и серверные - **Популярные клиентские**: pre-commit, commit-msg, pre-push - **Серверные**: pre-receive, update, post-receive - **Менеджеры**: pre-commit (Python), husky (Node.js), lefthook (Go) - **Обход**: git commit --no-verify **Git-хуки** (англ. *git hooks*) — программы, которые [Git](https://llmdocs.ru/wiki/git.md) автоматически запускает в определённые моменты своей работы: перед созданием коммита, после смены ветки, перед отправкой изменений на сервер, при приёме пуша на сервере. Если хук завершается с ненулевым кодом, Git отменяет операцию. Хуки используют, чтобы ловить ошибки как можно раньше — запускать линтер и форматтер, проверять сообщения коммитов, не пропускать в репозиторий секреты — ещё до того, как изменения попадут в [CI/CD](https://llmdocs.ru/wiki/ci-cd.md). ## Как устроены Хуки — это исполняемые файлы с фиксированными именами в каталоге `.git/hooks/`. При `git init` там создаются примеры с суффиксом `.sample`; чтобы включить хук, достаточно убрать суффикс и сделать файл исполняемым.[1] Язык не важен: подойдёт [shell](https://llmdocs.ru/wiki/shell-bash.md), Python, Node.js — что угодно с правильной строкой `#!`. Каталог `.git/` не попадает в репозиторий, поэтому хуки не передаются при клонировании — это сделано намеренно, иначе любой репозиторий мог бы выполнить код на машине разработчика. Чтобы поделиться хуками с командой, их кладут в отслеживаемую папку и указывают Git путь к ней: ```bash git config core.hooksPath .githooks ``` Либо используют менеджеры хуков, о которых ниже. ## Клиентские хуки | Хук | Когда | Типичное применение | |---|---|---| | `pre-commit` | перед созданием коммита | линтеры, форматтеры, поиск секретов | | `prepare-commit-msg` | перед открытием редактора | шаблон, номер задачи из имени ветки | | `commit-msg` | после ввода сообщения | проверка формата (Conventional Commits) | | `post-commit` | после коммита | уведомления | | `post-checkout`, `post-merge` | после смены ветки, слияния | установить зависимости, если изменился lock-файл | | `pre-rebase` | перед [rebase](https://llmdocs.ru/wiki/merge-rebase.md) | запрет переписывать опубликованные ветки | | `pre-push` | перед отправкой | быстрые тесты | Пример простого `pre-commit`, не дающего закоммитить отладочный вывод: ```bash #!/bin/sh if git diff --cached -U0 | grep -E '^\+.*(console\.log|breakpoint\(\))'; then echo "Уберите отладочный код перед коммитом" >&2 exit 1 fi ``` Хук должен проверять именно индекс (`git diff --cached`), а не рабочую копию — иначе в проверку попадут незастейдженные правки. ## Серверные хуки На сервере выполняются `pre-receive`, `update` и `post-receive`.[2] Они могут отклонить пуш (например, в защищённую ветку или без подписи) или запустить действие после него — исторически так делали простейший деплой: `post-receive` выкладывал код в каталог сайта. На [GitHub](https://llmdocs.ru/wiki/github.md) и [GitLab](https://llmdocs.ru/wiki/gitlab.md) произвольные серверные хуки обычно недоступны (GitLab разрешает их на собственной установке); вместо них используют правила защиты веток, push rules и вебхуки, а проверки — в CI. ## Менеджеры хуков - **pre-commit** — фреймворк на Python с тысячами готовых хуков; конфигурация в `.pre-commit-config.yaml`, каждое средство ставится в изолированное окружение. Работает для любых языков.[3] - **husky** — популярный выбор в экосистеме JavaScript, хуки хранятся в `.husky/`; часто в паре с `lint-staged`, который проверяет только изменённые файлы.[4] - **lefthook** — быстрый менеджер на Go с параллельным запуском и конфигурацией в YAML.[5] ```yaml # .pre-commit-config.yaml repos: - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.7.0 hooks: - id: ruff args: [--fix] - id: ruff-format - repo: https://github.com/gitleaks/gitleaks rev: v8.21.0 hooks: - id: gitleaks ``` После `pre-commit install` хуки срабатывают на каждом коммите и проверяют только изменённые файлы; `pre-commit run --all-files` прогоняет весь репозиторий. Здесь [Ruff](https://llmdocs.ru/wiki/ruff.md) проверяет Python-код, а gitleaks ищет случайно добавленные ключи и пароли. ## Проверка сообщений коммитов Хук `commit-msg` часто проверяет соответствие соглашению **Conventional Commits** (`feat: ...`, `fix(api): ...`) с помощью commitlint.[6] На таких сообщениях строится автоматическая генерация CHANGELOG и выбор следующей версии по правилам [семантического версионирования](https://llmdocs.ru/wiki/semver.md). ## Ограничения Клиентские хуки — удобство, а не гарантия: их легко обойти флагом `--no-verify`, а у нового участника они не установлены, пока он не выполнит установку. Поэтому все обязательные проверки дублируют в CI, а хуки делают быстрыми — несколько секунд, — иначе разработчики начнут их отключать. Долгие тесты лучше оставить для `pre-push` или CI. ## См. также - [Git](https://llmdocs.ru/wiki/git.md) - [CI/CD](https://llmdocs.ru/wiki/ci-cd.md) - [Pull request / Merge request](https://llmdocs.ru/wiki/pull-request.md) - [GitHub Actions](https://llmdocs.ru/wiki/github-actions.md) ## Источники 1. [Git Documentation — githooks](https://git-scm.com/docs/githooks) 2. [Pro Git — Customizing Git: Git Hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks) 3. [pre-commit — framework for managing git hooks](https://pre-commit.com/) 4. [husky](https://typicode.github.io/husky/) 5. [lefthook](https://github.com/evilmartians/lefthook) 6. [Conventional Commits](https://www.conventionalcommits.org/) --- # Git > Распределённая система контроля версий, созданная Линусом Торвальдсом в 2005 году; хранит историю изменений проекта в виде графа коммитов и стала стандартом разработки ПО. Источник: https://llmdocs.ru/wiki/git/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: распределённая система контроля версий - **Автор**: Линус Торвальдс - **Первый выпуск**: апрель 2005 - **Сопровождающий**: Дзюнио Хамано (с июля 2005) - **Языки**: C, Shell, Perl - **Лицензия**: GNU GPL v2 - **Хеш-функция объектов**: SHA-1 (поддерживается SHA-256) - **Сайт**: git-scm.com **Git** — распределённая система контроля версий: программа, которая хранит историю изменений файлов проекта, позволяет вернуться к любой прошлой версии, вести параллельные линии разработки и объединять работу многих людей. «Распределённая» означает, что у каждого участника есть полная копия репозитория со всей историей, и большинство операций выполняется локально, без сервера. Git используют подавляющее большинство разработчиков; на нём построены платформы [GitHub](https://llmdocs.ru/wiki/github.md) и [GitLab](https://llmdocs.ru/wiki/gitlab.md), процессы [code review](https://llmdocs.ru/wiki/pull-request.md) и [CI/CD](https://llmdocs.ru/wiki/ci-cd.md). Вне программирования Git применяют для документации, конфигураций ([Infrastructure as Code](https://llmdocs.ru/wiki/infrastructure-as-code.md)) и даже книг. ## История С 2002 года ядро [Linux](https://llmdocs.ru/wiki/linux.md) разрабатывалось в коммерческой системе BitKeeper, которую авторы предоставляли сообществу бесплатно. В 2005 году бесплатную лицензию отозвали, и Линус Торвальдс за несколько дней написал собственную систему. Требования были чёткими: скорость, простая модель, поддержка тысяч параллельных веток, полная распределённость и способность работать с проектом размера ядра.[2] Первая версия появилась 7 апреля 2005 года, а уже в июле сопровождение перешло к Дзюнио Хамано, который ведёт проект до сих пор. Название Торвальдс объяснял шутливо: *git* на британском сленге — «вредный тип», а он «называет все проекты в свою честь». Популярность Git резко выросла с запуском GitHub в 2008 году; к середине 2010-х он вытеснил Subversion, Mercurial и другие системы. ## Модель данных Git хранит не разницу между версиями, а **снимки** проекта. Все данные — объекты четырёх типов, адресуемые по [хешу](https://llmdocs.ru/wiki/hash-function.md) содержимого:[3] | Объект | Что хранит | |---|---| | blob | содержимое файла | | tree | каталог: имена файлов и ссылки на blob и другие tree | | commit | ссылка на tree (снимок), родительские коммиты, автор, дата, сообщение | | tag | именованная ссылка на коммит с подписью и описанием | Одинаковые файлы хранятся один раз, а любое изменение в истории меняет хеши всех последующих коммитов — поэтому историю нельзя незаметно подделать. Исторически Git использует SHA-1; после демонстрации практической коллизии SHA-1 в 2017 году в Git добавлены защита от известных атак и поддержка SHA-256 для новых репозиториев.[4] **Ветки** — это просто подвижные указатели на коммиты, поэтому создание ветки мгновенно; подробнее — в статье [Ветвление в Git](https://llmdocs.ru/wiki/git-branching.md). ## Три области Файл в рабочем каталоге проходит через три состояния: 1. **Рабочий каталог** (*working tree*) — файлы, которые вы редактируете. 2. **Индекс** (*staging area*) — подготовленные к коммиту изменения; `git add` переносит их сюда. 3. **Репозиторий** (`.git`) — зафиксированная история; `git commit` создаёт новый снимок из индекса. Индекс позволяет собрать в один коммит только часть изменений — например, отделить исправление ошибки от попутного рефакторинга (`git add -p`). ## Основные команды ```bash git init # новый репозиторий git clone git@github.com:user/repo.git git status # что изменено git add file.py # в индекс git commit -m "Добавить проверку email" git log --oneline --graph # история git diff # изменения, ещё не в индексе git switch -c feature/login # новая ветка git merge feature/login # слить ветку git pull # забрать изменения с сервера (fetch + merge/rebase) git push origin feature/login # отправить ветку на сервер git restore file.py # отменить локальные правки файла git revert a1b2c3d # новый коммит, отменяющий старый ``` Подробное описание каждой команды есть в справочнике Git, а лучшее введение — бесплатная книга «Pro Git».[6][1] ## Удалённые репозитории Удалённый репозиторий (*remote*) — копия на сервере, обычно с именем `origin`. Git передаёт данные по [SSH](https://llmdocs.ru/wiki/ssh.md) или HTTPS. Команда `fetch` скачивает новые коммиты, не трогая ваши ветки, `pull` дополнительно объединяет их с текущей веткой, `push` отправляет локальные коммиты. Поскольку у всех полные копии, потеря сервера не означает потерю истории. ## Хорошие практики - Небольшие осмысленные коммиты с сообщением в повелительном наклонении: что и зачем изменено. - Файл `.gitignore` для сборочных артефактов, `.venv`, `node_modules`, логов. - **Никогда не коммитить секреты**: ключ, попавший в историю, остаётся в ней и после удаления файла — его нужно отзывать. - Не переписывать (`rebase`, `push --force`) историю веток, которыми пользуются другие; про выбор между слиянием и перебазированием — [Merge и rebase](https://llmdocs.ru/wiki/merge-rebase.md). - Версии релизов отмечать тегами по правилам [семантического версионирования](https://llmdocs.ru/wiki/semver.md), а проверки перед коммитом автоматизировать [хуками](https://llmdocs.ru/wiki/git-hooks.md). ## См. также - [Ветвление в Git](https://llmdocs.ru/wiki/git-branching.md) - [Merge и rebase](https://llmdocs.ru/wiki/merge-rebase.md) - [GitHub](https://llmdocs.ru/wiki/github.md) - [Pull request / Merge request](https://llmdocs.ru/wiki/pull-request.md) - [CI/CD](https://llmdocs.ru/wiki/ci-cd.md) ## Источники 1. [Pro Git — Scott Chacon, Ben Straub](https://git-scm.com/book/en/v2) 2. [Pro Git — A Short History of Git](https://git-scm.com/book/en/v2/Getting-Started-A-Short-History-of-Git) 3. [Pro Git — Git Internals: Git Objects](https://git-scm.com/book/en/v2/Git-Internals-Git-Objects) 4. [Git — hash-function-transition](https://git-scm.com/docs/hash-function-transition) 5. [git/git — исходный код на GitHub](https://github.com/git/git) 6. [Git Reference Manual](https://git-scm.com/docs) --- # GitHub Actions > Встроенная в GitHub система CI/CD и автоматизации — запускает рабочие процессы из YAML-файлов в репозитории по событиям push, pull request, расписанию и другим. Источник: https://llmdocs.ru/wiki/github-actions/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: платформа CI/CD и автоматизации - **Разработчик**: GitHub (Microsoft) - **Анонс**: октябрь 2018 - **Общая доступность**: ноябрь 2019 - **Описание процессов**: YAML в каталоге .github/workflows/ - **Раннеры**: Linux, Windows, macOS (облачные) и self-hosted - **Каталог готовых действий**: GitHub Marketplace - **Бесплатно**: публичные репозитории; лимит минут для приватных **GitHub Actions** — система автоматизации, встроенная в [GitHub](https://llmdocs.ru/wiki/github.md): она запускает **рабочие процессы** (*workflows*), описанные в YAML-файлах прямо в репозитории, в ответ на события — push, открытие [pull request](https://llmdocs.ru/wiki/pull-request.md), публикацию релиза, расписание или ручной запуск.[1] Чаще всего Actions используют для [CI/CD](https://llmdocs.ru/wiki/ci-cd.md): собрать проект, прогнать тесты и линтеры, собрать и опубликовать [образ](https://llmdocs.ru/wiki/oci-image.md), развернуть приложение. Но это и универсальный инструмент: разметка задач, генерация документации, публикация сайта на GitHub Pages, обновление зависимостей. ## История GitHub анонсировал Actions в октябре 2018 года как средство автоматизации, а в ноябре 2019 года выпустил с полноценной поддержкой CI/CD и бесплатными минутами для публичных репозиториев.[6] Благодаря интеграции в саму платформу и каталогу готовых действий (Marketplace) сервис быстро потеснил внешние CI-системы — Travis CI, CircleCI — в открытых проектах. ## Устройство - **Workflow** — YAML-файл в `.github/workflows/`. В репозитории их может быть сколько угодно. - **Событие** (`on:`) — что запускает процесс: `push`, `pull_request`, `schedule` (cron), `workflow_dispatch` (кнопка), `release` и десятки других.[3] - **Job** — набор шагов, выполняемых на одной машине. Задания идут параллельно, если не связаны через `needs:`. - **Step** — шаг: либо команда оболочки (`run:`), либо готовое **действие** (`uses:`). - **Action** — переиспользуемый компонент: JavaScript-код, [Docker](https://llmdocs.ru/wiki/docker.md)-контейнер или составное действие из шагов. Хранится в репозитории и подключается по ссылке `владелец/репо@версия`. - **Runner** — машина, исполняющая задание: облачная виртуальная машина GitHub (`ubuntu-latest`, `windows-latest`, `macos-latest`) или собственная (*self-hosted*). ## Пример ```yaml # .github/workflows/ci.yml name: CI on: push: branches: [main] pull_request: permissions: contents: read jobs: test: runs-on: ubuntu-latest strategy: matrix: python: ["3.12", "3.13"] steps: - uses: actions/checkout@v4 - uses: astral-sh/setup-uv@v6 - run: uv sync --python ${{ matrix.python }} - run: uv run pytest deploy: needs: test if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest environment: production steps: - uses: actions/checkout@v4 - run: ./deploy.sh env: DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }} ``` **Матрица** (`strategy.matrix`) запускает задание для каждого сочетания параметров — версий языка, операционных систем. Выражения `${{ ... }}` дают доступ к контексту: ветке, событию, секретам, выходам предыдущих шагов.[2] ## Секреты и права Секреты задаются в настройках репозитория, окружения или организации и попадают в процесс через `secrets.*`; в логах они маскируются. Каждый запуск получает временный токен `GITHUB_TOKEN` для работы с API репозитория — его права стоит сужать блоком `permissions:`. **Окружения** (*environments*) добавляют свои секреты и правила: обязательное одобрение человеком, ограничение веток. Вместо долгоживущих ключей облаков рекомендуется **OIDC**: процесс получает подписанный токен от GitHub и обменивает его на временные учётные данные у провайдера, который доверяет конкретному репозиторию и ветке.[5] ## Безопасность Actions — частая цель атак на цепочку поставок:[4] - **Фиксируйте сторонние действия по хешу коммита**, а не по тегу: тег можно перенаправить. В марте 2025 года злоумышленники переписали теги популярного действия `tj-actions/changed-files`, и в логах тысяч репозиториев оказались секреты.[7] - Событие `pull_request_target` выполняется с секретами и правами целевого репозитория — запускать в нём код из чужого PR опасно. - Не подставляйте недоверенные данные (заголовок PR, имя ветки) в `run:` через `${{ }}` — это инъекция команд; передавайте их через переменные окружения. - Self-hosted раннеры в публичных репозиториях позволяют любому, кто откроет PR, выполнить код на вашей машине. ## Переиспользование - **Составные действия** (`runs.using: composite`) — набор шагов в отдельном `action.yml`. - **Переиспользуемые workflow** (`on: workflow_call`) — целый процесс, вызываемый из других репозиториев. - **Кеш** (`actions/cache`, встроенный кеш в setup-действиях) и **артефакты** (`actions/upload-artifact`) ускоряют сборки и передают файлы между заданиями. Отладка локально возможна утилитой `act`, которая запускает workflow в Docker; статус и логи удобно смотреть через `gh run list` и `gh run watch`. ## Ограничения Облачные раннеры ограничены по времени задания (6 часов) и бесплатным минутам для приватных репозиториев; минуты macOS и Windows тарифицируются дороже Linux. YAML-логика с выражениями быстро становится трудночитаемой, а процесс жёстко привязан к GitHub — переезд на [GitLab CI](https://llmdocs.ru/wiki/gitlab-ci.md) или другую систему требует переписывания. ## См. также - [CI/CD](https://llmdocs.ru/wiki/ci-cd.md) - [GitLab CI](https://llmdocs.ru/wiki/gitlab-ci.md) - [Управление секретами](https://llmdocs.ru/wiki/secrets-management.md) - [Семантическое версионирование](https://llmdocs.ru/wiki/semver.md) ## Источники 1. [GitHub Docs — GitHub Actions](https://docs.github.com/en/actions) 2. [GitHub Docs — Workflow syntax for GitHub Actions](https://docs.github.com/en/actions/writing-workflows/workflow-syntax-for-github-actions) 3. [GitHub Docs — Events that trigger workflows](https://docs.github.com/en/actions/writing-workflows/choosing-when-your-workflow-runs/events-that-trigger-workflows) 4. [GitHub Docs — Security hardening for GitHub Actions](https://docs.github.com/en/actions/security-for-github-actions/security-guides/security-hardening-for-github-actions) 5. [GitHub Docs — About security hardening with OpenID Connect](https://docs.github.com/en/actions/security-for-github-actions/security-hardening-your-deployments/about-security-hardening-with-openid-connect) 6. [GitHub Blog — GitHub Actions now supports CI/CD, free for public repositories (2019)](https://github.blog/news-insights/product-news/github-actions-now-supports-ci-cd/) 7. [CISA — Supply chain compromise of tj-actions/changed-files (CVE-2025-30066)](https://www.cisa.gov/news-events/alerts/2025/03/18/supply-chain-compromise-third-party-tj-actionschanged-files-cve-2025-30066-and-reviewdogaction) --- # GitHub > Крупнейшая платформа для хостинга Git-репозиториев и совместной разработки — pull request'ы, задачи, CI/CD через GitHub Actions, пакеты, Pages и Copilot; принадлежит Microsoft. Источник: https://llmdocs.ru/wiki/github/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: платформа хостинга Git-репозиториев и совместной разработки - **Основатели**: Том Престон-Вернер, Крис Ванстрат, Пи Джей Хайетт, Скотт Чакон - **Запуск**: апрель 2008 - **Владелец**: Microsoft (сделка объявлена в июне 2018, 7,5 млрд долларов) - **Пользователей**: более 100 млн (январь 2023) - **Ключевые сервисы**: Pull requests, Issues, Actions, Packages, Pages, Codespaces, Copilot - **CLI**: gh - **Сайт**: github.com **GitHub** — веб-платформа для хранения [Git](https://llmdocs.ru/wiki/git.md)-репозиториев и совместной работы над кодом. Помимо самого хостинга она даёт инструменты, вокруг которых строится процесс разработки: [pull request'ы](https://llmdocs.ru/wiki/pull-request.md) с код-ревью, задачи (Issues), обсуждения, автоматизацию [CI/CD](https://llmdocs.ru/wiki/ci-cd.md) через [GitHub Actions](https://llmdocs.ru/wiki/github-actions.md), реестр пакетов, хостинг статических сайтов и ИИ-ассистента Copilot.[1] GitHub — фактический центр мира открытого ПО: здесь живут Linux (зеркало), Python, Kubernetes, React и миллионы других проектов, а профиль на GitHub часто служит портфолио разработчика. ## История GitHub запустили в апреле 2008 года Том Престон-Вернер, Крис Ванстрат, Пи Джей Хайетт и Скотт Чакон (автор книги «Pro Git»). Сервис сделал Git удобным: веб-интерфейс, форки в один клик и pull request'ы превратили участие в чужом проекте в простую процедуру. В июне 2018 года Microsoft объявила о покупке GitHub за 7,5 млрд долларов;[2] после сделки появились бесплатные приватные репозитории (2019), GitHub Actions (общедоступен с 2019 года), Codespaces и Copilot (2021–2022). В 2023 году GitHub сообщил о 100 миллионах разработчиков.[3] Ежегодный отчёт Octoverse публикует статистику по языкам и активности.[7] ## Основные возможности | Сервис | Назначение | |---|---| | Репозитории | публичные и приватные, форки, звёзды, теги и релизы | | Pull requests | предложение изменений, ревью построчно, проверки перед слиянием | | Issues и Projects | задачи, метки, вехи, канбан-доски | | Discussions | форум проекта | | Actions | CI/CD и автоматизация по событиям репозитория | | Packages / GHCR | реестр пакетов и образов контейнеров (`ghcr.io`) | | Pages | хостинг [статических сайтов](https://llmdocs.ru/wiki/static-site-generators.md) из репозитория[6] | | Codespaces | облачная среда разработки в браузере или VS Code | | Copilot | ИИ-помощник в редакторе, чате и при ревью | | Безопасность | Dependabot, сканирование кода и утечек секретов | Файлы README, LICENSE, CONTRIBUTING, CODEOWNERS и каталог `.github/` задают оформление проекта, правила участия и ответственных за части кода. README отображается в формате [Markdown](https://llmdocs.ru/wiki/markdown.md) (диалект GitHub Flavored Markdown). ## Защита веток и правила Для основной ветки настраивают **правила защиты** (*branch protection*, в новом виде — *rulesets*):[4] запрет прямых push, обязательные ревью (в том числе от владельцев кода из CODEOWNERS), успешные проверки CI, линейная история, подписанные коммиты. Это реализует на практике модель работы через pull request'ы (см. [Ветвление в Git](https://llmdocs.ru/wiki/git-branching.md)). ## Работа из терминала Официальная утилита `gh` повторяет большую часть веб-интерфейса:[5] ```bash gh auth login gh repo create my-app --private --source=. --push gh repo clone owner/project gh pr create --fill gh pr checkout 123 gh pr view --web gh issue list --label bug gh run watch # следить за запуском Actions gh api repos/{owner}/{repo}/releases # произвольный запрос к REST API ``` Для доступа по [SSH](https://llmdocs.ru/wiki/ssh.md) на GitHub добавляют открытый ключ; для HTTPS используются персональные токены (classic или fine-grained) — пароль аккаунта для Git-операций не принимается с 2021 года. ## Модель и цены Публичные и приватные репозитории бесплатны; платные тарифы (Team, Enterprise) добавляют расширенную защиту веток для приватных репозиториев, больше минут Actions, аудит и SSO. GitHub Enterprise Server — версия для установки на собственных серверах. ## Альтернативы и критика Основные конкуренты — GitLab (сильная встроенная CI и возможность самостоятельной установки), Bitbucket, а также свободные Gitea и Forgejo (на нём работает Codeberg). Критика GitHub касается централизации открытого ПО в руках одной корпорации, использования публичного кода для обучения Copilot и рисков блокировок: в 2019 году аккаунты из стран под санкциями США получили ограничения. Поскольку Git распределён, полная копия истории есть у каждого клона, и переезд на другую платформу технически прост — сложнее перенести задачи, обсуждения и автоматизацию. ## См. также - [Git](https://llmdocs.ru/wiki/git.md) - [GitLab](https://llmdocs.ru/wiki/gitlab.md) - [GitHub Actions](https://llmdocs.ru/wiki/github-actions.md) - [Лицензии ПО (MIT, GPL, Apache, CC)](https://llmdocs.ru/wiki/software-licenses.md) ## Источники 1. [GitHub Docs](https://docs.github.com/) 2. [Microsoft News — Microsoft to acquire GitHub for $7.5 billion (2018)](https://news.microsoft.com/2018/06/04/microsoft-to-acquire-github-for-7-5-billion/) 3. [GitHub Blog — 100 million developers and counting (2023)](https://github.blog/news-insights/company-news/100-million-developers-and-counting/) 4. [GitHub Docs — About protected branches](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches) 5. [GitHub CLI manual](https://cli.github.com/manual/) 6. [GitHub Docs — About GitHub Pages](https://docs.github.com/en/pages/getting-started-with-github-pages/about-github-pages) 7. [GitHub Octoverse](https://octoverse.github.com/) --- # GitLab CI > Встроенная в GitLab система CI/CD — конвейеры из стадий и заданий описываются в файле .gitlab-ci.yml и выполняются раннерами, в том числе на собственных серверах. Источник: https://llmdocs.ru/wiki/gitlab-ci/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: система CI/CD - **Разработчик**: GitLab Inc. - **Встроена в GitLab**: с версии 8.0 (сентябрь 2015) - **Описание конвейера**: файл .gitlab-ci.yml в корне репозитория - **Исполнитель**: GitLab Runner (Go) - **Executors**: shell, docker, kubernetes, docker-autoscaler, ssh и др. - **Размещение**: GitLab.com или собственный сервер (self-managed) **GitLab CI** (GitLab CI/CD) — система непрерывной интеграции и доставки, встроенная в платформу [GitLab](https://llmdocs.ru/wiki/gitlab.md). Конвейер (*pipeline*) описывается в файле `.gitlab-ci.yml` в корне репозитория: из каких **стадий** и **заданий** он состоит, какие команды выполнять и при каких условиях.[1] Задания исполняет **GitLab Runner** — агент, который можно установить на свой сервер, виртуальную машину или в кластер [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md). Именно возможность держать всё — и Git-хостинг, и CI, и реестр образов — внутри собственной инфраструктуры сделала GitLab популярным в компаниях, в том числе российских. ## История GitLab начал в 2011 году Дмитрий Запорожец как открытую альтернативу [GitHub](https://llmdocs.ru/wiki/github.md). Система CI сначала была отдельным приложением GitLab CI, а в версии 8.0 (сентябрь 2015) её встроили в основной продукт.[6] Раннер переписали на Go, и он стал отдельным открытым проектом. Со временем GitLab превратился в «DevOps-платформу» — с задачами, реестрами пакетов и образов, сканерами безопасности и средствами развёртывания в одном интерфейсе. ## Основные понятия - **Pipeline** — один запуск конвейера для коммита, merge request, тега или по расписанию. - **Stage** — стадия; задания одной стадии идут параллельно, стадии — последовательно (по умолчанию `build`, `test`, `deploy`). - **Job** — задание: набор команд `script`, выполняемых раннером в чистом окружении. - **Runner** — агент, забирающий задания из очереди. **Executor** определяет, где они выполняются: прямо в оболочке, в контейнере [Docker](https://llmdocs.ru/wiki/docker.md), в поде Kubernetes.[3] - **Artifacts** — файлы, сохраняемые после задания и передаваемые следующим (сборки, отчёты тестов). - **Cache** — файлы, переиспользуемые между запусками для ускорения (зависимости). ## Пример ```yaml # .gitlab-ci.yml stages: [test, build, deploy] default: image: python:3.13-slim variables: PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache/pip" test: stage: test cache: paths: [.cache/pip] script: - pip install -r requirements.txt - pytest --junitxml=report.xml artifacts: reports: junit: report.xml build-image: stage: build image: docker:27 services: [docker:27-dind] script: - docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" "$CI_REGISTRY" - docker build -t "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA" . - docker push "$CI_REGISTRY_IMAGE:$CI_COMMIT_SHORT_SHA" rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH deploy-prod: stage: deploy script: ./deploy.sh "$CI_COMMIT_SHORT_SHA" environment: name: production url: https://example.com rules: - if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH when: manual ``` Переменные вида `CI_COMMIT_SHA`, `CI_REGISTRY_IMAGE`, `CI_DEFAULT_BRANCH` GitLab подставляет сам — их больше сотни.[4] ## Управление запуском - **`rules`** — условия, при которых задание попадает в конвейер: ветка, тип события, изменённые файлы (`changes:`), значения переменных. Пришли на смену устаревшим `only`/`except`.[2] - **`needs`** — явные зависимости между заданиями: задание стартует, как только готовы его зависимости, не дожидаясь конца стадии. Конвейер превращается в граф (DAG) и идёт быстрее. - **`when: manual`** — ручной запуск кнопкой, типично для выкладки в продакшен. - **`include`** и **`extends`** — подключение общих шаблонов из других файлов и проектов; **CI/CD-компоненты** с параметрами — современный способ переиспользования. - **Дочерние и многопроектные конвейеры** (`trigger:`) — для монорепозиториев и цепочек сервисов. ## Окружения и секреты **Окружения** (`environment:`) связывают задания развёртывания с адресами стендов, показывают историю выкладок и позволяют откатиться повторным запуском прошлого задания.[5] Переменные проекта и группы могут быть **защищёнными** (доступны только в защищённых ветках и тегах) и **маскированными** (скрываются в логах). Для облаков поддерживается выдача временных учётных данных через ID-токены (OIDC) и интеграция с HashiCorp Vault (см. [Управление секретами](https://llmdocs.ru/wiki/secrets-management.md)). ## Сравнение с GitHub Actions | | GitLab CI | [GitHub Actions](https://llmdocs.ru/wiki/github-actions.md) | |---|---|---| | Файл | один `.gitlab-ci.yml` (+ include) | много файлов в `.github/workflows/` | | Модель | стадии + DAG через `needs` | задания + `needs` | | Переиспользование | шаблоны, `extends`, компоненты | действия из Marketplace, reusable workflows | | Свой сервер | полноценный self-managed GitLab | GitHub Enterprise Server | | Сильная сторона | всё в одной платформе, свои раннеры | огромный каталог готовых действий | ## Отладка Конвейер можно проверить в редакторе пайплайнов GitLab (валидация и просмотр итоговой конфигурации). Упавшее задание перезапускают из интерфейса, а для долгих проблем включают `CI_DEBUG_TRACE: "true"` — с осторожностью, поскольку в журнал попадут значения переменных. ## См. также - [CI/CD](https://llmdocs.ru/wiki/ci-cd.md) - [Pull request / Merge request](https://llmdocs.ru/wiki/pull-request.md) - [Container registry](https://llmdocs.ru/wiki/container-registry.md) - [Infrastructure as Code](https://llmdocs.ru/wiki/infrastructure-as-code.md) ## Источники 1. [GitLab Docs — Get started with GitLab CI/CD](https://docs.gitlab.com/ci/) 2. [GitLab Docs — CI/CD YAML syntax reference](https://docs.gitlab.com/ci/yaml/) 3. [GitLab Docs — GitLab Runner](https://docs.gitlab.com/runner/) 4. [GitLab Docs — Predefined CI/CD variables](https://docs.gitlab.com/ci/variables/predefined_variables/) 5. [GitLab Docs — Environments and deployments](https://docs.gitlab.com/ci/environments/) 6. [GitLab Blog — GitLab 8.0 released with integrated CI (2015)](https://about.gitlab.com/releases/2015/09/22/gitlab-8-0-released/) --- # GitLab > Платформа для разработки на базе Git — репозитории, merge requests, CI/CD, реестры и задачи в одном продукте; доступна как облачный сервис и для установки на свои серверы. Источник: https://llmdocs.ru/wiki/gitlab/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Разработчик**: GitLab Inc. - **Авторы**: Дмитрий Запорожец, Валерий Сизов - **Первый выпуск**: 2011 - **Язык**: Ruby (Rails), Go, Vue.js - **Редакции**: Community Edition (MIT), Enterprise Edition (Premium, Ultimate) - **Варианты**: GitLab.com, Self-Managed, Dedicated - **Выпуски**: ежемесячно, 3-го четверга - **Конкуренты**: GitHub, Bitbucket, Gitea/Forgejo **GitLab** — платформа для совместной разработки программ на основе [Git](https://llmdocs.ru/wiki/git.md). В одном продукте собраны хостинг репозиториев, merge requests и код-ревью, задачи и доски, встроенный [CI/CD](https://llmdocs.ru/wiki/gitlab-ci.md), реестры контейнеров и пакетов, вики, управление окружениями и инструменты безопасности. Главное отличие от [GitHub](https://llmdocs.ru/wiki/github.md) — исторически сильная версия для установки на собственные серверы, благодаря чему GitLab широко распространён в компаниях, которым важно держать код внутри своей инфраструктуры. ## История Проект начали в 2011 году украинские программисты Дмитрий Запорожец и Валерий Сизов как открытую альтернативу GitHub для установки у себя.[2] В 2014 году была основана компания GitLab Inc. под руководством Сида Сейбрандея. В 2015-м CI-система GitLab CI была встроена в основной продукт — одна из ранних платформ «всё в одном». В 2018 году, после покупки GitHub компанией Microsoft, на GitLab переехали сотни тысяч репозиториев. В 2021 году компания вышла на биржу NASDAQ. GitLab известен полностью удалённой работой и публичным справочником компании (handbook). ## Редакции и варианты | Вариант | Где работает | Кому | |---|---|---| | **GitLab.com** | облако GitLab Inc. | командам без своей инфраструктуры | | **Self-Managed** | ваши серверы или облако | компаниям с требованиями к размещению данных | | **Dedicated** | выделенный экземпляр в облаке | крупным организациям | Код распространяется в двух редакциях: **Community Edition** под лицензией MIT и **Enterprise Edition** с платными уровнями Premium и Ultimate (расширенное ревью, безопасность, портфельное планирование).[6] Бесплатный уровень включает репозитории, merge requests, CI/CD и реестры. ## Основные возможности - **Группы и проекты** — иерархия групп и подгрупп с наследованием прав и настроек; удобно для большой организации. - **Merge requests** — аналог pull request на GitHub: обсуждение по строкам, обязательные одобрения, правила защиты веток, слияние после успешного конвейера (см. [Pull request / Merge request](https://llmdocs.ru/wiki/pull-request.md)).[4] - **Задачи** (issues) — метки, вехи (milestones), доски Kanban, эпики; связь коммитов и MR с задачами по ссылкам `#123`. - **CI/CD** — конвейеры описываются в `.gitlab-ci.yml`, задачи выполняет GitLab Runner на своих машинах, в Docker или [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md). - **Реестры** — встроенный [Container registry](https://llmdocs.ru/wiki/container-registry.md) (`registry.gitlab.com`), реестры пакетов (npm, PyPI, Maven, Go), хранилище [Helm](https://llmdocs.ru/wiki/helm.md)-чартов и состояний [Terraform](https://llmdocs.ru/wiki/terraform-opentofu.md).[5] - **Окружения и деплой** — история выкладок по окружениям, ревью-окружения для каждой ветки, интеграция с Kubernetes через агента. - **Безопасность** (часть функций — в Ultimate) — SAST, сканирование зависимостей и контейнеров, поиск секретов, отчёты прямо в MR. ## Установка на свой сервер Самый распространённый способ — пакет **Omnibus**, включающий все компоненты (Rails-приложение, Gitaly, PostgreSQL, Redis, nginx, Prometheus):[3] ```bash # Ubuntu / Debian curl -sS https://packages.gitlab.com/install/repositories/gitlab/gitlab-ee/script.deb.sh | sudo bash sudo EXTERNAL_URL="https://gitlab.example.com" apt install gitlab-ee sudo gitlab-ctl reconfigure sudo gitlab-ctl status ``` Альтернативы — образ Docker, Helm-чарт или оператор для Kubernetes. Для небольшой команды нужен сервер минимум с 4 ядрами и 8 ГБ памяти; конфигурация хранится в `/etc/gitlab/gitlab.rb`, резервная копия создаётся командой `gitlab-backup create` (секреты из `/etc/gitlab` копируются отдельно). Обновлять стоит регулярно и по рекомендуемому пути версий — GitLab выходит каждый месяц. ## GitLab и GitHub | | GitLab | GitHub | |---|---|---| | Своя установка | CE бесплатно, полноценная | GitHub Enterprise Server, платно | | CI/CD | встроен с 2015, единый `.gitlab-ci.yml` | GitHub Actions, большой маркетплейс | | Организация | вложенные группы | организации и команды | | Сообщество open source | меньше | крупнейшее | | Терминология | merge request | pull request | Для лёгкой собственной установки без CI-нагрузки также используют **Gitea** и её форк **Forgejo** — они требуют в десятки раз меньше ресурсов. ## Практика ```bash git remote add origin git@gitlab.com:group/project.git git push -u origin main # создать MR при пуше через push options git push -o merge_request.create -o merge_request.target=main ``` Командная утилита `glab` позволяет работать с MR, задачами и конвейерами из терминала, аналогично `gh` для GitHub. ## См. также - [GitLab CI](https://llmdocs.ru/wiki/gitlab-ci.md) - [GitHub](https://llmdocs.ru/wiki/github.md) - [Git](https://llmdocs.ru/wiki/git.md) - [Pull request / Merge request](https://llmdocs.ru/wiki/pull-request.md) ## Источники 1. [GitLab Docs](https://docs.gitlab.com/) 2. [GitLab — History](https://handbook.gitlab.com/handbook/company/history/) 3. [GitLab — Installation methods](https://docs.gitlab.com/install/install_methods/) 4. [GitLab — Merge requests](https://docs.gitlab.com/user/project/merge_requests/) 5. [GitLab — Container registry](https://docs.gitlab.com/user/packages/container_registry/) 6. [GitLab — Feature comparison (pricing)](https://about.gitlab.com/pricing/feature-comparison/) --- # Grafana > Открытая платформа визуализации метрик, логов и трасс — дашборды и алерты поверх Prometheus, Loki, баз данных и облачных сервисов. Источник: https://llmdocs.ru/wiki/grafana/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Разработчик**: Grafana Labs - **Автор**: Торкель Эдегор (Torkel Ödegaard) - **Первый выпуск**: 2014 - **Язык**: Go (бэкенд), TypeScript и React (фронтенд) - **Лицензия**: AGPLv3 (с 2021, ранее Apache 2.0) - **Порт по умолчанию**: 3000 - **Связанные проекты**: Loki (логи), Tempo (трассы), Mimir (метрики), Alloy (сборщик) - **Облако**: Grafana Cloud **Grafana** — открытое веб-приложение для визуализации и анализа данных наблюдаемости: метрик, логов и трасс. Пользователь подключает источники данных — чаще всего [Prometheus](https://llmdocs.ru/wiki/prometheus.md), — строит из панелей дашборды и настраивает алерты. Grafana сама не хранит метрики: она отправляет запросы в источники и отображает результат. Вместе с Prometheus она стала стандартным стеком [мониторинга](https://llmdocs.ru/wiki/monitoring-alerting.md) для серверов, [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) и приложений. ## История Шведский разработчик Торкель Эдегор выпустил Grafana в 2014 году как форк Kibana 3, переделанный для временных рядов Graphite и InfluxDB.[1] Проект быстро стал популярен; вокруг него сложилась компания Grafana Labs, которая развивает целый набор открытых инструментов: **Loki** для логов (2018), **Tempo** для трасс, **Mimir** для долговременного хранения метрик, **Pyroscope** для профилирования и сборщик **Alloy**. Вместе их называют стеком **LGTM** (Loki, Grafana, Tempo, Mimir). В 2021 году Grafana и Loki перешли с лицензии Apache 2.0 на AGPLv3.[6] ## Источники данных Grafana поддерживает десятки источников из коробки и сотни через плагины:[2] | Тип | Примеры | Язык запросов | |---|---|---| | Метрики | Prometheus, Mimir, VictoriaMetrics, InfluxDB, Graphite | PromQL, InfluxQL, Flux | | Логи | Loki, Elasticsearch, OpenSearch | LogQL, Lucene | | Трассы | Tempo, Jaeger, Zipkin | TraceQL | | SQL | [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md), MySQL, [ClickHouse](https://llmdocs.ru/wiki/clickhouse.md) | SQL | | Облака | CloudWatch, Azure Monitor, Google Cloud Monitoring | собственные | На одном дашборде можно совместить данные из разных источников, а режим **Explore** позволяет писать запросы интерактивно и переходить от метрики к логам и трассам того же момента — при условии, что они связаны общими метками или trace ID (см. [Логирование и трассировка (OpenTelemetry)](https://llmdocs.ru/wiki/opentelemetry.md)). ## Дашборды Дашборд состоит из **панелей**: временные ряды, одиночное значение (stat), шкалы, таблицы, тепловые карты, гистограммы, логи, графы узлов. Ключевые возможности: - **Переменные** — выпадающие списки (окружение, сервис, узел), значения подставляются в запросы: `rate(http_requests_total{job="$job"}[5m])`. Один дашборд обслуживает все сервисы. - **Трансформации** — объединение, фильтрация и вычисления над результатами запросов без изменения источника. - **Аннотации** — отметки событий на графиках, например моменты деплоя. - **Импорт готовых дашбордов** с grafana.com по номеру: известный Node Exporter Full (ID 1860) показывает всё о Linux-сервере. Хороший дашборд отвечает на конкретный вопрос: сверху — «золотые сигналы» сервиса (трафик, ошибки, задержки, насыщение), ниже — детали для расследования. ## Алерты Grafana Alerting вычисляет правила по любым источникам, группирует срабатывания и отправляет уведомления через **точки контакта**: почту, Telegram, Slack, PagerDuty, вебхуки.[3] Политики уведомлений маршрутизируют алерты по меткам, а «тихие часы» (silences) временно отключают их во время работ. Если в инфраструктуре уже есть Prometheus с Alertmanager, алерты часто оставляют там, а Grafana использует только для визуализации. ## Установка и конфигурация как код ```bash docker run -d --name grafana -p 3000:3000 \ -v grafana-data:/var/lib/grafana grafana/grafana-oss # http://localhost:3000, вход admin/admin со сменой пароля ``` В Kubernetes Grafana обычно ставят [Helm](https://llmdocs.ru/wiki/helm.md)-чартом `kube-prometheus-stack` вместе с Prometheus и Alertmanager. Дашборды, источники и алерты лучше хранить в [Git](https://llmdocs.ru/wiki/git.md), а не создавать мышкой: Grafana загружает их из YAML- и JSON-файлов при старте (**provisioning**).[4] ```yaml # /etc/grafana/provisioning/datasources/prometheus.yaml apiVersion: 1 datasources: - name: Prometheus type: prometheus url: http://prometheus:9090 isDefault: true ``` Для больших установок используют провайдер Grafana в [Terraform](https://llmdocs.ru/wiki/terraform-opentofu.md), библиотеки Grafonnet (Jsonnet) и Grafana Foundation SDK, позволяющие генерировать дашборды кодом. ## Loki **Loki** — система хранения логов, спроектированная «как Prometheus, но для логов»: она индексирует только метки (сервис, под, уровень), а сами строки хранит сжатыми в объектном хранилище.[5] Это гораздо дешевле полнотекстовых систем вроде Elasticsearch, хотя поиск по произвольному тексту медленнее. Запросы пишутся на LogQL: ``` {app="api", level="error"} |= "timeout" | json | duration > 2s ``` ## Альтернативы Kibana и OpenSearch Dashboards (в экосистеме Elasticsearch), встроенные консоли облачных провайдеров, коммерческие Datadog и New Relic, а для простых случаев — встроенный интерфейс Prometheus или Netdata. ## См. также - [Prometheus](https://llmdocs.ru/wiki/prometheus.md) - [Мониторинг и алертинг](https://llmdocs.ru/wiki/monitoring-alerting.md) - [Логирование и трассировка (OpenTelemetry)](https://llmdocs.ru/wiki/opentelemetry.md) - [SRE, SLO и SLA](https://llmdocs.ru/wiki/sre-slo-sla.md) ## Источники 1. [Grafana Documentation](https://grafana.com/docs/grafana/latest/) 2. [Grafana — Data sources](https://grafana.com/docs/grafana/latest/datasources/) 3. [Grafana Alerting](https://grafana.com/docs/grafana/latest/alerting/) 4. [Grafana — Provisioning](https://grafana.com/docs/grafana/latest/administration/provisioning/) 5. [Grafana Loki Documentation](https://grafana.com/docs/loki/latest/) 6. [Grafana Labs — Relicensing to AGPLv3 (2021)](https://grafana.com/blog/2021/04/20/grafana-loki-tempo-relicensing-to-agplv3/) --- # Infrastructure as Code > Подход, при котором серверы, сети, базы данных и прочая инфраструктура описываются в виде кода, хранятся в системе контроля версий и создаются автоматически. Источник: https://llmdocs.ru/wiki/infrastructure-as-code/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Сокращение**: IaC - **Подходы**: декларативный и императивный - **Предоставление ресурсов**: Terraform, OpenTofu, Pulumi, AWS CloudFormation - **Управление конфигурацией**: Ansible, Puppet, Chef, Salt - **Ключевые свойства**: идемпотентность, воспроизводимость, ревью изменений - **Связанные практики**: GitOps, CI/CD, неизменяемая инфраструктура **Infrastructure as Code** (IaC, «инфраструктура как код») — подход, при котором инфраструктура — виртуальные машины, сети, балансировщики, базы данных, DNS-записи, права доступа — описывается в текстовых файлах, а не настраивается вручную через веб-консоль или по SSH. Эти файлы хранятся в [Git](https://llmdocs.ru/wiki/git.md), проходят [ревью](https://llmdocs.ru/wiki/pull-request.md), тестируются и применяются автоматически, как обычный программный код.[5] IaC — одна из основ DevOps: она позволяет за минуты воспроизвести окружение, понять, кто и зачем изменил настройки, и выкатывать изменения инфраструктуры через тот же конвейер [CI/CD](https://llmdocs.ru/wiki/ci-cd.md), что и приложения. ## Проблема, которую решает IaC При ручной настройке серверы постепенно превращаются в «снежинки» — каждый уникален, никто точно не знает, как он устроен, а воспроизвести его после сбоя невозможно. Изменения не документированы, тестовое окружение незаметно отличается от продакшена (**дрейф конфигурации**), а повторение одних и тех же действий на десятках машин ведёт к ошибкам. С появлением облаков, где инфраструктуру можно создавать через API, стало естественным управлять ею программно. ## Декларативный и императивный подходы | | Декларативный | Императивный | |---|---|---| | Что описывается | желаемое конечное состояние | последовательность шагов | | Пример | «должно быть 3 сервера такого размера» | «создай сервер, затем ещё два» | | Повторный запуск | ничего не меняет, если состояние совпадает | может создать дубликаты | | Инструменты | Terraform, OpenTofu, CloudFormation, манифесты [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) | скрипты на Bash, SDK облаков | Ключевое свойство хороших инструментов IaC — **идемпотентность**: повторное применение той же конфигурации приводит к тому же результату и не делает лишних изменений. Ansible занимает промежуточное положение: сценарии пишутся как последовательность задач, но каждая задача (модуль) идемпотентна. ## Классы инструментов - **Предоставление ресурсов** (*provisioning*) — создание облачной инфраструктуры: [Terraform и OpenTofu](https://llmdocs.ru/wiki/terraform-opentofu.md), Pulumi (на обычных языках программирования), AWS CloudFormation, Azure Bicep.[2] - **Управление конфигурацией** — настройка того, что внутри серверов: пакеты, файлы, службы. [Ansible](https://llmdocs.ru/wiki/ansible.md) (подключается по [SSH](https://llmdocs.ru/wiki/ssh.md), без агентов), Puppet, Chef, Salt.[4] - **Образы и контейнеры** — вместо настройки работающих серверов собирают готовые образы: Packer для образов ВМ, [Dockerfile](https://llmdocs.ru/wiki/dockerfile.md) для контейнеров. Это **неизменяемая инфраструктура**: сервер не обновляют, а заменяют новым. - **Описание приложений в кластере** — манифесты Kubernetes, чарты [Helm](https://llmdocs.ru/wiki/helm.md), Kustomize; в подходе **GitOps** агенты (Argo CD, Flux) непрерывно приводят кластер к состоянию из репозитория. ## Пример: Terraform ```hcl # main.tf terraform { required_providers { aws = { source = "hashicorp/aws", version = "~> 5.0" } } } provider "aws" { region = "eu-central-1" } resource "aws_instance" "web" { count = 2 ami = "ami-0123456789abcdef0" instance_type = "t3.small" tags = { Name = "web-${count.index}" } } output "web_ips" { value = aws_instance.web[*].public_ip } ``` ```bash terraform init # скачать провайдеры terraform plan # показать, что будет создано, изменено или удалено terraform apply # применить изменения ``` Команда `plan` — главная страховка: перед применением видно точный список изменений, и его можно приложить к pull request. Terraform хранит соответствие описания и реальных ресурсов в **файле состояния** (*state*); в команде его держат в удалённом хранилище с блокировкой, чтобы два человека не применяли изменения одновременно.[6] ## Пример: Ansible ```yaml # playbook.yml - hosts: web become: true tasks: - name: Установить nginx ansible.builtin.apt: name: nginx state: present update_cache: true - name: Включить и запустить nginx ansible.builtin.systemd: name: nginx enabled: true state: started ``` Запуск `ansible-playbook -i inventory.ini playbook.yml` приведёт все серверы группы `web` к описанному состоянию; при повторном запуске Ansible сообщит, что изменений нет. ## История Идеи автоматизации конфигурации восходят к CFEngine (1993). Волна инструментов пришла вместе с облаками и DevOps: Puppet (2005), Chef (2009), AWS CloudFormation (2011), Ansible (2012), Terraform (2014). В 2023 году HashiCorp перевела Terraform с открытой лицензии MPL на Business Source License; в ответ сообщество создало открытый форк **OpenTofu** под эгидой Linux Foundation, совместимый с конфигурациями Terraform.[3] Систематически подход описан в книге Кифа Морриса «Infrastructure as Code».[1] ## Хорошие практики - Все изменения — только через код и ревью; ручные правки в консоли считаются инцидентом и устраняются. - Модули для повторяющихся элементов и отдельные конфигурации для окружений (dev, staging, prod). - Секреты — не в репозитории, а в хранилищах (Vault, менеджеры секретов облаков, SOPS). - `plan` в CI для каждого pull request, `apply` — после слияния. - Регулярная проверка дрейфа: не изменилось ли что-то в обход кода. ## См. также - [Terraform и OpenTofu](https://llmdocs.ru/wiki/terraform-opentofu.md) - [Ansible](https://llmdocs.ru/wiki/ansible.md) - [CI/CD](https://llmdocs.ru/wiki/ci-cd.md) - [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) - [Git](https://llmdocs.ru/wiki/git.md) ## Источники 1. [Kief Morris — Infrastructure as Code (O'Reilly)](https://www.oreilly.com/library/view/infrastructure-as-code/9781098114664/) 2. [Terraform Documentation — What is Terraform?](https://developer.hashicorp.com/terraform/intro) 3. [OpenTofu — документация](https://opentofu.org/docs/) 4. [Ansible Documentation — Getting started](https://docs.ansible.com/ansible/latest/getting_started/index.html) 5. [Martin Fowler — InfrastructureAsCode](https://martinfowler.com/bliki/InfrastructureAsCode.html) 6. [Terraform Documentation — State](https://developer.hashicorp.com/terraform/language/state) --- # Merge и rebase > Два способа объединить изменения веток в Git — merge сохраняет историю как есть и создаёт коммит слияния, rebase переносит коммиты поверх другой ветки и делает историю линейной. Источник: https://llmdocs.ru/wiki/merge-rebase/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Команды**: git merge, git rebase, git cherry-pick - **Стратегия слияния по умолчанию**: ort (с Git 2.34, 2021), ранее recursive - **Виды merge**: fast-forward, трёхсторонний (merge commit), squash - **Интерактивный режим**: git rebase -i - **Повторное использование решений конфликтов**: git rerere - **Главное правило**: не переписывать опубликованную общую историю **Merge** (слияние) и **rebase** (перебазирование) — два способа перенести изменения из одной ветки [Git](https://llmdocs.ru/wiki/git.md) в другую. Оба дают одинаковый итоговый код, но по-разному записывают историю. `git merge` соединяет две линии разработки, сохраняя их как есть, и при необходимости создаёт **коммит слияния** с двумя родителями.[1] `git rebase` берёт коммиты ветки и заново применяет их поверх другой, как будто работа начиналась с её последнего состояния, — история получается линейной.[2] Выбор между ними — один из главных вопросов командных договорённостей о работе с ветками (см. [Ветвление в Git](https://llmdocs.ru/wiki/git-branching.md)). ## Merge Предположим, ветка `feature` ответвилась от `main`, и с тех пор в обеих появились новые коммиты. ```text A---B---C feature / D---E---F---G main ``` `git switch main && git merge feature` находит общего предка (**merge base**, здесь `E`), сравнивает с ним обе вершины и создаёт коммит `M`, объединяющий изменения: ```text A---B---C / \ D---E---F---G---M main ``` Это **трёхстороннее слияние** (*three-way merge*). Если же в `main` новых коммитов не было, Git просто передвигает указатель ветки вперёд — это **fast-forward**, без коммита слияния. Флаг `--no-ff` заставляет создать коммит слияния и в этом случае, чтобы в истории было видно, что изменения пришли пачкой из отдельной ветки; `--ff-only` наоборот — разрешает только перемотку.[3] С версии Git 2.34 (2021) по умолчанию используется стратегия слияния **ort** — переписанная и заметно более быстрая замена прежней `recursive`.[5] **Squash-слияние** (`git merge --squash`) собирает все изменения ветки в один обычный коммит без ссылки на исходные — так часто вливают [pull request](https://llmdocs.ru/wiki/pull-request.md), чтобы в основной ветке был один коммит на задачу. ## Rebase `git switch feature && git rebase main` вычисляет изменения коммитов `A`, `B`, `C` и по очереди применяет их поверх `G`: ```text D---E---F---G main \ A'--B'--C' feature ``` `A'`, `B'`, `C'` — **новые** коммиты с тем же содержанием изменений, но другими родителями и хешами. После этого `main` можно перемотать на `C'` через fast-forward, и история останется прямой линией. ### Интерактивный rebase `git rebase -i HEAD~5` открывает список последних коммитов, в котором для каждого можно выбрать действие:[4][6] | Команда | Действие | |---|---| | `pick` | оставить как есть | | `reword` | изменить сообщение | | `edit` | остановиться, чтобы поправить коммит | | `squash` / `fixup` | слить с предыдущим (с сохранением сообщения или без) | | `drop` | удалить коммит | Строки можно переставлять. Так перед публикацией приводят в порядок историю: убирают коммиты «опечатка», «ещё фикс», объединяют связанные изменения. Связка `git commit --fixup ` и `git rebase -i --autosquash` делает это почти автоматически. ## Главное правило rebase **Не перебазируйте коммиты, которые уже опубликованы и на которых кто-то основывает свою работу.**[2] Rebase создаёт новые коммиты вместо старых; у коллег останутся старые версии, и при следующей синхронизации история раздвоится. Переписывать свою личную ветку можно, но отправлять её придётся с принудительной перезаписью — безопаснее вариантом `git push --force-with-lease`, который откажется затирать чужие коммиты, появившиеся на сервере. ## Конфликты Если обе ветки изменили одни и те же строки, Git останавливается и размечает файл маркерами `<<<<<<<`, `=======`, `>>>>>>>`. Дальше нужно отредактировать файл, выполнить `git add` и продолжить: `git merge --continue` или `git rebase --continue`. Отменить всё — `git merge --abort` / `git rebase --abort`. При merge конфликты решаются один раз для всего слияния, при rebase — отдельно для каждого переносимого коммита, что бывает утомительно. Помогает механизм **rerere** (*reuse recorded resolution*, `git config rerere.enabled true`): Git запоминает, как был решён конфликт, и повторяет решение автоматически. ## Что выбрать | | Merge | Rebase | |---|---|---| | История | истинная, с ветвлениями | линейная, «как будто последовательно» | | Хеши коммитов | не меняются | меняются | | Безопасность для общих веток | безопасен | только для личных веток | | Чтение `git log` | сложнее при множестве веток | проще | | Поиск ошибки `git bisect` | работает | работает удобнее на линейной истории | Распространённая практика: обновлять свою рабочую ветку из `main` через rebase (`git pull --rebase`), а в основную ветку вливать через merge или squash-merge при закрытии pull request. Командам стоит договориться о едином стиле и закрепить его настройками репозитория на [GitHub](https://llmdocs.ru/wiki/github.md) или в GitLab. **Cherry-pick** (`git cherry-pick `) — родственная операция: переносит отдельный коммит в текущую ветку, например исправление ошибки из `main` в ветку релиза. ## См. также - [Git](https://llmdocs.ru/wiki/git.md) - [Ветвление в Git](https://llmdocs.ru/wiki/git-branching.md) - [Git-хуки](https://llmdocs.ru/wiki/git-hooks.md) - [Pull request / Merge request](https://llmdocs.ru/wiki/pull-request.md) ## Источники 1. [Pro Git — 3.2 Basic Branching and Merging](https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging) 2. [Pro Git — 3.6 Rebasing](https://git-scm.com/book/en/v2/Git-Branching-Rebasing) 3. [git-merge documentation](https://git-scm.com/docs/git-merge) 4. [git-rebase documentation](https://git-scm.com/docs/git-rebase) 5. [Git 2.34 release notes (ort default)](https://github.com/git/git/blob/master/Documentation/RelNotes/2.34.0.txt) 6. [Pro Git — 7.6 Rewriting History](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History) --- # Мониторинг и алертинг > Постоянный сбор метрик, логов и трасс о работе систем и автоматическое оповещение людей, когда что-то идёт не так; основа надёжной эксплуатации. Источник: https://llmdocs.ru/wiki/monitoring-alerting/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Три столпа наблюдаемости**: метрики, логи, трассы - **Методики**: четыре золотых сигнала (Google SRE), USE (Б. Грегг), RED (Т. Уилки) - **Классические системы**: Nagios (1999), Zabbix (2001) - **Современный стек**: Prometheus + Alertmanager + Grafana, OpenTelemetry - **Каналы оповещений**: мессенджеры, почта, PagerDuty, Opsgenie, телефон - **Связанные понятия**: SLI, SLO, дежурство (on-call), постмортем **Мониторинг** — непрерывный сбор и анализ данных о работе систем: загрузки серверов, задержек и ошибок сервисов, бизнес-показателей. **Алертинг** — автоматическое оповещение людей, когда эти данные говорят о проблеме, требующей вмешательства. Вместе они отвечают на два вопроса: «работает ли система сейчас?» и «почему она перестала работать?».[1] Без мониторинга о сбое узнают от пользователей, без хорошего алертинга — либо слишком поздно, либо так часто, что перестают реагировать. ## Метрики, логи, трассы Современный подход называют **наблюдаемостью** (*observability*) и выделяют три вида телеметрии: | Вид | Что это | Пример инструментов | |---|---|---| | Метрики | числовые ряды во времени: запросы в секунду, процент ошибок, память | [Prometheus](https://llmdocs.ru/wiki/prometheus.md), VictoriaMetrics, Zabbix | | Логи | текстовые или структурированные записи о событиях | Loki, Elasticsearch/OpenSearch, ClickHouse, [journald](https://llmdocs.ru/wiki/journald-logs.md) | | Трассы | путь одного запроса через все сервисы с длительностью каждого шага | Jaeger, Tempo, Zipkin | Метрики дешёвые и хорошо подходят для алертов и графиков; логи и трассы нужны, чтобы разобраться в причине. Единый открытый стандарт сбора всех трёх видов — OpenTelemetry (см. [Логирование и трассировка (OpenTelemetry)](https://llmdocs.ru/wiki/opentelemetry.md)).[7] Различают также **мониторинг «белого ящика»** — по внутренним метрикам приложения — и **«чёрного ящика»** — внешние проверки, как это видит пользователь: доступен ли сайт, валиден ли [TLS](https://llmdocs.ru/wiki/tls.md)-сертификат, отвечает ли API за разумное время. ## Что измерять Три популярные методики помогают не утонуть в тысячах метрик: - **Четыре золотых сигнала** (Google SRE) для любого сервиса: **задержка** (latency), **трафик** (traffic), **ошибки** (errors), **насыщение** (saturation).[1] - **USE** (Брендан Грегг) для ресурсов — процессора, диска, сети: **Utilization** (загрузка), **Saturation** (очередь), **Errors** (ошибки).[2] - **RED** (Том Уилки) для запросных сервисов: **Rate** (частота), **Errors** (ошибки), **Duration** (длительность).[3] Задержку важно смотреть по **перцентилям** (p50, p95, p99), а не по среднему: среднее в 100 мс может скрывать, что каждый сотый пользователь ждёт 5 секунд. ## Принципы хорошего алертинга Алерт будит человека, поэтому каждый должен быть **срочным, требующим действия и реальным**.[6] - **Алертить по симптомам, а не по причинам.** «Доля ошибок API выше 2 % в течение 5 минут» — важно пользователю. «CPU 90 %» — может быть нормой; такие сигналы — для дашбордов и диагностики. - **Разделять срочность.** Критичное — звонок дежурному в любое время; важное, но терпящее — задача или сообщение в рабочий чат. - **Каждый алерт — с инструкцией** (*runbook*): что проверить и как исправить. - **Бороться с «усталостью от алертов».** Если оповещение регулярно игнорируют, его нужно исправить или удалить: шум приучает пропускать и настоящие сбои. - **Группировать и подавлять.** Падение одного узла не должно порождать сотню оповещений от всех сервисов на нём. Зрелый подход — алертинг по **SLO**: команда фиксирует цель (например, 99,9 % успешных запросов за 30 дней) и получает оповещение, когда «бюджет ошибок» расходуется слишком быстро (*burn rate*), а не на каждый кратковременный всплеск.[4] Подробнее — в статье [SRE, SLO и SLA](https://llmdocs.ru/wiki/sre-slo-sla.md). ## Пример правила В экосистеме Prometheus правило алерта — это запрос PromQL с порогом и длительностью, а **Alertmanager** группирует сработавшие алерты, подавляет дубликаты и рассылает их по каналам.[5] ```yaml groups: - name: api rules: - alert: HighErrorRate expr: | sum(rate(http_requests_total{job="api",code=~"5.."}[5m])) / sum(rate(http_requests_total{job="api"}[5m])) > 0.02 for: 5m labels: severity: page annotations: summary: "API: более 2% ответов с ошибкой 5xx" runbook: "https://wiki.example.com/runbooks/api-errors" ``` Условие `for: 5m` отсекает короткие всплески: алерт срабатывает, только если проблема держится пять минут подряд. ## Инструменты - **Nagios** (1999) и **Zabbix** (2001) — классические системы проверок «хост работает / не работает», с агентами и шаблонами; Zabbix широко распространён в российских компаниях. - **Prometheus** с Alertmanager — стандарт для облачных и [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md)-окружений, модель сбора метрик по HTTP (*pull*). - **[Grafana](https://llmdocs.ru/wiki/grafana.md)** — дашборды поверх многих источников данных, а также собственный модуль алертинга. - Облачные сервисы: Datadog, New Relic, Yandex Monitoring, а также встроенный мониторинг облачных провайдеров. - Простые внешние проверки доступности: Uptime Kuma, Gatus, healthchecks.io (для cron-задач). ## Дежурство и разбор инцидентов Алерты бессмысленны без процесса: кто дежурит, как эскалировать, если дежурный не ответил, где фиксировать ход инцидента. После серьёзных сбоев пишут **постмортем** без поиска виноватых: что случилось, как обнаружили, почему мониторинг не предупредил раньше и что изменить. ## См. также - [Prometheus](https://llmdocs.ru/wiki/prometheus.md) - [Grafana](https://llmdocs.ru/wiki/grafana.md) - [SRE, SLO и SLA](https://llmdocs.ru/wiki/sre-slo-sla.md) - [Логирование и трассировка (OpenTelemetry)](https://llmdocs.ru/wiki/opentelemetry.md) ## Источники 1. [Google SRE Book — Ch. 6 Monitoring Distributed Systems](https://sre.google/sre-book/monitoring-distributed-systems/) 2. [Brendan Gregg — The USE Method](https://www.brendangregg.com/usemethod.html) 3. [Grafana Labs — The RED Method: How to instrument your services](https://grafana.com/blog/2018/08/02/the-red-method-how-to-instrument-your-services/) 4. [Google SRE Workbook — Alerting on SLOs](https://sre.google/workbook/alerting-on-slos/) 5. [Prometheus Docs — Alerting overview](https://prometheus.io/docs/alerting/latest/overview/) 6. [Rob Ewaschuk — My Philosophy on Alerting](https://docs.google.com/document/d/199PqyG3UsyXlwieHaqbGiWVa8eMWi8zzAn0YfcApr8Q/preview) 7. [OpenTelemetry Documentation](https://opentelemetry.io/docs/) --- # Логирование и трассировка (OpenTelemetry) > Логи, метрики и распределённые трассы как три сигнала наблюдаемости и OpenTelemetry — открытый стандарт и набор SDK для их сбора и передачи. Источник: https://llmdocs.ru/wiki/opentelemetry/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Проект**: OpenTelemetry (CNCF, с 2019) - **Предшественники**: OpenTracing и OpenCensus - **Сигналы**: трассы, метрики, логи, профили - **Протокол**: OTLP (gRPC и HTTP) - **Компоненты**: API, SDK, Collector, автоинструментирование - **Контекст**: W3C Trace Context (traceparent) - **Бэкенды**: Jaeger, Tempo, Zipkin, Prometheus, Loki, коммерческие APM **Логирование и трассировка** — способы понять, что происходит внутри работающей системы. Вместе с метриками их называют тремя сигналами **наблюдаемости** (*observability*): метрики показывают, *что* сломалось, логи — *почему*, а распределённые трассы — *где* именно в цепочке сервисов. **OpenTelemetry** (OTel) — открытый стандарт и набор библиотек для сбора всех трёх сигналов единым способом и отправки их в любую систему хранения, без привязки к конкретному поставщику. ## Три сигнала | Сигнал | Что это | Сильная сторона | Пример хранилища | |---|---|---|---| | **Метрики** | числа во времени (RPS, задержка, память) | дёшево, алерты, тренды | [Prometheus](https://llmdocs.ru/wiki/prometheus.md) | | **Логи** | записи о событиях | подробности конкретного случая | Loki, Elasticsearch | | **Трассы** | путь одного запроса через сервисы | где тратится время и возникает ошибка | Jaeger, Tempo | Сила наблюдаемости — в связях между сигналами: из всплеска ошибок на графике [Grafana](https://llmdocs.ru/wiki/grafana.md) перейти к трассам этих запросов, а из трассы — к логам конкретного сервиса с тем же `trace_id`.[2] ## Логирование Современная практика — **структурированные логи**: каждая запись — объект [JSON](https://llmdocs.ru/wiki/json.md) с полями, а не произвольная строка. ```json {"ts":"2026-11-09T14:03:12Z","level":"error","service":"payments", "msg":"charge failed","order_id":"A-1042","trace_id":"4bf92f3577b34da6"} ``` Такие логи можно фильтровать и агрегировать по полям. Принципы: - писать в stdout, а сбор и доставку оставить среде: [systemd](https://llmdocs.ru/wiki/systemd.md) и journald, Docker, агенты Fluent Bit, Vector или OTel Collector — так советует методология Twelve-Factor App;[6] - использовать уровни (`debug`, `info`, `warn`, `error`) и не включать `debug` в продакшене постоянно; - не писать в логи пароли, токены и персональные данные; - добавлять идентификатор запроса или трассы, чтобы связать записи разных сервисов. ## Распределённая трассировка **Трасса** описывает путь одного запроса и состоит из **спанов** — операций с началом, длительностью, атрибутами и ссылкой на родителя. Запрос к API порождает спан, внутри — спаны обращения к базе данных и вызова другого сервиса, у того — свои спаны. В интерфейсе это выглядит как водопадная диаграмма, где сразу видно самое медленное звено. Чтобы спаны разных сервисов сложились в одну трассу, контекст передаётся с запросом — в HTTP это заголовок `traceparent` по стандарту **W3C Trace Context**:[4] ``` traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01 версия-trace_id-родительский span_id-флаги ``` Хранить каждую трассу дорого, поэтому применяют **сэмплирование**: на входе (сохранять, например, 10% запросов) или по завершении (tail sampling — сохранять все медленные и ошибочные). ## OpenTelemetry OpenTelemetry появился в 2019 году слиянием двух конкурирующих проектов — OpenTracing и OpenCensus — и входит в CNCF; по активности это один из крупнейших проектов фонда после [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md).[1] Он включает: - **API и SDK** для основных языков (Go, Java, Python, JavaScript, .NET, Rust и др.); - **автоинструментирование** — агенты, которые без изменения кода создают спаны для HTTP-фреймворков, клиентов баз данных и очередей; - **OTLP** — протокол передачи телеметрии; - **Collector** — отдельный сервис, принимающий, обрабатывающий и отправляющий данные; - **семантические соглашения** — единые имена атрибутов (`http.request.method`, `db.system`), чтобы данные разных сервисов были сопоставимы.[5] Пример ручного спана на Python: ```python from opentelemetry import trace tracer = trace.get_tracer("payments") def charge(order): with tracer.start_as_current_span("charge") as span: span.set_attribute("order.id", order.id) return gateway.charge(order) ``` Для веб-приложения на [FastAPI](https://llmdocs.ru/wiki/fastapi.md) достаточно запустить его через `opentelemetry-instrument` — спаны для входящих запросов и вызовов базы появятся автоматически. ## Collector Collector отделяет приложения от бэкендов: сервисы отправляют всё по OTLP на локальный Collector, а он фильтрует, сэмплирует, добавляет метки окружения и пересылает данные в нужные системы.[3] ```yaml receivers: otlp: protocols: {grpc: {}, http: {}} processors: batch: {} exporters: otlphttp/tempo: {endpoint: http://tempo:4318} prometheus: {endpoint: 0.0.0.0:8889} service: pipelines: traces: {receivers: [otlp], processors: [batch], exporters: [otlphttp/tempo]} metrics: {receivers: [otlp], processors: [batch], exporters: [prometheus]} ``` Сменить бэкенд — Jaeger на Tempo или открытое решение на коммерческое — можно правкой конфигурации Collector, не трогая код сервисов. ## Наблюдаемость LLM-приложений Те же принципы применяют к системам на языковых моделях: каждый вызов модели, шаг [агента](https://llmdocs.ru/wiki/ai-agent.md) и обращение к инструменту становится спаном с атрибутами — модель, число токенов, задержка. Для этого в OpenTelemetry развиваются семантические соглашения GenAI; на них опираются инструменты вроде Langfuse и Phoenix. ## См. также - [Мониторинг и алертинг](https://llmdocs.ru/wiki/monitoring-alerting.md) - [Prometheus](https://llmdocs.ru/wiki/prometheus.md) - [Grafana](https://llmdocs.ru/wiki/grafana.md) - [SRE, SLO и SLA](https://llmdocs.ru/wiki/sre-slo-sla.md) ## Источники 1. [OpenTelemetry — What is OpenTelemetry](https://opentelemetry.io/docs/what-is-opentelemetry/) 2. [OpenTelemetry — Observability primer](https://opentelemetry.io/docs/concepts/observability-primer/) 3. [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/) 4. [W3C Trace Context](https://www.w3.org/TR/trace-context/) 5. [OpenTelemetry — Semantic Conventions](https://opentelemetry.io/docs/specs/semconv/) 6. [The Twelve-Factor App — Logs](https://12factor.net/logs) --- # Prometheus > Открытая система мониторинга и база временных рядов — сама опрашивает сервисы по HTTP, хранит метрики с метками, позволяет запрашивать их на языке PromQL и формировать алерты. Источник: https://llmdocs.ru/wiki/prometheus/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: система мониторинга и TSDB - **Создан**: SoundCloud, 2012; публично — январь 2015 - **Язык**: Go - **Лицензия**: Apache 2.0 - **CNCF**: второй проект после Kubernetes (2016), выпускник с августа 2018 - **Версия 3.0**: ноябрь 2024 - **Модель сбора**: pull (опрос HTTP-эндпоинтов /metrics) - **Язык запросов**: PromQL - **Порт по умолчанию**: 9090 **Prometheus** — открытая система мониторинга и база данных временных рядов. Она периодически опрашивает сервисы по HTTP, забирает у них текущие значения метрик, хранит их у себя с привязкой к **меткам** (*labels*) и позволяет строить запросы на языке **PromQL** — для графиков, анализа и правил алертов.[1] Prometheus стал стандартом мониторинга в облачной инфраструктуре и в [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md): почти любое серверное ПО умеет отдавать метрики в его формате. ## История Систему начали в 2012 году инженеры SoundCloud — выходцы из Google, вдохновлённые внутренней системой Borgmon. В январе 2015 года проект открыли публично, в 2016-м он стал вторым проектом CNCF после Kubernetes, а в августе 2018 года — вторым её выпускником.[5] Формат метрик лёг в основу открытого стандарта OpenMetrics.[7] В ноябре 2024 года вышла версия 3.0 с новым веб-интерфейсом, поддержкой UTF-8 в именах и приёмом данных по протоколу OpenTelemetry.[6] ## Архитектура - **Сервер Prometheus** по расписанию (обычно раз в 15–60 секунд) опрашивает **цели** (*targets*) — HTTP-эндпоинты `/metrics` — и записывает результат в локальную базу временных рядов (TSDB). - **Обнаружение целей** (*service discovery*) — статический список или автоматическое: из Kubernetes, Consul, облачных API, [DNS](https://llmdocs.ru/wiki/dns.md). - **Экспортеры** — программы-переводчики для систем без собственных метрик: `node_exporter` (метрики [Linux](https://llmdocs.ru/wiki/linux.md)-хоста), `postgres_exporter`, `blackbox_exporter` (внешние проверки HTTP, TCP, ICMP). - **Alertmanager** — отдельный компонент, получающий сработавшие алерты, группирующий и рассылающий их (см. [Мониторинг и алертинг](https://llmdocs.ru/wiki/monitoring-alerting.md)). - **Pushgateway** — промежуточный узел для короткоживущих задач (cron), которые не доживают до опроса. Модель **pull** — главное отличие от многих систем: не сервис отправляет данные, а Prometheus их забирает. Так проще понять, жива ли цель (`up == 0`), и нельзя «завалить» сервер потоком от сбойного клиента. ## Модель данных Временной ряд определяется именем метрики и набором меток: ```text http_requests_total{method="GET", handler="/api/users", code="200"} 1027 ``` Каждое уникальное сочетание меток — отдельный ряд. Поэтому в метки нельзя класть значения с неограниченным разнообразием — идентификаторы пользователей, полные URL, email: число рядов («кардинальность») взрывается, и сервер исчерпывает память.[4] Четыре типа метрик:[2] | Тип | Что хранит | Пример | |---|---|---| | Counter | только растущий счётчик (сбрасывается при перезапуске) | `http_requests_total` | | Gauge | значение, которое растёт и падает | `memory_usage_bytes`, `queue_length` | | Histogram | распределение по корзинам (`_bucket`, `_sum`, `_count`) | `http_request_duration_seconds` | | Summary | готовые квантили, посчитанные на клиенте | редко, гистограммы предпочтительнее | ## PromQL ```promql # запросов в секунду за последние 5 минут, по обработчикам sum by (handler) (rate(http_requests_total[5m])) # доля ошибок 5xx sum(rate(http_requests_total{code=~"5.."}[5m])) / sum(rate(http_requests_total[5m])) # 95-й перцентиль задержки по гистограмме histogram_quantile(0.95, sum by (le) (rate(http_request_duration_seconds_bucket[5m]))) # диски, которые заполнятся в ближайшие 4 часа при текущем темпе predict_linear(node_filesystem_avail_bytes[1h], 4 * 3600) < 0 ``` К счётчикам почти всегда применяют `rate()` или `increase()`: само значение счётчика малоинформативно, важна скорость роста.[3] Частые сложные запросы заранее вычисляют **recording rules** — правила, сохраняющие результат как новый ряд. ## Пример конфигурации ```yaml # prometheus.yml global: scrape_interval: 30s scrape_configs: - job_name: node static_configs: - targets: ["10.0.0.11:9100", "10.0.0.12:9100"] - job_name: api metrics_path: /metrics static_configs: - targets: ["api.internal:8000"] rule_files: ["alerts.yml"] alerting: alertmanagers: - static_configs: [{targets: ["alertmanager:9093"]}] ``` В Kubernetes установку и описание целей обычно берёт на себя Prometheus Operator (через [Helm](https://llmdocs.ru/wiki/helm.md)-чарт kube-prometheus-stack), где цели задаются объектами `ServiceMonitor`. ## Инструментирование приложения Клиентские библиотеки есть для всех популярных языков. Пример на [Python](https://llmdocs.ru/wiki/python.md): ```python from prometheus_client import Counter, Histogram, start_http_server REQUESTS = Counter("app_requests_total", "Обработанные запросы", ["status"]) LATENCY = Histogram("app_request_duration_seconds", "Время обработки") start_http_server(8000) # отдаёт /metrics @LATENCY.time() def handle(req): ... REQUESTS.labels(status="ok").inc() ``` ## Ограничения и экосистема Один сервер Prometheus хранит данные локально и не масштабируется горизонтально; долгий срок хранения и глобальный обзор нескольких кластеров дают совместимые системы **Thanos**, **Grafana Mimir**, **VictoriaMetrics**, принимающие данные через `remote_write`. Prometheus не предназначен для логов и событий с точными значениями (например, биллинга): метрики — это агрегаты с потерей деталей. Визуализацию строят в [Grafana](https://llmdocs.ru/wiki/grafana.md), встроенный интерфейс годится для разовых запросов. ## См. также - [Мониторинг и алертинг](https://llmdocs.ru/wiki/monitoring-alerting.md) - [Grafana](https://llmdocs.ru/wiki/grafana.md) - [Логирование и трассировка (OpenTelemetry)](https://llmdocs.ru/wiki/opentelemetry.md) - [SRE, SLO и SLA](https://llmdocs.ru/wiki/sre-slo-sla.md) ## Источники 1. [Prometheus Docs — Overview](https://prometheus.io/docs/introduction/overview/) 2. [Prometheus Docs — Metric types](https://prometheus.io/docs/concepts/metric_types/) 3. [Prometheus Docs — Querying basics (PromQL)](https://prometheus.io/docs/prometheus/latest/querying/basics/) 4. [Prometheus Docs — Instrumentation best practices](https://prometheus.io/docs/practices/instrumentation/) 5. [CNCF — Prometheus graduation announcement (2018)](https://www.cncf.io/announcements/2018/08/09/prometheus-graduates/) 6. [Prometheus Blog — Announcing Prometheus 3.0 (2024)](https://prometheus.io/blog/2024/11/14/prometheus-3-0/) 7. [OpenMetrics specification](https://github.com/prometheus/OpenMetrics) --- # Pull request / Merge request > Запрос на слияние изменений из одной ветки в другую с обсуждением, код-ревью и автоматическими проверками; на GitHub называется pull request, в GitLab — merge request. Источник: https://llmdocs.ru/wiki/pull-request/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Названия**: pull request (GitHub, Bitbucket), merge request (GitLab) - **Появление**: GitHub, 2008 - **Основа в Git**: команда git request-pull (2005) - **Участники**: автор, ревьюеры, владельцы кода (CODEOWNERS) - **Способы слияния**: merge commit, squash, rebase - **Проверки**: CI, обязательные ревью, отсутствие конфликтов **Pull request** (PR, «запрос на вытягивание») или **merge request** (MR, «запрос на слияние») — предложение влить изменения из одной ветки [Git](https://llmdocs.ru/wiki/git.md) в другую, оформленное на платформе разработки как отдельная страница: описание, список коммитов, построчный дифф, обсуждение, ревью и результаты автоматических проверок.[1] Название зависит от платформы: [GitHub](https://llmdocs.ru/wiki/github.md) и Bitbucket говорят «pull request», [GitLab](https://llmdocs.ru/wiki/gitlab.md) — «merge request»; суть одна.[2] PR — основная единица командной работы с кодом: через него проходит почти каждое изменение основной ветки. ## Откуда название В самом Git есть команда `git request-pull` (2005): она формирует текстовое письмо с просьбой «вытянуть» (`git pull`) изменения из указанного репозитория — так до сих пор принимаются изменения в ядро Linux.[6] GitHub в 2008 году превратил это письмо в веб-страницу с обсуждением, а вместе с форками — в стандартный путь участия в открытых проектах. GitLab выбрал название, отражающее итоговое действие, — слияние. ## Жизненный цикл 1. Разработчик создаёт ветку от основной (или форк чужого репозитория), делает коммиты и отправляет ветку на сервер. 2. Открывает PR: указывает целевую ветку, пишет описание — что и зачем изменено, как проверить, ссылки на задачу (`Closes #123` закроет задачу при слиянии). 3. Запускаются автоматические проверки [CI/CD](https://llmdocs.ru/wiki/ci-cd.md): сборка, тесты, линтеры, сканеры безопасности. 4. Ревьюеры читают дифф, оставляют комментарии к строкам, предлагают правки (*suggestions*), одобряют или запрашивают изменения. 5. Автор отвечает и дописывает коммиты; PR обновляется автоматически. 6. Когда выполнены условия защиты ветки — нужные одобрения, зелёные проверки, нет конфликтов, — PR сливается и ветку удаляют. **Черновик** (*draft*) PR открывают заранее, чтобы показать ход работы и прогнать CI, — слить его нельзя, пока автор не отметит готовность. ```bash git switch -c fix/login-timeout git commit -am "Увеличить таймаут входа до 30 секунд" git push -u origin fix/login-timeout gh pr create --fill --draft # GitHub CLI glab mr create --fill # GitLab CLI ``` ## Способы слияния Платформы предлагают три кнопки (доступные варианты настраиваются в репозитории):[3] | Способ | Результат в основной ветке | |---|---| | Merge commit | все коммиты ветки + коммит слияния; история полная | | Squash and merge | один коммит на весь PR; история основной ветки чистая | | Rebase and merge | коммиты ветки переносятся поверх, без коммита слияния; история линейная | Подробно о различиях — в статье [Merge и rebase](https://llmdocs.ru/wiki/merge-rebase.md). ## Код-ревью Ревью — главная ценность PR: второй человек находит ошибки, следит за архитектурой и распространяет знание о коде в команде. Рекомендации из практики крупных компаний:[5] - **маленькие PR** — изменения на 100–300 строк ревьюят быстрее и внимательнее, чем на 2000; - **один PR — одна задача**, рефакторинг отдельно от новой функциональности; - описание отвечает на вопрос «зачем», а не пересказывает дифф; - комментарии — о коде, а не об авторе; мелочи помечают как необязательные (`nit:`); - стиль и форматирование проверяют автоматически (линтеры, форматтеры), а не люди. Файл **CODEOWNERS** назначает ответственных за каталоги и файлы: при изменении `infra/` в ревьюеры автоматически добавляется команда инфраструктуры, а правила защиты ветки могут требовать её одобрения.[4] ```text # .github/CODEOWNERS *.py @example/backend /infra/ @example/platform /docs/ @example/tech-writers ``` ## Шаблоны и автоматизация Шаблон описания (`.github/pull_request_template.md`, в GitLab — `.gitlab/merge_request_templates/`) задаёт чек-лист: тесты, миграции, документация. Боты обновляют зависимости собственными PR (Dependabot, Renovate), а ИИ-ассистенты всё чаще выполняют первичное ревью и описывают изменения. Очередь слияния (*merge queue*) последовательно проверяет PR поверх свежей основной ветки, чтобы два по отдельности зелёных изменения не сломали её вместе. ## Подходы - **Короткоживущие ветки** (GitHub Flow, trunk-based) — PR живёт часы или дни; чем дольше ветка, тем болезненнее конфликты. - **Стековые PR** (*stacked PRs*) — большая задача разбивается на цепочку зависимых PR, которые ревьюят по очереди. - **Ревью после слияния** — в небольших доверенных командах изменения вливают сразу, а смотрят позже; скорость в обмен на риск. ## См. также - [Ветвление в Git](https://llmdocs.ru/wiki/git-branching.md) - [Merge и rebase](https://llmdocs.ru/wiki/merge-rebase.md) - [GitHub Actions](https://llmdocs.ru/wiki/github-actions.md) - [GitLab CI](https://llmdocs.ru/wiki/gitlab-ci.md) ## Источники 1. [GitHub Docs — About pull requests](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests) 2. [GitLab Docs — Merge requests](https://docs.gitlab.com/user/project/merge_requests/) 3. [GitHub Docs — About merge methods on GitHub](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/configuring-pull-request-merges/about-merge-methods-on-github) 4. [GitHub Docs — About code owners](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners) 5. [Google Engineering Practices — Code Review Developer Guide](https://google.github.io/eng-practices/review/) 6. [git-request-pull documentation](https://git-scm.com/docs/git-request-pull) --- # Семантическое версионирование > Соглашение о номерах версий MAJOR.MINOR.PATCH, в котором каждая цифра сообщает о характере изменений — несовместимых, новых возможностях или исправлениях. Источник: https://llmdocs.ru/wiki/semver/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Автор**: Том Престон-Вернер - **Текущая версия спецификации**: 2.0.0 (2013) - **Формат**: MAJOR.MINOR.PATCH[-предрелиз][+сборка] - **Лицензия спецификации**: CC BY 3.0 - **Используется**: npm, Cargo, Go-модули, Helm, многие библиотеки - **Альтернативы**: календарное версионирование (CalVer), PEP 440 в Python - **Сайт**: semver.org **Семантическое версионирование** (англ. *Semantic Versioning*, **SemVer**) — соглашение о том, как присваивать номера версиям программ, чтобы номер сам говорил о характере изменений. Версия записывается как `MAJOR.MINOR.PATCH`, например `2.7.1`: рост первой цифры означает несовместимые изменения, второй — новые возможности без поломок, третьей — только исправления ошибок.[1] Благодаря этому пакетные менеджеры могут автоматически обновлять зависимости в безопасных пределах, а пользователь библиотеки заранее знает, чего ждать от обновления. ## История Спецификацию написал Том Престон-Вернер, сооснователь [GitHub](https://llmdocs.ru/wiki/github.md), обобщив сложившуюся практику открытых проектов. Версия 2.0.0, действующая до сих пор, опубликована в 2013 году на сайте semver.org. Соглашение было принято экосистемами npm, Cargo, Go-модулей, Composer, Helm и многими другими. ## Правила Обязательное условие — у проекта есть **публичный API**: документированный интерфейс, относительно которого и определяется совместимость. Дальше:[1] | Что изменилось | Какую часть увеличить | Пример | |---|---|---| | Несовместимое изменение API | MAJOR, остальные обнуляются | `1.4.2 → 2.0.0` | | Новая возможность, обратно совместимая | MINOR, PATCH обнуляется | `1.4.2 → 1.5.0` | | Исправление ошибки без изменения API | PATCH | `1.4.2 → 1.4.3` | Ещё несколько важных пунктов: - Опубликованная версия **неизменна**: исправление выпускается новым номером, а не перезаписью старого. - Версии `0.y.z` — начальная разработка: API нестабилен, и ломать его можно в любой момент. Версия `1.0.0` объявляет публичный API стабильным. - **Предрелизы** записываются через дефис: `2.0.0-alpha`, `2.0.0-beta.2`, `2.0.0-rc.1`. Они младше соответствующего релиза: `2.0.0-rc.1 < 2.0.0`. - **Метаданные сборки** — через плюс: `1.0.0+20261109.sha.5114f85`. При сравнении версий они игнорируются. - Сравнение покомпонентное и числовое: `1.10.0 > 1.9.0`, а предрелизные метки сравниваются по частям — `alpha.2 < alpha.10 < beta`. ## Диапазоны версий Пакетные менеджеры используют SemVer, чтобы описывать допустимые обновления:[2] | Запись (npm) | Разрешает | Смысл | |---|---|---| | `^1.4.2` | `>=1.4.2 <2.0.0` | любые совместимые обновления | | `~1.4.2` | `>=1.4.2 <1.5.0` | только исправления | | `1.4.2` | ровно эту версию | полная фиксация | | `^0.4.2` | `>=0.4.2 <0.5.0` | в нулевой версии MINOR считается «мажорным» | В Cargo запись `"1.4.2"` по умолчанию означает то же, что `^1.4.2`.[3] В Go несовместимая версия модуля получает новый путь импорта с суффиксом: `example.com/lib/v2` — так две мажорные версии могут жить в одной программе.[4] [Python](https://llmdocs.ru/wiki/python.md) использует собственную схему PEP 440, которая совместима с SemVer по форме, но допускает и другие варианты (`1.0.post1`, `2.0rc1`); оператор `~=` в ней похож на тильду npm.[7] Диапазоны дают гибкость, но для воспроизводимых сборок точные версии фиксируются в **lock-файлах** (`package-lock.json`, `Cargo.lock`, `uv.lock`), которые хранят в репозитории. ## Автоматизация Соглашение **Conventional Commits** структурирует сообщения коммитов: `fix:` соответствует PATCH, `feat:` — MINOR, а `BREAKING CHANGE:` в теле или `!` после типа (`feat!:`) — MAJOR.[5] Инструменты semantic-release, release-please и changesets по истории коммитов сами вычисляют следующую версию, пишут журнал изменений и публикуют релиз из [GitHub Actions](https://llmdocs.ru/wiki/github-actions.md) или другой CI-системы. ```text feat(api): добавить фильтр по дате → 1.5.0 fix: не падать на пустом ответе → 1.5.1 feat!: удалить устаревший метод /v1/list → 2.0.0 ``` Номер версии обычно ставят и Git-тегом: `git tag -a v1.5.1 -m "Release 1.5.1"`. ## Ограничения и критика - **Совместимость — суждение человека.** Изменение поведения, исправление ошибки, на которую кто-то полагался, или поднятие минимальной версии языка формально могут оказаться «ломающими». Отсюда шутка, что любое изменение для кого-то мажорное. - **«Вечный ноль».** Многие популярные проекты годами живут в `0.x`, обходя обязательства SemVer. - **Неприменимость к продуктам без API.** Для приложений и операционных систем часто удобнее **календарное версионирование** (CalVer): Ubuntu `24.04`, pip `25.1`, JetBrains `2025.2` — номер говорит о дате, а не о совместимости.[6] Несмотря на это, SemVer остаётся общим языком между авторами библиотек и их пользователями, и его соблюдение — признак зрелого проекта. ## См. также - [Git](https://llmdocs.ru/wiki/git.md) - [pip и PyPI](https://llmdocs.ru/wiki/pip-pypi.md) - [Cargo](https://llmdocs.ru/wiki/cargo.md) - [Helm](https://llmdocs.ru/wiki/helm.md) ## Источники 1. [Semantic Versioning 2.0.0](https://semver.org/) 2. [npm Docs — About semantic versioning](https://docs.npmjs.com/about-semantic-versioning) 3. [Cargo Book — SemVer Compatibility](https://doc.rust-lang.org/cargo/reference/semver.html) 4. [Go Modules Reference — Major version suffixes](https://go.dev/ref/mod#major-version-suffixes) 5. [Conventional Commits 1.0.0](https://www.conventionalcommits.org/en/v1.0.0/) 6. [Calendar Versioning](https://calver.org/) 7. [PEP 440 — Version Identification and Dependency Specification](https://peps.python.org/pep-0440/) --- # SRE, SLO и SLA > Site Reliability Engineering — подход Google к эксплуатации через инженерию; SLI, SLO и SLA задают измеримую надёжность, а бюджет ошибок балансирует скорость и стабильность. Источник: https://llmdocs.ru/wiki/sre-slo-sla/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Появление**: Google, 2003 (Бен Трейнор Слосс) - **Ключевая книга**: Site Reliability Engineering (O'Reilly, 2016) - **SLI**: показатель уровня обслуживания (что измеряем) - **SLO**: целевой уровень (внутренняя цель) - **SLA**: соглашение с клиентом (с последствиями) - **Бюджет ошибок**: 100% − SLO - **Практики**: постмортемы без поиска виновных, борьба с рутиной, дежурства **SRE** (*Site Reliability Engineering*, инженерия надёжности) — подход к эксплуатации сервисов, при котором задачи администрирования решаются методами программной инженерии: автоматизацией, измерениями и явными целями надёжности. Его центральные понятия — **SLI**, **SLO** и **SLA**: что именно измерять, какой уровень считать достаточным и что обещать клиентам. Из них выводится **бюджет ошибок** — допустимый объём ненадёжности, который команда может «потратить» на быстрые релизы и эксперименты. ## История Подход сложился в Google с 2003 года, когда Бен Трейнор Слосс возглавил команду эксплуатации и, по его словам, поставил вопрос «что будет, если поручить эксплуатацию программистам».[2] В 2016 году Google опубликовала книгу *Site Reliability Engineering*, а затем *The Site Reliability Workbook* — обе бесплатно доступны на sre.google. SRE часто описывают как конкретную реализацию идей DevOps: «class SRE implements DevOps». ## SLI, SLO, SLA | Термин | Расшифровка | Что это | Пример | |---|---|---|---| | **SLI** | Service Level Indicator | измеряемый показатель | доля HTTP-запросов, отвеченных без ошибки 5xx быстрее 300 мс | | **SLO** | Service Level Objective | целевое значение SLI за период | 99,9% таких запросов за 28 дней | | **SLA** | Service Level Agreement | договор с клиентом и последствия нарушения | 99,5% в месяц, иначе компенсация 10% стоимости | SLI лучше всего выражать как отношение «хороших» событий ко всем: `хорошие запросы / все запросы`.[1] Типичные SLI — доступность, задержка (доля запросов быстрее порога, а не среднее), корректность и свежесть данных. Они близки к «золотым сигналам» мониторинга: задержка, трафик, ошибки, насыщение.[6] SLO всегда строже SLA: внутренняя цель должна сработать как предупреждение задолго до нарушения договора. Ставить SLO 100% бессмысленно — пользователь не отличит 99,99% от 100% из-за собственного интернета, а цена каждой следующей «девятки» растёт многократно. ## Сколько это в минутах | Доступность | Простой в месяц (30 дней) | В год | |---|---|---| | 99% | 7 ч 12 мин | 3,65 дня | | 99,5% | 3 ч 36 мин | 1,83 дня | | 99,9% | 43 мин | 8 ч 46 мин | | 99,95% | 21,6 мин | 4 ч 23 мин | | 99,99% | 4,3 мин | 52,6 мин | Если сервис зависит от трёх компонентов с доступностью 99,9% каждый, его итоговая доступность без резервирования — около 99,7%. ## Бюджет ошибок **Бюджет ошибок** = 100% − SLO. При SLO 99,9% и миллионе запросов в месяц допустимо 1000 неудачных.[2] Пока бюджет не исчерпан, команда свободно выкатывает изменения; если исчерпан — приоритет переходит к стабильности: релизы замораживаются, кроме исправлений, а время уходит на устранение причин сбоев. Так спор «разработка хочет быстрее, эксплуатация — стабильнее» превращается в решение по данным, о котором стороны договорились заранее. ## Алерты по SLO Вместо алертов на каждый симптом («CPU > 80%») SRE рекомендует оповещать о **скорости сжигания бюджета** (burn rate).[3] Burn rate 1 означает, что бюджет закончится ровно к концу периода; 14,4 — что за час сгорает 2% месячного бюджета. Типичная схема — несколько окон: - burn rate > 14,4 за 1 час (и за 5 минут) — разбудить дежурного; - burn rate > 6 за 6 часов — срочно, но в рабочее время; - burn rate > 1 за 3 дня — тикет. ```promql # доля ошибок за 1 час относительно бюджета SLO 99,9% (sum(rate(http_requests_total{code=~"5.."}[1h])) / sum(rate(http_requests_total[1h]))) / 0.001 > 14.4 ``` Такие правила считаются в [Prometheus](https://llmdocs.ru/wiki/prometheus.md) и отображаются в [Grafana](https://llmdocs.ru/wiki/grafana.md); генераторы вроде Sloth и Pyrra строят их из короткого описания SLO. ## Практики SRE - **Постмортемы без поиска виновных** (blameless) — после инцидента описывают хронологию, причины и действия по предотвращению; цель — улучшить систему, а не наказать человека.[4] - **Борьба с рутиной** (toil) — ручная повторяющаяся работа без долговременной ценности; в Google ориентир — не более 50% времени SRE на рутину, остальное — на автоматизацию.[5] - **Дежурства** с ограниченной нагрузкой, ранбуки и понятная эскалация. - **Управление изменениями** — постепенные выкладки, канареечные релизы, быстрый откат (см. [CI/CD](https://llmdocs.ru/wiki/ci-cd.md)). - **Планирование мощности** и нагрузочное тестирование. ## Как начать 1. Выбрать 1–3 пользовательских пути (вход, оформление заказа, API поиска). 2. Определить SLI по уже собираемым метрикам и посмотреть фактические значения за месяц. 3. Поставить SLO чуть ниже текущего уровня и договориться о политике бюджета ошибок. 4. Настроить алерты по burn rate и убрать шумные алерты на причины. 5. Пересматривать SLO раз в квартал. ## См. также - [Мониторинг и алертинг](https://llmdocs.ru/wiki/monitoring-alerting.md) - [Prometheus](https://llmdocs.ru/wiki/prometheus.md) - [Логирование и трассировка (OpenTelemetry)](https://llmdocs.ru/wiki/opentelemetry.md) - [Бэкапы: правило 3-2-1](https://llmdocs.ru/wiki/backup-3-2-1.md) ## Источники 1. [Google SRE Book — Service Level Objectives](https://sre.google/sre-book/service-level-objectives/) 2. [Google SRE Book — Embracing Risk](https://sre.google/sre-book/embracing-risk/) 3. [Google SRE Workbook — Alerting on SLOs](https://sre.google/workbook/alerting-on-slos/) 4. [Google SRE Book — Postmortem Culture](https://sre.google/sre-book/postmortem-culture/) 5. [Google SRE Book — Eliminating Toil](https://sre.google/sre-book/eliminating-toil/) 6. [Google SRE Book — Monitoring Distributed Systems (golden signals)](https://sre.google/sre-book/monitoring-distributed-systems/) --- # Terraform и OpenTofu > Инструменты декларативного описания облачной инфраструктуры на языке HCL — планируют и применяют изменения через провайдеры облаков; OpenTofu — открытый форк Terraform. Источник: https://llmdocs.ru/wiki/terraform-opentofu/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: инструмент Infrastructure as Code - **Terraform**: HashiCorp, 2014; с 2025 года HashiCorp — часть IBM - **Лицензия Terraform**: BUSL 1.1 (с августа 2023, ранее MPL 2.0) - **OpenTofu**: форк под эгидой Linux Foundation, 1.6.0 — январь 2024 - **Лицензия OpenTofu**: MPL 2.0 - **Язык конфигурации**: HCL - **Язык реализации**: Go - **Ключевые понятия**: провайдер, ресурс, модуль, состояние (state), план **Terraform** — инструмент [Infrastructure as Code](https://llmdocs.ru/wiki/infrastructure-as-code.md), который описывает облачную инфраструктуру — виртуальные машины, сети, базы данных, DNS-записи, кластеры [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) — в декларативных файлах и приводит реальное состояние в соответствие с ними.[1] Пользователь пишет, *что* должно существовать, а Terraform вычисляет, какие API-вызовы нужны, показывает план и выполняет его. **OpenTofu** — открытый форк Terraform, появившийся после смены его лицензии в 2023 году; инструменты почти полностью совместимы, и всё сказанное ниже относится к обоим.[2] ## История HashiCorp выпустила Terraform в 2014 году; версия 1.0 со стабильными гарантиями совместимости вышла в 2021-м. Благодаря тысячам провайдеров Terraform стал стандартом описания облачной инфраструктуры. В августе 2023 года HashiCorp перевела свои продукты с открытой лицензии MPL 2.0 на Business Source License, ограничивающую использование конкурентами.[3] В ответ сообщество создало форк OpenTofu, который принял Linux Foundation; первая стабильная версия 1.6.0 вышла в январе 2024 года.[4] С тех пор проекты развиваются раздельно: в OpenTofu, например, появилось встроенное шифрование файла состояния.[6] В феврале 2025 года HashiCorp вошла в состав IBM.[7] ## Основные понятия - **Провайдер** — плагин для конкретного API: AWS, Google Cloud, Azure, Yandex Cloud, Cloudflare, Kubernetes, GitHub. Провайдеры скачиваются из реестра при `init`. - **Ресурс** (`resource`) — управляемый объект: сервер, бакет, запись DNS. - **Источник данных** (`data`) — чтение существующих объектов, которыми Terraform не управляет. - **Переменные и выходы** (`variable`, `output`) — параметры и результаты конфигурации. - **Модуль** — переиспользуемый набор ресурсов (например, «сеть + кластер + база»), подключаемый с параметрами. - **Состояние** (*state*) — файл `terraform.tfstate`, связывающий описание с реальными объектами. ## Пример ```hcl terraform { required_providers { aws = { source = "hashicorp/aws", version = "~> 5.0" } } backend "s3" { bucket = "example-tf-state" key = "prod/network.tfstate" region = "eu-central-1" } } variable "env" { default = "prod" } resource "aws_s3_bucket" "assets" { bucket = "example-assets-${var.env}" tags = { env = var.env } } output "bucket_name" { value = aws_s3_bucket.assets.bucket } ``` Ссылки между ресурсами (`aws_s3_bucket.assets.bucket`) образуют граф зависимостей: Terraform сам определяет порядок создания и создаёт независимые ресурсы параллельно. ## Рабочий цикл ```bash terraform init # скачать провайдеры и модули, подключить backend terraform fmt && terraform validate terraform plan -out=tfplan # показать, что будет создано (+), изменено (~), удалено (-) terraform apply tfplan terraform destroy # удалить всё, что описано tofu plan # то же самое в OpenTofu ``` **План** — главная гарантия безопасности: перед применением видно каждое изменение, и его проверяют на ревью в [pull request](https://llmdocs.ru/wiki/pull-request.md). Особого внимания требуют строки «must be replaced»: изменение некоторых атрибутов приводит к пересозданию ресурса, а для базы данных это означает потерю данных. ## Состояние Файл состояния — самая чувствительная часть.[5] - Его хранят не в Git, а в **удалённом backend** (S3-совместимое хранилище, Terraform Cloud, GitLab, Consul) с **блокировкой**, чтобы два человека не применяли изменения одновременно. - В нём лежат атрибуты ресурсов, нередко с паролями и ключами в открытом виде — доступ к нему должен быть ограничен (см. [Управление секретами](https://llmdocs.ru/wiki/secrets-management.md)). - Ручные изменения в облаке вызывают **дрейф** (*drift*): `plan` покажет расхождение и предложит вернуть описанное состояние. - `terraform import` и блоки `import` подключают уже существующие ресурсы, а `state mv` и блоки `moved` позволяют переименовывать без пересоздания. ## Практика - Делить инфраструктуру на небольшие независимые конфигурации (сеть, данные, приложения) с отдельными файлами состояния — так меньше «радиус поражения» ошибки. - Фиксировать версии провайдеров (`~> 5.0`) и коммитить `.terraform.lock.hcl`. - Запускать `plan` в [CI/CD](https://llmdocs.ru/wiki/ci-cd.md) на каждый pull request и `apply` только после слияния — вручную или через Atlantis, Terraform Cloud, Spacelift. - Использовать проверки tflint, checkov, trivy для поиска ошибок и небезопасных настроек. Terraform создаёт инфраструктуру, но обычно не настраивает программы внутри серверов — для этого применяют [Ansible](https://llmdocs.ru/wiki/ansible.md) или образы, собранные заранее. Альтернативы с языками общего назначения — Pulumi и AWS CDK. ## См. также - [Infrastructure as Code](https://llmdocs.ru/wiki/infrastructure-as-code.md) - [Ansible](https://llmdocs.ru/wiki/ansible.md) - [GitLab CI](https://llmdocs.ru/wiki/gitlab-ci.md) - [Лицензии ПО (MIT, GPL, Apache, CC)](https://llmdocs.ru/wiki/software-licenses.md) ## Источники 1. [Terraform Documentation](https://developer.hashicorp.com/terraform/docs) 2. [OpenTofu Documentation](https://opentofu.org/docs/) 3. [HashiCorp — HashiCorp adopts Business Source License (2023)](https://www.hashicorp.com/blog/hashicorp-adopts-business-source-license) 4. [Linux Foundation — OpenTofu announces general availability (2024)](https://www.linuxfoundation.org/press/opentofu-announces-general-availability) 5. [Terraform Docs — State](https://developer.hashicorp.com/terraform/language/state) 6. [OpenTofu Docs — State and plan encryption](https://opentofu.org/docs/language/state/encryption/) 7. [IBM — IBM completes acquisition of HashiCorp (2025)](https://newsroom.ibm.com/2025-02-27-ibm-completes-acquisition-of-hashicorp,-creates-comprehensive,-end-to-end-hybrid-cloud-platform) --- # Cargo и crates.io > Cargo — официальная система сборки и менеджер пакетов Rust; crates.io — центральный реестр пакетов (крейтов). Источник: https://llmdocs.ru/wiki/cargo/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: система сборки и менеджер пакетов - **Язык**: Rust - **Файлы проекта**: `Cargo.toml`, `Cargo.lock` - **Реестр**: crates.io - **Документация крейтов**: docs.rs - **Входит в**: стандартную установку Rust (rustup) - **Лицензия**: MIT / Apache 2.0 - **Сайт**: [doc.rust-lang.org/cargo](https://doc.rust-lang.org/cargo/) **Cargo** — официальная система сборки и менеджер пакетов языка [Rust](https://llmdocs.ru/wiki/rust.md), а **crates.io** — центральный публичный реестр пакетов, которые в Rust называют **крейтами** (crates). Cargo скачивает зависимости, компилирует проект, запускает тесты и бенчмарки, генерирует документацию и публикует крейты. Единый стандартный инструмент — одна из причин, почему экосистему Rust часто приводят в пример: любой проект собирается командой `cargo build` без отдельной настройки системы сборки. ## История Cargo создавался с 2014 года, параллельно с подготовкой Rust 1.0, разработчиками Иегудой Кацем и Карлом Лерке — авторами Bundler для Ruby. Реестр crates.io открылся незадолго до стабильного выпуска языка. Cargo поставляется вместе с компилятором через rustup. Со временем в него встроили команды, которые раньше были сторонними расширениями, — например, `cargo add`. Подробные правила описаны в «Книге Cargo».[1] ## Структура проекта ```bash cargo new hello # бинарный проект cargo new --lib mylib # библиотека ``` ```text hello/ ├── Cargo.toml # манифест: имя, версия, зависимости ├── Cargo.lock # точные версии всего дерева зависимостей └── src/ └── main.rs # для библиотеки — lib.rs ``` Манифест: ```toml [package] name = "hello" version = "0.1.0" edition = "2024" [dependencies] serde = { version = "1", features = ["derive"] } tokio = { version = "1", features = ["full"] } [dev-dependencies] criterion = "0.5" [profile.release] lto = true ``` ## Основные команды | Команда | Действие | |---|---| | `cargo build` / `cargo build --release` | сборка в режиме отладки / с оптимизациями | | `cargo run` | собрать и запустить | | `cargo check` | быстрая проверка без генерации кода | | `cargo test` | модульные, интеграционные тесты и примеры из документации | | `cargo add serde` | добавить зависимость в `Cargo.toml` | | `cargo update` | обновить версии в `Cargo.lock` в рамках ограничений | | `cargo doc --open` | сгенерировать и открыть документацию | | `cargo clippy`, `cargo fmt` | линтер и форматирование (см. [Clippy и rustfmt](https://llmdocs.ru/wiki/clippy-rustfmt.md)) | | `cargo publish` | опубликовать крейт на crates.io | | `cargo install ripgrep` | установить утилиту из crates.io | ## Версии и зависимости Версии крейтов следуют [семантическому версионированию](https://llmdocs.ru/wiki/semver.md). Запись `serde = "1.0"` по умолчанию означает `^1.0`: подходит любая совместимая версия от 1.0.0 до 2.0.0.[2] Точные выбранные версии фиксируются в `Cargo.lock`; для приложений его коммитят в репозиторий, чтобы сборки были воспроизводимыми. Зависимости можно брать не только из crates.io, но и из Git-репозитория или локальной папки. Cargo допускает в одном дереве несколько несовместимых версий одного крейта (например, 1.x и 2.x), чем отличается от многих менеджеров пакетов. ## Возможности - **Фичи** (features) — условная компиляция частей крейта; пользователь включает только то, что нужно, уменьшая время сборки и размер программы.[4] - **Рабочие пространства** (workspaces) — несколько крейтов в одном репозитории с общим `Cargo.lock` и каталогом сборки.[3] - **Профили** — настройки оптимизации для `dev`, `release` и собственных профилей. - **Сценарий сборки** `build.rs` — код, выполняемый перед компиляцией: генерация кода, сборка C-библиотек. - **Расширения** — любая программа `cargo-xxx` в `PATH` становится подкомандой `cargo xxx` (например, `cargo-audit`, `cargo-watch`). ## crates.io и docs.rs На crates.io публикуются открытые крейты. Опубликованную версию нельзя удалить или заменить — только «отозвать» (yank), чтобы новые проекты её не выбирали, но существующие продолжали собираться. Это гарантирует, что однажды собранный проект соберётся снова.[5] Для каждого опубликованного крейта сервис docs.rs автоматически собирает и размещает документацию. ## Безопасность Как и другие публичные реестры, crates.io подвержен рискам цепочки поставок: тайпсквоттингу и вредоносным сценариям `build.rs` и процедурным макросам, которые выполняются при сборке. Базу известных уязвимостей ведёт проект RustSec, а утилита `cargo audit` проверяет `Cargo.lock` по этой базе.[6] ## Сравнение | | Cargo | [pip](https://llmdocs.ru/wiki/pip-pypi.md) | [npm](https://llmdocs.ru/wiki/npm.md) | [Go-модули](https://llmdocs.ru/wiki/go-modules.md) | |---|---|---|---|---| | Сборка | встроена | нет | скрипты | встроена (`go build`) | | Файл блокировки | `Cargo.lock` | нет | `package-lock.json` | `go.sum` (хеши) | | Реестр | crates.io | PyPI | npmjs.com | любые Git-репозитории + прокси | | Тесты и документация | встроены | нет | скрипты | встроены | ## См. также - [Rust (язык)](https://llmdocs.ru/wiki/rust.md) - [Семантическое версионирование](https://llmdocs.ru/wiki/semver.md) - [Clippy и rustfmt](https://llmdocs.ru/wiki/clippy-rustfmt.md) - [pip и PyPI](https://llmdocs.ru/wiki/pip-pypi.md) ## Источники 1. [The Cargo Book](https://doc.rust-lang.org/cargo/) 2. [The Cargo Book — Specifying Dependencies](https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html) 3. [The Cargo Book — Workspaces](https://doc.rust-lang.org/cargo/reference/workspaces.html) 4. [The Cargo Book — Features](https://doc.rust-lang.org/cargo/reference/features.html) 5. [crates.io — Policies](https://crates.io/policies) 6. [RustSec Advisory Database](https://rustsec.org/) --- # Clippy и rustfmt > Официальные инструменты Rust — rustfmt форматирует код по единому стилю, Clippy проверяет его сотнями линтов на ошибки, неидиоматичные конструкции и проблемы производительности. Источник: https://llmdocs.ru/wiki/clippy-rustfmt/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Язык**: Rust - **rustfmt**: форматтер, команда cargo fmt - **Clippy**: линтер, команда cargo clippy; более 750 линтов - **Установка**: компоненты rustup (rustfmt, clippy) - **Настройки**: rustfmt.toml, clippy.toml, [lints] в Cargo.toml - **Интеграция**: rust-analyzer, pre-commit, CI **rustfmt** и **Clippy** — официальные инструменты экосистемы [Rust](https://llmdocs.ru/wiki/rust.md), которые устанавливаются вместе с компилятором через rustup. **rustfmt** автоматически приводит код к единому стилю, описанному в Rust Style Guide, а **Clippy** — линтер с сотнями проверок, который находит ошибки, неидиоматичный код и упущенные возможности для оптимизации. Оба запускаются через [Cargo](https://llmdocs.ru/wiki/cargo.md) одной командой и стали обязательной частью CI почти любого Rust-проекта.[1][3] ## rustfmt rustfmt следует официальному руководству по стилю Rust:[4] четыре пробела, максимальная ширина строки 100 символов, завершающие запятые в многострочных списках, упорядоченные импорты. ```bash rustup component add rustfmt cargo fmt # отформатировать весь проект cargo fmt --check # только проверить (для CI), код возврата ≠ 0 при расхождениях ``` В отличие от [gofmt](https://llmdocs.ru/wiki/gofmt-govet.md), у rustfmt есть настройки в файле `rustfmt.toml` — но сообщество рекомендует почти ничего не менять, чтобы код всех проектов выглядел одинаково.[6] ```toml # rustfmt.toml edition = "2024" max_width = 100 # nightly-опции: # imports_granularity = "Crate" # group_imports = "StdExternalCrate" ``` Многие опции доступны только в nightly-версии. Отдельный фрагмент можно исключить атрибутом `#[rustfmt::skip]` — например, вручную выровненную матрицу. Стиль привязан к **редакции** языка (style edition), поэтому обновление rustfmt не переформатирует код неожиданно. ## Clippy Clippy проверяет код на уровне, недоступном обычным предупреждениям компилятора. Название — отсылка к скрепке-помощнику из Microsoft Office.[1] ```bash rustup component add clippy cargo clippy # проверить cargo clippy --all-targets --all-features -- -D warnings # строго, для CI cargo clippy --fix # применить автоматические исправления ``` ### Группы линтов Линты разделены на группы с разным уровнем по умолчанию:[2] | Группа | По умолчанию | Что ловит | |---|---|---| | `correctness` | ошибка | почти наверняка баги | | `suspicious` | предупреждение | подозрительный код | | `style` | предупреждение | неидиоматичное написание | | `complexity` | предупреждение | излишне сложный код | | `perf` | предупреждение | лишние аллокации и копирования | | `pedantic` | выкл. | строгие, иногда спорные проверки | | `restriction` | выкл. | запреты под политику проекта (`unwrap_used`, `print_stdout`) | | `nursery` | выкл. | экспериментальные линты | | `cargo` | выкл. | проблемы метаданных Cargo.toml | ### Примеры ```rust // clippy::len_zero — используйте is_empty() if v.len() == 0 { } // clippy::needless_range_loop — итерируйтесь напрямую for i in 0..v.len() { println!("{}", v[i]); } // clippy::redundant_clone — лишнее копирование let s2 = s.clone(); drop(s); // clippy::manual_map let y = match x { Some(v) => Some(v + 1), None => None }; // → x.map(|v| v + 1) // clippy::unwrap_used (restriction) — запрет unwrap в продакшен-коде let n: i32 = input.parse().unwrap(); ``` Линты особенно полезны новичкам: они подсказывают идиомы — `if let`, итераторы, `?` вместо ручного `match` (см. [Обработка ошибок в Rust (Result, ?)](https://llmdocs.ru/wiki/rust-errors.md)) — и объясняют их ссылкой на документацию. ## Настройка С Rust 1.74 уровни линтов удобно задавать прямо в `Cargo.toml` — для одного крейта или для всего workspace:[5][7] ```toml [lints.rust] unsafe_code = "forbid" [lints.clippy] pedantic = { level = "warn", priority = -1 } unwrap_used = "deny" undocumented_unsafe_blocks = "deny" module_name_repetitions = "allow" ``` Отдельные места можно разрешить атрибутом с объяснением: ```rust #[expect(clippy::too_many_arguments, reason = "API повторяет C-функцию")] fn ffi_wrapper(a: i32, b: i32, c: i32, d: i32, e: i32, f: i32, g: i32, h: i32) {} ``` Атрибут `#[expect]` (стабилен с Rust 1.81) лучше `#[allow]`: он выдаст предупреждение, если подавляемый линт перестал срабатывать и подавление стало ненужным. Числовые пороги (например, допустимая когнитивная сложность) задаются в `clippy.toml`. Линт `undocumented_unsafe_blocks` требует комментарий `// SAFETY:` у каждого `unsafe`-блока — это стандартная практика для [Unsafe Rust](https://llmdocs.ru/wiki/unsafe-rust.md). ## В CI и редакторе Типичный набор шагов в [GitHub Actions](https://llmdocs.ru/wiki/github-actions.md) или [GitLab CI](https://llmdocs.ru/wiki/gitlab-ci.md): ```bash cargo fmt --all --check cargo clippy --all-targets --all-features -- -D warnings cargo test --all-features ``` Флаг `-D warnings` превращает предупреждения в ошибки, чтобы новый код не добавлял замечаний. Версию инструментов стоит закрепить файлом `rust-toolchain.toml`: каждый релиз Rust добавляет новые линты, и без фиксации сборка может внезапно «покраснеть». В редакторе rust-analyzer умеет запускать Clippy вместо `cargo check` при сохранении и показывать замечания прямо в коде. ## Аналоги Похожую пару в Go образуют gofmt и go vet со staticcheck, в Python — [Ruff](https://llmdocs.ru/wiki/ruff.md) (линтер и форматтер в одном), в JavaScript — Prettier и ESLint. Как и Ruff, Clippy умеет автоматически исправлять многие замечания. ## См. также - [gofmt и go vet](https://llmdocs.ru/wiki/gofmt-govet.md) - [Cargo и crates.io](https://llmdocs.ru/wiki/cargo.md) - [Ruff](https://llmdocs.ru/wiki/ruff.md) - [Макросы Rust](https://llmdocs.ru/wiki/rust-macros.md) ## Источники 1. [Clippy documentation](https://doc.rust-lang.org/clippy/) 2. [Clippy lints list](https://rust-lang.github.io/rust-clippy/master/index.html) 3. [rustfmt — GitHub](https://github.com/rust-lang/rustfmt) 4. [Rust Style Guide](https://doc.rust-lang.org/style-guide/) 5. [Cargo Book — The [lints] section](https://doc.rust-lang.org/cargo/reference/manifest.html#the-lints-section) 6. [rustfmt — Configuring Rustfmt](https://rust-lang.github.io/rustfmt/) 7. [Rust Blog — Announcing Rust 1.74.0 (lint configuration through Cargo)](https://blog.rust-lang.org/2023/11/16/Rust-1.74.0.html) --- # Сборка мусора vs ручное управление памятью > Сравнение способов освобождения памяти в языках программирования — ручное (C), RAII и умные указатели (C++), подсчёт ссылок (Python, Swift), трассирующая сборка мусора (Go, Java) и владение (Rust). Источник: https://llmdocs.ru/wiki/gc-vs-manual-memory/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Ручное управление**: C (malloc/free) - **RAII и умные указатели**: C++, Rust - **Подсчёт ссылок**: CPython, Swift (ARC), Rust (Rc, Arc) - **Трассирующая сборка мусора**: Go, Java, C#, JavaScript - **Владение и заимствование**: Rust (проверка при компиляции) - **Первая сборка мусора**: Lisp, Джон Маккарти (1959–1960) - **Цена ошибок**: около 70% уязвимостей в крупных кодовых базах на C и C++ связаны с памятью **Управление памятью** — способ, которым программа получает память для данных и возвращает её, когда данные больше не нужны. Языки решают эту задачу по-разному: в C программист освобождает память вручную, в [Go](https://llmdocs.ru/wiki/go.md), Java и [Python](https://llmdocs.ru/wiki/python.md) этим занимается **сборщик мусора**, а [Rust](https://llmdocs.ru/wiki/rust.md) проверяет правила владения при компиляции и освобождает память автоматически без сборщика. Выбор подхода определяет безопасность, производительность, предсказуемость задержек и удобство языка. ## Проблема Данные с неизвестным заранее временем жизни размещаются в **куче**. Их нужно освободить ровно один раз и ровно тогда, когда никто больше ими не пользуется. Ошибки приводят к тяжёлым последствиям: | Ошибка | Что происходит | |---|---| | Утечка памяти | память не освобождается, процесс постепенно разрастается | | Использование после освобождения (*use-after-free*) | чтение или запись в чужие данные, уязвимости | | Двойное освобождение | повреждение структур аллокатора | | Выход за границы буфера | перезапись соседних данных, классический способ взлома | По данным Microsoft и проекта Chromium, около 70% серьёзных уязвимостей в их кодовых базах на C и C++ связаны именно с безопасностью памяти.[4][5] Поэтому государственные агентства и крупные компании рекомендуют переходить на языки с безопасной памятью. ## Подходы ### Ручное управление В C память выделяют `malloc` и освобождают `free`. Это даёт полный контроль и предсказуемость, но вся ответственность лежит на программисте, и ошибки из таблицы выше неизбежны в больших программах. Инструменты — AddressSanitizer, Valgrind — помогают находить их при тестировании. ### RAII и умные указатели В C++ ресурс привязывается к времени жизни объекта (*Resource Acquisition Is Initialization*): деструктор освобождает память, закрывает файл или снимает блокировку при выходе из области видимости. Умные указатели `unique_ptr` (единственный владелец) и `shared_ptr` (подсчёт ссылок) избавляют от большинства ручных `delete`, но язык не запрещает небезопасные приёмы. ### Подсчёт ссылок У каждого объекта есть счётчик ссылок; когда он падает до нуля, объект немедленно освобождается. Так работает [CPython](https://llmdocs.ru/wiki/cpython.md), Swift (автоматический подсчёт ссылок, ARC) и типы `Rc`/`Arc` в Rust. Плюсы — предсказуемое освобождение без пауз. Минусы — накладные расходы на каждое присваивание и **циклические ссылки**: два объекта, ссылающиеся друг на друга, никогда не освободятся. CPython дополняет подсчёт ссылок циклическим сборщиком мусора.[3] ### Трассирующая сборка мусора Идею автоматической сборки мусора предложил Джон Маккарти для языка Lisp в 1959–1960 годах.[1] Сборщик периодически находит все объекты, достижимые от «корней» — глобальных переменных и стека, — а остальные считает мусором. Варианты:[6] - **Пометка и очистка** (*mark-sweep*) — пометить достижимое, освободить остальное. - **Поколенческая** сборка — большинство объектов умирает молодыми, поэтому молодое поколение проверяется часто, старое — редко (Java, .NET, V8). - **Конкурентная** сборка — основная работа выполняется параллельно с программой, паузы сокращаются до долей миллисекунды. Сборщик Go — конкурентный трёхцветный mark-sweep, настраиваемый параметрами `GOGC` и `GOMEMLIMIT`.[2] Плюсы — простота для программиста и безопасность: невозможно обратиться к освобождённой памяти. Минусы — дополнительная память (сборщику нужен запас), паузы и затраты процессора, менее предсказуемые задержки. Для большинства серверных приложений это приемлемо; для систем жёсткого реального времени, ядер ОС и игровых движков — часто нет. ### Владение и заимствование Rust применяет правила [владения](https://llmdocs.ru/wiki/ownership-borrowing.md) на этапе компиляции: у каждого значения один владелец, при выходе владельца из области видимости память освобождается (как RAII), а ссылки-заимствования не могут пережить данные, на которые указывают. Ошибки использования после освобождения и гонки данных отсекаются компилятором, а во время выполнения нет ни сборщика, ни накладных расходов. Цена — более сложное обучение и необходимость выражать структуры с общими ссылками через `Rc`, `Arc` и индексы. ## Сравнение | | Ручное (C) | RAII (C++) | Подсчёт ссылок | Трассирующий GC (Go, Java) | Владение (Rust) | |---|---|---|---|---|---| | Безопасность памяти | нет | частичная | да | да | да (вне `unsafe`) | | Паузы | нет | нет | нет (кроме сборки циклов) | короткие, но есть | нет | | Накладные расходы | минимальные | минимальные | на каждое присваивание | память и процессор сборщика | минимальные | | Сложность для программиста | высокая | средняя | низкая | низкая | средняя или высокая | | Утечки | возможны | возможны | при циклах | редки | возможны, но редки | ## Как выбирать - Сетевые сервисы, инструменты, бизнес-логика — языки со сборкой мусора (Go, Java, C#, Python) дают высокую продуктивность при достаточной скорости. - Системное программирование, встраиваемые системы, низкие и предсказуемые задержки, библиотеки для других языков — Rust, а в существующих кодовых базах — C и C++. - Утечки возможны в любом языке: кэш без ограничения размера или забытые подписки удерживают объекты и под сборщиком мусора. ## См. также - [Владение и заимствование (Rust)](https://llmdocs.ru/wiki/ownership-borrowing.md) - [Go vs Rust — сравнение](https://llmdocs.ru/wiki/go-vs-rust.md) - [Сборка мусора](https://llmdocs.ru/wiki/garbage-collection.md) - [CPython](https://llmdocs.ru/wiki/cpython.md) - [Unsafe Rust](https://llmdocs.ru/wiki/unsafe-rust.md) ## Источники 1. [J. McCarthy — Recursive Functions of Symbolic Expressions and Their Computation by Machine (CACM, 1960)](https://dl.acm.org/doi/10.1145/367177.367199) 2. [A Guide to the Go Garbage Collector](https://go.dev/doc/gc-guide) 3. [Python — gc: Garbage Collector interface](https://docs.python.org/3/library/gc.html) 4. [Microsoft Security Response Center — A proactive approach to more secure code (2019)](https://msrc.microsoft.com/blog/2019/07/a-proactive-approach-to-more-secure-code/) 5. [The Chromium Projects — Memory safety](https://www.chromium.org/Home/chromium-security/memory-safety/) 6. [R. Jones, A. Hosking, E. Moss — The Garbage Collection Handbook](https://gchandbook.org/) --- # Обработка ошибок в Go > В Go ошибки — обычные значения типа error, которые функции возвращают явно; вызывающий код проверяет их через if err != nil, оборачивает с контекстом и анализирует через errors.Is и errors.As. Источник: https://llmdocs.ru/wiki/go-errors/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Принцип**: ошибки — значения, возвращаемые явно - **Тип**: встроенный интерфейс error с методом Error() string - **Обёртывание**: fmt.Errorf с %w, errors.Is и errors.As (Go 1.13, 2019) - **Несколько ошибок**: errors.Join (Go 1.20) - **Исключительные ситуации**: panic и recover - **Синтаксический сахар**: предложения отклонены (2019, 2025) **Обработка ошибок в Go** построена не на исключениях, а на **явных возвращаемых значениях**. Функция, которая может завершиться неудачей, возвращает последним результатом значение встроенного типа `error`; вызывающий код обязан его проверить. Отсюда знаменитая конструкция `if err != nil`, которая встречается в Go-коде повсюду. Роб Пайк сформулировал философию так: «ошибки — это значения», и с ними можно программировать, как с любыми другими данными.[5] Подход делает пути ошибок видимыми в коде: читая функцию, сразу видно, где что-то может пойти не так и что тогда произойдёт. ## Тип error ```go type error interface { Error() string } ``` Любой тип с методом `Error() string` является ошибкой. Типичная функция возвращает результат и ошибку: ```go func ReadConfig(path string) (*Config, error) { data, err := os.ReadFile(path) if err != nil { return nil, fmt.Errorf("чтение конфигурации %s: %w", path, err) } var cfg Config if err := json.Unmarshal(data, &cfg); err != nil { return nil, fmt.Errorf("разбор конфигурации %s: %w", path, err) } return &cfg, nil } func main() { cfg, err := ReadConfig("app.json") if err != nil { log.Fatal(err) // чтение конфигурации app.json: open app.json: no such file or directory } _ = cfg } ``` По соглашению при ненулевой ошибке остальные возвращаемые значения не используются, а сообщения об ошибках пишут со строчной буквы и без точки в конце, потому что их часто вкладывают друг в друга.[4] ## Обёртывание и анализ Go 1.13 (2019) добавил стандартный механизм **обёртывания**: глагол `%w` в `fmt.Errorf` сохраняет исходную ошибку внутри новой, добавляя контекст. Функции пакета `errors` разворачивают цепочку:[2] ```go var ErrNotFound = errors.New("не найдено") // ошибка-маркер (sentinel) type ValidationError struct { // собственный тип ошибки с данными Field string } func (e *ValidationError) Error() string { return "некорректное поле " + e.Field } err := service.GetUser(ctx, id) switch { case errors.Is(err, ErrNotFound): // есть ли в цепочке конкретная ошибка http.Error(w, "нет такого пользователя", http.StatusNotFound) case errors.Is(err, context.DeadlineExceeded): http.Error(w, "таймаут", http.StatusGatewayTimeout) default: var ve *ValidationError if errors.As(err, &ve) { // есть ли ошибка нужного типа — и достать её http.Error(w, ve.Error(), http.StatusBadRequest) return } http.Error(w, "внутренняя ошибка", http.StatusInternalServerError) } ``` - **`errors.Is`** сравнивает с конкретным значением — для ошибок-маркеров вроде `io.EOF` или `sql.ErrNoRows`. - **`errors.As`** ищет ошибку определённого типа и даёт доступ к её полям. - **`errors.Join`** (Go 1.20) объединяет несколько ошибок в одну — например, при закрытии нескольких ресурсов.[3] Сравнивать ошибки по тексту сообщения (`err.Error() == "..."`) не следует — текст может измениться. ## panic и recover `panic` предназначен для действительно исключительных ситуаций — ошибок программиста и нарушенных инвариантов: выход за границы массива, разыменование `nil`, невозможное состояние. Паника раскручивает стек, выполняя отложенные (`defer`) вызовы, и завершает программу, если её не перехватить через `recover` в отложенной функции. HTTP-серверы перехватывают панику в обработчике, чтобы один сбойный запрос не уронил весь сервис. Для ожидаемых ситуаций — файла нет, сеть недоступна, данные некорректны — используют обычные ошибки, а не панику.[1] ## Критика и попытки упростить Главная претензия к подходу — многословие: в типичной функции значительная часть строк приходится на `if err != nil { return ..., err }`. Команда Go несколько раз предлагала сократить запись — встроенная функция `try` (2019), оператор `?` по образцу [Rust](https://llmdocs.ru/wiki/rust-errors.md), — но предложения не нашли поддержки сообщества. В 2025 году команда объявила, что больше не планирует менять синтаксис обработки ошибок, сосредоточившись на инструментах и библиотеках.[6] Сторонники подхода отмечают, что явность — достоинство: ошибка не может «пролететь» через несколько уровней незамеченной, как необработанное исключение, а контекст, добавляемый на каждом уровне, даёт понятные сообщения вроде «сохранение заказа 42: запись в базу: connection refused». ## Практические советы - **Добавляйте контекст** при передаче ошибки наверх: что делала функция и с какими данными. - **Обрабатывайте ошибку один раз**: либо залогируйте, либо верните наверх — не то и другое сразу, иначе одна ошибка появится в логах многократно. - **Не игнорируйте ошибки** через `_` без веской причины; линтеры (`errcheck`, `go vet` и сборки вроде golangci-lint) находят пропущенные проверки. - **Экспортируйте ошибки-маркеры и типы** в библиотеках, чтобы пользователи могли их различать, а внутренние детали оборачивайте. - Учитывайте ошибки отмены и таймаута контекста — в сетевом коде с [горутинами](https://llmdocs.ru/wiki/goroutines-channels.md) они встречаются постоянно. ## Сравнение с другими языками | Язык | Механизм | |---|---| | Go | значение `error`, явная проверка | | [Rust](https://llmdocs.ru/wiki/rust.md) | тип `Result`, компилятор требует обработать, оператор `?` для проброса | | [Python](https://llmdocs.ru/wiki/python.md), Java | исключения, `try`/`except` | | C | коды возврата и `errno` | ## См. также - [Go (язык)](https://llmdocs.ru/wiki/go.md) - [Обработка ошибок в Rust (Result, ?)](https://llmdocs.ru/wiki/rust-errors.md) - [Горутины и каналы](https://llmdocs.ru/wiki/goroutines-channels.md) - [Go-модули (go.mod)](https://llmdocs.ru/wiki/go-modules.md) - [Тестирование в Go](https://llmdocs.ru/wiki/go-testing.md) ## Источники 1. [The Go Blog — Error handling and Go](https://go.dev/blog/error-handling-and-go) 2. [The Go Blog — Working with Errors in Go 1.13](https://go.dev/blog/go1.13-errors) 3. [Go — package errors](https://pkg.go.dev/errors) 4. [Effective Go — Errors](https://go.dev/doc/effective_go#errors) 5. [Rob Pike — Errors are values (2015)](https://go.dev/blog/errors-are-values) 6. [The Go Blog — On | No syntactic support for error handling (2025)](https://go.dev/blog/error-syntax) --- # Дженерики в Go > Параметры типов в Go, появившиеся в версии 1.18 (2022), — обобщённые функции и типы с ограничениями через интерфейсы; пакеты slices и maps, итераторы и правила, когда дженерики не нужны. Источник: https://llmdocs.ru/wiki/go-generics/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Появились**: Go 1.18 (март 2022) - **Предложение**: Type Parameters Proposal (Иан Лэнс Тейлор, Роберт Гриземер) - **Синтаксис**: func Name[T Constraint](x T) - **Ограничения**: интерфейсы, в том числе наборы типов (~int | ~float64) - **Встроенные ограничения**: any, comparable - **Стандартные пакеты**: slices, maps, cmp, iter **Дженерики в Go** (параметры типов, англ. *type parameters*) — возможность писать функции и типы, которые работают с разными типами данных, сохраняя статическую проверку. Они появились в [Go](https://llmdocs.ru/wiki/go.md) 1.18 в марте 2022 года — после более чем десяти лет обсуждений и нескольких отвергнутых проектов — и стали самым крупным изменением языка с версии 1.0.[1][3] ## Зачем До дженериков обобщённый код в Go писали тремя способами, у каждого из которых есть недостатки: - **копированием** — `SumInts`, `SumFloats`, `SumInt64s`; - через **пустой интерфейс** `interface{}` — с потерей проверки типов и приведением в рантайме; - **генерацией кода** (`go generate`). С параметрами типов одна функция подходит для всех нужных типов, а ошибки ловит компилятор. ## Синтаксис Параметры типов объявляются в квадратных скобках перед обычными параметрами. Каждый параметр имеет **ограничение** (*constraint*) — интерфейс, описывающий допустимые типы:[2] ```go func Map[T, U any](s []T, f func(T) U) []U { out := make([]U, 0, len(s)) for _, v := range s { out = append(out, f(v)) } return out } lengths := Map([]string{"go", "rust"}, func(s string) int { return len(s) }) // [2 4] — T и U выведены компилятором ``` В большинстве вызовов аргументы типов **выводятся** автоматически; явно их пишут, когда вывести нельзя: `Map[string, int](...)`. ## Ограничения и наборы типов Интерфейс в Go 1.18 стал описывать не только набор методов, но и **набор типов**:[5] ```go type Number interface { ~int | ~int32 | ~int64 | ~float32 | ~float64 } func Sum[T Number](xs []T) T { var total T for _, x := range xs { total += x } return total } ``` - `|` перечисляет допустимые типы; - `~int` означает «любой тип, чьё базовое представление — `int`», включая пользовательские вроде `type UserID int`; - `any` — синоним `interface{}`, любой тип; - `comparable` — типы, поддерживающие `==` и `!=`; нужен для ключей `map`; - пакет `cmp` предоставляет `cmp.Ordered` — типы с операторами `<`, `>`. Интерфейсы с наборами типов можно использовать только как ограничения, но не как обычный тип переменной. ## Обобщённые типы ```go type Stack[T any] struct { items []T } func (s *Stack[T]) Push(v T) { s.items = append(s.items, v) } func (s *Stack[T]) Pop() (T, bool) { var zero T if len(s.items) == 0 { return zero, false } v := s.items[len(s.items)-1] s.items = s.items[:len(s.items)-1] return v, true } var st Stack[string] st.Push("a") ``` Ограничение языка: **методы не могут иметь собственных параметров типов** — только использовать параметры своего типа. Поэтому цепочки вида `stream.Map(...).Filter(...)` с меняющимся типом в Go пишут обычными функциями. ## Стандартная библиотека Дженерики позволили добавить в [стандартную библиотеку](https://llmdocs.ru/wiki/go-stdlib.md) типобезопасные утилиты:[7] ```go import ("slices"; "maps") xs := []int{3, 1, 2} slices.Sort(xs) // [1 2 3] i, found := slices.BinarySearch(xs, 2) slices.Contains(xs, 5) // false keys := slices.Sorted(maps.Keys(m)) // отсортированные ключи map ``` В Go 1.23 появились **итераторы** — функции вида `iter.Seq[T]`, по которым можно проходить обычным `for range`; они тоже обобщённые.[6] `sync.Map` и `atomic.Pointer[T]` — другие примеры обобщённых типов в библиотеке. ## Реализация Компилятор Go использует компромисс между полной мономорфизацией (как в Rust и C++, где для каждого типа генерируется отдельная копия кода) и упаковкой в интерфейсы (как в Java): функции компилируются по одной копии на **«форму»** типа (GC shape) — например, одна копия на все указатели — с передачей словаря с информацией о типе. Это ускоряет компиляцию и уменьшает размер бинарника, но обобщённый код иногда работает чуть медленнее, чем написанный вручную для конкретного типа. В Rust ту же задачу решают [трейты](https://llmdocs.ru/wiki/rust-traits.md) с мономорфизацией. ## Когда использовать Авторы Go советуют не превращать дженерики в инструмент по умолчанию:[4] - **Использовать** — для функций над срезами, map и каналами любого типа элемента; для обобщённых структур данных (стеки, очереди, деревья, кэши); когда иначе пришлось бы копировать одну и ту же реализацию. - **Не использовать** — если достаточно обычного интерфейса с методами (`io.Reader` лучше, чем `[T io.Reader]`); если реализация различается для разных типов; если код становится сложнее читать. Правило из блога Go: начинайте писать код без параметров типов и добавляйте их, когда обнаружите, что пишете одно и то же несколько раз. ## См. также - [Go (язык)](https://llmdocs.ru/wiki/go.md) - [Стандартная библиотека Go](https://llmdocs.ru/wiki/go-stdlib.md) - [Типизация в Python (type hints, PEP 484)](https://llmdocs.ru/wiki/type-hints.md) - [Go vs Rust — сравнение](https://llmdocs.ru/wiki/go-vs-rust.md) ## Источники 1. [Go — Type Parameters Proposal](https://go.googlesource.com/proposal/+/refs/heads/master/design/43651-type-parameters.md) 2. [Go Tutorial — Getting started with generics](https://go.dev/doc/tutorial/generics) 3. [Go Blog — An Introduction To Generics](https://go.dev/blog/intro-generics) 4. [Go Blog — When To Use Generics](https://go.dev/blog/when-generics) 5. [The Go Programming Language Specification — Type parameter declarations](https://go.dev/ref/spec#Type_parameter_declarations) 6. [Go Blog — Range Over Function Types](https://go.dev/blog/range-functions) 7. [Go — package slices](https://pkg.go.dev/slices) --- # Go-модули (go.mod) > Система управления зависимостями и версиями в Go — файлы go.mod и go.sum, семантическое версионирование импортов, минимальный выбор версий и прокси модулей. Источник: https://llmdocs.ru/wiki/go-modules/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Появились**: Go 1.11 (август 2018) - **По умолчанию**: с Go 1.16 (2021) - **Заменили**: GOPATH и сторонние менеджеры (dep, glide) - **Файлы**: go.mod (зависимости), go.sum (контрольные суммы) - **Алгоритм версий**: минимальный выбор версий (MVS), Расс Кокс - **Инфраструктура**: proxy.golang.org, sum.golang.org - **Рабочие пространства**: go.work (Go 1.18) **Go-модули** — встроенная в [Go](https://llmdocs.ru/wiki/go.md) система управления зависимостями. **Модуль** — набор пакетов, версионируемых вместе; его корень отмечает файл `go.mod`, где записаны путь модуля, требуемая версия Go и зависимости с точными версиями. Файл `go.sum` хранит криптографические контрольные суммы всех загруженных модулей, гарантируя, что сборка использует ровно тот же код, что и у автора.[1] Модули сделали сборку Go-программ воспроизводимой и избавили от требования держать весь код в одном каталоге GOPATH. ## История До 2018 года весь Go-код должен был лежать в каталоге `$GOPATH/src`, а команда `go get` всегда брала последнюю версию зависимости из основной ветки репозитория. Версий как таковых не было, и сообщество создавало сторонние инструменты — godep, glide, dep. В 2018 году Расс Кокс из команды Go предложил собственное решение (проект vgo), которое вошло в Go 1.11 как экспериментальная функция, а с Go 1.16 (2021) стало режимом по умолчанию.[4] ## go.mod ```bash mkdir hello && cd hello go mod init github.com/alice/hello # создать модуль go get github.com/go-chi/chi/v5@v5.2.1 # добавить зависимость go mod tidy # добавить недостающие и убрать лишние go build ./... # собрать все пакеты модуля ``` ```go // go.mod module github.com/alice/hello go 1.25 require ( github.com/go-chi/chi/v5 v5.2.1 golang.org/x/sync v0.16.0 ) require golang.org/x/text v0.27.0 // indirect ``` - **`module`** — путь модуля, обычно совпадающий с адресом репозитория; с него начинаются пути импорта пакетов. - **`go`** — минимальная версия языка. С Go 1.21 директива `toolchain` позволяет автоматически скачать нужную версию компилятора.[6] - **`require`** — зависимости; пометка `// indirect` означает, что пакет нужен не напрямую, а зависимостям. - **`replace`** — подменить модуль локальной копией или форком, **`exclude`** — запретить версию, **`retract`** — автор отзывает свои ошибочные версии. ## Версии Модули используют [семантическое версионирование](https://llmdocs.ru/wiki/semver.md) в виде тегов Git: `v1.4.2`. Особенность Go — **семантическое версионирование импортов**: начиная с v2 мажорная версия становится частью пути модуля (`github.com/go-chi/chi/v5`). Версии с несовместимыми API считаются разными модулями и могут сосуществовать в одной программе. Если тегов нет, используется **псевдоверсия** вида `v0.0.0-20251101120000-abcdef123456` — время и хеш коммита. ## Минимальный выбор версий Большинство менеджеров пакетов при установке выбирают *самую новую* допустимую версию зависимости, и результат зависит от момента сборки. Go использует **минимальный выбор версий** (MVS): из всех требований в графе зависимостей берётся *наименьшая* версия, удовлетворяющая каждому, то есть максимальная из явно запрошенных минимумов.[3] Сборка детерминирована без отдельного lock-файла: версии меняются только тогда, когда кто-то явно обновил `go.mod`. Обновление — осознанное действие: ```bash go list -m -u all # какие обновления доступны go get -u ./... # обновить зависимости до новых минорных версий go get example.com/lib@v1.8.0 ``` ## Прокси и база контрольных сумм По умолчанию модули скачиваются через публичное зеркало **proxy.golang.org**, а их хеши сверяются с открытой проверяемой базой **sum.golang.org**.[5] Зеркало ускоряет загрузку и сохраняет модули даже после удаления исходного репозитория, а база контрольных сумм защищает от подмены версии. Для приватного кода переменная `GOPRIVATE=github.com/mycompany/*` отключает прокси и проверку для этих путей; компании разворачивают собственные прокси (Athens, Artifactory). ## Рабочие пространства и вендоринг - **`go work`** (Go 1.18) объединяет несколько локальных модулей в рабочее пространство, чтобы разрабатывать их одновременно без директив `replace` в `go.mod`. - **`go mod vendor`** копирует все зависимости в каталог `vendor/` — для сборок без доступа к сети и аудита кода. - **`go mod why` и `go mod graph`** объясняют, зачем нужна зависимость и как устроен граф. ## Практика - Коммитьте и `go.mod`, и `go.sum`. - Запускайте `go mod tidy` перед коммитом и проверяйте в [CI/CD](https://llmdocs.ru/wiki/ci-cd.md), что он ничего не меняет. - Ведите список уязвимостей командой `govulncheck ./...` — она проверяет, вызывает ли ваш код уязвимые функции зависимостей. - Помните о стабильности: публичная библиотека с версией v1 и выше обещает не ломать API без смены мажорной версии и пути модуля. Подробное руководство по управлению зависимостями — в документации Go.[2] ## См. также - [Go (язык)](https://llmdocs.ru/wiki/go.md) - [Семантическое версионирование](https://llmdocs.ru/wiki/semver.md) - [Cargo и crates.io](https://llmdocs.ru/wiki/cargo.md) - [Обработка ошибок в Go](https://llmdocs.ru/wiki/go-errors.md) - [uv (менеджер пакетов)](https://llmdocs.ru/wiki/uv.md) ## Источники 1. [Go Modules Reference](https://go.dev/ref/mod) 2. [Go — Managing dependencies](https://go.dev/doc/modules/managing-dependencies) 3. [Russ Cox — Minimal Version Selection (2018)](https://research.swtch.com/vgo-mvs) 4. [The Go Blog — Using Go Modules](https://go.dev/blog/using-go-modules) 5. [Go module mirror and checksum database](https://proxy.golang.org/) 6. [Go — Toolchains](https://go.dev/doc/toolchain) --- # Стандартная библиотека Go > Набор пакетов, поставляемых с Go, — HTTP-сервер и клиент, JSON, криптография, конкурентность, тестирование, логирование; на нём без внешних зависимостей пишут полноценные сетевые сервисы. Источник: https://llmdocs.ru/wiki/go-stdlib/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Язык**: Go - **Документация**: pkg.go.dev/std - **Совместимость**: обещание Go 1 (с 2012 года) - **Ключевые пакеты**: net/http, encoding/json, context, io, os, sync, time, crypto - **Дополнительные пакеты**: golang.org/x/... (вне гарантий Go 1) - **Особенность**: сетевой сервер без сторонних зависимостей **Стандартная библиотека Go** — набор из более чем 150 пакетов, поставляемых вместе с компилятором [Go](https://llmdocs.ru/wiki/go.md). Она известна тем, что покрывает почти всё необходимое для сетевых сервисов и утилит командной строки: HTTP-сервер и клиент, [TLS](https://llmdocs.ru/wiki/tls.md), [JSON](https://llmdocs.ru/wiki/json.md), криптографию, работу с файлами, конкурентность, тестирование и профилирование. Многие Go-проекты обходятся вообще без внешних зависимостей или с минимумом их.[1] ## Принципы - **Обещание совместимости Go 1** (2012): код, написанный для Go 1.x, продолжает компилироваться и работать на всех следующих версиях 1.y.[2] Поэтому API стандартной библиотеки меняется осторожно: новые возможности добавляются, старые почти не удаляются. - **Небольшие интерфейсы**: `io.Reader` и `io.Writer` с одним методом связывают файлы, сетевые соединения, сжатие, шифрование и буферы в цепочки. - **Пакеты `golang.org/x/...`** — экспериментальные или узкоспециальные расширения (`x/crypto`, `x/net`, `x/sync`, `x/tools`) вне гарантий совместимости; удачные идеи потом переходят в стандартную библиотеку. ## Обзор пакетов | Область | Пакеты | |---|---| | Ввод-вывод | `io`, `bufio`, `os`, `io/fs`, `path/filepath`, `embed` | | Строки и текст | `strings`, `strconv`, `bytes`, `unicode/utf8`, `regexp`, `text/template`, `html/template` | | Сеть | `net`, `net/http`, `net/url`, `net/netip`, `crypto/tls` | | Форматы | `encoding/json`, `encoding/csv`, `encoding/xml`, `encoding/base64`, `archive/zip`, `compress/gzip` | | Конкурентность | `sync`, `sync/atomic`, `context`, `time` | | Криптография | `crypto/sha256`, `crypto/rand`, `crypto/aes`, `crypto/ed25519`, `crypto/mlkem` | | Коллекции | `slices`, `maps`, `sort`, `container/heap`, `iter` | | Данные | `database/sql` (общий интерфейс к драйверам) | | Диагностика | `log`, `log/slog`, `runtime/pprof`, `net/http/pprof`, `expvar` | | Тесты | `testing`, `net/http/httptest`, `testing/fstest` | | CLI | `flag`, `os/exec`, `os/signal` | Пакеты `slices` и `maps` появились в Go 1.21 благодаря [дженерикам](https://llmdocs.ru/wiki/go-generics.md), а `iter` — в Go 1.23 вместе с итераторами по функциям. ## HTTP-сервер Пакет `net/http` даёт готовый к продакшену сервер с поддержкой HTTP/1.1, [HTTP/2](https://llmdocs.ru/wiki/http2-http3.md) и TLS.[3] С Go 1.22 встроенный маршрутизатор `ServeMux` понимает методы и параметры пути, что для многих сервисов сделало сторонние роутеры необязательными:[4] ```go package main import ( "encoding/json" "log/slog" "net/http" "time" ) type Item struct { ID string `json:"id"` Name string `json:"name"` } func main() { mux := http.NewServeMux() mux.HandleFunc("GET /items/{id}", func(w http.ResponseWriter, r *http.Request) { item := Item{ID: r.PathValue("id"), Name: "пример"} w.Header().Set("Content-Type", "application/json") json.NewEncoder(w).Encode(item) }) srv := &http.Server{ Addr: ":8080", Handler: mux, ReadHeaderTimeout: 5 * time.Second, } slog.Info("listening", "addr", srv.Addr) if err := srv.ListenAndServe(); err != nil { slog.Error("server stopped", "err", err) } } ``` Каждый запрос обрабатывается в отдельной [горутине](https://llmdocs.ru/wiki/goroutines-channels.md). Тайм-ауты стоит задавать явно: у `http.Server` и `http.Client` по умолчанию их нет. ## context Пакет `context` передаёт по цепочке вызовов сроки выполнения, отмену и значения уровня запроса.[6] Первым аргументом функции, которая может долго работать, принято передавать `ctx context.Context`: ```go ctx, cancel := context.WithTimeout(r.Context(), 2*time.Second) defer cancel() req, _ := http.NewRequestWithContext(ctx, "GET", "https://api.example.com", nil) resp, err := http.DefaultClient.Do(req) ``` Если клиент закрыл соединение или истёк тайм-аут, отмена распространяется на запросы к базе и внешним API. ## JSON `encoding/json` преобразует структуры в JSON и обратно с помощью тегов полей (`json:"name,omitempty"`).[7] Пакет работает через рефлексию и не самый быстрый, поэтому для высоконагруженных сервисов существуют сторонние альтернативы; в Go 1.25 появился экспериментальный `encoding/json/v2`. Ошибки разбора возвращаются как обычные значения (см. [Обработка ошибок в Go](https://llmdocs.ru/wiki/go-errors.md)). ## Логирование: slog С Go 1.21 есть пакет `log/slog` для структурированных логов с уровнями и обработчиками текстового и JSON-формата — его удобно отправлять в системы сбора логов (см. [Логирование и трассировка (OpenTelemetry)](https://llmdocs.ru/wiki/opentelemetry.md)).[5] ```go logger := slog.New(slog.NewJSONHandler(os.Stdout, nil)) logger.Info("order created", "order_id", 42, "user", "ivan") // {"time":"...","level":"INFO","msg":"order created","order_id":42,"user":"ivan"} ``` ## Тестирование и профилирование Пакет `testing` вместе с командой `go test` поддерживает модульные тесты, табличные тесты, бенчмарки, фаззинг (с Go 1.18) и примеры, которые проверяются и попадают в документацию; `httptest` позволяет тестировать HTTP-обработчики без сети (см. [Тестирование в Go](https://llmdocs.ru/wiki/go-testing.md)). Профилировщик `pprof` показывает, где программа тратит процессор и память, а детектор гонок `-race` находит [гонки данных](https://llmdocs.ru/wiki/race-conditions-locks.md). ## Чего нет В стандартной библиотеке нет драйверов конкретных СУБД (только интерфейс `database/sql`, драйверы вроде pgx для [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) ставятся отдельно), ORM, GUI, полноценного веб-фреймворка, а также YAML и gRPC. Их подключают как [модули](https://llmdocs.ru/wiki/go-modules.md). ## См. также - [Go (язык)](https://llmdocs.ru/wiki/go.md) - [Горутины и каналы](https://llmdocs.ru/wiki/goroutines-channels.md) - [Обработка ошибок в Go](https://llmdocs.ru/wiki/go-errors.md) - [Go-модули (go.mod)](https://llmdocs.ru/wiki/go-modules.md) ## Источники 1. [Go — Standard library (pkg.go.dev)](https://pkg.go.dev/std) 2. [Go 1 and the Future of Go Programs (compatibility promise)](https://go.dev/doc/go1compat) 3. [Go — package net/http](https://pkg.go.dev/net/http) 4. [Go Blog — Routing Enhancements for Go 1.22](https://go.dev/blog/routing-enhancements) 5. [Go Blog — Structured Logging with slog](https://go.dev/blog/slog) 6. [Go Blog — Go Concurrency Patterns: Context](https://go.dev/blog/context) 7. [Go — package encoding/json](https://pkg.go.dev/encoding/json) --- # Тестирование в Go > Встроенная система тестирования Go — пакет testing и команда go test — с табличными тестами, подтестами, бенчмарками, фаззингом, покрытием и детектором гонок без сторонних фреймворков. Источник: https://llmdocs.ru/wiki/go-testing/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Язык**: Go - **Инструменты**: пакет testing, команда go test - **Файлы тестов**: *_test.go - **Виды**: тесты (TestXxx), бенчмарки (BenchmarkXxx), фаззинг (FuzzXxx), примеры (ExampleXxx) - **Покрытие**: go test -cover, -coverprofile - **Гонки**: go test -race **Тестирование в Go** встроено в сам инструментарий языка: пакет `testing` из [стандартной библиотеки](https://llmdocs.ru/wiki/go-stdlib.md) и команда `go test` поддерживают модульные тесты, бенчмарки, фаззинг, проверяемые примеры, покрытие кода и поиск гонок данных. В отличие от многих языков, для этого не нужен сторонний фреймворк — хотя библиотеки-помощники вроде testify популярны.[1][2] ## Основы Тесты лежат рядом с кодом в файлах с суффиксом `_test.go` и не попадают в итоговый бинарник. Тестовая функция называется `TestXxx` и принимает `*testing.T`: ```go // mathx/abs.go package mathx func Abs(x int) int { if x < 0 { return -x } return x } ``` ```go // mathx/abs_test.go package mathx import "testing" func TestAbs(t *testing.T) { if got := Abs(-3); got != 3 { t.Errorf("Abs(-3) = %d, want 3", got) } } ``` ```bash go test ./... # все пакеты модуля go test -run TestAbs -v ./mathx go test -count=1 ./... # без кэша результатов ``` `t.Errorf` отмечает ошибку и продолжает выполнение, `t.Fatalf` — останавливает тест. Встроенных функций-«ассертов» нет намеренно: проверки пишутся обычным `if`, а сообщение принято строить в форме «got X, want Y». ## Табличные тесты и подтесты Идиоматический стиль Go — **табличные тесты**: набор случаев описывается срезом структур, а одна петля их проверяет.[3] Каждый случай запускается как **подтест** через `t.Run`, что даёт отдельное имя, возможность запустить один случай и параллельность:[5] ```go func TestAbsTable(t *testing.T) { tests := []struct { name string in int want int }{ {"positive", 5, 5}, {"negative", -5, 5}, {"zero", 0, 0}, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { t.Parallel() if got := Abs(tt.in); got != tt.want { t.Errorf("Abs(%d) = %d, want %d", tt.in, got, tt.want) } }) } } ``` `go test -run 'TestAbsTable/negative'` запустит только один случай. С Go 1.22 переменная цикла создаётся заново на каждой итерации, поэтому старый приём `tt := tt` больше не нужен. ## Полезные возможности testing.T - `t.Helper()` — помечает вспомогательную функцию, чтобы ошибка указывала на строку вызывающего теста; - `t.Cleanup(func(){...})` — освобождение ресурсов после теста; - `t.TempDir()` — временный каталог, удаляемый автоматически; - `t.Setenv("KEY", "v")` — временная [переменная окружения](https://llmdocs.ru/wiki/environment-variables.md); - `t.Skip()` и флаг `-short` — пропуск медленных тестов; - `TestMain(m *testing.M)` — общая подготовка и завершение для пакета. ## Бенчмарки Функции `BenchmarkXxx(b *testing.B)` измеряют производительность. С Go 1.24 рекомендуемая форма — цикл `b.Loop()`, который сам управляет числом итераций и не даёт компилятору выбросить измеряемый код:[7] ```go func BenchmarkAbs(b *testing.B) { for b.Loop() { Abs(-42) } } ``` ```bash go test -bench=. -benchmem ./mathx ``` Для сравнения результатов до и после изменения используют утилиту `benchstat`, которая учитывает статистический разброс; профили для `pprof` получают флагами `-cpuprofile` и `-memprofile`. ## Фаззинг С Go 1.18 фаззинг встроен в `go test`.[4] Фазз-тест получает случайно мутируемые входные данные и ищет паники или нарушения свойств; найденные «падающие» входы сохраняются в `testdata/fuzz` и становятся регрессионными тестами: ```go func FuzzReverse(f *testing.F) { f.Add("hello") f.Fuzz(func(t *testing.T, s string) { if Reverse(Reverse(s)) != s { t.Errorf("double reverse mismatch for %q", s) } }) } ``` ```bash go test -fuzz=FuzzReverse -fuzztime=30s ``` ## Примеры Функции `ExampleXxx` с комментарием `// Output:` одновременно служат документацией на pkg.go.dev и тестом: `go test` сравнивает вывод с ожидаемым. ## HTTP и внешние зависимости Пакет `net/http/httptest` позволяет тестировать обработчики без сети — через `httptest.NewRecorder` — или поднять настоящий тестовый сервер на случайном порту через `httptest.NewServer`.[6] Зависимости от баз и внешних API в Go обычно заменяют через небольшие интерфейсы и собственные фейковые реализации; для интеграционных тестов с настоящей [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) популярен testcontainers-go, поднимающий контейнеры [Docker](https://llmdocs.ru/wiki/docker.md). ## Покрытие и гонки ```bash go test -cover ./... go test -coverprofile=cover.out ./... && go tool cover -html=cover.out go test -race ./... ``` Флаг `-race` включает детектор гонок данных, который находит одновременный доступ к памяти из разных [горутин](https://llmdocs.ru/wiki/goroutines-channels.md) без синхронизации (см. [Состояние гонки и блокировки](https://llmdocs.ru/wiki/race-conditions-locks.md)). В [CI/CD](https://llmdocs.ru/wiki/ci-cd.md) тесты обычно запускают с `-race` вместе с [go vet](https://llmdocs.ru/wiki/gofmt-govet.md) — последний и так частично выполняется при `go test`. ## Библиотеки Стандартных средств хватает большинству проектов, но популярны: **testify** (`assert`, `require`, моки), **go-cmp** (`cmp.Diff` для наглядного сравнения структур), **gomock** и **mockery** (генерация моков), **Ginkgo/Gomega** (BDD-стиль). В Python похожую роль играет [pytest](https://llmdocs.ru/wiki/pytest.md). ## См. также - [Go (язык)](https://llmdocs.ru/wiki/go.md) - [gofmt и go vet](https://llmdocs.ru/wiki/gofmt-govet.md) - [pytest](https://llmdocs.ru/wiki/pytest.md) - [CI/CD](https://llmdocs.ru/wiki/ci-cd.md) ## Источники 1. [Go — package testing](https://pkg.go.dev/testing) 2. [Go — Command go: Test packages](https://pkg.go.dev/cmd/go#hdr-Test_packages) 3. [Go Wiki — TableDrivenTests](https://go.dev/wiki/TableDrivenTests) 4. [Go — Tutorial: Getting started with fuzzing](https://go.dev/doc/tutorial/fuzz) 5. [Go Blog — Using Subtests and Sub-benchmarks](https://go.dev/blog/subtests) 6. [Go — package net/http/httptest](https://pkg.go.dev/net/http/httptest) 7. [Go Blog — More predictable benchmarking with testing.B.Loop](https://go.dev/blog/testing-b-loop) --- # Go vs Rust — сравнение > Сравнение двух популярных компилируемых языков для системного и серверного ПО — Go с простотой, сборщиком мусора и горутинами против Rust с владением, нулевой стоимостью абстракций и гарантиями безопасности памяти без GC. Источник: https://llmdocs.ru/wiki/go-vs-rust/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Go**: Google, 2009; GC, горутины, простота - **Rust**: Mozilla, 2010 (1.0 — 2015); владение, без GC, безопасность памяти - **Общее**: компиляция в машинный код, статическая типизация, единый тулчейн - **Go силён в**: сетевых сервисах, облачной инфраструктуре, CLI - **Rust силён в**: системном ПО, производительности, встраиваемых системах, WebAssembly **Go и Rust** — два компилируемых языка со статической типизацией, которые часто сравнивают как современные альтернативы C, C++ и Java для серверного и системного программирования. Оба появились в 2009–2010 годах, оба компилируются в машинный код и поставляются с единым набором инструментов. Но их философии противоположны: [Go](https://llmdocs.ru/wiki/go.md) оптимизирован под **простоту и скорость разработки** командами, [Rust](https://llmdocs.ru/wiki/rust.md) — под **контроль, производительность и гарантии корректности** на этапе компиляции.[1][2] ## Происхождение **Go** создали в Google Роберт Гриземер, Роб Пайк и Кен Томпсон (анонс в 2009, версия 1.0 в 2012). Цель — язык для больших кодовых баз и многоядерных серверов, быстро компилирующийся и легко читаемый новыми сотрудниками. **Rust** начал как личный проект Грейдона Хоара в Mozilla (2006), был официально поддержан в 2009–2010, версия 1.0 вышла в 2015 году. Цель — безопасная замена C++ для браузерного движка, без сборщика мусора и без ошибок памяти. С 2021 года Rust развивает независимый Rust Foundation. ## Ключевые различия | | Go | Rust | |---|---|---| | Управление памятью | сборщик мусора | [владение и заимствование](https://llmdocs.ru/wiki/ownership-borrowing.md), без GC | | Безопасность памяти | да (кроме гонок данных) | да, включая гонки данных; исключения — [unsafe](https://llmdocs.ru/wiki/unsafe-rust.md) | | Конкурентность | [горутины и каналы](https://llmdocs.ru/wiki/goroutines-channels.md) в рантайме | потоки, [async/await](https://llmdocs.ru/wiki/rust-async-tokio.md) с внешним рантаймом | | Обработка ошибок | значения `error`, `if err != nil` | тип `Result` и оператор `?` | | Обобщения | [дженерики](https://llmdocs.ru/wiki/go-generics.md) с 1.18, ограниченные | [трейты](https://llmdocs.ru/wiki/rust-traits.md) и дженерики, мономорфизация | | Метапрограммирование | генерация кода | [макросы](https://llmdocs.ru/wiki/rust-macros.md) | | Null | `nil` | нет; вместо него `Option` | | Скорость компиляции | очень быстрая | медленная | | Порог входа | низкий, язык осваивается за недели | высокий, «борьба с borrow checker» | | Размер языка | ~25 ключевых слов, намеренно мал | большой, выразительный | ## Производительность Оба языка намного быстрее интерпретируемых. Rust обычно быстрее Go и сопоставим с C/C++: отсутствие GC, абстракции нулевой стоимости, агрессивные оптимизации LLVM, контроль над размещением данных в памяти. В синтетических тестах вроде Benchmarks Game Rust часто оказывается в 1,5–3 раза быстрее Go и потребляет меньше памяти.[7] Для типичного сетевого сервиса разница часто несущественна: узкое место — база данных и сеть. Но заметна разница в **предсказуемости задержек**. Сборщик мусора Go конкурентный и делает паузы субмиллисекундными,[5] однако под большой нагрузкой с огромной кучей GC даёт периодические всплески задержки и расход процессора. Известный пример — Discord переписал сервис состояний прочтения с Go на Rust, избавившись от пиков задержки каждые две минуты.[4] Подробнее о компромиссах — в статье [Сборка мусора vs ручное управление памятью](https://llmdocs.ru/wiki/gc-vs-manual-memory.md). ## Безопасность Оба языка устраняют целый класс уязвимостей C/C++ — переполнения буфера, использование после освобождения. Rust идёт дальше: компилятор гарантирует отсутствие гонок данных и неинициализированной памяти. Google сообщал, что по мере роста доли кода на Rust и других безопасных языках в Android доля уязвимостей, связанных с памятью, упала с 76 % в 2019 году до 35 % в 2022-м.[6] В Go гонки данных возможны, их находит детектор `-race` (см. [Состояние гонки и блокировки](https://llmdocs.ru/wiki/race-conditions-locks.md)). ## Продуктивность и сопровождение Go выигрывает в скорости разработки: короткий цикл «правка — сборка — запуск», одна идиоматическая манера писать код ([gofmt](https://llmdocs.ru/wiki/gofmt-govet.md)), богатая [стандартная библиотека](https://llmdocs.ru/wiki/go-stdlib.md), простой код легко читать в ревью. Минус — многословность (`if err != nil`), меньше выразительных средств для моделирования предметной области. Rust требует больше времени на изучение и написание, зато компилятор ловит больше ошибок до запуска: «если скомпилировалось — скорее всего работает». Система типов позволяет выразить инварианты (перечисления с данными, исчерпывающий `match`, типы-состояния), а Clippy подсказывает идиомы (см. [Clippy и rustfmt](https://llmdocs.ru/wiki/clippy-rustfmt.md)). В опросах Stack Overflow Rust много лет подряд — самый «любимый» (admired) язык.[3] ## Экосистема и применения **Go** — язык облачной инфраструктуры: на нём написаны [Docker](https://llmdocs.ru/wiki/docker.md), [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md), [Terraform](https://llmdocs.ru/wiki/terraform-opentofu.md), [Prometheus](https://llmdocs.ru/wiki/prometheus.md), etcd, [Caddy](https://llmdocs.ru/wiki/caddy.md), Hugo, большинство CLI-утилит экосистемы CNCF. Типичные применения — микросервисы, API, прокси, DevOps-инструменты. **Rust** используется там, где важны производительность и надёжность: части ядра Linux и Windows, Android, Firefox, сетевые прокси (Cloudflare Pingora), базы данных и движки хранения, [WebAssembly](https://llmdocs.ru/wiki/webassembly.md), встраиваемые системы. Rust популярен и как «ускоритель» для экосистемы Python: [uv](https://llmdocs.ru/wiki/uv.md), [Ruff](https://llmdocs.ru/wiki/ruff.md), Polars, Pydantic-core написаны на нём. ## Как выбирать - **Go**, если нужен сетевой сервис или инструмент, команда большая или меняется, важны скорость разработки и простота сопровождения, допустим GC. - **Rust**, если критичны задержки и потребление памяти, нужен контроль над ресурсами, код работает близко к железу, в браузере через WebAssembly, встраивается в другие языки или его безопасность особенно важна. - Оба языка хорошо сосуществуют: нередко сервисы пишут на Go, а «горячие» компоненты — на Rust. ## См. также - [Go (язык)](https://llmdocs.ru/wiki/go.md) - [Rust (язык)](https://llmdocs.ru/wiki/rust.md) - [Сборка мусора vs ручное управление памятью](https://llmdocs.ru/wiki/gc-vs-manual-memory.md) - [Компилятор и интерпретатор](https://llmdocs.ru/wiki/compiler-interpreter.md) ## Источники 1. [Go — Frequently Asked Questions](https://go.dev/doc/faq) 2. [The Rust Programming Language (book)](https://doc.rust-lang.org/book/) 3. [Stack Overflow Developer Survey 2025](https://survey.stackoverflow.co/2025/) 4. [Discord Blog — Why Discord is switching from Go to Rust](https://discord.com/blog/why-discord-is-switching-from-go-to-rust) 5. [Go — A Guide to the Go Garbage Collector](https://go.dev/doc/gc-guide) 6. [Google Security Blog — Memory Safe Languages in Android 13](https://security.googleblog.com/2022/12/memory-safe-languages-in-android-13.html) 7. [The Computer Language Benchmarks Game](https://benchmarksgame-team.pages.debian.net/benchmarksgame/) --- # Go (язык) > Компилируемый язык программирования от Google со сборкой мусора, встроенной конкурентностью и минималистичным синтаксисом. Источник: https://llmdocs.ru/wiki/go/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Класс языка**: императивный, конкурентный, со статической типизацией - **Появился в**: 2009 - **Авторы**: Роберт Гризмер, Роб Пайк, Кен Томпсон - **Разработчик**: Google - **Выпуск версий**: дважды в год (февраль и август) - **Типизация**: статическая, строгая, структурная для интерфейсов - **Управление памятью**: сборка мусора - **Расширение файлов**: `.go` - **Лицензия**: BSD-3-Clause - **Сайт**: [go.dev](https://go.dev/) **Go** (часто **Golang** — по старому домену golang.org) — компилируемый язык программирования со статической типизацией и сборкой мусора, созданный в Google. Он задуман как простой язык для больших команд и больших кодовых баз: быстрая компиляция в один исполняемый файл без зависимостей, встроенная конкурентность и минимум синтаксических конструкций. На Go написаны многие ключевые инструменты облачной инфраструктуры — [Docker](https://llmdocs.ru/wiki/docker.md), [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md), [Terraform](https://llmdocs.ru/wiki/terraform-opentofu.md), [Prometheus](https://llmdocs.ru/wiki/prometheus.md), etcd, [Caddy](https://llmdocs.ru/wiki/caddy.md). ## История Работу над языком в 2007 году начали Роберт Гризмер, Роб Пайк и Кен Томпсон (соавтор Unix и языка B). По их словам, толчком стало раздражение от долгой сборки больших программ на C++ и сложности существующих языков.[1] Go был представлен публично 10 ноября 2009 года как проект с открытым исходным кодом. Версия Go 1.0 вышла в марте 2012 года вместе с **обещанием совместимости**: программы, написанные для Go 1, должны продолжать компилироваться и работать во всех последующих версиях 1.x.[2] Это обещание соблюдается до сих пор и стало одной из причин популярности языка в продакшене. Важные вехи: компилятор, переписанный с C на сам Go (1.5, 2015), модули для управления зависимостями (1.11, 2018), обобщённые типы — дженерики (1.18, 2022).[3] Новые версии выходят дважды в год, поддерживаются две последние.[6] Талисман языка — суслик (gopher), нарисованный Рене Френч. ## Особенности языка - **Простота.** Около 25 ключевых слов, один вид цикла (`for`), нет наследования классов, перегрузки функций и исключений. - **Структуры и интерфейсы.** Вместо классов — структуры с методами. Интерфейсы реализуются неявно: тип подходит под интерфейс, если у него есть нужные методы, без объявления `implements`. - **Ошибки как значения.** Функции возвращают ошибку последним значением, и её проверяют явно (см. [Обработка ошибок в Go](https://llmdocs.ru/wiki/go-errors.md)). - **Конкурентность.** Лёгкие потоки — горутины — и каналы для обмена данными встроены в язык (см. [Горутины и каналы](https://llmdocs.ru/wiki/goroutines-channels.md)). - **Единый стиль.** Утилита `gofmt` форматирует код однозначно, споров о стиле в сообществе практически нет (см. [gofmt и go vet](https://llmdocs.ru/wiki/gofmt-govet.md)). - **Богатая стандартная библиотека**: HTTP-сервер и клиент, [JSON](https://llmdocs.ru/wiki/json.md), криптография, тестирование (см. [Стандартная библиотека Go](https://llmdocs.ru/wiki/go-stdlib.md)). ## Пример ```go package main import ( "fmt" "net/http" ) func hello(w http.ResponseWriter, r *http.Request) { name := r.URL.Query().Get("name") if name == "" { name = "мир" } fmt.Fprintf(w, "Привет, %s!\n", name) } func main() { http.HandleFunc("/", hello) http.ListenAndServe(":8080", nil) // готовый HTTP-сервер из стандартной библиотеки } ``` ```bash go run main.go # скомпилировать и запустить go build -o server # собрать статический исполняемый файл GOOS=linux GOARCH=arm64 go build # кросс-компиляция под другую платформу ``` ## Инструменты Команда `go` объединяет всё необходимое: сборку, запуск, тесты (`go test`), форматирование (`go fmt`), статический анализ (`go vet`), управление зависимостями (`go mod`, см. [Go-модули (go.mod)](https://llmdocs.ru/wiki/go-modules.md)) и генерацию документации. Тестирование и бенчмарки встроены в стандартную библиотеку (см. [Тестирование в Go](https://llmdocs.ru/wiki/go-testing.md)). ## Применение - облачная инфраструктура и DevOps-инструменты; - сетевые сервисы, API, микросервисы; - утилиты командной строки — удобно распространять одним файлом; - прокси-серверы, балансировщики, базы данных (CockroachDB, InfluxDB). ## Сравнение | | Go | [Rust](https://llmdocs.ru/wiki/rust.md) | [Python](https://llmdocs.ru/wiki/python.md) | |---|---|---|---| | Управление памятью | сборка мусора | владение, без сборщика | подсчёт ссылок + сборщик | | Скорость компиляции | очень высокая | низкая | не компилируется заранее | | Порог входа | низкий | высокий | низкий | | Конкурентность | горутины, каналы | async, потоки, гарантии компилятора | asyncio, процессы | Подробнее — в статье [Go vs Rust — сравнение](https://llmdocs.ru/wiki/go-vs-rust.md). ## Критика Go критиковали за многословную обработку ошибок (`if err != nil` в каждой второй строке), за долгое отсутствие дженериков и за паузы сборщика мусора в задачах с жёсткими требованиями к задержкам. Сторонники отвечают, что простота и предсказуемость важнее выразительности, когда кодом владеют десятки людей. ## См. также - [Горутины и каналы](https://llmdocs.ru/wiki/goroutines-channels.md) - [Rust (язык)](https://llmdocs.ru/wiki/rust.md) - [Сборка мусора vs ручное управление памятью](https://llmdocs.ru/wiki/gc-vs-manual-memory.md) - [Компилятор и интерпретатор](https://llmdocs.ru/wiki/compiler-interpreter.md) ## Источники 1. [Go FAQ — Origins](https://go.dev/doc/faq) 2. [Go 1 and the Future of Go Programs (compatibility promise)](https://go.dev/doc/go1compat) 3. [Go 1.18 Release Notes (generics)](https://go.dev/doc/go1.18) 4. [Effective Go](https://go.dev/doc/effective_go) 5. [The Go Programming Language Specification](https://go.dev/ref/spec) 6. [Go Release History](https://go.dev/doc/devel/release) --- # gofmt и go vet > Встроенные инструменты Go — gofmt приводит код к единственному каноническому формату, go vet находит подозрительные конструкции; вместе с staticcheck и golangci-lint они составляют стандартный набор проверок Go-проекта. Источник: https://llmdocs.ru/wiki/gofmt-govet/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Язык**: Go - **gofmt**: форматирование, без настроек - **go vet**: статический анализ подозрительного кода - **Поставляются**: вместе с Go (go fmt, go vet) - **Сторонние**: goimports, staticcheck, golangci-lint, gofumpt - **Интеграция**: gopls (сервер языка), pre-commit, CI **gofmt** и **go vet** — два инструмента, которые поставляются вместе с [Go](https://llmdocs.ru/wiki/go.md). `gofmt` автоматически приводит исходный код к единственному каноническому виду, а `go vet` ищет конструкции, которые компилируются, но почти наверняка являются ошибками. Они задали культуру Go-сообщества: споры о стиле закончились, потому что стиль один, а базовый статический анализ запускается одной командой без настройки.[1][2] ## gofmt `gofmt` появился одновременно с языком в 2009 году. Его ключевая особенность — **отсутствие настроек**: нет выбора между табами и пробелами, нет длины строки, нет вариантов расстановки скобок. Отступы — табы, выравнивание — пробелы, открывающая фигурная скобка — на той же строке (это требует и сам синтаксис из-за автоматической вставки точек с запятой).[4] Роб Пайк сформулировал это так: «стиль gofmt никому не нравится, но gofmt нравится всем».[3] ```bash gofmt -l . # список файлов, которые отформатированы не так gofmt -d main.go # показать diff gofmt -w . # переписать файлы на месте go fmt ./... # то же для всех пакетов модуля (gofmt -l -w) gofmt -s -w . # дополнительно упростить код ``` Флаг `-s` упрощает выражения: например, `[]T{T{1}, T{2}}` превращается в `[]T{{1}, {2}}`, а `s[a:len(s)]` — в `s[a:]`. Флаг `-r` позволяет делать механические замены по шаблону: `gofmt -r 'bytes.Compare(a, b) == 0 -> bytes.Equal(a, b)' -w .`. Поскольку формат детерминирован, `gofmt` безопасно запускать автоматически: при сохранении в редакторе (через сервер языка **gopls**), в pre-commit и в [CI/CD](https://llmdocs.ru/wiki/ci-cd.md). Диффы в ревью содержат только смысловые изменения. Идея оказалась заразительной: rustfmt в Rust (см. [Clippy и rustfmt](https://llmdocs.ru/wiki/clippy-rustfmt.md)), Black и [Ruff](https://llmdocs.ru/wiki/ruff.md) в Python, Prettier в JavaScript переняли подход «форматтер без споров». ### goimports и gofumpt - **goimports** делает всё то же, что gofmt, и дополнительно добавляет недостающие и удаляет неиспользуемые импорты, группируя стандартную библиотеку отдельно. Многие редакторы используют именно его. - **gofumpt** — более строгий форматтер-надмножество: убирает лишние пустые строки, объединяет объявления и т. п. Его результат по-прежнему совместим с gofmt. ## go vet `go vet` — статический анализатор, который проверяет корректность, а не стиль. Он запускается как `go vet ./...` и, что важно, автоматически выполняет часть проверок при `go test`.[2] Набор анализаторов включает: | Анализатор | Что ловит | |---|---| | `printf` | несоответствие формата и аргументов в `fmt.Printf("%d", "строка")` | | `copylocks` | копирование `sync.Mutex` по значению | | `loopclosure` | захват переменной цикла в горутине (актуально до Go 1.22) | | `lostcancel` | `context.WithCancel` без вызова `cancel` | | `structtag` | некорректные теги полей вроде `json:name` без кавычек | | `unreachable` | недостижимый код | | `httpresponse` | использование `resp.Body` до проверки ошибки | | `nilfunc`, `bools`, `assign` | бессмысленные сравнения и присваивания | | `unusedresult` | игнорирование результата чистых функций вроде `fmt.Sprintf` | Пример, который скомпилируется, но vet отклонит: ```go var mu sync.Mutex func f(m sync.Mutex) {} // vet: f passes lock by value fmt.Printf("%s\n", 42) // vet: Printf format %s has arg 42 of wrong type int ``` Анализаторы построены на общем фреймворке `golang.org/x/tools/go/analysis`, поэтому их легко комбинировать и писать собственные.[7] Отдельно стоит детектор гонок `-race` — он не статический, а работает во время выполнения тестов (см. [Состояние гонки и блокировки](https://llmdocs.ru/wiki/race-conditions-locks.md)). ## Более строгие линтеры `go vet` намеренно консервативен: в нём только проверки почти без ложных срабатываний. Для большего используют: - **staticcheck** — самый известный сторонний анализатор: ошибки (SA), упрощения (S), стиль (ST), устаревшие API; многие его проверки в итоге попадают в gopls.[5] - **golangci-lint** — агрегатор, который запускает десятки линтеров (vet, staticcheck, errcheck, gosec, revive, ineffassign и др.) параллельно, с общим кэшем и одним конфигом `.golangci.yml`.[6] Это стандарт де-факто для CI. ```yaml # .golangci.yml (фрагмент) version: "2" linters: enable: [errcheck, govet, staticcheck, gosec, revive] formatters: enable: [gofumpt, goimports] ``` Линтер **errcheck** особенно полезен: он находит проигнорированные ошибки, что для Go с его явной [обработкой ошибок](https://llmdocs.ru/wiki/go-errors.md) — частый источник багов. ## В CI Типичная проверка в пайплайне [GitHub Actions](https://llmdocs.ru/wiki/github-actions.md): ```bash test -z "$(gofmt -l .)" # упасть, если что-то не отформатировано go vet ./... golangci-lint run go test -race ./... ``` Набор из форматтера, vet, линтера и тестов с `-race` дёшев и покрывает большую часть типовых ошибок ещё до ревью. ## См. также - [Тестирование в Go](https://llmdocs.ru/wiki/go-testing.md) - [Стандартная библиотека Go](https://llmdocs.ru/wiki/go-stdlib.md) - [Clippy и rustfmt](https://llmdocs.ru/wiki/clippy-rustfmt.md) - [Ruff](https://llmdocs.ru/wiki/ruff.md) ## Источники 1. [Go — Command gofmt](https://pkg.go.dev/cmd/gofmt) 2. [Go — Command vet](https://pkg.go.dev/cmd/vet) 3. [Go Blog — go fmt your code](https://go.dev/blog/gofmt) 4. [Effective Go — Formatting](https://go.dev/doc/effective_go#formatting) 5. [Staticcheck documentation](https://staticcheck.dev/docs/) 6. [golangci-lint documentation](https://golangci-lint.run/) 7. [Go — golang.org/x/tools/go/analysis](https://pkg.go.dev/golang.org/x/tools/go/analysis) --- # Горутины и каналы > Встроенная модель конкурентности Go — лёгкие потоки (горутины), каналы для обмена данными и оператор select. Источник: https://llmdocs.ru/wiki/goroutines-channels/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Язык**: Go - **Модель**: CSP (взаимодействующие последовательные процессы) - **Планировщик**: M:N, модель G-M-P - **Начальный стек горутины**: несколько КБ, растёт динамически - **Ключевые конструкции**: `go`, `chan`, `select`, `close` - **Сопутствующие пакеты**: sync, context, errgroup - **Поиск гонок**: `go test -race` **Горутины и каналы** — встроенные в язык [Go](https://llmdocs.ru/wiki/go.md) средства конкурентного программирования. **Горутина** — функция, выполняющаяся конкурентно с остальной программой под управлением планировщика среды исполнения Go; она намного легче потока операционной системы, и программа может держать сотни тысяч горутин одновременно. **Канал** — типизированная труба, через которую горутины передают друг другу значения и синхронизируются. Девиз подхода из официальной документации: «Не общайтесь через разделяемую память — разделяйте память через общение».[1] ## Происхождение Модель восходит к работе Тони Хоара «Взаимодействующие последовательные процессы» (CSP, 1978), где программы описываются как независимые процессы, обменивающиеся сообщениями по каналам.[3] Роб Пайк применял эти идеи в языках Newsqueak и Limbo до того, как они вошли в Go. ## Горутины Горутина запускается ключевым словом `go` перед вызовом функции: ```go go sendEmail(user) // выполняется конкурентно, main продолжает работу go func() { fmt.Println("анонимная горутина") }() ``` Горутина стартует с маленьким стеком в несколько килобайт, который автоматически растёт и сжимается. Планировщик Go распределяет горутины по потокам ОС по схеме **M:N** (модель G-M-P): G — горутины, M — потоки ОС, P — логические процессоры, число которых по умолчанию равно числу ядер (`GOMAXPROCS`). Когда горутина блокируется на вводе-выводе или канале, поток переключается на другую. С Go 1.14 планировщик умеет принудительно прерывать долгие циклы, чтобы одна горутина не захватывала процессор.[6] ## Каналы ```go ch := make(chan int) // небуферизованный канал buf := make(chan string, 10) // буферизованный на 10 элементов ch <- 42 // отправить (блокируется, пока кто-то не примет) v := <-ch // принять close(ch) // закрыть: новых значений не будет for v := range ch { ... } // читать до закрытия ``` - **Небуферизованный** канал синхронизирует отправителя и получателя: отправка завершается только в момент приёма. - **Буферизованный** канал позволяет отправить несколько значений без ожидания, пока буфер не заполнится. - Тип можно ограничить направлением: `chan<- int` — только отправка, `<-chan int` — только приём. - Отправка в закрытый канал вызывает панику; приём из закрытого возвращает нулевое значение и признак `ok == false`. ## Оператор select `select` ждёт сразу несколько операций с каналами и выполняет ту, что готова первой:[2] ```go select { case msg := <-results: fmt.Println("результат:", msg) case <-time.After(2 * time.Second): fmt.Println("таймаут") case <-ctx.Done(): return ctx.Err() // отмена извне } ``` ## Пример: пул обработчиков ```go func worker(id int, jobs <-chan int, results chan<- int, wg *sync.WaitGroup) { defer wg.Done() for j := range jobs { results <- j * j } } func main() { jobs, results := make(chan int, 100), make(chan int, 100) var wg sync.WaitGroup for w := 1; w <= 4; w++ { wg.Add(1) go worker(w, jobs, results, &wg) } for i := 1; i <= 9; i++ { jobs <- i } close(jobs) wg.Wait() close(results) for r := range results { fmt.Println(r) } } ``` Четыре горутины разбирают задания из общего канала; `sync.WaitGroup` ждёт их завершения. ## Сопутствующие средства | Средство | Назначение | |---|---| | `sync.WaitGroup` | дождаться группы горутин | | `sync.Mutex`, `RWMutex` | защитить общие данные, когда канал избыточен | | `sync.Once` | однократная инициализация | | `context.Context` | отмена и дедлайны, передаваемые по цепочке вызовов[4] | | `errgroup.Group` (golang.org/x/sync) | группа горутин с первой ошибкой и отменой | | `sync/atomic` | атомарные операции | ## Типичные ошибки - **Утечка горутин** — горутина вечно ждёт канал, в который никто не пишет. Лечится отменой через `context` и закрытием каналов. - **Гонка данных** — несколько горутин меняют переменную без синхронизации. Детектор гонок (`go run -race`, `go test -race`) находит такие места во время выполнения.[5] Подробнее — в статье [Состояние гонки и блокировки](https://llmdocs.ru/wiki/race-conditions-locks.md). - **Взаимная блокировка** — все горутины ждут друг друга; среда исполнения сообщает «all goroutines are asleep — deadlock!». - **Захват переменной цикла** — до Go 1.22 переменная цикла была общей для всех итераций, и горутины, созданные в цикле, могли видеть одно и то же значение. С 1.22 каждая итерация получает свою переменную. ## Сравнение с другими моделями | Язык | Модель | |---|---| | Go | горутины + каналы, вытесняющий планировщик в среде исполнения | | [Python](https://llmdocs.ru/wiki/python.md) | [asyncio](https://llmdocs.ru/wiki/asyncio.md): кооперативные сопрограммы в одном потоке | | JavaScript | цикл событий и промисы (см. [Промисы и async/await (JS)](https://llmdocs.ru/wiki/js-promises-async.md)) | | Rust | async/await поверх выбираемой среды исполнения (см. [async в Rust и Tokio](https://llmdocs.ru/wiki/rust-async-tokio.md)) | | Erlang/Elixir | лёгкие процессы с почтовыми ящиками (модель акторов) | Главное отличие Go — горутины не требуют «раскрашивать» функции в синхронные и асинхронные: любая функция может быть запущена конкурентно. ## См. также - [Go (язык)](https://llmdocs.ru/wiki/go.md) - [Конкурентность и параллелизм](https://llmdocs.ru/wiki/concurrency-parallelism.md) - [Состояние гонки и блокировки](https://llmdocs.ru/wiki/race-conditions-locks.md) - [async в Rust и Tokio](https://llmdocs.ru/wiki/rust-async-tokio.md) ## Источники 1. [Effective Go — Concurrency](https://go.dev/doc/effective_go#concurrency) 2. [The Go Programming Language Specification — Channel types, Select statements](https://go.dev/ref/spec#Channel_types) 3. [C. A. R. Hoare. Communicating Sequential Processes (1978)](https://dl.acm.org/doi/10.1145/359576.359585) 4. [Go Concurrency Patterns: Context — The Go Blog](https://go.dev/blog/context) 5. [Data Race Detector](https://go.dev/doc/articles/race_detector) 6. [Go 1.14 Release Notes — asynchronous preemption](https://go.dev/doc/go1.14) --- # Владение и заимствование (Rust) > Система правил Rust, по которой компилятор отслеживает владельца каждого значения и ссылки на него, гарантируя безопасность памяти без сборщика мусора. Источник: https://llmdocs.ru/wiki/ownership-borrowing/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Язык**: Rust - **Компонент компилятора**: borrow checker (проверка заимствований) - **Что предотвращает**: обращение к освобождённой памяти, двойное освобождение, гонки данных - **Ключевые понятия**: владение, перемещение, ссылки, времена жизни - **Умные указатели**: Box, Rc, Arc, RefCell - **Документация**: [The Rust Book, глава 4](https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html) **Владение и заимствование** — центральная идея языка [Rust](https://llmdocs.ru/wiki/rust.md): набор правил, по которым компилятор во время сборки определяет, кто владеет каждым значением в памяти, кто и как на него ссылается и когда его можно освободить. Это позволяет Rust обходиться без [сборщика мусора](https://llmdocs.ru/wiki/garbage-collection.md) и при этом исключать целые классы ошибок, типичных для C и C++: использование освобождённой памяти, двойное освобождение, висячие указатели и гонки данных. Проверку выполняет компонент компилятора, который называют **borrow checker**. ## Правила владения Книга по Rust формулирует три правила:[1] 1. У каждого значения есть **владелец** — переменная. 2. В каждый момент владелец может быть только один. 3. Когда владелец выходит из области видимости, значение уничтожается (вызывается `drop`). ```rust fn main() { let s1 = String::from("привет"); let s2 = s1; // владение ПЕРЕМЕЩЕНО в s2 // println!("{s1}"); // ошибка E0382: заимствование перемещённого значения println!("{s2}"); } // здесь s2 выходит из области видимости — память освобождается ``` Присваивание и передача в функцию по значению **перемещают** владение. Простые типы фиксированного размера (`i32`, `bool`, `char`) реализуют трейт `Copy` и копируются вместо перемещения. Глубокую копию данных в куче делают явно методом `.clone()`. ## Заимствование Чтобы использовать значение, не забирая владение, берут **ссылку** — заимствуют его: ```rust fn length(s: &String) -> usize { // неизменяемое заимствование s.len() } fn shout(s: &mut String) { // изменяемое заимствование s.push('!'); } fn main() { let mut text = String::from("привет"); let n = length(&text); shout(&mut text); println!("{text} ({n})"); } ``` Главное правило заимствования: в каждый момент может существовать **либо** любое число неизменяемых ссылок `&T`, **либо** ровно одна изменяемая `&mut T`.[1] Это то же правило «много читателей или один писатель», которое в других языках обеспечивают блокировки, только проверенное компилятором. Именно поэтому в безопасном Rust невозможны гонки данных. ```rust let mut v = vec![1, 2, 3]; let first = &v[0]; // неизменяемая ссылка v.push(4); // ошибка E0502: нельзя изменять, пока жива ссылка first println!("{first}"); ``` Ошибка здесь не формальная: `push` может переразместить вектор в памяти, и `first` указывала бы на освобождённый участок. ## Времена жизни Ссылка не может пережить данные, на которые указывает. Компилятор отслеживает это через **времена жизни** (lifetimes). Обычно они выводятся автоматически, но в сигнатурах иногда их нужно указать явно:[2] ```rust fn longest<'a>(a: &'a str, b: &'a str) -> &'a str { if a.len() > b.len() { a } else { b } } ``` Запись `'a` говорит: результат живёт не дольше, чем оба аргумента. С 2018 года действуют **нелексические времена жизни** (NLL): ссылка считается живой до последнего использования, а не до конца блока, что убрало многие ложные ошибки.[4] ## Когда правил мало Для ситуаций, которые не укладываются в «один владелец», стандартная библиотека предлагает умные указатели:[3] | Тип | Назначение | |---|---| | `Box` | значение в куче с единственным владельцем | | `Rc` | несколько владельцев в одном потоке (подсчёт ссылок) | | `Arc` | то же для нескольких потоков (атомарный счётчик) | | `RefCell` | проверка правил заимствования во время выполнения («внутренняя изменяемость») | | `Mutex`, `RwLock` | изменяемый доступ из нескольких потоков | Типичная связка для общих изменяемых данных между потоками — `Arc>`. Безопасность передачи между потоками обеспечивают маркерные трейты `Send` и `Sync`, которые компилятор выводит автоматически.[5] ## Сравнение подходов к памяти | Подход | Языки | Цена | |---|---|---| | ручное управление | C, C++ | ошибки памяти — частая причина уязвимостей | | сборка мусора | Java, [Go](https://llmdocs.ru/wiki/go.md), [Python](https://llmdocs.ru/wiki/python.md) | паузы и накладные расходы во время работы | | владение и заимствование | Rust | сложнее писать код, проверки — при компиляции | Подробнее — в статье [Сборка мусора vs ручное управление памятью](https://llmdocs.ru/wiki/gc-vs-manual-memory.md). ## Трудности Новички часто «воюют с borrow checker»: структуры с циклическими ссылками (графы, двусвязные списки) и некоторые шаблоны из других языков приходится перестраивать — использовать индексы вместо ссылок, `Rc`/`Weak` или арены. Компилятор консервативен и иногда отвергает корректный код; для таких случаев разрабатывается новый анализатор Polonius, а в крайнем случае есть [Unsafe Rust](https://llmdocs.ru/wiki/unsafe-rust.md). ## См. также - [Rust (язык)](https://llmdocs.ru/wiki/rust.md) - [Трейты (Rust)](https://llmdocs.ru/wiki/rust-traits.md) - [Состояние гонки и блокировки](https://llmdocs.ru/wiki/race-conditions-locks.md) - [Unsafe Rust](https://llmdocs.ru/wiki/unsafe-rust.md) ## Источники 1. [The Rust Book — Understanding Ownership](https://doc.rust-lang.org/book/ch04-00-understanding-ownership.html) 2. [The Rust Book — Validating References with Lifetimes](https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html) 3. [The Rust Book — Smart Pointers](https://doc.rust-lang.org/book/ch15-00-smart-pointers.html) 4. [RFC 2094 — Non-lexical lifetimes](https://rust-lang.github.io/rfcs/2094-nll.html) 5. [The Rustonomicon — Send and Sync](https://doc.rust-lang.org/nomicon/send-and-sync.html) --- # async в Rust и Tokio > Асинхронное программирование в Rust на основе async/await и ленивых футур, которые исполняет внешняя среда выполнения; Tokio — самая распространённая такая среда для сетевых приложений. Источник: https://llmdocs.ru/wiki/rust-async-tokio/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **async/await**: стабилизированы в Rust 1.39 (ноябрь 2019) - **Модель**: ленивые футуры с опросом (poll), без встроенной среды выполнения - **Tokio**: с 2016, версия 1.0 — декабрь 2020 - **Автор Tokio**: Карл Лерхе и сообщество - **Лицензия Tokio**: MIT - **Экосистема**: hyper, axum, reqwest, tonic, sqlx - **Альтернативы**: smol, embassy (встраиваемые системы) **Асинхронное программирование в Rust** позволяет одному потоку обслуживать тысячи одновременных операций ввода-вывода — сетевых соединений, запросов к базе данных, таймеров, — не создавая отдельный поток операционной системы на каждую. Функция, объявленная как `async fn`, возвращает **футуру** (*future*) — значение, представляющее ещё не завершённое вычисление, а `.await` ждёт её результата, не блокируя поток. В отличие от многих языков, в [Rust](https://llmdocs.ru/wiki/rust.md) нет встроенной среды выполнения: футуры исполняет подключаемая библиотека, и самая распространённая из них — **Tokio**. На асинхронном Rust построены веб-серверы, прокси, базы данных, брокеры сообщений и клиентские SDK облачных сервисов. ## История Синтаксис `async`/`await` стабилизировали в Rust 1.39 в ноябре 2019 года после нескольких лет проектирования.[3] Ключевое решение — **футуры с нулевой стоимостью**: компилятор превращает асинхронную функцию в конечный автомат, размер и поведение которого известны при компиляции, без выделения памяти в куче на каждый шаг. Tokio начали развивать в 2016 году; версия 1.0 с гарантией стабильности API вышла в декабре 2020 года.[4] В Rust 1.75 (2023) появились асинхронные методы в трейтах (см. [Трейты (Rust)](https://llmdocs.ru/wiki/rust-traits.md)). ## Как работают футуры Футура реализует трейт `Future` с методом `poll`. Среда выполнения опрашивает футуру: та либо возвращает `Ready(результат)`, либо `Pending` и регистрирует **пробуждатель** (*waker*), который сообщит среде, когда стоит опросить её снова — например, когда в сокет пришли данные.[5] Главное отличие от JavaScript и [asyncio](https://llmdocs.ru/wiki/asyncio.md) в Python: футуры в Rust **ленивые**. Вызов `async fn` ничего не выполняет, пока футуру не начнут ожидать через `.await` или не передадут исполнителю. Забытая без `.await` футура просто не выполнится — компилятор предупредит об этом. ## Пример с Tokio ```toml # Cargo.toml [dependencies] tokio = { version = "1", features = ["full"] } reqwest = "0.12" ``` ```rust use std::time::Duration; use tokio::time::sleep; async fn fetch(url: &str) -> Result { let body = reqwest::get(url).await?.text().await?; Ok(body.len()) } #[tokio::main] // запускает многопоточную среду выполнения async fn main() { let urls = ["https://example.com", "https://www.rust-lang.org"]; // конкурентно: обе загрузки идут одновременно let handles: Vec<_> = urls.iter() .map(|u| tokio::spawn(fetch(u))) // отдельная задача на каждый URL .collect(); for h in handles { println!("{:?}", h.await.unwrap()); } // таймаут и выбор первого завершившегося tokio::select! { r = fetch("https://example.com") => println!("ответ: {r:?}"), _ = sleep(Duration::from_secs(2)) => println!("таймаут"), } } ``` ## Что даёт Tokio | Компонент | Назначение | |---|---| | Планировщик | многопоточный исполнитель с перехватом задач (*work stealing*) | | Ввод-вывод | асинхронные TCP, UDP, Unix-сокеты, файлы, процессы | | Время | `sleep`, `timeout`, `interval` | | Синхронизация | асинхронные `Mutex`, `RwLock`, `Semaphore`, каналы `mpsc`, `oneshot`, `broadcast`, `watch` | | Задачи | `tokio::spawn`, `JoinSet`, отмена через удаление футуры | Подробное введение — в официальном руководстве Tokio, где по шагам строится мини-версия [Redis](https://llmdocs.ru/wiki/redis.md).[2] ## Экосистема - **hyper** — низкоуровневая реализация [HTTP](https://llmdocs.ru/wiki/http.md)/1 и HTTP/2; **axum** — популярный веб-фреймворк поверх hyper и Tokio.[6] - **reqwest** — HTTP-клиент, **tonic** — gRPC, **sqlx** — асинхронный доступ к [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md), MySQL и SQLite. - **tower** — промежуточные слои: повторы, таймауты, ограничение нагрузки. - **tracing** — структурированное логирование и трассировка асинхронного кода. ## Подводные камни - **Блокирующий код в асинхронной задаче.** Тяжёлые вычисления или синхронный ввод-вывод внутри `async fn` останавливают поток исполнителя и все задачи на нём. Для них есть `tokio::task::spawn_blocking`. - **Требование `Send`.** Задачи многопоточного исполнителя могут переезжать между потоками, поэтому всё, что живёт через `.await`, должно быть `Send`. Типичная ошибка — держать `std::sync::MutexGuard` или `Rc` через точку ожидания. - **«Цветные» функции.** Асинхронную функцию нельзя просто вызвать из синхронной — нужно запустить среду выполнения. Библиотеки нередко предлагают обе версии API. - **Отмена.** Удаление футуры отменяет её в ближайшей точке `.await`, поэтому код между точками ожидания должен оставлять данные в согласованном состоянии. - **Сложность.** Ошибки компиляции с `Pin`, временами жизни и `Send` — самая трудная часть изучения асинхронного Rust; подробности — в официальной книге по асинхронному программированию.[1] ## Когда нужен async Асинхронность оправдана для программ с большим числом одновременных операций ввода-вывода: серверов, прокси, краулеров (см. [Конкурентность и параллелизм](https://llmdocs.ru/wiki/concurrency-parallelism.md)). Для вычислений лучше подходят потоки и библиотеки вроде rayon, а для простых утилит командной строки — обычный синхронный код. Сравнение с моделью [горутин](https://llmdocs.ru/wiki/goroutines-channels.md) Go: там планировщик встроен в язык, а в Rust среда выполнения выбирается и подключается явно. ## См. также - [Rust (язык)](https://llmdocs.ru/wiki/rust.md) - [Конкурентность и параллелизм](https://llmdocs.ru/wiki/concurrency-parallelism.md) - [Трейты (Rust)](https://llmdocs.ru/wiki/rust-traits.md) - [Горутины и каналы](https://llmdocs.ru/wiki/goroutines-channels.md) - [asyncio](https://llmdocs.ru/wiki/asyncio.md) ## Источники 1. [Asynchronous Programming in Rust (async book)](https://rust-lang.github.io/async-book/) 2. [Tokio — Tutorial](https://tokio.rs/tokio/tutorial) 3. [Rust Blog — Async-await on stable Rust! (1.39)](https://blog.rust-lang.org/2019/11/07/Async-await-stable.html) 4. [Tokio Blog — Announcing Tokio 1.0](https://tokio.rs/blog/2020-12-tokio-1-0) 5. [Rust std — Trait std::future::Future](https://doc.rust-lang.org/std/future/trait.Future.html) 6. [axum — docs.rs](https://docs.rs/axum) --- # Обработка ошибок в Rust (Result, ?) > В Rust восстановимые ошибки выражаются типом Result, отсутствие значения — Option, а оператор ? лаконично пробрасывает ошибку вызывающему коду; неустранимые сбои вызывают panic!. Источник: https://llmdocs.ru/wiki/rust-errors/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Восстановимые ошибки**: Result — Ok(T) или Err(E) - **Отсутствие значения**: Option — Some(T) или None - **Проброс ошибок**: оператор ? (Rust 1.13, 2016; ранее макрос try!) - **Неустранимые ошибки**: panic! - **Трейт ошибок**: std::error::Error - **Популярные крейты**: thiserror (библиотеки), anyhow (приложения) **Обработка ошибок в Rust** основана на типах. Операция, которая может завершиться неудачей, возвращает **`Result`** — перечисление из двух вариантов: `Ok(значение)` при успехе или `Err(ошибка)` при неудаче. Значение, которого может не быть, описывается **`Option`** — `Some(значение)` или `None`. Компилятор не позволит использовать результат, не разобрав оба варианта, а **оператор `?`** позволяет коротко передать ошибку наверх. Для действительно неустранимых ситуаций есть **`panic!`**.[1] В Rust нет исключений и нет `null`: всё, что может пойти не так, видно в сигнатуре функции. ## Result и Option ```rust enum Result { Ok(T), Err(E) } enum Option { Some(T), None } ``` ```rust use std::fs; fn read_port(path: &str) -> Result { let text = match fs::read_to_string(path) { Ok(t) => t, Err(e) => return Err(format!("не удалось прочитать {path}: {e}")), }; text.trim().parse::().map_err(|e| format!("некорректный порт: {e}")) } match read_port("port.txt") { Ok(port) => println!("слушаем порт {port}"), Err(msg) => eprintln!("ошибка: {msg}"), } ``` У обоих типов десятки удобных методов-комбинаторов: `map`, `map_err`, `and_then`, `unwrap_or`, `unwrap_or_else`, `ok_or`, `ok()`. Они позволяют преобразовывать значения и ошибки без вложенных `match`.[2] ## Оператор ? Оператор `?` после выражения типа `Result` делает следующее: при `Ok` извлекает значение, при `Err` немедленно возвращает ошибку из текущей функции, предварительно преобразовав её в нужный тип через трейт `From`. Он появился в Rust 1.13 (2016), заменив макрос `try!`.[4] ```rust use std::{fs, io, num::ParseIntError}; #[derive(Debug)] enum ConfigError { Io(io::Error), Parse(ParseIntError), } impl From for ConfigError { fn from(e: io::Error) -> Self { ConfigError::Io(e) } } impl From for ConfigError { fn from(e: ParseIntError) -> Self { ConfigError::Parse(e) } } fn read_port(path: &str) -> Result { let text = fs::read_to_string(path)?; // io::Error → ConfigError::Io let port = text.trim().parse::()?; // ParseIntError → ConfigError::Parse Ok(port) } ``` Тот же оператор работает с `Option` в функциях, возвращающих `Option`, и в функции `main`, если она возвращает `Result`. ## panic! `panic!` прерывает поток выполнения при ошибке программиста или нарушенном инварианте: выход за границы вектора, деление на ноль в целых числах, явный `unreachable!()`. Методы `unwrap()` и `expect("сообщение")` извлекают значение из `Result` или `Option`, вызывая панику при ошибке. Они уместны в прототипах, тестах и там, где ошибка действительно невозможна; в рабочем коде предпочтительнее обработка или `expect` с объяснением, почему значение обязано быть. ## Трейт Error и экосистема Типы ошибок принято реализовывать с трейтом `std::error::Error` (требует `Debug` и `Display`) и методом `source()`, который даёт доступ к исходной причине.[3] Писать такие реализации вручную утомительно, поэтому сложились два популярных крейта Дэвида Толнея: | Крейт | Для чего | Подход | |---|---|---| | **thiserror** | библиотеки | собственное перечисление ошибок; `derive` генерирует `Display`, `Error` и `From`[5] | | **anyhow** | приложения | единый тип `anyhow::Error` для любых ошибок, удобное добавление контекста[6] | ```rust // библиотека: точные, различимые ошибки #[derive(Debug, thiserror::Error)] pub enum StoreError { #[error("запись {0} не найдена")] NotFound(u64), #[error("ошибка базы данных")] Db(#[from] sqlx::Error), } // приложение: ошибки с контекстом use anyhow::{Context, Result}; fn load() -> Result { let raw = std::fs::read_to_string("config.toml").context("чтение config.toml")?; let cfg: Config = toml::from_str(&raw).context("разбор config.toml")?; Ok(cfg) } ``` Правило большого пальца: библиотека должна давать вызывающему коду возможность различать ошибки (thiserror), а приложению чаще важно понятное сообщение с цепочкой причин (anyhow). ## Сравнение с Go и исключениями | | Rust | [Go](https://llmdocs.ru/wiki/go-errors.md) | Исключения (Python, Java) | |---|---|---|---| | Где видна ошибка | в типе возврата | в типе возврата | не видна в сигнатуре (кроме checked exceptions) | | Можно забыть обработать | нет — компилятор предупредит | да, если проигнорировать `err` | да | | Проброс | `?` | `if err != nil { return err }` | автоматический | | Стоимость | нулевая, обычное значение | обычное значение | раскрутка стека | ## Советы - Не злоупотребляйте `unwrap()` — каждая паника в продакшене начинается с одного из них; линтер Clippy может запрещать их в рабочем коде (см. [Clippy и rustfmt](https://llmdocs.ru/wiki/clippy-rustfmt.md)). - Добавляйте контекст при пробросе: что делала функция и с какими данными. - Не превращайте все ошибки в строки — типизированные ошибки позволяют вызывающему коду реагировать по-разному. ## См. также - [Rust (язык)](https://llmdocs.ru/wiki/rust.md) - [Трейты (Rust)](https://llmdocs.ru/wiki/rust-traits.md) - [Обработка ошибок в Go](https://llmdocs.ru/wiki/go-errors.md) - [Владение и заимствование (Rust)](https://llmdocs.ru/wiki/ownership-borrowing.md) - [Cargo и crates.io](https://llmdocs.ru/wiki/cargo.md) ## Источники 1. [The Rust Programming Language — Error Handling](https://doc.rust-lang.org/book/ch09-00-error-handling.html) 2. [Rust std — Module std::result](https://doc.rust-lang.org/std/result/) 3. [Rust std — Trait std::error::Error](https://doc.rust-lang.org/std/error/trait.Error.html) 4. [Rust Blog — Announcing Rust 1.13](https://blog.rust-lang.org/2016/11/10/Rust-1.13.html) 5. [thiserror — docs.rs](https://docs.rs/thiserror) 6. [anyhow — docs.rs](https://docs.rs/anyhow) --- # Макросы Rust > Механизм метапрограммирования Rust, генерирующий код на этапе компиляции; декларативные макросы macro_rules! и процедурные макросы — derive, атрибутные и функционально-подобные. Источник: https://llmdocs.ru/wiki/rust-macros/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Язык**: Rust - **Виды**: декларативные (macro_rules!), процедурные (derive, атрибутные, function-like) - **Работают с**: потоком токенов, а не текстом - **Гигиена**: локальные имена макроса не конфликтуют с кодом вызова - **Популярные крейты**: syn, quote, proc-macro2 - **Просмотр раскрытия**: cargo expand **Макросы Rust** — механизм метапрограммирования, который генерирует код во время компиляции. В отличие от макросов препроцессора C, работающих с текстом, макросы [Rust](https://llmdocs.ru/wiki/rust.md) оперируют синтаксическими токенами, проверяются компилятором и соблюдают **гигиену** — имена, объявленные внутри макроса, не сталкиваются с именами в месте вызова. Макрос узнаётся по восклицательному знаку (`println!`, `vec!`) или по атрибуту (`#[derive(Debug)]`).[1] ## Зачем макросы Функции Rust имеют фиксированное число аргументов определённых типов. Макросы нужны там, где этого недостаточно: - **переменное число аргументов** — `println!("{} + {} = {}", a, b, a + b)`, `vec![1, 2, 3]`; - **проверка на этапе компиляции** — `format!` проверяет, что строка формата совпадает с аргументами; - **генерация повторяющегося кода** — реализации трейтов для многих типов; - **встроенные предметные языки** (DSL) — SQL-запросы, HTML-шаблоны, маршруты; - **автоматическая реализация** [трейтов](https://llmdocs.ru/wiki/rust-traits.md) по структуре типа (`derive`). ## Декларативные макросы Макросы «по образцу» объявляются через `macro_rules!` и похожи на `match`: каждое правило сопоставляет входные токены с шаблоном и подставляет результат.[2] ```rust macro_rules! hashmap { ($($key:expr => $value:expr),* $(,)?) => {{ let mut m = ::std::collections::HashMap::new(); $( m.insert($key, $value); )* m }}; } let ages = hashmap! { "alice" => 31, "bob" => 25 }; ``` Элементы шаблона: | Фрагмент | Что совпадает | |---|---| | `$x:expr` | выражение | | `$t:ty` | тип | | `$i:ident` | идентификатор | | `$p:pat` | образец | | `$b:block`, `$s:stmt` | блок, оператор | | `$tt:tt` | любое дерево токенов | | `$( ... ),*` | повторение через запятую, 0 и более раз | | `$( ... );+` | повторение через `;`, 1 и более раз | Декларативные макросы можно объявить и использовать прямо в одном файле; экспортируют их атрибутом `#[macro_export]`. Сложные трюки вроде рекурсии по токенам описаны в «The Little Book of Rust Macros».[4] ## Процедурные макросы Процедурный макрос — функция на Rust, которая получает поток токенов (`TokenStream`) и возвращает новый. Такие макросы размещаются в отдельном крейте с `proc-macro = true` в [Cargo.toml](https://llmdocs.ru/wiki/cargo.md) и выполняются компилятором при сборке.[3] Три вида: **1. Derive-макросы** добавляют реализацию трейта к структуре или перечислению: ```rust use serde::{Deserialize, Serialize}; #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] struct User { id: u64, #[serde(rename = "userName")] name: String, } ``` `Debug`, `Clone`, `PartialEq` встроены в компилятор, а `Serialize` и `Deserialize` предоставляет крейт **Serde**, который генерирует код преобразования в [JSON](https://llmdocs.ru/wiki/json.md) и десятки других форматов без рефлексии во время выполнения.[6] **2. Атрибутные макросы** преобразуют элемент, к которому применены: ```rust #[tokio::main] async fn main() { /* ... */ } #[get("/users/{id}")] // actix-web async fn user(path: web::Path) -> impl Responder { /* ... */ } ``` `#[tokio::main]` превращает асинхронный `main` в обычный, создающий рантайм (см. [async в Rust и Tokio](https://llmdocs.ru/wiki/rust-async-tokio.md)). **3. Функционально-подобные макросы** вызываются как `name!(...)`, но, в отличие от `macro_rules!`, могут выполнять произвольный код при компиляции. Пример — `sqlx::query!`, который подключается к базе во время сборки и проверяет SQL-запрос и типы столбцов. Процедурные макросы почти всегда пишут с помощью крейтов **syn** (разбор токенов в синтаксическое дерево), **quote** (генерация токенов из шаблона) и **proc-macro2**:[5] ```rust #[proc_macro_derive(Hello)] pub fn derive_hello(input: TokenStream) -> TokenStream { let ast = syn::parse_macro_input!(input as syn::DeriveInput); let name = &ast.ident; quote::quote! { impl #name { pub fn hello() { println!("Привет от {}", stringify!(#name)); } } }.into() } ``` ## Отладка Увидеть, во что раскрывается макрос, позволяет `cargo expand` (обёртка над флагом nightly-компилятора):[7] ```bash cargo install cargo-expand cargo expand --lib models::user ``` Ошибки в процедурных макросах лучше выдавать через `syn::Error` с указанием места в исходнике — тогда компилятор подсветит нужный фрагмент кода пользователя, а не внутренности макроса. ## Недостатки - **Время компиляции** — процедурные макросы и syn заметно замедляют сборку, особенно чистую. - **Сложность чтения и сопровождения** — макрос скрывает сгенерированный код; IDE (rust-analyzer) поддерживает раскрытие, но не всегда идеально. - **Сообщения об ошибках** внутри сложных `macro_rules!` бывают малопонятными. - Процедурные макросы выполняют произвольный код при сборке, что важно для безопасности цепочки поставок — как и `build.rs`. Правило сообщества: сначала попробовать функции, обобщённые типы и трейты, а макросы использовать, когда без них не обойтись. ## Сравнение с другими языками Макросы препроцессора C работают с текстом и не гигиеничны. Шаблоны C++ — вычисления над типами. Lisp вдохновил идею макросов над синтаксическим деревом. В [Go](https://llmdocs.ru/wiki/go.md) макросов нет: вместо них используется `go generate` и генерация кода; в [Python](https://llmdocs.ru/wiki/python.md) похожие задачи решают [декораторы](https://llmdocs.ru/wiki/decorators.md) и метаклассы, но во время выполнения. ## См. также - [Трейты (Rust)](https://llmdocs.ru/wiki/rust-traits.md) - [Unsafe Rust](https://llmdocs.ru/wiki/unsafe-rust.md) - [Cargo и crates.io](https://llmdocs.ru/wiki/cargo.md) - [Clippy и rustfmt](https://llmdocs.ru/wiki/clippy-rustfmt.md) ## Источники 1. [The Rust Programming Language — Macros](https://doc.rust-lang.org/book/ch20-05-macros.html) 2. [The Rust Reference — Macros By Example](https://doc.rust-lang.org/reference/macros-by-example.html) 3. [The Rust Reference — Procedural Macros](https://doc.rust-lang.org/reference/procedural-macros.html) 4. [The Little Book of Rust Macros](https://veykril.github.io/tlborm/) 5. [syn crate documentation](https://docs.rs/syn/) 6. [Serde — Using derive](https://serde.rs/derive.html) 7. [cargo-expand](https://github.com/dtolnay/cargo-expand) --- # Трейты (Rust) > Трейт в Rust описывает общее поведение — набор методов, которые тип может реализовать; основа обобщённого программирования, статической и динамической диспетчеризации. Источник: https://llmdocs.ru/wiki/rust-traits/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Аналоги**: интерфейсы (Java, Go), классы типов (Haskell) - **Реализация**: impl Трейт for Тип - **Статическая диспетчеризация**: обобщения с ограничениями (T Display), impl Trait - **Динамическая диспетчеризация**: dyn Trait через таблицу виртуальных методов - **Автоматическая реализация**: #[derive(...)] - **Ограничение**: правило сироты (orphan rule) - **Стандартные трейты**: Debug, Display, Clone, Copy, From, Iterator, Send, Sync **Трейт** (англ. *trait* — «черта», «свойство»; в русских переводах также «типаж») — механизм [Rust](https://llmdocs.ru/wiki/rust.md) для описания общего поведения: набор методов, которые разные типы могут реализовать каждый по-своему. Трейты похожи на интерфейсы в Java и [Go](https://llmdocs.ru/wiki/go.md) и на классы типов в Haskell. На них построено обобщённое программирование в Rust: функция может принимать «любой тип, который умеет выводиться на экран» или «любой итератор», а компилятор проверяет это на этапе сборки.[1] Многие ключевые свойства языка выражены трейтами: копирование (`Copy`, `Clone`), вывод (`Debug`, `Display`), сравнение (`PartialEq`, `Ord`), итерация (`Iterator`), преобразования (`From`, `Into`) и потокобезопасность (`Send`, `Sync`). ## Определение и реализация ```rust trait Shape { fn area(&self) -> f64; // обязательный метод fn describe(&self) -> String { // метод с реализацией по умолчанию format!("фигура площадью {:.2}", self.area()) } } struct Circle { r: f64 } struct Rect { w: f64, h: f64 } impl Shape for Circle { fn area(&self) -> f64 { std::f64::consts::PI * self.r * self.r } } impl Shape for Rect { fn area(&self) -> f64 { self.w * self.h } fn describe(&self) -> String { format!("прямоугольник {}×{}", self.w, self.h) } } ``` В отличие от классического наследования, реализация трейта пишется отдельно от определения типа: можно реализовать свой трейт для чужих типов (например, для `i32` или `Vec`) и чужой трейт для своих. ## Обобщения и ограничения Трейты ограничивают параметры обобщённых функций — компилятор пропустит только подходящие типы: ```rust use std::fmt::Display; fn largest(items: &[T]) -> T { let mut max = items[0]; for &x in items { if x > max { max = x; } } max } fn print_all(items: &[impl Display]) { // сокращённая запись ограничения for x in items { println!("{x}"); } } fn total_area(shapes: &[S]) -> f64 where S: Shape, { shapes.iter().map(|s| s.area()).sum() } ``` Обобщённый код проходит **мономорфизацию**: для каждого конкретного типа компилятор создаёт отдельную специализированную копию функции. Вызовы методов разрешаются при компиляции и могут встраиваться — это **статическая диспетчеризация** без накладных расходов во время выполнения, ценой большего размера бинарника. ## Трейт-объекты Когда в одной коллекции нужны значения разных типов, используют **трейт-объекты** `dyn Trait`. Значение хранится за указателем (`Box`, `&`, `Arc`), а метод выбирается во время выполнения через таблицу виртуальных методов — **динамическая диспетчеризация**:[2] ```rust let shapes: Vec> = vec![ Box::new(Circle { r: 1.0 }), Box::new(Rect { w: 2.0, h: 3.0 }), ]; for s in &shapes { println!("{}", s.describe()); } ``` | | Обобщения (`T: Trait`, `impl Trait`) | Трейт-объекты (`dyn Trait`) | |---|---|---| | Выбор метода | при компиляции | во время выполнения | | Скорость | максимальная, возможна оптимизация | косвенный вызов | | Разнородные коллекции | нет | да | | Размер кода | растёт с числом типов | одна копия | Не каждый трейт можно сделать объектом: например, методы с обобщёнными параметрами или возвращающие `Self` этому мешают.[3] ## Ассоциированные типы и стандартные трейты Трейт может объявлять **ассоциированный тип**, который определяет реализация. Классический пример — `Iterator`: ```rust struct Countdown(u32); impl Iterator for Countdown { type Item = u32; // ассоциированный тип fn next(&mut self) -> Option { if self.0 == 0 { None } else { self.0 -= 1; Some(self.0 + 1) } } } let v: Vec = Countdown(3).filter(|x| x % 2 == 1).collect(); // [3, 1] ``` Реализовав один метод `next`, тип бесплатно получает десятки методов по умолчанию — `map`, `filter`, `sum`, `collect`. Многие стандартные трейты можно реализовать автоматически атрибутом `#[derive]`: ```rust #[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] struct UserId(u64); ``` Руководство по API для Rust рекомендует реализовывать для публичных типов стандартные трейты, где это имеет смысл, — так типы лучше сочетаются с остальной экосистемой.[6] ## Правило сироты Реализовать трейт для типа можно, только если трейт или тип определены в вашем крейте. Это **правило сироты** (*orphan rule*) не позволяет двум библиотекам дать конфликтующие реализации одного и того же трейта для одного типа. Обходной путь — обёртка-новый тип (*newtype*): `struct Wrapper(Vec);`. ## Трейты и асинхронность С Rust 1.75 (декабрь 2023) в трейтах можно объявлять асинхронные методы `async fn` и методы, возвращающие `impl Trait`; до этого требовались обходные решения вроде крейта `async-trait` (см. [async в Rust и Tokio](https://llmdocs.ru/wiki/rust-async-tokio.md)).[5] Маркерные трейты `Send` и `Sync` сообщают компилятору, можно ли передавать значение между потоками и разделять его, — на этом основана защита от гонок данных (см. [Владение и заимствование (Rust)](https://llmdocs.ru/wiki/ownership-borrowing.md)). Больше примеров — в Rust By Example.[4] ## См. также - [Rust (язык)](https://llmdocs.ru/wiki/rust.md) - [Владение и заимствование (Rust)](https://llmdocs.ru/wiki/ownership-borrowing.md) - [Обработка ошибок в Rust (Result, ?)](https://llmdocs.ru/wiki/rust-errors.md) - [async в Rust и Tokio](https://llmdocs.ru/wiki/rust-async-tokio.md) - [Макросы Rust](https://llmdocs.ru/wiki/rust-macros.md) ## Источники 1. [The Rust Programming Language — Traits: Defining Shared Behavior](https://doc.rust-lang.org/book/ch10-02-traits.html) 2. [The Rust Programming Language — Using Trait Objects](https://doc.rust-lang.org/book/ch18-02-trait-objects.html) 3. [The Rust Reference — Traits](https://doc.rust-lang.org/reference/items/traits.html) 4. [Rust By Example — Traits](https://doc.rust-lang.org/rust-by-example/trait.html) 5. [Rust Blog — Announcing async fn and return-position impl Trait in traits (Rust 1.75)](https://blog.rust-lang.org/2023/12/21/async-fn-rpit-in-traits.html) 6. [Rust API Guidelines — Interoperability (common traits)](https://rust-lang.github.io/api-guidelines/interoperability.html) --- # Rust (язык) > Системный язык программирования с гарантиями безопасности памяти без сборщика мусора, основанными на владении и заимствовании. Источник: https://llmdocs.ru/wiki/rust/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Класс языка**: мультипарадигменный, системный - **Появился в**: 2010 (публично), 1.0 — 15 мая 2015 - **Автор**: Грейдон Хоар - **Разработчик**: проект Rust, Rust Foundation (с 2021) - **Выпуск версий**: каждые 6 недель; редакции 2015, 2018, 2021, 2024 - **Типизация**: статическая, строгая, с выводом типов - **Управление памятью**: владение и заимствование, без сборщика мусора - **Компилятор**: rustc (бэкенд LLVM) - **Расширение файлов**: `.rs` - **Лицензия**: MIT / Apache 2.0 - **Сайт**: [rust-lang.org](https://www.rust-lang.org/) **Rust** — компилируемый системный язык программирования, который сочетает производительность уровня C и C++ с гарантиями безопасности памяти. Ошибки вроде обращения к освобождённой памяти, двойного освобождения и гонок данных отсекаются ещё на этапе компиляции благодаря системе [владения и заимствования](https://llmdocs.ru/wiki/ownership-borrowing.md), без сборщика мусора и без накладных расходов во время работы программы. Rust используют для операционных систем, браузеров, сетевых сервисов, инструментов командной строки и [WebAssembly](https://llmdocs.ru/wiki/webassembly.md). ## История Грейдон Хоар начал Rust как личный проект в 2006 году; в 2009-м его разработку стала спонсировать Mozilla, рассчитывая использовать язык для нового браузерного движка Servo. Ранние версии сильно отличались от современной: в языке были сборщик мусора и зелёные потоки, от которых впоследствии отказались. Стабильная версия Rust 1.0 вышла 15 мая 2015 года с обещанием обратной совместимости.[2] С тех пор новые версии выходят каждые шесть недель.[6] Несовместимые изменения синтаксиса вводятся через **редакции** (editions) — 2015, 2018, 2021 и 2024; крейты разных редакций свободно работают вместе.[4] В 2021 году создан независимый фонд Rust Foundation, учредителями которого стали AWS, Google, Huawei, Microsoft и Mozilla.[3] В 2022 году поддержка Rust вошла в ядро [Linux](https://llmdocs.ru/wiki/linux.md) (версия 6.1) как второй язык после C.[5] Язык много лет подряд возглавлял опрос Stack Overflow в номинации «самый любимый». Неофициальный талисман — краб Феррис. ## Ключевые идеи - **Владение.** У каждого значения ровно один владелец; когда владелец выходит из области видимости, значение освобождается. Передача значения перемещает владение. - **Заимствование.** Можно одновременно иметь либо сколько угодно неизменяемых ссылок `&T`, либо одну изменяемую `&mut T`. Это правило исключает гонки данных. - **Абстракции без накладных расходов.** Итераторы, замыкания, обобщённые типы компилируются в код, сравнимый с написанным вручную. - **Алгебраические типы и сопоставление с образцом.** `enum` с данными и `match`, проверяющий полноту вариантов. - **Нет null и исключений.** Отсутствие значения выражается типом `Option`, ошибка — `Result` (см. [Обработка ошибок в Rust (Result, ?)](https://llmdocs.ru/wiki/rust-errors.md)). - **Трейты** вместо наследования (см. [Трейты (Rust)](https://llmdocs.ru/wiki/rust-traits.md)). ## Пример ```rust use std::collections::HashMap; fn word_count(text: &str) -> HashMap { let mut counts = HashMap::new(); for word in text.split_whitespace() { *counts.entry(word.to_lowercase()).or_insert(0) += 1; } counts } fn main() { let counts = word_count("Раз два раз три раз"); match counts.get("раз") { Some(n) => println!("«раз» встречается {n} раз(а)"), None => println!("не найдено"), } } ``` ## Инструменты Экосистема собрана вокруг официальных утилит: - **rustup** — установка компилятора и переключение между версиями; - **[Cargo](https://llmdocs.ru/wiki/cargo.md)** — сборка, зависимости, тесты, публикация пакетов (крейтов) на crates.io; - **[Clippy и rustfmt](https://llmdocs.ru/wiki/clippy-rustfmt.md)** — линтер и форматировщик; - **rust-analyzer** — языковой сервер для редакторов. Компилятор славится подробными сообщениями об ошибках с подсказками, как их исправить. ## Применение - системное ПО: компоненты Windows, Android, ядра Linux; - инфраструктура: прокси, базы данных, среды исполнения (например, Deno); - инструменты разработчика: [Ruff](https://llmdocs.ru/wiki/ruff.md) и [uv](https://llmdocs.ru/wiki/uv.md) для Python, ripgrep, сборщики JavaScript; - встраиваемые системы и [WebAssembly](https://llmdocs.ru/wiki/webassembly.md). ## Сравнение | | Rust | C++ | [Go](https://llmdocs.ru/wiki/go.md) | |---|---|---|---| | Безопасность памяти | гарантирована компилятором (вне `unsafe`) | на совести программиста | сборщик мусора | | Сборщик мусора | нет | нет | есть | | Скорость компиляции | низкая | низкая | высокая | | Порог входа | высокий | высокий | низкий | Для низкоуровневых операций, которые компилятор не может проверить, есть блоки `unsafe` (см. [Unsafe Rust](https://llmdocs.ru/wiki/unsafe-rust.md)). ## Критика Главные претензии — крутая кривая обучения (споры с «проверяющим заимствования»), долгая компиляция больших проектов и сложность асинхронного программирования. Кроме того, экосистема моложе, чем у C++ или Java, и ряд библиотек ещё не достиг версии 1.0. ## См. также - [Владение и заимствование (Rust)](https://llmdocs.ru/wiki/ownership-borrowing.md) - [Cargo и crates.io](https://llmdocs.ru/wiki/cargo.md) - [Go vs Rust — сравнение](https://llmdocs.ru/wiki/go-vs-rust.md) - [Сборка мусора vs ручное управление памятью](https://llmdocs.ru/wiki/gc-vs-manual-memory.md) ## Источники 1. [The Rust Programming Language (книга)](https://doc.rust-lang.org/book/) 2. [Announcing Rust 1.0 — Rust Blog](https://blog.rust-lang.org/2015/05/15/Rust-1.0.html) 3. [Rust Foundation — About](https://foundation.rust-lang.org/about/) 4. [The Rust Edition Guide](https://doc.rust-lang.org/edition-guide/) 5. [Rust for Linux](https://rust-for-linux.com/) 6. [Rust Release Train (6-week cycle)](https://doc.rust-lang.org/book/appendix-07-nightly-rust.html) --- # Unsafe Rust > Подмножество Rust, в котором программист берёт на себя гарантии, обычно проверяемые компилятором, — разыменование сырых указателей, вызов FFI, unsafe-функции и трейты; основа безопасных абстракций стандартной библиотеки. Источник: https://llmdocs.ru/wiki/unsafe-rust/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Язык**: Rust - **Ключевое слово**: unsafe (блоки, функции, трейты, impl, extern-блоки) - **Пять «суперспособностей»**: сырые указатели, unsafe-функции, изменяемые static, unsafe-трейты, поля union - **Что не отключается**: проверка заимствований, типов, времён жизни для обычных ссылок - **Инструменты проверки**: Miri, санитайзеры, cargo-geiger - **Справочник**: The Rustonomicon **Unsafe Rust** — часть языка [Rust](https://llmdocs.ru/wiki/rust.md), в которой программист обещает компилятору соблюдать инварианты, которые тот не может проверить сам. Обычный («безопасный») Rust гарантирует отсутствие висячих указателей, гонок данных и выхода за границы через систему [владения и заимствования](https://llmdocs.ru/wiki/ownership-borrowing.md). Но некоторые вещи — работа с железом, вызов библиотек на C, реализация эффективных структур данных — принципиально требуют операций, корректность которых компилятор доказать не может. Для них есть ключевое слово `unsafe`.[1] ## Что разрешает unsafe `unsafe` не выключает проверки Rust: заимствования, типы и времена жизни обычных ссылок проверяются как всегда. Он лишь открывает пять дополнительных возможностей:[1] 1. разыменовывать **сырые указатели** `*const T` и `*mut T`; 2. вызывать **unsafe-функции**, включая функции из других языков (FFI); 3. читать и изменять **изменяемые статические** переменные (`static mut`); 4. реализовывать **unsafe-трейты** (например, `Send` и `Sync` вручную); 5. обращаться к полям `union`. ```rust let mut x = 10; let p = &mut x as *mut i32; // создать сырой указатель можно и в safe-коде unsafe { *p += 1; // а разыменовать — только в unsafe } assert_eq!(x, 11); ``` ## Неопределённое поведение Если внутри `unsafe` нарушить правила языка, возникает **неопределённое поведение** (UB): компилятор вправе оптимизировать код, исходя из того, что нарушения не бывает, и программа может вести себя как угодно — не только «упасть». К UB относятся:[3] - разыменование висячего, нулевого или невыровненного указателя; - гонка данных; - одновременное существование `&mut T` и другой ссылки на те же данные; - создание недопустимого значения: `bool`, отличного от 0 и 1, неинициализированной памяти как целого числа, невалидного UTF-8 в `str`; - вызов функции с неверным ABI. Важная мысль Rustonomicon: ошибка может быть *в безопасном коде рядом*, если он нарушает инвариант, на который опирается `unsafe`-блок.[2] Поэтому границей «опасной зоны» на практике считается модуль, а не блок. ## Безопасные абстракции Главный приём — инкапсулировать `unsafe` внутри функции или типа с **безопасным интерфейсом**, который невозможно использовать неправильно. Вся стандартная библиотека устроена так: `Vec`, `String`, `HashMap`, `Rc`, `Mutex` внутри используют сырые указатели и ручное управление памятью, но снаружи безопасны. ```rust pub fn split_at_mut(s: &mut [T], mid: usize) -> (&mut [T], &mut [T]) { let len = s.len(); let ptr = s.as_mut_ptr(); assert!(mid <= len); // проверка делает unsafe-код корректным // SAFETY: части не пересекаются, обе лежат внутри исходного среза. unsafe { ( std::slice::from_raw_parts_mut(ptr, mid), std::slice::from_raw_parts_mut(ptr.add(mid), len - mid), ) } } ``` Принятые соглашения:[7] - каждый `unsafe`-блок сопровождается комментарием `// SAFETY:` с объяснением, почему он корректен; - у каждой `unsafe fn` в документации есть раздел `# Safety` с условиями, которые должен выполнить вызывающий; - линт Clippy `undocumented_unsafe_blocks` следит за этим (см. [Clippy и rustfmt](https://llmdocs.ru/wiki/clippy-rustfmt.md)). В редакции Rust 2024 тело `unsafe fn` больше не считается одним большим unsafe-блоком: опасные операции внутри неё тоже нужно оборачивать в `unsafe { }`, а блоки `extern` пишутся как `unsafe extern "C"`.[5] ## FFI Вызов функций из библиотек на C — самая частая причина использовать `unsafe`: ```rust unsafe extern "C" { fn strlen(s: *const std::ffi::c_char) -> usize; } let s = std::ffi::CString::new("привет").unwrap(); let n = unsafe { strlen(s.as_ptr()) }; // 12 байт в UTF-8 ``` Компилятор не знает, что делает чужой код, поэтому ответственность за корректные аргументы лежит на программисте. Обёртки генерируют инструменты `bindgen` (из заголовков C) и `cxx` (для C++), а для экспорта Rust в C — `cbindgen`. Через тот же механизм Rust встраивается в [Python](https://llmdocs.ru/wiki/python.md) (PyO3) и компилируется в [WebAssembly](https://llmdocs.ru/wiki/webassembly.md). ## Сколько unsafe в реальном коде Исследование 2020 года по крейтам crates.io показало, что около 76 % крейтов не содержат `unsafe` вовсе, а в остальных он сосредоточен в небольших участках — чаще всего для FFI и оптимизаций.[6] Посчитать `unsafe` в зависимостях проекта помогает `cargo-geiger`. ## Как проверять - **Miri** — интерпретатор промежуточного представления Rust, который во время выполнения тестов обнаруживает многие виды UB: выход за границы, использование после освобождения, нарушения правил алиасинга:[4] ```bash rustup +nightly component add miri cargo +nightly miri test ``` - **Санитайзеры** (AddressSanitizer, ThreadSanitizer) через флаги nightly-компилятора. - **Фаззинг** (`cargo fuzz`) для кода, разбирающего внешние данные. - Ревью: `unsafe`-код проверяют особенно тщательно, многие проекты запрещают его атрибутом `#![forbid(unsafe_code)]`. ## Unsafe и безопасность памяти Наличие `unsafe` не отменяет преимуществ Rust перед C и C++: потенциально опасный код явно помечен, локализован и поддаётся аудиту, а остальная программа проверяется компилятором. Это противоположность языкам с ручным управлением памятью, где «опасна» любая строка (см. [Сборка мусора vs ручное управление памятью](https://llmdocs.ru/wiki/gc-vs-manual-memory.md)). ## См. также - [Владение и заимствование (Rust)](https://llmdocs.ru/wiki/ownership-borrowing.md) - [Макросы Rust](https://llmdocs.ru/wiki/rust-macros.md) - [Rust (язык)](https://llmdocs.ru/wiki/rust.md) - [Go vs Rust — сравнение](https://llmdocs.ru/wiki/go-vs-rust.md) ## Источники 1. [The Rust Programming Language — Unsafe Rust](https://doc.rust-lang.org/book/ch20-01-unsafe-rust.html) 2. [The Rustonomicon](https://doc.rust-lang.org/nomicon/) 3. [The Rust Reference — Behavior considered undefined](https://doc.rust-lang.org/reference/behavior-considered-undefined.html) 4. [Miri — an interpreter for Rust's mid-level IR](https://github.com/rust-lang/miri) 5. [Rust 2024 Edition Guide — Unsafe extern blocks and unsafe_op_in_unsafe_fn](https://doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html) 6. [Astrauskas et al. — How do programmers use unsafe Rust? (OOPSLA 2020)](https://doi.org/10.1145/3428204) 7. [Rust API Guidelines — Documentation (Safety sections)](https://rust-lang.github.io/api-guidelines/documentation.html) --- # WebAssembly > Переносимый двоичный формат инструкций для безопасного и быстрого выполнения кода в браузере и за его пределами; цель компиляции для Rust, C, C++, Go и других языков. Источник: https://llmdocs.ru/wiki/webassembly/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: двоичный формат инструкций для стековой виртуальной машины - **Разработчики**: W3C WebAssembly Community Group (Mozilla, Google, Microsoft, Apple и др.) - **Анонс**: 2015 - **Поддержка в браузерах**: 2017 (MVP) - **Рекомендация W3C**: декабрь 2019 - **Вне браузера**: WASI, среды wasmtime, Wasmer, WasmEdge - **Исходные языки**: Rust, C, C++, Go, Zig, C#, Kotlin и др. - **Форматы**: двоичный .wasm, текстовый .wat **WebAssembly** (сокращённо **Wasm**) — переносимый двоичный формат инструкций для виртуальной машины, позволяющий выполнять в браузере код, скомпилированный из [Rust](https://llmdocs.ru/wiki/rust.md), C, C++, [Go](https://llmdocs.ru/wiki/go.md) и других языков, со скоростью, близкой к нативной. Wasm работает в той же песочнице, что и [JavaScript](https://llmdocs.ru/wiki/javascript.md), и дополняет его там, где нужна производительность: обработка изображений и видео, игры, CAD-системы, криптография, запуск языковых моделей и баз данных прямо в браузере. За пределами браузера WebAssembly используется как лёгкая и безопасная среда выполнения для плагинов, бессерверных функций и пограничных вычислений. ## История Попытки ускорить веб предпринимались давно: Google Native Client (NaCl) выполнял машинный код в песочнице, а Mozilla asm.js — строгое подмножество JavaScript, которое движки умели оптимизировать. В 2015 году инженеры Mozilla, Google, Microsoft и Apple объявили о совместной работе над новым форматом, вобравшим опыт обоих подходов. В 2017 году минимальная версия (MVP) появилась во всех основных браузерах, тогда же вышла статья с описанием дизайна.[5] В декабре 2019 года W3C утвердил WebAssembly как рекомендацию — четвёртый язык веба после HTML, CSS и JavaScript.[4] Затем стандарт расширялся: SIMD, потоки и разделяемая память, подсчёт ссылок на объекты хоста, хвостовые вызовы, исключения, встроенная сборка мусора для управляемых языков (Kotlin, Java, Dart) и 64-битная память.[2] ## Как устроен - **Стековая виртуальная машина** с небольшим набором инструкций над целыми и дробными числами; код проверяется перед выполнением и компилируется движком в машинный код. - **Линейная память** — непрерывный массив байтов, к которому модуль обращается по смещениям; выйти за её пределы невозможно. - **Модули** импортируют функции из окружения (например, JavaScript-функции браузера) и экспортируют свои. Сам по себе Wasm не имеет доступа к DOM, сети или файлам — только к тому, что явно передал хост. - **Форматы**: компактный двоичный `.wasm` и текстовый `.wat` для чтения и отладки. ```wat (module (func (export "add") (param i32 i32) (result i32) local.get 0 local.get 1 i32.add)) ``` ## Пример: Rust в браузере ```rust // src/lib.rs use wasm_bindgen::prelude::*; #[wasm_bindgen] pub fn fib(n: u32) -> u64 { let (mut a, mut b) = (0u64, 1u64); for _ in 0..n { (a, b) = (b, a + b); } a } ``` ```bash cargo install wasm-pack wasm-pack build --target web # собирает .wasm и обёртку на JavaScript ``` ```javascript import init, { fib } from "./pkg/my_lib.js"; await init(); console.log(fib(90)); // вычисление внутри WebAssembly ``` Инструмент wasm-bindgen генерирует связующий код между Rust и JavaScript, преобразуя строки, массивы и объекты. Для C и C++ ту же роль играет Emscripten, а Go компилирует в Wasm встроенными средствами (`GOOS=js GOARCH=wasm`) и через TinyGo.[3] ## За пределами браузера **WASI** (*WebAssembly System Interface*) — стандартный интерфейс для доступа Wasm-модулей к файлам, часам, сети и случайным числам вне браузера.[6] Он построен на принципе возможностей: модуль получает доступ только к тому, что ему явно выдали (например, к одному каталогу). **Компонентная модель** позволяет собирать приложения из модулей, написанных на разных языках, с типизированными интерфейсами. Применения: - **Плагины** — расширения для приложений и прокси (Envoy, Zed, Figma) без риска для хост-программы. - **Пограничные и бессерверные функции** — Cloudflare Workers, Fastly Compute: холодный старт за микросекунды против сотен миллисекунд у [контейнеров](https://llmdocs.ru/wiki/containerization.md). - **Песочница для недоверенного кода** — в том числе для кода, сгенерированного языковыми моделями. - **Переносимые утилиты** — один `.wasm` работает на любой ОС и архитектуре. Среды выполнения вне браузера: wasmtime (Bytecode Alliance), Wasmer, WasmEdge. [Docker](https://llmdocs.ru/wiki/docker.md) умеет запускать Wasm-модули рядом с контейнерами. ## Ограничения - Wasm не заменяет JavaScript: доступ к DOM идёт через JavaScript, и частые переходы через границу «JS — Wasm» стоят времени. - Размер модулей языков со сборкой мусора и большой стандартной библиотекой может быть значительным; Rust, C и Zig дают компактные модули. - Отладка и профилирование сложнее, чем для JavaScript, хотя инструменты браузеров быстро улучшаются. - Экосистема WASI и компонентной модели ещё развивается. ## См. также - [Rust (язык)](https://llmdocs.ru/wiki/rust.md) - [JavaScript](https://llmdocs.ru/wiki/javascript.md) - [Контейнеризация](https://llmdocs.ru/wiki/containerization.md) - [Компилятор и интерпретатор](https://llmdocs.ru/wiki/compiler-interpreter.md) - [Cargo и crates.io](https://llmdocs.ru/wiki/cargo.md) ## Источники 1. [WebAssembly — официальный сайт](https://webassembly.org/) 2. [WebAssembly Specification](https://webassembly.github.io/spec/) 3. [MDN — WebAssembly](https://developer.mozilla.org/en-US/docs/WebAssembly) 4. [W3C — World Wide Web Consortium (W3C) brings a new language to the Web as WebAssembly becomes a W3C Recommendation (2019)](https://www.w3.org/press-releases/2019/wasm/) 5. [A. Haas et al. — Bringing the Web up to Speed with WebAssembly (PLDI 2017)](https://dl.acm.org/doi/10.1145/3062341.3062363) 6. [WASI — WebAssembly System Interface](https://wasi.dev/) --- # Сетевые плагины (CNI) > Container Network Interface — стандарт подключения контейнеров к сети и семейство плагинов (Calico, Cilium, Flannel), реализующих сеть подов в Kubernetes. Источник: https://llmdocs.ru/wiki/cni/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Полное название**: Container Network Interface - **Появление**: 2015 (CoreOS), проект CNCF с 2017 - **Тип**: спецификация + библиотека + плагины - **Конфигурация**: /etc/cni/net.d/ - **Плагины**: /opt/cni/bin/ - **Популярные реализации**: Cilium, Calico, Flannel, Weave Net (архив), Antrea - **Связанное**: NetworkPolicy, kube-proxy, eBPF **CNI** (*Container Network Interface*) — открытая спецификация, описывающая, как среда выполнения контейнеров подключает контейнер к сети: создаёт сетевой интерфейс, выдаёт IP-адрес, настраивает маршруты и затем освобождает всё это при удалении. Сам [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) сеть подов не реализует — он вызывает **CNI-плагин**, выбранный при установке кластера. От плагина зависят производительность сети, поддержка сетевых политик, шифрование трафика между узлами и наблюдаемость. ## Сетевая модель Kubernetes Kubernetes требует от сети трёх свойств:[2] 1. каждый [Pod](https://llmdocs.ru/wiki/pod.md) получает собственный IP-адрес; 2. поды на любых узлах общаются друг с другом напрямую, без [NAT](https://llmdocs.ru/wiki/nat.md); 3. агенты на узле (kubelet) видят все поды этого узла. Как именно это обеспечить — задача плагина. Адреса подов выделяются из отдельного диапазона (например, `10.244.0.0/16`, см. [IP-адрес и подсети (CIDR)](https://llmdocs.ru/wiki/ip-cidr.md)), обычно каждому узлу достаётся своя подсеть. ## Как работает CNI Спецификация очень проста: плагин — исполняемый файл в `/opt/cni/bin/`, который среда выполнения (containerd, CRI-O) вызывает с командой `ADD`, `DEL` или `CHECK` в переменной окружения и JSON-конфигурацией из `/etc/cni/net.d/` на стандартном вводе.[1] В ответ плагин возвращает назначенный адрес. Плагины можно выстраивать в цепочку: один создаёт интерфейс, другой выделяет адрес (IPAM), третий настраивает ограничение полосы. Внутри типичная схема такова: для пода создаётся пара виртуальных интерфейсов `veth` — один конец в сетевом пространстве имён пода (см. [Namespaces и cgroups](https://llmdocs.ru/wiki/namespaces-cgroups.md)), другой на узле. Дальше пакеты между узлами передаются одним из способов: | Способ | Как | Плюсы и минусы | |---|---|---| | Оверлей (VXLAN, Geneve) | пакеты подов упаковываются в UDP между узлами | работает в любой сети; накладные расходы и меньший MTU | | Прямая маршрутизация (BGP) | маршруты к подсетям подов анонсируются в сеть | без инкапсуляции, быстро; нужна поддержка сети | | Нативная сеть облака | поды получают адреса из сети VPC | интеграция с облаком; расход адресов | ## Популярные плагины - **Flannel** — простейший вариант: оверлей VXLAN, без сетевых политик. Используется по умолчанию в [k3s](https://llmdocs.ru/wiki/k3s.md).[6] - **Calico** — маршрутизация через BGP или оверлей, развитые сетевые политики, режимы на iptables и eBPF. Один из самых распространённых плагинов в продакшене.[5] - **Cilium** — построен на **eBPF**: программы в ядре Linux обрабатывают пакеты без длинных цепочек iptables. Может полностью заменить kube-proxy, поддерживает политики на уровне L7 (HTTP, gRPC), прозрачное шифрование WireGuard и наблюдаемость через Hubble. Выпускник CNCF и выбор по умолчанию во многих управляемых кластерах.[4] - **Облачные плагины** — AWS VPC CNI, Azure CNI, GKE Dataplane V2 (на базе Cilium). - **Multus** — метаплагин, позволяющий подключить к поду несколько сетей; используется в телекоме. ## Сетевые политики По умолчанию любой под может обращаться к любому. Объект **NetworkPolicy** ограничивает трафик по меткам подов, пространствам имён и портам — это базовый инструмент сегментации и принципа наименьших привилегий.[3] ```yaml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: db-allow-api spec: podSelector: matchLabels: {app: postgres} policyTypes: [Ingress] ingress: - from: - podSelector: matchLabels: {app: api} ports: - port: 5432 ``` Важно: политики применяет именно CNI-плагин. Если плагин их не поддерживает (как Flannel), объекты создадутся без ошибок, но ничего не будут блокировать. ## CNI и сервисы CNI отвечает за связность подов, а виртуальные адреса [Service](https://llmdocs.ru/wiki/service-ingress.md) и [балансировку](https://llmdocs.ru/wiki/load-balancing.md) между подами обычно реализует kube-proxy через iptables или IPVS. Плагины на eBPF (Cilium, Calico eBPF) берут эту функцию на себя и заметно ускоряют кластеры с тысячами сервисов. Шифрование и политики уровня приложений частично пересекаются с возможностями [Service mesh](https://llmdocs.ru/wiki/service-mesh.md). ## Диагностика ```bash kubectl get pods -n kube-system # поды плагина (cilium, calico-node) ls /etc/cni/net.d/ # активная конфигурация на узле kubectl run tmp --rm -it --image=nicolaka/netshoot -- bash cilium status && cilium connectivity test ``` Если узел в статусе `NotReady` с сообщением «network plugin is not ready», чаще всего плагин ещё не установлен или его под на этом узле не запустился. ## См. также - [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) - [Service и Ingress](https://llmdocs.ru/wiki/service-ingress.md) - [Namespaces и cgroups](https://llmdocs.ru/wiki/namespaces-cgroups.md) - [Service mesh](https://llmdocs.ru/wiki/service-mesh.md) ## Источники 1. [CNI — Container Network Interface specification](https://www.cni.dev/docs/spec/) 2. [Kubernetes Docs — Cluster Networking](https://kubernetes.io/docs/concepts/cluster-administration/networking/) 3. [Kubernetes Docs — Network Policies](https://kubernetes.io/docs/concepts/services-networking/network-policies/) 4. [Cilium Documentation](https://docs.cilium.io/) 5. [Calico Documentation](https://docs.tigera.io/calico/latest/about/) 6. [Flannel — репозиторий](https://github.com/flannel-io/flannel) --- # ConfigMap и Secret > Объекты Kubernetes для передачи конфигурации в поды — ConfigMap хранит обычные настройки, Secret предназначен для паролей, токенов и ключей. Источник: https://llmdocs.ru/wiki/configmap-secret/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: объекты API Kubernetes (core/v1) - **Хранилище**: etcd - **Максимальный размер**: 1 МиБ на объект - **Способы передачи**: переменные окружения, файлы в томе, аргументы команды - **Неизменяемые объекты**: поле immutable (стабильно с 1.21) - **Шифрование в etcd**: по умолчанию выключено, включается EncryptionConfiguration - **Внешние решения**: Sealed Secrets, External Secrets Operator, HashiCorp Vault, SOPS **ConfigMap** и **Secret** — объекты [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md), которые отделяют конфигурацию приложения от его образа. Один и тот же [образ](https://llmdocs.ru/wiki/oci-image.md) запускается в тестовом и боевом окружении, а различия — адрес базы, уровень логирования, ключи внешних API — подставляются при старте [пода](https://llmdocs.ru/wiki/pod.md). ConfigMap предназначен для обычных настроек,[1] Secret — для чувствительных данных: паролей, токенов, TLS-сертификатов, ключей доступа к реестру образов.[2] ## Зачем Принцип «конфигурация хранится в окружении, а не в коде» сформулирован в методологии Twelve-Factor App.[6] Kubernetes реализует его так: конфигурация — отдельный объект в API кластера, который можно менять, версионировать и подключать к любому числу подов. Код не пересобирается ради смены одного параметра, а секреты не попадают в слои образа и в историю [Git](https://llmdocs.ru/wiki/git.md). ## ConfigMap ConfigMap — это словарь «ключ → строка». Значением может быть и короткий параметр, и целый файл конфигурации. ```yaml apiVersion: v1 kind: ConfigMap metadata: name: web-config data: LOG_LEVEL: info FEATURE_X: "true" nginx.conf: | server { listen 8080; location / { proxy_pass http://127.0.0.1:8000; } } ``` Числа и логические значения в `data` нужно брать в кавычки — там допускаются только строки. Для двоичных данных есть поле `binaryData`. ## Secret Устроен так же, но значения в поле `data` записываются в кодировке Base64, а в `stringData` можно писать открытым текстом — API сам их закодирует. У Secret есть типы, задающие ожидаемые ключи: | Тип | Назначение | |---|---| | `Opaque` | произвольные данные (по умолчанию) | | `kubernetes.io/tls` | сертификат и ключ: `tls.crt`, `tls.key` (используется [Ingress](https://llmdocs.ru/wiki/service-ingress.md)) | | `kubernetes.io/dockerconfigjson` | учётные данные для закрытого реестра образов | | `kubernetes.io/basic-auth`, `ssh-auth` | логин и пароль, SSH-ключ | | `kubernetes.io/service-account-token` | токен сервисного аккаунта (устаревший способ) | ```bash kubectl create secret generic db --from-literal=PASSWORD='s3cr3t' kubectl create secret tls example-com --cert=fullchain.pem --key=privkey.pem kubectl get secret db -o jsonpath='{.data.PASSWORD}' | base64 -d ``` **Base64 — не шифрование.** Любой, кто может прочитать объект через API, получит секрет в открытом виде. По умолчанию Secret хранится в etcd незашифрованным; шифрование «на диске» включают отдельной настройкой API-сервера (EncryptionConfiguration), в том числе с ключом во внешнем KMS.[4] Главная защита — права доступа RBAC: чтение секретов разрешают только тем сервисным аккаунтам и людям, которым это действительно нужно.[3] ## Как передать в под ```yaml spec: containers: - name: app image: ghcr.io/example/web:1.4.0 envFrom: - configMapRef: {name: web-config} # все ключи как переменные env: - name: DB_PASSWORD valueFrom: secretKeyRef: {name: db, key: PASSWORD} volumeMounts: - name: nginx-conf mountPath: /etc/nginx/conf.d volumes: - name: nginx-conf configMap: name: web-config items: [{key: nginx.conf, path: default.conf}] ``` Два способа ведут себя по-разному при изменении объекта: - **[Переменные окружения](https://llmdocs.ru/wiki/environment-variables.md)** читаются только при старте контейнера. Чтобы применить новое значение, поды нужно перезапустить, например `kubectl rollout restart deployment/web`. - **Файлы в томе** kubelet обновляет автоматически (с задержкой до минуты), но приложение должно само перечитать файл. Исключение — тома, смонтированные через `subPath`: они не обновляются. Популярный приём — добавить в аннотацию шаблона пода хеш конфигурации: при её изменении меняется шаблон, и [Deployment](https://llmdocs.ru/wiki/deployment-replicaset.md) сам выполняет плавное обновление. Так делают многие чарты [Helm](https://llmdocs.ru/wiki/helm.md). С версии 1.21 объект можно пометить `immutable: true`: его нельзя изменить, только пересоздать, а kubelet перестаёт следить за ним — это снижает нагрузку на API-сервер в больших кластерах и защищает от случайных правок.[1] ## Секреты и Git Хранить манифесты Secret в репозитории в открытом виде нельзя: Base64 раскодирует кто угодно. Распространённые решения: - **Sealed Secrets** — секрет шифруется открытым ключом контроллера в кластере; в Git лежит зашифрованный `SealedSecret`, расшифровать его может только кластер. - **SOPS** — шифрует значения в YAML-файлах ключами age, PGP или облачного KMS; удобно в связке с GitOps (Argo CD, Flux). - **External Secrets Operator** — синхронизирует секреты из внешнего хранилища (HashiCorp Vault, AWS Secrets Manager, Yandex Lockbox и др.) в объекты Secret.[5] - **CSI-драйвер Secrets Store** — монтирует секреты из хранилища прямо в под, минуя etcd. Подробнее о подходах — в статье [Управление секретами](https://llmdocs.ru/wiki/secrets-management.md). ## Ограничения - Размер одного объекта — не больше 1 МиБ: для больших файлов нужен [PersistentVolume](https://llmdocs.ru/wiki/persistentvolume.md) или образ. - ConfigMap и Secret принадлежат пространству имён и доступны только подам из него же. - Под не запустится, если указанный ConfigMap или Secret отсутствует (если ссылка не помечена `optional: true`). - Секрет, переданный через переменную окружения, может утечь в логи, дампы и вывод отладочных инструментов; файлы в томе безопаснее. ## См. также - [Pod](https://llmdocs.ru/wiki/pod.md) - [kubectl](https://llmdocs.ru/wiki/kubectl.md) - [Аутентификация и авторизация](https://llmdocs.ru/wiki/authn-authz.md) - [Helm](https://llmdocs.ru/wiki/helm.md) ## Источники 1. [Kubernetes Docs — ConfigMaps](https://kubernetes.io/docs/concepts/configuration/configmap/) 2. [Kubernetes Docs — Secrets](https://kubernetes.io/docs/concepts/configuration/secret/) 3. [Kubernetes Docs — Good practices for Kubernetes Secrets](https://kubernetes.io/docs/concepts/security/secrets-good-practices/) 4. [Kubernetes Docs — Encrypting Confidential Data at Rest](https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/) 5. [External Secrets Operator](https://external-secrets.io/) 6. [The Twelve-Factor App — III. Config](https://12factor.net/config) --- # Container registry > Сервер, который хранит и раздаёт образы контейнеров по протоколу OCI Distribution; примеры — Docker Hub, GitHub Container Registry, Harbor. Источник: https://llmdocs.ru/wiki/container-registry/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Стандарт**: OCI Distribution Specification (1.0 — 2021) - **Протокол**: HTTP API поверх TLS - **Адресация образа**: реестр/пространство/имя:тег или @sha256:дайджест - **Публичные**: Docker Hub, GHCR, Quay.io, Amazon ECR Public - **Облачные**: Amazon ECR, Google Artifact Registry, Azure ACR, Yandex Container Registry - **Свои**: Harbor, GitLab Container Registry, Distribution (registry:2), Zot **Container registry** (реестр контейнеров) — сервер, на котором хранятся [образы контейнеров](https://llmdocs.ru/wiki/oci-image.md) и с которого их скачивают. Команда `docker push` отправляет собранный образ в реестр, а `docker pull` — или [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) при запуске пода — забирает его оттуда. Реестр — связующее звено между сборкой в [CI/CD](https://llmdocs.ru/wiki/ci-cd.md) и запуском в продакшене: CI публикует образ с версией, а кластер разворачивает именно её. ## Как устроен Реестр реализует HTTP API, стандартизированный как **OCI Distribution Specification** (на основе Docker Registry HTTP API V2).[1] Образ хранится не как один файл, а как набор объектов, адресуемых по хешу SHA-256 (content-addressable storage): - **блобы** — слои файловой системы (tar.gz) и конфигурация; - **манифест** — JSON со списком слоёв и их дайджестов; - **индекс** (manifest list) — список манифестов для разных архитектур (`linux/amd64`, `linux/arm64`). Одинаковые слои хранятся один раз и не скачиваются повторно, если уже есть на машине. Основные операции API: `GET /v2/<имя>/manifests/<ссылка>`, `GET /v2/<имя>/blobs/<дайджест>`, загрузка блобов через `POST`/`PUT`. ## Имена образов Полное имя образа: ``` ghcr.io/acme/api:1.4.2 └─реестр─┘└─репозиторий─┘└тег┘ ghcr.io/acme/api@sha256:9f86d081884c7d65... # по дайджесту ``` Если реестр не указан, Docker подставляет `docker.io`, а для официальных образов — ещё и `library/` (`nginx` = `docker.io/library/nginx`). **Тег** — изменяемая метка: `latest` или `1.4` сегодня и завтра могут указывать на разные образы. **Дайджест** неизменен, поэтому для воспроизводимых развёртываний образы фиксируют по нему или используют неизменяемые теги с [версией](https://llmdocs.ru/wiki/semver.md) и хешем коммита. ## Популярные реестры | Реестр | Особенности | |---|---| | **Docker Hub** | реестр по умолчанию, официальные образы; ограничения частоты скачивания для анонимных и бесплатных пользователей[3] | | **GitHub Container Registry** (`ghcr.io`) | привязан к репозиториям и [GitHub Actions](https://llmdocs.ru/wiki/github-actions.md), бесплатен для публичных образов[4] | | **Quay.io** | реестр Red Hat со сканированием уязвимостей | | **Amazon ECR, Google Artifact Registry, Azure ACR** | интеграция с IAM и кластерами своего облака | | **GitLab Container Registry** | встроен в [GitLab](https://llmdocs.ru/wiki/gitlab.md) и GitLab CI | | **Harbor** | open source, проект CNCF: проекты, RBAC, сканирование, репликация, прокси-кэш[5] | | **Distribution (`registry:2`)**, **Zot** | минимальные самостоятельные реестры | ## Работа с реестром ```bash docker login ghcr.io -u USER --password-stdin < token.txt docker build -t ghcr.io/acme/api:1.4.2 . docker push ghcr.io/acme/api:1.4.2 # мультиархитектурный образ docker buildx build --platform linux/amd64,linux/arm64 \ -t ghcr.io/acme/api:1.4.2 --push . # свой реестр для тестов docker run -d -p 5000:5000 --name registry registry:2 ``` Утилиты **skopeo** и **crane** копируют образы между реестрами и смотрят манифесты без скачивания слоёв. Чтобы Kubernetes скачивал образы из приватного реестра, создают секрет типа `docker-registry` и указывают его в `imagePullSecrets` пода (см. [ConfigMap и Secret](https://llmdocs.ru/wiki/configmap-secret.md)). ## Безопасность - **Сканирование уязвимостей** — Trivy, Grype или встроенные сканеры Harbor, ECR и Quay проверяют пакеты в слоях по базам CVE. - **Подпись образов** — `cosign` из проекта Sigstore подписывает образ по дайджесту; подпись хранится в том же реестре, а политика в кластере (Kyverno, policy-controller) не пускает неподписанные образы.[6] - **SBOM и аттестации** — список компонентов и сведения о сборке прикладываются к образу как OCI-артефакты. - **Секреты** — пароли и ключи не должны попадать в слои образа: даже удалённый в следующем слое файл остаётся в истории (решение — [многоэтапная сборка](https://llmdocs.ru/wiki/multi-stage-build.md) и секреты BuildKit). ## Эксплуатация Реестр быстро растёт: каждый пуш оставляет слои. Нужны **политики хранения** (удалять теги старше N дней, оставлять последние M версий) и сборка мусора для неиспользуемых блобов. **Прокси-кэш** (pull-through cache) перед Docker Hub снижает зависимость от внешнего сервиса и его лимитов. Помимо образов, реестры OCI сегодня хранят Helm-чарты (`helm push oci://...`), WebAssembly-модули и даже веса моделей машинного обучения. ## См. также - [Образ контейнера и OCI](https://llmdocs.ru/wiki/oci-image.md) - [Docker](https://llmdocs.ru/wiki/docker.md) - [Dockerfile](https://llmdocs.ru/wiki/dockerfile.md) - [GitHub Actions](https://llmdocs.ru/wiki/github-actions.md) ## Источники 1. [OCI Distribution Specification](https://github.com/opencontainers/distribution-spec/blob/main/spec.md) 2. [Docker Docs — Docker Hub](https://docs.docker.com/docker-hub/) 3. [Docker Docs — Usage and rate limits](https://docs.docker.com/docker-hub/usage/) 4. [GitHub Docs — Working with the Container registry](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry) 5. [Harbor — официальный сайт](https://goharbor.io/) 6. [Sigstore — cosign](https://docs.sigstore.dev/cosign/signing/overview/) --- # Контейнеризация > Способ упаковки приложения вместе со всеми зависимостями в изолированный контейнер, который запускается на общем ядре ОС; легче и быстрее виртуальных машин. Источник: https://llmdocs.ru/wiki/containerization/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Принцип**: изоляция процессов на общем ядре ОС - **Механизмы Linux**: namespaces, cgroups, capabilities, seccomp, overlay-файловые системы - **Предшественники**: chroot (1979), FreeBSD jails (2000), Solaris Zones (2004), LXC (2008) - **Массовое распространение**: Docker (2013) - **Стандарт**: Open Container Initiative (OCI, с 2015) - **Оркестрация**: Kubernetes, Docker Swarm, Nomad - **Инструменты**: Docker, Podman, containerd, CRI-O **Контейнеризация** — способ упаковать приложение вместе с его зависимостями (библиотеками, интерпретатором, конфигурацией) в **контейнер** — изолированную среду, которая одинаково запускается на ноутбуке разработчика, тестовом сервере и в облаке. В отличие от виртуальной машины, контейнер не содержит собственного ядра операционной системы: все контейнеры на хосте используют общее ядро, а изоляция обеспечивается его механизмами. Поэтому контейнеры запускаются за доли секунды и расходуют мало ресурсов. Контейнеры — основа современной разработки и эксплуатации: приложения поставляются как образы [Docker](https://llmdocs.ru/wiki/docker.md), собираются по [Dockerfile](https://llmdocs.ru/wiki/dockerfile.md), запускаются локально через [Docker Compose](https://llmdocs.ru/wiki/docker-compose.md) и в продакшене — под управлением [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md). ## Зачем нужны контейнеры - **«У меня работает».** Образ содержит всё нужное приложению, поэтому разница между средами разработки и продакшена исчезает. - **Изоляция зависимостей.** На одном сервере уживаются сервисы с несовместимыми версиями [Python](https://llmdocs.ru/wiki/python.md), библиотек и системных пакетов. - **Плотность и скорость.** Десятки контейнеров на одном сервере вместо нескольких виртуальных машин; запуск — за секунды. - **Неизменяемость.** Образ собирается один раз и разворачивается без изменений; обновление — это замена контейнера новым, а откат — запуск предыдущей версии образа. - **Единый формат поставки** для CI/CD, облаков и оркестраторов.[4] ## Контейнеры и виртуальные машины | | Виртуальная машина | Контейнер | |---|---|---| | Что виртуализируется | оборудование | окружение процесса | | Ядро ОС | своё в каждой ВМ | общее с хостом | | Размер образа | гигабайты | мегабайты — сотни мегабайт | | Запуск | десятки секунд — минуты | доли секунды | | Изоляция | сильная (гипервизор) | слабее (общее ядро) | | Другая ОС | любая | только совместимая с ядром хоста | Контейнер Linux нельзя напрямую запустить на ядре Windows или macOS — Docker Desktop на этих системах тайно запускает небольшую виртуальную машину с [Linux](https://llmdocs.ru/wiki/linux.md). Если нужна более сильная изоляция, используют гибриды: gVisor перехватывает системные вызовы, а Kata Containers и Firecracker запускают каждый контейнер в лёгкой виртуальной машине. ## Как устроен контейнер в Linux Контейнер — это обычный процесс, на который ядро наложило ограничения (см. [Namespaces и cgroups](https://llmdocs.ru/wiki/namespaces-cgroups.md)): - **Namespaces** (пространства имён) ограничивают то, что процесс *видит*: собственное дерево процессов (PID), сетевые интерфейсы (net), точки монтирования (mnt), имя хоста (UTS), пользователей (user), IPC.[1] - **Cgroups** (контрольные группы) ограничивают то, сколько процесс *потребляет*: память, процессор, ввод-вывод, число процессов.[2] - **Capabilities, seccomp, AppArmor/SELinux** урезают привилегии: даже root внутри контейнера не может загружать модули ядра или менять системное время (см. [Права доступа в Unix](https://llmdocs.ru/wiki/unix-permissions.md)). - **Многослойная файловая система** (overlayfs) собирает корневую ФС контейнера из слоёв образа, доступных только для чтения, и тонкого слоя для записи. ```bash docker run --rm -it --memory 256m --cpus 0.5 alpine sh # внутри: ps aux покажет только процессы контейнера, hostname — свой ``` ## История Идея изоляции появилась задолго до Docker. Системный вызов `chroot` (Unix V7, 1979) подменял корневой каталог процесса. В 2000 году FreeBSD добавила **jails** — изолированные окружения с собственными пользователями и сетью,[5] в 2004 году Sun представила Solaris Zones. В Linux механизмы появлялись постепенно: namespaces с 2002 года, cgroups — разработка инженеров Google, вошедшая в ядро в 2008 году. В том же году появился LXC, собравший их в удобный инструмент. Прорывом стал **Docker** (2013): он добавил простой формат образов со слоями, Dockerfile и публичный реестр Docker Hub, превратив контейнеры из инструмента администраторов в инструмент разработчиков. В 2014 году Google открыла [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md), а в 2015 году индустрия создала **Open Container Initiative** (OCI), которая стандартизировала формат образов и среды выполнения, чтобы контейнеры не зависели от одного поставщика.[3] ## Экосистема | Слой | Что делает | Примеры | |---|---|---| | Сборка | образ по описанию | Docker Build (BuildKit), Buildah, kaniko | | Хранение | реестр образов | Docker Hub, GitHub Container Registry, Harbor (см. [Container registry](https://llmdocs.ru/wiki/container-registry.md)) | | Запуск низкого уровня | создаёт процесс с namespaces и cgroups | runc, crun | | Среда выполнения | управляет образами и контейнерами | containerd, CRI-O | | Инструменты разработчика | CLI и локальная работа | Docker, [Podman](https://llmdocs.ru/wiki/podman.md), nerdctl | | Оркестрация | кластер, масштабирование, самовосстановление | [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md), Nomad, Docker Swarm | Формат описан в статье [Образ контейнера и OCI](https://llmdocs.ru/wiki/oci-image.md). Kubernetes с 2022 года работает с containerd или CRI-O напрямую, без Docker, но образы, собранные Docker, остаются совместимыми благодаря OCI.[6] ## Хорошие практики - Один процесс (одна ответственность) на контейнер; логи — в стандартный вывод. - Минимальные базовые образы (`alpine`, `distroless`, `-slim`) и [многоэтапная сборка](https://llmdocs.ru/wiki/multi-stage-build.md) — меньше размер и поверхность атаки. - Запуск не от root, файловая система только для чтения, где возможно. - Никаких секретов внутри образа: их передают через переменные окружения или хранилища секретов. - Состояние — в томах или внешних сервисах; сам контейнер можно в любой момент удалить и пересоздать. ## См. также - [Docker](https://llmdocs.ru/wiki/docker.md) - [Namespaces и cgroups](https://llmdocs.ru/wiki/namespaces-cgroups.md) - [Образ контейнера и OCI](https://llmdocs.ru/wiki/oci-image.md) - [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) - [Podman](https://llmdocs.ru/wiki/podman.md) ## Источники 1. [namespaces(7) — Linux manual page](https://man7.org/linux/man-pages/man7/namespaces.7.html) 2. [Linux kernel documentation — Control Group v2](https://docs.kernel.org/admin-guide/cgroup-v2.html) 3. [Open Container Initiative — About](https://opencontainers.org/about/overview/) 4. [Docker Docs — What is a container?](https://docs.docker.com/get-started/docker-concepts/the-basics/what-is-a-container/) 5. [FreeBSD Handbook — Jails](https://docs.freebsd.org/en/books/handbook/jails/) 6. [Kubernetes Documentation — Containers](https://kubernetes.io/docs/concepts/containers/) --- # Deployment и ReplicaSet > Контроллеры Kubernetes для stateless-приложений — ReplicaSet поддерживает заданное число одинаковых подов, а Deployment управляет ReplicaSet'ами и выполняет плавные обновления и откаты. Источник: https://llmdocs.ru/wiki/deployment-replicaset/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: объекты API Kubernetes (apps/v1) - **Назначение**: stateless-приложения с N одинаковыми репликами - **Стратегии обновления**: RollingUpdate (по умолчанию), Recreate - **Параметры обновления**: maxSurge, maxUnavailable (по умолчанию 25%) - **История ревизий**: revisionHistoryLimit (по умолчанию 10) - **Предшественник**: ReplicationController - **Альтернативы**: StatefulSet, DaemonSet, Job **Deployment** и **ReplicaSet** — объекты [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md), которые отвечают за работу приложений без собственного состояния (*stateless*): веб-серверов, API, воркеров очередей. **ReplicaSet** гарантирует, что в кластере всегда запущено заданное число одинаковых [подов](https://llmdocs.ru/wiki/pod.md). **Deployment** стоит уровнем выше: он создаёт ReplicaSet'ы и переключается между ними при обновлении версии, обеспечивая плавное обновление без простоя и откат.[1] На практике пишут именно Deployment, а ReplicaSet почти никогда не создают вручную. ## Принцип контроллера Kubernetes построен на **цикле согласования** (*reconciliation loop*): пользователь описывает желаемое состояние, а контроллер постоянно сравнивает его с фактическим и устраняет расхождения.[3] Контроллер ReplicaSet считает поды, подходящие под его селектор меток, и если их меньше, чем `replicas`, создаёт новые по шаблону, а если больше — удаляет лишние.[2] Поэтому упавший узел или удалённый вручную под не нарушают работу: замена появится через несколько секунд на другом узле. Связь между объектами держится на **метках** (*labels*) и **селекторах**.[4] Цепочка такая: Deployment → ReplicaSet (по одному на каждую версию шаблона) → Pod'ы. ## Пример ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: web spec: replicas: 3 selector: matchLabels: app: web strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 # сколько подов сверх replicas можно создать maxUnavailable: 0 # сколько может отсутствовать во время обновления template: metadata: labels: app: web spec: containers: - name: app image: ghcr.io/example/web:1.4.0 ports: - containerPort: 8000 readinessProbe: httpGet: {path: /healthz, port: 8000} ``` Секция `template` — это шаблон пода. Селектор `matchLabels` должен совпадать с метками шаблона и после создания не меняется. ## Плавное обновление Любое изменение шаблона пода (новый образ, переменная окружения, ресурсы) запускает **выкатку** (*rollout*). Deployment создаёт новый ReplicaSet и постепенно увеличивает его, одновременно уменьшая старый: 1. Создаётся новый под (в пределах `maxSurge`). 2. Когда он проходит `readinessProbe`, удаляется один старый (в пределах `maxUnavailable`). 3. Шаги повторяются, пока все реплики не будут новыми. Значения по умолчанию — 25% для обоих параметров. Без readiness-пробы Kubernetes считает под готовым сразу после старта и может переключить трафик на ещё не готовое приложение. Стратегия **Recreate** сначала удаляет все старые поды, потом создаёт новые — с простоем, но без одновременной работы двух версий (нужно, например, при несовместимой схеме базы). Изменение только `replicas` не создаёт новую ревизию — это масштабирование, а не обновление. ## Откат и история Старые ReplicaSet'ы не удаляются, а остаются с нулём реплик — по ним можно откатиться. Сколько их хранить, задаёт `revisionHistoryLimit`.[5] ```bash kubectl apply -f deployment.yaml kubectl set image deployment/web app=ghcr.io/example/web:1.5.0 kubectl rollout status deployment/web # дождаться окончания kubectl rollout history deployment/web kubectl rollout undo deployment/web # вернуть предыдущую ревизию kubectl rollout restart deployment/web # перезапустить поды без изменения образа kubectl scale deployment/web --replicas=5 kubectl get rs -l app=web # ReplicaSet'ы всех ревизий ``` Если выкатка застряла (поды не становятся готовыми), Deployment по истечении `progressDeadlineSeconds` (600 секунд) помечает её как неуспешную, но сам не откатывается — это делают вручную или средствами CI/CD. ## Связанные механизмы - **[Автомасштабирование (HPA)](https://llmdocs.ru/wiki/hpa.md)** меняет `replicas` автоматически по нагрузке на CPU или пользовательским метрикам. - **PodDisruptionBudget** запрещает плановым операциям (обновлению узлов) одновременно снимать больше заданного числа подов.[6] - **[Service](https://llmdocs.ru/wiki/service-ingress.md)** выбирает поды по тем же меткам, поэтому трафик автоматически идёт на новые реплики. - Шаблоны манифестов для разных окружений часто упаковывают в чарты [Helm](https://llmdocs.ru/wiki/helm.md). ## Когда нужен не Deployment | Объект | Для чего | |---|---| | StatefulSet | базы данных и кластеры: стабильные имена подов (`db-0`, `db-1`) и свой [том](https://llmdocs.ru/wiki/persistentvolume.md) у каждого | | DaemonSet | по одному поду на каждом узле: агенты логов и мониторинга, сетевые плагины | | Job / CronJob | разовые и периодические задачи, которые должны завершиться | Исторически ту же роль выполнял ReplicationController; ReplicaSet заменил его, добавив селекторы на основе множеств. ## См. также - [Pod](https://llmdocs.ru/wiki/pod.md) - [kubectl](https://llmdocs.ru/wiki/kubectl.md) - [CI/CD](https://llmdocs.ru/wiki/ci-cd.md) - [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) ## Источники 1. [Kubernetes Docs — Deployments](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) 2. [Kubernetes Docs — ReplicaSet](https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/) 3. [Kubernetes Docs — Controllers](https://kubernetes.io/docs/concepts/architecture/controller/) 4. [Kubernetes Docs — Labels and Selectors](https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/) 5. [kubectl reference — rollout](https://kubernetes.io/docs/reference/kubectl/generated/kubectl_rollout/) 6. [Kubernetes Docs — Disruptions (PodDisruptionBudget)](https://kubernetes.io/docs/concepts/workloads/pods/disruptions/) --- # Docker Compose > Инструмент для описания и запуска многоконтейнерных приложений одним YAML-файлом — сервисы, сети, тома и зависимости между ними. Источник: https://llmdocs.ru/wiki/docker-compose/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: инструмент оркестрации контейнеров на одном хосте - **Разработчик**: Docker, Inc. - **Предшественник**: Fig (Orchard Labs, 2013) - **Текущая версия**: Compose V2 — плагин docker compose на Go (с 2022) - **Формат**: YAML, Compose Specification - **Файл по умолчанию**: compose.yaml - **Лицензия**: Apache 2.0 **Docker Compose** — инструмент для описания и запуска приложений из нескольких контейнеров. Вместо длинных команд `docker run` для каждого сервиса всё приложение — веб-сервер, база данных, кэш, фоновые обработчики — описывается в одном YAML-файле `compose.yaml` и поднимается одной командой `docker compose up`. Compose создаёт общую сеть, в которой сервисы находят друг друга по именам, тома для данных и следит за порядком запуска.[1] Compose — стандартный способ локальной разработки с [Docker](https://llmdocs.ru/wiki/docker.md) и простой способ развернуть небольшой проект на одном сервере. Для кластеров из многих машин используют [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md). ## История Инструмент появился в 2013 году под названием **Fig** в стартапе Orchard Labs; в 2014 году Docker купила компанию и переименовала Fig в Docker Compose. Первая версия была написана на [Python](https://llmdocs.ru/wiki/python.md) и вызывалась как `docker-compose`. В 2020 году формат файла выделили в открытую **Compose Specification**, которую поддерживают и другие инструменты, например Podman.[2] Вторая версия, переписанная на Go, стала плагином Docker CLI и вызывается без дефиса — `docker compose`; первая версия перестала поддерживаться в 2023 году.[4] ## Пример Веб-приложение с базой [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) и кэшем [Redis](https://llmdocs.ru/wiki/redis.md): ```yaml # compose.yaml services: web: build: . # собрать образ по Dockerfile в этом каталоге ports: - "8000:8000" environment: DATABASE_URL: postgresql://app:secret@db:5432/app REDIS_URL: redis://cache:6379/0 depends_on: db: condition: service_healthy # ждать, пока база реально готова cache: condition: service_started restart: unless-stopped db: image: postgres:18 environment: POSTGRES_USER: app POSTGRES_PASSWORD: secret POSTGRES_DB: app volumes: - pgdata:/var/lib/postgresql healthcheck: test: ["CMD-SHELL", "pg_isready -U app"] interval: 5s retries: 10 cache: image: redis:8-alpine volumes: pgdata: ``` Сервис `web` обращается к базе по имени `db`, а к кэшу — по имени `cache`: Compose регистрирует имена сервисов во внутреннем DNS своей сети. Порт базы наружу не опубликован, поэтому она доступна только другим контейнерам проекта. ## Основные понятия - **Сервис** — описание контейнера: образ или инструкция сборки по [Dockerfile](https://llmdocs.ru/wiki/dockerfile.md), порты, [переменные окружения](https://llmdocs.ru/wiki/environment-variables.md), тома, политика перезапуска. Сервис можно масштабировать до нескольких одинаковых контейнеров. - **Сеть** — по умолчанию Compose создаёт одну сеть на проект; можно описать несколько, чтобы изолировать, например, фронтенд от базы. - **Том** — именованное хранилище, которое переживает пересоздание контейнеров. Данные базы должны лежать в томе, иначе исчезнут при `docker compose down`. - **Проект** — набор ресурсов одного `compose.yaml`; имя проекта по умолчанию берётся из имени каталога и служит префиксом для контейнеров, сетей и томов. ## Команды ```bash docker compose up -d # собрать при необходимости и запустить в фоне docker compose ps # состояние сервисов docker compose logs -f web # логи сервиса docker compose exec db psql -U app # команда внутри работающего контейнера docker compose run --rm web pytest # разовая задача в новом контейнере docker compose up -d --build web # пересобрать и перезапустить один сервис docker compose pull && docker compose up -d # обновить образы docker compose down # остановить и удалить контейнеры и сети docker compose down -v # то же вместе с томами — данные будут потеряны docker compose config # итоговая конфигурация после подстановок ``` ## Порядок запуска `depends_on` сам по себе гарантирует только порядок *старта* контейнеров, но не готовность приложения внутри: база может ещё инициализироваться, когда веб-сервис уже пытается подключиться. Условие `condition: service_healthy` вместе с `healthcheck` у зависимости заставляет Compose ждать реальной готовности.[3] Приложению всё равно полезно уметь повторять подключение — в продакшене зависимости тоже бывают недоступны. ## Возможности для разработки - **Переменные и файл `.env`.** Значения вида `${POSTGRES_PASSWORD}` подставляются из окружения или файла `.env` рядом с `compose.yaml`; секреты не нужно хранить в самом файле. - **Несколько файлов.** `compose.override.yaml` автоматически накладывается поверх основного — удобно для локальных настроек; другие файлы подключаются флагом `-f`. - **Профили.** Сервисы с `profiles: [debug]` запускаются только по запросу (`docker compose --profile debug up`) — например, админка базы или инструменты отладки.[6] - **Watch.** Режим `docker compose watch` синхронизирует изменённые файлы в контейнер или пересобирает образ при изменении зависимостей, заменяя ручной перезапуск.[5] ## Compose в продакшене На одном сервере Compose вполне подходит для небольших проектов: `restart: unless-stopped` поднимет контейнеры после перезагрузки, а обновление сводится к `pull` и `up -d`. Ограничения — нет распределения по нескольким машинам, обновлений без простоя и автоматического восстановления на другом узле. Когда это становится важным, переходят на [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) или его облегчённые варианты вроде [k3s](https://llmdocs.ru/wiki/k3s.md); утилита Kompose помогает перевести `compose.yaml` в манифесты Kubernetes. ## См. также - [Docker](https://llmdocs.ru/wiki/docker.md) - [Dockerfile](https://llmdocs.ru/wiki/dockerfile.md) - [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) - [Контейнеризация](https://llmdocs.ru/wiki/containerization.md) - [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) ## Источники 1. [Docker Docs — Docker Compose overview](https://docs.docker.com/compose/) 2. [Compose Specification](https://compose-spec.io/) 3. [Docker Docs — Control startup order](https://docs.docker.com/compose/how-tos/startup-order/) 4. [Docker Docs — Migrate to Compose V2](https://docs.docker.com/compose/releases/migrate/) 5. [Docker Docs — Use Compose Watch](https://docs.docker.com/compose/how-tos/file-watch/) 6. [Docker Docs — Using profiles with Compose](https://docs.docker.com/compose/how-tos/profiles/) --- # Docker > Платформа для сборки, доставки и запуска приложений в контейнерах — изолированных процессах с собственной файловой системой. Источник: https://llmdocs.ru/wiki/docker/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: платформа контейнеризации - **Разработчик**: Docker, Inc. - **Первый выпуск**: март 2013 - **Написан на**: Go - **ОС**: Linux; Windows и macOS через Docker Desktop - **Компоненты**: dockerd, containerd, runc, BuildKit, CLI - **Лицензия**: Apache 2.0 (Docker Engine); Docker Desktop — проприетарная - **Сайт**: [docker.com](https://www.docker.com/) **Docker** — платформа для упаковки приложения вместе со всеми зависимостями в стандартный образ и запуска его в виде изолированного контейнера. Контейнер использует ядро хост-системы, поэтому стартует за доли секунды и расходует меньше ресурсов, чем виртуальная машина. Docker сделал [контейнеризацию](https://llmdocs.ru/wiki/containerization.md) массовой технологией и стал стандартным способом доставки серверного ПО, а его формат образов лёг в основу спецификаций OCI и экосистемы [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md). ## История Docker вырос из внутреннего инструмента PaaS-компании dotCloud. Соломон Хайкс представил его публике в марте 2013 года на конференции PyCon, после чего компания сменила название на Docker, Inc. Первые версии опирались на LXC, но уже в 2014 году Docker перешёл на собственную библиотеку libcontainer. В 2015 году вместе с другими компаниями была создана Open Container Initiative (OCI), которой передали формат образа и среду исполнения **runc**.[4] В 2017 году демон управления контейнерами **containerd** был передан фонду CNCF,[5] а открытая часть кода выделена в проект Moby. В 2021 году изменились условия Docker Desktop: для компаний с более чем 250 сотрудниками или выручкой свыше 10 млн долларов в год он стал платным; Docker Engine на Linux остался открытым.[3] ## Архитектура Docker построен по клиент-серверной схеме:[1] - **CLI** (`docker`) отправляет команды через REST API; - **dockerd** — демон, управляющий образами, сетями и томами; - **containerd** — среда, управляющая жизненным циклом контейнеров; - **runc** — низкоуровневый исполнитель, который создаёт процесс с нужной изоляцией; - **BuildKit** — движок сборки образов, используемый по умолчанию с Docker Engine 23.0.[6] Изоляция обеспечивается механизмами ядра Linux: пространства имён ограничивают видимость процессов, сети и файловой системы, а контрольные группы — потребление CPU и памяти (см. [Namespaces и cgroups](https://llmdocs.ru/wiki/namespaces-cgroups.md)). На macOS и Windows Docker Desktop запускает лёгкую виртуальную машину с Linux. ## Образы и контейнеры **Образ** — неизменяемый набор слоёв файловой системы плюс метаданные (команда запуска, переменные окружения, порты). Каждый слой хранит изменения относительно предыдущего, одинаковые слои разделяются между образами и кешируются. Формат описан спецификацией OCI (см. [Образ контейнера и OCI](https://llmdocs.ru/wiki/oci-image.md)). **Контейнер** — запущенный экземпляр образа с тонким записываемым слоем поверх. После удаления контейнера этот слой пропадает, поэтому долговременные данные хранят в **томах** (volumes). Образы хранятся в реестрах: публичном Docker Hub или частных ([Container registry](https://llmdocs.ru/wiki/container-registry.md)). ## Dockerfile Образ описывается текстовым файлом [Dockerfile](https://llmdocs.ru/wiki/dockerfile.md) — последовательностью инструкций, каждая из которых обычно создаёт слой:[2] ```dockerfile FROM python:3.13-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . EXPOSE 8000 CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] ``` Зависимости копируются раньше исходного кода, чтобы при правке кода не пересобирать слой с установкой пакетов. Для уменьшения размера применяют [многоэтапную сборку](https://llmdocs.ru/wiki/multi-stage-build.md) и минимальные базовые образы. ## Основные команды | Команда | Действие | |---|---| | `docker build -t app:1.0 .` | собрать образ из Dockerfile | | `docker run -d -p 8000:8000 app:1.0` | запустить контейнер в фоне с пробросом порта | | `docker ps` | список запущенных контейнеров | | `docker logs -f ` | поток логов контейнера | | `docker exec -it sh` | оболочка внутри контейнера | | `docker pull` / `docker push` | скачать или опубликовать образ | | `docker compose up -d` | поднять набор сервисов из `compose.yaml` | Для описания многоконтейнерных приложений (сервис + база данных + кеш) используется [Docker Compose](https://llmdocs.ru/wiki/docker-compose.md). ## Безопасность Контейнер — не виртуальная машина: все контейнеры делят одно ядро, и уязвимость ядра или неверная настройка может дать выход на хост. Базовые меры: не запускать процессы от root внутри контейнера, не монтировать сокет Docker в контейнеры без необходимости, не использовать флаг `--privileged`, регулярно обновлять базовые образы и сканировать их на уязвимости. Членство в группе `docker` фактически равно правам root на хосте. ## Альтернативы - [Podman](https://llmdocs.ru/wiki/podman.md) — совместимый по командам инструмент без постоянного демона, с упором на работу без root; - containerd с утилитой `nerdctl` — прямое использование среды без dockerd; - в [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) с 2022 года Docker как среда исполнения (dockershim) удалён, кластеры используют containerd или CRI-O, но образы, собранные Docker, работают без изменений. ## См. также - [Контейнеризация](https://llmdocs.ru/wiki/containerization.md) - [Dockerfile](https://llmdocs.ru/wiki/dockerfile.md) - [Docker Compose](https://llmdocs.ru/wiki/docker-compose.md) - [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) ## Источники 1. [Docker overview — Docker Docs](https://docs.docker.com/get-started/docker-overview/) 2. [Dockerfile reference](https://docs.docker.com/reference/dockerfile/) 3. [Docker Desktop license agreement](https://docs.docker.com/subscription/desktop-license/) 4. [Open Container Initiative — About](https://opencontainers.org/about/overview/) 5. [containerd — CNCF project page](https://www.cncf.io/projects/containerd/) 6. [BuildKit — Docker Docs](https://docs.docker.com/build/buildkit/) --- # Dockerfile > Текстовый файл с инструкциями для сборки образа контейнера — базовый образ, копирование файлов, установка зависимостей и команда запуска. Источник: https://llmdocs.ru/wiki/dockerfile/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: формат описания сборки образа - **Разработчик**: Docker, Inc. - **Появился**: 2013 - **Сборщик по умолчанию**: BuildKit (с Docker Engine 23.0, 2023) - **Многоэтапная сборка**: с Docker 17.05 (2017) - **Альтернативное имя**: Containerfile (Podman, Buildah) - **Линтер**: hadolint **Dockerfile** — текстовый файл с последовательностью инструкций, по которым [Docker](https://llmdocs.ru/wiki/docker.md) (или совместимый сборщик) собирает **образ контейнера**: с какого базового образа начать, какие файлы скопировать, какие команды выполнить и что запускать при старте контейнера. Dockerfile хранится в репозитории рядом с кодом и превращает сборку окружения в воспроизводимый, версионируемый процесс (см. [Контейнеризация](https://llmdocs.ru/wiki/containerization.md)). Формат появился вместе с Docker в 2013 году и стал стандартом де-факто: его понимают Podman и Buildah (там он может называться `Containerfile`), kaniko, облачные сборщики и CI-системы. ## Пример Типичный Dockerfile для веб-приложения на [Python](https://llmdocs.ru/wiki/python.md): ```dockerfile # syntax=docker/dockerfile:1 FROM python:3.13-slim ENV PYTHONDONTWRITEBYTECODE=1 \ PYTHONUNBUFFERED=1 WORKDIR /app # сначала только зависимости — этот слой кэшируется, пока они не меняются COPY requirements.txt . RUN --mount=type=cache,target=/root/.cache/pip \ pip install -r requirements.txt # потом код приложения COPY . . RUN useradd --create-home app USER app EXPOSE 8000 HEALTHCHECK CMD python -c "import urllib.request; urllib.request.urlopen('http://localhost:8000/health')" CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] ``` ```bash docker build -t myapp:1.0 . # собрать образ из Dockerfile в текущем каталоге docker run -p 8000:8000 myapp:1.0 ``` ## Основные инструкции | Инструкция | Назначение | |---|---| | `FROM` | базовый образ; начинает новый этап сборки | | `RUN` | выполнить команду при сборке (установка пакетов) | | `COPY` | скопировать файлы из контекста сборки в образ | | `ADD` | как `COPY`, но умеет скачивать URL и распаковывать архивы | | `WORKDIR` | рабочий каталог для последующих инструкций | | `ENV` | [переменная окружения](https://llmdocs.ru/wiki/environment-variables.md) в образе и контейнере | | `ARG` | параметр, доступный только во время сборки | | `USER` | от какого пользователя выполнять команды и запускать процесс | | `EXPOSE` | документирует порт, который слушает приложение | | `CMD` | команда по умолчанию при запуске контейнера | | `ENTRYPOINT` | исполняемый файл, к которому добавляются аргументы `CMD` | | `HEALTHCHECK` | команда проверки работоспособности | | `LABEL` | метаданные образа | Полное описание — в справочнике Docker.[1] ### CMD и ENTRYPOINT `CMD` задаёт команду, которую легко заменить: `docker run myapp bash` запустит оболочку вместо приложения. `ENTRYPOINT` фиксирует исполняемый файл, а `CMD` превращается в его аргументы по умолчанию — так делают образы-утилиты. Обе инструкции лучше писать в **exec-форме** — JSON-массивом `["uvicorn", "main:app"]`. В shell-форме (`CMD uvicorn main:app`) процесс запускается через `/bin/sh -c`, оболочка становится PID 1 и не передаёт приложению сигнал `SIGTERM`, из-за чего контейнер останавливается только по тайм-ауту. ## Слои и кэш Каждая инструкция `RUN`, `COPY` и `ADD` создаёт новый **слой** образа. Сборщик кэширует слои: если инструкция и её входные данные не изменились, слой берётся из кэша. Как только один слой меняется, все последующие пересобираются.[4] Отсюда главное правило порядка инструкций — от редко меняющихся к часто меняющимся: сначала системные пакеты, затем файл зависимостей и их установка, и только в конце — код приложения. Иначе любая правка кода заново скачивает все библиотеки. Файл `.dockerignore` исключает из контекста сборки лишнее — `.git`, `node_modules`, `.venv`, локальные секреты, — ускоряя сборку и не давая этим файлам попасть в образ. ## Многоэтапная сборка Компиляторы и инструменты сборки не нужны в итоговом образе. [Многоэтапная сборка](https://llmdocs.ru/wiki/multi-stage-build.md) позволяет собрать приложение в одном образе, а скопировать результат в другой, минимальный:[3] ```dockerfile FROM golang:1.25 AS build WORKDIR /src COPY go.mod go.sum ./ RUN go mod download COPY . . RUN CGO_ENABLED=0 go build -o /out/server ./cmd/server FROM gcr.io/distroless/static-debian12 COPY --from=build /out/server /server USER nonroot ENTRYPOINT ["/server"] ``` Итоговый образ содержит только бинарник и занимает единицы мегабайт вместо сотен. ## BuildKit С Docker Engine 23.0 (2023) сборку по умолчанию выполняет **BuildKit**. Он параллельно собирает независимые этапы, пропускает неиспользуемые и добавляет возможности: кэш-монтирования для менеджеров пакетов (`RUN --mount=type=cache`), безопасную передачу секретов при сборке (`RUN --mount=type=secret`), сборку под несколько архитектур (`docker buildx build --platform linux/amd64,linux/arm64`).[5] Первая строка `# syntax=docker/dockerfile:1` подключает актуальную версию синтаксиса. ## Хорошие практики - Используйте небольшие официальные базовые образы (`-slim`, `alpine`, distroless) и фиксируйте их версии, а для полной воспроизводимости — дайджест `@sha256:...`. - Объединяйте установку и очистку кэша пакетного менеджера в одной инструкции `RUN`: удаление файлов в следующем слое не уменьшает размер образа. - Не запускайте процесс от root — добавьте `USER`. - Не записывайте секреты в `ENV`, `ARG` или файлы образа: они остаются в слоях и видны любому, у кого есть образ. - Проверяйте Dockerfile линтером hadolint[6] и сканируйте образ на уязвимости. - Готовый образ публикуйте в [реестр](https://llmdocs.ru/wiki/container-registry.md) с осмысленными тегами — версией и хешем коммита, а не только `latest`.[2] Формат хранения готового образа описан в статье [Образ контейнера и OCI](https://llmdocs.ru/wiki/oci-image.md), а запуск нескольких контейнеров вместе — в статье [Docker Compose](https://llmdocs.ru/wiki/docker-compose.md). ## См. также - [Docker](https://llmdocs.ru/wiki/docker.md) - [Образ контейнера и OCI](https://llmdocs.ru/wiki/oci-image.md) - [Многоэтапная сборка (multi-stage)](https://llmdocs.ru/wiki/multi-stage-build.md) - [Docker Compose](https://llmdocs.ru/wiki/docker-compose.md) - [Container registry](https://llmdocs.ru/wiki/container-registry.md) ## Источники 1. [Docker Docs — Dockerfile reference](https://docs.docker.com/reference/dockerfile/) 2. [Docker Docs — Building best practices](https://docs.docker.com/build/building/best-practices/) 3. [Docker Docs — Multi-stage builds](https://docs.docker.com/build/building/multi-stage/) 4. [Docker Docs — Docker build cache](https://docs.docker.com/build/cache/) 5. [Docker Docs — BuildKit](https://docs.docker.com/build/buildkit/) 6. [hadolint — Dockerfile linter](https://github.com/hadolint/hadolint) --- # Helm > Пакетный менеджер для Kubernetes — упаковывает манифесты приложения в параметризуемые чарты, устанавливает их в кластер как релизы и управляет обновлениями и откатами. Источник: https://llmdocs.ru/wiki/helm/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: пакетный менеджер Kubernetes - **Авторы**: Deis (2015), затем совместно с Google - **Язык**: Go - **Лицензия**: Apache 2.0 - **Статус в CNCF**: выпускник (graduated, апрель 2020) - **Ключевые версии**: Helm 2 (2016, сервер Tiller), Helm 3 (ноябрь 2019, без Tiller), Helm 4 (ноябрь 2025) - **Шаблоны**: Go templates + библиотека Sprig - **Каталог чартов**: Artifact Hub **Helm** — пакетный менеджер для [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md). Приложение в кластере — это обычно десяток манифестов: [Deployment](https://llmdocs.ru/wiki/deployment-replicaset.md), [Service, Ingress](https://llmdocs.ru/wiki/service-ingress.md), [ConfigMap, Secret](https://llmdocs.ru/wiki/configmap-secret.md), права доступа. Helm собирает их в **чарт** (*chart*) — пакет с шаблонами и настройками по умолчанию — и позволяет одной командой установить, обновить или откатить всё приложение целиком.[1] Его часто сравнивают с apt или Homebrew (см. [пакетные менеджеры](https://llmdocs.ru/wiki/package-managers.md)): `helm install` для кластера — то же, что `apt install` для сервера. ## История Helm создала компания Deis и представила в 2015 году; вскоре проект объединился с похожей разработкой Google и вошёл в экосистему Kubernetes. **Helm 2** (2016) состоял из клиента и серверного компонента **Tiller**, который работал в кластере с широкими правами и считался серьёзной проблемой безопасности. **Helm 3** (ноябрь 2019) убрал Tiller: клиент обращается к API напрямую с правами пользователя, а данные о релизах хранит в Secret'ах того же пространства имён.[5] В 2020 году Helm получил статус выпускника CNCF.[6] В ноябре 2025 года вышел Helm 4 с новой системой плагинов и переходом на server-side apply. ## Основные понятия - **Чарт** — каталог (или архив `.tgz`) с шаблонами манифестов и метаданными. - **Values** — параметры, подставляемые в шаблоны: значения по умолчанию лежат в `values.yaml`, пользователь переопределяет их своими файлами или флагами `--set`. - **Релиз** — установленный экземпляр чарта с именем; один чарт можно установить много раз (`redis-cache`, `redis-sessions`). - **Ревизия** — номер версии релиза; каждое `upgrade` создаёт новую, к любой можно откатиться. - **Репозиторий** — место, откуда скачивают чарты: HTTP-сервер с файлом `index.yaml` или OCI-реестр. ## Структура чарта ```text mychart/ ├── Chart.yaml # имя, версия чарта, appVersion, зависимости ├── values.yaml # параметры по умолчанию ├── values.schema.json # необязательная JSON-схема для проверки values ├── templates/ │ ├── deployment.yaml │ ├── service.yaml │ ├── _helpers.tpl # общие именованные шаблоны │ └── NOTES.txt # подсказка, выводимая после установки └── charts/ # зависимости (подчарты) ``` Шаблоны написаны на языке Go templates с библиотекой функций Sprig:[3] ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: {{ include "mychart.fullname" . }} spec: replicas: {{ .Values.replicaCount }} template: spec: containers: - name: app image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" {{- with .Values.resources }} resources: {{- toYaml . | nindent 12 }} {{- end }} ``` В `Chart.yaml` различают `version` — версию самого чарта по правилам [SemVer](https://llmdocs.ru/wiki/semver.md) — и `appVersion` — версию упакованного приложения.[2] ## Работа с Helm ```bash helm repo add bitnami https://charts.bitnami.com/bitnami helm search repo postgresql helm show values bitnami/postgresql > pg-values.yaml # что можно настроить helm install pg bitnami/postgresql -n db --create-namespace -f pg-values.yaml helm upgrade --install web ./mychart -f values-prod.yaml --set image.tag=1.5.0 --atomic helm list -A helm history web helm rollback web 3 helm template web ./mychart -f values-prod.yaml # отрендерить манифесты без установки helm lint ./mychart helm uninstall web ``` `upgrade --install` — идемпотентная команда, удобная в [CI/CD](https://llmdocs.ru/wiki/ci-cd.md): установит релиз, если его нет, и обновит, если есть. Флаг `--atomic` откатывает изменения при неудачном обновлении. С версии 3.8 чарты хранятся в **OCI-реестрах** наравне с образами контейнеров: `helm push mychart-0.1.0.tgz oci://ghcr.io/example/charts`.[4] Готовые чарты для популярных систем ищут в каталоге Artifact Hub. ## Достоинства и критика Helm стал стандартом распространения приложений для Kubernetes: почти у каждого серверного продукта есть официальный чарт. Однако у подхода есть известные недостатки: - шаблонизация YAML как текста — с ручными отступами (`nindent`) — хрупка и плохо читается; - большие чарты обрастают сотнями параметров и становятся сложнее самих манифестов; - `helm upgrade` не замечает ручных изменений объектов в кластере. Поэтому Helm сочетают или заменяют другими инструментами: **Kustomize** (наложения без шаблонов, встроен в [kubectl](https://llmdocs.ru/wiki/kubectl.md)), Helmfile (декларативный список релизов), GitOps-контроллеры Argo CD и Flux, которые умеют разворачивать Helm-чарты из Git, а также языки конфигурации вроде CUE и Jsonnet. Сравнение подходов к декларативному описанию инфраструктуры — в статье [Infrastructure as Code](https://llmdocs.ru/wiki/infrastructure-as-code.md). ## См. также - [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) - [Оператор Kubernetes](https://llmdocs.ru/wiki/kubernetes-operator.md) - [Пакетные менеджеры Linux (apt, dnf, pacman)](https://llmdocs.ru/wiki/package-managers.md) - [Container registry](https://llmdocs.ru/wiki/container-registry.md) ## Источники 1. [Helm Documentation](https://helm.sh/docs/) 2. [Helm Docs — Charts](https://helm.sh/docs/topics/charts/) 3. [Helm Docs — Chart Template Guide](https://helm.sh/docs/chart_template_guide/) 4. [Helm Docs — Use OCI-based registries](https://helm.sh/docs/topics/registries/) 5. [Helm Blog — Helm 3.0.0 has been released](https://helm.sh/blog/helm-3-released/) 6. [CNCF — Helm graduation announcement (2020)](https://www.cncf.io/announcements/2020/04/30/cloud-native-computing-foundation-announces-helm-graduation/) --- # Автомасштабирование (HPA) > Механизмы Kubernetes, меняющие число подов (HPA), их ресурсы (VPA) и число узлов (Cluster Autoscaler, Karpenter) в зависимости от нагрузки. Источник: https://llmdocs.ru/wiki/hpa/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Объект**: HorizontalPodAutoscaler (autoscaling/v2) - **Источник метрик**: metrics-server, Prometheus Adapter, внешние метрики - **Цикл проверки**: 15 секунд (по умолчанию) - **Масштабирует**: Deployment, StatefulSet, ReplicaSet - **Вертикальное**: Vertical Pod Autoscaler (VPA) - **По событиям**: KEDA (проект CNCF) - **Узлы**: Cluster Autoscaler, Karpenter **Автомасштабирование** в [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) — набор механизмов, которые подстраивают мощность приложения под нагрузку без участия человека. Главный из них — **Horizontal Pod Autoscaler** (HPA): он увеличивает или уменьшает число реплик [Deployment](https://llmdocs.ru/wiki/deployment-replicaset.md) в зависимости от загрузки процессора, памяти или прикладных метрик. Днём, когда пользователей много, работает десять подов, ночью — два. Дополняют его вертикальное масштабирование подов (VPA) и масштабирование самих узлов кластера. ## Уровни масштабирования | Что меняется | Инструмент | Пример | |---|---|---| | Число подов | HPA, KEDA | 2 → 10 реплик при росте RPS | | Ресурсы пода | VPA | запросы памяти 256 → 512 МиБ | | Число узлов | Cluster Autoscaler, Karpenter | добавить ВМ, когда поды не помещаются | Обычно они работают вместе: HPA добавляет поды, им не хватает места на узлах, и Cluster Autoscaler заказывает у облака новую машину. ## Как работает HPA Контроллер HPA раз в 15 секунд запрашивает метрики и вычисляет нужное число реплик по формуле:[1] ``` желаемые = ceil(текущие × текущее_значение / целевое_значение) ``` Если цель — 60% CPU, а четыре пода загружены в среднем на 90%, нужно `ceil(4 × 90 / 60) = 6` реплик. Загрузка процессора считается **относительно запросов ресурсов** (`resources.requests`) — без них HPA по CPU работать не может. Источником базовых метрик служит **metrics-server**; прикладные метрики (запросы в секунду, длина очереди) подключают через Prometheus Adapter или KEDA.[3] ```yaml apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: api spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: api minReplicas: 2 maxReplicas: 20 metrics: - type: Resource resource: name: cpu target: {type: Utilization, averageUtilization: 60} behavior: scaleDown: stabilizationWindowSeconds: 300 policies: - {type: Percent, value: 50, periodSeconds: 60} ``` Блок `behavior` защищает от «дребезга»: уменьшение реплик откладывается на 5 минут (окно стабилизации по умолчанию) и ограничивается по скорости. Быстрое создание HPA — `kubectl autoscale deployment api --cpu-percent=60 --min=2 --max=20`; состояние — `kubectl get hpa` и `kubectl describe hpa api` (см. [kubectl](https://llmdocs.ru/wiki/kubectl.md)).[2] ## Метрики - **Resource** — CPU и память контейнеров. Память — плохой сигнал для масштабирования: многие среды выполнения (JVM, Python) не возвращают её системе после пика. - **Pods / Object** — прикладные метрики из [Prometheus](https://llmdocs.ru/wiki/prometheus.md): RPS на под, задержки, число активных соединений. - **External** — метрики вне кластера: длина очереди в облачном брокере, лаг потребителя Kafka. Лучший сигнал — тот, что напрямую отражает нагрузку: для веб-API — запросы в секунду или задержка, для обработчиков — длина очереди. ## KEDA **KEDA** (*Kubernetes Event-driven Autoscaling*) расширяет HPA десятками источников событий — Kafka, RabbitMQ, Redis, SQS, cron, запросы к Prometheus — и умеет масштабировать **до нуля**: если очередь пуста, подов нет вообще, а при появлении сообщений они создаются.[4] Это удобно для фоновых обработчиков и задач по расписанию. ## VPA и масштабирование узлов **Vertical Pod Autoscaler** анализирует фактическое потребление и рекомендует или выставляет запросы CPU и памяти. Применение новых значений обычно требует пересоздания пода; совмещать VPA и HPA по одной и той же метрике CPU нельзя — они будут мешать друг другу.[5] Часто VPA используют в режиме рекомендаций, чтобы правильно задать запросы. **Cluster Autoscaler** добавляет узлы, когда поды висят в `Pending` из-за нехватки ресурсов, и удаляет недогруженные узлы. **Karpenter** (AWS, теперь проект Kubernetes SIG) подбирает тип и размер машины под конкретные ожидающие поды и быстрее реагирует.[6] ## Практика - Всегда задавайте `resources.requests` — от них считается и загрузка, и размещение подов. - `minReplicas` не меньше 2 для сервисов, которые должны переживать сбой узла; добавьте PodDisruptionBudget. - Учитывайте время старта: если под готов через минуту, HPA не спасёт от резкого всплеска — нужен запас или предварительное масштабирование по расписанию. - Приложение должно быть без состояния и корректно завершаться по SIGTERM, иначе уменьшение реплик обрывает запросы. - Проверяйте поведение нагрузочным тестом и следите за событиями масштабирования в [мониторинге](https://llmdocs.ru/wiki/monitoring-alerting.md). ## См. также - [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) - [Deployment и ReplicaSet](https://llmdocs.ru/wiki/deployment-replicaset.md) - [Prometheus](https://llmdocs.ru/wiki/prometheus.md) - [k3s и лёгкие дистрибутивы](https://llmdocs.ru/wiki/k3s.md) ## Источники 1. [Kubernetes Docs — Horizontal Pod Autoscaling](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/) 2. [Kubernetes Docs — HorizontalPodAutoscaler Walkthrough](https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale-walkthrough/) 3. [Kubernetes Docs — Resource Management for Pods and Containers](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) 4. [KEDA — Kubernetes Event-driven Autoscaling](https://keda.sh/docs/latest/concepts/) 5. [Kubernetes Autoscaler — Cluster Autoscaler and VPA](https://github.com/kubernetes/autoscaler) 6. [Karpenter Documentation](https://karpenter.sh/docs/) --- # k3s и лёгкие дистрибутивы > Облегчённые сборки Kubernetes — k3s, k0s, MicroK8s, kind, minikube — для небольших серверов, edge-устройств, разработки и тестов. Источник: https://llmdocs.ru/wiki/k3s/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **k3s**: Rancher (SUSE), 2019, проект CNCF - **Размер k3s**: один бинарник менее 100 МБ - **Минимум памяти**: около 512 МБ на сервер k3s - **Хранилище состояния**: SQLite, etcd, MySQL, PostgreSQL (kine) - **Для разработки**: kind, minikube, k3d - **Для edge и продакшена**: k3s, k0s, MicroK8s, Talos - **Сертификация**: CNCF Certified Kubernetes **Лёгкие дистрибутивы Kubernetes** — сборки [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md), упрощённые для установки и требующие меньше ресурсов, чем «классический» кластер, разворачиваемый через kubeadm. Самый известный из них — **k3s**: полноценный сертифицированный Kubernetes в одном исполняемом файле, который ставится одной командой и работает даже на Raspberry Pi. Такие дистрибутивы используют на небольших VPS, в домашних лабораториях, на edge-устройствах и для локальной разработки и тестов в [CI/CD](https://llmdocs.ru/wiki/ci-cd.md). ## Зачем нужны Стандартный кластер состоит из множества компонентов: API-сервер, etcd, планировщик, менеджер контроллеров, kubelet, kube-proxy, плагин сети, DNS, ingress-контроллер. Каждый ставится и обновляется отдельно, а управляющая плоскость с etcd желает 2+ ГБ памяти. Лёгкие дистрибутивы собирают всё это в готовый комплект с разумными значениями по умолчанию, чтобы кластер можно было получить за минуту. ## k3s k3s создала компания Rancher Labs в 2019 году; название — игра с «k8s»: «вдвое меньше букв».[1] С 2020 года проект находится в CNCF. Особенности:[2] - **Один бинарник** содержит все компоненты управляющей плоскости, kubelet и containerd. - Вместо etcd по умолчанию используется **SQLite** через прослойку kine; для отказоустойчивых кластеров — встроенный etcd или внешняя [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md)/MySQL. - В комплекте: сеть Flannel (см. [Сетевые плагины (CNI)](https://llmdocs.ru/wiki/cni.md)), CoreDNS, ingress-контроллер Traefik, балансировщик ServiceLB, `local-path-provisioner` для [томов](https://llmdocs.ru/wiki/persistentvolume.md) и контроллер установки [Helm](https://llmdocs.ru/wiki/helm.md)-чартов. - Удалены устаревшие и облачно-специфичные части Kubernetes. Установка сервера и подключение рабочего узла: ```bash curl -sfL https://get.k3s.io | sh - sudo k3s kubectl get nodes # на рабочем узле: адрес сервера и токен из /var/lib/rancher/k3s/server/node-token curl -sfL https://get.k3s.io | K3S_URL=https://server:6443 K3S_TOKEN=... sh - ``` Конфигурация для [kubectl](https://llmdocs.ru/wiki/kubectl.md) лежит в `/etc/rancher/k3s/k3s.yaml`. Встроенные компоненты можно отключить флагами, например `--disable traefik`, если вместо Traefik нужен другой ingress. Служба k3s управляется через [systemd](https://llmdocs.ru/wiki/systemd.md). ## Сравнение | Дистрибутив | Для чего | Особенности | |---|---|---| | **k3s** | маленькие серверы, edge, домашние кластеры | один бинарник, SQLite, всё в комплекте | | **k0s** (Mirantis) | продакшен с минимумом зависимостей | один бинарник, без привязки к ОС, ванильные компоненты[5] | | **MicroK8s** (Canonical) | Ubuntu, рабочие станции, edge | ставится через snap, дополнения включаются командой `microk8s enable`[6] | | **kind** | тесты и CI | узлы кластера — контейнеры [Docker](https://llmdocs.ru/wiki/docker.md)[3] | | **minikube** | обучение и локальная разработка | ВМ или контейнер, дашборд и дополнения[4] | | **k3d** | локальная разработка | k3s внутри Docker, кластер за секунды | | **Talos Linux** | продакшен на «железе» | неизменяемая ОС только для Kubernetes, управление через API | ## Разработка и CI **kind** (*Kubernetes IN Docker*) создан для тестирования самого Kubernetes: каждый узел — контейнер, кластер из нескольких узлов поднимается за полминуты и удаляется без следа. Это стандартный выбор для интеграционных тестов в [GitHub Actions](https://llmdocs.ru/wiki/github-actions.md) и проверки [операторов](https://llmdocs.ru/wiki/kubernetes-operator.md). ```bash kind create cluster --name dev kind load docker-image myapp:dev --name dev # без реестра kubectl cluster-info --context kind-dev kind delete cluster --name dev ``` **minikube** удобнее для обучения: дашборд (`minikube dashboard`), туннель для сервисов типа LoadBalancer, набор дополнений. **k3d** даёт то же, что kind, но на базе k3s и с встроенным локальным [реестром](https://llmdocs.ru/wiki/container-registry.md). ## Когда выбирать - **Один сервер или несколько небольших** — k3s: полноценный Kubernetes с минимальными накладными расходами. Впрочем, для одного сервера с парой сервисов часто проще [Docker Compose](https://llmdocs.ru/wiki/docker-compose.md). - **Edge и IoT** — k3s или MicroK8s, поддерживают ARM. - **Тесты в CI** — kind или k3d. - **Обучение** — minikube или kind. - **Крупный продакшен** — управляемые кластеры облаков (EKS, GKE, Managed Kubernetes в российских облаках) или kubeadm/Talos; впрочем, k3s с внешней базой данных тоже применяют в продакшене. Все перечисленные дистрибутивы проходят тесты соответствия CNCF, поэтому манифесты и Helm-чарты переносятся между ними без изменений; различаются лишь встроенные компоненты — ingress, хранилище и сеть. ## См. также - [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) - [kubectl](https://llmdocs.ru/wiki/kubectl.md) - [Docker Compose](https://llmdocs.ru/wiki/docker-compose.md) - [Сетевые плагины (CNI)](https://llmdocs.ru/wiki/cni.md) ## Источники 1. [k3s Documentation](https://docs.k3s.io/) 2. [k3s — Architecture](https://docs.k3s.io/architecture) 3. [kind — Kubernetes IN Docker](https://kind.sigs.k8s.io/) 4. [minikube documentation](https://minikube.sigs.k8s.io/docs/) 5. [k0s Documentation](https://docs.k0sproject.io/) 6. [MicroK8s Documentation](https://microk8s.io/docs) --- # kubectl > Официальная утилита командной строки Kubernetes — отправляет запросы к API-серверу кластера, создаёт и изменяет объекты, показывает их состояние, логи и события. Источник: https://llmdocs.ru/wiki/kubectl/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: CLI-клиент Kubernetes API - **Язык**: Go - **Лицензия**: Apache 2.0 - **Конфигурация**: ~/.kube/config (переменная KUBECONFIG) - **Совместимость версий**: ± одна минорная версия относительно API-сервера - **Расширения**: плагины kubectl-*, менеджер krew - **Альтернативы и дополнения**: k9s, Lens, kubectx/kubens, stern **kubectl** (произносят «кьюб-контрол», «кьюб-си-ти-эл» или «кубкатл») — официальная утилита командной строки [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md). Всё, что она делает, — отправляет HTTP-запросы к API-серверу кластера: создаёт, читает, изменяет и удаляет объекты, а также открывает потоки логов, выполняет команды в контейнерах и пробрасывает порты.[1] Это основной инструмент администратора и разработчика: им пользуются и вручную, и в скриптах [CI/CD](https://llmdocs.ru/wiki/ci-cd.md). ## Подключение к кластеру Куда и с какими правами ходить, kubectl узнаёт из файла **kubeconfig** — по умолчанию `~/.kube/config` или файлы из переменной `KUBECONFIG`.[3] В нём три списка: - **clusters** — адреса API-серверов и сертификаты их центров сертификации; - **users** — учётные данные: клиентский сертификат, токен или внешняя программа входа (например, облачный CLI); - **contexts** — сочетания «кластер + пользователь + пространство имён по умолчанию». ```bash kubectl config get-contexts kubectl config use-context prod kubectl config set-context --current --namespace=web ``` Ошибиться контекстом и выполнить команду в боевом кластере вместо тестового — классическая авария; поэтому текущий контекст выводят в приглашение оболочки, а для быстрого переключения используют утилиты kubectx и kubens. Версия kubectl должна отличаться от версии API-сервера не больше чем на одну минорную в любую сторону.[4] ## Основные команды Общий вид: `kubectl <глагол> <тип> [имя] [флаги]`.[2] | Команда | Что делает | |---|---| | `get` | список объектов: `kubectl get pods -A -o wide` | | `describe` | подробности и **события** — первое, что смотрят при проблемах | | `apply -f` | создать или обновить объекты по манифестам | | `delete` | удалить объекты | | `logs` | логи контейнера (`-f` — следить, `--previous` — прошлый запуск) | | `exec -it` | выполнить команду внутри контейнера | | `port-forward` | пробросить порт пода или сервиса на локальную машину | | `rollout` | статус, история и откат выкаток [Deployment](https://llmdocs.ru/wiki/deployment-replicaset.md) | | `scale` | изменить число реплик | | `top` | потребление CPU и памяти (нужен metrics-server) | | `explain` | документация по полям объекта: `kubectl explain pod.spec.containers` | | `debug` | временный отладочный контейнер рядом с приложением или на узле | Флаг `-n` задаёт пространство имён, `-A` — все сразу, `-l app=web` — фильтр по меткам. ## Декларативный и императивный стиль Объекты можно создавать командами (`kubectl create deployment web --image=nginx`, `kubectl expose`), но в рабочих проектах применяют **декларативный** подход: манифесты в YAML хранятся в Git, а `kubectl apply` приводит кластер к описанному состоянию. ```bash kubectl apply -f k8s/ # все манифесты каталога kubectl diff -f k8s/ # что изменится, до применения kubectl apply -k overlays/prod # с наложениями Kustomize kubectl apply --server-side -f big-crd.yaml ``` Клиентский `apply` хранит последнюю применённую конфигурацию в аннотации объекта и вычисляет изменения у себя. **Server-side apply** (стабилен с версии 1.22) переносит слияние на сервер и отслеживает, какой «менеджер» владеет каждым полем, — это снимает конфликты, когда один объект правят несколько инструментов.[5] Генерация заготовки без создания объекта — удобный способ не писать YAML с нуля: ```bash kubectl create deployment web --image=nginx:1.27 --dry-run=client -o yaml > web.yaml ``` ## Вывод и отладка ```bash kubectl get pods -o yaml # объект целиком kubectl get pods -o jsonpath='{.items[*].metadata.name}' kubectl get pods -o custom-columns=NAME:.metadata.name,NODE:.spec.nodeName kubectl get events --sort-by=.lastTimestamp kubectl get pods -w # следить за изменениями kubectl auth can-i delete pods --as=system:serviceaccount:web:deployer ``` Флаг `-v=6` (до `-v=9`) показывает HTTP-запросы, которые kubectl отправляет к API, — полезно, чтобы понять, что на самом деле происходит. Типичный порядок разбора проблемного [пода](https://llmdocs.ru/wiki/pod.md): `get` → `describe` (события: нехватка ресурсов, ошибка скачивания образа) → `logs --previous` → `exec` или `debug`. ## Расширения Любой исполняемый файл с именем `kubectl-<имя>` в `PATH` становится подкомандой `kubectl <имя>`.[6] Менеджер плагинов **krew** устанавливает их из общего каталога: `ctx`, `ns`, `neat` (очищает вывод от служебных полей), `tree` (показывает владельцев объектов). Рядом с kubectl обычно используют k9s — терминальный интерфейс для навигации по кластеру, stern — для логов сразу нескольких подов, и [Helm](https://llmdocs.ru/wiki/helm.md) — для установки готовых пакетов. Для удобства включают автодополнение (`source <(kubectl completion zsh)`) и короткий псевдоним `alias k=kubectl`. Сокращения типов тоже работают: `po`, `svc`, `deploy`, `ns`, `cm`. ## См. также - [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) - [Shell и Bash](https://llmdocs.ru/wiki/shell-bash.md) - [ConfigMap и Secret](https://llmdocs.ru/wiki/configmap-secret.md) - [Service и Ingress](https://llmdocs.ru/wiki/service-ingress.md) ## Источники 1. [Kubernetes Docs — Command line tool (kubectl)](https://kubernetes.io/docs/reference/kubectl/) 2. [Kubernetes Docs — kubectl Quick Reference](https://kubernetes.io/docs/reference/kubectl/quick-reference/) 3. [Kubernetes Docs — Organizing Cluster Access Using kubeconfig Files](https://kubernetes.io/docs/concepts/configuration/organize-cluster-access-kubeconfig/) 4. [Kubernetes Docs — Version Skew Policy](https://kubernetes.io/releases/version-skew-policy/) 5. [Kubernetes Docs — Server-Side Apply](https://kubernetes.io/docs/reference/using-api/server-side-apply/) 6. [Kubernetes Docs — Extend kubectl with plugins](https://kubernetes.io/docs/tasks/extend-kubectl/kubectl-plugins/) --- # Оператор Kubernetes > Паттерн расширения Kubernetes — собственный контроллер плюс пользовательский ресурс (CRD), который автоматизирует эксплуатацию сложного приложения, например базы данных. Источник: https://llmdocs.ru/wiki/kubernetes-operator/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Автор идеи**: CoreOS (2016) - **Состав**: CustomResourceDefinition + контроллер - **Принцип**: цикл согласования (reconcile loop) - **Фреймворки**: Kubebuilder, Operator SDK, kopf (Python), Metacontroller - **Каталоги**: OperatorHub.io, Artifact Hub - **Примеры**: CloudNativePG, Prometheus Operator, cert-manager, Strimzi **Оператор Kubernetes** — программа, которая работает внутри кластера [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) и управляет конкретным приложением так, как это делал бы опытный администратор: разворачивает, обновляет, делает резервные копии, переключает реплики при сбое. Технически оператор — это собственный **контроллер** плюс собственный тип ресурса (**Custom Resource**). Пользователь описывает желаемое состояние декларативно — «кластер PostgreSQL из трёх узлов, бэкап каждую ночь», — а оператор непрерывно приводит реальность к описанию. ## История Термин предложила компания CoreOS в 2016 году, представив операторы для etcd и Prometheus.[6] Идея опиралась на то, что сам Kubernetes построен из контроллеров: контроллер [Deployment](https://llmdocs.ru/wiki/deployment-replicaset.md) следит за числом подов, контроллер узлов — за состоянием машин. Оператор применяет тот же подход к приложениям, знания об эксплуатации которых не встроены в Kubernetes. В 2017 году механизм CustomResourceDefinition (CRD) заменил ранние ThirdPartyResources и стал стандартным способом расширять API.[2] ## Как устроен **1. CRD** регистрирует в API-сервере новый тип объекта. После этого с ним можно работать через [kubectl](https://llmdocs.ru/wiki/kubectl.md), как со встроенными: ```yaml apiVersion: postgresql.cnpg.io/v1 kind: Cluster metadata: name: app-db spec: instances: 3 storage: size: 20Gi backup: barmanObjectStore: destinationPath: s3://backups/app-db ``` **2. Контроллер** — обычно приложение на [Go](https://llmdocs.ru/wiki/go.md) в [поде](https://llmdocs.ru/wiki/pod.md) — подписывается на изменения этих объектов и связанных ресурсов и выполняет **цикл согласования** (reconcile loop):[3] 1. прочитать желаемое состояние (`spec`); 2. посмотреть фактическое: какие StatefulSet, Service, [тома](https://llmdocs.ru/wiki/persistentvolume.md) и [секреты](https://llmdocs.ru/wiki/configmap-secret.md) существуют; 3. выполнить шаги, уменьшающие разницу, — создать, изменить, удалить; 4. записать наблюдаемое состояние в `status` и повторить при следующем событии. Согласование должно быть **идемпотентным**: оператор не помнит, «что делал в прошлый раз», а каждый раз смотрит на текущую картину. Поэтому он переживает перезапуски и сбои сам по себе. ## Уровни зрелости Operator Framework описывает пять уровней возможностей:[5] | Уровень | Что умеет оператор | |---|---| | 1. Basic Install | развернуть приложение | | 2. Seamless Upgrades | обновлять версии и схемы | | 3. Full Lifecycle | бэкапы, восстановление, отказоустойчивость | | 4. Deep Insights | метрики, алерты, анализ логов | | 5. Auto Pilot | автомасштабирование, самонастройка, самолечение | ## Известные операторы - **CloudNativePG**, **Zalando Postgres Operator**, **Percona** — кластеры [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) с репликацией и автоматическим переключением. - **Prometheus Operator** — ресурсы `ServiceMonitor` и `PrometheusRule` для настройки [Prometheus](https://llmdocs.ru/wiki/prometheus.md). - **cert-manager** — выпуск и продление TLS-сертификатов, в том числе через [ACME](https://llmdocs.ru/wiki/lets-encrypt-acme.md). - **Strimzi** — Apache Kafka; **ECK** — Elasticsearch; **Argo CD** и **Flux** — GitOps-доставка, тоже построенная на контроллерах. Готовые операторы ищут на OperatorHub.io и Artifact Hub; устанавливают их обычно через [Helm](https://llmdocs.ru/wiki/helm.md) или Operator Lifecycle Manager (OLM). ## Как написать свой - **Kubebuilder** и **Operator SDK** (Go) генерируют каркас: типы CRD, контроллер на библиотеке controller-runtime, манифесты RBAC и тесты.[4] - **kopf** — фреймворк на Python с обработчиками-декораторами. - **Metacontroller** позволяет описать логику веб-хуком на любом языке; **Operator SDK** умеет строить операторы из Helm-чартов и Ansible-ролей. ```bash kubebuilder init --domain example.com --repo example.com/app-operator kubebuilder create api --group apps --version v1 --kind App make manifests install run ``` ## Когда оператор не нужен Оператор — это код, который нужно поддерживать и которому выдаются широкие права в кластере. Для приложений без состояния обычно хватает Deployment и Helm-чарта. Операторы оправданы для систем с состоянием (базы данных, очереди, кластеры поиска), где установка, обновление и восстановление требуют последовательности действий, а ошибка стоит данных. При выборе готового оператора стоит смотреть на уровень зрелости, активность разработки и то, как он ведёт себя при собственном сбое. ## См. также - [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) - [Helm](https://llmdocs.ru/wiki/helm.md) - [Deployment и ReplicaSet](https://llmdocs.ru/wiki/deployment-replicaset.md) - [PersistentVolume](https://llmdocs.ru/wiki/persistentvolume.md) ## Источники 1. [Kubernetes Docs — Operator pattern](https://kubernetes.io/docs/concepts/extend-kubernetes/operator/) 2. [Kubernetes Docs — Custom Resources](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/custom-resources/) 3. [Kubernetes Docs — Controllers](https://kubernetes.io/docs/concepts/architecture/controller/) 4. [The Kubebuilder Book](https://book.kubebuilder.io/) 5. [Operator SDK](https://sdk.operatorframework.io/) 6. [CNCF Operator White Paper](https://github.com/cncf/tag-app-delivery/blob/main/operator-wg/whitepaper/Operator-WhitePaper_v1-0.md) --- # Kubernetes > Открытая платформа оркестрации контейнеров — автоматически размещает, масштабирует, обновляет и восстанавливает контейнерные приложения в кластере машин. Источник: https://llmdocs.ru/wiki/kubernetes/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: система оркестрации контейнеров - **Разработчик**: Google, затем Cloud Native Computing Foundation (CNCF) - **Анонс**: июнь 2014 - **Версия 1.0**: июль 2015 - **Язык**: Go - **Лицензия**: Apache 2.0 - **Цикл выпусков**: три минорные версии в год - **Предшественник**: Borg (внутренняя система Google) - **Сайт**: kubernetes.io **Kubernetes** (от греч. κυβερνήτης — «кормчий», «рулевой»; сокращённо **K8s** — между «K» и «s» восемь букв) — открытая платформа для оркестрации контейнеров. Kubernetes управляет кластером из многих машин как единым ресурсом: решает, на каком узле запустить контейнер, перезапускает упавшие, распределяет трафик, масштабирует приложения под нагрузку и обновляет их без простоя. Пользователь описывает *желаемое состояние* — «три копии этого сервиса, доступные по такому адресу», — а Kubernetes непрерывно приводит к нему фактическое.[1] Kubernetes — стандарт индустрии для запуска [контейнерных](https://llmdocs.ru/wiki/containerization.md) приложений: управляемые кластеры предлагают все крупные облака, а для небольших установок есть облегчённые дистрибутивы. ## История В Google больше десяти лет работала внутренняя система управления кластерами Borg, запускавшая практически все сервисы компании.[4] В 2014 году инженеры Google — Джо Беда, Брендан Бёрнс и Крейг Маклаки — представили открытый проект, вобравший опыт Borg и его преемника Omega. Версия 1.0 вышла в июле 2015 года, и одновременно Google передала проект новой организации Cloud Native Computing Foundation (CNCF) при Linux Foundation; в 2018 году Kubernetes стал первым «выпускником» CNCF.[7] Новая минорная версия выходит примерно три раза в год, каждая поддерживается около 14 месяцев.[3] В версии 1.24 (2022) была удалена встроенная прослойка для Docker (dockershim): кластеры работают с containerd или CRI-O через интерфейс CRI, а образы, собранные [Docker](https://llmdocs.ru/wiki/docker.md), по-прежнему совместимы благодаря стандарту OCI.[5] ## Архитектура Кластер состоит из **управляющего слоя** (*control plane*) и **рабочих узлов** (*nodes*):[2] | Компонент | Где | Роль | |---|---|---| | kube-apiserver | control plane | единая точка входа: REST API для всех операций | | etcd | control plane | распределённое хранилище ключ-значение с состоянием кластера | | kube-scheduler | control plane | выбирает узел для каждого нового пода | | kube-controller-manager | control plane | контроллеры, приводящие состояние к желаемому | | kubelet | каждый узел | запускает контейнеры подов через среду выполнения | | kube-proxy | каждый узел | сетевые правила для сервисов | | Среда выполнения | каждый узел | containerd или CRI-O | Ключевая идея — **цикл согласования** (*reconciliation loop*): контроллеры постоянно сравнивают желаемое состояние, записанное в etcd, с фактическим и устраняют расхождения. Если узел выходит из строя, контроллер замечает нехватку копий и создаёт их на других узлах. ## Основные объекты Все ресурсы описываются как объекты API, обычно в YAML-манифестах:[6] - **[Pod](https://llmdocs.ru/wiki/pod.md)** — минимальная единица запуска: один или несколько контейнеров с общей сетью и томами. - **[Deployment](https://llmdocs.ru/wiki/deployment-replicaset.md)** — поддерживает заданное число одинаковых подов и выполняет плавные обновления с возможностью отката. - **[Service](https://llmdocs.ru/wiki/service-ingress.md)** — стабильный адрес и балансировка для набора подов; **Ingress** и **Gateway API** — маршрутизация внешнего HTTP-трафика. - **[ConfigMap и Secret](https://llmdocs.ru/wiki/configmap-secret.md)** — конфигурация и секреты отдельно от образа. - **[PersistentVolume](https://llmdocs.ru/wiki/persistentvolume.md)** — постоянное хранилище для баз данных и файлов. - **Namespace** — логическое разделение кластера между командами и окружениями. - **StatefulSet, DaemonSet, Job, CronJob** — приложения с состоянием, агенты на каждом узле, разовые и периодические задачи. ## Пример манифеста ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: web spec: replicas: 3 selector: matchLabels: {app: web} template: metadata: labels: {app: web} spec: containers: - name: web image: ghcr.io/example/web:1.4.2 ports: [{containerPort: 8000}] resources: requests: {cpu: 100m, memory: 128Mi} limits: {memory: 256Mi} readinessProbe: httpGet: {path: /health, port: 8000} --- apiVersion: v1 kind: Service metadata: name: web spec: selector: {app: web} ports: [{port: 80, targetPort: 8000}] ``` ```bash kubectl apply -f web.yaml # создать или обновить объекты kubectl get pods -l app=web # поды приложения kubectl rollout status deployment/web # ход обновления kubectl logs -f deployment/web # логи kubectl scale deployment/web --replicas=5 ``` Работа с кластером ведётся утилитой [kubectl](https://llmdocs.ru/wiki/kubectl.md); приложения из многих манифестов упаковывают в чарты [Helm](https://llmdocs.ru/wiki/helm.md). ## Расширяемость Kubernetes расширяется через собственные типы ресурсов (CRD) и **[операторы](https://llmdocs.ru/wiki/kubernetes-operator.md)** — контроллеры, которые автоматизируют эксплуатацию сложных систем вроде [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) или Kafka. Сеть подключается через плагины [CNI](https://llmdocs.ru/wiki/cni.md), хранилища — через CSI. Количество подов может меняться автоматически по нагрузке ([HPA](https://llmdocs.ru/wiki/hpa.md)). ## Когда Kubernetes не нужен Kubernetes сложен в установке и сопровождении. Для одного сервера и нескольких сервисов обычно достаточно [Docker Compose](https://llmdocs.ru/wiki/docker-compose.md), а для простых веб-приложений — PaaS или бессерверных платформ. Кластер оправдан, когда много сервисов и команд, нужна отказоустойчивость, автоматическое масштабирование и единый способ развёртывания. Для небольших кластеров и периферийных устройств есть [облегчённые дистрибутивы](https://llmdocs.ru/wiki/k3s.md) — k3s, k0s, MicroK8s, — а для локальной разработки — kind и minikube. ## См. также - [Pod](https://llmdocs.ru/wiki/pod.md) - [Deployment и ReplicaSet](https://llmdocs.ru/wiki/deployment-replicaset.md) - [kubectl](https://llmdocs.ru/wiki/kubectl.md) - [Helm](https://llmdocs.ru/wiki/helm.md) - [Контейнеризация](https://llmdocs.ru/wiki/containerization.md) ## Источники 1. [Kubernetes Documentation — Overview](https://kubernetes.io/docs/concepts/overview/) 2. [Kubernetes Documentation — Kubernetes Components](https://kubernetes.io/docs/concepts/overview/components/) 3. [Kubernetes — Releases](https://kubernetes.io/releases/) 4. [Verma et al. — Large-scale cluster management at Google with Borg (EuroSys 2015)](https://research.google/pubs/large-scale-cluster-management-at-google-with-borg/) 5. [Kubernetes Documentation — Migrating from dockershim](https://kubernetes.io/docs/tasks/administer-cluster/migrating-from-dockershim/) 6. [Kubernetes Documentation — Objects in Kubernetes](https://kubernetes.io/docs/concepts/overview/working-with-objects/) 7. [CNCF — Kubernetes project](https://www.cncf.io/projects/kubernetes/) --- # Многоэтапная сборка (multi-stage) > Приём в Dockerfile, при котором программа собирается в одном образе со всеми инструментами, а в итоговый образ копируются только готовые артефакты. Источник: https://llmdocs.ru/wiki/multi-stage-build/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Появление**: Docker 17.05 (май 2017) - **Где описывается**: Dockerfile - **Ключевые инструкции**: FROM ... AS name, COPY --from=name - **Сборщик**: BuildKit (по умолчанию с Docker 23.0) - **Поддержка**: Docker, Podman/Buildah, kaniko - **Цель**: маленькие и безопасные образы **Многоэтапная сборка** (англ. *multi-stage build*) — способ описать в одном [Dockerfile](https://llmdocs.ru/wiki/dockerfile.md) несколько последовательных этапов, каждый со своим базовым образом. На первых этапах ставятся компиляторы, менеджеры пакетов и зависимости для сборки, а в финальный образ копируются только готовые файлы — бинарник, собранная статика или установленные библиотеки. В результате образ получается в разы меньше, быстрее скачивается и содержит меньше программ, в которых могут найтись уязвимости. ## Зачем это нужно До появления многоэтапной сборки в 2017 году (Docker 17.05) разработчики либо тащили в продакшен образ с полным набором инструментов, либо держали два Dockerfile и скрипт, который копировал артефакты из одного контейнера в другой («builder pattern»).[1] Каждая инструкция Dockerfile создаёт слой, и удаление файла в следующем слое не уменьшает образ — файл остаётся в предыдущем. Многоэтапная сборка решает это: в финальный [образ](https://llmdocs.ru/wiki/oci-image.md) попадают только слои последнего этапа. Типичный выигрыш: | Стек | Один этап | Многоэтапная | |---|---|---| | Go | `golang` ~800 МБ | `scratch`/distroless 10–20 МБ | | Node.js (фронтенд) | `node` ~1 ГБ | `nginx:alpine` ~50 МБ | | Python | `python` ~1 ГБ | `python:slim` 150–250 МБ | | Java | JDK + Maven ~700 МБ | JRE ~200 МБ | ## Синтаксис Этапу дают имя через `AS`, а файлы из него копируют `COPY --from=имя`:[2] ```dockerfile # этап 1: сборка FROM golang:1.23 AS build WORKDIR /src COPY go.mod go.sum ./ RUN go mod download COPY . . RUN CGO_ENABLED=0 go build -o /app ./cmd/server # этап 2: запуск FROM gcr.io/distroless/static-debian12 COPY --from=build /app /app USER nonroot ENTRYPOINT ["/app"] ``` [Go](https://llmdocs.ru/wiki/go.md) особенно хорошо подходит для этого: статически слинкованный бинарник может работать даже в пустом образе `scratch`. Образы **distroless** от Google содержат только библиотеки времени выполнения — без shell и менеджера пакетов.[5] Фронтенд-пример: ```dockerfile FROM node:22 AS build WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build FROM nginx:1.27-alpine COPY --from=build /app/dist /usr/share/nginx/html ``` Здесь [Node.js](https://llmdocs.ru/wiki/nodejs.md) нужен только для сборки, а раздаёт статику [nginx](https://llmdocs.ru/wiki/nginx.md). ## Python Для интерпретируемых языков переносят не бинарник, а установленное окружение: ```dockerfile FROM python:3.12 AS build RUN pip install uv WORKDIR /app COPY pyproject.toml uv.lock ./ RUN uv sync --frozen --no-dev FROM python:3.12-slim WORKDIR /app COPY --from=build /app/.venv /app/.venv COPY . . ENV PATH="/app/.venv/bin:$PATH" CMD ["python", "-m", "app"] ``` Компиляторы для пакетов с C-расширениями остаются на этапе сборки. Важно, чтобы базовые образы этапов совпадали по версии Python и libc. ## Возможности BuildKit С Docker 23.0 сборку по умолчанию выполняет BuildKit, который:[3] - строит **независимые этапы параллельно** и пропускает этапы, не нужные для цели; - позволяет собрать конкретный этап: `docker build --target test .` — удобно для прогона тестов в [CI/CD](https://llmdocs.ru/wiki/ci-cd.md); - поддерживает **кэш-монтирование**: `RUN --mount=type=cache,target=/root/.cache/pip pip install ...` — кэш менеджера пакетов сохраняется между сборками, но не попадает в образ; - передаёт **секреты** без записи в слои: `RUN --mount=type=secret,id=npmrc ...`; - копирует файлы из любого образа: `COPY --from=ghcr.io/astral-sh/uv:latest /uv /bin/uv`. ## Практические советы - Копируйте сначала файлы зависимостей (`go.mod`, `package.json`, `uv.lock`), затем исходники — так слой с зависимостями кэшируется, пока они не меняются.[4] - Фиксируйте версии базовых образов (`node:22.11`, а лучше по дайджесту), чтобы сборка была воспроизводимой. - Запускайте финальный образ не от root (`USER`). - Добавьте `.dockerignore` — `node_modules`, `.git` и локальные `.env` не должны попадать в контекст сборки. - Отдельный этап `test` или `lint` можно запускать в CI, не включая инструменты тестирования в продакшен-образ. Многоэтапные Dockerfile понимают и альтернативные сборщики: [Podman](https://llmdocs.ru/wiki/podman.md) и Buildah, kaniko в [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md). ## См. также - [Dockerfile](https://llmdocs.ru/wiki/dockerfile.md) - [Docker](https://llmdocs.ru/wiki/docker.md) - [Образ контейнера и OCI](https://llmdocs.ru/wiki/oci-image.md) - [Container registry](https://llmdocs.ru/wiki/container-registry.md) ## Источники 1. [Docker Docs — Multi-stage builds](https://docs.docker.com/build/building/multi-stage/) 2. [Dockerfile reference](https://docs.docker.com/reference/dockerfile/) 3. [Docker Docs — BuildKit](https://docs.docker.com/build/buildkit/) 4. [Docker Docs — Optimize cache usage in builds](https://docs.docker.com/build/cache/optimize/) 5. [GoogleContainerTools — distroless](https://github.com/GoogleContainerTools/distroless) --- # Namespaces и cgroups > Два механизма ядра Linux, на которых построены контейнеры: пространства имён изолируют то, что процесс видит, а cgroups ограничивают, сколько ресурсов он потребляет. Источник: https://llmdocs.ru/wiki/namespaces-cgroups/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Подсистема**: ядро Linux - **Namespaces**: с 2002 (mount), полный набор к 2013 (user), cgroup ns 2016, time ns 2020 - **cgroups**: Google (2006), в ядре с 2.6.24 (2008) - **cgroup v2**: стабильна с ядра 4.5 (2016) - **Видов namespaces**: 8 (mnt, pid, net, ipc, uts, user, cgroup, time) - **Утилиты**: unshare, nsenter, lsns, systemd-cgls, systemd-cgtop **Namespaces** (пространства имён) и **cgroups** (*control groups*, контрольные группы) — два механизма ядра [Linux](https://llmdocs.ru/wiki/linux.md), из которых собирается то, что мы называем контейнером. Пространства имён отвечают на вопрос «*что* процесс видит»: свой список процессов, свою сеть, свою файловую систему, своё имя хоста. Контрольные группы отвечают на вопрос «*сколько* процесс может потребить»: процессорного времени, памяти, операций ввода-вывода. Контейнер — это обычный процесс, запущенный в отдельных namespaces и помещённый в свою cgroup; никакой виртуальной машины при этом нет. ## История Первым в 2002 году появилось пространство имён точек монтирования (mount namespace, ядро 2.4.19), вдохновлённое ОС Plan 9. Остальные добавлялись постепенно, и набор, достаточный для полноценных контейнеров, сложился к ядру 3.8 (2013) с появлением user namespaces.[6] Механизм cgroups инженеры Google начали разрабатывать в 2006 году под названием «process containers»; в ядро он вошёл в 2.6.24 (2008). Из-за запутанной иерархии первой версии была создана **cgroup v2** с единым деревом, стабильная с ядра 4.5 (2016).[3] На этих механизмах построены LXC (2008), [Docker](https://llmdocs.ru/wiki/docker.md) (2013) и все современные среды выполнения. ## Пространства имён Каждый процесс принадлежит одному пространству имён каждого вида; по умолчанию — общим «корневым».[1] | Вид | Флаг | Что изолирует | |---|---|---| | mnt | `CLONE_NEWNS` | дерево точек монтирования (своя корневая ФС) | | pid | `CLONE_NEWPID` | номера процессов: внутри контейнера приложение — PID 1 | | net | `CLONE_NEWNET` | сетевые интерфейсы, маршруты, правила iptables, порты | | ipc | `CLONE_NEWIPC` | очереди сообщений и разделяемую память System V / POSIX | | uts | `CLONE_NEWUTS` | имя хоста и домена | | user | `CLONE_NEWUSER` | UID/GID: root внутри может быть обычным пользователем снаружи | | cgroup | `CLONE_NEWCGROUP` | видимую часть дерева cgroups | | time | `CLONE_NEWTIME` | смещения часов `CLOCK_MONOTONIC` и `CLOCK_BOOTTIME` | Пространства создаются системными вызовами `clone()` и `unshare()`, присоединиться к существующему можно через `setns()`. Они видны как файлы в `/proc//ns/`. **User namespaces** особенно важны для безопасности: они позволяют запускать контейнеры без прав root на хосте (*rootless*-режим [Podman](https://llmdocs.ru/wiki/podman.md) и Docker).[4] ## Контрольные группы cgroup — это узел иерархии в виртуальной файловой системе `/sys/fs/cgroup`, к которому привязаны процессы и **контроллеры** ресурсов.[2] В cgroup v2 основные контроллеры такие: - **cpu** — веса (`cpu.weight`) и жёсткие квоты (`cpu.max`, например `50000 100000` = половина ядра); - **memory** — лимит (`memory.max`); при его превышении внутри группы срабатывает OOM killer; - **io** — ограничение пропускной способности и IOPS для блочных устройств; - **pids** — максимальное число процессов (защита от fork-бомбы); - **cpuset** — привязка к конкретным ядрам и NUMA-узлам. В современных дистрибутивах деревом cgroups управляет [systemd](https://llmdocs.ru/wiki/systemd.md): каждая служба, пользовательская сессия и контейнер получают свою группу. [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) переводит `requests` и `limits` из описания [Pod](https://llmdocs.ru/wiki/pod.md) в настройки cgroup на узле; начиная с версии 1.25 поддержка cgroup v2 стабильна, а cgroup v1 объявлена устаревшей.[5] ## Попробовать вручную ```bash # новая оболочка в отдельных pid-, mount- и uts-пространствах sudo unshare --pid --fork --mount-proc --uts bash hostname sandbox; ps aux # видны только процессы этой оболочки # пространства имён процесса и вход в них (как docker exec) lsns -p sudo nsenter -t -n ip addr # сеть контейнера # cgroups systemd-cgls # дерево групп systemd-run --scope -p MemoryMax=200M -p CPUQuota=50% ./heavy_job cat /sys/fs/cgroup/system.slice/nginx.service/memory.current ``` ## Изоляция и её пределы Все контейнеры на хосте делят **одно ядро**. Уязвимость в ядре или опасные привилегии (`--privileged`, монтирование сокета Docker, лишние capabilities) позволяют выбраться из контейнера. Поэтому namespaces и cgroups дополняют другими механизмами: capabilities (дробление прав root), seccomp (фильтр системных вызовов), AppArmor и SELinux. Для более жёсткой изоляции применяют песочницы вроде gVisor и микро-VM вроде Kata Containers и Firecracker. ## См. также - [Контейнеризация](https://llmdocs.ru/wiki/containerization.md) - [Образ контейнера и OCI](https://llmdocs.ru/wiki/oci-image.md) - [Процессы и сигналы](https://llmdocs.ru/wiki/processes-signals.md) - [Права доступа в Unix](https://llmdocs.ru/wiki/unix-permissions.md) ## Источники 1. [man 7 namespaces — overview of Linux namespaces](https://man7.org/linux/man-pages/man7/namespaces.7.html) 2. [man 7 cgroups — Linux control groups](https://man7.org/linux/man-pages/man7/cgroups.7.html) 3. [Linux kernel docs — Control Group v2](https://docs.kernel.org/admin-guide/cgroup-v2.html) 4. [man 7 user_namespaces](https://man7.org/linux/man-pages/man7/user_namespaces.7.html) 5. [Kubernetes Docs — About cgroup v2](https://kubernetes.io/docs/concepts/architecture/cgroups/) 6. [LWN — Namespaces in operation (series, 2013)](https://lwn.net/Articles/531114/) --- # Образ контейнера и OCI > Образ контейнера — неизменяемый пакет из слоёв файловой системы и конфигурации; OCI — открытые спецификации формата образа, среды выполнения и реестров. Источник: https://llmdocs.ru/wiki/oci-image/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Организация**: Open Container Initiative (Linux Foundation) - **Основана**: июнь 2015 - **Спецификации**: Image Spec, Runtime Spec, Distribution Spec - **Версии 1.0**: июль 2017 (Image и Runtime), май 2021 (Distribution) - **Эталонная среда**: runc - **Адресация**: SHA-256 дайджесты (content-addressable) - **Инструменты**: Docker, Podman, Buildah, containerd, skopeo, crane **Образ контейнера** (англ. *container image*) — неизменяемый пакет, содержащий всё, что нужно для запуска приложения: файловую систему с программой и её зависимостями плюс метаданные о том, как её запускать (команда, переменные окружения, рабочий каталог, пользователь). Из одного образа можно запустить сколько угодно контейнеров. **OCI** (*Open Container Initiative*) — организация при Linux Foundation, которая стандартизировала формат образов, способ их запуска и протокол раздачи, чтобы образ, собранный одним инструментом, работал в любом другом.[4] ## История Формат образов в массы принёс [Docker](https://llmdocs.ru/wiki/docker.md) (2013). Когда вокруг контейнеров выросла экосистема, конкуренты (CoreOS со своим форматом appc) и сама Docker договорились о едином стандарте: в июне 2015 года была основана OCI. Docker передал в неё код своей низкоуровневой среды выполнения — так появился **runc** — и формат образа Docker v2, ставший основой спецификации. Версии 1.0 Image Spec и Runtime Spec вышли в 2017 году, Distribution Spec — в 2021-м, а версия 1.1 (2024) добавила хранение произвольных артефактов (подписей, SBOM) рядом с образами.[6] ## Три спецификации | Спецификация | Что описывает | |---|---| | Image Spec[1] | формат образа: манифест, конфигурация, слои, индекс для нескольких платформ | | Runtime Spec[2] | как запустить «распакованный» контейнер (bundle): каталог `rootfs` + `config.json` | | Distribution Spec[3] | HTTP API реестра для загрузки и выгрузки образов (`/v2/...`) | Благодаря этому разделению Docker, Podman, Buildah, containerd и CRI-O взаимозаменяемы: собрали образ одним — запустили другим, а [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) работает с любой совместимой средой. ## Устройство образа Образ OCI состоит из объектов, каждый из которых адресуется по содержимому — SHA-256 дайджесту (например, `sha256:9b2a…`): - **Слои** (*layers*) — tar-архивы (обычно сжатые gzip или zstd) с изменениями файловой системы. Каждая инструкция `RUN`, `COPY`, `ADD` в [Dockerfile](https://llmdocs.ru/wiki/dockerfile.md) порождает новый слой. Удаление файла в верхнем слое записывается специальной меткой *whiteout*. - **Конфигурация** — JSON с командой запуска (`Entrypoint`, `Cmd`), переменными, портами, архитектурой и историей сборки. - **Манифест** — JSON со ссылками на конфигурацию и слои по дайджестам. - **Индекс** (*image index*, «мультиархитектурный образ») — список манифестов для разных платформ: `linux/amd64`, `linux/arm64` и т. д. Клиент сам выбирает подходящий. При запуске контейнера слои накладываются друг на друга с помощью объединяющей файловой системы (обычно **overlayfs**), а сверху добавляется тонкий записываемый слой контейнера.[5] Слои общие: если десять образов основаны на одном `python:3.12-slim`, базовые слои хранятся и скачиваются один раз. ## Теги и дайджесты Полное имя образа: `реестр/репозиторий:тег@дайджест`, например `docker.io/library/nginx:1.27`. - **Тег** — изменяемый ярлык: `latest` или `1.27` сегодня и через месяц могут указывать на разные образы. - **Дайджест** — неизменяемый: `nginx@sha256:…` всегда даёт ровно тот же образ. В продакшене и CI образы рекомендуют фиксировать по дайджесту. Тег `latest` не означает «самый новый» — это просто тег по умолчанию, который никто не обязан обновлять. ## Работа с образами ```bash docker build -t registry.example.com/app:1.4.0 . # собрать docker image inspect app:1.4.0 # конфигурация и слои docker history app:1.4.0 # какой инструкцией создан каждый слой docker push registry.example.com/app:1.4.0 # загрузить в реестр docker buildx build --platform linux/amd64,linux/arm64 -t app:1.4.0 --push . skopeo inspect docker://docker.io/library/alpine:3.20 # посмотреть образ без скачивания ``` Образы хранятся в реестрах ([Container registry](https://llmdocs.ru/wiki/container-registry.md)): Docker Hub, GitHub Container Registry, GitLab Registry, Harbor, облачные реестры. ## Хорошие практики - Минимальная база: `alpine`, `-slim`, distroless — меньше размер и меньше уязвимостей. - [Многоэтапная сборка (multi-stage)](https://llmdocs.ru/wiki/multi-stage-build.md): компилятор и инструменты сборки остаются в промежуточном этапе и не попадают в итоговый образ. - Порядок инструкций от редко меняющихся к часто меняющимся — так кеш слоёв работает лучше. - Не класть секреты в слои: удалённый в следующем слое файл всё равно остаётся в истории образа. - Подписывать образы (cosign, Notation) и сканировать на уязвимости (Trivy, Grype). ## См. также - [Контейнеризация](https://llmdocs.ru/wiki/containerization.md) - [Namespaces и cgroups](https://llmdocs.ru/wiki/namespaces-cgroups.md) - [Podman](https://llmdocs.ru/wiki/podman.md) - [Pod](https://llmdocs.ru/wiki/pod.md) ## Источники 1. [OCI Image Format Specification](https://github.com/opencontainers/image-spec) 2. [OCI Runtime Specification](https://github.com/opencontainers/runtime-spec) 3. [OCI Distribution Specification](https://github.com/opencontainers/distribution-spec) 4. [Open Container Initiative — About](https://opencontainers.org/about/overview/) 5. [Docker Docs — Storage drivers and image layers](https://docs.docker.com/engine/storage/drivers/) 6. [OCI Image Spec v1.1 — Artifacts and referrers](https://github.com/opencontainers/image-spec/blob/main/manifest.md) --- # PersistentVolume > Абстракция постоянного хранилища в Kubernetes — тома, переживающие перезапуск подов; запрашиваются через PersistentVolumeClaim и создаются динамически по StorageClass. Источник: https://llmdocs.ru/wiki/persistentvolume/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Объекты**: PersistentVolume, PersistentVolumeClaim, StorageClass - **Связанный контроллер**: StatefulSet - **Режимы доступа**: RWO, ROX, RWX, RWOP - **Интерфейс драйверов**: Container Storage Interface (CSI) - **Политики возврата**: Retain, Delete - **Примеры хранилищ**: облачные диски, NFS, Ceph (Rook), Longhorn, local-path **PersistentVolume** (PV, постоянный том) — объект [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md), представляющий кусок хранилища в кластере: облачный диск, сетевую папку NFS, том в Ceph или каталог на узле. В отличие от файловой системы контейнера, которая исчезает вместе с [подом](https://llmdocs.ru/wiki/pod.md), данные на PersistentVolume сохраняются при перезапуске, пересоздании и переносе пода на другой узел. Поэтому именно через PV в Kubernetes запускают базы данных, очереди и всё, что хранит состояние. ## Три объекта Хранилище в Kubernetes разделено на роли администратора и разработчика:[1] | Объект | Кто создаёт | Что описывает | |---|---|---| | **PersistentVolume** | администратор или автоматически | конкретный том: размер, тип, где находится | | **PersistentVolumeClaim** (PVC) | разработчик | заявку: «нужно 10 ГиБ, запись с одного узла» | | **StorageClass** | администратор | «тип хранилища» и драйвер, создающий тома по заявкам | Под ссылается не на PV, а на PVC — так манифест приложения не зависит от того, где кластер работает: в облаке, на собственном железе или на ноутбуке. ## Пример ```yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: data spec: accessModes: [ReadWriteOnce] storageClassName: fast-ssd resources: requests: storage: 10Gi --- apiVersion: v1 kind: Pod metadata: name: db spec: containers: - name: postgres image: postgres:17 volumeMounts: - name: data mountPath: /var/lib/postgresql/data volumes: - name: data persistentVolumeClaim: claimName: data ``` ## Динамическое выделение В современных кластерах PV почти никогда не создают вручную. Когда появляется PVC с указанным StorageClass, **провижинер** — драйвер CSI — сам создаёт диск у провайдера и соответствующий PV, после чего связывает его с заявкой (статус `Bound`).[2] Один StorageClass обычно помечен как класс по умолчанию. ```yaml apiVersion: storage.k8s.io/v1 kind: StorageClass metadata: name: fast-ssd provisioner: ebs.csi.aws.com parameters: type: gp3 reclaimPolicy: Delete allowVolumeExpansion: true volumeBindingMode: WaitForFirstConsumer ``` Режим `WaitForFirstConsumer` откладывает создание тома, пока под не назначен на узел, — иначе диск может оказаться в другой зоне доступности, чем под. ## Режимы доступа - **ReadWriteOnce (RWO)** — чтение и запись с одного узла; типично для блочных дисков. - **ReadOnlyMany (ROX)** — только чтение с многих узлов. - **ReadWriteMany (RWX)** — запись с многих узлов; нужна файловая система с общим доступом (NFS, CephFS, облачные файловые хранилища). - **ReadWriteOncePod (RWOP)** — запись только из одного пода во всём кластере. Частая ошибка — ждать от облачного блочного диска режима RWX: он не поддерживается, и под на втором узле не запустится. ## Жизненный цикл и политики Когда PVC удаляют, судьба тома определяется политикой `reclaimPolicy`: **Delete** — диск удаляется вместе с данными (по умолчанию для динамических томов), **Retain** — PV остаётся в статусе `Released`, и данные можно восстановить вручную. Для важных баз данных разумно использовать `Retain` и всё равно делать резервные копии. Тома можно увеличивать (`allowVolumeExpansion`) — уменьшать нельзя. Механизм **VolumeSnapshot** создаёт снимки томов средствами хранилища.[4] ## StatefulSet Для приложений с состоянием используется контроллер **StatefulSet**: в отличие от [Deployment](https://llmdocs.ru/wiki/deployment-replicaset.md), он даёт подам стабильные имена (`db-0`, `db-1`) и через `volumeClaimTemplates` создаёт каждому реплике свой PVC, который сохраняется при пересоздании пода.[3] Сложные системы с репликацией и переключением обычно разворачивают через [оператор](https://llmdocs.ru/wiki/kubernetes-operator.md), который сам управляет StatefulSet и томами. ## CSI и типы хранилищ **Container Storage Interface** — стандарт, по которому производители хранилищ пишут драйверы для Kubernetes и других оркестраторов, не меняя код самого Kubernetes.[5] Распространённые варианты: - **Облачные диски** — AWS EBS, Google Persistent Disk, Azure Disk, диски Yandex Cloud. - **Локальные тома** — `local-path-provisioner` (по умолчанию в [k3s](https://llmdocs.ru/wiki/k3s.md)): быстро, но данные привязаны к узлу. - **Распределённые** — Rook/Ceph, Longhorn, OpenEBS: реплицируют данные между узлами собственного кластера. - **NFS** — простой вариант для RWX. ## Диагностика ```bash kubectl get pvc,pv kubectl describe pvc data # события: почему не Bound kubectl get storageclass ``` Если PVC висит в `Pending`, причины обычно три: нет подходящего StorageClass, драйвер не установлен или заявка требует неподдерживаемый режим доступа. ## См. также - [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) - [Pod](https://llmdocs.ru/wiki/pod.md) - [Оператор Kubernetes](https://llmdocs.ru/wiki/kubernetes-operator.md) - [ConfigMap и Secret](https://llmdocs.ru/wiki/configmap-secret.md) ## Источники 1. [Kubernetes Docs — Persistent Volumes](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) 2. [Kubernetes Docs — Storage Classes](https://kubernetes.io/docs/concepts/storage/storage-classes/) 3. [Kubernetes Docs — StatefulSets](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/) 4. [Kubernetes Docs — Volume Snapshots](https://kubernetes.io/docs/concepts/storage/volume-snapshots/) 5. [Container Storage Interface specification](https://github.com/container-storage-interface/spec) --- # Pod > Минимальная единица развёртывания в Kubernetes — группа из одного или нескольких контейнеров с общей сетью и томами, которые всегда размещаются на одном узле. Источник: https://llmdocs.ru/wiki/pod/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: объект API Kubernetes (core/v1) - **Содержит**: один или несколько контейнеров + общие тома - **Сеть**: один IP-адрес на под, общий для всех контейнеров - **Время жизни**: эфемерный, не переносится между узлами - **Фазы**: Pending, Running, Succeeded, Failed, Unknown - **Обычно создаётся**: Deployment, StatefulSet, DaemonSet, Job **Pod** (под; от англ. *pod* — «стручок», также «стая китов» — отсылка к логотипу Docker) — минимальная единица, которую [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) размещает и запускает. Под — это группа из одного или нескольких контейнеров, которые всегда работают вместе на одном узле, разделяют сетевое пространство (один IP-адрес, общий `localhost`) и могут монтировать общие тома.[1] Kubernetes управляет не отдельными контейнерами, а подами: планирует, перезапускает и удаляет их целиком. ## Зачем группа, а не контейнер Под моделирует «логический хост»: процессы, которые на обычном сервере работали бы рядом и общались через `localhost` или общие файлы. Технически контейнеры пода делят сетевое и IPC-[пространства имён](https://llmdocs.ru/wiki/namespaces-cgroups.md), а их ресурсы находятся в общей родительской cgroup. Чаще всего в поде ровно один контейнер, но бывают и вспомогательные: - **init-контейнеры** — выполняются последовательно до старта основных: дождаться базы данных, применить миграции, скачать конфигурацию.[3] - **sidecar-контейнеры** — работают рядом с основным всё время его жизни: прокси service mesh, сборщик логов, обновляющий сертификаты агент. С версии 1.29 (стабильно в 1.33) их объявляют как init-контейнеры с `restartPolicy: Always`, чтобы они стартовали раньше и останавливались позже основного.[4] ## Пример манифеста ```yaml apiVersion: v1 kind: Pod metadata: name: web labels: app: web spec: containers: - name: app image: ghcr.io/example/web:1.4.0 ports: - containerPort: 8000 env: - name: LOG_LEVEL value: info resources: requests: {cpu: 250m, memory: 256Mi} limits: {memory: 512Mi} readinessProbe: httpGet: {path: /healthz, port: 8000} periodSeconds: 5 livenessProbe: httpGet: {path: /healthz, port: 8000} initialDelaySeconds: 10 ``` Поля `labels` нужны, чтобы другие объекты находили под: [Service](https://llmdocs.ru/wiki/service-ingress.md) направляет на него трафик, ReplicaSet считает реплики. ## Жизненный цикл Под проходит фазы **Pending** (принят, ждёт размещения или скачивания образа), **Running**, **Succeeded** или **Failed** (все контейнеры завершились), **Unknown** (узел недоступен).[2] Внутри пода kubelet следит за контейнерами и перезапускает их по политике `restartPolicy` (`Always`, `OnFailure`, `Never`) с нарастающей задержкой — отсюда знакомый статус `CrashLoopBackOff`. Под **эфемерен**: если узел выходит из строя или под удаляют, он не «переезжает», а исчезает. Новый под — уже другой объект с другим именем и IP. Поэтому голые поды почти не создают вручную: за нужным числом реплик следят контроллеры — [Deployment](https://llmdocs.ru/wiki/deployment-replicaset.md), StatefulSet (стабильные имена и тома), DaemonSet (по поду на узел), Job и CronJob (разовые и периодические задачи). При удалении kubelet отправляет главному процессу контейнера SIGTERM, ждёт `terminationGracePeriodSeconds` (по умолчанию 30 секунд) и затем посылает SIGKILL — приложение должно корректно обрабатывать сигналы (см. [Процессы и сигналы](https://llmdocs.ru/wiki/processes-signals.md)). ## Пробы Kubelet проверяет состояние контейнера тремя видами проб (HTTP-запрос, TCP-подключение, команда или gRPC):[6] | Проба | Если не проходит | |---|---| | `startupProbe` | остальные пробы не запускаются, пока приложение стартует; при провале — перезапуск | | `livenessProbe` | контейнер перезапускается | | `readinessProbe` | под исключается из балансировки Service, но не перезапускается | Типичная ошибка — делать liveness-пробу зависимой от базы данных: при сбое БД Kubernetes начнёт бесконечно перезапускать здоровые поды. ## Ресурсы `requests` — сколько ресурсов гарантировано; по ним планировщик выбирает узел. `limits` — потолок: превышение CPU приводит к троттлингу, превышение памяти — к завершению контейнера с причиной `OOMKilled`.[5] По соотношению requests и limits под получает класс качества обслуживания (QoS): Guaranteed, Burstable или BestEffort — он определяет порядок вытеснения при нехватке памяти на узле. ## Полезные команды ```bash kubectl get pods -o wide # статус, узел, IP kubectl describe pod web # события: почему Pending, почему перезапуск kubectl logs web -c app --previous # логи упавшего экземпляра kubectl exec -it web -- sh # оболочка внутри контейнера kubectl port-forward pod/web 8000:8000 ``` Подробнее об утилите — в статье [kubectl](https://llmdocs.ru/wiki/kubectl.md). ## См. также - [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) - [ConfigMap и Secret](https://llmdocs.ru/wiki/configmap-secret.md) - [PersistentVolume](https://llmdocs.ru/wiki/persistentvolume.md) - [Автомасштабирование (HPA)](https://llmdocs.ru/wiki/hpa.md) ## Источники 1. [Kubernetes Docs — Pods](https://kubernetes.io/docs/concepts/workloads/pods/) 2. [Kubernetes Docs — Pod Lifecycle](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/) 3. [Kubernetes Docs — Init Containers](https://kubernetes.io/docs/concepts/workloads/pods/init-containers/) 4. [Kubernetes Docs — Sidecar Containers](https://kubernetes.io/docs/concepts/workloads/pods/sidecar-containers/) 5. [Kubernetes Docs — Resource Management for Pods and Containers](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) 6. [Kubernetes Docs — Configure Liveness, Readiness and Startup Probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) --- # Podman > Инструмент для запуска контейнеров без демона и без прав root, совместимый с командной строкой Docker; развивается Red Hat. Источник: https://llmdocs.ru/wiki/podman/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Разработчик**: Red Hat и сообщество (проект Containers) - **Первый выпуск**: 2018 (1.0 — январь 2019) - **Язык**: Go - **Лицензия**: Apache 2.0 - **Архитектура**: без демона (fork/exec), rootless - **Совместимость**: CLI Docker, образы OCI, Docker API - **Связанные инструменты**: Buildah, Skopeo, CRI-O - **Платформы**: Linux; macOS и Windows через виртуальную машину **Podman** (*Pod Manager*) — программа для сборки, запуска и управления контейнерами в Linux, альтернатива [Docker](https://llmdocs.ru/wiki/docker.md). Его главные отличия — отсутствие постоянно работающего демона и запуск контейнеров от обычного пользователя без прав root (rootless). Команды Podman повторяют Docker настолько точно, что многие пользователи просто делают `alias docker=podman`. Podman по умолчанию входит в Red Hat Enterprise Linux, Fedora и CentOS Stream. ## История Podman вырос в Red Hat из проекта libpod в 2017–2018 годах как часть набора инструментов, разбирающих монолитный Docker на независимые части: **Buildah** — сборка образов, **Skopeo** — копирование и проверка образов в реестрах, **CRI-O** — среда выполнения для [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md), **Podman** — запуск контейнеров.[1] Версия 1.0 вышла в 2019 году. С версии 2.0 Podman предоставляет REST API, совместимый с Docker, а Podman Desktop — графический интерфейс для macOS и Windows. ## Архитектура | | Docker | Podman | |---|---|---| | Демон | `dockerd` работает постоянно от root | нет: каждый контейнер — дочерний процесс команды | | Права | по умолчанию root (есть rootless-режим) | rootless по умолчанию для пользователя | | Поды | нет (только в Compose/Kubernetes) | встроенные поды, как в Kubernetes | | Автозапуск | политика restart демона | [systemd](https://llmdocs.ru/wiki/systemd.md) через Quadlet | | Сборка | BuildKit | Buildah (встроен) | Без демона нет единой точки отказа и привилегированного сокета: доступ к `/var/run/docker.sock` фактически равен правам root на хосте, а у Podman такого сокета по умолчанию нет. Каждый контейнер запускается через небольшой процесс-монитор `conmon` и низкоуровневую среду выполнения (`crun` или `runc`), совместимую со стандартом OCI.[2] ## Rootless-контейнеры В rootless-режиме Podman использует пространства имён пользователей (user namespaces, см. [Namespaces и cgroups](https://llmdocs.ru/wiki/namespaces-cgroups.md)): root внутри контейнера отображается на непривилегированного пользователя хоста через диапазоны из `/etc/subuid` и `/etc/subgid`.[3] Даже при выходе из контейнера злоумышленник получит только права этого пользователя. Сеть в rootless-режиме обеспечивает `pasta` (раньше `slirp4netns`). Ограничения: без дополнительных настроек нельзя слушать порты ниже 1024, а файлы в смонтированных томах могут получить неожиданные UID. ## Основные команды ```bash podman run -d --name web -p 8080:80 docker.io/library/nginx:alpine podman ps podman logs -f web podman build -t myapp . # тот же Dockerfile (Containerfile) podman images podman push myapp registry.example.com/myapp:1.0 ``` Короткие имена образов (`nginx`) Podman разрешает по списку реестров в `/etc/containers/registries.conf`; надёжнее всегда указывать полный адрес, например `docker.io/library/nginx`. Файл сборки может называться `Containerfile`, но `Dockerfile` тоже подходит, включая [многоэтапную сборку](https://llmdocs.ru/wiki/multi-stage-build.md). ## Поды Как и в Kubernetes, под — группа контейнеров с общим сетевым пространством имён: ```bash podman pod create --name app -p 8080:80 podman run -d --pod app docker.io/library/postgres:17 podman run -d --pod app myapp podman kube generate app > app.yaml # манифест Kubernetes podman kube play app.yaml # и обратно ``` Это удобно для локальной разработки: связку контейнеров можно отладить на ноутбуке и получить заготовку манифеста для [Pod](https://llmdocs.ru/wiki/pod.md) в кластере. ## Интеграция с systemd Для сервисов на сервере Podman предлагает **Quadlet**: контейнер описывается декларативным файлом `.container`, из которого systemd сам генерирует юнит.[4] ```ini # ~/.config/containers/systemd/web.container [Container] Image=docker.io/library/nginx:alpine PublishPort=8080:80 AutoUpdate=registry [Install] WantedBy=default.target ``` После `systemctl --user daemon-reload` контейнер управляется как обычная служба: запуск при загрузке, перезапуск при сбое, логи в journald. `podman auto-update` обновляет такие контейнеры при появлении новой версии образа. ## Совместимость с Docker - `podman compose` вызывает docker-compose или podman-compose; [Docker Compose](https://llmdocs.ru/wiki/docker-compose.md)-файлы в большинстве случаев работают без изменений. - Включив сокет (`systemctl --user enable --now podman.socket`), можно направить на Podman инструменты, ожидающие Docker API, через `DOCKER_HOST`. - На macOS и Windows Podman, как и Docker Desktop, запускает Linux в виртуальной машине (`podman machine`). Отличия проявляются в деталях: сетевые настройки, поведение томов в rootless-режиме и отсутствие Docker Swarm. ## См. также - [Docker](https://llmdocs.ru/wiki/docker.md) - [Контейнеризация](https://llmdocs.ru/wiki/containerization.md) - [Namespaces и cgroups](https://llmdocs.ru/wiki/namespaces-cgroups.md) - [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) ## Источники 1. [Podman — официальный сайт](https://podman.io/) 2. [Podman Documentation](https://docs.podman.io/) 3. [Podman — Rootless tutorial](https://github.com/containers/podman/blob/main/docs/tutorials/rootless_tutorial.md) 4. [podman-systemd.unit(5) — Quadlet](https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html) 5. [Buildah — официальный сайт](https://buildah.io/) --- # Service и Ingress > Сетевые объекты Kubernetes — Service даёт группе подов постоянный адрес и балансирует трафик, Ingress маршрутизирует внешние HTTP(S)-запросы к сервисам по домену и пути. Источник: https://llmdocs.ru/wiki/service-ingress/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: объекты API Kubernetes (core/v1 Service, networking.k8s.io/v1 Ingress) - **Типы Service**: ClusterIP, NodePort, LoadBalancer, ExternalName - **Обнаружение**: DNS-имя <сервис>..svc.cluster.local - **Реализация Service**: kube-proxy (iptables, IPVS, nftables) или eBPF (Cilium) - **Ingress GA**: Kubernetes 1.19 (2020) - **Преемник Ingress**: Gateway API (GA в октябре 2023) - **Контроллеры Ingress**: ingress-nginx, Traefik, HAProxy, Contour, облачные **Service** и **Ingress** — объекты [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md), решающие задачу «как достучаться до приложения». [Поды](https://llmdocs.ru/wiki/pod.md) постоянно пересоздаются и каждый раз получают новый IP-адрес, поэтому обращаться к ним напрямую нельзя. **Service** даёт группе подов стабильное имя и виртуальный IP и распределяет между ними запросы.[1] **Ingress** публикует сервисы наружу по HTTP(S): направляет `api.example.com` в один сервис, `example.com/static` — в другой и завершает [TLS](https://llmdocs.ru/wiki/tls.md).[2] ## Service Service выбирает поды по меткам — теми же селекторами, что использует [Deployment](https://llmdocs.ru/wiki/deployment-replicaset.md). Список адресов готовых подов (прошедших readiness-пробу) хранится в объектах EndpointSlice и обновляется автоматически. ```yaml apiVersion: v1 kind: Service metadata: name: web spec: selector: app: web ports: - port: 80 # порт сервиса targetPort: 8000 # порт контейнера ``` Внутри кластера к сервису обращаются по [DNS](https://llmdocs.ru/wiki/dns.md)-имени: `web` из того же пространства имён или полностью `web.prod.svc.cluster.local`.[3] За разрешение имён отвечает CoreDNS. ### Типы | Тип | Доступен | Как работает | |---|---|---| | `ClusterIP` (по умолчанию) | только внутри кластера | виртуальный IP, трафик распределяется по подам | | `NodePort` | снаружи, `IP_узла:порт` | порт из диапазона 30000–32767 открывается на всех узлах | | `LoadBalancer` | снаружи, отдельный IP | облако или MetalLB создаёт внешний балансировщик, ведущий на NodePort | | `ExternalName` | внутри | DNS-псевдоним (CNAME) на внешний хост | Особый случай — **headless**-сервис (`clusterIP: None`): виртуального IP нет, DNS возвращает адреса всех подов. Его используют StatefulSet'ы, чтобы обращаться к конкретной реплике (`db-0.db`). ### Как это реализовано Виртуальный IP сервиса не принадлежит ни одному интерфейсу. На каждом узле компонент **kube-proxy** следит за сервисами и программирует ядро — правила iptables, IPVS или nftables, — которые подменяют адрес назначения на IP одного из подов (по сути [NAT](https://llmdocs.ru/wiki/nat.md)).[4] Сетевые плагины на eBPF, например Cilium, умеют делать то же самое без kube-proxy. Балансировка работает на уровне TCP/UDP-соединений, а не отдельных HTTP-запросов (см. [Балансировка нагрузки](https://llmdocs.ru/wiki/load-balancing.md)). ## Ingress Создавать по LoadBalancer на каждое приложение дорого и неудобно. Ingress описывает правила маршрутизации HTTP, а реализует их **Ingress-контроллер** — по сути [обратный прокси](https://llmdocs.ru/wiki/reverse-proxy.md) внутри кластера, обычно доступный через единственный LoadBalancer. Сам Kubernetes контроллер не включает — его устанавливают отдельно: ingress-nginx на базе [nginx](https://llmdocs.ru/wiki/nginx.md), Traefik, HAProxy, облачные варианты. ```yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: web annotations: cert-manager.io/cluster-issuer: letsencrypt spec: ingressClassName: nginx tls: - hosts: [example.com] secretName: example-com-tls rules: - host: example.com http: paths: - path: /api pathType: Prefix backend: service: {name: api, port: {number: 80}} - path: / pathType: Prefix backend: service: {name: web, port: {number: 80}} ``` Сертификат хранится в Secret (см. [ConfigMap и Secret](https://llmdocs.ru/wiki/configmap-secret.md)); его выпуск и продление через [Let's Encrypt](https://llmdocs.ru/wiki/lets-encrypt-acme.md) автоматизирует cert-manager. Слабое место Ingress — бедная стандартная спецификация: таймауты, переписывание путей, ограничение частоты запросов задаются аннотациями, свои у каждого контроллера, и манифесты плохо переносятся. ## Gateway API Преемником Ingress стал **Gateway API** (версия 1.0 вышла в октябре 2023 года).[5] Он разделяет роли: оператор кластера описывает `GatewayClass` и `Gateway` (точку входа, порты, сертификаты), а команды приложений — маршруты `HTTPRoute`, `GRPCRoute`, `TLSRoute`. Разделение трафика по весам, сопоставление по заголовкам и межпространственные ссылки входят в стандарт, а не в аннотации. Ingress не удалён и продолжает работать, но новые возможности развиваются в Gateway API; проект ingress-nginx объявил о прекращении сопровождения в марте 2026 года.[6] ## Отладка ```bash kubectl get svc,endpointslices -l app=web kubectl describe ingress web kubectl run tmp --rm -it --image=busybox -- wget -qO- http://web # запрос изнутри кластера kubectl port-forward svc/web 8080:80 ``` Пустой список endpoints почти всегда означает, что селектор сервиса не совпадает с метками подов или поды не проходят readiness-пробу. ## См. также - [Pod](https://llmdocs.ru/wiki/pod.md) - [Service mesh](https://llmdocs.ru/wiki/service-mesh.md) - [Сетевые плагины (CNI)](https://llmdocs.ru/wiki/cni.md) - [Обратный прокси (reverse proxy)](https://llmdocs.ru/wiki/reverse-proxy.md) ## Источники 1. [Kubernetes Docs — Service](https://kubernetes.io/docs/concepts/services-networking/service/) 2. [Kubernetes Docs — Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) 3. [Kubernetes Docs — DNS for Services and Pods](https://kubernetes.io/docs/concepts/services-networking/dns-pod-service/) 4. [Kubernetes Docs — Virtual IPs and Service Proxies](https://kubernetes.io/docs/reference/networking/virtual-ips/) 5. [Gateway API](https://gateway-api.sigs.k8s.io/) 6. [Kubernetes Blog — Ingress NGINX Retirement (November 2025)](https://kubernetes.io/blog/2025/11/11/ingress-nginx-retirement/) --- # Service mesh > Инфраструктурный слой для связи микросервисов — шифрование mTLS, маршрутизация, повторы, метрики и трассировка без изменения кода; примеры — Istio, Linkerd, Cilium. Источник: https://llmdocs.ru/wiki/service-mesh/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Назначение**: управление трафиком между сервисами - **Архитектура**: data plane (прокси) + control plane - **Прокси**: Envoy, linkerd2-proxy (Rust), eBPF - **Реализации**: Istio, Linkerd, Cilium Service Mesh, Consul, Kuma - **Режимы**: sidecar, sidecarless (ambient, eBPF) - **Стандарты**: Gateway API (GAMMA), SPIFFE **Service mesh** (сервисная сетка) — отдельный инфраструктурный слой, через который проходит весь сетевой трафик между сервисами приложения. Сетка берёт на себя то, что иначе пришлось бы реализовать в каждом сервисе: взаимное шифрование и аутентификацию ([mTLS](https://llmdocs.ru/wiki/tls.md)), повторы и тайм-ауты, [балансировку](https://llmdocs.ru/wiki/load-balancing.md), постепенный перевод трафика на новую версию, метрики и распределённую трассировку. Код приложения при этом не меняется. Чаще всего service mesh разворачивают поверх [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md). ## Зачем В монолите вызов другого модуля — вызов функции. В микросервисной архитектуре это сетевой запрос, который может потеряться, зависнуть или прийти от злоумышленника. Компании вроде Twitter и Netflix в 2010-х решали это библиотеками (Finagle, Hystrix), но библиотеки привязаны к языку и требуют обновления всех сервисов. Service mesh выносит эти функции из процесса в прокси рядом с ним — так подход стал независимым от языка.[1] ## Архитектура | Плоскость | Что делает | Примеры | |---|---|---| | **Data plane** | прокси, через которые идёт трафик: шифрование, маршрутизация, сбор метрик | Envoy, linkerd2-proxy, ztunnel | | **Control plane** | раздаёт прокси конфигурацию и сертификаты, следит за сервисами | istiod, Linkerd control plane | Классическая схема — **сайдкар**: в каждый [Pod](https://llmdocs.ru/wiki/pod.md) автоматически добавляется контейнер-прокси, а правила iptables перенаправляют через него весь входящий и исходящий трафик. Прокси двух сервисов устанавливают между собой mTLS-соединение, проверяя криптографическую идентичность друг друга — обычно в формате SPIFFE (`spiffe://cluster.local/ns/shop/sa/payments`).[6] Сайдкары расходуют память и процессор на каждом поде и усложняют обновления, поэтому появились **режимы без сайдкаров**: Istio ambient mode использует общий L4-прокси на узле (ztunnel) и необязательные L7-прокси на пространство имён,[2] а Cilium реализует часть функций в ядре через eBPF (см. [Сетевые плагины (CNI)](https://llmdocs.ru/wiki/cni.md)). ## Возможности - **Безопасность.** Автоматический mTLS между всеми сервисами без ручного управления сертификатами; политики авторизации «сервис A может вызывать `GET /orders` у сервиса B». Это основа модели нулевого доверия (zero trust). - **Управление трафиком.** Канареечные релизы (5% трафика на новую версию), маршрутизация по заголовкам, зеркалирование трафика, внесение задержек и ошибок для тестирования устойчивости. - **Надёжность.** Тайм-ауты, повторы с ограничением, автоматический выключатель (circuit breaker), исключение неисправных экземпляров. - **Наблюдаемость.** «Золотые сигналы» — частота запросов, ошибки, задержки — для каждой пары сервисов без изменения кода; экспорт в [Prometheus](https://llmdocs.ru/wiki/prometheus.md) и трассировку через [OpenTelemetry](https://llmdocs.ru/wiki/opentelemetry.md). ## Реализации - **Istio** — самая функциональная сетка (Google, IBM, Lyft), прокси Envoy, режимы sidecar и ambient. Выпускник CNCF. - **Linkerd** — упор на простоту и производительность: собственный лёгкий прокси на Rust, mTLS включён по умолчанию.[3] - **Cilium Service Mesh** — на базе eBPF и Envoy, совмещён с CNI. - **Consul** (HashiCorp) и **Kuma** — работают также вне Kubernetes, на виртуальных машинах. Прокси **Envoy**, созданный в Lyft, стал фактическим стандартом data plane и используется также в API-шлюзах и ingress-контроллерах.[4] ## Пример: канареечный релиз в Istio ```yaml apiVersion: networking.istio.io/v1 kind: VirtualService metadata: name: reviews spec: hosts: [reviews] http: - route: - destination: {host: reviews, subset: v1} weight: 90 - destination: {host: reviews, subset: v2} weight: 10 ``` Инициатива **GAMMA** переносит такие правила на стандартные ресурсы Gateway API (`HTTPRoute`), чтобы конфигурация не зависела от конкретной сетки.[5] Gateway API — развитие [Ingress](https://llmdocs.ru/wiki/service-ingress.md). ## Когда нужен Service mesh добавляет движущиеся части: control plane, прокси, сертификаты, новый слой для отладки. Он оправдан, когда сервисов десятки, требуется обязательный mTLS (регуляторика, zero trust) или нужны единые метрики и канареечные релизы для всех команд. Для нескольких сервисов обычно достаточно ingress-контроллера, сетевых политик CNI и библиотек трассировки в коде. Начинать разумно с минимального набора — mTLS и метрики — и включать сложную маршрутизацию по мере необходимости. ## См. также - [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) - [Service и Ingress](https://llmdocs.ru/wiki/service-ingress.md) - [Сетевые плагины (CNI)](https://llmdocs.ru/wiki/cni.md) - [Мониторинг и алертинг](https://llmdocs.ru/wiki/monitoring-alerting.md) ## Источники 1. [Istio — What is a service mesh](https://istio.io/latest/about/service-mesh/) 2. [Istio — Ambient mode overview](https://istio.io/latest/docs/ambient/overview/) 3. [Linkerd — Documentation](https://linkerd.io/2/overview/) 4. [Envoy proxy — What is Envoy](https://www.envoyproxy.io/docs/envoy/latest/intro/what_is_envoy) 5. [Kubernetes Gateway API — GAMMA initiative](https://gateway-api.sigs.k8s.io/mesh/gamma/) 6. [SPIFFE — Secure Production Identity Framework for Everyone](https://spiffe.io/docs/latest/spiffe-about/overview/) --- # cron и таймеры systemd > Средства запуска задач по расписанию в Linux — классический cron с файлами crontab и таймеры systemd с журналированием, зависимостями и догоняющими запусками. Источник: https://llmdocs.ru/wiki/cron-systemd-timers/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **cron**: Unix Version 7 (1979); Vixie cron (1987); сейчас cronie и др. - **Формат crontab**: минута, час, день месяца, месяц, день недели, команда - **Таймеры systemd**: юниты .timer + .service - **Расписание в systemd**: OnCalendar, OnBootSec, OnUnitActiveSec - **Пропущенные запуски**: anacron, Persistent=true - **В Kubernetes**: CronJob **cron** — классический планировщик Unix, запускающий команды по расписанию: каждую минуту, каждую ночь в 3:00, по понедельникам. Расписание хранится в файлах **crontab**. **Таймеры systemd** — современная альтернатива в системах на [systemd](https://llmdocs.ru/wiki/systemd.md): расписание описывается юнитом `.timer`, который запускает парный юнит `.service`, с журналированием, зависимостями, ограничением ресурсов и догоняющим запуском пропущенных задач. Типичные задачи по расписанию: резервные копии ([Бэкапы: правило 3-2-1](https://llmdocs.ru/wiki/backup-3-2-1.md)), ротация и очистка логов, обновление сертификатов ([Let's Encrypt и ACME](https://llmdocs.ru/wiki/lets-encrypt-acme.md)), выгрузки отчётов, синхронизация данных. ## cron cron появился в Unix Version 7 (1979). Широко распространённую реализацию написал Пол Викси в 1987 году; современные дистрибутивы используют её потомков — cronie и аналоги.[6] Демон `crond` каждую минуту проверяет таблицы и запускает подходящие задачи. ### Формат crontab ```text # ┌───────── минута (0–59) # │ ┌─────── час (0–23) # │ │ ┌───── день месяца (1–31) # │ │ │ ┌─── месяц (1–12) # │ │ │ │ ┌─ день недели (0–7, 0 и 7 — воскресенье) # │ │ │ │ │ 0 3 * * * /usr/local/bin/backup.sh >> /var/log/backup.log 2>&1 */5 * * * * /usr/local/bin/healthcheck.sh 0 9 * * 1-5 /usr/local/bin/report.sh 30 2 1 * * /usr/local/bin/monthly-cleanup.sh @reboot /usr/local/bin/on-boot.sh ``` `*` — любое значение, `*/5` — каждые 5, `1-5` — диапазон, `1,15` — список. Сокращения `@hourly`, `@daily`, `@weekly`, `@reboot` заменяют частые варианты.[1] Проверить выражение удобно на crontab.guru.[4] ```bash crontab -e # редактировать таблицу текущего пользователя crontab -l # показать sudo ls /etc/cron.d /etc/cron.daily # системные задачи ``` ### Подводные камни cron - **Минимальное окружение.** Задача запускается не из вашей интерактивной оболочки: `PATH` урезан, [переменные](https://llmdocs.ru/wiki/environment-variables.md) из `~/.bashrc` не загружены. Используйте абсолютные пути или задайте `PATH=` в начале crontab. - **Вывод теряется** или уходит письмом на локальную почту. Перенаправляйте его в файл или журнал явно. - **Символ `%`** в crontab означает перевод строки — в командах вроде `date +%F` его нужно экранировать: `\%`. - **Наложение запусков.** Если задача длится дольше интервала, запуски накладываются; защищаются блокировкой — `flock -n /tmp/job.lock команда`. - **Выключенная машина.** Задача, время которой пришлось на выключенный компьютер, не выполнится; для этого существует anacron. ## Таймеры systemd Задача описывается двумя юнитами: ```ini # /etc/systemd/system/backup.service [Unit] Description=Ночная резервная копия [Service] Type=oneshot User=backup ExecStart=/usr/local/bin/backup.sh Nice=10 IOSchedulingClass=idle ``` ```ini # /etc/systemd/system/backup.timer [Unit] Description=Запуск backup.service каждую ночь [Timer] OnCalendar=*-*-* 03:00:00 Persistent=true # выполнить пропущенный запуск после включения RandomizedDelaySec=15min # случайная задержка, чтобы не нагружать всё сразу [Install] WantedBy=timers.target ``` ```bash sudo systemctl daemon-reload sudo systemctl enable --now backup.timer systemctl list-timers # все таймеры и время следующего запуска journalctl -u backup.service # вывод всех запусков systemd-analyze calendar "Mon..Fri 09:00" # проверить выражение расписания sudo systemctl start backup.service # запустить вручную, вне расписания ``` Выражения `OnCalendar` читаются проще cron: `daily`, `weekly`, `Mon..Fri 09:00`, `*-*-01 02:30:00` (первого числа каждого месяца).[3] Помимо календаря есть относительные таймеры: `OnBootSec=5min` (через 5 минут после загрузки), `OnUnitActiveSec=1h` (через час после предыдущего запуска).[2] ## Сравнение | | cron | Таймеры systemd | |---|---|---| | Простота | одна строка | два файла | | Логи | нужно перенаправлять вручную | автоматически в журнал ([journald и логи](https://llmdocs.ru/wiki/journald-logs.md)) | | Пропущенные запуски | только с anacron | `Persistent=true` | | Наложение запусков | нужен `flock` | служба не запустится повторно, пока работает | | Зависимости и ресурсы | нет | `After=`, `Requires=`, лимиты памяти и процессора, песочница | | Ручной запуск | скопировать команду | `systemctl start` | | Переносимость | любые Unix-системы, контейнеры | только системы на systemd | Для серверов на systemd таймеры обычно надёжнее, а cron остаётся удобным для быстрых пользовательских задач и систем без systemd. ## Расписание в контейнерах и облаке В [Docker](https://llmdocs.ru/wiki/docker.md)-контейнерах нет ни cron, ни systemd по умолчанию — задачи по расписанию запускают снаружи (таймером на хосте) или отдельным контейнером с планировщиком. В [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) для этого есть объект **CronJob** с тем же синтаксисом расписания, что и у cron, и настройками параллелизма и истории запусков.[5] В CI-системах вроде [GitHub Actions](https://llmdocs.ru/wiki/github-actions.md) периодические задания тоже задаются выражениями cron. ## Советы - Логируйте результат и время выполнения каждой задачи, а об ошибках — оповещайте (см. [Мониторинг и алертинг](https://llmdocs.ru/wiki/monitoring-alerting.md)): тихо сломавшийся ночной бэкап обнаруживается только тогда, когда он нужен. - Делайте задачи идемпотентными: повторный запуск не должен ничего портить. - Учитывайте часовой пояс сервера и переходы на летнее время там, где они есть. ## См. также - [systemd](https://llmdocs.ru/wiki/systemd.md) - [journald и логи](https://llmdocs.ru/wiki/journald-logs.md) - [Бэкапы: правило 3-2-1](https://llmdocs.ru/wiki/backup-3-2-1.md) - [Shell и Bash](https://llmdocs.ru/wiki/shell-bash.md) - [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) ## Источники 1. [crontab(5) — Linux manual page](https://man7.org/linux/man-pages/man5/crontab.5.html) 2. [systemd.timer — manual](https://www.freedesktop.org/software/systemd/man/latest/systemd.timer.html) 3. [systemd.time — Calendar Events](https://www.freedesktop.org/software/systemd/man/latest/systemd.time.html) 4. [crontab.guru — редактор выражений cron](https://crontab.guru/) 5. [Kubernetes — CronJob](https://kubernetes.io/docs/concepts/workloads/controllers/cron-jobs/) 6. [cronie — GitHub](https://github.com/cronie-crond/cronie) --- # curl > Утилита командной строки и библиотека libcurl для передачи данных по URL — HTTP(S), FTP, SFTP и десяткам других протоколов; стандартный инструмент для работы с веб-API. Источник: https://llmdocs.ru/wiki/curl/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: утилита командной строки и библиотека - **Автор**: Даниэль Стенберг - **Первый выпуск**: 1998 (предшественники — с 1996) - **Язык**: C - **Лицензия**: curl license (разрешительная, в духе MIT) - **Протоколы**: HTTP/1.1, HTTP/2, HTTP/3, FTP, SFTP, SCP, SMTP, IMAP, MQTT, WebSocket и др. - **Встроен в**: macOS, Windows 10 и новее, большинство дистрибутивов Linux - **Сайт**: curl.se **curl** (от *client URL*, произносится «кёрл») — утилита командной строки для передачи данных по URL, а **libcurl** — библиотека, на которой она построена. curl умеет отправлять и получать данные по [HTTP](https://llmdocs.ru/wiki/http.md) и HTTPS, FTP, SFTP, SMTP и ещё нескольким десяткам протоколов, поддерживает [TLS](https://llmdocs.ru/wiki/tls.md), прокси, cookies, загрузку файлов и аутентификацию. Для разработчика это главный инструмент проверки веб-сервисов и [REST](https://llmdocs.ru/wiki/rest.md)-API прямо из терминала. libcurl встроена в огромное количество программ и устройств — от автомобилей и телевизоров до игровых консолей, — поэтому curl часто называют одной из самых распространённых программ в мире.[3] ## История Шведский программист Даниэль Стенберг в 1996 году начал развивать небольшую программу httpget для загрузки курсов валют в IRC-бот. После добавления FTP её переименовали в urlget, а 20 марта 1998 года вышла версия 4.0 под именем curl.[2] Библиотека libcurl появилась в 2000 году. Стенберг остаётся ведущим разработчиком больше четверти века; проект выпускает новую версию примерно каждые восемь недель и известен тщательной работой с уязвимостями. curl распространяется под собственной разрешительной лицензией, близкой к MIT, что позволяет использовать libcurl в закрытых продуктах.[4] С 2018 года curl входит в состав Windows 10, в macOS и большинстве дистрибутивов [Linux](https://llmdocs.ru/wiki/linux.md) он есть из коробки. ## Основы ```bash curl https://example.com # тело ответа в stdout curl -o page.html https://example.com # сохранить в файл curl -O https://example.com/file.tar.gz # сохранить под исходным именем curl -L https://git.io/xyz # следовать редиректам curl -I https://example.com # только заголовки (HEAD) curl -i https://example.com # заголовки и тело curl -v https://example.com # подробно: DNS, TLS, заголовки curl -fsSL https://example.com/install.sh # тихо, но с ошибками; падать на HTTP 4xx/5xx ``` По умолчанию curl не считает ответы 404 или 500 ошибкой и завершается с кодом 0. Флаг `-f` (`--fail`) делает код выхода ненулевым при [кодах ответа](https://llmdocs.ru/wiki/http-status-codes.md) 400 и выше — без него скрипты в [Bash](https://llmdocs.ru/wiki/shell-bash.md) молча продолжают работу после сбоя. ## Работа с API ```bash # GET с заголовком авторизации curl -H "Authorization: Bearer $TOKEN" https://api.example.com/v1/users/42 # POST JSON (флаг --json появился в 7.82.0, 2022) curl --json '{"name": "Алиса"}' https://api.example.com/v1/users # то же явно curl -X POST -H 'Content-Type: application/json' \ -d '{"name": "Алиса"}' https://api.example.com/v1/users # отправка формы и файла curl -F 'avatar=@photo.jpg' -F 'user=42' https://api.example.com/upload # разбор ответа через jq curl -s https://api.github.com/repos/curl/curl | jq '.stargazers_count' ``` Флаг `-d` автоматически переключает метод на POST, а `-X` задаёт метод явно (PUT, PATCH, DELETE). Ответ в JSON удобно разбирать утилитой [jq](https://llmdocs.ru/wiki/json.md).[1] ## Диагностика curl — первый инструмент при отладке сетевых проблем: ```bash # время по фазам: DNS, соединение, TLS, первый байт, всего curl -o /dev/null -s -w 'dns %{time_namelookup} tcp %{time_connect} tls %{time_appconnect} ttfb %{time_starttransfer} total %{time_total}\n' https://example.com # обратиться к конкретному IP, сохранив имя хоста (SNI и заголовок Host) curl --resolve example.com:443:203.0.113.10 https://example.com curl --http2 -I https://example.com # принудительно HTTP/2 curl --http3 -I https://example.com # HTTP/3 поверх QUIC (если собран с поддержкой) curl -x socks5h://127.0.0.1:1080 https://example.com # через прокси ``` Ключ `--resolve` позволяет проверить новый сервер до переключения [DNS](https://llmdocs.ru/wiki/dns.md), а `-v` показывает рукопожатие TLS и выбранный по ALPN протокол. Поддержка HTTP/3 зависит от того, с какой TLS-библиотекой собран curl.[5] ## Безопасность - Ключ `-k` (`--insecure`) отключает проверку сертификата сервера. Он допустим только для отладки: в скриптах он делает соединение уязвимым для перехвата. Правильное решение — указать доверенный корневой сертификат через `--cacert`.[6] - Шаблон установки `curl ... | sh` запускает чужой код без проверки; безопаснее скачать скрипт, прочитать и только потом выполнить. - Токены в командной строке видны в истории оболочки и списке процессов; их лучше передавать через [переменные окружения](https://llmdocs.ru/wiki/environment-variables.md) или файл (`-H @headers.txt`, `--netrc`). ## Альтернативы Wget удобнее для рекурсивной загрузки сайтов и докачки файлов; HTTPie и xh предлагают более дружелюбный синтаксис для API. В [Python](https://llmdocs.ru/wiki/python.md) ту же роль играют библиотеки requests и httpx, а многие из них умеют превращать запрос в эквивалентную команду curl — она стала универсальным языком описания HTTP-запросов в документации. ## См. также - [HTTP](https://llmdocs.ru/wiki/http.md) - [REST](https://llmdocs.ru/wiki/rest.md) - [jq](https://llmdocs.ru/wiki/json.md) - [TLS](https://llmdocs.ru/wiki/tls.md) - [Коды состояния HTTP](https://llmdocs.ru/wiki/http-status-codes.md) ## Источники 1. [curl — man page](https://curl.se/docs/manpage.html) 2. [curl — History](https://curl.se/docs/history.html) 3. [Everything curl — книга Даниэля Стенберга](https://everything.curl.dev/) 4. [curl — License](https://curl.se/docs/copyright.html) 5. [curl — HTTP/3 support](https://curl.se/docs/http3.html) 6. [curl — SSL certificate verification](https://curl.se/docs/sslcerts.html) --- # Переменные окружения > Именованные строковые значения, которые каждый процесс получает от родителя и передаёт дочерним; через них настраиваются программы — PATH, HOME, LANG, адреса сервисов, режимы работы и ключи доступа. Источник: https://llmdocs.ru/wiki/environment-variables/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Что это**: пары ИМЯ=значение в окружении процесса - **Наследование**: копируются от родителя к дочернему процессу - **Просмотр**: env, printenv, echo $ИМЯ - **Установка в Bash**: export ИМЯ=значение - **Стандартные**: PATH, HOME, USER, SHELL, LANG, TZ, PWD - **Принцип конфигурации**: The Twelve-Factor App — конфигурация в окружении **Переменные окружения** — именованные строковые значения вида `ИМЯ=значение`, которые есть у каждого процесса в Unix-подобных системах (и в Windows). Процесс получает копию окружения от родителя при запуске и может передать её — с изменениями — своим дочерним процессам.[1] Через переменные окружения программы узнают, где искать исполняемые файлы (`PATH`), домашний каталог пользователя (`HOME`), язык интерфейса (`LANG`), а приложения — адрес базы данных, режим работы и ключи доступа к API. Переменные окружения — стандартный способ настраивать приложения, особенно в контейнерах и облаке. ## Основы ```bash echo $HOME # прочитать printenv PATH # то же env # все переменные окружения export APP_ENV=production # установить для текущей оболочки и всех дочерних процессов DEBUG=1 python app.py # установить только для одной команды unset APP_ENV # удалить ``` Важно различать **переменные оболочки** и **переменные окружения**. Присваивание `NAME=value` в [Bash](https://llmdocs.ru/wiki/shell-bash.md) создаёт переменную только в текущей оболочке; `export` делает её частью окружения, которое унаследуют запущенные программы.[3] Изменение окружения дочерним процессом никогда не влияет на родителя — поэтому скрипт, запущенный как `./set_env.sh`, не может поменять переменные вашей оболочки; для этого его выполняют через `source set_env.sh`. ## Стандартные переменные | Переменная | Значение | |---|---| | `PATH` | каталоги через двоеточие, где оболочка ищет команды | | `HOME` | домашний каталог пользователя | | `USER`, `LOGNAME` | имя пользователя | | `SHELL` | оболочка пользователя по умолчанию | | `PWD` | текущий каталог | | `LANG`, `LC_*` | язык и региональные настройки (`ru_RU.UTF-8`) | | `TZ` | часовой пояс (`Europe/Moscow`) | | `EDITOR` | редактор по умолчанию для `git commit`, `crontab -e` | | `TMPDIR` | каталог для временных файлов | Многие из них определены в стандарте POSIX.[2] Порядок каталогов в `PATH` важен: побеждает первая найденная программа. Узнать, какая именно запустится, помогает `command -v python` или `which python`. ## Где задаются постоянно - `~/.bashrc`, `~/.zshrc` — для интерактивных оболочек пользователя; - `~/.profile`, `~/.bash_profile` — для оболочек входа; - `/etc/environment`, `/etc/profile.d/*.sh` — для всех пользователей; - в юнитах [systemd](https://llmdocs.ru/wiki/systemd.md) — директивы `Environment=` и `EnvironmentFile=`: службы не читают `~/.bashrc`; - в crontab — строки `ИМЯ=значение` в начале файла (см. [cron и таймеры systemd](https://llmdocs.ru/wiki/cron-systemd-timers.md)). ## Конфигурация приложений Методология **The Twelve-Factor App** рекомендует хранить конфигурацию, которая отличается между окружениями (разработка, тест, продакшен), в переменных окружения, а не в коде: один и тот же собранный артефакт запускается везде, меняются только переменные.[4] ```python import os DATABASE_URL = os.environ["DATABASE_URL"] # обязательная — упадёт, если не задана DEBUG = os.environ.get("DEBUG", "0") == "1" # необязательная со значением по умолчанию WORKERS = int(os.getenv("WORKERS", "4")) ``` Все значения — строки, поэтому их нужно преобразовывать и проверять. Удобно делать это одной моделью настроек, например через pydantic-settings (см. [Dataclasses и Pydantic](https://llmdocs.ru/wiki/dataclasses-pydantic.md)).[5] ### Файлы .env При локальной разработке переменные хранят в файле `.env` в корне проекта: ```text DATABASE_URL=postgresql://app:secret@localhost:5432/app REDIS_URL=redis://localhost:6379/0 DEBUG=1 ``` Его загружают библиотеки вроде python-dotenv, [Docker Compose](https://llmdocs.ru/wiki/docker-compose.md) (автоматически для подстановок в `compose.yaml`)[6] и `uv run --env-file .env`. Файл `.env` с реальными значениями **никогда не коммитят** — в [Git](https://llmdocs.ru/wiki/git.md) кладут шаблон `.env.example` без секретов, а `.env` добавляют в `.gitignore`. ## Контейнеры и Kubernetes ```bash docker run -e APP_ENV=production --env-file prod.env myapp:1.0 ``` В [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) переменные контейнеров берутся из манифеста, ConfigMap и Secret (см. [ConfigMap и Secret](https://llmdocs.ru/wiki/configmap-secret.md)). Изменение переменной требует перезапуска процесса: окружение читается при старте и само не обновляется. ## Секреты в переменных окружения Переменные окружения — распространённый способ передать приложению пароли и ключи, но у него есть риски: - окружение процесса может прочитать тот же пользователь или root через `/proc//environ`; - переменные наследуются всеми дочерними процессами, в том числе сторонними утилитами; - они попадают в отчёты об ошибках, отладочный вывод и логи, если их неосторожно распечатать; - `docker inspect` показывает переменные контейнера. Для чувствительных данных лучше использовать специализированные хранилища и монтирование секретов файлами (см. [Управление секретами](https://llmdocs.ru/wiki/secrets-management.md)), а в переменных передавать хотя бы не больше, чем нужно. ## Типичные ошибки - Пробелы вокруг `=` в Bash: `export NAME = value` не работает, нужно `export NAME=value`. - Значения с пробелами без кавычек: `export GREETING="Привет, мир"`. - Служба systemd или задача cron «не видит» переменную из `~/.bashrc` — у них своё окружение. - Опечатка в имени необязательной переменной молча включает значение по умолчанию — обязательные настройки стоит проверять при старте. ## См. также - [Shell и Bash](https://llmdocs.ru/wiki/shell-bash.md) - [Управление секретами](https://llmdocs.ru/wiki/secrets-management.md) - [Docker Compose](https://llmdocs.ru/wiki/docker-compose.md) - [systemd](https://llmdocs.ru/wiki/systemd.md) - [ConfigMap и Secret](https://llmdocs.ru/wiki/configmap-secret.md) ## Источники 1. [environ(7) — Linux manual page](https://man7.org/linux/man-pages/man7/environ.7.html) 2. [POSIX.1-2024 — Environment Variables](https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap08.html) 3. [GNU Bash manual — Environment](https://www.gnu.org/software/bash/manual/html_node/Environment.html) 4. [The Twelve-Factor App — Config](https://12factor.net/config) 5. [Python — os.environ](https://docs.python.org/3/library/os.html#os.environ) 6. [Docker Docs — Set environment variables in Compose](https://docs.docker.com/compose/how-tos/environment-variables/) --- # Файловая система Unix (FHS) > Иерархия каталогов Unix и Linux с единым корнем / и стандарт FHS, определяющий назначение /etc, /usr, /var, /home, /tmp и других каталогов; а также inode, монтирование и виртуальные файловые системы. Источник: https://llmdocs.ru/wiki/fhs/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Стандарт**: Filesystem Hierarchy Standard - **Предшественник**: FSSTND (1994) - **Текущая версия**: FHS 3.0 (2015) - **Сопровождение**: Linux Foundation - **Принцип**: единое дерево с корнем /, устройства монтируются в каталоги - **Виртуальные ФС**: /proc, /sys, /dev, /run - **Файловые системы**: ext4, XFS, Btrfs, ZFS, tmpfs **Файловая система Unix** устроена как единое дерево каталогов с корнем `/`. В отличие от Windows с её дисками `C:` и `D:`, все устройства — диски, разделы, флешки, сетевые ресурсы — **монтируются** в каталоги этого дерева. Назначение стандартных каталогов в [Linux](https://llmdocs.ru/wiki/linux.md) описывает **FHS** (*Filesystem Hierarchy Standard* — стандарт иерархии файловой системы), благодаря которому администратор в любом [дистрибутиве](https://llmdocs.ru/wiki/linux-distribution.md) знает, где искать конфигурацию, логи и программы.[1] ## История стандарта В начале 1990-х каждый дистрибутив раскладывал файлы по-своему. В 1994 году вышел первый стандарт FSSTND, в 1997 году — FHS 2.0, обобщённый на все Unix-подобные системы, а в 2015 году Linux Foundation выпустила FHS 3.0. Современные системы на [systemd](https://llmdocs.ru/wiki/systemd.md) дополнительно описывают иерархию в документе `file-hierarchy(7)`.[3] ## Основные каталоги | Каталог | Назначение | |---|---| | `/` | корень всей иерархии | | `/etc` | конфигурация системы и служб: `/etc/ssh/sshd_config`, `/etc/nginx/` | | `/home` | домашние каталоги пользователей; `/root` — домашний каталог root | | `/usr` | установленные программы и данные только для чтения: `/usr/bin`, `/usr/lib`, `/usr/share` | | `/usr/local` | программы, установленные администратором вручную, вне пакетного менеджера | | `/opt` | крупные сторонние пакеты целиком: `/opt/google/chrome` | | `/var` | изменяющиеся данные: логи (`/var/log`), кэши, очереди, базы данных (`/var/lib/postgresql`) | | `/tmp` | временные файлы, часто очищается при перезагрузке | | `/srv` | данные, обслуживаемые сервером (сайты, FTP) | | `/boot` | ядро и загрузчик | | `/dev` | файлы устройств: `/dev/sda`, `/dev/null`, `/dev/random` | | `/proc`, `/sys` | виртуальные ФС с информацией о процессах и ядре | | `/run` | данные времени выполнения (PID-файлы, сокеты), в памяти | | `/mnt`, `/media` | точки монтирования — временные и съёмные носители | Исторически программы делились между `/bin` (необходимые для загрузки) и `/usr/bin`, потому что `/usr` мог находиться на отдельном диске. В большинстве современных дистрибутивов прошло **объединение `/usr`** (*usr merge*): `/bin`, `/sbin` и `/lib` стали символическими ссылками на соответствующие каталоги в `/usr`.[6] ## «Всё есть файл» Философия Unix представляет как файлы не только данные, но и устройства, процессы и параметры ядра:[2] - `/dev/sda` — диск целиком; запись в него — запись на диск напрямую. - `/dev/null` поглощает всё записанное, `/dev/zero` выдаёт нули, `/dev/urandom` — случайные байты. - `/proc//` — сведения о процессе (см. [Процессы и сигналы](https://llmdocs.ru/wiki/processes-signals.md)); `/proc/cpuinfo`, `/proc/meminfo` — о системе. - `/sys/` — устройства и параметры ядра; запись в некоторые файлы меняет настройки на лету. ## Inode и ссылки Файл на диске описывается **inode** — структурой с метаданными: тип, владелец, [права](https://llmdocs.ru/wiki/unix-permissions.md), размер, время изменения и расположение данных. Имя файла хранится не в inode, а в каталоге — это просто запись «имя → номер inode».[4] Отсюда: - **Жёсткая ссылка** (`ln a b`) — ещё одно имя того же inode; файл удаляется, когда исчезает последнее имя. - **Символическая ссылка** (`ln -s target link`) — отдельный маленький файл, содержащий путь к цели; может указывать на каталоги и другие файловые системы, но «ломается», если цель удалить. - Файловая система может закончиться не по месту, а по inode — если создано очень много мелких файлов (`df -i`). ## Монтирование ```bash lsblk # диски и разделы df -h # занятое место по точкам монтирования sudo mount /dev/sdb1 /mnt/data # подключить раздел findmnt # дерево смонтированных ФС cat /etc/fstab # что монтируется при загрузке du -sh /var/log/* | sort -h # что занимает место ``` Файл `/etc/fstab` описывает, какие разделы и куда монтировать при загрузке; современные системы указывают разделы по UUID, а не по именам вроде `/dev/sda1`, которые могут меняться.[5] ## Типы файловых систем | ФС | Особенности | |---|---| | ext4 | надёжный стандарт по умолчанию во многих дистрибутивах | | XFS | хорошо масштабируется на больших дисках, по умолчанию в RHEL | | Btrfs | копирование при записи, снимки, сжатие, подтома | | ZFS | снимки, контрольные суммы, RAID, встроенное сжатие | | tmpfs | ФС в оперативной памяти: `/tmp`, `/run` | | overlayfs | слои поверх друг друга — основа образов [Docker](https://llmdocs.ru/wiki/docker.md) | ## Практические советы - Конфигурацию служб ищите в `/etc`, логи — в `/var/log` или в журнале ([journald и логи](https://llmdocs.ru/wiki/journald-logs.md)), данные служб — в `/var/lib`. - Не устанавливайте файлы вручную в `/usr/bin` — это территория пакетного менеджера; для своего используйте `/usr/local` или `/opt`. - Следите за заполнением `/var`: разросшиеся логи и кэши — частая причина остановки серверов. - Размещайте данные баз и важные каталоги на отдельных разделах или томах, чтобы переполнение не затронуло систему. ## См. также - [Linux](https://llmdocs.ru/wiki/linux.md) - [Права доступа в Unix](https://llmdocs.ru/wiki/unix-permissions.md) - [journald и логи](https://llmdocs.ru/wiki/journald-logs.md) - [Процессы и сигналы](https://llmdocs.ru/wiki/processes-signals.md) - [find и xargs](https://llmdocs.ru/wiki/find-xargs.md) ## Источники 1. [Filesystem Hierarchy Standard 3.0](https://refspecs.linuxfoundation.org/FHS_3.0/fhs/index.html) 2. [hier(7) — Linux manual page](https://man7.org/linux/man-pages/man7/hier.7.html) 3. [file-hierarchy(7) — systemd](https://www.freedesktop.org/software/systemd/man/latest/file-hierarchy.html) 4. [inode(7) — Linux manual page](https://man7.org/linux/man-pages/man7/inode.7.html) 5. [mount(8) — Linux manual page](https://man7.org/linux/man-pages/man8/mount.8.html) 6. [freedesktop.org — The Case for the /usr Merge](https://www.freedesktop.org/wiki/Software/systemd/TheCaseForTheUsrMerge/) --- # find и xargs > find — утилита поиска файлов по имени, типу, размеру, времени изменения и другим признакам с выполнением действий над найденным; xargs превращает поток строк в аргументы команды. Источник: https://llmdocs.ru/wiki/find-xargs/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: утилиты командной строки Unix - **Появление**: PWB/Unix (1970-е) - **Реализации**: GNU findutils, BSD find, BusyBox - **Стандарт**: POSIX - **Безопасная работа с именами**: -print0 и xargs -0 - **Современная альтернатива**: fd (Rust) **find** — утилита Unix для поиска файлов и каталогов по множеству признаков: имени, типу, размеру, времени изменения, владельцу, [правам](https://llmdocs.ru/wiki/unix-permissions.md) — с возможностью сразу выполнить действие над каждым найденным файлом. **xargs** читает поток строк со стандартного ввода и подставляет их как аргументы в команду. Вместе они решают задачи вроде «удалить все логи старше 30 дней» или «найти все файлы `.py` и проверить их линтером». Обе утилиты появились в 1970-х в PWB/Unix и описаны в стандарте POSIX;[2][3] в [Linux](https://llmdocs.ru/wiki/linux.md) используется реализация GNU findutils. ## find: основы Синтаксис: `find [где искать] [условия] [действия]`. ```bash find . -name "*.py" # по шаблону имени (с учётом регистра) find . -iname "readme*" # без учёта регистра find /var/log -type f -name "*.log" # только файлы (d — каталоги, l — ссылки) find . -type f -size +100M # больше 100 МБ find . -mtime -1 # изменённые за последние сутки find /tmp -type f -mtime +7 -delete # удалить файлы старше 7 дней find . -empty -type d # пустые каталоги find . -user www-data ! -perm -u=r # владелец www-data, но без права чтения find . -name node_modules -prune -o -name "*.js" -print # не заходить в node_modules ``` Шаблон имени нужно брать в кавычки: иначе оболочка раскроет `*.py` в текущем каталоге до запуска find. ### Условия | Условие | Смысл | |---|---| | `-name`, `-iname`, `-path` | имя или путь по шаблону | | `-regex` | путь по [регулярному выражению](https://llmdocs.ru/wiki/regex.md) | | `-type f/d/l` | файл, каталог, символическая ссылка | | `-size +N/-N` | размер больше или меньше (k, M, G) | | `-mtime`, `-mmin`, `-newer` | время изменения в днях, минутах, новее файла | | `-user`, `-group`, `-perm` | владелец, группа, права | | `-maxdepth N` | глубина обхода | | `!`, `-o`, `( )` | отрицание, «или», группировка (скобки экранируются) | Условия, записанные подряд, объединяются через «и».[1] ### Действия ```bash find . -name "*.tmp" -delete # удалить find . -name "*.sh" -exec chmod +x {} \; # команда для каждого файла отдельно find . -name "*.py" -exec ruff check {} + # одна команда для пачки файлов — быстрее find . -type f -printf "%s %p\n" | sort -n | tail # самые большие файлы (GNU find) ``` `{}` заменяется именем файла. Вариант `\;` запускает команду для каждого файла, `+` — передаёт сразу много файлов в одну команду, что на порядки быстрее для тысяч файлов. ## xargs xargs читает строки и запускает команду, подставляя их в качестве аргументов, автоматически разбивая на пачки, чтобы не превысить ограничение длины командной строки. ```bash cat urls.txt | xargs -n 1 curl -sO # по одному аргументу на запуск grep -rl "TODO" src/ | xargs wc -l # число строк в файлах с TODO find . -name "*.log" -print0 | xargs -0 gzip # безопасно для имён с пробелами find . -name "*.png" -print0 | xargs -0 -P 8 -n 10 optipng # 8 процессов параллельно echo "a b c" | xargs -I{} echo "элемент: {}" ``` - **`-0` вместе с `find -print0`** разделяет имена нулевым байтом. Без этого имена с пробелами, кавычками и переводами строк разбиваются неправильно — частая причина ошибок и даже удаления не тех файлов. - **`-P N`** запускает до N процессов параллельно — простой способ задействовать все ядра. Для сложных случаев есть GNU Parallel.[5] - **`-I{}`** подставляет строку в заданное место команды, **`-n N`** ограничивает число аргументов на запуск. - **`-r`** (GNU) не запускает команду, если входных данных нет. ## Типичные рецепты ```bash # найти и удалить старые резервные копии, сначала проверив список find /backups -name "*.tar.gz" -mtime +30 -print find /backups -name "*.tar.gz" -mtime +30 -delete # что занимает место find / -xdev -type f -size +1G 2>/dev/null # поиск текста только в файлах определённого типа find . -name "*.yaml" -print0 | xargs -0 grep -n "image:" # переименовать расширение find . -name "*.jpeg" -exec sh -c 'mv "$1" "${1%.jpeg}.jpg"' _ {} \; ``` Перед `-delete` или деструктивным `-exec` полезно сначала запустить команду с `-print` и посмотреть список — find выполнит действие над всем найденным без вопросов. ## fd — современная альтернатива Утилита **fd**, написанная на [Rust](https://llmdocs.ru/wiki/rust.md), предлагает более простой синтаксис и разумные значения по умолчанию: ищет по подстроке или регулярному выражению, пропускает скрытые файлы и файлы из `.gitignore`, раскрашивает вывод и работает параллельно.[4] ```bash fd "\.py$" # аналог find . -name "*.py", без .gitignore-файлов fd -e log -x gzip # найти .log и сжать каждый fd -H config # включая скрытые файлы ``` Для поиска *содержимого* в файлах используют [grep](https://llmdocs.ru/wiki/grep.md) или ripgrep, для массовой правки текста — [sed и awk](https://llmdocs.ru/wiki/sed-awk.md). ## См. также - [grep и регулярные выражения](https://llmdocs.ru/wiki/grep.md) - [sed и awk](https://llmdocs.ru/wiki/sed-awk.md) - [Конвейеры и перенаправление (pipes)](https://llmdocs.ru/wiki/pipes-redirection.md) - [Файловая система Unix (FHS)](https://llmdocs.ru/wiki/fhs.md) - [Shell и Bash](https://llmdocs.ru/wiki/shell-bash.md) ## Источники 1. [GNU Findutils manual](https://www.gnu.org/software/findutils/manual/html_mono/find.html) 2. [POSIX.1-2024 — find](https://pubs.opengroup.org/onlinepubs/9799919799/utilities/find.html) 3. [POSIX.1-2024 — xargs](https://pubs.opengroup.org/onlinepubs/9799919799/utilities/xargs.html) 4. [fd — a simple, fast and user-friendly alternative to find](https://github.com/sharkdp/fd) 5. [GNU Parallel](https://www.gnu.org/software/parallel/) --- # grep и регулярные выражения > grep — классическая утилита Unix для поиска строк, соответствующих шаблону; шаблоны записываются регулярными выражениями в синтаксисах BRE, ERE или PCRE. Источник: https://llmdocs.ru/wiki/grep/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: утилита командной строки - **Автор**: Кен Томпсон - **Появилась**: 1973 (Unix Version 4) - **Название**: от команды ed g/re/p - **Реализации**: GNU grep, BSD grep, BusyBox, ripgrep (rg) - **Синтаксисы шаблонов**: BRE, ERE (-E), PCRE (-P), фиксированные строки (-F) - **Стандарт**: POSIX **grep** — утилита командной строки Unix, которая выводит строки файлов (или стандартного ввода), соответствующие заданному шаблону. Шаблоны записываются **регулярными выражениями** — компактным языком описания множеств строк. grep — один из самых часто используемых инструментов в [Linux](https://llmdocs.ru/wiki/linux.md): им ищут ошибки в логах, вызовы функций в коде, строки конфигурации и фильтруют вывод других программ в [конвейерах](https://llmdocs.ru/wiki/pipes-redirection.md). Название происходит от команды текстового редактора ed `g/re/p` — «глобально найти по регулярному выражению (*regular expression*) и напечатать». Слово «грепнуть» давно стало глаголом в жаргоне программистов. ## История Утилиту написал Кен Томпсон, один из создателей Unix; она вошла в Unix Version 4 (1973). Томпсон и раньше занимался регулярными выражениями: в 1968 году он опубликовал алгоритм их компиляции в автомат, который и сегодня лежит в основе быстрых движков. Позже появились варианты `egrep` (расширенные выражения) и `fgrep` (фиксированные строки); теперь вместо них используют ключи `grep -E` и `grep -F`.[1] Синтаксис выражений и поведение grep закреплены в стандарте POSIX.[3] ## Основные ключи ```bash grep ERROR app.log # строки, содержащие ERROR grep -i error app.log # без учёта регистра grep -v DEBUG app.log # строки, НЕ содержащие DEBUG grep -n 'def main' *.py # с номерами строк grep -c ERROR app.log # только количество совпадений grep -rn 'TODO' src/ # рекурсивно по каталогу grep -rl 'api_key' . # только имена файлов grep -w log file.txt # целое слово: log, но не login grep -o '[0-9]\+ms' app.log # вывести только совпавшую часть grep -A3 -B1 Traceback app.log # 3 строки после и 1 до совпадения grep -F '[x]' list.md # шаблон как обычная строка, без спецсимволов ps aux | grep -v grep | grep nginx # фильтр вывода другой команды ``` Код выхода grep — 0, если что-то найдено, 1, если ничего, и 2 при ошибке; на этом строятся проверки в скриптах ([Shell и Bash](https://llmdocs.ru/wiki/shell-bash.md)): `if grep -q ready status.txt; then ...`. ## Регулярные выражения Регулярное выражение — шаблон из обычных символов и метасимволов. Подробная теория — в статье [Регулярные выражения](https://llmdocs.ru/wiki/regex.md); ниже — то, что нужно для grep. | Конструкция | Смысл | Пример | |---|---|---| | `.` | любой символ | `h.t` — hat, hot, h1t | | `^`, `$` | начало и конец строки | `^#` — строки-комментарии | | `[abc]`, `[^0-9]` | символ из набора / не из набора | `[Ee]rror` | | `*` | 0 и более повторений | `ab*c` | | `+`, `?` | 1 и более / 0 или 1 (в ERE) | `colou?r` | | `{n,m}` | от n до m повторений (в ERE) | `[0-9]{3}` | | `\|` | альтернатива (в ERE) | `ERROR\|FATAL` | | `( )` | группировка (в ERE) | `(ab)+` | | `[[:digit:]]`, `[[:space:]]` | классы символов POSIX | | ### BRE, ERE и PCRE grep понимает несколько диалектов:[2] - **BRE** (базовые, по умолчанию) — `+`, `?`, `|`, `{}` и `()` считаются обычными символами, а для специального значения их нужно экранировать: `\+`, `\(`. Это источник постоянной путаницы. - **ERE** (расширенные, `grep -E`) — метасимволы работают без обратной косой черты. Для новых шаблонов удобнее всего. - **PCRE** (`grep -P`, только GNU grep) — синтаксис Perl: `\d`, `\w`, нежадные квантификаторы `*?`, просмотр вперёд и назад `(?=...)`.[5] Совпадает с привычными выражениями [Python](https://llmdocs.ru/wiki/python.md) и JavaScript. ```bash grep -E '^(ERROR|WARN) ' app.log # ERE grep -E '\b[0-9]{1,3}(\.[0-9]{1,3}){3}\b' access.log # похожее на IPv4 grep -oP '(?<=user_id=)\d+' app.log # PCRE: число после user_id= ``` Шаблон почти всегда стоит брать в **одинарные кавычки**: иначе оболочка сама раскроет `*`, `$` и `\` до того, как их увидит grep. ## ripgrep и другие альтернативы Для поиска по коду популярна утилита **ripgrep** (`rg`) Эндрю Галланта, написанная на [Rust](https://llmdocs.ru/wiki/rust.md) (2016). Она по умолчанию ищет рекурсивно, пропускает файлы из `.gitignore` и двоичные файлы, использует все ядра процессора и обычно заметно быстрее `grep -r` на больших репозиториях.[4] Для структурного поиска по коду применяют ast-grep, для поиска внутри JSON — [jq](https://llmdocs.ru/wiki/json.md), а для редактирования найденного — [sed и awk](https://llmdocs.ru/wiki/sed-awk.md). ```bash rg 'fn main' -t rust # только Rust-файлы rg -l TODO # файлы с TODO, с учётом .gitignore ``` ## Типичные ошибки - `grep '*.log'` — `*` в регулярном выражении означает «повторить предыдущее», а не «любые символы», как в шаблонах имён файлов оболочки. - Точка в IP-адресе или имени домена совпадает с любым символом; её нужно экранировать (`\.`) или использовать `-F`. - Конструкция `cat file | grep x` работает, но лишний `cat` не нужен: `grep x file`. - В выводе `grep -r` по огромным каталогам (`node_modules`, `.git`) теряются нужные совпадения — помогает `--exclude-dir` или ripgrep. ## См. также - [Регулярные выражения](https://llmdocs.ru/wiki/regex.md) - [sed и awk](https://llmdocs.ru/wiki/sed-awk.md) - [find и xargs](https://llmdocs.ru/wiki/find-xargs.md) - [Конвейеры и перенаправление (pipes)](https://llmdocs.ru/wiki/pipes-redirection.md) - [Shell и Bash](https://llmdocs.ru/wiki/shell-bash.md) ## Источники 1. [GNU grep manual](https://www.gnu.org/software/grep/manual/grep.html) 2. [POSIX.1-2024 — Regular Expressions](https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/V1_chap09.html) 3. [POSIX.1-2024 — grep](https://pubs.opengroup.org/onlinepubs/9799919799/utilities/grep.html) 4. [ripgrep — GitHub](https://github.com/BurntSushi/ripgrep) 5. [PCRE — Perl Compatible Regular Expressions](https://www.pcre.org/) --- # journald и логи > journald — служба журналирования systemd, собирающая структурированные логи ядра и всех служб; journalctl — инструмент их просмотра. Также о традиционных логах в /var/log, syslog и ротации. Источник: https://llmdocs.ru/wiki/journald-logs/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Служба**: systemd-journald (часть systemd) - **Инструмент просмотра**: journalctl - **Хранение**: двоичный журнал в /var/log/journal (постоянно) или /run/log/journal (до перезагрузки) - **Источники**: ядро, stdout/stderr служб, syslog, sd_journal API - **Уровни важности**: 0 (emerg) — 7 (debug), по RFC 5424 - **Традиционные инструменты**: rsyslog, /var/log, logrotate **journald** (служба `systemd-journald`) — компонент [systemd](https://llmdocs.ru/wiki/systemd.md), который собирает логи со всей системы: сообщения ядра, стандартный вывод и поток ошибок каждой службы, сообщения syslog. Записи хранятся в структурированном двоичном журнале с метаданными — время, служба, PID, пользователь, уровень важности, — по которым их можно быстро фильтровать. Просматривают журнал утилитой **`journalctl`**.[2] Логи — первое, куда смотрят при любой проблеме на сервере: почему не запустилась служба, что случилось перед падением, кто подключался по [SSH](https://llmdocs.ru/wiki/ssh.md). ## Как устроен журнал Служба, запущенная systemd, может не заботиться о файлах логов: всё, что она пишет в stdout и stderr, автоматически попадает в журнал с пометкой, от какого юнита оно пришло. Каждая запись — набор полей: `MESSAGE`, `PRIORITY`, `_SYSTEMD_UNIT`, `_PID`, `_UID`, `_HOSTNAME`, `_BOOT_ID` и другие. Приложения могут добавлять собственные поля через API. Журнал хранится в `/var/log/journal/`, если каталог существует (постоянное хранение), иначе — в `/run/log/journal/`, в памяти до перезагрузки. Размер ограничивается настройками в `/etc/systemd/journald.conf`, например `SystemMaxUse=1G`; старые записи удаляются автоматически.[3] ## journalctl ```bash journalctl -u nginx # логи одной службы journalctl -u nginx -f # следить в реальном времени journalctl -u nginx --since "1 hour ago" journalctl -u nginx --since "2026-11-09 10:00" --until "2026-11-09 11:00" journalctl -b # с момента текущей загрузки journalctl -b -1 -p err # ошибки предыдущей загрузки (после сбоя) journalctl -k # сообщения ядра (как dmesg) journalctl -p warning # уровень warning и важнее journalctl _PID=1234 # по полю journalctl -u myapp -o json-pretty -n 5 # последние 5 записей со всеми полями journalctl -u myapp -o cat # только текст сообщений journalctl --disk-usage # сколько места занимает журнал sudo journalctl --vacuum-time=14d # удалить записи старше 14 дней ``` Фильтры комбинируются: `journalctl -u nginx -u php-fpm -p err --since today`.[1] ## Уровни важности Уровни унаследованы от протокола syslog (RFC 5424):[4] | Код | Имя | Значение | |---|---|---| | 0 | emerg | система неработоспособна | | 1 | alert | нужно немедленное действие | | 2 | crit | критическое состояние | | 3 | err | ошибка | | 4 | warning | предупреждение | | 5 | notice | нормальное, но значимое событие | | 6 | info | информационное сообщение | | 7 | debug | отладка | ## Традиционные логи: /var/log До systemd логи писал демон syslog (сегодня — обычно rsyslog) в текстовые файлы каталога `/var/log` (см. [Файловая система Unix (FHS)](https://llmdocs.ru/wiki/fhs.md)). Многие системы используют оба механизма: journald принимает сообщения и передаёт их rsyslog, а тот раскладывает по файлам. | Файл | Содержимое | |---|---| | `/var/log/syslog` или `/var/log/messages` | общий системный журнал (Debian/Ubuntu и RHEL соответственно) | | `/var/log/auth.log` или `/var/log/secure` | входы, `sudo`, SSH | | `/var/log/nginx/`, `/var/log/postgresql/` | логи отдельных приложений | | `/var/log/kern.log` | сообщения ядра | Текстовые файлы растут бесконечно, поэтому их **ротирует** утилита logrotate: по расписанию переименовывает текущий файл, сжимает старые и удаляет самые давние.[5] Работа с текстовыми логами — основная область [grep](https://llmdocs.ru/wiki/grep.md), [sed и awk](https://llmdocs.ru/wiki/sed-awk.md) и `tail -f`. ## Логи в контейнерах В [Docker](https://llmdocs.ru/wiki/docker.md) приложения тоже пишут в stdout и stderr, а драйвер логирования сохраняет вывод (`docker logs -f container`). Драйвер `journald` отправляет логи контейнеров прямо в журнал хоста. Для драйвера по умолчанию `json-file` важно задать ограничение размера (`max-size`, `max-file`), иначе логи заполнят диск. В [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) логи читают через `kubectl logs`. ## Централизованное логирование Когда серверов и контейнеров много, логи собирают в одно место: - **Сборщики** — Vector, Fluent Bit, Promtail/Alloy, rsyslog — читают журнал и файлы и отправляют дальше. - **Хранилища** — Grafana Loki (индексирует только метки, дёшево),[6] Elasticsearch/OpenSearch (полнотекстовый поиск), [ClickHouse](https://llmdocs.ru/wiki/clickhouse.md). - **Интерфейсы** — Grafana, Kibana. Связь логов с метриками и трассировками описывает статья [Логирование и трассировка (OpenTelemetry)](https://llmdocs.ru/wiki/opentelemetry.md). ## Хорошие практики - Пишите **структурированные** логи (JSON или пары ключ-значение) с идентификатором запроса — их можно фильтровать и агрегировать. - Не логируйте секреты, пароли, токены и лишние персональные данные. - Используйте уровни осмысленно: `error` — то, что требует внимания, `debug` — выключен в продакшене. - Включите постоянное хранение журнала (`mkdir -p /var/log/journal`), чтобы логи переживали перезагрузку и можно было разобрать причину сбоя. - Ограничьте размер логов и следите за свободным местом на диске. ## См. также - [systemd](https://llmdocs.ru/wiki/systemd.md) - [Логирование и трассировка (OpenTelemetry)](https://llmdocs.ru/wiki/opentelemetry.md) - [Мониторинг и алертинг](https://llmdocs.ru/wiki/monitoring-alerting.md) - [grep и регулярные выражения](https://llmdocs.ru/wiki/grep.md) - [Процессы и сигналы](https://llmdocs.ru/wiki/processes-signals.md) ## Источники 1. [journalctl — manual](https://www.freedesktop.org/software/systemd/man/latest/journalctl.html) 2. [systemd-journald.service — manual](https://www.freedesktop.org/software/systemd/man/latest/systemd-journald.service.html) 3. [journald.conf — manual](https://www.freedesktop.org/software/systemd/man/latest/journald.conf.html) 4. [RFC 5424 — The Syslog Protocol](https://www.rfc-editor.org/rfc/rfc5424) 5. [logrotate — GitHub](https://github.com/logrotate/logrotate) 6. [Grafana Loki — документация](https://grafana.com/docs/loki/latest/) --- # Дистрибутив Linux > Готовая операционная система на основе ядра Linux — с системными утилитами, пакетным менеджером, программой установки и политикой выпусков; Debian, Ubuntu, Fedora, RHEL, Arch, Alpine и сотни других. Источник: https://llmdocs.ru/wiki/linux-distribution/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Состав**: ядро Linux, системные библиотеки (glibc или musl), init (systemd), утилиты, пакетный менеджер - **Первые дистрибутивы**: SLS и Slackware (1992–1993), Debian (1993) - **Семейства**: Debian, Red Hat, Arch, SUSE, Alpine, Gentoo - **Модели выпусков**: фиксированные (с LTS), скользящие (rolling) - **Пакетные форматы**: .deb, .rpm, pacman, apk - **Каталог дистрибутивов**: DistroWatch **Дистрибутив Linux** — готовая к установке операционная система, построенная на ядре [Linux](https://llmdocs.ru/wiki/linux.md). Само ядро — лишь часть системы: чтобы получить работающий компьютер, к нему нужны системные библиотеки, командная оболочка и утилиты, система инициализации ([systemd](https://llmdocs.ru/wiki/systemd.md)), [пакетный менеджер](https://llmdocs.ru/wiki/package-managers.md), программа установки, а для настольных систем — графическое окружение. Дистрибутив собирает всё это вместе, тестирует совместимость, выпускает обновления безопасности и определяет политику: какие версии программ включать и как долго их поддерживать. Существуют сотни дистрибутивов, но большинство принадлежит нескольким семействам. ## История Первыми дистрибутивами в 1992 году стали MCC Interim Linux и SLS; в 1993 году появились Slackware Патрика Фолькердинга (старейший из живущих) и **Debian** Иэна Мёрдока — проект, управляемый сообществом добровольцев по общественному договору.[1] В 1994–1995 годах вышли Red Hat Linux и SUSE. В 2002 году появился Arch Linux, в 2003-м Red Hat разделила свой продукт на коммерческий Red Hat Enterprise Linux (RHEL) и общественную Fedora, а в 2004 году компания Canonical Марка Шаттлворта выпустила **Ubuntu** на основе Debian, сделав Linux заметно доступнее на настольных компьютерах. ## Основные семейства | Семейство | Дистрибутивы | Пакеты | Особенности | |---|---|---|---| | Debian | Debian, Ubuntu, Linux Mint, Astra Linux | `.deb`, apt | стабильность, огромный репозиторий | | Red Hat | RHEL, Fedora, CentOS Stream, Rocky Linux, AlmaLinux, RED OS | `.rpm`, dnf | корпоративный стандарт, долгая поддержка | | Arch | Arch Linux, Manjaro, EndeavourOS, SteamOS | pacman | скользящие выпуски, минимализм, ArchWiki | | SUSE | openSUSE, SLES | `.rpm`, zypper | YaST, снимки Btrfs | | Alpine | Alpine Linux | apk | крошечный размер, musl и BusyBox | | Независимые | Gentoo, NixOS, Slackware, ALT Linux | разные | сборка из исходников, декларативная конфигурация | ## Модели выпусков - **Фиксированные выпуски.** Новая версия выходит по расписанию, а внутри версии меняются только исправления. Ubuntu выпускается каждые шесть месяцев, а раз в два года (в апреле чётных лет) — версия с долгосрочной поддержкой (LTS) на 5 лет и больше по подписке.[2] Debian выходит примерно раз в два года, RHEL поддерживается десять лет. Fedora выходит каждые полгода с поддержкой около 13 месяцев.[3] - **Скользящие выпуски** (*rolling release*). Версий нет: система непрерывно обновляется до свежих версий программ — Arch Linux, openSUSE Tumbleweed, Gentoo.[4] Новинки появляются сразу, но обновление может что-то сломать. ## Как выбрать | Задача | Частый выбор | |---|---| | Сервер общего назначения | Debian, Ubuntu LTS | | Корпоративный сервер с поддержкой и сертификацией | RHEL, Rocky Linux, AlmaLinux, SLES | | Базовый образ контейнера | Alpine, Debian slim, distroless, Ubuntu | | Рабочий стол для новичка | Ubuntu, Linux Mint, Fedora Workstation | | Свежие версии программ, контроль над системой | Arch, Fedora, openSUSE Tumbleweed | | Воспроизводимая конфигурация системы | NixOS | | Импортозамещение и сертификация в России | Astra Linux, ALT Linux, RED OS | Для серверов важнее всего срок поддержки и предсказуемость: обновления безопасности без неожиданных смен версий. Образы [Docker](https://llmdocs.ru/wiki/docker.md) чаще всего строят на Debian или Alpine. Alpine использует библиотеку musl вместо glibc, поэтому образ занимает единицы мегабайт, но некоторые программы — особенно с бинарными зависимостями, как пакеты [Python](https://llmdocs.ru/wiki/python.md) с расширениями на C, — работают с ним хуже.[5] ## В чём разница на практике ```bash cat /etc/os-release # какой дистрибутив и версия # Debian, Ubuntu sudo apt update && sudo apt install nginx # Fedora, RHEL, Rocky sudo dnf install nginx # Arch sudo pacman -S nginx # Alpine apk add nginx ``` Различаются пакетный менеджер и имена пакетов, расположение некоторых конфигурационных файлов, версии ПО, настройки безопасности по умолчанию (SELinux в семействе Red Hat, AppArmor в Ubuntu и Debian) и инструменты администрирования. Ядро, оболочка, [systemd](https://llmdocs.ru/wiki/systemd.md) и основные утилиты почти везде одинаковы, поэтому навыки легко переносятся. ## Разделы и рабочие столы Настольные дистрибутивы поставляются с графическим окружением — GNOME, KDE Plasma, Xfce, Cinnamon, — часто в нескольких редакциях. Универсальные форматы приложений Flatpak и Snap позволяют устанавливать программы одинаково на разных дистрибутивах, независимо от их репозиториев. Найти и сравнить дистрибутивы помогает каталог DistroWatch.[6] ## См. также - [Linux](https://llmdocs.ru/wiki/linux.md) - [Пакетные менеджеры Linux (apt, dnf, pacman)](https://llmdocs.ru/wiki/package-managers.md) - [systemd](https://llmdocs.ru/wiki/systemd.md) - [Файловая система Unix (FHS)](https://llmdocs.ru/wiki/fhs.md) - [Docker](https://llmdocs.ru/wiki/docker.md) ## Источники 1. [Debian — About Debian](https://www.debian.org/intro/about) 2. [Ubuntu — Release cycle](https://ubuntu.com/about/release-cycle) 3. [Fedora — Release Life Cycle](https://docs.fedoraproject.org/en-US/releases/lifecycle/) 4. [ArchWiki — Arch Linux](https://wiki.archlinux.org/title/Arch_Linux) 5. [Alpine Linux — About](https://alpinelinux.org/about/) 6. [DistroWatch](https://distrowatch.com/) --- # Linux > Свободное ядро операционной системы, созданное Линусом Торвальдсом в 1991 году, и семейство операционных систем на его основе — от серверов и смартфонов до суперкомпьютеров. Источник: https://llmdocs.ru/wiki/linux/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: ядро операционной системы (монолитное, с загружаемыми модулями) - **Автор**: Линус Торвальдс - **Первый выпуск**: 0.01 — сентябрь 1991 - **Языки**: C, ассемблер; Rust (с версии 6.1, 2022) - **Лицензия**: GNU GPL v2 - **Цикл выпусков**: новая версия примерно раз в 9–10 недель - **Семейство**: Unix-подобные - **Сайт**: kernel.org **Linux** (произносится «линукс») — свободное ядро операционной системы, а также общее название операционных систем, построенных на этом ядре. Ядро управляет процессором, памятью, устройствами и файловыми системами, а поверх него работают системные утилиты, командная оболочка ([Bash](https://llmdocs.ru/wiki/shell-bash.md)), службы и приложения. Готовый набор из ядра и программ называют [дистрибутивом](https://llmdocs.ru/wiki/linux-distribution.md): Debian, Ubuntu, Fedora, Arch Linux, Alpine и сотни других. Linux — основная операционная система серверов, облаков и [контейнеров](https://llmdocs.ru/wiki/containerization.md): на нём работают почти все веб-сайты, [Docker](https://llmdocs.ru/wiki/docker.md) и [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md). Ядро Linux лежит в основе Android, большинства роутеров, телевизоров и встраиваемых устройств, а с ноября 2017 года на нём работают все 500 самых мощных суперкомпьютеров мира.[6] ## История 25 августа 1991 года финский студент Линус Торвальдс написал в конференцию comp.os.minix, что делает «бесплатную операционную систему (просто хобби, ничего большого и профессионального, как GNU)» для компьютеров на процессоре 386.[1] Версия 0.01 вышла в сентябре того же года. С версии 0.12 (1992) ядро распространяется под лицензией GNU GPL v2 (см. [лицензии ПО](https://llmdocs.ru/wiki/software-licenses.md)), которая требует открывать исходный код производных работ. Ядро удачно совпало с проектом GNU Ричарда Столлмана, начатым в 1983 году: у GNU уже были компилятор, оболочка и утилиты, но не было готового ядра. Поэтому Фонд свободного ПО настаивает на названии **GNU/Linux** для полной системы.[5] В 1993 году появились первые долгоживущие дистрибутивы — Slackware и Debian, в 1994–1995 годах — Red Hat, в 2004 году — Ubuntu. ## Устройство Linux — **монолитное ядро**: планировщик процессов, управление памятью, драйверы, сетевой стек и файловые системы работают в одном адресном пространстве с полными привилегиями. При этом большая часть драйверов собирается как **загружаемые модули**, которые подключаются на ходу (`modprobe`). Программы общаются с ядром через **системные вызовы** — `open`, `read`, `write`, `fork`, `execve` и около трёхсот других. Ядро следует философии Unix: «всё есть файл» — устройства, процессы (`/proc`) и параметры ядра (`/sys`) представлены как файлы (см. [Файловая система Unix (FHS)](https://llmdocs.ru/wiki/fhs.md)). Механизмы изоляции — namespaces и cgroups — позволяют запускать процессы в отдельных окружениях; на них построены контейнеры (см. [Namespaces и cgroups](https://llmdocs.ru/wiki/namespaces-cgroups.md)). Загрузка системы идёт так: загрузчик (GRUB, systemd-boot) запускает ядро, ядро монтирует корневую файловую систему и запускает первый процесс (PID 1) — сегодня это почти всегда [systemd](https://llmdocs.ru/wiki/systemd.md), который поднимает остальные службы. ## Разработка Ядро — один из крупнейших проектов с открытым кодом: десятки миллионов строк и тысячи разработчиков из сотен компаний за каждый выпуск. Новая версия выходит примерно раз в 9–10 недель: две недели «окна слияния» новых возможностей, затем еженедельные кандидаты (rc) с исправлениями.[3] Изменения проходят через списки рассылки и иерархию сопровождающих подсистем, а окончательное слово остаётся за Торвальдсом. Для управления кодом ядра Торвальдс в 2005 году создал [Git](https://llmdocs.ru/wiki/git.md). Часть версий объявляется **долгосрочными** (LTS) и получает исправления несколько лет — их используют дистрибутивы и производители устройств. Свежие версии публикуются на kernel.org.[2] С версии 6.1 (декабрь 2022) в ядре можно писать код на [Rust](https://llmdocs.ru/wiki/rust.md) — прежде всего драйверы, где безопасность памяти особенно важна.[4] ## Работа в Linux Основной интерфейс администратора — командная строка. Самые частые задачи: ```bash uname -r # версия ядра cat /etc/os-release # какой дистрибутив ps aux | grep nginx # процессы df -h; free -h # диск и память sudo systemctl status ssh # состояние службы journalctl -u ssh -n 50 # последние логи службы ls -l /etc/passwd # права доступа к файлу ``` Ключевые понятия, с которыми сталкивается каждый: [права доступа](https://llmdocs.ru/wiki/unix-permissions.md) и пользователь root, [процессы и сигналы](https://llmdocs.ru/wiki/processes-signals.md), [пакетные менеджеры](https://llmdocs.ru/wiki/package-managers.md), [переменные окружения](https://llmdocs.ru/wiki/environment-variables.md), [конвейеры](https://llmdocs.ru/wiki/pipes-redirection.md) и утилиты вроде [grep](https://llmdocs.ru/wiki/grep.md) и [curl](https://llmdocs.ru/wiki/curl.md). На удалённые серверы заходят по [SSH](https://llmdocs.ru/wiki/ssh.md). ## Linux на рабочем столе На настольных компьютерах доля Linux невелика, но растёт: популярны графические окружения GNOME и KDE Plasma, а игровая приставка Steam Deck работает на SteamOS — дистрибутиве на базе Arch Linux. Разработчики на Windows используют Linux через подсистему WSL 2, где работает настоящее ядро Linux, а на macOS — через виртуальные машины и Docker. ## См. также - [Дистрибутив Linux](https://llmdocs.ru/wiki/linux-distribution.md) - [Shell и Bash](https://llmdocs.ru/wiki/shell-bash.md) - [systemd](https://llmdocs.ru/wiki/systemd.md) - [Права доступа в Unix](https://llmdocs.ru/wiki/unix-permissions.md) - [Контейнеризация](https://llmdocs.ru/wiki/containerization.md) ## Источники 1. [Linus Torvalds — анонс в comp.os.minix (25 августа 1991)](https://groups.google.com/g/comp.os.minix/c/dlNtH7RRrGA/m/SwRavCzVE7gJ) 2. [The Linux Kernel Archives](https://www.kernel.org/) 3. [Linux kernel documentation — How the development process works](https://docs.kernel.org/process/2.Process.html) 4. [Linux kernel documentation — Rust](https://docs.kernel.org/rust/index.html) 5. [GNU — Linux and the GNU System](https://www.gnu.org/gnu/linux-and-gnu.html) 6. [TOP500 — List Statistics (Operating System Family)](https://top500.org/statistics/list/) --- # man-страницы > Встроенная справочная система Unix — страницы руководства по командам, системным вызовам, файлам конфигурации, разбитые на нумерованные разделы. Источник: https://llmdocs.ru/wiki/man-pages/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Появление**: Unix Programmer's Manual (1971) - **Команда**: man, apropos, whatis - **Формат**: roff (макросы man и mdoc) - **Реализации**: man-db (Linux), mandoc (BSD, macOS) - **Проект Linux**: man-pages (kernel.org) - **Расположение**: /usr/share/man - **Альтернативы**: info, tldr-pages, --help **man-страницы** (*manual pages*, страницы руководства) — традиционная справочная документация Unix-подобных систем, доступная прямо из терминала командой `man`. У каждой команды, системного вызова, библиотечной функции и формата конфигурационного файла обычно есть своя страница со строго заданной структурой. man-страницы работают без сети, соответствуют установленной версии программы и поэтому остаются первоисточником, даже когда под рукой есть поиск и краткие шпаргалки вроде [tldr-pages](https://llmdocs.ru/wiki/tldr-pages.md). ## История Первое издание *Unix Programmer's Manual* Кен Томпсон и Деннис Ритчи подготовили в 1971 году; уже тогда оно делилось на разделы и состояло из отдельных страниц на каждую команду.[5] Страницы набирались в системе roff — она же использовалась для вёрстки документов в Bell Labs. Эта схема почти без изменений дожила до наших дней. В Linux страницы ядра и glibc поддерживает проект **man-pages** на kernel.org; страницы утилит поставляются вместе с самими пакетами.[1] ## Разделы Страницы сгруппированы по разделам; номер пишут в скобках: `printf(1)` — команда, `printf(3)` — функция языка C.[2] | Раздел | Содержание | Пример | |---|---|---| | 1 | пользовательские команды | `ls(1)`, `grep(1)` | | 2 | системные вызовы ядра | `open(2)`, `fork(2)` | | 3 | функции библиотек | `printf(3)`, `malloc(3)` | | 4 | специальные файлы (устройства) | `null(4)` | | 5 | форматы файлов и конфигурации | `crontab(5)`, `sshd_config(5)` | | 6 | игры | | | 7 | обзоры, соглашения, протоколы | `signal(7)`, `regex(7)` | | 8 | команды администрирования | `mount(8)`, `iptables(8)` | Разделы помогают различать одинаковые имена: `man crontab` покажет команду, а `man 5 crontab` — формат файла расписания (см. [cron и таймеры systemd](https://llmdocs.ru/wiki/cron-systemd-timers.md)). ## Структура страницы Стандартные секции:[3] - **NAME** — имя и однострочное описание (по нему ищет `apropos`). - **SYNOPSIS** — синтаксис вызова: `[...]` — необязательно, `...` — можно повторять, `|` — альтернативы. - **DESCRIPTION** — подробное описание. - **OPTIONS** — ключи командной строки. - **EXIT STATUS**, **ENVIRONMENT**, **FILES** — коды возврата, [переменные окружения](https://llmdocs.ru/wiki/environment-variables.md) и используемые файлы. - **EXAMPLES**, **SEE ALSO**, **BUGS** — примеры, связанные страницы, известные ошибки. ## Использование ```bash man ls # страница команды ls man 7 signal # обзор сигналов из раздела 7 man -k compress # поиск по описаниям (то же, что apropos) whatis tar # однострочное описание man -f printf # во всех разделах, где есть printf man -w grep # путь к файлу страницы ``` Страница открывается в пейджере (обычно `less`), где работают привычные клавиши: `/шаблон` — поиск, `n` — следующее совпадение, `g`/`G` — начало и конец, `q` — выход. Быстро перейти к описанию ключа можно поиском вроде `/^ +-r`. Цветной вывод настраивается переменными `LESS_TERMCAP_*` или переменной `MANPAGER` (например, просмотр через `bat` или [Vim](https://llmdocs.ru/wiki/vim.md)). Если `apropos` ничего не находит, нужно обновить индекс: `sudo mandb` (man-db) или `makewhatis` (BSD). В минимальных образах [Docker](https://llmdocs.ru/wiki/docker.md) man-страницы часто удалены ради размера — их возвращают командой `unminimize` в Ubuntu или установкой пакетов `man-db` и `manpages`. ## Формат и реализации Исходники страниц пишутся на языке разметки roff с набором макросов **man** (Linux) или более семантическим **mdoc** (BSD). В Linux просмотрщик — **man-db**, в BSD и macOS — **mandoc**, который также конвертирует страницы в HTML и проверяет их на ошибки.[4] Хранятся страницы сжатыми в `/usr/share/man/manN/`, путь поиска задаётся переменной `MANPATH`. Многие проекты больше не пишут roff вручную, а генерируют страницы из Markdown или reStructuredText (pandoc, scdoc, Sphinx) или из описания аргументов CLI (например, `clap_mangen` в Rust). ## Альтернативы - **`--help`** — краткая справка самой программы, всегда под рукой. - **info** — гипертекстовая документация GNU; у некоторых утилит GNU она полнее man-страниц. - **tldr-pages** — примеры частых случаев использования вместо полного справочника. - **man7.org** и **manpages.debian.org** — веб-версии страниц для разных дистрибутивов. Для языковых моделей man-страницы — ценный источник точного синтаксиса: их удобно передавать в контекст как текст (`man ls | col -b`), см. [Документация для ИИ](https://llmdocs.ru/wiki/docs-for-ai.md). ## См. также - [tldr-pages](https://llmdocs.ru/wiki/tldr-pages.md) - [Shell и Bash](https://llmdocs.ru/wiki/shell-bash.md) - [Linux](https://llmdocs.ru/wiki/linux.md) - [Vim](https://llmdocs.ru/wiki/vim.md) ## Источники 1. [man-pages project (kernel.org)](https://www.kernel.org/doc/man-pages/) 2. [man(1) — man-db](https://man7.org/linux/man-pages/man1/man.1.html) 3. [man-pages(7) — conventions for writing Linux man pages](https://man7.org/linux/man-pages/man7/man-pages.7.html) 4. [mandoc — UNIX manpage compiler](https://mandoc.bsd.lv/) 5. [Unix Programmer's Manual, First Edition (1971)](https://www.bell-labs.com/usr/dmr/www/1stEdman.html) --- # Пакетные менеджеры Linux (apt, dnf, pacman) > Системы установки, обновления и удаления программ в дистрибутивах Linux — apt (Debian, Ubuntu), dnf (Fedora, RHEL), pacman (Arch), apk (Alpine) — с репозиториями, зависимостями и подписями пакетов. Источник: https://llmdocs.ru/wiki/package-managers/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Debian, Ubuntu**: dpkg (1994) и APT (1998), пакеты .deb - **Fedora, RHEL**: rpm (1997), yum (2003), dnf (с 2015), пакеты .rpm - **Arch Linux**: pacman (2002) - **Alpine**: apk - **openSUSE**: zypper - **Универсальные форматы**: Flatpak, Snap, AppImage - **Функции**: зависимости, репозитории, подписи, обновления **Пакетный менеджер** — программа, которая устанавливает, обновляет и удаляет программы в [дистрибутиве Linux](https://llmdocs.ru/wiki/linux-distribution.md). Программы распространяются в виде **пакетов** — архивов с файлами и метаданными: версия, описание, список зависимостей, скрипты установки. Пакетный менеджер скачивает пакеты из **репозиториев** дистрибутива, проверяет их цифровые подписи, автоматически доставляет нужные зависимости и следит, чтобы в системе не было конфликтов. Это одно из главных отличий Linux от традиционной установки программ скачанными с сайтов инсталляторами: одна команда обновляет всю систему вместе со всеми приложениями. ## Два уровня Обычно есть низкоуровневый инструмент, работающий с отдельными файлами пакетов, и высокоуровневый, который умеет работать с репозиториями и разрешать зависимости: | Семейство | Низкий уровень | Высокий уровень | Формат | |---|---|---|---| | Debian, Ubuntu | dpkg | apt (apt-get) | `.deb` | | Fedora, RHEL, Rocky | rpm | dnf (ранее yum) | `.rpm` | | Arch Linux | — | pacman | `.pkg.tar.zst` | | Alpine | — | apk | `.apk` | | openSUSE | rpm | zypper | `.rpm` | dpkg появился в Debian в 1994 году, а APT — в 1998-м; формат RPM создан в Red Hat в 1997 году, менеджер yum — в 2003-м, а в 2015 году Fedora перешла на его преемника dnf.[2][3] ## Основные команды | Действие | apt | dnf | pacman | apk | |---|---|---|---|---| | Обновить списки пакетов | `apt update` | (автоматически) | `pacman -Sy` | `apk update` | | Обновить систему | `apt upgrade` | `dnf upgrade` | `pacman -Syu` | `apk upgrade` | | Установить | `apt install nginx` | `dnf install nginx` | `pacman -S nginx` | `apk add nginx` | | Удалить | `apt remove nginx` | `dnf remove nginx` | `pacman -R nginx` | `apk del nginx` | | Найти | `apt search nginx` | `dnf search nginx` | `pacman -Ss nginx` | `apk search nginx` | | Какому пакету принадлежит файл | `dpkg -S /usr/bin/curl` | `dnf provides /usr/bin/curl` | `pacman -Qo /usr/bin/curl` | `apk info --who-owns` | | Убрать ненужные зависимости | `apt autoremove` | `dnf autoremove` | `pacman -Rns $(pacman -Qdtq)` | — | В Debian и Ubuntu команда `apt` удобнее для интерактивной работы, а `apt-get` — для скриптов: её вывод и поведение стабильны между версиями.[1] В Arch не рекомендуется частичное обновление (`pacman -Sy` без `-u`): при скользящих выпусках это ломает зависимости.[4] ## Репозитории и доверие Список репозиториев хранится в `/etc/apt/sources.list.d/` (Debian), `/etc/yum.repos.d/` (Fedora и RHEL), `/etc/pacman.conf` (Arch). Метаданные и пакеты подписаны ключами дистрибутива, и менеджер отказывается ставить пакет с неверной подписью — это защищает от подмены по пути. Сторонние репозитории (например, официальный репозиторий [Docker](https://llmdocs.ru/wiki/docker.md) или [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md)) подключают вместе с их ключом подписи. ```bash # Debian/Ubuntu: добавить сторонний репозиторий с ключом curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg echo "deb [signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/debian trixie stable" \ | sudo tee /etc/apt/sources.list.d/docker.list sudo apt update && sudo apt install docker-ce ``` Arch дополнительно поддерживает пользовательский репозиторий AUR со сценариями сборки от сообщества — удобный, но требующий внимательности источник. ## Обновления безопасности На серверах исправления безопасности стоит ставить автоматически: в Debian и Ubuntu — пакетом `unattended-upgrades`,[6] в Fedora и RHEL — `dnf-automatic`. Обновление ядра и системных библиотек часто требует перезапуска служб или перезагрузки; утилиты `needrestart` и `needs-restarting` подскажут, что перезапустить. ```bash sudo apt install unattended-upgrades sudo dpkg-reconfigure -plow unattended-upgrades ``` Чтобы пакет не обновлялся (например, критичная версия СУБД), его закрепляют: `apt-mark hold postgresql-17`, `dnf versionlock add ...`. ## Пакеты в Docker-образах В [Dockerfile](https://llmdocs.ru/wiki/dockerfile.md) установку пакетов объединяют с очисткой кэша в одной инструкции, чтобы не раздувать слой: ```dockerfile RUN apt-get update \ && apt-get install -y --no-install-recommends curl ca-certificates \ && rm -rf /var/lib/apt/lists/* ``` В Alpine то же делает `apk add --no-cache curl`.[5] ## Универсальные форматы **Flatpak** и **Snap** распространяют настольные приложения одинаково для всех дистрибутивов, со всеми зависимостями внутри и в песочнице; **AppImage** — один исполняемый файл без установки. Они удобны для свежих версий приложений, но занимают больше места и слабее интегрированы с системой. Для языков программирования существуют свои менеджеры — [pip](https://llmdocs.ru/wiki/pip-pypi.md) и [uv](https://llmdocs.ru/wiki/uv.md) для Python, [npm](https://llmdocs.ru/wiki/npm.md) для JavaScript, [Cargo](https://llmdocs.ru/wiki/cargo.md) для Rust; системным пакетным менеджером их зависимости лучше не смешивать. ## Советы - Устанавливайте программы из репозиториев дистрибутива, когда это возможно: они получают обновления безопасности. - Не используйте `sudo pip install` в системный Python — для этого есть [виртуальные окружения](https://llmdocs.ru/wiki/venv.md). - Фиксируйте список установленных пакетов в [коде инфраструктуры](https://llmdocs.ru/wiki/infrastructure-as-code.md) (Ansible, Dockerfile), а не устанавливайте вручную. ## См. также - [Дистрибутив Linux](https://llmdocs.ru/wiki/linux-distribution.md) - [Linux](https://llmdocs.ru/wiki/linux.md) - [Dockerfile](https://llmdocs.ru/wiki/dockerfile.md) - [pip и PyPI](https://llmdocs.ru/wiki/pip-pypi.md) - [Ansible](https://llmdocs.ru/wiki/ansible.md) ## Источники 1. [Debian Wiki — Apt](https://wiki.debian.org/Apt) 2. [Debian Reference — Debian package management](https://www.debian.org/doc/manuals/debian-reference/ch02.en.html) 3. [DNF documentation](https://dnf.readthedocs.io/) 4. [ArchWiki — pacman](https://wiki.archlinux.org/title/Pacman) 5. [Alpine Linux Wiki — Alpine Package Keeper](https://wiki.alpinelinux.org/wiki/Alpine_Package_Keeper) 6. [Debian Wiki — UnattendedUpgrades](https://wiki.debian.org/UnattendedUpgrades) --- # Конвейеры и перенаправление (pipes) > Механизмы оболочки Unix для соединения программ — конвейер | передаёт вывод одной команды на вход другой, а перенаправления >, <, 2> связывают потоки с файлами. Источник: https://llmdocs.ru/wiki/pipes-redirection/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Идея конвейеров**: Дуглас Макилрой (1964) - **Реализация в Unix**: Кен Томпсон, Unix Version 3 (1973) - **Стандартные потоки**: 0 — stdin, 1 — stdout, 2 — stderr - **Операторы**: |, >, >>, <, 2>, 2>&1, &>, <<, <<< - **Связанные механизмы**: tee, именованные каналы (mkfifo), подстановка процессов - **Принцип**: маленькие программы, каждая делает одно дело **Конвейер** (англ. *pipe*, «труба», в жаргоне — «пайп») — механизм Unix, который соединяет стандартный вывод одной программы со стандартным вводом другой: `команда1 | команда2`. **Перенаправление** связывает потоки ввода-вывода с файлами: `команда > out.txt`. Вместе они воплощают философию Unix: вместо одной большой программы, делающей всё, — маленькие утилиты, каждая из которых делает одно дело хорошо, соединяемые в цепочки. Конвейеры — основа повседневной работы в [командной строке](https://llmdocs.ru/wiki/shell-bash.md) [Linux](https://llmdocs.ru/wiki/linux.md): найти в логе ошибки, отсортировать, посчитать, взять первые десять — одной строкой. ## История Идею соединять программы «как садовые шланги» высказал Дуглас Макилрой в служебной записке Bell Labs ещё в 1964 году. В 1973 году Кен Томпсон за одну ночь добавил в Unix системный вызов `pipe()` и синтаксис с вертикальной чертой, переписав утилиты так, чтобы они читали стандартный ввод и писали в стандартный вывод. Этот момент часто называют рождением «философии Unix». ## Стандартные потоки Каждый процесс начинает работу с тремя открытыми потоками — **файловыми дескрипторами**: | Номер | Имя | Назначение | По умолчанию | |---|---|---|---| | 0 | stdin | стандартный ввод | клавиатура | | 1 | stdout | стандартный вывод | экран | | 2 | stderr | поток ошибок | экран | Разделение вывода и ошибок важно: при `команда > file` в файл уходят данные, а сообщения об ошибках по-прежнему видны на экране и не портят результат. ## Перенаправления ```bash ls > files.txt # stdout в файл (перезаписать) ls >> files.txt # дописать в конец sort < names.txt # stdin из файла make 2> errors.log # только stderr в файл cmd > out.log 2>&1 # оба потока в один файл (порядок важен!) cmd &> out.log # то же, сокращение Bash cmd 2>/dev/null # выбросить ошибки cmd > /dev/null 2>&1 # выбросить всё ``` Запись `2>&1` означает «направить поток 2 туда же, куда сейчас направлен поток 1». Поэтому `cmd 2>&1 > file` отправит ошибки на экран, а в файл — только вывод: перенаправления применяются слева направо.[2] ### Here-документ и here-строка ```bash cat < config.ini [server] host = $HOSTNAME port = 8080 EOF grep -c "a" <<< "banana" # строка как stdin ``` Внутри `<&1 | tee build.log`. Запись в файл с правами root: `echo "..." | sudo tee /etc/file`. - **Подстановка процессов** `<(команда)` подставляет вывод команды как временный файл: `diff <(sort a.txt) <(sort b.txt)`. - **Подстановка команд** `$(команда)` вставляет вывод в строку: `kill $(pgrep -f worker)`. - **Именованные каналы** (`mkfifo /tmp/pipe`) — конвейер в виде файла, через который могут общаться независимые процессы.[5] - **`xargs`** превращает поток строк в аргументы команды (см. [find и xargs](https://llmdocs.ru/wiki/find-xargs.md)). ## Классический пример Подсчёт десяти самых частых слов в тексте — задача, на которой Макилрой в 1986 году показал силу конвейеров: ```bash tr -cs '[:alpha:]' '\n' < book.txt | tr '[:upper:]' '[:lower:]' | sort | uniq -c | sort -rn | head ``` Каждая утилита проста: `tr` разбивает текст на слова и приводит к нижнему регистру, `sort` и `uniq -c` считают повторы, `sort -rn` упорядочивает, `head` берёт верхушку. Те же блоки решают и десятки других задач — для полей и сумм удобен [awk](https://llmdocs.ru/wiki/sed-awk.md), для поиска — [grep](https://llmdocs.ru/wiki/grep.md), для JSON — [jq](https://llmdocs.ru/wiki/json.md). ## Ограничения Конвейеры передают неструктурированный текст: каждая программа заново разбирает строки, и пробелы в именах файлов или неожиданный формат вывода ломают цепочку. Для сложной логики и структурированных данных лучше подходят [Python](https://llmdocs.ru/wiki/python.md) или оболочки нового поколения, передающие объекты (PowerShell, Nushell). Синтаксис конвейеров и перенаправлений закреплён в стандарте POSIX и одинаково работает в Bash, Zsh и dash.[4] ## См. также - [Shell и Bash](https://llmdocs.ru/wiki/shell-bash.md) - [grep и регулярные выражения](https://llmdocs.ru/wiki/grep.md) - [sed и awk](https://llmdocs.ru/wiki/sed-awk.md) - [find и xargs](https://llmdocs.ru/wiki/find-xargs.md) - [Процессы и сигналы](https://llmdocs.ru/wiki/processes-signals.md) ## Источники 1. [GNU Bash manual — Pipelines](https://www.gnu.org/software/bash/manual/html_node/Pipelines.html) 2. [GNU Bash manual — Redirections](https://www.gnu.org/software/bash/manual/html_node/Redirections.html) 3. [pipe(7) — Linux manual page](https://man7.org/linux/man-pages/man7/pipe.7.html) 4. [POSIX.1-2024 — Shell Command Language](https://pubs.opengroup.org/onlinepubs/9799919799/utilities/V3_chap02.html) 5. [mkfifo(1) — Linux manual page](https://man7.org/linux/man-pages/man1/mkfifo.1.html) --- # Процессы и сигналы > Процесс — запущенная программа со своим PID, памятью и ресурсами; сигналы — асинхронные уведомления, которыми ядро и другие процессы сообщают процессу о событиях, например о просьбе завершиться. Источник: https://llmdocs.ru/wiki/processes-signals/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Идентификатор**: PID; у родителя — PPID - **Создание**: fork() и execve() - **Первый процесс**: init/systemd (PID 1) - **Состояния**: R (выполняется), S (спит), D (ожидает ввода-вывода), T (остановлен), Z (зомби) - **Частые сигналы**: SIGTERM (15), SIGKILL (9), SIGINT (2), SIGHUP (1), SIGCHLD - **Инструменты**: ps, top, htop, pgrep, kill, pkill, /proc **Процесс** — экземпляр выполняющейся программы: код, загруженный в память, вместе с данными, открытыми файлами, переменными окружения и правами пользователя. У каждого процесса в [Linux](https://llmdocs.ru/wiki/linux.md) есть уникальный номер — **PID** — и родитель (PPID). **Сигнал** — короткое асинхронное уведомление, которое ядро или другой процесс посылает процессу: «завершись», «перечитай конфигурацию», «ты обратился к чужой памяти», «твой дочерний процесс закончил работу». Понимание процессов и сигналов нужно, чтобы корректно останавливать службы, искать зависшие программы, писать скрипты и правильно завершать приложения в [Docker](https://llmdocs.ru/wiki/docker.md) и [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md). ## Жизнь процесса Новые процессы в Unix создаются двумя системными вызовами: **`fork()`** создаёт копию текущего процесса, а **`execve()`** заменяет программу в этой копии на другую.[2] Так оболочка запускает каждую команду: делает `fork`, в дочернем процессе вызывает `exec` нужной программы, а сама ждёт её завершения через `wait`. Все процессы образуют дерево с корнем в процессе с PID 1 — сегодня это обычно [systemd](https://llmdocs.ru/wiki/systemd.md). Завершившись, процесс возвращает **код выхода** (0 — успех) и становится **зомби** — записью в таблице процессов, ожидающей, пока родитель прочитает код выхода. Если родитель умер раньше, «сирот» усыновляет PID 1 и сам их «хоронит». | Состояние | Обозначение | Смысл | |---|---|---| | Выполняется | R | работает или готов к работе | | Спит | S | ждёт события (сеть, таймер, ввод) | | Непрерываемый сон | D | ждёт ввода-вывода, не реагирует даже на SIGKILL | | Остановлен | T | приостановлен (Ctrl+Z, отладчик) | | Зомби | Z | завершён, родитель не забрал код выхода | ## Просмотр процессов ```bash ps aux # все процессы: пользователь, PID, CPU, память, команда ps -ef --forest # дерево процессов pgrep -a nginx # найти по имени top # интерактивно; htop — удобнее cat /proc/1234/status # всё о процессе из виртуальной ФС /proc ls -l /proc/1234/fd # открытые файлы и сокеты lsof -i :8080 # какой процесс занял порт ``` Каталог `/proc` — окно в ядро: для каждого процесса есть каталог с его командной строкой, окружением, картой памяти и открытыми файлами.[3][4] ## Сигналы | Сигнал | Номер | Действие по умолчанию | Когда приходит | |---|---|---|---| | SIGHUP | 1 | завершение | закрыт терминал; демоны часто перечитывают конфигурацию | | SIGINT | 2 | завершение | Ctrl+C в терминале | | SIGQUIT | 3 | завершение с дампом | Ctrl+\ | | SIGKILL | 9 | немедленное завершение | `kill -9`; нельзя перехватить | | SIGSEGV | 11 | завершение с дампом | обращение к недопустимой памяти | | SIGPIPE | 13 | завершение | запись в закрытый канал | | SIGTERM | 15 | завершение | вежливая просьба завершиться — `kill` по умолчанию | | SIGCHLD | 17 | игнорируется | завершился дочерний процесс | | SIGSTOP, SIGCONT | 19, 18 | остановка, продолжение | приостановить и возобновить; SIGSTOP нельзя перехватить | Процесс может перехватить большинство сигналов и обработать их по-своему — например, по SIGTERM закрыть соединения и сохранить данные. SIGKILL и SIGSTOP перехватить нельзя: их обрабатывает ядро.[1] ```bash kill 1234 # SIGTERM — попросить завершиться kill -HUP $(pgrep nginx) # перечитать конфигурацию kill -9 1234 # SIGKILL — крайняя мера pkill -f "python worker.py" # по шаблону командной строки ``` ## Корректное завершение Правильный порядок остановки — сначала SIGTERM, дать процессу время закончить работу и только затем SIGKILL. Так поступают systemd (`TimeoutStopSec`), `docker stop` (по умолчанию 10 секунд)[5] и Kubernetes (`terminationGracePeriodSeconds`). Приложение должно обрабатывать SIGTERM: перестать принимать новые запросы, дождаться текущих, закрыть соединения с базой. ```python import signal, sys def shutdown(signum, frame): print("получен SIGTERM, завершаемся") server.stop(grace=10) sys.exit(0) signal.signal(signal.SIGTERM, shutdown) ``` В [Bash](https://llmdocs.ru/wiki/shell-bash.md) обработчик ставится командой `trap 'cleanup' TERM INT EXIT`. ## Процессы в контейнерах В контейнере приложение часто становится PID 1, а у PID 1 особые правила: ядро не применяет к нему действия сигналов по умолчанию, поэтому процесс, не установивший обработчик SIGTERM, просто его проигнорирует, и контейнер будет убит по таймауту. Кроме того, PID 1 обязан собирать зомби. Решения — запускать команду в exec-форме (`CMD ["python", "app.py"]`, а не через `sh -c`, см. [Dockerfile](https://llmdocs.ru/wiki/dockerfile.md)), обрабатывать сигналы в приложении или использовать маленький init вроде tini (`docker run --init`).[6] ## Приоритеты и ресурсы Приоритет планирования задаётся значением **nice** от −20 (высший) до 19: `nice -n 10 ./backup.sh`, `renice`. Ограничения ресурсов — `ulimit` (число открытых файлов, размер стека) и cgroups (память, процессор; см. [Namespaces и cgroups](https://llmdocs.ru/wiki/namespaces-cgroups.md)). Когда память кончается, ядро запускает **OOM killer**, который завершает процесс с наибольшим «счётом» потребления — частая причина внезапной гибели баз данных и Java-приложений. ## См. также - [systemd](https://llmdocs.ru/wiki/systemd.md) - [Shell и Bash](https://llmdocs.ru/wiki/shell-bash.md) - [Namespaces и cgroups](https://llmdocs.ru/wiki/namespaces-cgroups.md) - [Конкурентность и параллелизм](https://llmdocs.ru/wiki/concurrency-parallelism.md) - [Linux](https://llmdocs.ru/wiki/linux.md) ## Источники 1. [signal(7) — Linux manual page](https://man7.org/linux/man-pages/man7/signal.7.html) 2. [fork(2) — Linux manual page](https://man7.org/linux/man-pages/man2/fork.2.html) 3. [proc(5) — Linux manual page](https://man7.org/linux/man-pages/man5/proc.5.html) 4. [ps(1) — Linux manual page](https://man7.org/linux/man-pages/man1/ps.1.html) 5. [Docker Docs — docker container stop](https://docs.docker.com/reference/cli/docker/container/stop/) 6. [tini — A tiny but valid init for containers](https://github.com/krallin/tini) --- # rsync > Утилита синхронизации файлов и каталогов локально и по сети, передающая только изменившиеся части файлов благодаря алгоритму скользящих контрольных сумм; стандартный инструмент резервного копирования и развёртывания. Источник: https://llmdocs.ru/wiki/rsync/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Авторы**: Эндрю Триджелл, Пол Маккеррас - **Первый выпуск**: 1996 - **Язык**: C - **Лицензия**: GNU GPL v3 - **Транспорт**: SSH или собственный демон rsyncd (порт 873) - **Ключевая идея**: передача только различий (дельта-кодирование) - **Альтернативы**: rclone (облачные хранилища), restic и borg (резервные копии) **rsync** — утилита для синхронизации файлов и каталогов: между папками на одной машине или между компьютерами по сети, обычно через [SSH](https://llmdocs.ru/wiki/ssh.md). Её главное достоинство — передаются только изменения: если в гигабайтном файле поменялось несколько килобайт, по сети уйдут лишь они. rsync сохраняет права, владельцев, время изменения и символические ссылки, умеет удалять на приёмнике файлы, исчезнувшие в источнике, и продолжать прерванную передачу. rsync — стандартный инструмент резервного копирования, зеркалирования, переноса данных между серверами и простого развёртывания сайтов. ## История и алгоритм rsync создали австралийские программисты Эндрю Триджелл (известный также как автор Samba) и Пол Маккеррас; первая версия вышла в 1996 году.[1] Алгоритм описан в техническом отчёте и диссертации Триджелла.[3][4] Задача: синхронизировать файл, когда у получателя уже есть его старая версия, а пересылать файл целиком дорого. 1. Получатель делит свою версию на блоки и отправляет для каждого две контрольные суммы — быструю «скользящую» и надёжную. 2. Отправитель проходит по своему файлу окном размером в блок, сдвигаясь на один байт. Скользящая сумма пересчитывается за константное время при сдвиге, поэтому совпадения находятся даже при вставке данных в середину файла. 3. Совпавшие блоки отправитель заменяет ссылками «возьми свой блок № N», а передаёт только данные, которых у получателя нет. Для решения, какие файлы вообще нужно проверять, rsync по умолчанию сравнивает размер и время изменения — это быстро. ## Основы ```bash rsync -av src/ backup/ # локально: архивный режим, подробный вывод rsync -avz src/ user@server:/var/www/site/ # на сервер по SSH со сжатием rsync -avz user@server:/var/log/app/ ./logs/ # с сервера rsync -avP big.iso server:/data/ # прогресс и докачка прерванной передачи rsync -av --delete src/ backup/ # точное зеркало: удалить лишнее в приёмнике rsync -avn --delete src/ backup/ # -n (--dry-run): показать, что будет сделано ``` | Ключ | Смысл | |---|---| | `-a` | архивный режим: рекурсивно, с правами, владельцами, временем, ссылками | | `-v` | подробный вывод | | `-z` | сжатие при передаче | | `-P` | прогресс и сохранение частично переданных файлов | | `--delete` | удалять в приёмнике файлы, которых нет в источнике | | `-n` | пробный запуск без изменений | | `--exclude`, `--exclude-from` | исключить файлы по шаблону | | `-e "ssh -p 2222"` | параметры SSH | | `--bwlimit` | ограничение скорости | Полный перечень — в руководстве rsync.[2] ## Косая черта в конце Самая частая ловушка — косая черта в конце пути источника: ```bash rsync -a photos backup/ # создаст backup/photos/... rsync -a photos/ backup/ # скопирует содержимое: backup/... ``` `src/` означает «содержимое каталога», `src` — «сам каталог». С ключом `--delete` ошибка в одном символе может стереть данные, поэтому сначала запускайте команду с `-n`. ## Резервные копии С ключом `--link-dest` rsync создаёт снимки, в которых неизменившиеся файлы — жёсткие ссылки на предыдущий снимок (см. [Файловая система Unix (FHS)](https://llmdocs.ru/wiki/fhs.md)). Каждый снимок выглядит как полная копия, но занимает место только под изменения: ```bash today=$(date +%F) rsync -a --delete --link-dest=/backups/latest /home/ /backups/$today/ ln -sfn /backups/$today /backups/latest ``` Такую команду запускают по расписанию ([cron и таймеры systemd](https://llmdocs.ru/wiki/cron-systemd-timers.md)). Однако rsync — не полноценная система резервного копирования: у него нет шифрования хранилища, дедупликации между файлами и проверки целостности снимков. Для этого существуют restic и BorgBackup (см. [Бэкапы: правило 3-2-1](https://llmdocs.ru/wiki/backup-3-2-1.md)). ## Безопасность: ограниченный доступ Когда сервер с данными отправляет копии на сервер резервного хранения, ключ SSH для этого стоит ограничить. Скрипт **rrsync**, поставляемый с rsync, разрешает ключу только операции rsync внутри заданного каталога и может запретить чтение:[5] ```text # ~/.ssh/authorized_keys на сервере хранения command="rrsync -wo /backups/app",restrict ssh-ed25519 AAAA... backup@app ``` Режим `-wo` (только запись) означает, что даже при краже ключа злоумышленник не сможет ни прочитать старые копии, ни получить оболочку на сервере. Это пример [принципа наименьших привилегий](https://llmdocs.ru/wiki/least-privilege.md). ## Развёртывание ```bash rsync -avz --delete --exclude ".git" --exclude "node_modules" build/ deploy@web:/var/www/site/ ``` Для статических сайтов ([Статический сайт и генераторы (SSG)](https://llmdocs.ru/wiki/static-site-generators.md)) этого часто достаточно. Для приложений надёжнее атомарное переключение: загрузить в новый каталог и сменить символическую ссылку, чтобы пользователи не увидели полузагруженную версию. ## Альтернативы - **scp и sftp** — простое копирование без дельта-передачи. - **rclone** — «rsync для облаков»: синхронизация с S3, Google Drive и десятками других хранилищ.[6] - **restic, BorgBackup** — резервное копирование с шифрованием, дедупликацией и снимками. - **Syncthing** — непрерывная двусторонняя синхронизация между устройствами. ## См. также - [SSH](https://llmdocs.ru/wiki/ssh.md) - [Бэкапы: правило 3-2-1](https://llmdocs.ru/wiki/backup-3-2-1.md) - [cron и таймеры systemd](https://llmdocs.ru/wiki/cron-systemd-timers.md) - [Принцип наименьших привилегий](https://llmdocs.ru/wiki/least-privilege.md) - [Файловая система Unix (FHS)](https://llmdocs.ru/wiki/fhs.md) ## Источники 1. [rsync — официальный сайт](https://rsync.samba.org/) 2. [rsync(1) — manual page](https://download.samba.org/pub/rsync/rsync.1) 3. [A. Tridgell, P. Mackerras — The rsync algorithm (technical report)](https://rsync.samba.org/tech_report/) 4. [A. Tridgell — Efficient Algorithms for Sorting and Synchronization (PhD thesis, 1999)](https://www.samba.org/~tridge/phd_thesis.pdf) 5. [rrsync(1) — restricted rsync](https://download.samba.org/pub/rsync/rrsync.1) 6. [rclone](https://rclone.org/) --- # sed и awk > sed — потоковый редактор для замены и правки текста по шаблонам; awk — язык обработки текстовых данных по полям и строкам. Классические утилиты Unix для конвейеров и однострочников. Источник: https://llmdocs.ru/wiki/sed-awk/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **sed**: Ли Макмэхон, Bell Labs (1973–1974) - **awk**: Альфред Ахо, Питер Вайнбергер, Брайан Керниган (1977) - **Название awk**: по первым буквам фамилий авторов - **Реализации**: GNU sed и gawk, BSD sed, mawk, BusyBox - **Стандарт**: POSIX - **Книга**: The AWK Programming Language (1988, 2-е изд. 2023) **sed** (от *stream editor* — потоковый редактор) и **awk** — классические утилиты Unix для обработки текста. sed читает поток строк и применяет к нему команды редактирования: замену по [регулярным выражениям](https://llmdocs.ru/wiki/regex.md), удаление и вставку строк. awk — небольшой язык программирования для данных, разбитых на поля: он перебирает строки, делит каждую на столбцы и выполняет действия для строк, подходящих под шаблон. Обе утилиты есть в любой Unix-подобной системе и незаменимы в [конвейерах](https://llmdocs.ru/wiki/pipes-redirection.md) и скриптах на [Bash](https://llmdocs.ru/wiki/shell-bash.md): поправить конфигурацию, вытащить столбец из лога, посчитать сумму. ## История sed написал Ли Макмэхон в Bell Labs в 1973–1974 годах на основе команд строкового редактора ed: идея была применять те же команды к потоку, не открывая файл интерактивно. awk создали в 1977 году Альфред Ахо, Питер Вайнбергер и Брайан Керниган — название составлено из первых букв их фамилий. В 1988 году авторы выпустили книгу «The AWK Programming Language», а в 2023 году — второе издание.[5] Поведение обеих утилит закреплено в POSIX.[3][4] ## sed ```bash sed 's/http:/https:/' urls.txt # заменить первое вхождение в каждой строке sed 's/http:/https:/g' urls.txt # все вхождения sed -n '10,20p' big.log # напечатать строки 10–20 sed '/^#/d; /^$/d' config.conf # удалить комментарии и пустые строки sed -E 's/([0-9]{4})-([0-9]{2})-([0-9]{2})/\3.\2.\1/' dates.txt # 2026-11-09 → 09.11.2026 sed -i 's/^PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config # правка файла на месте ``` Основная команда — `s/шаблон/замена/флаги`. Флаг `g` заменяет все вхождения, `I` — без учёта регистра; ключ `-E` включает расширенные регулярные выражения, а в замене `\1`, `\2` подставляют группы, `&` — всё найденное. Перед командой можно указать **адрес**: номер строки, диапазон или шаблон (`/ERROR/s/.../.../`).[1] **Внимание: `sed -i` различается** в GNU (Linux) и BSD (macOS): на macOS нужен аргумент суффикса резервной копии, хотя бы пустой — `sed -i '' 's/a/b/' file`. Переносимый вариант — `sed -i.bak ...` с последующим удалением `.bak`-файла. ## awk Программа awk — набор правил `шаблон { действие }`. Каждая строка делится на поля `$1`, `$2`, …; `$0` — вся строка, `NF` — число полей, `NR` — номер строки. Разделитель задаётся ключом `-F`. ```bash awk '{print $1}' access.log # первый столбец (IP-адрес) awk -F: '{print $1, $7}' /etc/passwd # пользователь и его оболочка awk '$9 >= 500' access.log # строки, где код ответа ≥ 500 awk '{sum += $10} END {print sum/1024/1024 " МБ"}' access.log # сумма по столбцу awk -F, 'NR > 1 {total[$2] += $3} END {for (c in total) print c, total[c]}' sales.csv # группировка awk 'length > 120 {print FILENAME ":" FNR}' *.py # строки длиннее 120 символов ``` Блок `BEGIN` выполняется до чтения данных, `END` — после. Ассоциативные массивы (`total[$2]`) делают awk удобным для подсчётов и группировки — аналога `GROUP BY` в [SQL](https://llmdocs.ru/wiki/sql.md). Полное описание языка — в руководстве GNU Awk.[2] ## Примеры конвейеров ```bash # топ-10 IP-адресов по числу запросов awk '{print $1}' access.log | sort | uniq -c | sort -rn | head # среднее время ответа по эндпоинтам из лога вида: GET /api/users 200 123ms awk '{gsub("ms", "", $4); t[$2] += $4; n[$2]++} END {for (u in t) printf "%-30s %6.1f\n", u, t[u]/n[u]}' app.log | sort -k2 -rn # заменить версию во всех файлах проекта grep -rl 'version = "1.2.0"' . | xargs sed -i.bak 's/version = "1.2.0"/version = "1.3.0"/' ``` Здесь sed и awk работают вместе с [grep](https://llmdocs.ru/wiki/grep.md), sort, uniq и [xargs](https://llmdocs.ru/wiki/find-xargs.md) — каждый делает одно дело, а конвейер решает задачу целиком. ## Когда что использовать | Задача | Инструмент | |---|---| | Найти строки | grep | | Заменить текст, удалить строки | sed | | Работать со столбцами, считать, группировать | awk | | JSON | [jq](https://llmdocs.ru/wiki/json.md) | | CSV с кавычками и запятыми внутри полей | специализированные инструменты (Miller, csvkit) или [Python](https://llmdocs.ru/wiki/python.md) | | Логика сложнее нескольких строк | Python | ## Типичные ошибки - Одинарные кавычки вокруг программы обязательны: иначе оболочка раскроет `$1` и `*` до того, как их увидит awk или sed. - Символ `/` в шаблоне нужно экранировать или сменить разделитель: `sed 's|/usr/local|/opt|g'`. - `sed -i` без резервной копии на важных файлах — сначала проверьте результат без `-i`. - awk по умолчанию делит по пробелам и табуляции; для CSV с запятыми внутри кавычек он не подходит. ## См. также - [grep и регулярные выражения](https://llmdocs.ru/wiki/grep.md) - [Регулярные выражения](https://llmdocs.ru/wiki/regex.md) - [Конвейеры и перенаправление (pipes)](https://llmdocs.ru/wiki/pipes-redirection.md) - [find и xargs](https://llmdocs.ru/wiki/find-xargs.md) - [Shell и Bash](https://llmdocs.ru/wiki/shell-bash.md) ## Источники 1. [GNU sed manual](https://www.gnu.org/software/sed/manual/sed.html) 2. [GNU Awk User's Guide](https://www.gnu.org/software/gawk/manual/gawk.html) 3. [POSIX.1-2024 — sed](https://pubs.opengroup.org/onlinepubs/9799919799/utilities/sed.html) 4. [POSIX.1-2024 — awk](https://pubs.opengroup.org/onlinepubs/9799919799/utilities/awk.html) 5. [The AWK Programming Language, Second Edition](https://awk.dev/) --- # Shell и Bash > Командная оболочка (shell) — программа, принимающая команды пользователя и запускающая другие программы; Bash — самая распространённая оболочка в Linux. Источник: https://llmdocs.ru/wiki/shell-bash/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: командная оболочка Unix и язык сценариев - **Автор Bash**: Брайан Фокс (проект GNU) - **Первый выпуск Bash**: 1989 - **Сопровождающий**: Чет Рэми (с 1990-х) - **Предшественник**: Bourne shell (sh, Стивен Борн, 1979) - **Стандарт**: POSIX Shell Command Language - **Лицензия**: GNU GPL v3 (с версии 4.0) - **Альтернативы**: Zsh, fish, dash, ksh **Командная оболочка** (англ. *shell*, «оболочка», «шелл») — программа, которая читает команды пользователя, запускает соответствующие программы и показывает результат. Это главный текстовый интерфейс [Linux](https://llmdocs.ru/wiki/linux.md) и других Unix-подобных систем. Оболочка одновременно служит и интерактивной средой, и языком программирования: последовательность команд можно сохранить в файл-**скрипт** и запускать как программу. **Bash** (*Bourne Again Shell* — игра слов: «снова Борн» и «рождённый заново») — самая распространённая оболочка Linux, стандартная во многих дистрибутивах и в образах [Docker](https://llmdocs.ru/wiki/docker.md). Под словом «шелл-скрипт» обычно понимают скрипт на Bash или на совместимом с POSIX `sh`. ## История Первая оболочка Unix (Thompson shell, 1971) умела только запускать команды и перенаправлять ввод-вывод. В 1979 году в Unix Version 7 появилась **Bourne shell** (`sh`) Стивена Борна — уже с переменными, условиями и циклами. Затем возникли C shell (csh), KornShell (ksh), а в 1989 году Брайан Фокс написал для проекта GNU свободную замену `sh` — Bash.[2] Вскоре сопровождение перешло к Чету Рэми, который ведёт проект до сих пор. Язык оболочки стандартизирован в POSIX: скрипт, использующий только возможности POSIX `sh`, переносим между Bash, dash, ksh и [Zsh](https://llmdocs.ru/wiki/zsh.md).[3] В Debian и Ubuntu `/bin/sh` — это минималистичная оболочка dash, а Bash используется для интерактивной работы. Apple в macOS Catalina (2019) сменила оболочку по умолчанию на Zsh, оставив в системе старую Bash 3.2 — последнюю версию под GPL v2.[5] ## Как оболочка выполняет команду Прежде чем запустить программу, оболочка разбирает строку в несколько этапов: разбивает её на слова, раскрывает фигурные скобки (`{a,b}`), тильду (`~`), переменные (`$HOME`), подстановку команд (`$(date)`), арифметику (`$((1+2))`), затем снова делит результат на слова по пробелам и раскрывает шаблоны имён файлов (`*.txt`). Только после этого ищется программа в каталогах из [переменной](https://llmdocs.ru/wiki/environment-variables.md) `PATH` и запускается через системные вызовы `fork` и `exec`.[1] Отсюда главное правило: **заключайте переменные в двойные кавычки**. `rm $file` при имени файла с пробелом удалит два разных файла, а `rm "$file"` — ровно один. ## Основы синтаксиса ```bash #!/usr/bin/env bash set -euo pipefail # падать на ошибках и неопределённых переменных name="мир" # без пробелов вокруг = echo "Привет, $name" files=(*.log) # массив (возможность Bash, не POSIX) echo "логов: ${#files[@]}" if [[ -d /var/log ]]; then # [[ ]] — расширенная проверка Bash echo "каталог есть" fi for f in "${files[@]}"; do gzip -- "$f" done count=$(grep -c ERROR app.log || true) # подстановка вывода команды (( count > 0 )) && echo "ошибок: $count" backup() { # функция local src=$1 tar czf "/tmp/$(basename "$src").tgz" "$src" } backup /etc/nginx ``` Каждая команда возвращает **код выхода**: 0 — успех, любое другое число — ошибка. На кодах выхода построены `if`, операторы `&&` и `||`. Строка `set -euo pipefail` заставляет скрипт останавливаться при первой ошибке, при обращении к неопределённой переменной и при сбое любой команды в [конвейере](https://llmdocs.ru/wiki/pipes-redirection.md). ## Перенаправление и конвейеры | Запись | Смысл | |---|---| | `cmd > file` | вывод в файл (перезаписать) | | `cmd >> file` | дописать в конец файла | | `cmd 2> err.log` | поток ошибок в файл | | `cmd > out.log 2>&1` | оба потока в один файл | | `cmd < file` | ввод из файла | | `a \| b` | вывод `a` на вход `b` | Конвейеры — суть философии Unix: маленькие программы, каждая делает одно дело, соединяются в цепочку. Например, десять самых частых IP-адресов в логе: `cut -d' ' -f1 access.log | sort | uniq -c | sort -rn | head`. Для поиска по тексту используют [grep](https://llmdocs.ru/wiki/grep.md), для преобразования — [sed и awk](https://llmdocs.ru/wiki/sed-awk.md), для обхода файлов — [find и xargs](https://llmdocs.ru/wiki/find-xargs.md). ## Интерактивная работа Bash хранит историю команд (`Ctrl+R` — поиск по ней), дополняет имена по `Tab`, поддерживает горячие клавиши в стиле Emacs (`Ctrl+A`/`Ctrl+E` — начало и конец строки). Настройки и псевдонимы (`alias ll='ls -la'`) хранятся в `~/.bashrc`. Справку по встроенным командам даёт `help`, по остальным — [man-страницы](https://llmdocs.ru/wiki/man-pages.md) и краткие примеры [tldr-pages](https://llmdocs.ru/wiki/tldr-pages.md). ## Когда не писать на Bash Bash хорош для склейки программ, автоматизации развёртывания и коротких сценариев. Когда скрипт перерастает сотню строк, требует сложных структур данных, разбора JSON (хотя есть [jq](https://llmdocs.ru/wiki/json.md)) или обработки ошибок, его лучше переписать на [Python](https://llmdocs.ru/wiki/python.md). Для проверки скриптов незаменим статический анализатор ShellCheck: он находит пропущенные кавычки, непереносимые конструкции и типичные ловушки.[4] ## См. также - [Zsh](https://llmdocs.ru/wiki/zsh.md) - [Конвейеры и перенаправление (pipes)](https://llmdocs.ru/wiki/pipes-redirection.md) - [Переменные окружения](https://llmdocs.ru/wiki/environment-variables.md) - [grep и регулярные выражения](https://llmdocs.ru/wiki/grep.md) - [Linux](https://llmdocs.ru/wiki/linux.md) ## Источники 1. [GNU Bash Reference Manual](https://www.gnu.org/software/bash/manual/bash.html) 2. [Bash — домашняя страница Чета Рэми](https://tiswww.case.edu/php/chet/bash/bashtop.html) 3. [POSIX.1-2024 — Shell Command Language](https://pubs.opengroup.org/onlinepubs/9799919799/utilities/V3_chap02.html) 4. [ShellCheck — статический анализатор shell-скриптов](https://www.shellcheck.net/) 5. [Apple — Use zsh as the default shell on your Mac](https://support.apple.com/en-us/102360) --- # SSH > Сетевой протокол для защищённого удалённого входа, выполнения команд, передачи файлов и туннелирования портов. Источник: https://llmdocs.ru/wiki/ssh/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Полное название**: Secure Shell - **Автор**: Тату Юлёнен - **Появился**: 1995 - **Стандарт**: SSH-2, RFC 4251–4254 (2006) - **Порт**: 22/TCP - **Основная реализация**: OpenSSH (с 1999) - **Другие реализации**: Dropbear, PuTTY, libssh - **Заменил**: telnet, rlogin, rsh, rcp - **Сайт OpenSSH**: [openssh.com](https://www.openssh.com/) **SSH** (англ. *Secure Shell* — «безопасная оболочка») — сетевой протокол для защищённого удалённого управления компьютером. Он шифрует весь трафик, проверяет подлинность сервера и пользователя и, помимо интерактивного входа в командную оболочку, умеет выполнять отдельные команды, передавать файлы и пробрасывать сетевые порты. SSH — основной способ администрирования серверов на [Linux](https://llmdocs.ru/wiki/linux.md) и других Unix-подобных системах, а также транспорт для [Git](https://llmdocs.ru/wiki/git.md), [rsync](https://llmdocs.ru/wiki/rsync.md) и систем управления конфигурацией вроде [Ansible](https://llmdocs.ru/wiki/ansible.md). ## История В 1995 году Тату Юлёнен, исследователь Хельсинкского технологического университета, после атаки с перехватом паролей в университетской сети написал первую версию SSH как замену протоколам telnet, rlogin и rsh, которые передавали пароли открытым текстом. Протокол быстро распространился, а позднее был переработан в несовместимую версию SSH-2, стандартизированную IETF в 2006 году в RFC 4251–4254.[1] В 1999 году разработчики OpenBSD на основе последней свободной версии исходного кода создали **OpenSSH**.[2] Сегодня это самая распространённая реализация: она входит в Linux, macOS, BSD и с 2018 года — в Windows. ## Устройство протокола SSH-2 состоит из трёх уровней:[1] 1. **Транспортный** — согласование алгоритмов, обмен ключами (Диффи — Хеллман), шифрование и проверка целостности. Здесь же клиент проверяет ключ сервера. 2. **Аутентификация пользователя** — по паролю, по открытому ключу, через сертификаты или внешние механизмы. 3. **Соединение** — внутри одного зашифрованного канала мультиплексируются сессии: оболочка, команды, подсистема SFTP, проброшенные порты. При первом подключении клиент показывает отпечаток ключа сервера и сохраняет его в `~/.ssh/known_hosts`. Если ключ позже изменится, клиент предупредит о возможной атаке «человек посередине». ## Ключи Вход по ключу надёжнее пароля: закрытый ключ остаётся у пользователя, на сервер кладётся только открытый (см. [Криптография с открытым ключом](https://llmdocs.ru/wiki/public-key-cryptography.md)). ```bash ssh-keygen -t ed25519 -C "laptop" # создать пару ключей ssh-copy-id user@server.example # дописать открытый ключ в ~/.ssh/authorized_keys ssh user@server.example # войти ``` Рекомендуемый тип ключа — Ed25519 (поддерживается в OpenSSH с 2014 года); RSA допустим при длине не менее 3072 бит. **ssh-agent** хранит расшифрованные ключи в памяти, чтобы не вводить парольную фразу при каждом подключении. ## Конфигурация клиента Файл `~/.ssh/config` задаёт короткие имена и параметры подключения:[4] ```text Host prod HostName 203.0.113.10 User deploy Port 2222 IdentityFile ~/.ssh/prod_ed25519 Host internal HostName 10.0.0.5 ProxyJump prod ``` После этого достаточно команды `ssh prod`, а `ssh internal` пройдёт к внутреннему узлу через `prod` как через промежуточный хост. ## Проброс портов | Флаг | Название | Что делает | |---|---|---| | `-L 8080:localhost:80` | локальный | порт 8080 на клиенте ведёт на порт 80 сервера | | `-R 9000:localhost:3000` | удалённый | порт 9000 на сервере ведёт на порт 3000 клиента | | `-D 1080` | динамический | SOCKS-прокси на клиенте, соединения выходят с сервера | | `-J host` | ProxyJump | подключение через промежуточный узел | Локальный проброс часто используют, чтобы открыть веб-интерфейс или базу данных, доступные на сервере только через `localhost`. ## Передача файлов - `scp file user@host:/path/` — простое копирование; начиная с OpenSSH 9.0 (2022) по умолчанию работает поверх протокола SFTP;[3] - `sftp user@host` — интерактивный файловый клиент; - [rsync](https://llmdocs.ru/wiki/rsync.md) `-avz -e ssh` — синхронизация каталогов с передачей только изменений. ## Безопасность сервера Базовые настройки `/etc/ssh/sshd_config`: запрет входа по паролю (`PasswordAuthentication no`), запрет прямого входа root (`PermitRootLogin no` или `prohibit-password`), ограничение списка пользователей. Перебор паролей отсекают ограничением частоты подключений или утилитой [Fail2ban](https://llmdocs.ru/wiki/fail2ban.md). OpenSSH внедряет постквантовую криптографию: с версии 9.0 по умолчанию используется гибридный обмен ключами `sntrup761x25519-sha512`, а с версии 10.0 (2025) — `mlkem768x25519-sha256`.[3] Заметные уязвимости последних лет — атака Terrapin на целостность рукопожатия (2023, устранена режимом «strict kex» в OpenSSH 9.6)[5] и regreSSHion (CVE-2024-6387) — удалённое выполнение кода в сервере OpenSSH на Linux с glibc, исправленное в версии 9.8.[6] Обе истории напоминают: SSH-сервер нужно своевременно обновлять. ## См. также - [Криптография с открытым ключом](https://llmdocs.ru/wiki/public-key-cryptography.md) - [TLS](https://llmdocs.ru/wiki/tls.md) - [Shell и Bash](https://llmdocs.ru/wiki/shell-bash.md) - [Аутентификация и авторизация](https://llmdocs.ru/wiki/authn-authz.md) ## Источники 1. [RFC 4251 — The Secure Shell (SSH) Protocol Architecture](https://www.rfc-editor.org/rfc/rfc4251) 2. [OpenSSH — History](https://www.openssh.com/history.html) 3. [OpenSSH Release Notes](https://www.openssh.com/releasenotes.html) 4. [ssh_config(5) — OpenBSD manual](https://man.openbsd.org/ssh_config) 5. [Terrapin Attack](https://terrapin-attack.com/) 6. [regreSSHion: RCE in OpenSSH's server (CVE-2024-6387) — Qualys](https://www.qualys.com/2024/07/01/cve-2024-6387/regresshion.txt) --- # systemd > Система инициализации и управления службами в большинстве современных дистрибутивов Linux; запускается первым процессом (PID 1) и управляет юнитами — службами, сокетами, таймерами, точками монтирования. Источник: https://llmdocs.ru/wiki/systemd/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: система инициализации и менеджер служб - **Авторы**: Леннарт Поттеринг, Кай Сиверс - **Первый выпуск**: 2010 - **Язык**: C - **Лицензия**: LGPL 2.1+ - **Основные утилиты**: systemctl, journalctl, systemd-analyze, loginctl - **По умолчанию в**: Debian, Ubuntu, Fedora, RHEL, Arch Linux, openSUSE - **Сайт**: systemd.io **systemd** — система инициализации и менеджер служб для [Linux](https://llmdocs.ru/wiki/linux.md). Ядро запускает её первым процессом (PID 1), и дальше systemd поднимает всё остальное: монтирует файловые системы, настраивает сеть, запускает службы, следит за ними и перезапускает при сбоях, а при выключении корректно всё останавливает. Помимо этого, в проект входят журнал (journald), управление сеансами пользователей (logind), сетевые настройки (networkd), DNS-резолвер (resolved), синхронизация времени и другие компоненты. Почти все популярные [дистрибутивы](https://llmdocs.ru/wiki/linux-distribution.md) используют systemd по умолчанию, поэтому `systemctl` и `journalctl` — повседневные инструменты любого администратора. ## История Классическая система инициализации SysV init запускала службы shell-скриптами строго по очереди, не умела надёжно отслеживать упавшие процессы и медленно загружала систему. Ubuntu в 2006 году перешла на событийный Upstart, но в 2010 году Леннарт Поттеринг и Кай Сиверс из Red Hat предложили более радикальный подход в статье «Rethinking PID 1».[2] Fedora 15 (2011) стала первым крупным дистрибутивом с systemd по умолчанию, затем последовали Arch Linux, openSUSE и RHEL 7. В 2014 году после долгого и бурного обсуждения на systemd перешёл Debian (выпуск Debian 8, 2015), а вслед за ним Ubuntu 15.04. Критики упрекали проект в нарушении философии Unix «одна программа — одна задача»; часть сообщества ушла в форки вроде Devuan, но большинство дистрибутивов осталось с systemd. ## Юниты Всё, чем управляет systemd, описывается **юнитами** (*units*) — текстовыми файлами в формате INI. Тип юнита задаётся расширением: | Тип | Назначение | |---|---| | `.service` | служба (демон или разовая задача) | | `.socket` | сокет; служба запускается при первом подключении | | `.timer` | запуск по расписанию — замена cron (см. [cron и таймеры systemd](https://llmdocs.ru/wiki/cron-systemd-timers.md)) | | `.target` | группа юнитов, аналог уровней запуска (`multi-user.target`) | | `.mount`, `.automount` | точки монтирования | | `.path` | реакция на изменение файла | Системные юниты лежат в `/usr/lib/systemd/system/` (от пакетов) и `/etc/systemd/system/` (локальные, имеют приоритет). Зависимости задаются директивами `Requires=`, `Wants=`, `After=`, и systemd запускает независимые службы параллельно, что ускоряет загрузку. ## Пример службы ```ini # /etc/systemd/system/myapp.service [Unit] Description=My web app After=network-online.target Wants=network-online.target [Service] User=myapp WorkingDirectory=/opt/myapp EnvironmentFile=/etc/myapp.env ExecStart=/opt/myapp/.venv/bin/uvicorn app:app --port 8000 Restart=on-failure RestartSec=5 # песочница NoNewPrivileges=yes ProtectSystem=strict ReadWritePaths=/var/lib/myapp PrivateTmp=yes [Install] WantedBy=multi-user.target ``` `Restart=on-failure` перезапускает службу при падении, а параметры песочницы ограничивают её доступ к системе: запрещают повышение привилегий, делают файловую систему доступной только для чтения, кроме указанных путей.[3][5] Служба запускается от отдельного пользователя — см. [Права доступа в Unix](https://llmdocs.ru/wiki/unix-permissions.md). ## systemctl ```bash sudo systemctl daemon-reload # перечитать unit-файлы после изменений sudo systemctl enable --now myapp # включить автозапуск и запустить сразу systemctl status myapp # состояние, PID, последние строки лога sudo systemctl restart myapp systemctl list-units --failed # что упало systemctl list-timers # таймеры и время следующего запуска systemctl cat myapp # итоговый unit-файл с переопределениями sudo systemctl edit myapp # переопределение без правки исходного файла systemd-analyze blame # какие юниты дольше всего грузились ``` Команда `systemctl edit` создаёт файл-переопределение (*drop-in*) в `/etc/systemd/system/myapp.service.d/`, поэтому обновление пакета не затрёт локальные изменения. ## Журнал Компонент journald собирает вывод всех служб, сообщения ядра и syslog в единый структурированный журнал (см. [journald и логи](https://llmdocs.ru/wiki/journald-logs.md)). Службе не нужно самой писать логи в файлы — достаточно выводить их в стандартный поток:[6] ```bash journalctl -u myapp -f # следить за логом службы journalctl -u myapp --since "1 hour ago" journalctl -p err -b # только ошибки с момента загрузки ``` ## Таймеры Таймер — пара юнитов `name.timer` и `name.service`. В отличие от cron, таймеры пишут вывод в журнал, учитывают зависимости, умеют догонять пропущенные запуски (`Persistent=true`) и добавлять случайную задержку, чтобы не нагружать сервер одновременно:[4] ```ini [Timer] OnCalendar=*-*-* 03:00:00 Persistent=true RandomizedDelaySec=10m ``` ## systemd и контейнеры Внутри [Docker](https://llmdocs.ru/wiki/docker.md)-контейнеров systemd обычно не запускают: контейнер содержит один процесс, а перезапуском занимается сам контейнерный рантайм или [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md). На хосте же systemd управляет и демоном Docker, и cgroups, через которые ограничиваются ресурсы любых служб (`MemoryMax=`, `CPUQuota=`).[1] ## См. также - [journald и логи](https://llmdocs.ru/wiki/journald-logs.md) - [cron и таймеры systemd](https://llmdocs.ru/wiki/cron-systemd-timers.md) - [Процессы и сигналы](https://llmdocs.ru/wiki/processes-signals.md) - [Linux](https://llmdocs.ru/wiki/linux.md) - [Namespaces и cgroups](https://llmdocs.ru/wiki/namespaces-cgroups.md) ## Источники 1. [systemd.io — официальный сайт проекта](https://systemd.io/) 2. [Lennart Poettering — Rethinking PID 1 (2010)](https://0pointer.de/blog/projects/systemd.html) 3. [systemd.service — manual](https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html) 4. [systemd.timer — manual](https://www.freedesktop.org/software/systemd/man/latest/systemd.timer.html) 5. [systemd.exec — sandboxing options](https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html) 6. [journalctl — manual](https://www.freedesktop.org/software/systemd/man/latest/journalctl.html) --- # tldr-pages > Сообщество и набор кратких справочных страниц по консольным командам с практическими примерами — упрощённая альтернатива man-страницам. Источник: https://llmdocs.ru/wiki/tldr-pages/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: справочник по командам командной строки - **Основан**: 2013 - **Автор идеи**: Ромен Прието - **Формат страниц**: Markdown - **Лицензия**: CC BY 4.0 (страницы), MIT (код) - **Платформы**: common, linux, osx, windows, android, freebsd и др. - **Клиенты**: tlrc (официальный), tealdeer, tldr (Node.js), веб-версия - **Сайт**: tldr.sh **tldr-pages** — открытый проект, собирающий короткие справочные страницы по командам командной строки. Каждая страница описывает команду одной фразой и даёт несколько самых нужных примеров с пояснениями. Название — интернет-аббревиатура *TL;DR* (*too long; didn't read*, «слишком длинно, не читал»): проект задуман как ответ на объёмные и сухие [man-страницы](https://llmdocs.ru/wiki/man-pages.md), в которых трудно быстро найти типичный способ использования. Страницы пишутся в [Markdown](https://llmdocs.ru/wiki/markdown.md) и распространяются под свободной лицензией, поэтому их читают не только люди, но и программы — в том числе языковые модели и ассистенты в терминале. ## История Проект начал Ромен Прието в 2013 году. Со временем он перерос в сообщество с тысячами участников и организацию на GitHub, которая поддерживает репозиторий страниц, спецификацию клиентов и официальный клиент.[2] Сегодня в коллекции тысячи страниц для разных платформ и переводы на десятки языков, включая русский. ## Пример страницы Страница — это Markdown-файл строгой структуры: заголовок с именем команды, описание в цитате, ссылка на подробную документацию и пары «пояснение — команда». Так выглядит страница для [curl](https://llmdocs.ru/wiki/curl.md) (сокращённо): ```markdown # curl > Transfers data from or to a server. > Supports most protocols, including HTTP, HTTPS, FTP, SCP, etc. > More information: . - Make an HTTP GET request and dump the contents in `stdout`: `curl {{https://example.com}}` - Send form-encoded data (POST request of type `application/x-www-form-urlencoded`): `curl {{[-d|--data]}} '{{name=bob}}' {{http://example.com/form}}` ``` Значения в двойных фигурных скобках — подстановки, которые пользователь заменяет своими. Обычно на странице не больше восьми примеров: только самые частые сценарии, а не все флаги. Правила оформления — повелительное наклонение, единые обозначения параметров, длинные и короткие формы опций — описаны в руководстве по стилю.[4] ## Организация Страницы разложены по каталогам платформ: | Каталог | Содержание | |---|---| | `common` | команды, одинаковые на всех системах (`git`, `tar`, `curl`) | | `linux` | специфичные для [Linux](https://llmdocs.ru/wiki/linux.md) (`systemctl`, `apt`, `ip`) | | `osx` | macOS (`brew`, `defaults`, `pbcopy`) | | `windows` | Windows (`winget`, `robocopy`) | | `android`, `freebsd`, `openbsd`, `sunos` | прочие платформы | Переводы лежат в отдельных каталогах `pages.<язык>`, например `pages.ru`. Клиент сначала ищет страницу для текущей платформы и языка, затем откатывается на `common` и английскую версию.[3] ## Клиенты Читать страницы можно через сайт tldr.sh, но обычно ставят консольный клиент. Он скачивает архив страниц, хранит его локально и показывает страницу с подсветкой: ```bash brew install tlrc # официальный клиент на Rust; в Linux — пакет tlrc или cargo install tlrc tldr tar # примеры для tar tldr --platform linux ss # страница для конкретной платформы tldr --language ru grep # перевод, если есть tldr --update # обновить локальный кэш ``` Популярны также tealdeer (быстрый клиент на [Rust](https://llmdocs.ru/wiki/rust.md)) и исторический клиент на Node.js.[6] Поведение клиентов — порядок поиска, кэширование, обязательные ключи — закреплено в спецификации, поэтому все они взаимозаменяемы.[3] ## tldr и man | | man-страницы | tldr-pages | |---|---|---| | Цель | полное описание всех опций | несколько типовых примеров | | Объём | от экрана до сотен страниц | обычно до 8 примеров | | Источник | авторы программы | сообщество | | Формат | roff | Markdown | tldr не заменяет man: когда нужен редкий флаг или точная семантика, приходится открывать полную документацию (ссылка на неё есть в каждой странице). Но в повседневной работе — вспомнить синтаксис `tar`, [find](https://llmdocs.ru/wiki/find-xargs.md), [grep](https://llmdocs.ru/wiki/grep.md) или `ffmpeg` — короткой страницы обычно достаточно. ## Значение для LLM-документации Страницы tldr — пример документации, удобной и людям, и машинам: компактный, единообразный Markdown с примерами, которые можно сразу выполнить. Похожие идеи развивает формат [llms.txt](https://llmdocs.ru/wiki/llms-txt.md) — краткая карта сайта в Markdown для языковых моделей. Свободная лицензия CC BY 4.0 разрешает использовать страницы в своих проектах при указании авторства.[5] Внести свою страницу или перевод можно обычным pull request в репозиторий проекта.[1] ## См. также - [man-страницы](https://llmdocs.ru/wiki/man-pages.md) - [Shell и Bash](https://llmdocs.ru/wiki/shell-bash.md) - [Markdown](https://llmdocs.ru/wiki/markdown.md) - [llms.txt](https://llmdocs.ru/wiki/llms-txt.md) ## Источники 1. [tldr-pages — официальный сайт](https://tldr.sh/) 2. [tldr-pages/tldr — репозиторий на GitHub](https://github.com/tldr-pages/tldr) 3. [tldr-pages — Client Specification](https://github.com/tldr-pages/tldr/blob/main/CLIENT-SPECIFICATION.md) 4. [tldr-pages — Style guide](https://github.com/tldr-pages/tldr/blob/main/contributing-guides/style-guide.md) 5. [tldr-pages — License](https://github.com/tldr-pages/tldr/blob/main/LICENSE.md) 6. [tealdeer — быстрый клиент tldr на Rust](https://github.com/tealdeer-rs/tealdeer) --- # tmux > Терминальный мультиплексор — делит одно окно терминала на панели и окна и сохраняет сессии запущенными после отключения, в том числе по SSH. Источник: https://llmdocs.ru/wiki/tmux/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Автор**: Николас Мэрриотт (Nicholas Marriott) - **Первый выпуск**: 2007 - **Тип**: терминальный мультиплексор - **Язык**: C - **Лицензия**: ISC - **Платформы**: Linux, macOS, BSD - **Предшественник**: GNU Screen (1987) - **Файл настройки**: ~/.tmux.conf (или ~/.config/tmux/tmux.conf) **tmux** (*terminal multiplexer*) — программа, которая запускает внутри одного окна терминала несколько независимых псевдотерминалов, раскладывает их на окна и панели и, главное, продолжает держать их запущенными, когда пользователь отключается. Если соединение по [SSH](https://llmdocs.ru/wiki/ssh.md) оборвалось, долгая сборка или обучение модели не прервутся: достаточно переподключиться и выполнить `tmux attach`. ## История Идея мультиплексора восходит к GNU Screen (1987).[4] tmux написал Николас Мэрриотт в 2007 году как современную альтернативу с понятной архитектурой «клиент — сервер», вертикальным и горизонтальным делением экрана и скриптуемой конфигурацией. С 2009 года tmux входит в базовую систему OpenBSD, а в Linux-дистрибутивах доступен через [пакетный менеджер](https://llmdocs.ru/wiki/package-managers.md).[1] ## Устройство tmux состоит из **сервера** — фонового процесса, который владеет всеми сессиями, — и **клиентов**, подключающихся к нему из терминалов. Иерархия объектов:[2] | Объект | Что это | |---|---| | Сервер | один процесс на пользователя, общается с клиентами через сокет в `/tmp` | | Сессия | набор окон; можно отсоединиться и вернуться | | Окно | «вкладка», занимает весь экран | | Панель (pane) | часть окна со своим shell | Поскольку процессы принадлежат серверу, а не терминалу, закрытие окна эмулятора или разрыв сети не отправляет им сигнал SIGHUP (см. [Процессы и сигналы](https://llmdocs.ru/wiki/processes-signals.md)). ## Основные команды Все сочетания клавиш начинаются с **префикса** — по умолчанию `Ctrl+b`, затем отпустить и нажать клавишу команды.[3] | Действие | Команда / клавиши | |---|---| | Новая сессия | `tmux new -s work` | | Список сессий | `tmux ls` | | Подключиться | `tmux attach -t work` (или `tmux a`) | | Отсоединиться | `префикс d` | | Новое окно | `префикс c` | | Следующее/предыдущее окно | `префикс n` / `префикс p` | | Деление по вертикали / горизонтали | `префикс %` / `префикс "` | | Переход между панелями | `префикс` + стрелки | | Увеличить панель на весь экран | `префикс z` | | Режим прокрутки и копирования | `префикс [` | | Командная строка tmux | `префикс :` | ## Настройка Конфигурация пишется на языке команд tmux в `~/.tmux.conf`: ```tmux # префикс Ctrl+a вместо Ctrl+b unbind C-b set -g prefix C-a bind C-a send-prefix # мышь: выбор панелей, прокрутка, изменение размеров set -g mouse on # нумерация окон с 1 и большая история set -g base-index 1 set -g history-limit 50000 # vi-клавиши в режиме копирования setw -g mode-keys vi ``` Применить без перезапуска: `tmux source-file ~/.tmux.conf`. Режим копирования с vi-клавишами удобен тем, кто привык к [Vim](https://llmdocs.ru/wiki/vim.md). ## Скриптование Любое действие доступно как команда, поэтому раскладку рабочего места можно описать скриптом: ```bash tmux new-session -d -s dev -n editor tmux send-keys -t dev:editor 'vim .' C-m tmux new-window -t dev -n server tmux send-keys -t dev:server 'npm run dev' C-m tmux split-window -h -t dev:server 'tail -f app.log' tmux attach -t dev ``` Для этого существуют и готовые инструменты: **tmuxinator** и **tmuxp** описывают сессии в YAML. Плагины подключаются через **TPM** (Tmux Plugin Manager); популярный `tmux-resurrect` сохраняет раскладку между перезагрузками сервера. ## Сравнение - **GNU Screen** — старше, есть почти везде, умеет работать с последовательными портами; деление экрана и настройка менее удобны. - **Zellij** — мультиплексор на Rust с подсказками клавиш на экране и плагинами на WebAssembly. - **Встроенные вкладки терминала** (iTerm2, WezTerm, Kitty) удобны локально, но не переживают разрыв SSH; iTerm2 умеет интегрироваться с tmux через `tmux -CC`. ## Практика Типичный сценарий на сервере: зайти по SSH, выполнить `tmux new -s train`, запустить длинную задачу, нажать `Ctrl+b d` и выйти. Позже — `ssh host -t tmux attach -t train`. Для фоновых служб, которые должны пережить перезагрузку, правильнее использовать [systemd](https://llmdocs.ru/wiki/systemd.md), а не tmux. ## См. также - [SSH](https://llmdocs.ru/wiki/ssh.md) - [Shell и Bash](https://llmdocs.ru/wiki/shell-bash.md) - [Zsh](https://llmdocs.ru/wiki/zsh.md) - [Vim](https://llmdocs.ru/wiki/vim.md) ## Источники 1. [tmux — репозиторий и wiki](https://github.com/tmux/tmux/wiki) 2. [tmux(1) — man page (OpenBSD)](https://man.openbsd.org/tmux) 3. [tmux Getting Started](https://github.com/tmux/tmux/wiki/Getting-Started) 4. [GNU Screen](https://www.gnu.org/software/screen/) --- # Права доступа в Unix > Модель разграничения доступа к файлам в Unix и Linux — владелец, группа и остальные, права на чтение, запись и выполнение, а также setuid, sticky bit, umask и ACL. Источник: https://llmdocs.ru/wiki/unix-permissions/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Классы пользователей**: владелец (u), группа (g), остальные (o) - **Базовые права**: чтение (r), запись (w), выполнение (x) - **Специальные биты**: setuid, setgid, sticky - **Запись**: символьная (rwxr-xr-x) или восьмеричная (755) - **Команды**: chmod, chown, chgrp, umask, setfacl - **Суперпользователь**: root (UID 0) **Права доступа в Unix** — модель, по которой операционная система решает, кто может читать, изменять и запускать файл. У каждого файла и каталога есть владелец, группа и набор из девяти битов прав: что разрешено владельцу, членам группы и всем остальным. Эта простая схема появилась в первых версиях Unix в начале 1970-х и до сих пор лежит в основе безопасности [Linux](https://llmdocs.ru/wiki/linux.md), macOS и BSD. ## Пользователи и группы Каждый процесс работает от имени пользователя с числовым идентификатором **UID** и состоит в одной или нескольких группах (**GID**). Пользователи перечислены в `/etc/passwd`, группы — в `/etc/group`. Пользователь **root** (UID 0) — суперпользователь: проверки прав на него не распространяются. Поэтому повседневная работа ведётся от обычного пользователя, а административные команды запускаются через `sudo`. Службы на сервере принято запускать от отдельных непривилегированных пользователей (`www-data`, `postgres`), чтобы взлом одной из них не давал доступа ко всей системе. ## Базовые права Вывод `ls -l` показывает тип и права в первом столбце: ```text -rwxr-x--- 1 alice devs 4096 ноя 9 10:00 deploy.sh drwxr-xr-x 2 alice devs 4096 ноя 9 10:00 public ``` Первый символ — тип (`-` файл, `d` каталог, `l` символическая ссылка), затем три тройки: владелец, группа, остальные.[2] Смысл букв для файлов и каталогов различается: | Право | Для файла | Для каталога | |---|---|---| | `r` (4) | читать содержимое | получать список имён | | `w` (2) | изменять содержимое | создавать, удалять и переименовывать файлы внутри | | `x` (1) | запускать как программу | входить (`cd`) и обращаться к файлам по имени | Важное следствие: возможность удалить файл определяется правом `w` на **каталог**, а не на сам файл. А без `x` на каталог файлы в нём недоступны, даже если права самих файлов открыты. ## Восьмеричная запись Каждая тройка кодируется цифрой — суммой значений `r=4`, `w=2`, `x=1`: | Запись | Права | Типичное применение | |---|---|---| | `755` | `rwxr-xr-x` | программы, каталоги | | `644` | `rw-r--r--` | обычные файлы | | `700` | `rwx------` | личный каталог, `~/.ssh` | | `600` | `rw-------` | закрытые ключи, файлы с паролями | | `777` | `rwxrwxrwx` | почти всегда ошибка | ```bash chmod 600 ~/.ssh/id_ed25519 # восьмеричная запись chmod u+x,go-w script.sh # символьная: добавить x владельцу, убрать w группе и остальным chmod -R g+rX shared/ # X — выполнение только для каталогов и уже исполняемых файлов chown alice:devs report.txt # сменить владельца и группу ``` Клиент [SSH](https://llmdocs.ru/wiki/ssh.md) откажется использовать закрытый ключ, если права на него слишком открыты, — частая причина ошибок подключения.[1] ## Специальные биты - **setuid** (4000) — программа запускается с правами владельца файла, а не запустившего пользователя. Так работает `passwd`: обычный пользователь меняет свой пароль в файле, доступном только root. В `ls -l` отображается как `s` вместо `x` у владельца. - **setgid** (2000) — на файле аналогично для группы; на каталоге — новые файлы наследуют группу каталога, что удобно для общих рабочих папок. - **sticky bit** (1000) — на каталоге удалять файл может только его владелец. Стоит на `/tmp` (права `1777`, буква `t`), куда пишут все. Setuid-программы — излюбленная цель атак на повышение привилегий, поэтому их число в системе стараются сводить к минимуму. ## umask **umask** — маска, которая убирает права у вновь создаваемых файлов. Программы обычно создают файлы с правами 666 и каталоги с 777, а маска вычитает лишнее: при типичном `umask 022` получаются 644 и 755, при `077` — файлы доступны только владельцу.[3] ## ACL и capabilities Классической тройки «владелец, группа, остальные» иногда не хватает — например, чтобы дать доступ к файлу ещё одному конкретному пользователю. Для этого существуют **списки контроля доступа** (POSIX ACL):[4] ```bash setfacl -m u:bob:r report.txt # разрешить bob чтение getfacl report.txt # показать ACL ``` С другой стороны, всемогущество root разбито в Linux на отдельные **привилегии** (*capabilities*): например, `CAP_NET_BIND_SERVICE` позволяет занимать порты ниже 1024 без остальных прав суперпользователя.[5] Capabilities активно используют [systemd](https://llmdocs.ru/wiki/systemd.md) и контейнерные среды вроде [Docker](https://llmdocs.ru/wiki/docker.md), отбирая у процессов всё лишнее. ## Типичные ошибки - `chmod -R 777` «чтобы заработало» — открывает файлы всем пользователям системы и маскирует настоящую проблему (не тот владелец). - Файлы, созданные через `sudo`, принадлежат root, и потом обычный пользователь не может их изменить — нужно `chown`. - Скрипт без бита `x` запускается только как `bash script.sh`, а не `./script.sh`; см. [Shell и Bash](https://llmdocs.ru/wiki/shell-bash.md). - В контейнерах UID процесса и UID владельца смонтированного тома могут не совпадать, отсюда «Permission denied» при вполне разумных правах. ## См. также - [Linux](https://llmdocs.ru/wiki/linux.md) - [Процессы и сигналы](https://llmdocs.ru/wiki/processes-signals.md) - [SSH](https://llmdocs.ru/wiki/ssh.md) - [Файловая система Unix (FHS)](https://llmdocs.ru/wiki/fhs.md) ## Источники 1. [chmod(1) — Linux manual page](https://man7.org/linux/man-pages/man1/chmod.1.html) 2. [inode(7) — Linux manual page (file type and mode)](https://man7.org/linux/man-pages/man7/inode.7.html) 3. [umask(2) — Linux manual page](https://man7.org/linux/man-pages/man2/umask.2.html) 4. [acl(5) — Linux manual page](https://man7.org/linux/man-pages/man5/acl.5.html) 5. [capabilities(7) — Linux manual page](https://man7.org/linux/man-pages/man7/capabilities.7.html) --- # Vim > Модальный текстовый редактор для терминала, наследник vi; редактирование командами-«предложениями» из операторов и движений. Neovim — его современный форк. Источник: https://llmdocs.ru/wiki/vim/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Полное название**: Vi IMproved - **Автор**: Брам Моленар (Bram Moolenaar) - **Первый выпуск**: 1991 - **Предшественник**: vi (Билл Джой, 1976) - **Язык**: C, Vim script - **Лицензия**: Vim License (совместима с GPL) - **Форк**: Neovim (2014, Lua) - **Файл настройки**: ~/.vimrc (Neovim — ~/.config/nvim/init.lua) **Vim** (*Vi IMproved*) — текстовый редактор для терминала, расширенная версия классического Unix-редактора vi. Главная черта Vim — **модальность**: в одном режиме клавиши вводят текст, в другом — работают как команды. Это позволяет редактировать текст без мыши и без длинных сочетаний с Ctrl, комбинируя короткие команды. Vim или совместимый vi есть практически на любом сервере с [Linux](https://llmdocs.ru/wiki/linux.md), поэтому базовые навыки работы с ним — часть грамотности системного администратора. ## История Редактор **vi** написал Билл Джой в 1976 году для BSD Unix; он вошёл в стандарт POSIX.[4] В 1991 году голландский программист Брам Моленар выпустил Vim для компьютера Amiga, и редактор быстро стал стандартом де-факто на Unix-системах. Моленар руководил проектом более тридцати лет; после его смерти в 2023 году разработку продолжает команда мейнтейнеров на GitHub.[5] Vim распространяется как «charityware»: автор просил жертвовать детям в Уганде.[1] В 2014 году появился форк **Neovim** — с асинхронной архитектурой, встроенным Lua, клиентом LSP и tree-sitter для подсветки синтаксиса.[3] Сегодня Vim и Neovim развиваются параллельно. ## Режимы | Режим | Как войти | Назначение | |---|---|---| | Normal | `Esc` | навигация и команды (основной) | | Insert | `i`, `a`, `o` | ввод текста | | Visual | `v`, `V`, `Ctrl+v` | выделение символов, строк, блока | | Command-line | `:` | команды Ex: сохранение, замена, настройки | | Replace | `R` | перезапись поверх текста | Знаменитый вопрос «как выйти из Vim» решается так: `Esc`, затем `:q` (выйти), `:wq` (сохранить и выйти) или `:q!` (выйти без сохранения). ## Язык команд Команды Normal-режима складываются по схеме **[число] оператор движение**, как фразы:[2] - **Операторы**: `d` — удалить, `c` — изменить, `y` — скопировать, `>` — сдвинуть, `gU` — в верхний регистр. - **Движения**: `w` — слово, `$` — конец строки, `}` — абзац, `gg`/`G` — начало/конец файла, `f,` — до запятой. - **Текстовые объекты**: `iw` — слово, `i"` — внутри кавычек, `ap` — абзац, `it` — внутри тега. Отсюда: `d3w` — удалить три слова, `ci"` — заменить текст в кавычках, `yap` — скопировать абзац. Команда `.` повторяет последнее изменение, `u` отменяет, `Ctrl+r` возвращает. ## Полезные команды ```vim :%s/old/new/gc " заменить во всём файле с подтверждением :g/DEBUG/d " удалить все строки с DEBUG :sort u " отсортировать строки и убрать дубли :e file.txt " открыть файл :vsplit other.py " вертикальное деление окна :set number " номера строк qa ... q, затем @a " записать и воспроизвести макрос ``` Поиск — `/шаблон`, следующий результат — `n`. Шаблоны — регулярные выражения со своими особенностями синтаксиса (см. [grep и регулярные выражения](https://llmdocs.ru/wiki/grep.md)); ключ `\v` («very magic») делает их ближе к привычным расширенным регэкспам. ## Настройка Минимальный `~/.vimrc`: ```vim syntax on set number relativenumber set expandtab shiftwidth=4 tabstop=4 set ignorecase smartcase incsearch hlsearch set clipboard=unnamedplus ``` Плагины ставятся менеджерами `vim-plug` или встроенными пакетами (`:help packages`). В Neovim конфигурацию пишут на Lua, а дистрибутивы вроде LazyVim и kickstart.nvim дают готовую IDE-подобную сборку с LSP, автодополнением и поиском по файлам. ## Vim вне Vim Модальные клавиши Vim поддерживают многие программы: расширения для VS Code и JetBrains, режим `set -o vi` в [Bash](https://llmdocs.ru/wiki/shell-bash.md) и `bindkey -v` в [Zsh](https://llmdocs.ru/wiki/zsh.md), режим копирования в [tmux](https://llmdocs.ru/wiki/tmux.md), утилиты `less` и `man` (навигация `j`/`k`, поиск `/`). Встроенный учебник запускается командой `vimtutor` и занимает около получаса. Встроенная справка открывается командой `:help` и по объёму сопоставима с книгой: например, `:help text-objects` описывает все текстовые объекты, а `:help usr_toc` — оглавление пользовательского руководства. Поскольку vi входит в стандарт POSIX, минимальные навыки — вставка, сохранение, поиск и выход — пригодятся на любом сервере, даже если основным редактором остаётся графическая IDE. ## См. также - [Linux](https://llmdocs.ru/wiki/linux.md) - [tmux](https://llmdocs.ru/wiki/tmux.md) - [man-страницы](https://llmdocs.ru/wiki/man-pages.md) - [grep и регулярные выражения](https://llmdocs.ru/wiki/grep.md) ## Источники 1. [Vim — официальный сайт](https://www.vim.org/) 2. [Vim documentation (vimhelp.org)](https://vimhelp.org/) 3. [Neovim — официальный сайт](https://neovim.io/) 4. [POSIX — vi utility](https://pubs.opengroup.org/onlinepubs/9799919799/utilities/vi.html) 5. [Vim repository on GitHub](https://github.com/vim/vim) --- # Zsh > Командная оболочка Unix, совместимая с sh, с мощным автодополнением, глоббингом и гибкой настройкой; оболочка по умолчанию в macOS с 2019 года. Источник: https://llmdocs.ru/wiki/zsh/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Автор**: Пол Фальстад (Paul Falstad) - **Первый выпуск**: 1990 - **Тип**: командная оболочка Unix - **Совместимость**: POSIX sh (в режиме эмуляции), во многом Bash - **Лицензия**: MIT-подобная (Zsh License) - **По умолчанию**: macOS Catalina (10.15) и новее, Kali Linux - **Файлы настройки**: ~/.zshenv, ~/.zprofile, ~/.zshrc, ~/.zlogin - **Сайт**: zsh.org **Zsh** (*Z shell*) — командная оболочка для Unix-подобных систем, расширяющая классический Bourne shell (sh). Zsh понимает почти все скрипты для [Bash](https://llmdocs.ru/wiki/shell-bash.md), но добавляет к ним развитое программируемое автодополнение, расширенный глоббинг (шаблоны имён файлов), исправление опечаток, общую историю между сессиями и систему тем и плагинов. С версии macOS Catalina (2019) zsh — оболочка по умолчанию на Mac.[3] ## История Первую версию написал в 1990 году Пол Фальстад, тогда студент Принстона. Название происходит от логина преподавателя Чжуна Шао (Zhong Shao) — `zsh`. Со временем проект перешёл к сообществу; разработку координирует группа мейнтейнеров, исходники и документация доступны на zsh.org.[1] Широкую популярность zsh получил в 2010-х благодаря фреймворку **Oh My Zsh** (2009), который упростил установку тем и плагинов.[4] Переход Apple на zsh был связан с лицензией: Bash в macOS оставался на версии 3.2, последней под GPLv2, а более новые версии распространяются под GPLv3. ## Отличия от Bash Zsh не является строгим надмножеством Bash, но различия обычно заметны только в скриптах.[5] | Возможность | Bash | Zsh | |---|---|---| | Индексы массивов | с 0 | с 1 (по умолчанию) | | Разбиение `$var` на слова | да | нет (без `setopt SH_WORD_SPLIT`) | | Рекурсивный глоб `**/` | с `shopt -s globstar` | встроен | | Квалификаторы глоба | нет | `*(.)`, `*(/)`, `*(om[1,5])` | | Правый промпт | нет | `RPROMPT` | | Автодополнение | bash-completion | compsys, с меню и описаниями | Отсутствие разбиения переменных на слова — частый источник сюрпризов при переносе скриптов, но и защита от целого класса ошибок с пробелами в именах файлов. Для переносимых скриптов принято писать `#!/bin/sh` или `#!/usr/bin/env bash`, а zsh использовать как интерактивную оболочку. ## Возможности **Глоббинг.** Квалификаторы в скобках фильтруют файлы прямо в шаблоне: `ls **/*.py(.m-7)` — обычные файлы `.py`, изменённые за последнюю неделю, во всех подкаталогах; `rm *(.L0)` — пустые файлы. Это часто заменяет связку [find и xargs](https://llmdocs.ru/wiki/find-xargs.md). **Автодополнение.** Система `compsys` знает аргументы тысяч команд (git, docker, kubectl, ssh-хосты из `~/.ssh/config`), показывает меню со стрелками и подсказками. Включается строками: ```zsh autoload -Uz compinit && compinit zstyle ':completion:*' menu select ``` **История.** Опции `SHARE_HISTORY`, `HIST_IGNORE_DUPS`, `EXTENDED_HISTORY` позволяют делить историю между окнами терминала, убирать дубли и хранить время выполнения команд. **Прочее.** Автоматический `cd` по имени каталога (`AUTO_CD`), стек каталогов (`pushd`/`popd`, `cd -`), коррекция опечаток (`CORRECT`), глобальные алиасы (`alias -g G='| grep'`), модульная загрузка функций через `autoload`. ## Файлы настройки Zsh читает конфигурацию в определённом порядке:[2] 1. `~/.zshenv` — всегда, для любых экземпляров (в том числе скриптов); подходит для [переменных окружения](https://llmdocs.ru/wiki/environment-variables.md) вроде `PATH`. 2. `~/.zprofile` — для оболочек входа (login shell). 3. `~/.zshrc` — для интерактивных оболочек: алиасы, промпт, плагины. 4. `~/.zlogin` и `~/.zlogout` — при входе и выходе. Системные аналоги лежат в `/etc/zsh/` или `/etc/`. ## Фреймворки и плагины - **Oh My Zsh** — самый популярный фреймворк: сотни плагинов (`git`, `docker`, `kubectl`) и тем. Минус — замедляет запуск оболочки. - **Prezto**, **zinit**, **antidote** — более лёгкие менеджеры плагинов с ленивой загрузкой. - **zsh-autosuggestions** — подсказывает команду из истории серым текстом; **zsh-syntax-highlighting** — подсвечивает синтаксис по мере ввода. - **Powerlevel10k** и кроссплатформенный **Starship** — быстрые информативные промпты (ветка git, код возврата, версия языка). ## Практика ```bash # сменить оболочку на zsh chsh -s "$(command -v zsh)" # замерить скорость запуска time zsh -i -c exit # проверить, какая оболочка запущена echo $ZSH_VERSION ``` Если запуск занимает больше 200–300 мс, обычно виноваты тяжёлые плагины или повторный `compinit`; профилировать можно модулем `zmodload zsh/zprof`. ## См. также - [Shell и Bash](https://llmdocs.ru/wiki/shell-bash.md) - [Linux](https://llmdocs.ru/wiki/linux.md) - [tmux](https://llmdocs.ru/wiki/tmux.md) - [Конвейеры и перенаправление (pipes)](https://llmdocs.ru/wiki/pipes-redirection.md) ## Источники 1. [Zsh — официальный сайт](https://www.zsh.org/) 2. [Zsh Manual (zsh.sourceforge.io)](https://zsh.sourceforge.io/Doc/Release/) 3. [Apple — Use zsh as the default shell on your Mac](https://support.apple.com/en-us/102360) 4. [Oh My Zsh — репозиторий](https://github.com/ohmyzsh/ohmyzsh) 5. [Zsh FAQ — How does zsh differ from bash](https://zsh.sourceforge.io/FAQ/zshfaq02.html) --- # ИИ-агент > Система на основе языковой модели, которая самостоятельно планирует и выполняет многошаговые задачи, вызывая инструменты и наблюдая результаты, пока цель не достигнута. Источник: https://llmdocs.ru/wiki/ai-agent/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Основа**: большая языковая модель - **Ключевой механизм**: цикл «рассуждение — действие — наблюдение» - **Действия**: вызов инструментов (tool use), API, код, браузер, файлы - **Протоколы**: Model Context Protocol (MCP) - **Примеры**: агенты для кода, исследовательские агенты, управление компьютером - **Риски**: ошибки на длинных цепочках, prompt injection, лишние права **ИИ-агент** — система на основе [языковой модели](https://llmdocs.ru/wiki/llm.md), которая не просто отвечает на один вопрос, а сама ведёт многошаговую работу: планирует, вызывает инструменты — поиск, API, выполнение кода, работу с файлами, — смотрит на результаты и решает, что делать дальше, пока задача не будет выполнена. В классическом определении искусственного интеллекта агент — это всё, что воспринимает среду и действует в ней;[6] LLM-агенты используют языковую модель как «мозг», принимающий решения. Агенты применяются для написания и исправления кода ([Агенты для кода](https://llmdocs.ru/wiki/coding-agents.md)), исследования и сбора информации, обработки документов, поддержки клиентов и управления компьютером через интерфейс. ## Агентный цикл В основе почти любого агента — простой цикл: 1. Модель получает цель, инструкции, описание доступных инструментов и историю предыдущих шагов. 2. Модель рассуждает и выбирает действие — вызов инструмента с аргументами — или решает, что задача выполнена. 3. Программа-оркестратор выполняет вызов ([Tool use / function calling](https://llmdocs.ru/wiki/tool-use.md)) и возвращает результат модели. 4. Результат добавляется в контекст, и цикл повторяется. Подход, чередующий рассуждения и действия, описан в работе ReAct (2022).[2] Ранее Toolformer показал, что модели могут научиться сами решать, когда вызывать внешние инструменты.[3] ```python messages = [{"role": "user", "content": task}] while True: resp = client.messages.create(model=MODEL, tools=TOOLS, messages=messages, max_tokens=4096) messages.append({"role": "assistant", "content": resp.content}) if resp.stop_reason != "tool_use": break # модель дала финальный ответ results = [ {"type": "tool_result", "tool_use_id": b.id, "content": run_tool(b.name, b.input)} for b in resp.content if b.type == "tool_use" ] messages.append({"role": "user", "content": results}) ``` ## Агенты и рабочие процессы Anthropic в руководстве «Building effective agents» разделяет два типа систем:[1] - **Рабочие процессы** (*workflows*) — шаги заранее заданы кодом: цепочка запросов, маршрутизация по типу задачи, параллельная обработка, схема «исполнитель и проверяющий». Предсказуемы и дёшевы. - **Агенты** — модель сама решает, какие шаги делать и в каком порядке. Гибки, но дороже, медленнее и менее предсказуемы. Главный совет — начинать с самого простого решения: часто одного хорошо составленного запроса с [RAG](https://llmdocs.ru/wiki/rag.md) достаточно, рабочий процесс нужен для чётко структурированных задач, а агент — когда шаги невозможно предсказать заранее. ## Составные части | Компонент | Назначение | |---|---| | Модель | рассуждение и выбор действий | | Инструменты | поиск, чтение и запись файлов, выполнение команд, API, браузер | | Память | контекст диалога, заметки в файлах, базы знаний | | Оркестратор | цикл вызовов, ограничения, обработка ошибок | | Окружение | песочница, где выполняются действия | | Ограждения | права доступа, подтверждения, лимиты шагов и бюджета | Подключать инструменты и источники данных к разным агентам позволяет открытый протокол [MCP](https://llmdocs.ru/wiki/mcp.md): один сервер — например, доступ к базе данных или документации — работает с любым совместимым клиентом.[5] ## Мультиагентные системы Сложные задачи иногда делят между несколькими агентами: оркестратор разбивает работу и раздаёт подзадачи исполнителям, каждый со своим контекстом и инструментами. Это позволяет работать параллельно и не перегружать [контекстное окно](https://llmdocs.ru/wiki/context-window.md) одного агента, но многократно увеличивает расход токенов и усложняет отладку. Оправдано, когда подзадачи действительно независимы. ## Оценка Качество агентов измеряют на задачах с проверяемым результатом. Бенчмарк SWE-bench предлагает исправлять реальные ошибки из открытых репозиториев на GitHub, а правильность проверяется тестами проекта.[4] Для своих агентов собирают набор характерных задач и отслеживают долю успешных выполнений, число шагов и стоимость (см. [Оценка LLM (evals)](https://llmdocs.ru/wiki/llm-evals.md)). ## Риски и ограничения - **Накопление ошибок.** Каждый шаг может ошибиться, и на длинных цепочках ошибки складываются; агенту нужна возможность проверять себя — тесты, линтеры, сверка с источником. - **Prompt injection.** Агент читает внешние данные — веб-страницы, письма, документы, — в которых могут быть вредоносные инструкции (см. [Безопасность LLM: prompt injection](https://llmdocs.ru/wiki/prompt-injection.md)). - **Лишние права.** Агенту стоит давать минимальные необходимые полномочия ([Принцип наименьших привилегий](https://llmdocs.ru/wiki/least-privilege.md)), выполнять код в изолированной среде и требовать подтверждения человеком для необратимых действий: удаления данных, платежей, отправки сообщений. - **Стоимость и время.** Десятки вызовов модели на задачу; помогают кэширование, лимиты шагов и более дешёвые модели для простых подзадач. ## См. также - [Tool use / function calling](https://llmdocs.ru/wiki/tool-use.md) - [Model Context Protocol (MCP)](https://llmdocs.ru/wiki/mcp.md) - [Агенты для кода](https://llmdocs.ru/wiki/coding-agents.md) - [Безопасность LLM: prompt injection](https://llmdocs.ru/wiki/prompt-injection.md) - [Промпт-инжиниринг](https://llmdocs.ru/wiki/prompt-engineering.md) ## Источники 1. [Anthropic — Building effective agents (2024)](https://www.anthropic.com/engineering/building-effective-agents) 2. [S. Yao et al. — ReAct: Synergizing Reasoning and Acting in Language Models (2022)](https://arxiv.org/abs/2210.03629) 3. [T. Schick et al. — Toolformer: Language Models Can Teach Themselves to Use Tools (2023)](https://arxiv.org/abs/2302.04761) 4. [C. Jimenez et al. — SWE-bench: Can Language Models Resolve Real-World GitHub Issues? (2023)](https://arxiv.org/abs/2310.06770) 5. [Model Context Protocol — Specification](https://modelcontextprotocol.io/specification) 6. [S. Russell, P. Norvig — Artificial Intelligence: A Modern Approach](https://aima.cs.berkeley.edu/) --- # Чанкинг документов > Разбиение документов на фрагменты (чанки) для индексации и поиска в RAG-системах; стратегии, размеры, перекрытие и типичные ошибки. Источник: https://llmdocs.ru/wiki/chunking/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Применение**: RAG, семантический поиск, суммаризация длинных текстов - **Типичный размер**: 200–1000 токенов - **Перекрытие**: 10–20% от размера чанка - **Стратегии**: фиксированная длина, рекурсивная, по структуре, семантическая - **Инструменты**: LangChain text splitters, LlamaIndex node parsers, Unstructured, Docling **Чанкинг** (англ. *chunking*) — разбиение документов на небольшие фрагменты, **чанки**, которые затем по отдельности индексируются и находятся поиском. Это первый и один из самых влиятельных этапов в системах [RAG](https://llmdocs.ru/wiki/rag.md): модель отвечает на основе найденных чанков, и если нужный факт разрезан пополам или утонул в слишком большом фрагменте, качество ответа падает независимо от того, насколько хороша сама [языковая модель](https://llmdocs.ru/wiki/llm.md).[4] ## Зачем разбивать - **Точность поиска.** [Эмбеддинг](https://llmdocs.ru/wiki/embedding.md) длинного текста усредняет много тем и плохо совпадает с конкретным вопросом; эмбеддинг короткого фрагмента выражает одну мысль. - **Ограничения моделей.** У моделей эмбеддингов есть предел входа (часто 512–8192 [токенов](https://llmdocs.ru/wiki/tokenization.md)), а [контекстное окно](https://llmdocs.ru/wiki/context-window.md) генератора не безгранично и стоит денег. - **Цитирование.** Маленький фрагмент можно показать пользователю как источник ответа. Противоположная крайность — слишком мелкие чанки: они теряют контекст («он», «этот метод», «см. выше») и не содержат полного ответа. Выбор размера — компромисс между точностью поиска и полнотой фрагмента. ## Стратегии | Стратегия | Как режет | Плюсы и минусы | |---|---|---| | Фиксированная длина | каждые N символов или токенов | просто, но рвёт предложения | | Рекурсивная | по абзацам, затем предложениям, затем словам — пока кусок не влезет | хороший вариант по умолчанию | | По структуре | по заголовкам [Markdown](https://llmdocs.ru/wiki/markdown.md) или HTML, функциям в коде, строкам таблицы | сохраняет смысловые границы | | Семантическая | там, где резко меняется смысл соседних предложений по эмбеддингам | дороже, выигрыш нестабилен | | Агентная / LLM | модель сама выделяет смысловые блоки | качественно, но медленно и дорого | Рекурсивный разделитель — стандарт в библиотеках LangChain и LlamaIndex.[1][2] Для документации и вики лучше всего работает разбиение по структуре: раздел с заголовком — естественная единица смысла. ```python from langchain_text_splitters import (MarkdownHeaderTextSplitter, RecursiveCharacterTextSplitter) md = open("tls.md").read() by_headers = MarkdownHeaderTextSplitter( headers_to_split_on=[("#", "h1"), ("##", "h2"), ("###", "h3")] ).split_text(md) splitter = RecursiveCharacterTextSplitter(chunk_size=1200, chunk_overlap=150) chunks = splitter.split_documents(by_headers) # заголовки сохраняются в metadata ``` ## Перекрытие и метаданные **Перекрытие** (overlap) — соседние чанки делят 10–20% текста, чтобы факт на границе попал целиком хотя бы в один из них. **Метаданные** — источник, заголовки раздела, дата, язык — хранятся вместе с чанком: их используют для фильтрации, цитирования и для добавления в сам текст перед вычислением эмбеддинга. ## Контекст для чанка Главная слабость чанкинга — фрагмент, вырванный из документа, теряет контекст. Приёмы борьбы: - **Заголовочная цепочка** — к тексту чанка приписывается путь «Документ → Раздел → Подраздел». - **Контекстный поиск** (contextual retrieval) — языковая модель пишет к каждому чанку одно-два предложения о его месте в документе; по данным Anthropic, это заметно сокращает число неудачных извлечений, особенно в сочетании с ключевым поиском BM25.[3] - **Позднее разбиение** (late chunking) — эмбеддинги токенов вычисляются по всему документу длинноконтекстной моделью и только потом усредняются по чанкам.[5] - **Родитель–потомок** — ищут по мелким чанкам, а модели отдают крупный родительский фрагмент. ## Подготовка исходников Качество чанкинга упирается в извлечение текста. PDF с колонками, таблицами и колонтитулами превращается в кашу, если читать его наивно; инструменты вроде Docling и Unstructured восстанавливают структуру, таблицы и порядок чтения.[6] Поэтому документация, изначально написанная в Markdown, — лучший вход для RAG (см. [Markdown как формат для LLM](https://llmdocs.ru/wiki/markdown-for-llm.md) и [Документация для ИИ: как подготовить](https://llmdocs.ru/wiki/docs-for-ai.md)). ## Как подобрать параметры Универсального размера нет. Разумный старт — 500–1000 токенов с перекрытием 10–15% и разбиением по заголовкам. Дальше параметры подбирают на наборе реальных вопросов с известными ответами, измеряя долю найденных нужных фрагментов (recall@k) — см. [Оценка LLM (evals)](https://llmdocs.ru/wiki/llm-evals.md). С ростом контекстных окон часть задач решается вообще без разбиения: небольшой корпус целиком помещают в промпт с [кэшированием](https://llmdocs.ru/wiki/prompt-caching.md). ## См. также - [RAG (генерация с дополнением поиском)](https://llmdocs.ru/wiki/rag.md) - [Векторный поиск](https://llmdocs.ru/wiki/vector-search.md) - [Эмбеддинг](https://llmdocs.ru/wiki/embedding.md) - [Markdown как формат для LLM](https://llmdocs.ru/wiki/markdown-for-llm.md) - [llms.txt](https://llmdocs.ru/wiki/llms-txt.md) ## Источники 1. [LangChain — Text splitters](https://python.langchain.com/docs/concepts/text_splitters/) 2. [LlamaIndex — Node Parser Modules](https://docs.llamaindex.ai/en/stable/module_guides/loading/node_parsers/modules/) 3. [Anthropic — Introducing Contextual Retrieval (2024)](https://www.anthropic.com/news/contextual-retrieval) 4. [Pinecone — Chunking Strategies for LLM Applications](https://www.pinecone.io/learn/chunking-strategies/) 5. [Günther et al. — Late Chunking: Contextual Chunk Embeddings (2024)](https://arxiv.org/abs/2409.04701) 6. [Docling — документация](https://docling-project.github.io/docling/) --- # Агенты для кода > ИИ-агенты, которые самостоятельно читают репозиторий, редактируют файлы, запускают команды и тесты — Claude Code, Codex, Cursor, Aider и другие. Источник: https://llmdocs.ru/wiki/coding-agents/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: ИИ-агент с инструментами файловой системы и терминала - **Формы**: CLI в терминале, плагин IDE, облачный агент, бот в репозитории - **Примеры**: Claude Code, OpenAI Codex, Gemini CLI, Cursor, GitHub Copilot agent, Aider, Cline - **Ключевые инструменты**: чтение и правка файлов, поиск, shell, тесты, git - **Бенчмарки**: SWE-bench Verified, Terminal-Bench - **Файлы инструкций**: AGENTS.md, CLAUDE.md **Агенты для кода** (англ. *coding agents*) — разновидность [ИИ-агентов](https://llmdocs.ru/wiki/ai-agent.md), которые выполняют задачи программирования самостоятельно: изучают структуру репозитория, ищут нужные места, правят файлы, запускают сборку и тесты, читают ошибки и исправляют их, пока задача не будет решена. В отличие от автодополнения, которое предлагает следующую строку, агент получает цель на естественном языке («добавь эндпоинт и тесты к нему», «почему падает CI?») и работает в цикле, используя инструменты. К 2025–2026 годам агенты стали массовым инструментом разработки.[1] ## История Первая волна ИИ-помощников (GitHub Copilot, 2021) сводилась к автодополнению. В 2023 году появились чаты в редакторе и первые экспериментальные агенты; бенчмарк SWE-bench — исправление реальных задач из GitHub-репозиториев Python-проектов — дал общую мерку.[5] Исследовательский агент SWE-agent (2024) показал, что важен не только интеллект модели, но и удобный для неё интерфейс к компьютеру.[6] В 2025 году вышли терминальные агенты Claude Code, OpenAI Codex CLI и Gemini CLI, агентные режимы появились в Cursor, Windsurf и Copilot, а доля решённых задач SWE-bench Verified у лучших систем превысила 70%. ## Как устроены Основа — [языковая модель](https://llmdocs.ru/wiki/llm.md), умеющая [вызывать инструменты](https://llmdocs.ru/wiki/tool-use.md), и цикл «подумать → вызвать инструмент → прочитать результат». Типичный набор инструментов: | Инструмент | Зачем | |---|---| | чтение файлов, поиск (`grep`, `glob`) | найти нужный код, не загружая весь репозиторий | | правка файлов (точечная замена, запись) | изменить код | | терминал | сборка, тесты, линтеры, [Git](https://llmdocs.ru/wiki/git.md), утилиты | | веб-поиск и загрузка страниц | документация библиотек | | подагенты | параллельные или изолированные подзадачи | | внешние инструменты через [MCP](https://llmdocs.ru/wiki/mcp.md) | трекер задач, базы данных, браузер | Главное ограничение — [контекстное окно](https://llmdocs.ru/wiki/context-window.md): репозиторий не помещается целиком, поэтому агент сам решает, что прочитать. Длинные сессии сжимаются автоматическим пересказом истории. ## Формы - **Терминальные** (Claude Code, Codex CLI, Gemini CLI, Aider) — работают в каталоге проекта, легко встраиваются в скрипты и [CI/CD](https://llmdocs.ru/wiki/ci-cd.md).[7] - **В редакторе** (Cursor, Windsurf, Copilot, Cline) — показывают правки как diff прямо в IDE. - **Облачные** — агент получает задачу из трекера или [pull request](https://llmdocs.ru/wiki/pull-request.md), работает в изолированной среде и возвращает готовый PR.[3] ## Инструкции проекту Агенты читают файл с правилами проекта в корне репозитория — `CLAUDE.md`, `AGENTS.md` (открытый формат, поддерживаемый многими инструментами) и аналоги: как собрать и протестировать проект, стиль кода, что нельзя трогать.[4] Это частный случай подготовки [документации для ИИ](https://llmdocs.ru/wiki/docs-for-ai.md). ```markdown # AGENTS.md ## Сборка и тесты - `uv run pytest -q` — тесты; перед коммитом должны проходить - `uv run ruff check --fix` — линтер ## Правила - Python 3.12, типы обязательны - Не менять файлы в migrations/ вручную ``` ## Практика работы Рекомендации разработчиков агентов:[2] - **Давать проверяемую цель.** Агент работает лучше всего, когда может сам убедиться в результате: тесты, линтер, скриншот, ожидаемый вывод. - **Сначала план.** Для больших задач — попросить исследовать код и предложить план, утвердить его, затем реализовывать. - **Маленькие шаги и коммиты.** Проще ревьюить и откатывать. - **Чистый контекст.** Разные задачи — в разных сессиях; длинная история с тупиковыми попытками ухудшает качество. - **Ревью обязательно.** Агент может написать работающий, но избыточный или небезопасный код, «подогнать» тесты под результат или удалить неудобную проверку. ## Безопасность Агент выполняет команды с правами пользователя, поэтому инструменты предлагают режимы разрешений (подтверждение каждой команды, разрешённые списки, песочницы и контейнеры). Особый риск — [prompt injection](https://llmdocs.ru/wiki/prompt-injection.md): инструкция, спрятанная в файле, задаче или веб-странице, может заставить агента выполнить вредное действие или отправить секреты наружу. Не стоит давать агенту доступ к продакшен-секретам и запускать его без изоляции на недоверенном коде. Отдельная угроза — [выдуманные](https://llmdocs.ru/wiki/hallucinations.md) имена пакетов, которые злоумышленники регистрируют в реестрах. ## Влияние Агенты резко ускоряют рутину — шаблонный код, миграции, тесты, исправление очевидных ошибок, работу с незнакомыми кодовыми базами — и позволяют непрограммистам собирать прототипы («вайб-кодинг»). Измерения продуктивности опытных разработчиков на сложных задачах дают противоречивые результаты; сильнее всего выигрыш там, где результат легко проверить. ## См. также - [ИИ-агент](https://llmdocs.ru/wiki/ai-agent.md) - [Tool use / function calling](https://llmdocs.ru/wiki/tool-use.md) - [Model Context Protocol (MCP)](https://llmdocs.ru/wiki/mcp.md) - [Документация для ИИ: как подготовить](https://llmdocs.ru/wiki/docs-for-ai.md) - [Безопасность LLM: prompt injection](https://llmdocs.ru/wiki/prompt-injection.md) ## Источники 1. [Anthropic — Claude Code documentation](https://docs.claude.com/en/docs/claude-code/overview) 2. [Anthropic — Claude Code: Best practices for agentic coding](https://www.anthropic.com/engineering/claude-code-best-practices) 3. [OpenAI — Codex](https://developers.openai.com/codex) 4. [AGENTS.md — открытый формат инструкций для агентов](https://agents.md/) 5. [Jimenez et al. — SWE-bench (2023)](https://arxiv.org/abs/2310.06770) 6. [Yang et al. — SWE-agent: Agent-Computer Interfaces (2024)](https://arxiv.org/abs/2405.15793) 7. [Aider — документация](https://aider.chat/docs/) --- # Контекстное окно > Максимальный объём текста в токенах, который языковая модель учитывает за один запрос — инструкции, история диалога, документы и ответ вместе. Источник: https://llmdocs.ru/wiki/context-window/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Единица измерения**: токены - **Что входит**: системный промпт, история диалога, документы, результаты инструментов, ответ модели - **Ранние модели**: GPT-3 — 2048 токенов (2020) - **Современные модели**: от 128 тыс. до 1 млн токенов и больше - **Ограничивающий фактор**: квадратичная сложность внимания, память KV-кэша - **Связанные эффекты**: «потеря в середине», рост стоимости и задержки **Контекстное окно** — максимальный объём текста, измеряемый в [токенах](https://llmdocs.ru/wiki/tokenization.md), который [языковая модель](https://llmdocs.ru/wiki/llm.md) может учитывать при обработке одного запроса. В окно входит всё сразу: системные инструкции, история диалога, приложенные документы, описания инструментов и результаты их вызовов, а также ответ, который модель генерирует. Всё, что за пределами окна, для модели не существует: у неё нет памяти между запросами, кроме того, что передано в контексте.[2] ## Как менялся размер | Период | Типичный размер окна | |---|---| | 2020 (GPT-3) | 2 048 токенов[4] | | 2023 | 8–32 тыс., затем 100–200 тыс. токенов | | 2024–2026 | от 128 тыс. до 1 млн токенов и больше | Для ориентира: тысяча токенов — это примерно 750 английских слов или заметно меньше русских; 200 тысяч токенов вмещают несколько книг или средний программный проект. Рост окна сделал возможным анализ целых кодовых баз, длинных договоров и многочасовых транскриптов без нарезки. ## Почему окно ограничено Механизм внимания в [трансформере](https://llmdocs.ru/wiki/transformer.md) сравнивает каждый токен с каждым, поэтому вычисления растут квадратично с длиной входа. Кроме того, при генерации модель хранит ключи и значения всех предыдущих токенов (KV-кэш), и его объём растёт линейно, занимая память GPU. Модели также нужно уметь работать с позициями, которых не было при обучении: для расширения окна применяют масштабирование позиционных кодировок (например, YaRN) и дообучение на длинных текстах.[3] ## Заявленный и эффективный контекст То, что текст помещается в окно, не значит, что модель одинаково хорошо использует все его части. - **Потеря в середине.** Исследование 2023 года показало, что модели лучше всего извлекают информацию из начала и конца длинного контекста и хуже — из середины.[1] Новые модели заметно улучшили этот показатель, но эффект полностью не исчез. - **«Иголка в стоге сена».** Популярный тест — спрятать факт в длинный текст и попросить его найти. Простой поиск современные модели проходят почти идеально, но задачи, требующие сопоставить много фактов из разных мест, даются заметно хуже; бенчмарки вроде RULER оценивают «реальный» размер контекста.[6] - **Отвлечение.** Нерелевантный текст в контексте может ухудшать ответы, поэтому «положить всё» не всегда лучше, чем отобрать нужное. ## Стоимость и задержка Входные токены оплачиваются при каждом запросе. В многошаговом диалоге или работе [агента](https://llmdocs.ru/wiki/ai-agent.md) вся история отправляется заново на каждом шаге, поэтому стоимость растёт быстро. Длинный контекст увеличивает и время до первого токена ответа. Повторяющуюся часть запроса — системный промпт, документацию, описание инструментов — выгодно кэшировать на стороне провайдера: это снижает цену и задержку (см. [Кэширование промптов](https://llmdocs.ru/wiki/prompt-caching.md)).[5] ## Управление контекстом Длинный контекст не отменяет необходимости им управлять: 1. **Отбор вместо загрузки всего.** [RAG](https://llmdocs.ru/wiki/rag.md) находит и подставляет только релевантные фрагменты; документы при этом режут на части (см. [Чанкинг документов](https://llmdocs.ru/wiki/chunking.md)). 2. **Сжатие истории.** Старые сообщения диалога заменяются кратким пересказом, а длинные результаты инструментов — выжимкой. 3. **Структура.** Важные инструкции размещают в начале или повторяют в конце, документы оборачивают в явные разделители или теги. 4. **Компактные форматы.** Чистый [Markdown](https://llmdocs.ru/wiki/markdown.md) вместо HTML, удаление повторов и служебного текста экономит токены (см. [Markdown как формат для LLM](https://llmdocs.ru/wiki/markdown-for-llm.md) и [llms.txt](https://llmdocs.ru/wiki/llms-txt.md)). 5. **Внешняя память.** Агенты сохраняют заметки и промежуточные результаты в файлы или базы и подгружают по необходимости, вместо того чтобы держать всё в окне. ## Окно и длина ответа У многих моделей отдельно ограничено число токенов в ответе (`max_tokens`): оно меньше общего окна, а сумма входа и выхода не может превышать окно. Если ответ упирается в лимит, генерация обрывается на полуслове — это стоит проверять в коде по признаку причины остановки, а не только по тексту ответа. ```python resp = client.messages.create(model="claude-sonnet-5-5", max_tokens=2048, messages=msgs) if resp.stop_reason == "max_tokens": print("Ответ обрезан — увеличьте max_tokens или попросите продолжить") print(resp.usage.input_tokens, resp.usage.output_tokens) ``` ## См. также - [Токен и токенизация](https://llmdocs.ru/wiki/tokenization.md) - [Кэширование промптов](https://llmdocs.ru/wiki/prompt-caching.md) - [RAG (генерация с дополнением поиском)](https://llmdocs.ru/wiki/rag.md) - [Чанкинг документов](https://llmdocs.ru/wiki/chunking.md) - [Большая языковая модель (LLM)](https://llmdocs.ru/wiki/llm.md) ## Источники 1. [N. F. Liu et al. — Lost in the Middle: How Language Models Use Long Contexts (2023)](https://arxiv.org/abs/2307.03172) 2. [Anthropic — Context windows](https://docs.anthropic.com/en/docs/build-with-claude/context-windows) 3. [B. Peng et al. — YaRN: Efficient Context Window Extension of Large Language Models (2023)](https://arxiv.org/abs/2309.00071) 4. [T. Brown et al. — Language Models are Few-Shot Learners (2020)](https://arxiv.org/abs/2005.14165) 5. [Anthropic — Prompt caching](https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching) 6. [C.-P. Hsieh et al. — RULER: What's the Real Context Size of Your Long-Context Language Models? (2024)](https://arxiv.org/abs/2404.06654) --- # Документация для ИИ: как подготовить > Практическое руководство по подготовке технической документации так, чтобы её надёжно понимали языковые модели и агенты — Markdown-версии страниц, llms.txt, структура, примеры и MCP-доступ. Источник: https://llmdocs.ru/wiki/docs-for-ai/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Цель**: документация, которую одинаково хорошо читают люди и языковые модели - **Форматы**: Markdown-копии страниц, llms.txt, llms-full.txt - **Доступ для агентов**: MCP-серверы документации, поиск, API - **Принципы**: самодостаточные разделы, явный контекст, проверяемые примеры, актуальность - **Связанные подходы**: Diátaxis, docs-as-code, RAG **Документация для ИИ** — набор практик, которые делают техническую документацию удобной не только для людей, но и для [языковых моделей](https://llmdocs.ru/wiki/llm.md) и [агентов](https://llmdocs.ru/wiki/ai-agent.md). Всё больше разработчиков узнают, как пользоваться библиотекой или API, не со страницы сайта, а из ответа ассистента или [агента для кода](https://llmdocs.ru/wiki/coding-agents.md), который сам ищет и читает документацию. Если документация плохо доступна моделям, они опираются на устаревшие знания из обучающих данных и чаще ошибаются. Хорошая новость: почти всё, что помогает моделям, помогает и людям — ясная структура, полные примеры, явный контекст. ## Почему модели читают документацию иначе - **Нет навигации и вёрстки.** Модель получает текст страницы — часто вместе с меню, рекламой, скриптами и куками, — и всё это тратит [контекст](https://llmdocs.ru/wiki/context-window.md). - **Фрагменты без окружения.** Системы [RAG](https://llmdocs.ru/wiki/rag.md) режут документы на фрагменты, и фрагмент «Затем вызовите `init()` с этим параметром» без заголовка и соседних абзацев теряет смысл. - **Буквальность.** Модель воспроизведёт пример кода дословно — включая устаревший импорт или пропущенный шаг. - **Знания из обучения.** Модель «помнит» старые версии API и смешивает их с новыми, если документация не говорит явно, что изменилось. ## Форматы для машин ### Markdown-версии страниц Публикуйте рядом с каждой HTML-страницей её чистую версию в [Markdown](https://llmdocs.ru/wiki/markdown.md) — например, по тому же адресу с расширением `.md`. Markdown сохраняет структуру (заголовки, списки, таблицы, код с указанием языка) и при этом в несколько раз компактнее HTML (см. [Markdown как формат для LLM](https://llmdocs.ru/wiki/markdown-for-llm.md)). Генераторы статических сайтов легко выдают обе версии из одного источника ([Статический сайт и генераторы (SSG)](https://llmdocs.ru/wiki/static-site-generators.md)). ### llms.txt Файл [llms.txt](https://llmdocs.ru/wiki/llms-txt.md) в корне сайта — карта документации для моделей: название проекта, краткое описание и список ключевых страниц со ссылками на Markdown-версии и пояснением в одну строку.[1] Часто рядом кладут `llms-full.txt` — всю документацию одним файлом для загрузки в контекст целиком. ```markdown # Acme SDK > Python-библиотека для работы с API платёжного сервиса Acme. ## Документация - [Быстрый старт](https://docs.acme.dev/quickstart.md): установка и первый платёж - [Аутентификация](https://docs.acme.dev/auth.md): ключи API и OAuth - [Ошибки](https://docs.acme.dev/errors.md): коды ошибок и повторы ## Optional - [История изменений](https://docs.acme.dev/changelog.md) ``` ### Доступ для агентов Агенты всё чаще получают документацию не по ссылке, а через инструменты: MCP-сервер документации даёт поиск и чтение страниц по запросу ([Model Context Protocol (MCP)](https://llmdocs.ru/wiki/mcp.md)).[4] Так агент берёт только нужный раздел актуальной версии, не загружая весь сайт. ## Как писать 1. **Самодостаточные разделы.** Каждый раздел должен быть понятен без чтения предыдущих: повторите в начале, о каком продукте и версии идёт речь, а не полагайтесь на «как описано выше». Это напрямую улучшает поиск по фрагментам; та же идея лежит в основе подхода Contextual Retrieval, где к каждому фрагменту добавляется краткий контекст документа.[3] 2. **Описательные заголовки.** «Повтор запросов при ошибке 429» вместо «Дополнительно». Заголовок — главный сигнал для поиска и нарезки на фрагменты ([Чанкинг документов](https://llmdocs.ru/wiki/chunking.md)). 3. **Полные, проверяемые примеры.** Код с импортами, установкой зависимостей и ожидаемым выводом; примеры прогоняются в CI, чтобы не устаревали. 4. **Явные версии и изменения.** Указывайте, с какой версии доступна функция, что устарело и чем заменить. Страница миграции «было → стало» особенно ценна для моделей с устаревшими знаниями. 5. **Однозначные определения.** Термины определяются один раз и используются единообразно; синонимы для одного понятия путают и людей, и модели.[5] 6. **Типы документов не смешиваются.** Разделение на обучающие материалы, практические инструкции, справочник и объяснения (подход Diátaxis) помогает и человеку, и модели найти нужный вид информации.[2] 7. **Ограничения и ошибки.** Пишите, чего библиотека *не* умеет и какие ошибки бывают, — иначе модель додумает. ## Технические детали - Чистый CommonMark с таблицами и блоками кода с указанием языка; без нестандартных расширений, которые превращаются в мусор вне вашего сайта.[6] - Стабильные URL и редиректы со старых адресов — модели и поисковые индексы помнят старые ссылки. - Не закрывайте документацию от ботов без необходимости: проверьте `robots.txt` и защиту от ботов, которые могут блокировать агентов (см. [robots.txt и sitemap](https://llmdocs.ru/wiki/robots-sitemap.md)). - Справочник API — из машиночитаемого описания (OpenAPI), чтобы он не расходился с реальностью. - Дата обновления и версия на каждой странице. ## Как проверить Лучший тест — спросить модель. Подайте ей Markdown-версию раздела или подключите MCP-сервер и попросите решить типичную задачу пользователя: установить библиотеку, сделать первый запрос, обработать ошибку. Ошибки модели показывают, где документация неполна или двусмысленна. Набор таких задач можно запускать регулярно как тесты документации (см. [Оценка LLM (evals)](https://llmdocs.ru/wiki/llm-evals.md)). ## Пример Эта вики устроена по описанным принципам: каждая статья хранится в Markdown с метаданными, сайт публикует HTML и Markdown-копии всех страниц, файлы `llms.txt` и `llms-full.txt`, а статьи написаны как самодостаточные разделы со ссылками на первоисточники. Похожий подход используют справочники [tldr-pages](https://llmdocs.ru/wiki/tldr-pages.md) — короткие страницы единого формата с проверяемыми примерами. ## См. также - [llms.txt](https://llmdocs.ru/wiki/llms-txt.md) - [Markdown как формат для LLM](https://llmdocs.ru/wiki/markdown-for-llm.md) - [RAG (генерация с дополнением поиском)](https://llmdocs.ru/wiki/rag.md) - [Model Context Protocol (MCP)](https://llmdocs.ru/wiki/mcp.md) - [Статический сайт и генераторы (SSG)](https://llmdocs.ru/wiki/static-site-generators.md) ## Источники 1. [llms.txt — предложение стандарта (Jeremy Howard, 2024)](https://llmstxt.org/) 2. [Diátaxis — систематический подход к технической документации](https://diataxis.fr/) 3. [Anthropic — Introducing Contextual Retrieval (2024)](https://www.anthropic.com/news/contextual-retrieval) 4. [Model Context Protocol — Specification](https://modelcontextprotocol.io/specification) 5. [Google developer documentation style guide](https://developers.google.com/style) 6. [CommonMark Spec](https://spec.commonmark.org/) --- # Fine-tuning и LoRA > Дообучение готовой модели на своих данных — полное или параметро-эффективное через низкоранговые адаптеры LoRA и QLoRA; когда оно нужно и когда хватает промптов и RAG. Источник: https://llmdocs.ru/wiki/fine-tuning-lora/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Виды**: полное дообучение, PEFT (LoRA, QLoRA, адаптеры), дообучение по предпочтениям - **LoRA**: Hu et al., Microsoft, 2021 - **QLoRA**: Dettmers et al., 2023 - **Этапы для LLM**: SFT → выравнивание по предпочтениям (RLHF, DPO) - **Инструменты**: Hugging Face PEFT и TRL, Unsloth, Axolotl, LLaMA-Factory, torchtune **Fine-tuning** (дообучение, файнтюнинг) — продолжение обучения уже готовой, предобученной модели на небольшом наборе своих данных, чтобы адаптировать её к задаче, стилю или формату ответов. **LoRA** (*Low-Rank Adaptation*) — самый популярный способ сделать это дёшево: вместо изменения всех миллиардов весов обучаются небольшие добавочные матрицы, составляющие доли процента от размера модели. Благодаря LoRA и её квантованному варианту QLoRA дообучить [большую языковую модель](https://llmdocs.ru/wiki/llm.md) можно на одной видеокарте.[1] ## Когда дообучать Дообучение — не первый инструмент. Сначала пробуют: 1. **[Промпт-инжиниринг](https://llmdocs.ru/wiki/prompt-engineering.md)** — инструкции и примеры в промпте. 2. **[RAG](https://llmdocs.ru/wiki/rag.md)** — если модели не хватает знаний (документации, базы фактов). Дообучение плохо «вкладывает» новые факты и не обновляется так легко, как индекс. 3. **Дообучение** — когда нужно устойчиво менять *поведение*: строгий формат ответа, стиль и тон, узкая классификация, специфический жаргон, или когда нужно заменить большую дорогую модель маленькой и быстрой (дистилляция).[7] ## Виды дообучения - **Полное** — обновляются все веса. Требует памяти под веса, градиенты и состояние оптимизатора — в 3–4 раза больше самой модели; для моделей в десятки миллиардов параметров нужен кластер. - **Параметро-эффективное** (PEFT) — замораживается основная модель, обучается малая добавка: LoRA, адаптеры, prefix tuning.[4] - **Инструктивное дообучение** (SFT, supervised fine-tuning) — на парах «запрос → желаемый ответ»; см. [Обучение с учителем и без](https://llmdocs.ru/wiki/supervised-unsupervised.md). - **Выравнивание по предпочтениям** — модель учится выбирать лучший из двух ответов: RLHF с моделью вознаграждения или более простой **DPO**, обучающийся прямо на парах «лучше / хуже».[3] ## Как работает LoRA Обновление матрицы весов $W$ размером $d \times k$ представляется произведением двух узких матриц: $W' = W + \frac{\alpha}{r} BA$, где $B$ имеет размер $d \times r$, $A$ — $r \times k$, а ранг $r$ мал (4–64). Исходные веса заморожены, обучаются только $A$ и $B$. Для слоя 4096×4096 это 65 тысяч параметров при $r=8$ вместо 16,7 миллиона.[1] Преимущества: - память и время обучения сокращаются в разы, состояние оптимизатора крошечное; - адаптер весит мегабайты — можно хранить много адаптеров для одной базовой модели и переключать их на лету (инференс-серверы вроде [vLLM](https://llmdocs.ru/wiki/vllm.md) обслуживают сотни адаптеров одновременно); - адаптер можно «влить» в веса, и тогда инференс не замедляется. **QLoRA** хранит замороженную базовую модель в 4-битном формате NF4 (см. [Квантизация моделей](https://llmdocs.ru/wiki/quantization.md)), а адаптеры обучает в 16 битах; так модель на 65 млрд параметров дообучили на одном GPU с 48 ГБ.[2] ```python from peft import LoraConfig from trl import SFTConfig, SFTTrainer peft_cfg = LoraConfig(r=16, lora_alpha=32, lora_dropout=0.05, target_modules="all-linear", task_type="CAUSAL_LM") trainer = SFTTrainer( model="Qwen/Qwen3-4B", train_dataset=dataset, # колонка messages в формате чата peft_config=peft_cfg, args=SFTConfig(output_dir="out", num_train_epochs=2, learning_rate=2e-4), ) trainer.train() ``` Библиотеки [Hugging Face](https://llmdocs.ru/wiki/hugging-face.md) PEFT и TRL — стандарт; Unsloth ускоряет обучение на одной карте, Axolotl и LLaMA-Factory позволяют описать всё конфигом.[5] ## Данные Качество данных важнее их количества: несколько сотен — пара тысяч чистых, разнообразных и согласованных примеров часто дают больше, чем десятки тысяч шумных. Примеры должны быть в том же формате чата, что и при использовании, включая системный промпт. Обязательно отложить часть данных для проверки и сравнивать дообученную модель с исходной на своих задачах (см. [Оценка LLM (evals)](https://llmdocs.ru/wiki/llm-evals.md)). ## Риски - **[Переобучение](https://llmdocs.ru/wiki/overfitting-regularization.md)** — модель заучивает примеры; помогают 1–3 эпохи и малый темп обучения. - **Катастрофическое забывание** — потеря общих навыков. LoRA забывает меньше полного дообучения, но и усваивает меньше нового.[6] - **Ослабление защитных механизмов** — даже безобидное дообучение может снизить отказ от вредных запросов. - **Лицензия** базовой модели определяет, можно ли распространять результат. ## См. также - [Квантизация моделей](https://llmdocs.ru/wiki/quantization.md) - [Hugging Face](https://llmdocs.ru/wiki/hugging-face.md) - [RAG (генерация с дополнением поиском)](https://llmdocs.ru/wiki/rag.md) - [Промпт-инжиниринг](https://llmdocs.ru/wiki/prompt-engineering.md) - [Оценка LLM (evals)](https://llmdocs.ru/wiki/llm-evals.md) ## Источники 1. [Hu et al. — LoRA: Low-Rank Adaptation of Large Language Models (2021)](https://arxiv.org/abs/2106.09685) 2. [Dettmers et al. — QLoRA: Efficient Finetuning of Quantized LLMs (2023)](https://arxiv.org/abs/2305.14314) 3. [Rafailov et al. — Direct Preference Optimization (2023)](https://arxiv.org/abs/2305.18290) 4. [Hugging Face — PEFT](https://huggingface.co/docs/peft/index) 5. [Hugging Face — TRL](https://huggingface.co/docs/trl/index) 6. [Biderman et al. — LoRA Learns Less and Forgets Less (2024)](https://arxiv.org/abs/2405.09673) 7. [OpenAI — Fine-tuning best practices](https://platform.openai.com/docs/guides/fine-tuning-best-practices) --- # GGUF > Формат файлов для квантизованных языковых моделей экосистемы llama.cpp — веса, токенизатор и метаданные в одном файле; используется Ollama, LM Studio и другими. Источник: https://llmdocs.ru/wiki/gguf/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Полное название**: GPT-Generated Unified Format (по распространённой версии) - **Появление**: август 2023 - **Предшественник**: GGML, GGJT - **Проект**: llama.cpp / ggml (Георгий Герганов) - **Содержимое**: тензоры, токенизатор, шаблон чата, гиперпараметры - **Типы квантизации**: F16, Q8_0, Q6_K, Q5_K_M, Q4_K_M, IQ-кванты - **Используют**: llama.cpp, Ollama, LM Studio, GPT4All, koboldcpp **GGUF** — бинарный формат файлов для хранения языковых моделей, созданный в проекте llama.cpp. Один файл `.gguf` содержит всё необходимое для запуска: веса (обычно [квантизованные](https://llmdocs.ru/wiki/quantization.md)), словарь и правила [токенизатора](https://llmdocs.ru/wiki/tokenization.md), шаблон чата и параметры архитектуры. Благодаря этому GGUF стал стандартом де-факто для [локального запуска моделей](https://llmdocs.ru/wiki/local-llm.md) на ноутбуках, компьютерах Mac с Apple Silicon и потребительских видеокартах. ## История Георгий Герганов в марте 2023 года выпустил llama.cpp — реализацию модели LLaMA на чистом C/C++ поверх своей тензорной библиотеки **ggml**. Первые форматы файлов (GGML, затем GGJT) хранили мало метаданных, и каждое изменение ломало совместимость. В августе 2023 года их заменил **GGUF** — расширяемый формат, в который можно добавлять новые поля без поломки старых программ.[1] Сегодня на [Hugging Face](https://llmdocs.ru/wiki/hugging-face.md) размещены десятки тысяч моделей в GGUF, а Hub умеет показывать их метаданные и тензоры прямо в браузере.[4] ## Устройство файла Файл состоит из трёх частей:[1] 1. **Заголовок** — магическое число `GGUF`, версия формата, количество тензоров и метаданных. 2. **Метаданные** — пары «ключ — значение» с типами: `general.architecture = llama`, `llama.context_length`, `tokenizer.ggml.tokens`, `tokenizer.chat_template` и т. д. 3. **Описание и данные тензоров** — имена, формы, тип квантизации и смещения; данные выровнены, чтобы файл можно было **отобразить в память** (mmap) и начать работу без полного чтения. Поскольку токенизатор и шаблон чата хранятся внутри, модель запускается одним файлом без конфигураций из исходного репозитория. ## Квантизация GGUF поддерживает множество способов сжатия весов. Названия кодируют число бит и вариант:[3] | Тип | Бит на вес (≈) | Размер модели 8B | Качество | |---|---|---|---| | F16 / BF16 | 16 | ~16 ГБ | исходное | | Q8_0 | 8,5 | ~8,5 ГБ | практически без потерь | | Q6_K | 6,6 | ~6,6 ГБ | очень близко к исходному | | Q5_K_M | 5,7 | ~5,7 ГБ | хороший баланс | | Q4_K_M | 4,8 | ~4,9 ГБ | самый популярный выбор | | Q3_K_M | 3,9 | ~4 ГБ | заметная деградация | | IQ2_XS | 2,3 | ~2,5 ГБ | только для очень больших моделей | **K-кванты** (`_K`) группируют веса в блоки с собственными масштабами и разной точностью для разных слоёв (суффиксы `S`, `M`, `L` — меньше или больше бит на важные тензоры). **IQ-кванты** используют более сложные кодовые книги и дают лучшее качество при 2–3 битах. Для низкобитных вариантов применяют **матрицу важности** (imatrix), рассчитанную на калибровочном тексте. Практическое правило: из двух моделей при одинаковом объёме памяти обычно лучше бо́льшая модель с Q4, чем меньшая с Q8. Оценить качество можно по перплексии (`llama-perplexity`) и на собственных задачах. ## Конвертация ```bash git clone https://github.com/ggml-org/llama.cpp && cd llama.cpp pip install -r requirements.txt # из формата Hugging Face в GGUF F16 python convert_hf_to_gguf.py ../Qwen2.5-7B-Instruct --outfile qwen-f16.gguf # квантизация ./build/bin/llama-quantize qwen-f16.gguf qwen-Q4_K_M.gguf Q4_K_M ``` Готовые квантизованные файлы для популярных моделей обычно уже лежат на Hugging Face — их публикуют сами авторы моделей и энтузиасты.[2] ## Запуск ```bash # llama.cpp: консоль или сервер с OpenAI-совместимым API llama-cli -m qwen-Q4_K_M.gguf -p "Привет" llama-server -m qwen-Q4_K_M.gguf -c 8192 -ngl 99 # -ngl: слои на GPU # Ollama: прямо с Hugging Face ollama run hf.co/Qwen/Qwen2.5-7B-Instruct-GGUF:Q4_K_M ``` Параметр `-ngl` (число слоёв на GPU) позволяет частично выгрузить модель в видеопамять, а остальное оставить в оперативной памяти — так большие модели работают даже на скромных видеокартах. В Ollama собственный GGUF подключается через Modelfile со строкой `FROM ./model.gguf`.[5] ## GGUF и другие форматы | Формат | Для чего | |---|---| | **GGUF** | локальный запуск, CPU и смешанный CPU+GPU, Apple Silicon | | **safetensors** | исходные веса на Hugging Face, обучение, серверные движки | | **AWQ, GPTQ, FP8** | квантизованные веса для серверных GPU в [vLLM](https://llmdocs.ru/wiki/vllm.md) и подобных | | **[ONNX](https://llmdocs.ru/wiki/onnx.md)** | кроссплатформенный инференс небольших моделей | | **MLX** | оптимизированный запуск на Apple Silicon через фреймворк Apple | vLLM умеет загружать GGUF, но для высокой нагрузки на серверных GPU эффективнее родные форматы. GGUF силён там, где важны простота — один файл — и работа на обычном железе. ## См. также - [Локальный запуск LLM (llama.cpp, Ollama)](https://llmdocs.ru/wiki/local-llm.md) - [Квантизация моделей](https://llmdocs.ru/wiki/quantization.md) - [vLLM и инференс-серверы](https://llmdocs.ru/wiki/vllm.md) - [Hugging Face](https://llmdocs.ru/wiki/hugging-face.md) ## Источники 1. [ggml — GGUF specification](https://github.com/ggml-org/ggml/blob/master/docs/gguf.md) 2. [llama.cpp — репозиторий](https://github.com/ggml-org/llama.cpp) 3. [llama.cpp — quantize tool README](https://github.com/ggml-org/llama.cpp/blob/master/tools/quantize/README.md) 4. [Hugging Face Docs — GGUF](https://huggingface.co/docs/hub/gguf) 5. [Ollama — Importing a model (Modelfile)](https://github.com/ollama/ollama/blob/main/docs/import.md) --- # Галлюцинации LLM > Склонность языковых моделей уверенно выдавать правдоподобную, но неверную или выдуманную информацию; причины, виды и способы снижения. Источник: https://llmdocs.ru/wiki/hallucinations/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Суть**: правдоподобный, но не подкреплённый данными или ложный ответ - **Виды**: фактические, по отношению к контексту (faithfulness), выдуманные ссылки и API - **Основные причины**: обучение предсказанию текста, поощрение угадывания, пробелы в знаниях - **Способы снижения**: RAG, цитирование, право сказать «не знаю», проверка, evals - **Бенчмарки**: TruthfulQA, SimpleQA, HaluEval, FACTS Grounding **Галлюцинации** языковых моделей (англ. *hallucinations*) — ответы [LLM](https://llmdocs.ru/wiki/llm.md), которые звучат уверенно и правдоподобно, но содержат неверные или выдуманные сведения: несуществующие статьи и законы, ошибочные даты, вымышленные функции библиотек, искажённое содержание переданного документа. Термин условный — модель не «видит» несуществующее, а порождает статистически правдоподобный текст; некоторые исследователи предпочитают слово «конфабуляция». Галлюцинации — главная причина, по которой ответы моделей требуют проверки в ответственных применениях.[1] ## Виды - **Фактические** — противоречат реальному миру: неверная столица, выдуманная биография, несуществующий судебный прецедент. - **По отношению к контексту** (нарушение *faithfulness*) — модель искажает или дополняет документ, который ей передали: в пересказе появляются цифры, которых не было в источнике. Для [RAG](https://llmdocs.ru/wiki/rag.md)-систем это основная проблема. - **Выдуманные ссылки** — правдоподобные, но несуществующие URL, DOI, цитаты. - **В коде** — вызовы несуществующих функций и параметров, импорт несуществующих пакетов. Последнее стало вектором атаки: злоумышленники регистрируют в реестрах пакеты с часто «галлюцинируемыми» именами (*slopsquatting*).[6] - **Логические** — неверные шаги рассуждения при верных исходных данных. ## Почему возникают 1. **Цель обучения.** Модель предобучается предсказывать следующий [токен](https://llmdocs.ru/wiki/tokenization.md); у неё нет встроенного механизма отличить «знаю» от «звучит похоже». Редкие факты, встречавшиеся в обучающих данных один-два раза, воспроизводятся особенно ненадёжно. 2. **Поощрение угадывания.** Бенчмарки и обучение по оценкам обычно дают ноль баллов и за неверный ответ, и за «не знаю» — модели выгоднее угадывать, как студенту на тесте без штрафа за ошибку. Исследователи OpenAI в 2025 году показали, что галлюцинации — статистически ожидаемое следствие такой постановки, и предложили менять системы оценки.[2] 3. **Устаревшие и неполные знания.** У модели есть дата среза знаний; о более поздних событиях она может «досочинить». 4. **Давление промпта.** Вопрос с ложной предпосылкой («Почему Эйнштейн получил вторую Нобелевскую премию?») подталкивает к выдуманному ответу. Модели также склонны повторять распространённые заблуждения — это измеряет бенчмарк TruthfulQA.[3] 5. **Длинный контекст.** Факты в середине большого [контекстного окна](https://llmdocs.ru/wiki/context-window.md) извлекаются хуже. ## Как снижать ### Опора на источники - **RAG** — подставлять в контекст найденные документы и требовать отвечать только по ним.[4] Качество зависит от поиска: если нужного фрагмента нет, модель всё равно может ответить «из головы» (см. [Чанкинг документов](https://llmdocs.ru/wiki/chunking.md)). - **Цитирование** — просить указывать, из какого фрагмента взято каждое утверждение; утверждения без цитаты легко отфильтровать или проверить. - **Инструменты** — для расчётов, дат и актуальных данных давать модели калькулятор, поиск, базу данных (см. [Tool use / function calling](https://llmdocs.ru/wiki/tool-use.md)). ### Промпт и формат - Явно разрешить ответ «не знаю» или «в документе этого нет».[5] - Просить сначала выписать дословные цитаты из документа, затем отвечать на их основе. - В [структурированном выводе](https://llmdocs.ru/wiki/structured-output.md) предусматривать `null` для отсутствующих полей. - Снижать температуру для фактологических задач. ### Проверка - **Самопроверка** — повторная генерация нескольких ответов: расхождение между ними сигнализирует о неуверенности. - **Модель-проверяющий** — отдельный вызов проверяет, подтверждается ли каждое утверждение источником. - **Автоматические проверки** — существование ссылок, пакетов и функций, компиляция и тесты для кода. - **Измерение** — набор вопросов с известными ответами и метрики доли галлюцинаций, см. [Оценка LLM (evals)](https://llmdocs.ru/wiki/llm-evals.md). ## Можно ли устранить полностью Нет: в вероятностной генерации всегда остаётся ненулевая доля ошибок. Новые модели галлюцинируют заметно реже, особенно в режиме рассуждений и с поиском, но в медицине, праве и финансах ответы по-прежнему нужно проверять. Хорошая документация, доступная модели в чистом виде ([Документация для ИИ: как подготовить](https://llmdocs.ru/wiki/docs-for-ai.md)), — один из самых дешёвых способов сократить выдумки о конкретном продукте или API. ## См. также - [RAG (генерация с дополнением поиском)](https://llmdocs.ru/wiki/rag.md) - [Оценка LLM (evals)](https://llmdocs.ru/wiki/llm-evals.md) - [Промпт-инжиниринг](https://llmdocs.ru/wiki/prompt-engineering.md) - [Безопасность LLM: prompt injection](https://llmdocs.ru/wiki/prompt-injection.md) - [Документация для ИИ: как подготовить](https://llmdocs.ru/wiki/docs-for-ai.md) ## Источники 1. [Ji et al. — Survey of Hallucination in Natural Language Generation (2022)](https://arxiv.org/abs/2202.03629) 2. [Kalai et al. — Why Language Models Hallucinate (OpenAI, 2025)](https://arxiv.org/abs/2509.04664) 3. [Lin et al. — TruthfulQA: Measuring How Models Mimic Human Falsehoods (2021)](https://arxiv.org/abs/2109.07958) 4. [Lewis et al. — Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks (2020)](https://arxiv.org/abs/2005.11401) 5. [Anthropic — Reduce hallucinations](https://docs.claude.com/en/docs/test-and-evaluate/strengthen-guardrails/reduce-hallucinations) 6. [Spracklen et al. — We Have a Package for You! Package Hallucinations by Code LLMs (2024)](https://arxiv.org/abs/2406.10279) --- # Оценка LLM (evals) > Методы измерения качества языковых моделей и LLM-приложений — бенчмарки, собственные наборы тестов, автоматические проверки, модель-судья и оценка людьми. Источник: https://llmdocs.ru/wiki/llm-evals/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Уровни**: оценка модели (бенчмарки) и оценка приложения (свои тесты) - **Способы проверки**: точное совпадение, код и правила, модель-судья, люди - **Публичные бенчмарки**: MMLU, GPQA, SWE-bench, HumanEval, Chatbot Arena - **Инструменты**: OpenAI Evals, Inspect, promptfoo, DeepEval, Ragas, lm-evaluation-harness - **Связанная практика**: регрессионное тестирование промптов в CI **Оценка LLM**, или **evals** (от *evaluations*), — систематическое измерение качества [языковых моделей](https://llmdocs.ru/wiki/llm.md) и построенных на них приложений. Различают два уровня: **оценку моделей** на публичных бенчмарках (насколько модель умна в целом) и **оценку приложения** на собственном наборе задач (насколько хорошо *ваша* система решает *вашу* задачу). Второе важнее на практике: без своих тестов любое изменение промпта, модели или поиска — это гадание, а [галлюцинации](https://llmdocs.ru/wiki/hallucinations.md) и регрессии обнаруживают пользователи.[4] ## Публичные бенчмарки | Бенчмарк | Что измеряет | |---|---| | MMLU, MMLU-Pro | знания по десяткам предметов, вопросы с вариантами | | GPQA | сложные научные вопросы уровня аспирантуры | | HumanEval, LiveCodeBench | генерация кода по описанию | | SWE-bench Verified | исправление реальных задач из GitHub-репозиториев[6] | | AIME, MATH | математика | | Chatbot Arena (LMArena) | слепые попарные сравнения ответов людьми, рейтинг Эло[1] | Ограничения бенчмарков: **загрязнение** (тестовые вопросы попадают в обучающие данные), **насыщение** (лучшие модели набирают почти максимум, и различия теряются), **несоответствие** реальным задачам. Высокий балл на MMLU не гарантирует хорошей работы с вашей документацией на русском языке. Для запуска стандартных бенчмарков на своих моделях используют lm-evaluation-harness и Inspect.[2][3] ## Собственный набор тестов Основа — **набор примеров** (eval set): входы, которые реально приходят в систему, и критерии хорошего ответа. Рекомендации: 1. Начать с 20–50 примеров из реальных логов и известных провалов; расширять по мере появления новых ошибок. 2. Покрыть типичные случаи, крайние случаи и случаи, где правильный ответ — отказ или «не знаю». 3. Сформулировать критерии заранее и измеримо: «ответ содержит номер статьи», «JSON соответствует схеме», «нет фактов вне контекста». 4. Хранить набор в репозитории и прогонять при каждом изменении промпта, модели или параметров — как регрессионные тесты в [CI/CD](https://llmdocs.ru/wiki/ci-cd.md). ## Способы проверки - **Точное совпадение и правила** — для классификации, извлечения полей, [структурированного вывода](https://llmdocs.ru/wiki/structured-output.md); дёшево и надёжно. Метрики — как в [классическом ML](https://llmdocs.ru/wiki/classification-metrics.md). - **Исполнение кода** — сгенерированный код запускается против тестов. - **Модель-судья** (LLM-as-a-judge) — другая модель оценивает ответ по рубрике или сравнивает два ответа. Хорошо согласуется с людьми в среднем, но имеет перекосы: предпочитает длинные ответы, ответы на первой позиции и ответы собственного семейства.[1] Помогают чёткая рубрика с примерами, бинарные вопросы вместо шкалы 1–10, перестановка порядка и выборочная проверка судьи людьми. - **Оценка людьми** — эталон качества, но дорого; нужна для калибровки автоматических проверок. ```yaml # promptfoo: регрессионные тесты промпта prompts: [file://prompts/answer.txt] providers: [anthropic:messages:claude-sonnet-4-5, openai:gpt-5-mini] tests: - vars: {question: "Какой порт у HTTPS?"} assert: - {type: contains, value: "443"} - vars: {question: "Сколько стоит подписка Pro?"} assert: - {type: llm-rubric, value: "Отвечает, что в документации нет этой информации, и не выдумывает цену"} ``` promptfoo, DeepEval, Inspect и OpenAI Evals позволяют описывать такие наборы декларативно и сравнивать модели в таблице.[5] ## Оценка RAG и агентов Для [RAG](https://llmdocs.ru/wiki/rag.md) оценивают отдельно **поиск** (нашёлся ли нужный фрагмент: recall@k, MRR) и **генерацию** (опирается ли ответ на найденное — faithfulness, отвечает ли он на вопрос — relevance). Библиотека Ragas реализует эти метрики.[7] Раздельная оценка показывает, где проблема: в [чанкинге](https://llmdocs.ru/wiki/chunking.md) и поиске или в промпте. Для [агентов](https://llmdocs.ru/wiki/ai-agent.md) важны доля успешно завершённых задач, число шагов, стоимость и безопасность действий; проверяется итоговое состояние среды, а не только текст. ## В продакшене Онлайн-оценка дополняет офлайн-наборы: явная обратная связь пользователей, косвенные сигналы (переформулировка вопроса, копирование ответа), выборочная проверка логов моделью-судьёй. Трассировку и оценку объединяют платформы вроде [MLflow](https://llmdocs.ru/wiki/mlflow.md), Langfuse и LangSmith. Неудачные случаи из продакшена пополняют eval set — так замыкается цикл улучшений. ## См. также - [Галлюцинации LLM](https://llmdocs.ru/wiki/hallucinations.md) - [Метрики качества классификации](https://llmdocs.ru/wiki/classification-metrics.md) - [Промпт-инжиниринг](https://llmdocs.ru/wiki/prompt-engineering.md) - [RAG (генерация с дополнением поиском)](https://llmdocs.ru/wiki/rag.md) - [MLflow](https://llmdocs.ru/wiki/mlflow.md) ## Источники 1. [Zheng et al. — Judging LLM-as-a-Judge with MT-Bench and Chatbot Arena (2023)](https://arxiv.org/abs/2306.05685) 2. [UK AISI — Inspect](https://inspect.aisi.org.uk/) 3. [EleutherAI — lm-evaluation-harness](https://github.com/EleutherAI/lm-evaluation-harness) 4. [Anthropic — Define success criteria and build evaluations](https://docs.claude.com/en/docs/test-and-evaluate/develop-tests) 5. [promptfoo — документация](https://www.promptfoo.dev/docs/intro/) 6. [Jimenez et al. — SWE-bench (2023)](https://arxiv.org/abs/2310.06770) 7. [Ragas — документация](https://docs.ragas.io/) --- # Большая языковая модель (LLM) > Нейросеть-трансформер с миллиардами параметров, обученная предсказывать следующий токен на огромных объёмах текста; умеет отвечать на вопросы, писать код и выполнять задачи по инструкции. Источник: https://llmdocs.ru/wiki/llm/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Архитектура**: трансформер (обычно только декодер) - **Принцип**: предсказание следующего токена - **Этапы обучения**: предобучение, дообучение на инструкциях, обучение на предпочтениях - **Размер**: от миллиардов до триллионов параметров - **Примеры семейств**: Claude, GPT, Gemini, Llama, Qwen, DeepSeek, Mistral - **Доступ**: через API, в чат-интерфейсах, локально (открытые веса) **Большая языковая модель** (англ. *Large Language Model*, LLM) — [нейронная сеть](https://llmdocs.ru/wiki/neural-network.md) с миллиардами параметров, обученная на огромных объёмах текста предсказывать следующий [токен](https://llmdocs.ru/wiki/tokenization.md). Из этой простой задачи при достаточном масштабе возникают разнообразные способности: модель отвечает на вопросы, пересказывает и переводит тексты, пишет и исправляет код, рассуждает по шагам и выполняет задачи по инструкции на естественном языке. LLM — основа чат-ассистентов, [помощников программиста](https://llmdocs.ru/wiki/coding-agents.md), [ИИ-агентов](https://llmdocs.ru/wiki/ai-agent.md) и систем поиска по документам ([RAG](https://llmdocs.ru/wiki/rag.md)). Почти все современные LLM построены на архитектуре [трансформер](https://llmdocs.ru/wiki/transformer.md).[6] ## История Языковые модели существовали давно — от n-граммных моделей для распознавания речи до рекуррентных сетей. Переломом стал трансформер (2017), позволивший эффективно обучать модели на огромных корпусах. В 2018 году появились BERT и первая GPT. Модель GPT-3 (2020) со 175 миллиардами параметров показала, что большая модель может решать новые задачи по нескольким примерам в запросе, без дообучения.[1] Исследования **законов масштабирования** показали, что качество предсказуемо растёт с размером модели, объёмом данных и вычислений,[2] а работа Chinchilla (2022) уточнила оптимальное соотношение параметров и данных.[3] Широкую известность технологии принёс ChatGPT (ноябрь 2022). В 2023 году вышли Claude, GPT-4, открытые модели Llama, затем Gemini, Mistral, Qwen и DeepSeek. С 2024 года распространились **рассуждающие модели**, которые перед ответом генерируют развёрнутую цепочку размышлений. ## Как обучают 1. **Предобучение.** Модель читает триллионы токенов текста и кода и учится предсказывать следующий токен. Это самый дорогой этап: тысячи [GPU](https://llmdocs.ru/wiki/gpu-cuda.md) работают недели и месяцы. Результат — **базовая модель**, которая хорошо продолжает текст, но плохо следует инструкциям. 2. **Дообучение на инструкциях** (SFT). Модель обучают на примерах диалогов «запрос — хороший ответ». 3. **Обучение на предпочтениях.** Люди или другие модели сравнивают варианты ответов, и модель учится давать предпочтительные: RLHF — обучение с подкреплением на отзывах людей,[4] методы вроде Constitutional AI, где модель оценивает ответы по набору принципов.[5] Обучение с подкреплением на задачах с проверяемым ответом (математика, код) развивает рассуждение. ## Как работает генерация Текст запроса разбивается на токены, модель вычисляет распределение вероятностей следующего токена, выбирает один, добавляет его к входу и повторяет. Выбор регулируется параметрами: **температура** (ниже — предсказуемее, выше — разнообразнее), top-p, ограничение длины. Всё, что модель «видит» в данный момент, — это содержимое её [контекстного окна](https://llmdocs.ru/wiki/context-window.md): системные инструкции, история диалога, документы и результаты инструментов. ## Возможности - Ответы на вопросы, объяснения, пересказ, перевод, редактирование текстов. - Написание, объяснение и исправление кода. - Извлечение данных в заданном формате ([структурированный вывод](https://llmdocs.ru/wiki/structured-output.md)). - Вызов внешних функций и API ([Tool use / function calling](https://llmdocs.ru/wiki/tool-use.md)), в том числе через протокол [MCP](https://llmdocs.ru/wiki/mcp.md). - Работа с изображениями, звуком и документами в [мультимодальных моделях](https://llmdocs.ru/wiki/multimodal-models.md). Поведение модели задаётся текстом запроса — этому посвящён [промпт-инжиниринг](https://llmdocs.ru/wiki/prompt-engineering.md). Для специальных задач модель можно дообучить ([Fine-tuning и LoRA](https://llmdocs.ru/wiki/fine-tuning-lora.md)). ## Ограничения - **Галлюцинации.** Модель может уверенно выдавать правдоподобную, но ложную информацию (см. [Галлюцинации LLM](https://llmdocs.ru/wiki/hallucinations.md)). Снижают риск подача источников в контекст (RAG) и проверка ответов. - **Дата отсечения знаний.** Модель знает о мире только то, что было в обучающих данных; свежие сведения нужно передавать в контексте или через поиск. - **Ограниченный контекст** и рост стоимости с длиной запроса. - **Уязвимость к инструкциям во входных данных** — [prompt injection](https://llmdocs.ru/wiki/prompt-injection.md). - **Недетерминированность.** Один и тот же запрос может давать разные ответы, что важно учитывать при [оценке качества](https://llmdocs.ru/wiki/llm-evals.md). ## Использование ```python import anthropic client = anthropic.Anthropic() # ключ берётся из ANTHROPIC_API_KEY msg = client.messages.create( model="claude-sonnet-5-5", max_tokens=1024, system="Отвечай кратко и по-русски.", messages=[{"role": "user", "content": "Чем TCP отличается от UDP?"}], ) print(msg.content[0].text) ``` Коммерческие модели доступны через API провайдеров с оплатой за токены. Модели с открытыми весами можно запускать на своём оборудовании — см. [Локальный запуск LLM (llama.cpp, Ollama)](https://llmdocs.ru/wiki/local-llm.md) — что важно для приватности и работы без интернета. ## См. также - [Трансформер (архитектура)](https://llmdocs.ru/wiki/transformer.md) - [Токен и токенизация](https://llmdocs.ru/wiki/tokenization.md) - [Контекстное окно](https://llmdocs.ru/wiki/context-window.md) - [Промпт-инжиниринг](https://llmdocs.ru/wiki/prompt-engineering.md) - [ИИ-агент](https://llmdocs.ru/wiki/ai-agent.md) ## Источники 1. [T. Brown et al. — Language Models are Few-Shot Learners (GPT-3, 2020)](https://arxiv.org/abs/2005.14165) 2. [J. Kaplan et al. — Scaling Laws for Neural Language Models (2020)](https://arxiv.org/abs/2001.08361) 3. [J. Hoffmann et al. — Training Compute-Optimal Large Language Models (Chinchilla, 2022)](https://arxiv.org/abs/2203.15556) 4. [L. Ouyang et al. — Training language models to follow instructions with human feedback (2022)](https://arxiv.org/abs/2203.02155) 5. [Y. Bai et al. — Constitutional AI: Harmlessness from AI Feedback (2022)](https://arxiv.org/abs/2212.08073) 6. [A. Vaswani et al. — Attention Is All You Need (2017)](https://arxiv.org/abs/1706.03762) --- # llms.txt > Предложенный в 2024 году формат файла в корне сайта, который даёт языковым моделям краткий обзор сайта и ссылки на Markdown-версии страниц. Источник: https://llmdocs.ru/wiki/llms-txt/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: соглашение о формате файла - **Автор**: Джереми Ховард (Answer.AI) - **Предложен**: сентябрь 2024 - **Формат**: Markdown - **Расположение**: `/llms.txt` в корне сайта - **Статус**: открытое предложение, не стандарт IETF/W3C - **Сайт**: [llmstxt.org](https://llmstxt.org/) **llms.txt** — соглашение о файле `/llms.txt` в корне веб-сайта, который предназначен для [больших языковых моделей](https://llmdocs.ru/wiki/llm.md) и [ИИ-агентов](https://llmdocs.ru/wiki/ai-agent.md). Файл в формате [Markdown](https://llmdocs.ru/wiki/markdown.md) кратко описывает сайт и перечисляет ссылки на самые полезные страницы, желательно на их Markdown-версии. Идея в том, чтобы модель, имеющая ограниченное [контекстное окно](https://llmdocs.ru/wiki/context-window.md), получила сжатую и чистую карту сайта вместо HTML с навигацией, рекламой и скриптами. ## История Формат предложил Джереми Ховард, сооснователь fast.ai и компании Answer.AI, в сентябре 2024 года.[1] Спецификация и инструменты опубликованы в открытом репозитории.[2] Предложение быстро подхватили платформы документации и разработчики библиотек: многие проекты стали автоматически генерировать `llms.txt` и полные текстовые выгрузки документации. Формальным стандартом файл не является, и поддержка со стороны конкретных поисковых систем и ИИ-сервисов не гарантирована. ## Формат Файл — обычный Markdown со строго заданным порядком блоков:[1] 1. Заголовок первого уровня `#` с названием проекта — единственный обязательный элемент. 2. Цитата `>` с кратким описанием. 3. Необязательные абзацы и списки с подробностями (без заголовков). 4. Разделы с заголовками второго уровня `##`, каждый содержит список ссылок в виде `- [название](url): пояснение`. 5. Раздел `## Optional` — ссылки, которые можно пропустить, если контекста не хватает. Пример: ```markdown # llmdocs > Справочник разработчика на русском языке. Каждая статья доступна как Markdown. ## Сети и протоколы - [DNS](https://llmdocs.ru/wiki/dns.md): система доменных имён - [TLS](https://llmdocs.ru/wiki/tls.md): шифрование соединений ## Optional - [Все статьи одним файлом](https://llmdocs.ru/llms-full.txt) ``` ## Сопутствующие соглашения - **Markdown-версии страниц.** Предложение рекомендует отдавать чистый текст каждой страницы по тому же адресу с добавлением `.md` (например, `page.html.md` или `page.md`). - **llms-full.txt** — распространённое неофициальное дополнение: вся документация одним файлом, чтобы загрузить её в контекст целиком или в систему [RAG](https://llmdocs.ru/wiki/rag.md). - Инструмент `llms_txt2ctx` из исходного репозитория разворачивает `llms.txt` в единый контекстный файл, подтягивая содержимое ссылок.[2] ## Сравнение с robots.txt и sitemap.xml | Файл | Для кого | Что сообщает | |---|---|---| | `robots.txt` | поисковые роботы | что можно и нельзя сканировать (RFC 9309)[3] | | `sitemap.xml` | поисковые системы | полный список адресов для индексации[4] | | `llms.txt` | языковые модели и агенты | что на сайте главное и где лежит чистый текст | `llms.txt` не управляет доступом и не заменяет [robots.txt и sitemap](https://llmdocs.ru/wiki/robots-sitemap.md): это не запрет и не разрешение, а подсказка. ## Применение На практике файл чаще всего полезен не для обучения моделей, а во время работы с ними: - **агенты для кода** читают документацию библиотеки перед написанием кода (см. [Агенты для кода](https://llmdocs.ru/wiki/coding-agents.md)); - **пользователь** вставляет ссылку на `llms.txt` или `llms-full.txt` в чат, чтобы модель отвечала по актуальной версии документации; - **MCP-серверы документации** используют файл как оглавление для поиска (см. [Model Context Protocol (MCP)](https://llmdocs.ru/wiki/mcp.md)). ## Критика Скептики указывают, что крупные поисковые системы публично не подтверждали использование файла, а сам формат дублирует то, что уже дают sitemap и семантическая разметка. Сторонники отвечают, что ценность не в поиске, а в удобстве для агентов и людей, загружающих документацию в контекст: короткий Markdown-файл обходится в разы дешевле по [токенам](https://llmdocs.ru/wiki/tokenization.md), чем HTML-страницы. ## См. также - [Документация для ИИ: как подготовить](https://llmdocs.ru/wiki/docs-for-ai.md) - [Markdown как формат для LLM](https://llmdocs.ru/wiki/markdown-for-llm.md) - [Model Context Protocol (MCP)](https://llmdocs.ru/wiki/mcp.md) - [Контекстное окно](https://llmdocs.ru/wiki/context-window.md) ## Источники 1. [The /llms.txt file — llmstxt.org](https://llmstxt.org/) 2. [AnswerDotAI/llms-txt — GitHub](https://github.com/AnswerDotAI/llms-txt) 3. [RFC 9309 — Robots Exclusion Protocol](https://www.rfc-editor.org/rfc/rfc9309) 4. [Sitemaps XML format](https://www.sitemaps.org/protocol.html) --- # Локальный запуск LLM (llama.cpp, Ollama) > Запуск языковых моделей на своём компьютере или сервере без облачных API — llama.cpp, Ollama, LM Studio; требования к железу, выбор модели и квантизации. Источник: https://llmdocs.ru/wiki/local-llm/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **llama.cpp**: Георгий Герганов, март 2023, C/C++, MIT - **Ollama**: 2023, Go (поверх llama.cpp), MIT - **Формат моделей**: GGUF - **Бэкенды**: CPU, CUDA, Metal, Vulkan, ROCm - **API**: совместимый с OpenAI (/v1/chat/completions) - **Альтернативы**: LM Studio, MLX (Apple), vLLM, Jan, KoboldCpp **Локальный запуск LLM** — использование [больших языковых моделей](https://llmdocs.ru/wiki/llm.md) на собственном компьютере или сервере вместо облачных API. Главные причины — **приватность** (данные не покидают машину), **работа без интернета** и без блокировок, **отсутствие платы за токены** и полный контроль над моделью. Плата за это — более слабые модели, чем передовые облачные, и требования к железу. Основные инструменты — библиотека **llama.cpp** и построенная на ней программа **Ollama**.[1][2] ## История После утечки весов модели LLaMA от Meta в марте 2023 года болгарский разработчик Георгий Герганов за несколько вечеров написал llama.cpp — реализацию инференса на чистом C/C++ без Python и PyTorch, способную работать на обычном ноутбуке, в том числе на Apple Silicon. Ключевым была агрессивная [квантизация](https://llmdocs.ru/wiki/quantization.md) до 4 бит. Проект быстро стал основой экосистемы: появился формат [GGUF](https://llmdocs.ru/wiki/gguf.md) (2023), сотни поддерживаемых архитектур и обёртки — Ollama, LM Studio, Jan, KoboldCpp. Тем временем Meta, Mistral, Alibaba (Qwen), Google (Gemma), DeepSeek и другие начали выпускать открытые веса официально. ## Инструменты | Инструмент | Для кого | Особенности | |---|---|---| | **llama.cpp** | разработчики, серверы | максимум настроек, `llama-server` с веб-интерфейсом и API[4] | | **Ollama** | разработчики, быстрый старт | `ollama run модель`, каталог моделей, фоновый сервис | | **LM Studio** | пользователи | графический интерфейс, поиск моделей на Hugging Face | | **MLX** | владельцы Mac | фреймворк Apple, быстрый на Apple Silicon[5] | | **vLLM** | серверы с GPU, много пользователей | высокая пропускная способность, см. [vLLM и инференс-серверы](https://llmdocs.ru/wiki/vllm.md) | ```bash # Ollama ollama pull qwen3:8b ollama run qwen3:8b "Объясни, что такое GIL, в трёх предложениях" # llama.cpp: сервер с OpenAI-совместимым API и веб-чатом llama-server -hf ggml-org/gemma-3-4b-it-GGUF --port 8080 -c 16384 -ngl 99 ``` Оба поднимают HTTP API, совместимый с OpenAI, поэтому существующие клиенты, редакторы кода и библиотеки работают с локальной моделью сменой адреса: ```python from openai import OpenAI client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama") r = client.chat.completions.create(model="qwen3:8b", messages=[{"role": "user", "content": "Привет!"}]) print(r.choices[0].message.content) ``` Ollama описывает настройки модели (системный промпт, температуру, размер контекста) в файле Modelfile по аналогии с Dockerfile.[3] ## Требования к железу Главный ограничитель — **память**: модель должна поместиться в видеопамять [GPU](https://llmdocs.ru/wiki/gpu-cuda.md) или в общую память Apple Silicon. Грубая оценка для 4-битной квантизации — около 0,6 ГБ на миллиард параметров плюс память на KV-кэш, растущая с длиной [контекста](https://llmdocs.ru/wiki/context-window.md). | Модель | Память (Q4) | Где запускать | |---|---|---| | 1–4 млрд | 1–3 ГБ | любой ноутбук, телефон | | 7–9 млрд | 5–6 ГБ | ноутбук с 16 ГБ, видеокарта 8 ГБ | | 14–32 млрд | 9–20 ГБ | Mac с 32 ГБ, видеокарта 24 ГБ | | 70 млрд | ~40 ГБ | Mac с 64 ГБ, две видеокарты | Скорость генерации определяется пропускной способностью памяти, поэтому Mac с большой объединённой памятью и видеокарты вроде RTX 3090/4090 — популярный выбор. Без GPU модель работает и на CPU, но медленно. Модели семейства MoE (смесь экспертов) активируют лишь часть параметров на токен и работают быстрее, чем подсказывает их полный размер, хотя памяти требуют на все веса. ## Выбор модели и квантизации Модели в формате GGUF публикуются на [Hugging Face](https://llmdocs.ru/wiki/hugging-face.md) в нескольких вариантах квантизации.[6] Разумный выбор — `Q4_K_M` как компромисс размера и качества, `Q5_K_M`/`Q6_K` при запасе памяти, `Q8_0` — почти без потерь. Крупная модель в 4 битах обычно лучше меньшей в 8 битах. ## Применения - приватный чат и работа с конфиденциальными документами (локальный [RAG](https://llmdocs.ru/wiki/rag.md) с локальной моделью [эмбеддингов](https://llmdocs.ru/wiki/embedding.md)); - автодополнение кода в редакторе без отправки кода наружу; - офлайн-перевод, суммаризация, классификация больших объёмов текста без оплаты за токены; - эксперименты с [дообучением](https://llmdocs.ru/wiki/fine-tuning-lora.md) и прототипы до выбора облачного провайдера. ## Ограничения Локальные модели уступают передовым облачным в сложных рассуждениях, коде и длинном контексте; качество вызова инструментов и [структурированного вывода](https://llmdocs.ru/wiki/structured-output.md) сильно зависит от модели и шаблона чата. Сервер Ollama по умолчанию слушает только `localhost` — открывать его в сеть без [аутентификации](https://llmdocs.ru/wiki/authn-authz.md) опасно. ## См. также - [GGUF](https://llmdocs.ru/wiki/gguf.md) - [Квантизация моделей](https://llmdocs.ru/wiki/quantization.md) - [GPU и CUDA](https://llmdocs.ru/wiki/gpu-cuda.md) - [vLLM и инференс-серверы](https://llmdocs.ru/wiki/vllm.md) - [Hugging Face](https://llmdocs.ru/wiki/hugging-face.md) ## Источники 1. [llama.cpp — GitHub](https://github.com/ggml-org/llama.cpp) 2. [Ollama — документация](https://docs.ollama.com/) 3. [Ollama — Modelfile reference](https://docs.ollama.com/modelfile) 4. [llama.cpp — llama-server README](https://github.com/ggml-org/llama.cpp/tree/master/tools/server) 5. [Apple — MLX](https://github.com/ml-explore/mlx) 6. [Hugging Face — GGUF](https://huggingface.co/docs/hub/gguf) --- # Markdown как формат для LLM > Почему Markdown стал основным форматом обмена текстом с языковыми моделями — экономия токенов, сохранение структуры, удобство чанкинга — и как готовить в нём документы. Источник: https://llmdocs.ru/wiki/markdown-for-llm/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Роль**: формат входа (документы, промпты) и выхода (ответы) LLM - **Преимущества**: мало служебной разметки, явная структура, родной для моделей - **Конвертеры**: MarkItDown, Docling, Pandoc, Jina Reader, Trafilatura - **Связанные соглашения**: llms.txt, .md-версии страниц, AGENTS.md - **Альтернативы**: XML-теги, JSON, YAML, обычный текст **Markdown как формат для LLM** — практика подготовки текстов для [языковых моделей](https://llmdocs.ru/wiki/llm.md) в разметке [Markdown](https://llmdocs.ru/wiki/markdown.md): документация, базы знаний и веб-страницы конвертируются из HTML, PDF и DOCX в `.md`, прежде чем попасть в промпт, индекс [RAG](https://llmdocs.ru/wiki/rag.md) или инструменты [агентов](https://llmdocs.ru/wiki/ai-agent.md). Модели и сами по умолчанию отвечают в Markdown. Формат стал фактическим стандартом обмена текстом между людьми, программами и LLM; на нём построены соглашение [llms.txt](https://llmdocs.ru/wiki/llms-txt.md) и файлы инструкций для агентов.[1] ## Почему Markdown - **Экономия токенов.** HTML-страница документации содержит навигацию, скрипты, атрибуты и вложенные `div`; полезный текст нередко занимает меньше трети. Та же страница в Markdown в несколько раз короче — меньше стоимость, меньше шума, больше места в [контекстном окне](https://llmdocs.ru/wiki/context-window.md) (см. [Токен и токенизация](https://llmdocs.ru/wiki/tokenization.md)). - **Сохранение структуры.** Заголовки, списки, таблицы, блоки кода и ссылки остаются явными — в отличие от «плоского» текста, извлечённого из PDF. - **Знакомость модели.** В обучающих данных огромное количество Markdown — README, документация, форумы, — и модели хорошо понимают его соглашения. - **Удобство разбиения.** Заголовки задают естественные границы для [чанкинга](https://llmdocs.ru/wiki/chunking.md), а путь заголовков даёт чанку контекст. - **Читаемость человеком.** Один и тот же файл годится и для модели, и для ревьюера, и для рендеринга в HTML. ## Конвертация | Источник | Инструменты | Трудности | |---|---|---| | HTML | Trafilatura, Readability, Jina Reader, html2text | вырезать навигацию и рекламу, не потерять таблицы и код | | PDF | Docling, Marker, MinerU | колонки, колонтитулы, формулы, таблицы, сканы | | DOCX, PPTX, XLSX | MarkItDown, Pandoc | стили вместо заголовков, вложенные таблицы | MarkItDown от Microsoft и Docling от IBM — популярные открытые конвертеры, разработанные именно для подготовки документов к LLM.[2][3] ```bash pip install 'markitdown[all]' markitdown report.pdf > report.md pandoc manual.docx -t gfm -o manual.md # GitHub-flavored Markdown ``` ## Как писать Markdown для моделей - **Один `#`-заголовок** на документ и последовательная иерархия `##`, `###` — без пропуска уровней. - **Информативные заголовки**: «Настройка TLS в nginx» лучше, чем «Настройка» — заголовок часто попадает в чанк без окружения. - **Самодостаточные разделы**: избегать «как сказано выше»; раздел может быть найден поиском отдельно. - **Блоки кода с указанием языка** (` ```python `) — модель точнее понимает и воспроизводит код. - **Таблицы — для коротких фактов**; длинные таблицы с десятками колонок модели читают хуже, чем списки «ключ: значение».[6] - **Ссылки с осмысленным текстом**, абсолютные URL — относительные теряют смысл вне сайта. - **Метаданные во frontmatter** (YAML в начале файла): заголовок, дата обновления, версия продукта. - **Без HTML-вставок** там, где можно обойтись разметкой. ## Markdown в промптах В самих промптах Markdown удобен для структуры инструкций — заголовки разделов, нумерованные шаги, примеры в блоках кода (см. [Промпт-инжиниринг](https://llmdocs.ru/wiki/prompt-engineering.md)). Для разделения *данных* и *инструкций* многие предпочитают XML-подобные теги (``, ``): их границы однозначны, и они не конфликтуют с Markdown внутри документа.[4] Часто используют комбинацию: документ в Markdown, обёрнутый в тег. ## На сайтах документации Распространённая практика — отдавать каждую страницу также в виде `.md` по тому же адресу с расширением (`/docs/tls` → `/docs/tls.md`), публиковать индекс `llms.txt` и полный дамп `llms-full.txt`. Генераторы [статических сайтов](https://llmdocs.ru/wiki/static-site-generators.md) создают это при сборке, поскольку исходники и так написаны в Markdown. Подробнее — в статье [Документация для ИИ: как подготовить](https://llmdocs.ru/wiki/docs-for-ai.md). ## Ограничения Markdown не стандартизирован до конца: CommonMark и GitHub-flavored Markdown различаются в таблицах, сносках и расширениях.[5] Сложные документы — формулы, диаграммы, многоуровневые таблицы — теряют часть информации; для них используют LaTeX внутри Markdown, описания картинок или [мультимодальные модели](https://llmdocs.ru/wiki/multimodal-models.md), читающие исходные страницы как изображения. ## См. также - [Markdown](https://llmdocs.ru/wiki/markdown.md) - [llms.txt](https://llmdocs.ru/wiki/llms-txt.md) - [Документация для ИИ: как подготовить](https://llmdocs.ru/wiki/docs-for-ai.md) - [Чанкинг документов](https://llmdocs.ru/wiki/chunking.md) - [Промпт-инжиниринг](https://llmdocs.ru/wiki/prompt-engineering.md) ## Источники 1. [llms.txt — proposal](https://llmstxt.org/) 2. [Microsoft — MarkItDown](https://github.com/microsoft/markitdown) 3. [Docling — документация](https://docling-project.github.io/docling/) 4. [Anthropic — Use XML tags to structure your prompts](https://docs.claude.com/en/docs/build-with-claude/prompt-engineering/use-xml-tags) 5. [CommonMark Spec](https://spec.commonmark.org/) 6. [Sui et al. — Table Meets LLM: Can Large Language Models Understand Structured Table Data? (2024)](https://arxiv.org/abs/2305.13062) --- # Model Context Protocol (MCP) > Открытый протокол на основе JSON-RPC, по которому ИИ-приложения подключаются к внешним инструментам, данным и сервисам. Источник: https://llmdocs.ru/wiki/mcp/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: открытый протокол - **Автор**: Anthropic - **Представлен**: 25 ноября 2024 - **Основа**: JSON-RPC 2.0 - **Транспорт**: stdio, Streamable HTTP - **Примитивы сервера**: инструменты, ресурсы, промпты - **Версии спецификации**: по датам (2024-11-05, 2025-03-26, 2025-06-18, 2025-11-25) - **SDK**: Python, TypeScript, Java, Kotlin, C#, Go, Rust и др. - **Лицензия**: MIT (спецификация и SDK) - **Сайт**: [modelcontextprotocol.io](https://modelcontextprotocol.io/) **Model Context Protocol** (**MCP**, «протокол контекста модели») — открытый протокол, который стандартизирует подключение ИИ-приложений к внешним источникам данных и инструментам. Вместо того чтобы для каждой пары «приложение — сервис» писать отдельную интеграцию, сервис один раз реализует MCP-сервер, и им могут пользоваться любые совместимые клиенты: чат-ассистенты, среды разработки, [агенты для кода](https://llmdocs.ru/wiki/coding-agents.md). Протокол часто сравнивают с USB-C для языковых моделей. ## История MCP представила компания Anthropic 25 ноября 2024 года вместе со спецификацией, SDK для Python и TypeScript и набором эталонных серверов (файловая система, Git, GitHub, базы данных).[1] В 2025 году протокол поддержали другие крупные разработчики моделей и инструментов, и он стал фактическим стандартом подключения инструментов к [ИИ-агентам](https://llmdocs.ru/wiki/ai-agent.md). В декабре 2025 года Anthropic передала MCP в Agentic AI Foundation под эгидой Linux Foundation. Спецификация версионируется датами. Редакция 2025-03-26 заменила прежний транспорт HTTP+SSE на Streamable HTTP и добавила авторизацию на основе [OAuth 2.1](https://llmdocs.ru/wiki/oauth-oidc.md); последующие редакции развивали структурированный вывод инструментов, запросы уточнений у пользователя и безопасность.[2] ## Архитектура В MCP три роли:[3] - **хост** — приложение, с которым работает пользователь (чат, IDE, агент); - **клиент** — компонент внутри хоста, который держит соединение с одним сервером; - **сервер** — программа, предоставляющая возможности: доступ к файлам, базе данных, API сервиса. Сообщения передаются в формате JSON-RPC 2.0[5] одним из двух транспортов:[4] - **stdio** — хост запускает сервер как локальный процесс и общается через стандартные ввод и вывод; - **Streamable HTTP** — сервер работает удалённо, клиент отправляет запросы POST, а сервер может отвечать потоком событий. Соединение начинается с рукопожатия `initialize`, в котором стороны сообщают версию протокола и поддерживаемые возможности. ## Примитивы | Сторона | Примитив | Кто управляет | Пример | |---|---|---|---| | сервер | **инструменты** (tools) | модель решает вызвать | «найти в документации», «создать задачу» | | сервер | **ресурсы** (resources) | приложение выбирает | содержимое файла, схема БД | | сервер | **промпты** (prompts) | пользователь выбирает | шаблон «сделай ревью кода» | | клиент | **сэмплинг** (sampling) | сервер просит модель хоста | сгенерировать текст без собственного ключа API | | клиент | **корни** (roots) | хост сообщает границы | разрешённые каталоги | | клиент | **уточнение** (elicitation) | сервер запрашивает у пользователя | подтвердить параметр | Инструменты — самый используемый примитив и прямое развитие механизма [вызова функций](https://llmdocs.ru/wiki/tool-use.md): сервер описывает каждый инструмент названием, описанием и JSON-схемой аргументов, а модель сама решает, когда его вызвать. ## Пример обмена Клиент запрашивает список инструментов, затем вызывает один из них: ```json {"jsonrpc": "2.0", "id": 2, "method": "tools/call", "params": {"name": "search_docs", "arguments": {"query": "asyncio TaskGroup"}}} ``` ```json {"jsonrpc": "2.0", "id": 2, "result": {"content": [{"type": "text", "text": "TaskGroup — асинхронный контекстный менеджер..."}]}} ``` Минимальный сервер на официальном Python SDK: ```python from mcp.server.fastmcp import FastMCP mcp = FastMCP("docs") @mcp.tool() def search_docs(query: str) -> str: """Поиск по документации, возвращает фрагменты текста.""" return find_fragments(query) if __name__ == "__main__": mcp.run() # по умолчанию транспорт stdio ``` Хост подключает такой сервер строкой конфигурации с командой запуска; удалённые серверы подключаются по URL. ## Безопасность MCP-сервер получает реальные права — читать файлы, писать в базы, действовать от имени пользователя, — поэтому спецификация уделяет внимание рискам:[6] - **внедрение инструкций** — текст из документа, страницы или ответа инструмента может содержать команды для модели (см. [Безопасность LLM: prompt injection](https://llmdocs.ru/wiki/prompt-injection.md)); - **отравление описаний инструментов** — недобросовестный сервер прячет инструкции в описаниях; - **избыточные права** — серверу стоит выдавать минимум доступа ([Принцип наименьших привилегий](https://llmdocs.ru/wiki/least-privilege.md)), а опасные действия подтверждать у пользователя. ## Применение Типичные MCP-серверы: доступ к репозиториям и задачам, базам данных, браузеру, поиску по внутренней документации, облачным сервисам. Для документации MCP дополняет [llms.txt](https://llmdocs.ru/wiki/llms-txt.md): файл даёт оглавление, а сервер — поиск и выдачу нужных фрагментов, экономя [контекстное окно](https://llmdocs.ru/wiki/context-window.md). ## См. также - [ИИ-агент](https://llmdocs.ru/wiki/ai-agent.md) - [Tool use / function calling](https://llmdocs.ru/wiki/tool-use.md) - [llms.txt](https://llmdocs.ru/wiki/llms-txt.md) - [RAG (генерация с дополнением поиском)](https://llmdocs.ru/wiki/rag.md) ## Источники 1. [Introducing the Model Context Protocol — Anthropic](https://www.anthropic.com/news/model-context-protocol) 2. [Model Context Protocol — Specification](https://modelcontextprotocol.io/specification/latest) 3. [MCP Architecture overview](https://modelcontextprotocol.io/docs/learn/architecture) 4. [MCP Transports — Streamable HTTP](https://modelcontextprotocol.io/specification/latest/basic/transports) 5. [JSON-RPC 2.0 Specification](https://www.jsonrpc.org/specification) 6. [MCP Security Best Practices](https://modelcontextprotocol.io/specification/latest/basic/security_best_practices) --- # Мультимодальные модели > Модели, которые принимают и/или генерируют несколько типов данных — текст, изображения, аудио, видео; от CLIP до современных LLM, понимающих картинки и речь. Источник: https://llmdocs.ru/wiki/multimodal-models/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Модальности**: текст, изображения, аудио, видео, документы - **Типы**: VLM (понимание), генеративные (диффузия), any-to-any - **Ключевые работы**: CLIP (2021), Flamingo (2022), LLaVA (2023) - **Коммерческие**: GPT-4o, Claude, Gemini - **Открытые**: Qwen2.5-VL, Llama 3.2 Vision, Gemma 3, Pixtral, InternVL - **Связанное**: Эмбеддинг, Трансформер (архитектура) **Мультимодальные модели** — модели машинного обучения, которые работают с несколькими типами данных (модальностями) одновременно: текстом, изображениями, звуком, видео. Современная [большая языковая модель](https://llmdocs.ru/wiki/llm.md) может прочитать скриншот с ошибкой, разобрать отсканированный договор, описать фотографию, ответить на вопрос по графику или распознать речь. Мультимодальность расширяет применение LLM от текстовых задач к работе с документами, интерфейсами и реальным миром. ## Виды моделей | Вид | Вход → выход | Примеры | |---|---|---| | **Контрастные энкодеры** | текст и изображения → общие [эмбеддинги](https://llmdocs.ru/wiki/embedding.md) | CLIP, SigLIP | | **Визуально-языковые модели (VLM)** | изображение + текст → текст | Claude, GPT-4o, Gemini, Qwen2.5-VL, LLaVA | | **Генерация изображений** | текст → изображение | Stable Diffusion, FLUX, Midjourney | | **Речь** | аудио → текст и обратно | Whisper (распознавание), TTS-модели | | **Any-to-any** | любые модальности → любые | GPT-4o с голосом, Gemini Live | ## Как устроены VLM Типичная визуально-языковая модель собирается из трёх частей:[5] 1. **Визуальный энкодер** — обычно Vision Transformer (ViT): изображение режется на квадраты 14×14 или 16×16 пикселей, каждый превращается в вектор — «визуальный токен».[3] 2. **Проектор** — небольшая сеть, переводящая визуальные векторы в пространство эмбеддингов языковой модели. 3. **Языковая модель** — получает визуальные токены вперемешку с текстовыми и генерирует ответ как обычно. Обучение идёт в два этапа: сначала проектор учат сопоставлять изображения с подписями, затем всю систему дообучают на инструкциях вида «картинка + вопрос → ответ». Именно так в 2023 году была построена открытая модель LLaVA.[2] Крупные модели вроде Gemini изначально обучаются на смеси модальностей. Основа многих энкодеров — **CLIP** (OpenAI, 2021): две сети, текстовая и визуальная, обученные на 400 миллионах пар «изображение — подпись» так, чтобы эмбеддинги подходящих пар были близки.[1] CLIP сразу умеет классифицировать изображения по текстовому описанию без дообучения и используется для поиска картинок по тексту. ## Изображения и токены Изображение в контексте модели занимает [токены](https://llmdocs.ru/wiki/tokenization.md) — их число зависит от разрешения. У Claude, например, картинка около 1000×1000 пикселей стоит порядка 1300 токенов, а слишком большие изображения уменьшаются автоматически.[4] Поэтому: - мелкий текст на сильно уменьшенном скриншоте модель может не прочитать — лучше обрезать нужную область; - десятки изображений быстро заполняют [контекстное окно](https://llmdocs.ru/wiki/context-window.md); - PDF-документы многие API обрабатывают как изображения страниц плюс извлечённый текст. ## Применение - **Документы**: извлечение данных из счетов, паспортов, таблиц и сканов — часто в паре со [структурированным выводом](https://llmdocs.ru/wiki/structured-output.md); во многих задачах VLM заменяют классический OCR. - **Интерфейсы**: агенты «computer use» видят экран как скриншоты и управляют мышью и клавиатурой. - **Код**: перевод макета или скриншота в HTML и CSS, разбор диаграмм. - **Поиск**: мультимодальные эмбеддинги для поиска по фотографиям и смешанным базам знаний, мультимодальный [RAG](https://llmdocs.ru/wiki/rag.md). - **Доступность**: описание изображений для незрячих пользователей. - **Речь**: голосовые ассистенты, расшифровка встреч (Whisper — открытая модель распознавания речи на 99 языках).[6] ## Пример запроса ```python import base64, anthropic client = anthropic.Anthropic() img = base64.standard_b64encode(open("chart.png", "rb").read()).decode() msg = client.messages.create( model="claude-sonnet-4-5", max_tokens=1024, messages=[{"role": "user", "content": [ {"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": img}}, {"type": "text", "text": "Какой месяц на графике с максимальной выручкой?"}, ]}], ) print(msg.content[0].text) ``` Открытые VLM запускаются локально через Ollama, llama.cpp или [vLLM](https://llmdocs.ru/wiki/vllm.md). ## Ограничения - **Галлюцинации** на изображениях: модель уверенно «видит» объекты, которых нет, или неверно читает цифры (см. [Галлюцинации LLM](https://llmdocs.ru/wiki/hallucinations.md)). - Слабости в точном счёте объектов, пространственных отношениях, чтении мелкого и рукописного текста. - **Prompt injection через изображения**: текст на картинке может содержать инструкции, которые модель выполнит (см. [Безопасность LLM: prompt injection](https://llmdocs.ru/wiki/prompt-injection.md)). - Конфиденциальность: изображения документов и экранов часто содержат персональные данные. Важные задачи проверяют на собственном наборе примеров — [evals](https://llmdocs.ru/wiki/llm-evals.md) для мультимодальных моделей так же необходимы, как для текстовых. ## См. также - [Большая языковая модель (LLM)](https://llmdocs.ru/wiki/llm.md) - [Трансформер (архитектура)](https://llmdocs.ru/wiki/transformer.md) - [Эмбеддинг](https://llmdocs.ru/wiki/embedding.md) - [Безопасность LLM: prompt injection](https://llmdocs.ru/wiki/prompt-injection.md) ## Источники 1. [Radford et al. — Learning Transferable Visual Models From Natural Language Supervision (CLIP, 2021)](https://arxiv.org/abs/2103.00020) 2. [Liu et al. — Visual Instruction Tuning (LLaVA, 2023)](https://arxiv.org/abs/2304.08485) 3. [Dosovitskiy et al. — An Image is Worth 16x16 Words (ViT, 2020)](https://arxiv.org/abs/2010.11929) 4. [Anthropic Docs — Vision](https://docs.anthropic.com/en/docs/build-with-claude/vision) 5. [Hugging Face — Vision Language Models Explained](https://huggingface.co/blog/vlms) 6. [Radford et al. — Robust Speech Recognition via Large-Scale Weak Supervision (Whisper, 2022)](https://arxiv.org/abs/2212.04356) --- # Кэширование промптов > Повторное использование уже вычисленного начала промпта (KV-кэша) между запросами к LLM; снижает стоимость и задержку при длинных системных инструкциях, документах и диалогах. Источник: https://llmdocs.ru/wiki/prompt-caching/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Принцип**: переиспользование KV-кэша общего префикса - **Условие**: точное совпадение начала промпта - **Экономия**: до ~90% стоимости и до ~80% задержки на кэшированной части - **У провайдеров**: Anthropic, OpenAI, Google Gemini, DeepSeek - **В открытых серверах**: vLLM (prefix caching), SGLang (RadixAttention), llama.cpp - **Время жизни**: минуты — часы (зависит от провайдера) **Кэширование промптов** (англ. *prompt caching*) — техника, при которой результат обработки начала промпта сохраняется и используется повторно в следующих запросах с тем же началом. Если каждый запрос к [языковой модели](https://llmdocs.ru/wiki/llm.md) начинается с одной и той же длинной системной инструкции, описания инструментов или документа на сотню страниц, модели не нужно каждый раз заново «читать» этот текст. Провайдеры API берут за кэшированные [токены](https://llmdocs.ru/wiki/tokenization.md) в разы меньше денег, а ответ начинается быстрее. ## Как работает При обработке промпта ([фаза prefill](https://llmdocs.ru/wiki/vllm.md)) модель-[трансформер](https://llmdocs.ru/wiki/transformer.md) вычисляет для каждого токена ключи и значения механизма внимания — **KV-кэш**. Он зависит только от предыдущих токенов, поэтому KV-кэш префикса «системная инструкция + документ» одинаков для всех запросов, которые с него начинаются. Сервер сохраняет этот кэш, и следующий запрос с тем же префиксом обрабатывает только новую часть. Отсюда главное правило: кэш срабатывает лишь при **точном совпадении начала** промпта, токен в токен. Изменение одного символа в начале — например, текущего времени в системной инструкции — делает недействительным всё, что идёт после. ## У провайдеров API | Провайдер | Как включается | Особенности | |---|---|---| | **Anthropic (Claude)** | явные точки `cache_control` в запросе | запись в кэш дороже обычного ввода, чтение — около 10% цены; TTL 5 минут (продлевается при использовании) или 1 час[1] | | **OpenAI** | автоматически для промптов от 1024 токенов | скидка на кэшированный ввод, без доплаты за запись[2] | | **Google Gemini** | неявное автоматическое и явное с созданием объекта кэша и TTL | явный кэш оплачивается за время хранения[3] | Пример для Anthropic API — кэшируется всё до отмеченного блока включительно: ```python response = client.messages.create( model="claude-sonnet-4-5", max_tokens=1024, system=[ {"type": "text", "text": "Ты — ассистент по документации проекта."}, {"type": "text", "text": big_documentation, "cache_control": {"type": "ephemeral"}}, ], messages=[{"role": "user", "content": "Как настроить авторизацию?"}], ) print(response.usage) # cache_creation_input_tokens, cache_read_input_tokens ``` Поля `usage` в ответе показывают, сколько токенов записано в кэш и сколько прочитано из него, — по ним проверяют, что кэш действительно работает. ## В собственных серверах Открытые инференс-серверы делают то же самое автоматически. В vLLM это **Automatic Prefix Caching**: блоки KV-кэша хешируются по содержимому и переиспользуются между запросами.[4] SGLang хранит префиксы в дереве (RadixAttention) и эффективно обслуживает много запросов с общими частями — например, несколько вариантов ответа на один вопрос или шаги агента.[5] llama.cpp сохраняет кэш между запросами в одном слоте и умеет записывать его на диск. ## Как построить промпт под кэш Порядок частей промпта — от самого стабильного к самому изменчивому: 1. описание инструментов ([tool use](https://llmdocs.ru/wiki/tool-use.md)); 2. системная инструкция; 3. справочные документы, примеры, база знаний; 4. история диалога; 5. новый вопрос пользователя. Практические советы: - не вставлять в начало дату, время, идентификаторы запроса и другие изменяющиеся значения — переносить их в конец; - сохранять стабильный порядок инструментов и документов (например, сортировать); - в многоходовых диалогах ставить точку кэширования на последнем сообщении — каждое следующее обращение будет переиспользовать всю предыдущую историю; - учитывать минимальную длину кэшируемого префикса (порядка 1–4 тысяч токенов в зависимости от модели) и время жизни кэша: при редких запросах он успевает истечь. ## Где особенно полезно - **[Агенты](https://llmdocs.ru/wiki/ai-agent.md) и [агенты для кода](https://llmdocs.ru/wiki/coding-agents.md)** — на каждом шаге отправляется вся растущая история; без кэша стоимость растёт квадратично. - **Чат с большим документом** или кодовой базой — документ кэшируется один раз, вопросы задаются дёшево. - **Few-shot с множеством примеров** и длинные системные инструкции. - **Пакетная обработка** однотипных задач с общей инструкцией. ## Кэширование промптов и RAG Кэширование не заменяет [RAG](https://llmdocs.ru/wiki/rag.md), но меняет компромиссы: если база знаний помещается в [контекстное окно](https://llmdocs.ru/wiki/context-window.md) и стабильна, её можно целиком положить в кэшируемый префикс и обойтись без поиска. Когда документов больше или они часто меняются, по-прежнему нужен поиск. Не следует путать с **семантическим кэшем** — хранением готовых ответов на похожие вопросы: он экономит весь вызов модели, но рискует отдать неподходящий ответ. ## См. также - [Контекстное окно](https://llmdocs.ru/wiki/context-window.md) - [vLLM и инференс-серверы](https://llmdocs.ru/wiki/vllm.md) - [Промпт-инжиниринг](https://llmdocs.ru/wiki/prompt-engineering.md) - [ИИ-агент](https://llmdocs.ru/wiki/ai-agent.md) ## Источники 1. [Anthropic Docs — Prompt caching](https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching) 2. [OpenAI Docs — Prompt caching](https://platform.openai.com/docs/guides/prompt-caching) 3. [Google — Gemini API context caching](https://ai.google.dev/gemini-api/docs/caching) 4. [vLLM — Automatic Prefix Caching](https://docs.vllm.ai/en/latest/features/automatic_prefix_caching.html) 5. [Zheng et al. — SGLang: Efficient Execution of Structured Language Model Programs](https://arxiv.org/abs/2312.07104) --- # Промпт-инжиниринг > Практика составления запросов (промптов) к языковым моделям так, чтобы получать точные, полезные и предсказуемые ответы — инструкции, контекст, примеры, формат и проверка. Источник: https://llmdocs.ru/wiki/prompt-engineering/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Объект**: текст запроса к языковой модели - **Основные приёмы**: чёткие инструкции, контекст, примеры (few-shot), рассуждение по шагам, формат вывода - **Ключевые работы**: GPT-3 и few-shot (2020), chain-of-thought (2022), ReAct (2022) - **Связанные практики**: оценка (evals), RAG, контекст-инжиниринг - **Руководства**: документация Anthropic, OpenAI, Google **Промпт-инжиниринг** (англ. *prompt engineering*) — практика составления запросов к [языковым моделям](https://llmdocs.ru/wiki/llm.md) так, чтобы получать точные, полезные и предсказуемые результаты. **Промпт** — весь текст, который получает модель: системные инструкции, вопрос пользователя, приложенные документы, примеры, описание желаемого формата. Модель не знает ничего о задаче, кроме того, что есть в промпте и в её обучающих данных, поэтому качество ответа сильно зависит от того, как задача сформулирована. С ростом возможностей моделей «магические формулы» потеряли значение, но основы остаются: ясная постановка задачи, достаточный контекст, примеры и проверка результата. Шире эту работу называют **контекст-инжинирингом** — управлением всем, что попадает в [контекстное окно](https://llmdocs.ru/wiki/context-window.md). ## Основные принципы 1. **Ясность и конкретность.** Объясните задачу так, как объясняли бы новому коллеге, не знающему контекста: цель, аудиторию, ограничения, критерии хорошего результата. «Сделай короче» хуже, чем «сократи до 3 предложений для руководителя, сохранив цифры».[1] 2. **Контекст и мотивация.** Объяснение, *зачем* нужно правило, помогает модели применить его разумно: не «никаких списков», а «ответ будет зачитан голосовым ассистентом, поэтому без списков и разметки». 3. **Примеры.** Несколько образцов входа и выхода (*few-shot*) показывают формат и стиль лучше длинных описаний. Эта способность модели учиться по примерам в запросе была ключевым открытием GPT-3.[4] 4. **Структура.** Разделяйте инструкции, данные и примеры явными границами — заголовками [Markdown](https://llmdocs.ru/wiki/markdown.md) или XML-тегами вроде `` и ``. Длинные документы лучше помещать в начало, а вопрос — в конец. 5. **Формат вывода.** Явно опишите, что нужно получить: таблицу, JSON по схеме, определённую длину. Для машинной обработки используйте [структурированный вывод](https://llmdocs.ru/wiki/structured-output.md). 6. **Позитивные формулировки.** «Пиши связными абзацами» работает надёжнее, чем «не используй списки». ## Пример ```text Системный промпт: Ты — ревьюер кода в команде бэкенда на Python. Ревью читают младшие разработчики, поэтому объясняй причину каждого замечания. Сообщение пользователя: def get_user(id): return db.execute(f"SELECT * FROM users WHERE id = {id}") Найди проблемы в коде выше. Для каждой укажи: 1) серьёзность (критично / желательно), 2) что не так и почему, 3) исправленный вариант. Если проблем нет — так и скажи. ``` Промпт задаёт роль и аудиторию, отделяет код тегами, описывает формат ответа и даёт модели разрешение сказать «проблем нет», уменьшая соблазн придумать замечания. ## Приёмы | Приём | Суть | Когда помогает | |---|---|---| | Роль в системном промпте | задать экспертизу, тон, аудиторию | стиль и глубина ответов | | Few-shot | 2–5 примеров вход — выход | нестандартный формат, классификация | | Рассуждение по шагам (*chain-of-thought*) | попросить подумать перед ответом[3] | математика, логика, многошаговые задачи | | Декомпозиция и цепочки | разбить задачу на этапы, каждый — отдельный запрос | сложные документы, конвейеры | | Предоставление источников | вставить документы и требовать ссылок на них | фактические вопросы, снижение [галлюцинаций](https://llmdocs.ru/wiki/hallucinations.md) | | Самопроверка | попросить проверить ответ по критериям | код, расчёты, соответствие требованиям | | Рассуждение и действие (ReAct) | чередование мыслей и вызовов инструментов[5] | [агенты](https://llmdocs.ru/wiki/ai-agent.md) | Рассуждающие модели думают по шагам сами, поэтому для них подробные указания «как думать» часто не нужны и даже мешают; полезнее чётко описать задачу и критерии успеха. Систематический обзор десятков техник — в работе «The Prompt Report».[6] ## Промпты для агентов и инструментов Для систем с вызовом функций ([Tool use / function calling](https://llmdocs.ru/wiki/tool-use.md)) значительная часть промпт-инжиниринга переходит в **описания инструментов**: понятные имена, точные описания параметров, примеры, указание, когда инструмент использовать и когда нет. Инструкции агенту стоит писать как регламент для сотрудника: границы полномочий, что делать при неясности, когда остановиться и спросить. ## Итерации и оценка Промпт — это код: его стоит хранить в системе контроля версий и проверять на наборе тестовых примеров, а не на одном удачном запросе. Типичный цикл — сформулировать критерии успеха, собрать 20–100 характерных входов, запустить, разобрать ошибки, поправить промпт и повторить. Подробнее — в статье [Оценка LLM (evals)](https://llmdocs.ru/wiki/llm-evals.md). Повторяющуюся длинную часть промпта выгодно кэшировать ([Кэширование промптов](https://llmdocs.ru/wiki/prompt-caching.md)).[2] ## Безопасность Если в промпт попадают данные из внешних источников — письма, веб-страницы, документы пользователей, — они могут содержать инструкции, которые модель примет за команды. Защиту от этого описывает статья [Безопасность LLM: prompt injection](https://llmdocs.ru/wiki/prompt-injection.md): разделение данных и инструкций, ограничение прав инструментов и подтверждение опасных действий человеком. ## См. также - [Большая языковая модель (LLM)](https://llmdocs.ru/wiki/llm.md) - [Контекстное окно](https://llmdocs.ru/wiki/context-window.md) - [Оценка LLM (evals)](https://llmdocs.ru/wiki/llm-evals.md) - [Tool use / function calling](https://llmdocs.ru/wiki/tool-use.md) - [Структурированный вывод (JSON mode)](https://llmdocs.ru/wiki/structured-output.md) ## Источники 1. [Anthropic — Prompt engineering overview](https://docs.anthropic.com/en/docs/build-with-claude/prompt-engineering/overview) 2. [OpenAI — Prompt engineering guide](https://platform.openai.com/docs/guides/prompt-engineering) 3. [J. Wei et al. — Chain-of-Thought Prompting Elicits Reasoning in Large Language Models (2022)](https://arxiv.org/abs/2201.11903) 4. [T. Brown et al. — Language Models are Few-Shot Learners (2020)](https://arxiv.org/abs/2005.14165) 5. [S. Yao et al. — ReAct: Synergizing Reasoning and Acting in Language Models (2022)](https://arxiv.org/abs/2210.03629) 6. [S. Schulhoff et al. — The Prompt Report: A Systematic Survey of Prompting Techniques (2024)](https://arxiv.org/abs/2406.06608) --- # Безопасность LLM: prompt injection > Внедрение инструкций в данные, которые обрабатывает языковая модель, чтобы перехватить её поведение; прямые и косвенные атаки, «летальная триада» и способы защиты. Источник: https://llmdocs.ru/wiki/prompt-injection/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Термин**: Саймон Уиллисон, сентябрь 2022 - **Виды**: прямая, косвенная (через документы, страницы, письма, инструменты) - **Место в OWASP**: LLM01 в OWASP Top 10 for LLM Applications - **Главный риск**: агенты с доступом к данным и внешним действиям - **Защита**: разделение привилегий, подтверждение действий, изоляция, фильтры **Prompt injection** (промпт-инъекция) — атака на приложения с [языковыми моделями](https://llmdocs.ru/wiki/llm.md), при которой злоумышленник внедряет инструкции в данные, обрабатываемые моделью, и тем самым перехватывает её поведение. Причина в устройстве LLM: инструкции разработчика и обрабатываемый текст поступают в модель одним потоком [токенов](https://llmdocs.ru/wiki/tokenization.md), и у неё нет надёжного способа отличить команду от данных. Уязвимость занимает первое место в списке OWASP Top 10 для LLM-приложений и считается нерешённой в общем виде.[1] ## История и название Термин предложил Саймон Уиллисон в сентябре 2022 года по аналогии с [SQL-инъекцией](https://llmdocs.ru/wiki/sql-injection.md): там данные пользователя смешиваются с кодом запроса, здесь — с инструкциями промпта.[2] Первые примеры были забавными — бот для твитов, которому велели «игнорировать предыдущие инструкции». Серьёзность проблемы стала ясна с появлением моделей с доступом к почте, веб-поиску и инструментам: исследование 2023 года показало **косвенные** инъекции через веб-страницы и документы.[3] ## Виды - **Прямая инъекция** — пользователь сам пишет модели «забудь инструкции и …». Близка к **джейлбрейку** — обходу ограничений безопасности модели, — но цели разные: джейлбрейк направлен против создателя модели, инъекция — против приложения и его пользователей. - **Косвенная инъекция** — инструкция спрятана в контенте, который модель читает по ходу работы: веб-странице, письме, PDF, комментарии в коде, описании задачи, результате вызова инструмента. Пользователь может не подозревать об атаке; текст бывает невидим человеку (белый шрифт, HTML-комментарий, метаданные, символы Unicode-тегов). ```text ``` ## Последствия - **Утечка данных** — модель вставляет приватные данные в ссылку или картинку на сервер атакующего; браузер или клиент загружает её автоматически. - **Несанкционированные действия** — отправка писем, изменение файлов, покупки, выполнение команд в [агентах для кода](https://llmdocs.ru/wiki/coding-agents.md). - **Манипуляция ответом** — искажённые выводы, реклама, фишинговые ссылки, влияние на автоматические оценки (например, скрытый текст в резюме или научной статье). - **Отравление памяти** — инструкция записывается в долговременную память агента и срабатывает позже. ## «Летальная триада» Уиллисон сформулировал простое правило: опасна комбинация трёх возможностей агента — **доступ к приватным данным**, **контакт с недоверенным контентом** и **способ передать данные наружу** (сетевые запросы, ссылки, письма).[4] Если у [агента](https://llmdocs.ru/wiki/ai-agent.md) есть все три, утечку данных можно считать вопросом времени. Убрать хотя бы одну — самый надёжный способ защиты. ## Защита Надёжного фильтра не существует: модели можно обучить сопротивляться известным атакам, и классификаторы ловят многие попытки, но новые формулировки обходят их с заметной вероятностью. Поэтому защита строится на архитектуре, а не на надежде, что модель «поймёт»: - **Принцип наименьших привилегий** — агенту даются только нужные инструменты и данные, токены с минимальными правами (см. [Принцип наименьших привилегий](https://llmdocs.ru/wiki/least-privilege.md)). - **Подтверждение человеком** опасных действий: отправки, удаления, платежей, команд вне песочницы. - **Изоляция** — запуск в контейнере без секретов, ограничение сетевого доступа белым списком доменов. - **Разделение ролей** — модель, читающая недоверенный контент, не имеет инструментов; привилегированная модель видит только её структурированный, проверенный вывод. Подходы вроде CaMeL отделяют поток управления от потока данных.[5][6] - **Запрет автоматической загрузки** ссылок и изображений из ответов модели. - **Маркировка недоверенных данных** в промпте (теги, отдельные роли сообщений) — снижает, но не устраняет риск. - **Мониторинг и журналирование** вызовов инструментов для расследования. ## Связь с другими угрозами Prompt injection — частный случай более общей проблемы смешения кода и данных, знакомой по [XSS](https://llmdocs.ru/wiki/xss.md) и SQL-инъекциям, но без аналога экранирования. В [MCP](https://llmdocs.ru/wiki/mcp.md) дополнительные риски создают недоверенные серверы, описания инструментов которых сами могут содержать инъекции. Сходные вопросы рассматривает [OWASP Top 10](https://llmdocs.ru/wiki/owasp-top-10.md) для веб-приложений. ## См. также - [ИИ-агент](https://llmdocs.ru/wiki/ai-agent.md) - [Агенты для кода](https://llmdocs.ru/wiki/coding-agents.md) - [Model Context Protocol (MCP)](https://llmdocs.ru/wiki/mcp.md) - [Принцип наименьших привилегий](https://llmdocs.ru/wiki/least-privilege.md) - [Галлюцинации LLM](https://llmdocs.ru/wiki/hallucinations.md) ## Источники 1. [OWASP — Top 10 for LLM Applications: LLM01 Prompt Injection](https://genai.owasp.org/llmrisk/llm01-prompt-injection/) 2. [Simon Willison — Prompt injection attacks against GPT-3 (2022)](https://simonwillison.net/2022/Sep/12/prompt-injection/) 3. [Greshake et al. — Not what you've signed up for: Indirect Prompt Injection (2023)](https://arxiv.org/abs/2302.12173) 4. [Simon Willison — The lethal trifecta for AI agents (2025)](https://simonwillison.net/2025/Jun/16/the-lethal-trifecta/) 5. [Debenedetti et al. — Defeating Prompt Injections by Design (CaMeL, 2025)](https://arxiv.org/abs/2503.18813) 6. [Beurer-Kellner et al. — Design Patterns for Securing LLM Agents against Prompt Injections (2025)](https://arxiv.org/abs/2506.08837) --- # RAG (генерация с дополнением поиском) > Подход, при котором языковая модель перед ответом получает релевантные фрагменты из внешней базы знаний, найденные поиском. Источник: https://llmdocs.ru/wiki/rag/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Полное название**: Retrieval-Augmented Generation - **Впервые описан**: 2020, Льюис и соавт. (Facebook AI Research) - **Компоненты**: разбиение на фрагменты, эмбеддинги, индекс, поиск, реранжирование, генерация - **Типичные хранилища**: pgvector, Qdrant, Milvus, Weaviate, Chroma, FAISS - **Связанные подходы**: дообучение, длинный контекст, GraphRAG, агентный поиск **RAG** (англ. *Retrieval-Augmented Generation* — генерация с дополнением поиском) — способ построения систем на основе [больших языковых моделей](https://llmdocs.ru/wiki/llm.md), при котором перед ответом модель получает фрагменты текста из внешней базы знаний, отобранные поиском по запросу. Модель отвечает, опираясь на эти фрагменты, а не только на то, что запомнила при обучении. RAG позволяет работать с внутренними и свежими документами без дообучения, ссылаться на источники и снижать число [галлюцинаций](https://llmdocs.ru/wiki/hallucinations.md). ## История Термин ввели исследователи Facebook AI Research во главе с Патриком Льюисом в статье 2020 года, где генеративная модель обучалась совместно с нейросетевым поисковиком по Википедии.[1] С распространением чат-моделей в 2023 году название закрепилось за более простой и практичной схемой: готовая модель плюс поиск по базе фрагментов, найденные тексты подставляются в промпт. Именно в этом смысле термин обычно употребляется сегодня. ## Схема работы **Индексация** (выполняется заранее): 1. Документы очищаются и разбиваются на фрагменты (**чанки**) — обычно от нескольких сотен до тысячи [токенов](https://llmdocs.ru/wiki/tokenization.md), часто с перекрытием (см. [Чанкинг документов](https://llmdocs.ru/wiki/chunking.md)). 2. Каждый фрагмент превращается в вектор моделью [эмбеддингов](https://llmdocs.ru/wiki/embedding.md). 3. Векторы и тексты сохраняются в индексе — векторной базе или расширении обычной СУБД (см. [pgvector и векторные БД](https://llmdocs.ru/wiki/pgvector.md)).[4] **Ответ на запрос:** 1. Запрос пользователя тоже переводится в вектор. 2. В индексе ищутся ближайшие векторы — приближённым поиском ближайших соседей, чаще всего по графу HNSW[2] (см. [Векторный поиск](https://llmdocs.ru/wiki/vector-search.md)). 3. Найденные фрагменты при необходимости **реранжируются** более точной моделью. 4. Лучшие фрагменты вместе с вопросом передаются модели с инструкцией отвечать по ним и указывать источник. ```python query_vec = embed(question) chunks = index.search(query_vec, k=20) # кандидаты chunks = rerank(question, chunks)[:5] # самые релевантные prompt = f"Ответь по фрагментам, укажи источник.\n\n{format(chunks)}\n\nВопрос: {question}" answer = llm(prompt) ``` ## Улучшения базовой схемы | Приём | Суть | |---|---| | Гибридный поиск | объединение векторного поиска с лексическим (BM25), результаты сливаются, например, методом Reciprocal Rank Fusion[3] | | Реранжирование | кросс-энкодер оценивает пару «вопрос — фрагмент» точнее, чем сравнение векторов | | Переформулировка запроса | модель расширяет или разбивает вопрос на подзапросы | | Метаданные и фильтры | поиск только по нужному продукту, версии, дате | | Контекстные чанки | к фрагменту добавляется заголовок документа и раздела | | GraphRAG | граф сущностей и связей для вопросов «обо всём корпусе»[5] | | Агентный RAG | [ИИ-агент](https://llmdocs.ru/wiki/ai-agent.md) сам решает, что и сколько раз искать, в том числе через инструменты [MCP](https://llmdocs.ru/wiki/mcp.md) | ## RAG, дообучение и длинный контекст - **[Дообучение](https://llmdocs.ru/wiki/fine-tuning-lora.md)** меняет поведение и стиль модели, но плохо подходит для фактов, которые часто обновляются, и не даёт ссылок на источники. - **Длинный контекст** позволяет вставить документы целиком, но стоит дороже, отвечает медленнее, а качество использования информации из середины длинного контекста падает.[6] - **RAG** дешевле на каждый запрос и прозрачнее, но качество ответа ограничено качеством поиска: если нужный фрагмент не найден, модель его не увидит. На практике подходы сочетают. ## Оценка качества Отдельно оценивают **поиск** (нашёлся ли нужный фрагмент среди первых k — метрики recall@k, MRR) и **генерацию** (опирается ли ответ на найденное, отвечает ли он на вопрос). Для этого собирают набор вопросов с эталонными ответами и источниками (см. [Оценка LLM (evals)](https://llmdocs.ru/wiki/llm-evals.md)). ## Типичные проблемы - неудачное разбиение: таблица или фрагмент кода разрезаны посередине; - устаревший индекс, не синхронизированный с документами; - модель игнорирует найденное или смешивает его с собственными «знаниями»; - внедрение инструкций через проиндексированные документы ([Безопасность LLM: prompt injection](https://llmdocs.ru/wiki/prompt-injection.md)). ## См. также - [Векторный поиск](https://llmdocs.ru/wiki/vector-search.md) - [Эмбеддинг](https://llmdocs.ru/wiki/embedding.md) - [llms.txt](https://llmdocs.ru/wiki/llms-txt.md) - [Контекстное окно](https://llmdocs.ru/wiki/context-window.md) ## Источники 1. [Lewis et al. Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks (2020)](https://arxiv.org/abs/2005.11401) 2. [Malkov, Yashunin. Efficient and robust approximate nearest neighbor search using HNSW graphs](https://arxiv.org/abs/1603.09320) 3. [Cormack et al. Reciprocal Rank Fusion outperforms Condorcet and individual Rank Learning Methods (2009)](https://plg.uwaterloo.ca/~gvcormac/cormacksigir09-rrf.pdf) 4. [pgvector — GitHub](https://github.com/pgvector/pgvector) 5. [Edge et al. From Local to Global: A Graph RAG Approach (Microsoft, 2024)](https://arxiv.org/abs/2404.16130) 6. [Liu et al. Lost in the Middle: How Language Models Use Long Contexts (2023)](https://arxiv.org/abs/2307.03172) --- # Структурированный вывод (JSON mode) > Способы заставить языковую модель отвечать данными строго заданной формы — JSON по схеме — через промпт, JSON mode, ограниченное декодирование и валидацию. Источник: https://llmdocs.ru/wiki/structured-output/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Задача**: получать от LLM машиночитаемые данные вместо свободного текста - **Формат схем**: JSON Schema - **Уровни гарантий**: промпт → JSON mode → строгая схема (constrained decoding) - **Библиотеки**: Pydantic, Instructor, Outlines, XGrammar, llguidance - **Поддержка в API**: OpenAI, Anthropic, Google, vLLM, llama.cpp **Структурированный вывод** (англ. *structured output*) — режим работы [языковой модели](https://llmdocs.ru/wiki/llm.md), при котором ответ представляет собой данные заданной формы, чаще всего [JSON](https://llmdocs.ru/wiki/json.md) по схеме, а не свободный текст. Это нужно везде, где ответ модели читает программа: извлечение полей из документов, классификация, заполнение форм, вызов функций в [агентах](https://llmdocs.ru/wiki/ai-agent.md). Без специальных мер модель время от времени добавляет пояснения, пропускает поля, путает типы или выдаёт синтаксически сломанный JSON — и каждый такой случай ломает конвейер. ## Уровни гарантий | Подход | Как | Гарантия | |---|---|---| | Просьба в промпте | «Ответь только JSON вида …» с примером | никакой; ошибки в процентах случаев | | JSON mode | API гарантирует синтаксически корректный JSON | синтаксис, но не схема | | Строгая схема | API или движок ограничивает генерацию по JSON Schema | синтаксис и структура | | Валидация и повтор | проверить ответ, при ошибке отправить её модели | зависит от числа попыток | Хорошая практика — сочетать строгую схему на уровне генерации и валидацию на стороне приложения: схема гарантирует форму, но не правильность значений. ## Ограниченное декодирование Модель генерирует текст по одному [токену](https://llmdocs.ru/wiki/tokenization.md), каждый раз выбирая из распределения вероятностей по словарю. **Ограниченное декодирование** (constrained decoding) на каждом шаге обнуляет вероятность токенов, недопустимых по грамматике: после `{"age": ` разрешены только цифры, после закрытия последнего обязательного поля — только `}`. Схема JSON или регулярное выражение компилируется в конечный автомат или грамматику, и проверка выполняется быстро.[4] На этом принципе работают режим strict в API OpenAI, структурированный вывод Anthropic, движки Outlines, XGrammar и llguidance, встроенные в [инференс-серверы](https://llmdocs.ru/wiki/vllm.md), и грамматики GBNF в llama.cpp.[1][2][5][7] Поддерживается не вся JSON Schema: обычно доступны объекты, массивы, перечисления, обязательные поля и вложенность, но часть ограничений (форматы, сложные условия) не применяется.[3] ## Пример Схему удобно описывать классами Pydantic и получать сразу типизированный объект (см. [Dataclasses и Pydantic](https://llmdocs.ru/wiki/dataclasses-pydantic.md)): ```python from pydantic import BaseModel, Field from openai import OpenAI class Vacancy(BaseModel): title: str salary_from: int | None = Field(description="в рублях, без НДФЛ") remote: bool stack: list[str] client = OpenAI() resp = client.responses.parse( model="gpt-5-mini", input=[{"role": "user", "content": f"Извлеки поля из вакансии:\n{text}"}], text_format=Vacancy, ) vacancy: Vacancy = resp.output_parsed ``` Библиотека Instructor даёт такой же интерфейс для разных провайдеров и локальных моделей, добавляя автоматический повтор с текстом ошибки валидации.[6] ## Связь с вызовом инструментов [Вызов инструментов](https://llmdocs.ru/wiki/tool-use.md) технически — тот же структурированный вывод: модель выдаёт имя функции и аргументы по JSON Schema. Поэтому один из способов получить структуру — объявить «инструмент» с нужной схемой и потребовать его вызова. Современные API предлагают для этого отдельный режим. ## Практические советы - **Порядок полей важен.** Модель генерирует слева направо: поле с рассуждением (`reasoning`) перед итоговым ответом улучшает точность, после — бесполезно. - **Описания полей** в схеме работают как часть промпта: единицы измерения, формат дат, что делать при отсутствии значения. - **Оставлять выход.** Для извлечения данных нужен способ сказать «не найдено» (`null`, отдельное перечисление), иначе модель выдумает значение — см. [Галлюцинации LLM](https://llmdocs.ru/wiki/hallucinations.md). - **Не перегружать схему.** Глубоко вложенные структуры с десятками полей лучше разбить на несколько вызовов. - **Жёсткие ограничения могут вредить.** Если формат мешает модели «думать», качество падает; иногда лучше дать свободный ответ, а затем извлечь из него структуру вторым вызовом. - **Проверять смысл**, а не только форму: правильный по схеме JSON может содержать неверные данные. Качество измеряют на размеченном наборе — см. [Оценка LLM (evals)](https://llmdocs.ru/wiki/llm-evals.md). ## См. также - [Tool use / function calling](https://llmdocs.ru/wiki/tool-use.md) - [JSON](https://llmdocs.ru/wiki/json.md) - [Промпт-инжиниринг](https://llmdocs.ru/wiki/prompt-engineering.md) - [Dataclasses и Pydantic](https://llmdocs.ru/wiki/dataclasses-pydantic.md) - [Галлюцинации LLM](https://llmdocs.ru/wiki/hallucinations.md) ## Источники 1. [OpenAI — Structured Outputs](https://platform.openai.com/docs/guides/structured-outputs) 2. [Anthropic — Structured outputs](https://docs.claude.com/en/docs/build-with-claude/structured-outputs) 3. [JSON Schema — specification](https://json-schema.org/specification) 4. [Willard, Louf — Efficient Guided Generation for Large Language Models (Outlines, 2023)](https://arxiv.org/abs/2307.09702) 5. [llama.cpp — GBNF grammars](https://github.com/ggml-org/llama.cpp/blob/master/grammars/README.md) 6. [Instructor — документация](https://python.useinstructor.com/) 7. [vLLM — Structured Outputs](https://docs.vllm.ai/en/latest/features/structured_outputs.html) --- # Токен и токенизация > Токен — минимальная единица текста, с которой работает языковая модель (обычно часть слова); токенизация — разбиение текста на токены и их перевод в числовые идентификаторы. Источник: https://llmdocs.ru/wiki/tokenization/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Что такое токен**: фрагмент текста из словаря модели — слово, часть слова, символ или байт - **Основные алгоритмы**: BPE, WordPiece, Unigram - **Библиотеки**: tiktoken, SentencePiece, Hugging Face Tokenizers - **Размер словаря**: обычно от 32 тыс. до 256 тыс. токенов - **Эмпирика для английского**: около 4 символов или 0,75 слова на токен - **Влияние**: стоимость, скорость, длина контекста, качество на разных языках **Токен** — минимальная единица текста, с которой работает [языковая модель](https://llmdocs.ru/wiki/llm.md). Обычно это не слово и не буква, а что-то среднее: частое слово целиком, кусок редкого слова, знак препинания или пробел вместе с началом слова. **Токенизация** — процесс разбиения текста на токены и перевода каждого в числовой идентификатор из фиксированного словаря модели. Модель видит только последовательность чисел и генерирует ответ тоже по одному токену. В токенах измеряется почти всё, что важно на практике: цена запроса к API, размер [контекстного окна](https://llmdocs.ru/wiki/context-window.md), скорость генерации и лимиты.[5] ## Зачем делить на части слов Есть три очевидных варианта разбиения, и у каждого свои проблемы: | Единица | Плюсы | Минусы | |---|---|---| | Слово | короткие последовательности | огромный словарь, неизвестные слова, опечатки, разные формы слова | | Символ или байт | маленький словарь, любой текст | очень длинные последовательности, медленно и дорого | | Часть слова (*subword*) | компромисс: частые слова целиком, редкие — из кусков | разбиение иногда неинтуитивно | Подсловная токенизация позволяет модели обработать любое слово — даже выдуманное или с опечаткой, — собрав его из известных фрагментов, и при этом держать последовательности короткими. ## Алгоритмы **BPE** (*Byte Pair Encoding*) изначально был методом сжатия данных; для нейросетей его адаптировали Рико Зеннрих и коллеги в 2015 году.[1] Обучение начинается со словаря из отдельных символов (в современных вариантах — байтов), затем самая частая пара соседних единиц объединяется в новую, и так тысячи раз, пока словарь не достигнет нужного размера. Байтовый BPE используют модели GPT, Llama и многие другие. **WordPiece** (BERT) похож на BPE, но выбирает слияния по вероятностному критерию. **Unigram** начинает с большого словаря и удаляет наименее полезные токены. Библиотека **SentencePiece** реализует BPE и Unigram, работая с сырым текстом без предварительного деления на слова, что удобно для языков без пробелов.[2] Обзор алгоритмов — в документации Hugging Face.[4] ## Пример ```python import tiktoken # токенизатор моделей OpenAI; у других моделей свои словари enc = tiktoken.get_encoding("o200k_base") for text in ["Hello, world!", "Привет, мир!", "PostgreSQL"]: ids = enc.encode(text) print(len(ids), [enc.decode([i]) for i in ids]) ``` Вывод показывает, как текст режется на фрагменты: частые английские слова обычно занимают один токен, а редкие слова и названия делятся на несколько. Точное разбиение зависит от модели: у каждой свой словарь, поэтому один и тот же текст для разных моделей — разное число токенов.[3] ## Языки и токены Словарь строится по обучающим данным, где больше всего английского текста и кода. Поэтому английский токенизируется экономнее всего — в среднем около четырёх символов на токен, — а русский и другие языки на кириллице, а также языки со своими письменностями требуют заметно больше токенов на тот же смысл. Это означает более высокую цену, меньший эффективный контекст и более медленную генерацию для этих языков.[6] Новые модели расширяют словари и добавляют больше многоязычных данных, сокращая разрыв. ## Особенности и подводные камни - **Пробелы входят в токены.** Токены «мир» и « мир» (с пробелом) — разные, поэтому лишние пробелы и переводы строк меняют разбиение. - **Числа** нередко режутся на группы цифр, что исторически затрудняло моделям арифметику. - **Подсчёт букв.** Модель не видит отдельных символов внутри токена, поэтому ей трудно сказать, сколько букв «р» в слове, или написать слово задом наперёд. - **Специальные токены** отмечают границы сообщений, роли в диалоге, начало и конец текста; их нельзя подделать обычным текстом. - **Код и форматирование.** Отступы, повторяющиеся символы и разметка тоже стоят токенов; компактный [Markdown](https://llmdocs.ru/wiki/markdown.md) обходится дешевле, чем HTML с той же информацией (см. [Markdown как формат для LLM](https://llmdocs.ru/wiki/markdown-for-llm.md)). ## Практические советы - Для оценки стоимости и проверки лимитов используйте токенизатор или эндпоинт подсчёта токенов конкретного провайдера, а не правило «слово ≈ токен».[5] - Убирайте из документов, подаваемых в модель, лишнюю разметку, повторы и служебный текст. - При нарезке документов для [RAG](https://llmdocs.ru/wiki/rag.md) размер фрагментов задавайте в токенах (см. [Чанкинг документов](https://llmdocs.ru/wiki/chunking.md)). - Повторяющееся начало запроса выгодно кэшировать — см. [Кэширование промптов](https://llmdocs.ru/wiki/prompt-caching.md). Связь токенов с текстом обратимая: последовательность идентификаторов однозначно декодируется в исходную строку, включая [любые символы Unicode](https://llmdocs.ru/wiki/unicode-utf8.md) — байтовые токенизаторы при необходимости собирают их из отдельных байтов. ## См. также - [Большая языковая модель (LLM)](https://llmdocs.ru/wiki/llm.md) - [Контекстное окно](https://llmdocs.ru/wiki/context-window.md) - [Эмбеддинг](https://llmdocs.ru/wiki/embedding.md) - [Кэширование промптов](https://llmdocs.ru/wiki/prompt-caching.md) - [Unicode и UTF-8](https://llmdocs.ru/wiki/unicode-utf8.md) ## Источники 1. [R. Sennrich, B. Haddow, A. Birch — Neural Machine Translation of Rare Words with Subword Units (BPE, 2015)](https://arxiv.org/abs/1508.07909) 2. [T. Kudo, J. Richardson — SentencePiece (2018)](https://arxiv.org/abs/1808.06226) 3. [openai/tiktoken — GitHub](https://github.com/openai/tiktoken) 4. [Hugging Face — Summary of the tokenizers](https://huggingface.co/docs/transformers/tokenizer_summary) 5. [Anthropic — Token counting](https://docs.anthropic.com/en/docs/build-with-claude/token-counting) 6. [A. Petrov et al. — Language Model Tokenizers Introduce Unfairness Between Languages (2023)](https://arxiv.org/abs/2305.15425) --- # Tool use / function calling > Возможность языковой модели вызывать внешние функции и API — модель выбирает инструмент и формирует аргументы по JSON-схеме, а приложение выполняет вызов и возвращает результат. Источник: https://llmdocs.ru/wiki/tool-use/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Суть**: модель генерирует структурированный вызов, приложение его исполняет - **Описание инструментов**: имя, описание, JSON Schema параметров - **Появление в API**: 2023 (OpenAI), 2024 (Anthropic, общий доступ) - **Типы**: клиентские (выполняет приложение), серверные (выполняет провайдер) - **Стандарт подключения**: Model Context Protocol (MCP) - **Применение**: агенты, доступ к данным, действия во внешних системах, структурированный вывод **Tool use** («использование инструментов»), или **function calling** («вызов функций»), — возможность [языковой модели](https://llmdocs.ru/wiki/llm.md) обращаться к внешним функциям: искать в интернете, читать базу данных, вызывать API, выполнять код. Модель сама ничего не выполняет: она получает список доступных инструментов с описаниями, решает, какой из них нужен, и генерирует структурированный вызов с аргументами. Приложение выполняет вызов и возвращает результат модели, которая использует его для ответа или следующего шага.[1] Tool use превращает модель из собеседника в исполнителя: на нём построены [ИИ-агенты](https://llmdocs.ru/wiki/ai-agent.md), ассистенты с доступом к корпоративным данным и интеграции через [MCP](https://llmdocs.ru/wiki/mcp.md). ## Как это работает 1. Приложение передаёт модели запрос пользователя и **определения инструментов**: имя, описание на естественном языке и схему параметров в формате JSON Schema.[3] 2. Модель отвечает либо текстом, либо блоком вызова: имя инструмента и аргументы в [JSON](https://llmdocs.ru/wiki/json.md). 3. Приложение проверяет и выполняет вызов — обращается к API, базе, файловой системе. 4. Результат отправляется модели как сообщение специального типа. 5. Модель формирует ответ или запрашивает следующий вызов. Несколько независимых вызовов можно сделать параллельно. ## Пример ```python import anthropic client = anthropic.Anthropic() tools = [{ "name": "get_weather", "description": "Текущая погода в городе. Использовать, когда пользователь спрашивает о погоде сейчас.", "input_schema": { "type": "object", "properties": { "city": {"type": "string", "description": "Город, например «Москва»"}, "units": {"type": "string", "enum": ["celsius", "fahrenheit"]}, }, "required": ["city"], }, }] resp = client.messages.create( model="claude-sonnet-5-5", max_tokens=1024, tools=tools, messages=[{"role": "user", "content": "Нужен ли зонт в Казани?"}], ) call = next(b for b in resp.content if b.type == "tool_use") print(call.name, call.input) # get_weather {'city': 'Казань', 'units': 'celsius'} ``` Дальше приложение вызывает настоящий сервис погоды и возвращает результат блоком `tool_result` с тем же идентификатором вызова; модель отвечает пользователю уже с опорой на данные. У OpenAI и других провайдеров механизм устроен аналогично, отличаются названия полей.[2] ## История Первые эксперименты строились на промптах: модели предлагали выводить вызовы в условном текстовом формате, который разбирала программа. Работа Toolformer (2023) показала, что модель можно обучить самостоятельно вставлять вызовы API в текст.[6] В июне 2023 года OpenAI добавила в API нативный вызов функций, в 2024 году общий доступ к tool use открыла Anthropic, затем Google и другие. Сейчас модели специально обучают выбирать инструменты и формировать корректные аргументы; качество сравнивают, например, на Berkeley Function Calling Leaderboard.[4] ## Типы инструментов - **Клиентские** — определяет и выполняет ваше приложение: доступ к вашей базе, CRM, файлам. - **Серверные** — выполняются на стороне провайдера: веб-поиск, выполнение кода в песочнице, получение веб-страниц. - **Инструменты через MCP** — внешние серверы по открытому протоколу предоставляют наборы инструментов любому совместимому клиенту, будь то IDE, чат или агент.[5] ## Как писать хорошие инструменты Описание инструмента — часть промпта, и от него зависит, правильно ли модель его использует (см. [Промпт-инжиниринг](https://llmdocs.ru/wiki/prompt-engineering.md)): - **Подробное описание.** Что делает инструмент, когда его использовать и когда нет, что он возвращает, какие у него ограничения. Несколько предложений лучше одного слова. - **Понятные параметры.** Говорящие имена, описания с примерами, `enum` для фиксированных значений, минимум обязательных полей. - **Немного инструментов с ясными границами** лучше десятков пересекающихся: модель путается, если два инструмента делают почти одно и то же. - **Полезные результаты.** Возвращайте то, что нужно модели для следующего шага, компактно и без лишних полей — результаты занимают [контекстное окно](https://llmdocs.ru/wiki/context-window.md). - **Понятные ошибки.** Сообщение «город не найден, уточните написание» позволяет модели исправиться; трассировка стека — нет. ## Безопасность Аргументы, сгенерированные моделью, — это непроверенный ввод. Их нужно валидировать так же, как данные от пользователя: параметризовать запросы к базе, ограничивать пути к файлам, не передавать в оболочку без экранирования. Инструментам дают минимально необходимые права ([Принцип наименьших привилегий](https://llmdocs.ru/wiki/least-privilege.md)), а действия с последствиями — отправку денег, удаление, публикацию — подтверждает человек. Результаты инструментов, содержащие внешний текст, могут нести внедрённые инструкции (см. [Безопасность LLM: prompt injection](https://llmdocs.ru/wiki/prompt-injection.md)). ## Tool use и структурированный вывод Тот же механизм используют, чтобы получить от модели данные строго по схеме: определяют «инструмент» с нужной схемой и требуют его вызвать. Многие провайдеры теперь предлагают для этого отдельный режим — см. [Структурированный вывод (JSON mode)](https://llmdocs.ru/wiki/structured-output.md). ## См. также - [ИИ-агент](https://llmdocs.ru/wiki/ai-agent.md) - [Model Context Protocol (MCP)](https://llmdocs.ru/wiki/mcp.md) - [Структурированный вывод (JSON mode)](https://llmdocs.ru/wiki/structured-output.md) - [JSON](https://llmdocs.ru/wiki/json.md) - [Промпт-инжиниринг](https://llmdocs.ru/wiki/prompt-engineering.md) ## Источники 1. [Anthropic — Tool use with Claude](https://docs.anthropic.com/en/docs/agents-and-tools/tool-use/overview) 2. [OpenAI — Function calling](https://platform.openai.com/docs/guides/function-calling) 3. [JSON Schema](https://json-schema.org/) 4. [Berkeley Function Calling Leaderboard](https://gorilla.cs.berkeley.edu/leaderboard.html) 5. [Model Context Protocol — Specification](https://modelcontextprotocol.io/specification) 6. [T. Schick et al. — Toolformer (2023)](https://arxiv.org/abs/2302.04761) --- # Векторный поиск > Поиск объектов по близости их векторных представлений (эмбеддингов) — точный или приближённый (ANN) с помощью индексов HNSW, IVF и квантизации; основа семантического поиска и RAG. Источник: https://llmdocs.ru/wiki/vector-search/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Задача**: найти k векторов, ближайших к вектору запроса - **Точный поиск**: полный перебор (kNN) - **Приближённый поиск**: ANN — HNSW, IVF, DiskANN, ScaNN - **Сжатие**: продуктовая (PQ), скалярная и бинарная квантизация - **Метрики качества**: recall@k, задержка, память - **Библиотеки**: FAISS, hnswlib, ScaNN - **Хранилища**: pgvector, Qdrant, Milvus, Weaviate, Elasticsearch, OpenSearch **Векторный поиск** — поиск объектов по близости их векторных представлений. Тексты, изображения или товары заранее превращаются в [эмбеддинги](https://llmdocs.ru/wiki/embedding.md) — векторы, в которых похожие по смыслу объекты расположены рядом. Запрос тоже превращается в вектор, и система находит *k* ближайших к нему векторов в коллекции. В отличие от поиска по ключевым словам, векторный поиск находит «машину» по запросу «автомобиль» и правильный раздел документации по вопросу, сформулированному своими словами. Векторный поиск — центральная часть [RAG](https://llmdocs.ru/wiki/rag.md), рекомендательных систем, поиска по изображениям и обнаружения дубликатов. ## Точный и приближённый поиск **Точный поиск** (kNN) сравнивает запрос со всеми векторами коллекции. Он прост и гарантирует правильный результат, но время растёт линейно: миллион векторов размерности 1024 — это миллиард умножений на каждый запрос. Для тысяч и десятков тысяч векторов этого достаточно, особенно на GPU. **Приближённый поиск ближайших соседей** (ANN) использует индексы, которые проверяют лишь малую часть коллекции. Он находит *почти* всех настоящих соседей — доля найденных называется **полнотой** (*recall@k*) — но работает в сотни и тысячи раз быстрее. На практике полнота 95–99% при задержке в миллисекунды — обычный компромисс. ## Основные алгоритмы | Метод | Идея | Сильные стороны | Слабые стороны | |---|---|---|---| | HNSW | многоуровневый граф «тесного мира»: поиск спускается от дальних связей к ближним[1] | высокая полнота и скорость, добавление на лету | много памяти, долгое построение | | IVF | векторы разбиты на кластеры, поиск только в ближайших | быстро строится, экономнее по памяти | полнота зависит от числа просматриваемых кластеров | | PQ (продуктовая квантизация) | вектор делится на части, каждая кодируется номером ближайшего центроида[3] | сжатие в десятки раз | потеря точности, нужен пересчёт лучших кандидатов | | DiskANN | граф, хранимый на SSD | миллиарды векторов на одном сервере | сложнее в эксплуатации | | ScaNN | анизотропная квантизация от Google[4] | высокая скорость на CPU | меньше интеграций | Библиотека FAISS от Meta реализует большинство этих методов и их комбинации, например IVF+PQ, на CPU и GPU.[2] Сравнивать алгоритмы на одинаковых данных позволяет открытый набор тестов ANN-Benchmarks.[6] ## Пример ```python import faiss import numpy as np d = 768 # размерность эмбеддингов xb = np.random.rand(100_000, d).astype("float32") faiss.normalize_L2(xb) # для косинусного сходства index = faiss.IndexHNSWFlat(d, 32, faiss.METRIC_INNER_PRODUCT) # 32 связи на узел index.hnsw.efConstruction = 200 index.add(xb) q = np.random.rand(1, d).astype("float32") faiss.normalize_L2(q) index.hnsw.efSearch = 64 # больше — точнее, но медленнее scores, ids = index.search(q, 5) # 5 ближайших соседей ``` В продакшене индекс обычно живёт не в памяти скрипта, а в хранилище: в [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) через расширение [pgvector](https://llmdocs.ru/wiki/pgvector.md) или в специализированной векторной базе. ## Фильтрация Реальные запросы почти всегда сочетают смысловую близость с условиями: «документы этого клиента», «товары в наличии дешевле 5000 рублей», «статьи после 2024 года». Есть два наивных подхода — отфильтровать после поиска (рискуя получить пустой результат) или до поиска (теряя преимущества индекса). Современные системы поддерживают фильтрацию прямо во время обхода индекса; при выборе хранилища стоит проверять именно поиск с фильтрами на своих данных. ## Гибридный поиск и переранжирование Эмбеддинги хорошо передают общий смысл, но слабо работают с точными совпадениями: номерами ошибок, артикулами, именами функций, редкими терминами. Поэтому распространён **гибридный поиск**: параллельно выполняются векторный и полнотекстовый поиск (BM25), а списки объединяются, например методом обратного рангового слияния (RRF), где документ получает сумму величин `1 / (60 + ранг)` из каждого списка.[5] Затем лучшие 50–100 кандидатов можно **переранжировать** более точной, но медленной моделью (*cross-encoder*, *reranker*), которая читает запрос и документ вместе. Эта двухэтапная схема — быстрый отбор и точная сортировка — стандарт качественного поиска. ## Практические советы - Используйте одну и ту же модель эмбеддингов для документов и запросов; при смене модели переиндексируйте всё. - Качество поиска чаще определяется подготовкой данных — нарезкой на фрагменты ([Чанкинг документов](https://llmdocs.ru/wiki/chunking.md)), очисткой и метаданными, — чем выбором алгоритма индекса. - Меряйте полноту на своём наборе запросов с известными правильными ответами, а не только скорость. - Начинайте с простого: точный поиск или pgvector; специализированная инфраструктура нужна на десятках миллионов векторов. ## См. также - [Эмбеддинг](https://llmdocs.ru/wiki/embedding.md) - [pgvector и векторные БД](https://llmdocs.ru/wiki/pgvector.md) - [RAG (генерация с дополнением поиском)](https://llmdocs.ru/wiki/rag.md) - [Чанкинг документов](https://llmdocs.ru/wiki/chunking.md) - [Индекс (базы данных)](https://llmdocs.ru/wiki/database-index.md) ## Источники 1. [Yu. Malkov, D. Yashunin — Efficient and robust approximate nearest neighbor search using HNSW graphs (2016)](https://arxiv.org/abs/1603.09320) 2. [J. Johnson, M. Douze, H. Jégou — Billion-scale similarity search with GPUs (FAISS, 2017)](https://arxiv.org/abs/1702.08734) 3. [H. Jégou, M. Douze, C. Schmid — Product Quantization for Nearest Neighbor Search (IEEE TPAMI, 2011)](https://ieeexplore.ieee.org/document/5432202) 4. [R. Guo et al. — Accelerating Large-Scale Inference with Anisotropic Vector Quantization (ScaNN, 2019)](https://arxiv.org/abs/1908.10396) 5. [G. Cormack et al. — Reciprocal Rank Fusion outperforms Condorcet and individual Rank Learning Methods (SIGIR 2009)](https://dl.acm.org/doi/10.1145/1571941.1572114) 6. [ANN-Benchmarks](https://ann-benchmarks.com/) --- # vLLM и инференс-серверы > Серверы для высокопроизводительного запуска больших языковых моделей — vLLM, SGLang, TGI, TensorRT-LLM; ключевые техники — PagedAttention, непрерывный батчинг, OpenAI-совместимый API. Источник: https://llmdocs.ru/wiki/vllm/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **vLLM**: UC Berkeley (Sky Computing Lab), 2023 - **Лицензия vLLM**: Apache 2.0 - **Ключевая идея**: PagedAttention — KV-кэш страницами - **API**: OpenAI-совместимый (/v1/chat/completions) - **Другие серверы**: SGLang, TGI, TensorRT-LLM, LMDeploy, llama.cpp server - **Железо**: NVIDIA, AMD, Intel, TPU, CPU **Инференс-серверы LLM** — программы, которые загружают [большую языковую модель](https://llmdocs.ru/wiki/llm.md) на GPU и обслуживают запросы многих пользователей одновременно, выжимая максимум из дорогого железа. Самый популярный открытый сервер — **vLLM**, созданный в Калифорнийском университете в Беркли. Он и его аналоги — SGLang, TGI, TensorRT-LLM — предоставляют HTTP API, совместимый с OpenAI, поэтому существующие клиенты и фреймворки работают с ними без изменений. ## Почему нужен специальный сервер Наивный запуск модели через `model.generate()` обрабатывает запросы по одному и использует GPU на несколько процентов. Генерация текста состоит из двух фаз: - **prefill** — обработка всего промпта сразу; упирается в вычисления; - **decode** — генерация по одному [токену](https://llmdocs.ru/wiki/tokenization.md) за шаг; упирается в пропускную способность памяти, потому что на каждом шаге нужно прочитать все веса модели. Чтобы decode был эффективным, нужно обрабатывать много запросов в одном батче. Но запросы разной длины начинаются и заканчиваются в разное время, а для каждого хранится **KV-кэш** — промежуточные ключи и значения механизма внимания для всех предыдущих токенов, — который занимает гигабайты и растёт с длиной [контекста](https://llmdocs.ru/wiki/context-window.md). ## Ключевые техники **PagedAttention.** Главная идея vLLM: хранить KV-кэш не сплошным куском под максимальную длину, а блоками фиксированного размера, как страницы виртуальной памяти в операционной системе.[2] Это почти устраняет фрагментацию (в ранних системах до 60–80% памяти KV-кэша пропадало), позволяет держать в батче в несколько раз больше запросов и разделять общие префиксы между запросами без копирования. **Непрерывный батчинг** (continuous batching). Новые запросы добавляются в батч на каждом шаге генерации, а завершённые сразу освобождают место — не нужно ждать окончания самого длинного ответа.[6] **Кэширование префиксов.** KV-кэш общего начала промптов (системная инструкция, документ) переиспользуется между запросами — локальный аналог [кэширования промптов](https://llmdocs.ru/wiki/prompt-caching.md) у облачных провайдеров. SGLang развивает эту идею структурой RadixAttention.[3] **Прочее.** Спекулятивное декодирование (маленькая модель предлагает токены, большая проверяет), chunked prefill, тензорный и конвейерный параллелизм на нескольких GPU, [квантизация](https://llmdocs.ru/wiki/quantization.md) (FP8, AWQ, GPTQ), обслуживание нескольких адаптеров [LoRA](https://llmdocs.ru/wiki/fine-tuning-lora.md) поверх одной модели, [структурированный вывод](https://llmdocs.ru/wiki/structured-output.md) по JSON-схеме. ## Запуск vLLM ```bash pip install vllm vllm serve Qwen/Qwen2.5-7B-Instruct \ --max-model-len 32768 --gpu-memory-utilization 0.9 ``` Сервер слушает `http://localhost:8000/v1` и принимает запросы в формате OpenAI:[1] ```python from openai import OpenAI client = OpenAI(base_url="http://localhost:8000/v1", api_key="none") r = client.chat.completions.create( model="Qwen/Qwen2.5-7B-Instruct", messages=[{"role": "user", "content": "Что такое PagedAttention?"}], ) print(r.choices[0].message.content) ``` Модели загружаются с [Hugging Face](https://llmdocs.ru/wiki/hugging-face.md); для больших моделей добавляют `--tensor-parallel-size 4`, чтобы распределить веса по четырём GPU. Есть официальный Docker-образ и Helm-чарты для [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md). ## Сравнение серверов | Сервер | Разработчик | Особенности | |---|---|---| | **vLLM** | UC Berkeley и сообщество | самая широкая поддержка моделей и железа, стандарт де-факто | | **SGLang** | LMSYS | RadixAttention, быстрый структурированный вывод, сильная производительность | | **TensorRT-LLM** | NVIDIA | максимальная скорость на GPU NVIDIA, компиляция движка под модель[4] | | **TGI** | Hugging Face | интеграция с экосистемой HF[5] | | **LMDeploy** | Shanghai AI Lab | быстрый движок TurboMind, квантизация | | **llama.cpp server**, **Ollama** | сообщество | CPU, Apple Silicon, потребительские GPU, формат [GGUF](https://llmdocs.ru/wiki/gguf.md) | Для одного пользователя на ноутбуке удобнее [llama.cpp и Ollama](https://llmdocs.ru/wiki/local-llm.md); для сервиса с десятками одновременных запросов на серверных GPU — vLLM или SGLang. ## Метрики - **TTFT** (time to first token) — задержка до первого токена, важна для чатов; - **TPOT / ITL** — время на каждый следующий токен, определяет скорость «печати»; - **пропускная способность** — токенов в секунду на весь сервер при заданной нагрузке; - **стоимость** — рублей или долларов за миллион токенов. Эти метрики конфликтуют: больший батч повышает пропускную способность, но увеличивает задержку каждого запроса. Настройку проверяют нагрузочным тестом (`vllm bench serve`) на реалистичных длинах промптов и ответов, а в продакшене экспортируют метрики сервера в [Prometheus](https://llmdocs.ru/wiki/prometheus.md). ## См. также - [Локальный запуск LLM (llama.cpp, Ollama)](https://llmdocs.ru/wiki/local-llm.md) - [Сервинг моделей](https://llmdocs.ru/wiki/model-serving.md) - [GPU и CUDA](https://llmdocs.ru/wiki/gpu-cuda.md) - [Квантизация моделей](https://llmdocs.ru/wiki/quantization.md) ## Источники 1. [vLLM Documentation](https://docs.vllm.ai/) 2. [Kwon et al. — Efficient Memory Management for LLM Serving with PagedAttention (SOSP 2023)](https://arxiv.org/abs/2309.06180) 3. [SGLang Documentation](https://docs.sglang.ai/) 4. [NVIDIA TensorRT-LLM](https://nvidia.github.io/TensorRT-LLM/) 5. [Hugging Face Text Generation Inference](https://huggingface.co/docs/text-generation-inference/) 6. [Yu et al. — Orca: A Distributed Serving System for Transformer-Based Generative Models (OSDI 2022)](https://www.usenix.org/conference/osdi22/presentation/yu) --- # Метрики качества классификации > Числовые меры качества классификаторов — accuracy, precision, recall, F1, ROC AUC, PR AUC, log loss — и правила выбора метрики под задачу. Источник: https://llmdocs.ru/wiki/classification-metrics/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Основа**: матрица ошибок (TP, FP, FN, TN) - **Пороговые метрики**: accuracy, precision, recall, F1 - **Беспороговые метрики**: ROC AUC, PR AUC (average precision) - **Вероятностные метрики**: log loss, Brier score - **Реализация**: sklearn.metrics **Метрики качества классификации** — числовые показатели, по которым оценивают и сравнивают модели, предсказывающие класс объекта: «спам / не спам», «уйдёт клиент / останется», диагноз по снимку. Единой лучшей метрики нет: выбор зависит от того, какие ошибки дороже в конкретной задаче и насколько несбалансированы классы. Метрики считают на отложенных данных, которых модель не видела, — иначе оценка будет завышена из-за [переобучения](https://llmdocs.ru/wiki/overfitting-regularization.md).[1] ## Матрица ошибок Для бинарной задачи все предсказания делятся на четыре группы: | | Предсказано «да» | Предсказано «нет» | |---|---|---| | **На самом деле «да»** | TP — верно найден | FN — пропуск (ошибка II рода) | | **На самом деле «нет»** | FP — ложная тревога (ошибка I рода) | TN — верно отклонён | Из этих четырёх чисел строятся почти все пороговые метрики. ## Основные метрики - **Accuracy** (доля правильных ответов) $= \frac{TP+TN}{\text{всего}}$. Понятна, но обманчива при дисбалансе: если мошеннических транзакций 0,5%, модель «всегда нет» даёт 99,5% accuracy и бесполезна. - **Precision** (точность) $= \frac{TP}{TP+FP}$ — какая доля найденного действительно нужного класса. Важна, когда дорого ложное срабатывание: блокировка честного пользователя, ложное обвинение. - **Recall** (полнота, чувствительность, TPR) $= \frac{TP}{TP+FN}$ — какую долю нужного класса модель нашла. Важна, когда дорог пропуск: болезнь, мошенничество, дефект. - **F1-мера** — гармоническое среднее precision и recall: $F_1 = \frac{2PR}{P+R}$. Обобщение $F_\beta$ позволяет придать полноте больший ($\beta>1$) или меньший вес. - **Специфичность** (TNR) $= \frac{TN}{TN+FP}$ — парная к полноте в медицине. - **Коэффициент корреляции Мэттьюса** (MCC) учитывает все четыре клетки матрицы и устойчив к дисбалансу.[6] Precision и recall конфликтуют: снижая порог срабатывания, модель находит больше (recall растёт), но и ошибается чаще (precision падает).[4] ## Порог и кривые Большинство моделей выдают не класс, а оценку вероятности; класс получается сравнением с **порогом** (по умолчанию 0,5, что часто неоптимально). Беспороговые метрики оценивают качество ранжирования сразу для всех порогов: - **ROC-кривая** — зависимость TPR от FPR при изменении порога; **ROC AUC** — площадь под ней. Равна вероятности того, что случайный положительный объект получит оценку выше случайного отрицательного: 0,5 — случайное угадывание, 1,0 — идеал.[2] - **PR-кривая** — зависимость precision от recall; площадь под ней — **PR AUC** (average precision). При сильном дисбалансе она информативнее ROC: ROC AUC может выглядеть высоким за счёт огромного числа легко отсекаемых отрицательных примеров.[3] ```python from sklearn.metrics import (classification_report, roc_auc_score, average_precision_score, confusion_matrix) proba = model.predict_proba(X_test)[:, 1] pred = (proba >= 0.3).astype(int) # порог под задачу, а не 0.5 print(confusion_matrix(y_test, pred)) print(classification_report(y_test, pred, digits=3)) print("ROC AUC", roc_auc_score(y_test, proba)) print("PR AUC ", average_precision_score(y_test, proba)) ``` ## Вероятностные метрики и калибровка Если важны сами вероятности (расчёт ожидаемых потерь, ставки, медицинский риск), используют **log loss** (перекрёстную энтропию) и **Brier score**. Модель может хорошо ранжировать, но выдавать смещённые вероятности; **калибровка** (Platt scaling, изотоническая регрессия) это исправляет.[5] [Бустинг](https://llmdocs.ru/wiki/gradient-boosting.md) и нейросети часто нуждаются в калибровке. ## Многоклассовый случай Метрики считаются для каждого класса «один против остальных» и усредняются: **macro** (простое среднее — все классы равноправны), **weighted** (с весами по частоте), **micro** (суммирование TP/FP/FN по всем классам — для однометочной задачи совпадает с accuracy). ## Как выбрать 1. Начать с бизнес-вопроса: что стоит пропуск и что стоит ложная тревога. 2. Для ранжирования и сравнения моделей — ROC AUC или PR AUC (при дисбалансе — PR AUC). 3. Для принятия решений — подобрать порог на валидации под нужный precision или recall, затем отчитаться на тесте. 4. Смотреть на матрицу ошибок, а не только на одно число, и оценивать разброс метрики по фолдам [кросс-валидации](https://llmdocs.ru/wiki/cross-validation.md). Для [языковых моделей](https://llmdocs.ru/wiki/llm.md) классические метрики применяются, когда задача сводится к классификации; более общие подходы описаны в статье [Оценка LLM (evals)](https://llmdocs.ru/wiki/llm-evals.md). ## См. также - [scikit-learn](https://llmdocs.ru/wiki/scikit-learn.md) - [Кросс-валидация](https://llmdocs.ru/wiki/cross-validation.md) - [Обучение с учителем и без](https://llmdocs.ru/wiki/supervised-unsupervised.md) - [Оценка LLM (evals)](https://llmdocs.ru/wiki/llm-evals.md) - [Дрейф данных](https://llmdocs.ru/wiki/data-drift.md) ## Источники 1. [scikit-learn — Metrics and scoring: quantifying the quality of predictions](https://scikit-learn.org/stable/modules/model_evaluation.html) 2. [Fawcett — An introduction to ROC analysis (2006)](https://doi.org/10.1016/j.patrec.2005.10.010) 3. [Saito, Rehmsmeier — The Precision-Recall Plot Is More Informative than the ROC Plot on Imbalanced Datasets (2015)](https://doi.org/10.1371/journal.pone.0118432) 4. [Google — Machine Learning Crash Course: Classification](https://developers.google.com/machine-learning/crash-course/classification) 5. [scikit-learn — Probability calibration](https://scikit-learn.org/stable/modules/calibration.html) 6. [Chicco, Jurman — The advantages of the Matthews correlation coefficient (2020)](https://doi.org/10.1186/s12864-019-6413-7) --- # Кросс-валидация > Метод оценки качества модели, при котором данные многократно делятся на обучающую и проверочную части; даёт устойчивую оценку и помогает подбирать гиперпараметры. Источник: https://llmdocs.ru/wiki/cross-validation/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Назначение**: оценка обобщающей способности модели - **Основной вариант**: k-fold (обычно k = 5 или 10) - **Варианты**: stratified, group, time series, leave-one-out, nested - **Реализация**: scikit-learn (sklearn.model_selection) - **Связанное**: подбор гиперпараметров, переобучение, утечка данных **Кросс-валидация** (перекрёстная проверка, англ. *cross-validation*) — способ оценить, насколько хорошо модель [машинного обучения](https://llmdocs.ru/wiki/machine-learning.md) будет работать на новых данных. Данные несколько раз делят на обучающую и проверочную части, модель обучают и проверяют на каждом разбиении, а результаты усредняют. В отличие от единственного разбиения на train/test, кросс-валидация использует все данные и для обучения, и для проверки и показывает не только среднее качество, но и его разброс. ## Зачем Качество модели на обучающих данных ничего не говорит о качестве на новых: сложная модель может просто запомнить примеры (см. [Переобучение и регуляризация](https://llmdocs.ru/wiki/overfitting-regularization.md)). Поэтому часть данных откладывают. Но одно случайное разбиение ненадёжно: на маленьком наборе оценка сильно зависит от того, какие примеры попали в тест. Кросс-валидация уменьшает эту случайность и позволяет честно сравнивать модели и гиперпараметры.[4] ## k-fold Самый распространённый вариант — **k-кратная кросс-валидация**: 1. перемешать данные и разбить на *k* равных частей (фолдов); 2. для каждого *i* от 1 до *k* обучить модель на всех фолдах, кроме *i*-го, и измерить качество на *i*-м; 3. усреднить *k* оценок и посчитать стандартное отклонение. Обычно берут *k* = 5 или 10: модель обучается на 80–90% данных, а вычислений в 5–10 раз больше, чем при одном разбиении. Крайний случай — **leave-one-out** (*k* равно числу примеров): почти несмещённая, но дорогая и шумная оценка. ```python from sklearn.model_selection import cross_val_score from sklearn.ensemble import RandomForestClassifier scores = cross_val_score(RandomForestClassifier(), X, y, cv=5, scoring="f1") print(f"F1 = {scores.mean():.3f} ± {scores.std():.3f}") ``` Метрику выбирают по задаче (см. [Метрики качества классификации](https://llmdocs.ru/wiki/classification-metrics.md)).[1] ## Варианты разбиения | Вариант | Когда использовать | |---|---| | **StratifiedKFold** | классификация с несбалансированными классами — доля классов в каждом фолде одинакова | | **GroupKFold** | у примеров есть группы (пациент, пользователь, документ), которые нельзя разрывать между train и test | | **TimeSeriesSplit** | временные ряды — обучение только на прошлом, проверка на будущем | | **RepeatedKFold** | маленький набор — несколько повторов с разными перемешиваниями | | **ShuffleSplit** | большой набор — несколько случайных разбиений произвольного размера | Для временных данных обычное перемешивание недопустимо: модель «подглядит» в будущее, и оценка окажется оптимистичной. TimeSeriesSplit расширяет обучающее окно шаг за шагом, как в реальной эксплуатации. ## Подбор гиперпараметров Кросс-валидация — основа подбора гиперпараметров: для каждой комбинации считается средняя оценка по фолдам, и выбирается лучшая.[2] ```python from sklearn.model_selection import GridSearchCV search = GridSearchCV( estimator=model, param_grid={"max_depth": [3, 5, 8], "n_estimators": [200, 500]}, cv=5, scoring="roc_auc", n_jobs=-1, ) search.fit(X_train, y_train) print(search.best_params_, search.best_score_) ``` Есть тонкость: если много раз выбирать лучшую конфигурацию по одной и той же кросс-валидации, её оценка становится смещённой вверх — модель «переобучается на валидацию».[5] Честная оценка требует отложенного тестового набора, который не участвует в подборе, или **вложенной кросс-валидации** (nested CV): внутренний цикл подбирает параметры, внешний оценивает весь процесс. ## Утечка данных Самая частая ошибка — выполнить предобработку (масштабирование, отбор признаков, заполнение пропусков, балансировку классов) на всём наборе до разбиения. Тогда статистики тестовых фолдов влияют на обучение, и оценка завышена.[3] Решение — объединить предобработку и модель в `Pipeline`, чтобы на каждом фолде всё обучалось только на обучающей части: ```python from sklearn.pipeline import make_pipeline from sklearn.preprocessing import StandardScaler from sklearn.linear_model import LogisticRegression pipe = make_pipeline(StandardScaler(), LogisticRegression(max_iter=1000)) cross_val_score(pipe, X, y, cv=StratifiedKFold(5, shuffle=True, random_state=0)) ``` Другие источники утечки — дубликаты между фолдами, признаки, вычисленные с использованием целевой переменной, и данные одного объекта по разные стороны разбиения (решается GroupKFold). ## Кросс-валидация в бустинге и глубоком обучении Для [градиентного бустинга](https://llmdocs.ru/wiki/gradient-boosting.md) кросс-валидация, помимо оценки, помогает выбрать число деревьев через раннюю остановку на каждом фолде; предсказания моделей разных фолдов часто усредняют (out-of-fold ансамбль), что популярно на соревнованиях Kaggle. В глубоком обучении, где одна модель обучается часами, обычно ограничиваются одним валидационным набором — данных достаточно, а k-кратное обучение слишком дорого. ## См. также - [Переобучение и регуляризация](https://llmdocs.ru/wiki/overfitting-regularization.md) - [scikit-learn](https://llmdocs.ru/wiki/scikit-learn.md) - [Метрики качества классификации](https://llmdocs.ru/wiki/classification-metrics.md) - [Машинное обучение](https://llmdocs.ru/wiki/machine-learning.md) ## Источники 1. [scikit-learn — Cross-validation: evaluating estimator performance](https://scikit-learn.org/stable/modules/cross_validation.html) 2. [scikit-learn — Tuning the hyper-parameters of an estimator](https://scikit-learn.org/stable/modules/grid_search.html) 3. [scikit-learn — Common pitfalls and recommended practices](https://scikit-learn.org/stable/common_pitfalls.html) 4. [Hastie, Tibshirani, Friedman — The Elements of Statistical Learning, ch. 7](https://hastie.su.domains/ElemStatLearn/) 5. [Cawley, Talbot — On Over-fitting in Model Selection (JMLR, 2010)](https://jmlr.org/papers/v11/cawley10a.html) --- # Дрейф данных > Изменение распределения входных данных или связи между признаками и целевой переменной после обучения модели; главная причина тихой деградации моделей в продакшене. Источник: https://llmdocs.ru/wiki/data-drift/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Виды**: ковариатный сдвиг, сдвиг меток, дрейф концепции - **Метрики**: PSI, KS-тест, расстояние Вассерштейна, дивергенция Дженсена — Шеннона - **Инструменты**: Evidently, NannyML, whylogs, Alibi Detect - **Реакция**: переобучение, пересмотр признаков, откат - **Связанное**: MLOps, мониторинг, Feature store **Дрейф данных** (англ. *data drift*) — изменение свойств данных, поступающих в модель машинного обучения, по сравнению с данными, на которых она обучалась. Модель неявно предполагает, что мир остаётся таким же, как в обучающей выборке; когда это перестаёт быть правдой — меняются пользователи, сезон, цены, интерфейс сайта или источник данных, — качество предсказаний падает. Опасность в том, что модель не выдаёт ошибок: она продолжает уверенно отвечать, только всё менее точно. Обнаружение дрейфа — одна из главных задач мониторинга в [MLOps](https://llmdocs.ru/wiki/mlops.md). ## Виды дрейфа Пусть модель учит зависимость *P(y | x)* — вероятность ответа *y* при признаках *x*.[1] | Вид | Что меняется | Пример | |---|---|---| | **Ковариатный сдвиг** (data drift) | распределение признаков *P(x)* | приложение вышло в новый регион — другие возраст и доход клиентов | | **Сдвиг меток** (prior shift) | доля классов *P(y)* | доля мошеннических транзакций выросла вдвое | | **Дрейф концепции** (concept drift) | сама зависимость *P(y \| x)* | после изменения правил те же признаки означают другое поведение | Дрейф бывает **внезапным** (поменялся формат поля в источнике, пандемия), **постепенным** (медленная смена аудитории), **сезонным** (праздники, выходные) и **повторяющимся**. Отдельный и очень частый случай — не настоящий дрейф, а **поломка конвейера**: признак начал приходить пустым, в других единицах или с ошибкой в джойне. ## Как обнаруживать **Если есть истинные ответы** — например, через день становится известно, вернул ли клиент кредит, — нужно напрямую считать метрики качества по свежим данным (см. [Метрики качества классификации](https://llmdocs.ru/wiki/classification-metrics.md)). Но ответы часто приходят с большой задержкой или не приходят вовсе, поэтому следят за косвенными сигналами. **Распределения признаков.** Для каждого признака сравнивают распределение в продакшене за окно (день, неделю) с эталоном — обучающей выборкой или «хорошим» периодом:[2] - **PSI** (Population Stability Index) — популярен в кредитном скоринге; по традиции PSI < 0,1 — стабильно, 0,1–0,25 — заметное изменение, > 0,25 — серьёзный сдвиг; - **тест Колмогорова — Смирнова** для числовых признаков и **хи-квадрат** для категориальных — на больших объёмах срабатывают на любые мелочи, поэтому смотрят и на величину эффекта; - **расстояние Вассерштейна** и **дивергенция Дженсена — Шеннона** — меры величины сдвига. **Распределение предсказаний.** Резкое изменение доли положительных ответов или средней уверенности модели — дешёвый и полезный сигнал. **Оценка качества без меток.** Методы вроде CBPE в NannyML оценивают ожидаемую точность по калиброванным вероятностям модели.[3] **Проверки данных.** Доля пропусков, диапазоны значений, новые категории, схема — их проверяют до модели (Great Expectations, Pandera). ## Пример ```python import numpy as np def psi(expected, actual, bins=10): edges = np.quantile(expected, np.linspace(0, 1, bins + 1)) edges[0], edges[-1] = -np.inf, np.inf e = np.histogram(expected, edges)[0] / len(expected) a = np.histogram(actual, edges)[0] / len(actual) e, a = np.clip(e, 1e-6, None), np.clip(a, 1e-6, None) return float(np.sum((a - e) * np.log(a / e))) psi(train_df["income"], prod_df["income"]) # > 0.25 — повод разбираться ``` На практике используют готовые библиотеки: **Evidently** строит отчёты по всем признакам, **NannyML**, **whylogs** и **Alibi Detect** решают похожие задачи; облачные платформы предлагают встроенный мониторинг моделей.[4] Метрики дрейфа можно экспортировать в [Prometheus](https://llmdocs.ru/wiki/prometheus.md) и настраивать алерты так же, как для сервисов. ## Что делать при дрейфе 1. **Проверить данные.** Сначала исключить поломку конвейера или источника — это самая частая причина. 2. **Оценить влияние.** Дрейф неважного признака может не влиять на качество; смотрят на важность признака и косвенные метрики. 3. **Переобучить** модель на свежих данных — по расписанию или по срабатыванию мониторинга. Нужна воспроизводимая процедура обучения ([версии данных](https://llmdocs.ru/wiki/dvc.md), конвейер, валидация перед выкладкой). 4. **Пересмотреть признаки**, если связь изменилась принципиально, — например, убрать признак, зависящий от изменившегося процесса. 5. **Откатиться** к предыдущей модели или к простому правилу, если новая версия хуже. ## Дрейф в системах с LLM Для приложений на языковых моделях дрейф проявляется иначе: меняются темы и формулировки запросов пользователей, устаревают документы в базе знаний [RAG](https://llmdocs.ru/wiki/rag.md), а провайдер может обновить модель. Здесь мониторят распределение [эмбеддингов](https://llmdocs.ru/wiki/embedding.md) запросов, долю отказов и регулярно прогоняют наборы [evals](https://llmdocs.ru/wiki/llm-evals.md). ## См. также - [MLOps](https://llmdocs.ru/wiki/mlops.md) - [Сервинг моделей](https://llmdocs.ru/wiki/model-serving.md) - [Feature store](https://llmdocs.ru/wiki/feature-store.md) - [Мониторинг и алертинг](https://llmdocs.ru/wiki/monitoring-alerting.md) ## Источники 1. [Gama et al. — A Survey on Concept Drift Adaptation (ACM Computing Surveys, 2014)](https://dl.acm.org/doi/10.1145/2523813) 2. [Evidently AI — Data drift: what it is and how to detect it](https://www.evidentlyai.com/ml-in-production/data-drift) 3. [NannyML — Performance estimation without ground truth](https://nannyml.readthedocs.io/en/stable/how_it_works/performance_estimation.html) 4. [Google Cloud — Vertex AI Model Monitoring](https://cloud.google.com/vertex-ai/docs/model-monitoring/overview) 5. [Sculley et al. — Hidden Technical Debt in Machine Learning Systems (NeurIPS 2015)](https://papers.nips.cc/paper/5656-hidden-technical-debt-in-machine-learning-systems) --- # Версионирование данных (DVC) > Управление версиями датасетов и моделей рядом с кодом; DVC хранит большие файлы во внешнем хранилище, а в Git — лишь маленькие указатели и описание конвейера. Источник: https://llmdocs.ru/wiki/dvc/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Инструмент**: DVC (Data Version Control) - **Разработчик**: Iterative.ai (с 2024 — lakeFS) - **Первый выпуск**: 2017 - **Язык**: Python - **Лицензия**: Apache 2.0 - **Хранилища**: S3, GCS, Azure, SSH, HDFS, локальный диск - **Файлы**: *.dvc, dvc.yaml, dvc.lock, .dvc/config - **Альтернативы**: Git LFS, lakeFS, Delta Lake, Hugging Face Datasets **Версионирование данных** — практика хранения истории изменений датасетов и моделей так же, как [Git](https://llmdocs.ru/wiki/git.md) хранит историю кода. Оно позволяет ответить на вопросы «на каких данных обучена эта модель?», «что изменилось в выборке между версиями?» и «как воспроизвести результат полугодовой давности?». Самый известный инструмент — **DVC** (*Data Version Control*): он работает поверх Git, но большие файлы кладёт во внешнее хранилище, оставляя в репозитории только маленькие файлы-указатели с хешами. ## Зачем Git плохо подходит для гигабайтных файлов: каждая версия навсегда остаётся в истории, клонирование становится медленным, а хостинги ограничивают размер репозитория. При этом результат машинного обучения определяется тройкой **код + данные + параметры**, и без версии данных эксперимент невоспроизводим. Версионирование данных — одна из базовых практик [MLOps](https://llmdocs.ru/wiki/mlops.md). ## Как работает DVC Команда `dvc add` вычисляет хеш файла или каталога, перемещает содержимое в локальный кэш (`.dvc/cache`) и создаёт текстовый файл-указатель:[1] ```yaml # data/train.csv.dvc outs: - md5: 3863d0e317dee0a55c4e59d2ec0eef33 size: 145276800 path: train.csv ``` Указатель коммитится в Git, а сам файл добавляется в `.gitignore`. Команда `dvc push` отправляет данные в **удалённое хранилище** (remote) — S3, Google Cloud Storage, Azure, сервер по [SSH](https://llmdocs.ru/wiki/ssh.md) или сетевой диск.[3] На другой машине `git clone` и `dvc pull` восстанавливают ровно те данные, что соответствуют коммиту. ```bash pip install "dvc[s3]" dvc init dvc remote add -d storage s3://ml-data/project dvc add data/train.csv git add data/train.csv.dvc data/.gitignore git commit -m "train: выгрузка за октябрь" dvc push # вернуться к данным прошлой версии git checkout v1.0 -- data/train.csv.dvc dvc checkout ``` Так как хранилище адресуется по хешам, одинаковые файлы не дублируются, а переключение версий сводится к замене ссылок в рабочем каталоге. ## Конвейеры DVC умеет описывать этапы обработки и обучения в `dvc.yaml` — с зависимостями, параметрами и результатами:[2] ```yaml stages: prepare: cmd: python src/prepare.py deps: [src/prepare.py, data/raw] outs: [data/prepared] train: cmd: python src/train.py deps: [src/train.py, data/prepared] params: [train.lr, train.epochs] outs: [models/model.pkl] metrics: [metrics.json] ``` `dvc repro` перезапускает только те этапы, у которых изменились входы, — как `make`, но с учётом хешей данных. Файл `dvc.lock` фиксирует хеши всех входов и выходов, поэтому коммит в Git полностью описывает, как получена модель. ## Эксперименты `dvc exp run -S train.lr=0.01` запускает эксперимент с изменёнными параметрами, не создавая коммитов; `dvc exp show` выводит таблицу экспериментов с параметрами и метриками, а лучший можно превратить в ветку.[4] Для визуального сравнения есть расширение для VS Code. Многие команды совмещают DVC (данные и конвейер) с [MLflow](https://llmdocs.ru/wiki/mlflow.md) (трекинг метрик и реестр моделей). ## Альтернативы | Инструмент | Подход | Когда подходит | |---|---|---| | **Git LFS** | большие файлы на сервере LFS, указатели в Git | бинарники и модели среднего размера; нет конвейеров[5] | | **lakeFS** | Git-подобные ветки и коммиты над объектным хранилищем | озёра данных на терабайты, много пользователей[6] | | **Delta Lake, Apache Iceberg** | версии таблиц, time travel | табличные данные в Spark и хранилищах | | **Hugging Face Datasets / Hub** | репозитории датасетов с версиями | открытые датасеты и модели (см. [Hugging Face](https://llmdocs.ru/wiki/hugging-face.md)) | | **Снимки в хранилище** | версионирование бакета S3, даты в путях | простые случаи | DVC хорош для проектов, где данные — файлы (выгрузки, изображения, аудио) размером до сотен гигабайт и где важна связь данных с коммитом кода. Для таблиц в корпоративном хранилище естественнее time travel самих таблиц. ## Практика - Храните в DVC сырые выгрузки и итоговые обучающие наборы; промежуточные результаты конвейера восстановятся через `dvc repro`. - Указывайте версию данных в метаданных модели (хеш из `dvc.lock`), чтобы связать модель в продакшене с выборкой. - В [CI/CD](https://llmdocs.ru/wiki/ci-cd.md) используйте `dvc pull` с ограниченными правами только на чтение. - Персональные и чувствительные данные в удалённом хранилище должны подчиняться тем же правилам доступа и удаления, что и исходные системы. ## См. также - [MLOps](https://llmdocs.ru/wiki/mlops.md) - [Git](https://llmdocs.ru/wiki/git.md) - [MLflow](https://llmdocs.ru/wiki/mlflow.md) - [Feature store](https://llmdocs.ru/wiki/feature-store.md) ## Источники 1. [DVC Documentation](https://dvc.org/doc) 2. [DVC — Data Pipelines](https://dvc.org/doc/start/data-pipelines/data-pipelines) 3. [DVC — Remote storage](https://dvc.org/doc/user-guide/data-management/remote-storage) 4. [DVC — Experiment management](https://dvc.org/doc/user-guide/experiment-management) 5. [Git LFS](https://git-lfs.com/) 6. [lakeFS Documentation](https://docs.lakefs.io/) --- # Эмбеддинг > Представление объекта — слова, текста, изображения, товара — в виде вектора чисел, в котором близкие по смыслу объекты оказываются рядом; основа семантического поиска и RAG. Источник: https://llmdocs.ru/wiki/embedding/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Что это**: вектор фиксированной длины, кодирующий смысл объекта - **Типичная размерность**: от 384 до 4096 - **Мера близости**: косинусное сходство, скалярное произведение - **Исторические модели**: word2vec (2013), GloVe (2014), BERT (2018) - **Текстовые модели**: Sentence-BERT, E5, BGE, модели эмбеддингов облачных провайдеров - **Бенчмарк**: MTEB - **Применение**: семантический поиск, RAG, кластеризация, рекомендации, поиск дубликатов **Эмбеддинг** (англ. *embedding* — «вложение») — представление объекта в виде вектора — списка из сотен или тысяч чисел — так, что близкие по смыслу объекты получают близкие векторы. Объектом может быть слово, предложение, целый документ, изображение, товар или пользователь. Эмбеддинги переводят «смысл» на язык геометрии: чтобы найти похожие тексты, достаточно найти ближайшие векторы. Эмбеддинги — основа [векторного поиска](https://llmdocs.ru/wiki/vector-search.md), [RAG](https://llmdocs.ru/wiki/rag.md), рекомендательных систем, кластеризации и поиска дубликатов. Внутри [трансформеров](https://llmdocs.ru/wiki/transformer.md) и языковых моделей каждый [токен](https://llmdocs.ru/wiki/tokenization.md) тоже сначала превращается в эмбеддинг. ## История Идея представлять слова векторами восходит к дистрибутивной гипотезе лингвистики: «слово узнаётся по его окружению». Практический прорыв совершил **word2vec** Томаша Миколова и коллег из Google (2013): небольшая сеть, обученная предсказывать соседние слова, давала векторы, в которых проявлялись смысловые отношения — знаменитый пример `король − мужчина + женщина ≈ королева`.[1] Вскоре появились GloVe (Стэнфорд, 2014)[6] и fastText. Векторы слов не учитывали контекст: у слова «ключ» был один вектор и для замка, и для родника. Модели на основе трансформеров — ELMo и BERT (2018) — стали давать **контекстные** эмбеддинги. В 2019 году Sentence-BERT показал, как дообучить BERT так, чтобы эмбеддинги целых предложений можно было сравнивать косинусным сходством; так появились современные модели эмбеддингов текста.[2] ## Как получают эмбеддинги Модель эмбеддингов — обычно трансформер-энкодер, обученный методом **контрастного обучения**: векторы пар «вопрос — релевантный ответ» или «перевод — оригинал» сближаются, а случайных пар — раздвигаются. На выходе любой текст превращается в вектор фиксированной длины. ```python from sentence_transformers import SentenceTransformer model = SentenceTransformer("intfloat/multilingual-e5-small") docs = ["passage: PostgreSQL — реляционная СУБД", "passage: Kubernetes управляет контейнерами", "passage: pgvector добавляет векторный поиск в Postgres"] query = "query: как искать похожие векторы в базе данных" doc_vecs = model.encode(docs, normalize_embeddings=True) q_vec = model.encode(query, normalize_embeddings=True) scores = doc_vecs @ q_vec # косинусное сходство для нормированных векторов print(scores.argsort()[::-1]) # ближайшим окажется фрагмент про pgvector ``` Библиотека Sentence Transformers даёт доступ к сотням открытых моделей с [Hugging Face](https://llmdocs.ru/wiki/hugging-face.md);[5] облачные провайдеры предлагают модели эмбеддингов через API. Некоторые модели требуют префиксов вроде `query:` и `passage:`, отличающих вопрос от документа. ## Меры близости | Мера | Формула | Замечание | |---|---|---| | Косинусное сходство | `cos θ = a·b / (‖a‖·‖b‖)` | стандарт для текстовых эмбеддингов | | Скалярное произведение | `a·b` | совпадает с косинусом для нормированных векторов, быстрее | | Евклидово расстояние | `‖a − b‖` | для нормированных векторов даёт тот же порядок, что косинус | ## Выбор модели - **Качество** сравнивают на бенчмарке MTEB, охватывающем поиск, классификацию, кластеризацию и десятки языков.[3] Для русского текста нужны мультиязычные модели или модели, обученные на русском. - **Размерность** влияет на память и скорость поиска: миллион векторов по 1024 числа с плавающей точкой занимает около 4 ГБ. Модели, обученные по схеме **Матрёшки**, позволяют обрезать вектор до первых 256 или 512 компонент почти без потери качества.[4] - **Максимальная длина входа** — длинные документы приходится разбивать на фрагменты (см. [Чанкинг документов](https://llmdocs.ru/wiki/chunking.md)). - **Одна модель на всё.** Векторы разных моделей несовместимы: при смене модели нужно пересчитать эмбеддинги всей коллекции. ## Хранение и поиск Для небольших коллекций достаточно хранить векторы в массиве NumPy и сравнивать полным перебором. Для миллионов векторов используют индексы приближённого поиска ближайших соседей — в [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) через расширение [pgvector](https://llmdocs.ru/wiki/pgvector.md) или в специализированных векторных базах. Векторы можно сжимать квантизацией — до 8 бит или даже 1 бита на компоненту — с небольшой потерей точности. ## Ограничения Эмбеддинги хорошо улавливают общий смысл, но хуже — точные совпадения: артикулы, номера версий, редкие имена и отрицания («без сахара»). Поэтому в поисковых системах векторный поиск сочетают с классическим полнотекстовым (BM25) — **гибридный поиск** — и уточняют результаты переранжированием. ## См. также - [Векторный поиск](https://llmdocs.ru/wiki/vector-search.md) - [pgvector и векторные БД](https://llmdocs.ru/wiki/pgvector.md) - [RAG (генерация с дополнением поиском)](https://llmdocs.ru/wiki/rag.md) - [Трансформер (архитектура)](https://llmdocs.ru/wiki/transformer.md) - [Чанкинг документов](https://llmdocs.ru/wiki/chunking.md) ## Источники 1. [T. Mikolov et al. — Efficient Estimation of Word Representations in Vector Space (2013)](https://arxiv.org/abs/1301.3781) 2. [N. Reimers, I. Gurevych — Sentence-BERT (2019)](https://arxiv.org/abs/1908.10084) 3. [N. Muennighoff et al. — MTEB: Massive Text Embedding Benchmark (2022)](https://arxiv.org/abs/2210.07316) 4. [A. Kusupati et al. — Matryoshka Representation Learning (2022)](https://arxiv.org/abs/2205.13147) 5. [Sentence Transformers — документация](https://sbert.net/) 6. [J. Pennington, R. Socher, C. Manning — GloVe: Global Vectors for Word Representation (2014)](https://nlp.stanford.edu/projects/glove/) --- # Feature store > Хранилище признаков для машинного обучения — единое место, где признаки вычисляются, версионируются и одинаково отдаются для обучения и для онлайн-инференса. Источник: https://llmdocs.ru/wiki/feature-store/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Появление**: Uber Michelangelo (2017) - **Компоненты**: офлайн-хранилище, онлайн-хранилище, реестр признаков - **Ключевая задача**: устранить training-serving skew - **Open source**: Feast, Hopsworks, Featureform - **Коммерческие**: Tecton, Databricks Feature Store, SageMaker Feature Store, Vertex AI - **Онлайн-хранилища**: Redis, DynamoDB, Cassandra **Feature store** (хранилище признаков) — компонент [MLOps](https://llmdocs.ru/wiki/mlops.md)-платформы, который хранит признаки (features) для моделей машинного обучения и выдаёт их в двух режимах: большими историческими выборками для обучения и по одной сущности с минимальной задержкой для онлайн-предсказаний. Признак — например, «число заказов пользователя за 30 дней» — описывается один раз, а все модели и команды используют одно и то же определение. Главная цель — чтобы модель в продакшене получала признаки, вычисленные ровно так же, как при обучении. ## Проблема Без общего хранилища каждая команда пишет свои SQL-запросы для обучения в ноутбуке, а затем отдельный код на сервисе для онлайн-вычислений. Возникают типичные проблемы: - **training-serving skew** — признак в продакшене считается иначе, чем при обучении (другой часовой пояс, другая обработка пропусков), и модель тихо деградирует; - **утечка из будущего** — при сборке обучающей выборки к событию присоединяется значение признака, известное только позже; - **дублирование** — десять команд по-разному считают «активность пользователя»; - **задержка** — тяжёлые агрегаты невозможно вычислить за миллисекунды во время запроса. Идею хранилища признаков популяризировала Uber, описав в 2017 году платформу Michelangelo с общим Feature Store.[2] ## Архитектура | Компонент | Что хранит | Для чего | Примеры | |---|---|---|---| | **Офлайн-хранилище** | полная история значений признаков | обучение, бэктесты, батч-инференс | BigQuery, Snowflake, [ClickHouse](https://llmdocs.ru/wiki/clickhouse.md), Parquet в S3 | | **Онлайн-хранилище** | последнее значение для каждой сущности | инференс за миллисекунды | [Redis](https://llmdocs.ru/wiki/redis.md), DynamoDB, Cassandra | | **Реестр** | определения, владельцы, версии | поиск и повторное использование | метаданные в базе | | **Конвейеры** | вычисление и загрузка (materialization) | пакетные и потоковые расчёты | Spark, Flink, dbt | Признаки вычисляются конвейерами из исходных данных, пишутся в офлайн-хранилище и периодически **материализуются** в онлайн-хранилище. Потоковые признаки (например, «число транзакций за последние 5 минут» для антифрода) обновляются в реальном времени из Kafka. ## Point-in-time join Ключевая функция для обучения — **соединение на момент времени**: для каждого примера (пользователь, момент события) берётся значение признака, актуальное *именно тогда*, а не последнее.[3] Если модель предсказывает отток на 1 марта, признак «число заказов за 30 дней» должен быть посчитан на 1 марта, а не на сегодня. Ручная реализация таких соединений — частый источник ошибок, и feature store берёт её на себя. ## Пример: Feast Feast — самый распространённый открытый feature store; признаки описываются кодом на Python:[1] ```python from datetime import timedelta from feast import Entity, FeatureView, Field, FileSource from feast.types import Float32, Int64 user = Entity(name="user", join_keys=["user_id"]) user_stats = FeatureView( name="user_stats", entities=[user], ttl=timedelta(days=1), schema=[Field(name="orders_30d", dtype=Int64), Field(name="avg_check", dtype=Float32)], source=FileSource(path="data/user_stats.parquet", timestamp_field="event_ts"), ) ``` Обучающая выборка и онлайн-запрос: ```python # обучение: point-in-time join к таблице событий train_df = store.get_historical_features( entity_df=events_df, features=["user_stats:orders_30d", "user_stats:avg_check"] ).to_df() # инференс: последнее значение из онлайн-хранилища store.get_online_features( features=["user_stats:orders_30d"], entity_rows=[{"user_id": 42}] ).to_dict() ``` Команда `feast materialize-incremental` переносит свежие значения в онлайн-хранилище. ## Когда нужен Feature store оправдан, когда: - модели работают онлайн и требуют свежих признаков с малой задержкой (рекомендации, антифрод, ценообразование); - одни и те же признаки используют несколько моделей и команд; - уже были инциденты из-за расхождения обучения и продакшена. Для одной модели с пакетным инференсом раз в сутки обычно достаточно витрины данных в хранилище, SQL-трансформаций в dbt и [версионирования данных](https://llmdocs.ru/wiki/dvc.md). Внедрение feature store — заметная инфраструктурная работа, и начинать её стоит с конкретной боли, а не «на вырост». ## Связь с другими инструментами Feature store дополняет реестр моделей и трекинг экспериментов ([MLflow](https://llmdocs.ru/wiki/mlflow.md)), системы [сервинга](https://llmdocs.ru/wiki/model-serving.md) запрашивают из него признаки при каждом предсказании, а мониторинг сравнивает распределения признаков в продакшене с обучающими, чтобы ловить [дрейф данных](https://llmdocs.ru/wiki/data-drift.md). Похожая идея применяется и к [эмбеддингам](https://llmdocs.ru/wiki/embedding.md): векторные представления пользователей и товаров хранятся и отдаются так же, как обычные признаки. ## См. также - [MLOps](https://llmdocs.ru/wiki/mlops.md) - [Сервинг моделей](https://llmdocs.ru/wiki/model-serving.md) - [Дрейф данных](https://llmdocs.ru/wiki/data-drift.md) - [Версионирование данных (DVC)](https://llmdocs.ru/wiki/dvc.md) ## Источники 1. [Feast — Documentation](https://docs.feast.dev/) 2. [Uber Engineering — Meet Michelangelo: Uber's Machine Learning Platform](https://www.uber.com/blog/michelangelo-machine-learning-platform/) 3. [Feast — Point-in-time joins](https://docs.feast.dev/getting-started/concepts/point-in-time-joins) 4. [Hopsworks — What is a Feature Store](https://www.hopsworks.ai/dictionary/feature-store) 5. [Google Cloud — Vertex AI Feature Store overview](https://cloud.google.com/vertex-ai/docs/featurestore/latest/overview) --- # GPU и CUDA > Графические процессоры как массово-параллельные ускорители вычислений и платформа NVIDIA CUDA для программирования их; основа обучения и инференса нейросетей. Источник: https://llmdocs.ru/wiki/gpu-cuda/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **CUDA**: Compute Unified Device Architecture (NVIDIA, 2007) - **Модель программирования**: ядра (kernels), сетка блоков потоков, варпы по 32 потока - **Библиотеки**: cuBLAS, cuDNN, NCCL, TensorRT - **Альтернативы**: AMD ROCm/HIP, Apple Metal (MPS), Intel oneAPI, Google TPU - **Ключевые параметры**: объём и пропускная способность памяти, FLOPS в FP16/BF16/FP8 - **Утилита мониторинга**: nvidia-smi **GPU** (англ. *graphics processing unit* — графический процессор) — процессор с тысячами простых вычислительных ядер, изначально созданный для отрисовки графики и ставший главным ускорителем для [нейросетей](https://llmdocs.ru/wiki/neural-network.md). **CUDA** — платформа и модель программирования NVIDIA, позволяющая запускать на GPU произвольные вычисления. Почти всё современное глубокое обучение, от обучения [больших языковых моделей](https://llmdocs.ru/wiki/llm.md) до их инференса, выполняется на GPU NVIDIA через CUDA, хотя альтернативы постепенно развиваются.[1] ## Почему GPU Центральный процессор (CPU) — несколько десятков мощных ядер, оптимизированных для последовательной логики с ветвлениями. GPU — тысячи упрощённых ядер, выполняющих одну и ту же операцию над разными данными. Нейросети в основном состоят из умножений матриц, которые идеально распараллеливаются, поэтому GPU выполняет их в десятки и сотни раз быстрее. Поворотным моментом стала сеть AlexNet (2012): обученная на двух игровых видеокартах, она с большим отрывом выиграла конкурс ImageNet и запустила бум глубокого обучения.[3] ## CUDA NVIDIA выпустила CUDA в 2007 году. Программист пишет **ядро** (kernel) — функцию, которая выполняется параллельно множеством потоков; потоки организованы в блоки, блоки — в сетку. Аппаратно потоки исполняются группами по 32 (**варпы**), а у каждого блока есть быстрая общая память.[1] На практике ядра пишут редко: фреймворки вроде [PyTorch](https://llmdocs.ru/wiki/pytorch.md) вызывают оптимизированные библиотеки — **cuBLAS** (линейная алгебра), **cuDNN** (операции нейросетей), **NCCL** (обмен данными между GPU), **TensorRT** (оптимизация инференса). Для собственных ядер всё чаще используют язык Triton от OpenAI, генерирующий код из Python. Пример оптимизированного ядра — FlashAttention, ускоряющий механизм внимания [трансформеров](https://llmdocs.ru/wiki/transformer.md) за счёт работы в быстрой памяти чипа.[7] ```python import torch print(torch.cuda.is_available(), torch.cuda.get_device_name(0)) x = torch.randn(8192, 8192, device="cuda", dtype=torch.bfloat16) y = x @ x # выполняется на GPU через cuBLAS torch.cuda.synchronize() # вызовы асинхронны — ждём завершения ``` ```bash nvidia-smi # загрузка, память, температура, процессы nvidia-smi -l 1 # обновление раз в секунду ``` ## Что важно в GPU для ML - **Объём видеопамяти (VRAM)** — часто главный ограничитель: модель, активации, градиенты и состояние оптимизатора должны поместиться. Для инференса модели в 7 млрд параметров в 16-битной точности нужно около 14 ГБ на веса плюс память на KV-кэш.[6] - **Пропускная способность памяти** — при генерации текста LLM упирается именно в неё, а не в вычисления. - **Тензорные ядра** — специализированные блоки для матричных операций в пониженной точности (FP16, BF16, FP8, FP4), дающие основной прирост скорости. - **Связь между GPU** — NVLink и InfiniBand для обучения на многих картах. | Класс | Примеры | Память | |---|---|---| | Игровые | RTX 4090, RTX 5090 | 24–32 ГБ | | Рабочие станции | RTX 6000 Ada / Blackwell | 48–96 ГБ | | Дата-центр | A100, H100, H200, B200 | 40–192 ГБ HBM | ## Смешанная точность Обучение в 16-битных форматах (BF16, FP16) вдвое сокращает память и многократно ускоряет вычисления на тензорных ядрах; критичные части (накопление сумм, главная копия весов) остаются в FP32.[4] Для инференса веса сжимают ещё сильнее — до 8 и 4 бит; см. [Квантизация моделей](https://llmdocs.ru/wiki/quantization.md). ## Альтернативы CUDA - **AMD ROCm** и язык HIP, близкий к CUDA; PyTorch поддерживает ROCm официально.[5] - **Apple Silicon** — общая память CPU и GPU, бэкенд MPS в PyTorch и фреймворк MLX; удобен для локального запуска моделей. - **Google TPU**, AWS Trainium, Intel Gaudi — специализированные ускорители в облаках. Привязка экосистемы к CUDA («CUDA lock-in») — одна из причин доминирования NVIDIA на рынке. ## В контейнерах GPU пробрасывается в [Docker](https://llmdocs.ru/wiki/docker.md)-контейнер через NVIDIA Container Toolkit (`docker run --gpus all`), в [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) — через device plugin, после чего поды запрашивают ресурс `nvidia.com/gpu`. Версия драйвера на хосте должна быть не ниже требуемой версией CUDA в образе. ## См. также - [PyTorch](https://llmdocs.ru/wiki/pytorch.md) - [Квантизация моделей](https://llmdocs.ru/wiki/quantization.md) - [Локальный запуск LLM (llama.cpp, Ollama)](https://llmdocs.ru/wiki/local-llm.md) - [vLLM и инференс-серверы](https://llmdocs.ru/wiki/vllm.md) - [Сервинг моделей](https://llmdocs.ru/wiki/model-serving.md) ## Источники 1. [NVIDIA — CUDA C++ Programming Guide](https://docs.nvidia.com/cuda/cuda-c-programming-guide/) 2. [PyTorch — CUDA semantics](https://pytorch.org/docs/stable/notes/cuda.html) 3. [Krizhevsky, Sutskever, Hinton — ImageNet Classification with Deep CNNs (2012)](https://papers.nips.cc/paper/4824-imagenet-classification-with-deep-convolutional-neural-networks) 4. [NVIDIA — Mixed Precision Training](https://docs.nvidia.com/deeplearning/performance/mixed-precision-training/) 5. [AMD ROCm — документация](https://rocm.docs.amd.com/) 6. [Hugging Face — Model memory anatomy](https://huggingface.co/docs/transformers/model_memory_anatomy) 7. [Dao et al. — FlashAttention (2022)](https://arxiv.org/abs/2205.14135) --- # Градиентный бустинг (XGBoost, CatBoost, LightGBM) > Ансамблевый метод, последовательно добавляющий решающие деревья, каждое из которых исправляет ошибки предыдущих; лучший выбор для табличных данных. Источник: https://llmdocs.ru/wiki/gradient-boosting/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: ансамбль решающих деревьев - **Теория**: Джером Фридман, «Greedy Function Approximation» (1999–2001) - **XGBoost**: Тяньци Чэнь, 2014 - **LightGBM**: Microsoft, 2016 - **CatBoost**: Яндекс, 2017 - **Применение**: табличные данные — скоринг, отток, ранжирование, прогноз спроса **Градиентный бустинг** (англ. *gradient boosting*) — метод [машинного обучения](https://llmdocs.ru/wiki/machine-learning.md), который строит сильную модель как сумму множества слабых — обычно неглубоких решающих деревьев. Деревья добавляются последовательно, и каждое новое учится исправлять ошибки уже построенного ансамбля. Реализации XGBoost, LightGBM и CatBoost годами доминируют в задачах на **табличных данных** — кредитный скоринг, прогноз оттока, ранжирование, предсказание спроса — и обычно обходят там нейросети.[5] ## Идея Бустинг как идею «усиления» слабых моделей сформулировали Шапир и Фройнд в 1990-х (алгоритм AdaBoost). Джером Фридман в 1999–2001 годах обобщил его: добавление каждого дерева — это шаг [градиентного спуска](https://llmdocs.ru/wiki/gradient-descent.md), только не по весам, а в пространстве функций.[1] Алгоритм для функции потерь $L$: 1. Начать с константы $F_0$ (например, среднего значения целевой переменной). 2. На шаге $m$ вычислить для каждого объекта **антиградиент** потерь — для квадратичной ошибки это просто остатки $y - F_{m-1}(x)$. 3. Обучить небольшое дерево $h_m$ предсказывать эти остатки. 4. Обновить модель: $F_m = F_{m-1} + \eta \, h_m$, где $\eta$ — темп обучения (shrinkage), обычно 0,01–0,1. Выбор функции потерь задаёт задачу: квадратичная — регрессия, логистическая — классификация, специальные попарные и списочные потери — ранжирование. В отличие от случайного леса, где деревья независимы и усредняются (снижается разброс), в бустинге деревья зависимы и уменьшают смещение — поэтому бустинг точнее, но легче [переобучается](https://llmdocs.ru/wiki/overfitting-regularization.md). ## Реализации | | XGBoost | LightGBM | CatBoost | |---|---|---|---| | Автор | Тяньци Чэнь (2014) | Microsoft (2016) | Яндекс (2017) | | Рост деревьев | по уровням | по листьям (leaf-wise) | симметричные (oblivious) | | Категориальные признаки | базовая поддержка | встроенная | сильная сторона: target statistics | | Особенности | регуляризация в целевой функции, стандарт индустрии[2] | гистограммы, GOSS, EFB — самая быстрая на больших данных[3] | упорядоченный бустинг против утечки, хорош «из коробки»[4] | Все три поддерживают GPU, пропуски в данных, раннюю остановку, распределённое обучение и интерфейс, совместимый со [scikit-learn](https://llmdocs.ru/wiki/scikit-learn.md). В самом scikit-learn есть быстрый `HistGradientBoostingClassifier`, построенный по образцу LightGBM. ## Пример ```python from catboost import CatBoostClassifier from sklearn.model_selection import train_test_split X_train, X_val, y_train, y_val = train_test_split(X, y, stratify=y, random_state=0) model = CatBoostClassifier( iterations=3000, learning_rate=0.05, depth=6, eval_metric="AUC", cat_features=["city", "device"], # категории без one-hot early_stopping_rounds=200, verbose=500, ) model.fit(X_train, y_train, eval_set=(X_val, y_val)) print(model.get_feature_importance(prettified=True).head(10)) ``` ## Основные гиперпараметры - **Число деревьев и темп обучения** — связаны: меньший темп требует больше деревьев и обычно даёт лучший результат. Число деревьев подбирают **ранней остановкой** по валидации. - **Глубина / число листьев** — сложность отдельного дерева; типично 4–10 уровней. - **Подвыборки** строк и признаков (`subsample`, `colsample_bytree`) — вносят случайность и снижают переобучение. - **Регуляризация** листьев (L1/L2), минимальное число объектов в листе.[6] Подбор удобно автоматизировать (Optuna) с честной [кросс-валидацией](https://llmdocs.ru/wiki/cross-validation.md); для временных рядов — с разбиением по времени. ## Интерпретация Важность признаков доступна «из коробки», но может вводить в заблуждение; точнее объясняют предсказания значения SHAP, для деревьев вычисляемые быстро и точно. Это важно в регулируемых областях вроде банковского скоринга. Качество классификаторов оценивают ROC AUC, PR AUC и другими [метриками](https://llmdocs.ru/wiki/classification-metrics.md). ## Когда не подходит Изображения, звук, тексты — область нейросетей и [эмбеддингов](https://llmdocs.ru/wiki/embedding.md) (которые, впрочем, нередко подают бустингу как признаки). Деревья плохо экстраполируют: за пределами диапазона обучающих данных предсказание остаётся константой. Для продакшена модели экспортируют в собственные бинарные форматы или [ONNX](https://llmdocs.ru/wiki/onnx.md). ## См. также - [Градиентный спуск](https://llmdocs.ru/wiki/gradient-descent.md) - [scikit-learn](https://llmdocs.ru/wiki/scikit-learn.md) - [Переобучение и регуляризация](https://llmdocs.ru/wiki/overfitting-regularization.md) - [Метрики качества классификации](https://llmdocs.ru/wiki/classification-metrics.md) - [MLOps](https://llmdocs.ru/wiki/mlops.md) ## Источники 1. [Friedman — Greedy Function Approximation: A Gradient Boosting Machine (2001)](https://projecteuclid.org/journals/annals-of-statistics/volume-29/issue-5/Greedy-function-approximation-A-gradient-boosting-machine/10.1214/aos/1013203451.full) 2. [Chen, Guestrin — XGBoost: A Scalable Tree Boosting System (2016)](https://arxiv.org/abs/1603.02754) 3. [Ke et al. — LightGBM: A Highly Efficient Gradient Boosting Decision Tree (NeurIPS 2017)](https://papers.nips.cc/paper/6907-lightgbm-a-highly-efficient-gradient-boosting-decision-tree) 4. [Prokhorenkova et al. — CatBoost: unbiased boosting with categorical features (2018)](https://arxiv.org/abs/1706.09516) 5. [Grinsztajn et al. — Why do tree-based models still outperform deep learning on tabular data? (2022)](https://arxiv.org/abs/2207.08815) 6. [XGBoost — Parameters](https://xgboost.readthedocs.io/en/stable/parameter.html) 7. [CatBoost — документация](https://catboost.ai/docs/) --- # Градиентный спуск > Итеративный метод оптимизации, сдвигающий параметры модели против градиента функции потерь; в стохастических вариантах (SGD, Adam) — основа обучения нейросетей. Источник: https://llmdocs.ru/wiki/gradient-descent/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: метод оптимизации первого порядка - **Предложен**: Огюстен Коши (1847) - **Стохастический вариант**: Роббинс и Монро (1951) - **Ключевой гиперпараметр**: темп обучения (learning rate) - **Популярные оптимизаторы**: SGD с моментом, Adam, AdamW - **Вычисление градиента в нейросетях**: обратное распространение ошибки **Градиентный спуск** (англ. *gradient descent*) — итеративный метод поиска минимума функции: на каждом шаге параметры сдвигаются в направлении, противоположном градиенту, то есть туда, где функция убывает быстрее всего. В [машинном обучении](https://llmdocs.ru/wiki/machine-learning.md) минимизируется **функция потерь** — мера ошибки модели на данных, — а параметрами служат веса модели. Почти все [нейросети](https://llmdocs.ru/wiki/neural-network.md), включая [большие языковые модели](https://llmdocs.ru/wiki/llm.md), обучаются одним из вариантов градиентного спуска.[3] ## Идея Градиент $\nabla L(\theta)$ — вектор частных производных функции потерь по каждому параметру; он указывает направление наискорейшего роста. Шаг обновления: $$\theta \leftarrow \theta - \eta \, \nabla L(\theta)$$ где $\eta$ — **темп обучения** (learning rate). Образ — спуск с горы в тумане: видно только наклон под ногами, и путник каждый раз шагает вниз по склону. Метод описал Огюстен Коши в 1847 году. Для нейросетей он стал практичным после популяризации **обратного распространения ошибки** (backpropagation, 1986) — алгоритма, вычисляющего градиент по всем весам за один проход назад по сети с помощью цепного правила.[6] Сейчас это делают автоматически фреймворки вроде [PyTorch](https://llmdocs.ru/wiki/pytorch.md). ## Темп обучения Самый важный гиперпараметр. Слишком маленький темп — обучение идёт мучительно долго и застревает; слишком большой — шаги «перепрыгивают» минимум, потери скачут или уходят в бесконечность. На практике темп меняют по **расписанию**: короткий разогрев (warmup) с нуля, затем плавное снижение — косинусное или ступенчатое. ## Варианты по объёму данных | Вариант | Градиент считается по | Свойства | |---|---|---| | Полный (batch) | всей выборке | точный, но дорогой шаг; не помещается в память | | Стохастический (SGD) | одному примеру | шумный, дешёвый шаг | | Мини-батч | группе из 32–4096 примеров | компромисс, стандарт на практике | Стохастический подход восходит к работе Роббинса и Монро 1951 года.[5] Шум мини-батчей не только экономит вычисления, но и помогает выбираться из неудачных областей и, по-видимому, способствует лучшему обобщению. Под «SGD» сегодня почти всегда понимают мини-батчевый вариант. ## Оптимизаторы Поверх базового шага придуманы улучшения:[1] - **Момент** (momentum) — накапливает «скорость» из предыдущих градиентов, сглаживая колебания в узких оврагах функции потерь. Вариант — момент Нестерова. - **Адаптивные методы** — AdaGrad, RMSProp — подбирают свой темп для каждого параметра по истории его градиентов. - **Adam** (2014) сочетает момент и адаптивный темп и стал выбором по умолчанию для нейросетей.[2] **AdamW** правильно отделяет регуляризацию весов от шага (см. [Переобучение и регуляризация](https://llmdocs.ru/wiki/overfitting-regularization.md)) и используется при обучении трансформеров. ```python import torch model = torch.nn.Linear(10, 1) opt = torch.optim.AdamW(model.parameters(), lr=1e-3, weight_decay=0.01) loss_fn = torch.nn.MSELoss() for xb, yb in loader: # мини-батчи opt.zero_grad() loss = loss_fn(model(xb), yb) loss.backward() # обратное распространение: градиенты opt.step() # шаг градиентного спуска ``` ## Трудности - **Невыпуклость.** У нейросетей функция потерь имеет множество локальных минимумов и седловых точек. На практике в высокой размерности плохие локальные минимумы редки, а от сёдел спасает шум SGD. - **Затухание и взрыв градиентов** в глубоких сетях — решаются нормализацией, остаточными связями и обрезкой градиента (gradient clipping). - **Масштаб признаков.** Признаки разного порядка вытягивают поверхность потерь, и спуск идёт зигзагом; помогает стандартизация. - **Память.** Adam хранит два дополнительных значения на каждый параметр, поэтому оптимизатор занимает больше памяти, чем сама модель; для больших моделей используют шардирование состояния и смешанную точность. ## Где ещё применяется [Градиентный бустинг](https://llmdocs.ru/wiki/gradient-boosting.md) — тоже градиентный спуск, только в пространстве функций: каждое новое дерево аппроксимирует антиградиент потерь. Линейные модели в [scikit-learn](https://llmdocs.ru/wiki/scikit-learn.md) (`SGDClassifier`) обучаются SGD на данных, не помещающихся в память. ## См. также - [Нейронная сеть](https://llmdocs.ru/wiki/neural-network.md) - [PyTorch](https://llmdocs.ru/wiki/pytorch.md) - [Переобучение и регуляризация](https://llmdocs.ru/wiki/overfitting-regularization.md) - [Градиентный бустинг (XGBoost, CatBoost, LightGBM)](https://llmdocs.ru/wiki/gradient-boosting.md) ## Источники 1. [Ruder — An overview of gradient descent optimization algorithms (2016)](https://arxiv.org/abs/1609.04747) 2. [Kingma, Ba — Adam: A Method for Stochastic Optimization (2014)](https://arxiv.org/abs/1412.6980) 3. [Goodfellow, Bengio, Courville — Deep Learning, гл. 8](https://www.deeplearningbook.org/contents/optimization.html) 4. [PyTorch — torch.optim](https://pytorch.org/docs/stable/optim.html) 5. [Robbins, Monro — A Stochastic Approximation Method (1951)](https://projecteuclid.org/journals/annals-of-mathematical-statistics/volume-22/issue-3/A-Stochastic-Approximation-Method/10.1214/aoms/1177729586.full) 6. [Rumelhart, Hinton, Williams — Learning representations by back-propagating errors (1986)](https://www.nature.com/articles/323533a0) --- # Hugging Face > Компания и платформа-хаб для открытых моделей, датасетов и демо, а также набор библиотек — Transformers, Datasets, Tokenizers, PEFT, Accelerate. Источник: https://llmdocs.ru/wiki/hugging-face/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Основана**: 2016, Нью-Йорк - **Основатели**: Клеман Деланг, Жюльен Шомон, Тома Вольф - **Продукты**: Hub (модели, датасеты, Spaces), библиотеки, Inference Endpoints - **Ключевые библиотеки**: transformers, datasets, tokenizers, huggingface_hub, peft, accelerate, diffusers - **Формат весов**: safetensors - **Сайт**: huggingface.co **Hugging Face** — компания и одноимённая платформа, ставшая центральным хранилищем открытых моделей [машинного обучения](https://llmdocs.ru/wiki/machine-learning.md). На **Hub** размещены миллионы моделей, сотни тысяч датасетов и интерактивных демо (Spaces) — от классических BERT до открытых [больших языковых моделей](https://llmdocs.ru/wiki/llm.md) Llama, Qwen, Mistral и DeepSeek. Вторая половина экосистемы — библиотеки на [Python](https://llmdocs.ru/wiki/python.md), прежде всего **Transformers**, позволяющие загрузить и запустить почти любую модель в несколько строк.[1] ## История Компания основана в 2016 году в Нью-Йорке французскими предпринимателями и начинала с чат-бота для подростков (отсюда название — эмодзи 🤗 «обнимающее лицо»). В 2018 году команда выложила PyTorch-реализацию модели BERT, которая быстро превратилась в библиотеку `pytorch-transformers`, а затем `transformers` — единый интерфейс к десяткам архитектур [трансформеров](https://llmdocs.ru/wiki/transformer.md).[3] Вокруг библиотеки вырос Hub, и компания сменила профиль на платформу для открытого ИИ. Hugging Face также участвует в открытых исследованиях: модель BLOOM (проект BigScience), семейство SmolLM, наборы данных FineWeb. ## Hub Hub устроен как «GitHub для моделей»: каждая модель, датасет или Space — это [Git](https://llmdocs.ru/wiki/git.md)-репозиторий с большими файлами в LFS-подобном хранилище.[1] - **Карточка модели** (model card) — README с описанием, назначением, ограничениями, лицензией и метаданными для поиска.[4] - **Версии** — коммиты и ветки; загрузку можно закрепить за конкретной ревизией. - **Доступ** — открытые, закрытые и «gated» модели, требующие принять лицензию. - **Spaces** — демо-приложения на Gradio, Streamlit или в [Docker](https://llmdocs.ru/wiki/docker.md). - **Таблицы лидеров**, сравнение моделей, наборы (collections), обсуждения и pull request прямо в репозитории. Для безопасности Hub продвигает формат **safetensors**: в отличие от `pickle`-файлов PyTorch, он хранит только тензоры и не может выполнить произвольный код при загрузке.[5] Файлы также сканируются на вредоносное содержимое. ```bash pip install -U huggingface_hub hf auth login # токен для закрытых моделей hf download Qwen/Qwen3-8B --local-dir ./qwen3 # скачать репозиторий ``` Скачанное кэшируется в `~/.cache/huggingface`; переменная `HF_HOME` меняет расположение, `HF_HUB_OFFLINE=1` включает автономный режим.[6] ## Библиотеки | Библиотека | Назначение | |---|---| | `transformers` | модели и пайплайны для текста, изображений, звука; обучение через `Trainer` | | `datasets` | загрузка и обработка датасетов с отображением в память (Apache Arrow) | | `tokenizers` | быстрые токенизаторы на Rust (см. [Токен и токенизация](https://llmdocs.ru/wiki/tokenization.md)) | | `huggingface_hub` | работа с Hub из кода и CLI | | `peft` | эффективное дообучение: LoRA и другие адаптеры (см. [Fine-tuning и LoRA](https://llmdocs.ru/wiki/fine-tuning-lora.md)) | | `accelerate` | запуск на многих GPU и в смешанной точности без переписывания кода | | `diffusers` | диффузионные модели для генерации изображений и видео | | `sentence-transformers` | модели [эмбеддингов](https://llmdocs.ru/wiki/embedding.md) для поиска | | `trl` | дообучение по предпочтениям (DPO, RLHF) | ```python from transformers import pipeline clf = pipeline("sentiment-analysis", model="blanchefort/rubert-base-cased-sentiment") print(clf("Документация наконец-то понятная!")) chat = pipeline("text-generation", model="Qwen/Qwen3-0.6B", device_map="auto") print(chat([{"role": "user", "content": "Что такое GIL?"}], max_new_tokens=200)) ``` Transformers работает поверх [PyTorch](https://llmdocs.ru/wiki/pytorch.md); для продакшен-инференса языковых моделей чаще используют специализированные серверы — [vLLM, TGI, SGLang](https://llmdocs.ru/wiki/vllm.md), которые загружают модели прямо с Hub. Квантованные версии моделей в формате [GGUF](https://llmdocs.ru/wiki/gguf.md) для [локального запуска](https://llmdocs.ru/wiki/local-llm.md) тоже публикуются на Hub. ## Коммерческие услуги Inference Endpoints (выделенные серверы для модели), Inference Providers (единый API к моделям у разных провайдеров), платные аккаунты PRO и Enterprise с приватными хранилищами и SSO. ## Доступность из России Сайт и загрузка моделей работают с перебоями; распространённые обходы — зеркала (переменная `HF_ENDPOINT`), предварительное скачивание через сервер за рубежом и локальное хранение моделей. ## См. также - [Трансформер (архитектура)](https://llmdocs.ru/wiki/transformer.md) - [PyTorch](https://llmdocs.ru/wiki/pytorch.md) - [Fine-tuning и LoRA](https://llmdocs.ru/wiki/fine-tuning-lora.md) - [GGUF](https://llmdocs.ru/wiki/gguf.md) - [MLflow](https://llmdocs.ru/wiki/mlflow.md) ## Источники 1. [Hugging Face Hub — документация](https://huggingface.co/docs/hub/index) 2. [Transformers — документация](https://huggingface.co/docs/transformers/index) 3. [Wolf et al. — Transformers: State-of-the-Art Natural Language Processing (2020)](https://aclanthology.org/2020.emnlp-demos.6/) 4. [Hugging Face — Model Cards](https://huggingface.co/docs/hub/model-cards) 5. [safetensors — документация](https://huggingface.co/docs/safetensors/index) 6. [huggingface_hub — CLI](https://huggingface.co/docs/huggingface_hub/guides/cli) --- # Машинное обучение > Раздел искусственного интеллекта, изучающий алгоритмы, которые учатся решать задачи по данным, а не по явно запрограммированным правилам. Источник: https://llmdocs.ru/wiki/machine-learning/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Термин**: Артур Сэмюэл (1959) - **Основные виды**: обучение с учителем, без учителя, с подкреплением - **Задачи**: классификация, регрессия, кластеризация, ранжирование, генерация - **Популярные методы**: линейные модели, деревья и бустинг, нейронные сети - **Библиотеки**: scikit-learn, XGBoost, CatBoost, PyTorch, JAX - **Смежные области**: статистика, оптимизация, анализ данных **Машинное обучение** (англ. *machine learning*, ML) — раздел искусственного интеллекта, изучающий алгоритмы, которые улучшают решение задачи на основе опыта, то есть данных, а не следуют вручную написанным правилам. Вместо того чтобы программировать, как отличить спам от обычного письма, разработчик показывает модели тысячи размеченных писем, и она сама находит закономерности. Машинное обучение лежит в основе поиска и рекомендаций, распознавания речи и изображений, кредитного скоринга, машинного перевода и [больших языковых моделей](https://llmdocs.ru/wiki/llm.md). ## Определение и история Термин ввёл Артур Сэмюэл из IBM: в 1959 году он описал программу для игры в шашки, которая улучшала игру, анализируя свои партии.[1] Классическое определение дал Том Митчелл (1997): программа обучается на опыте E относительно задачи T и меры качества P, если её качество на задаче T, измеренное P, растёт с опытом E.[2] Развитие шло волнами. Перцептрон Розенблатта (1958) вызвал первую волну интереса к [нейросетям](https://llmdocs.ru/wiki/neural-network.md); в 1990–2000-х доминировали статистические методы — метод опорных векторов, случайный лес, [градиентный бустинг](https://llmdocs.ru/wiki/gradient-boosting.md). В 2012 году свёрточная сеть AlexNet с большим отрывом выиграла конкурс ImageNet, начав эпоху **глубокого обучения**.[5] С 2017 года архитектура [трансформер](https://llmdocs.ru/wiki/transformer.md) привела к современным языковым моделям. ## Виды обучения | Вид | Данные | Задачи | Примеры | |---|---|---|---| | С учителем (*supervised*) | примеры с правильными ответами | классификация, регрессия | спам-фильтр, прогноз цены | | Без учителя (*unsupervised*) | данные без ответов | кластеризация, снижение размерности, поиск аномалий | сегментация клиентов | | Самообучение (*self-supervised*) | ответы извлекаются из самих данных | предсказание следующего слова, восстановление фрагментов | предобучение LLM, [эмбеддинги](https://llmdocs.ru/wiki/embedding.md) | | С подкреплением (*reinforcement*) | награды за действия в среде | управление, игры, выравнивание моделей | AlphaGo, RLHF | Подробнее о первых двух — в статье [Обучение с учителем и без](https://llmdocs.ru/wiki/supervised-unsupervised.md). ## Как устроен процесс 1. **Постановка задачи** — что предсказываем и как измерим успех в терминах бизнеса. 2. **Сбор и разметка данных** — чаще всего самая дорогая часть. 3. **Подготовка признаков** — очистка, кодирование категорий, нормализация, новые признаки. 4. **Обучение** — подбор параметров модели, минимизирующих функцию потерь, обычно [градиентным спуском](https://llmdocs.ru/wiki/gradient-descent.md) или его вариантами. 5. **Оценка** — на отложенных данных, которые модель не видела, с помощью подходящих [метрик](https://llmdocs.ru/wiki/classification-metrics.md) и [кросс-валидации](https://llmdocs.ru/wiki/cross-validation.md). 6. **Внедрение и мониторинг** — модель обслуживает запросы, а за качеством и сдвигом данных следят; этим занимается [MLOps](https://llmdocs.ru/wiki/mlops.md). ## Пример Обучение классификатора в [scikit-learn](https://llmdocs.ru/wiki/scikit-learn.md):[3] ```python from sklearn.datasets import load_breast_cancer from sklearn.model_selection import train_test_split from sklearn.ensemble import HistGradientBoostingClassifier from sklearn.metrics import classification_report X, y = load_breast_cancer(return_X_y=True) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, stratify=y, random_state=42) model = HistGradientBoostingClassifier(max_iter=200, learning_rate=0.1) model.fit(X_train, y_train) # обучение на 80% данных print(classification_report(y_test, model.predict(X_test))) # оценка на отложенных 20% ``` ## Ключевые понятия - **Признаки и целевая переменная** — входные данные модели и то, что она предсказывает. - **Функция потерь** — число, показывающее, насколько ошибается модель; обучение — её минимизация. - **Обобщение** — способность работать на новых данных. Модель, запомнившая обучающую выборку, **переобучена**; слишком простая — **недообучена** (см. [Переобучение и регуляризация](https://llmdocs.ru/wiki/overfitting-regularization.md)). - **Гиперпараметры** — настройки, которые не обучаются, а задаются: глубина деревьев, скорость обучения, число слоёв. - **Утечка данных** — когда в признаки случайно попадает информация о правильном ответе, недоступная в реальной работе; даёт прекрасные метрики на тесте и провал в продакшене. ## Классическое ML и глубокое обучение Для табличных данных (строки и столбцы, как в базе) чаще всего лучше работают градиентный бустинг и линейные модели: они быстрее обучаются, проще интерпретируются и требуют меньше данных. Глубокие нейросети незаменимы для неструктурированных данных — текста, изображений, звука — и для больших объёмов, где они обучаются на [GPU](https://llmdocs.ru/wiki/gpu-cuda.md) с помощью фреймворков вроде [PyTorch](https://llmdocs.ru/wiki/pytorch.md).[6] Практичный путь в изучение — бесплатные курсы, например Machine Learning Crash Course от Google.[4] ## См. также - [Обучение с учителем и без](https://llmdocs.ru/wiki/supervised-unsupervised.md) - [Нейронная сеть](https://llmdocs.ru/wiki/neural-network.md) - [Переобучение и регуляризация](https://llmdocs.ru/wiki/overfitting-regularization.md) - [scikit-learn](https://llmdocs.ru/wiki/scikit-learn.md) - [MLOps](https://llmdocs.ru/wiki/mlops.md) ## Источники 1. [A. L. Samuel — Some Studies in Machine Learning Using the Game of Checkers (IBM Journal, 1959)](https://ieeexplore.ieee.org/document/5392560) 2. [Tom M. Mitchell — Machine Learning (McGraw Hill, 1997)](https://www.cs.cmu.edu/~tom/mlbook.html) 3. [scikit-learn — User Guide](https://scikit-learn.org/stable/user_guide.html) 4. [Google — Machine Learning Crash Course](https://developers.google.com/machine-learning/crash-course) 5. [Krizhevsky, Sutskever, Hinton — ImageNet Classification with Deep Convolutional Neural Networks (NeurIPS 2012)](https://papers.nips.cc/paper_files/paper/2012/hash/c399862d3b9d6b76c8436e924a68c45b-Abstract.html) 6. [I. Goodfellow, Y. Bengio, A. Courville — Deep Learning (MIT Press, 2016)](https://www.deeplearningbook.org/) --- # MLflow > Открытая платформа для жизненного цикла ML — трекинг экспериментов, реестр моделей, упаковка и сервинг; с версии 3 также трассировка и оценка LLM-приложений. Источник: https://llmdocs.ru/wiki/mlflow/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Разработчик**: Databricks, сообщество (Linux Foundation) - **Первый выпуск**: июнь 2018 - **Язык**: Python (также API для R, Java, TypeScript) - **Компоненты**: Tracking, Models, Model Registry, Projects, Tracing, Evaluation - **Хранилище метаданных**: файлы, SQLite, PostgreSQL, MySQL - **Хранилище артефактов**: локальный диск, S3, GCS, Azure Blob - **Лицензия**: Apache 2.0 - **Сайт**: mlflow.org **MLflow** — открытая платформа для управления жизненным циклом моделей [машинного обучения](https://llmdocs.ru/wiki/machine-learning.md): журналирования экспериментов, хранения и версионирования моделей, их упаковки и развёртывания. Это один из самых распространённых инструментов [MLOps](https://llmdocs.ru/wiki/mlops.md): он не привязан к конкретной библиотеке и работает с [scikit-learn](https://llmdocs.ru/wiki/scikit-learn.md), [PyTorch](https://llmdocs.ru/wiki/pytorch.md), XGBoost, [Hugging Face](https://llmdocs.ru/wiki/hugging-face.md) и другими. Последние версии добавили трассировку и оценку приложений на [больших языковых моделях](https://llmdocs.ru/wiki/llm.md).[1] ## История MLflow представила компания Databricks в 2018 году; среди авторов — Матей Захария, создатель Apache Spark.[5] Мотивом была типичная боль ML-команд: результаты экспериментов разбросаны по ноутбукам и таблицам, неясно, какой код и какие данные дали модель в продакшене, а каждая библиотека сохраняет модели по-своему. Проект с самого начала открыт и в 2020 году передан в Linux Foundation. Версия 2.0 вышла в 2022-м, 3.0 — в 2025 году с упором на генеративный ИИ. ## Компоненты | Компонент | Назначение | |---|---| | **Tracking** | журнал запусков: параметры, метрики, артефакты, теги, версия кода | | **Models** | единый формат упаковки модели («flavor») с окружением и сигнатурой | | **Model Registry** | реестр с версиями, псевдонимами (`champion`), описаниями | | **Projects** | воспроизводимый запуск кода с описанием окружения (используется редко) | | **Tracing / Evaluation** | трассировка вызовов LLM и агентов, оценка ответов | ### Tracking Единица учёта — **запуск** (run), запуски группируются в **эксперименты**.[2] ```python import mlflow from sklearn.ensemble import RandomForestClassifier mlflow.set_tracking_uri("http://mlflow.internal:5000") mlflow.set_experiment("churn") with mlflow.start_run(run_name="rf-baseline"): params = {"n_estimators": 300, "max_depth": 8} model = RandomForestClassifier(**params).fit(X_train, y_train) mlflow.log_params(params) mlflow.log_metric("roc_auc", roc_auc_score(y_val, model.predict_proba(X_val)[:, 1])) mlflow.sklearn.log_model(model, name="model", input_example=X_val[:5]) ``` Вызов `mlflow.autolog()` включает автоматическое журналирование для поддерживаемых библиотек. Веб-интерфейс (`mlflow ui` или `mlflow server`) позволяет сортировать запуски, сравнивать графики метрик и выбирать лучшую модель. ### Модели и реестр Модель сохраняется как каталог с файлом `MLmodel`, описанием зависимостей (`requirements.txt`, `conda.yaml`) и сигнатурой входа и выхода. Универсальный интерфейс **pyfunc** позволяет загрузить любую модель одинаково: `mlflow.pyfunc.load_model(uri).predict(df)`. **Реестр моделей** хранит версии под общим именем. Вместо устаревших стадий Staging/Production используются **псевдонимы**: приложение загружает `models:/churn@champion`, а смена продакшен-версии сводится к переназначению псевдонима — без изменения кода.[3] ### Развёртывание `mlflow models serve` поднимает REST-сервер для модели, `mlflow models build-docker` собирает [Docker](https://llmdocs.ru/wiki/docker.md)-образ; также есть интеграции с Kubernetes (через KServe и Seldon), SageMaker и Azure ML. Подробнее о подходах — в статье [Сервинг моделей](https://llmdocs.ru/wiki/model-serving.md). ## MLflow для LLM С версии 3 MLflow трассирует цепочки вызовов LLM-приложений: каждый вызов модели, инструмента и поиска записывается как span с входами, выходами, задержкой и стоимостью — по стандарту [OpenTelemetry](https://llmdocs.ru/wiki/opentelemetry.md).[4] Автотрассировка есть для OpenAI, Anthropic, LangChain, LlamaIndex и других. Модуль оценки позволяет прогонять наборы вопросов и оценивать ответы правилами или моделью-судьёй — см. [Оценка LLM (evals)](https://llmdocs.ru/wiki/llm-evals.md). Также поддерживается реестр промптов с версиями. ## Развёртывание сервера Для команды сервер запускают с базой метаданных и объектным хранилищем артефактов: ```bash mlflow server \ --backend-store-uri postgresql://mlflow:***@db/mlflow \ --artifacts-destination s3://ml-artifacts \ --host 0.0.0.0 --port 5000 ``` Встроенная аутентификация минимальна; на практике сервер ставят за [обратный прокси](https://llmdocs.ru/wiki/reverse-proxy.md) с SSO. Управляемые версии предлагают Databricks, AWS SageMaker, Azure ML и Nebius. ## Альтернативы Weights & Biases и Comet (облачные, с сильной визуализацией), ClearML, Neptune, Aim; для версионирования данных MLflow часто сочетают с [DVC](https://llmdocs.ru/wiki/dvc.md). ## См. также - [MLOps](https://llmdocs.ru/wiki/mlops.md) - [Сервинг моделей](https://llmdocs.ru/wiki/model-serving.md) - [Версионирование данных (DVC)](https://llmdocs.ru/wiki/dvc.md) - [Оценка LLM (evals)](https://llmdocs.ru/wiki/llm-evals.md) - [Hugging Face](https://llmdocs.ru/wiki/hugging-face.md) ## Источники 1. [MLflow — документация](https://mlflow.org/docs/latest/) 2. [MLflow Tracking](https://mlflow.org/docs/latest/ml/tracking/) 3. [MLflow Model Registry](https://mlflow.org/docs/latest/ml/model-registry/) 4. [MLflow — Tracing for GenAI](https://mlflow.org/docs/latest/genai/tracing/) 5. [Zaharia et al. — Accelerating the Machine Learning Lifecycle with MLflow (2018)](https://people.eecs.berkeley.edu/~matei/papers/2018/ieee_mlflow.pdf) 6. [MLflow — GitHub](https://github.com/mlflow/mlflow) --- # MLOps > Набор практик и инструментов для надёжной разработки, развёртывания и сопровождения моделей машинного обучения в продакшене — перенос идей DevOps на ML. Источник: https://llmdocs.ru/wiki/mlops/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Полное название**: Machine Learning Operations - **Истоки**: DevOps, статья Google «Hidden Technical Debt in Machine Learning Systems» (2015) - **Этапы**: данные, обучение, оценка, развёртывание, мониторинг - **Отслеживание экспериментов**: MLflow, Weights & Biases - **Данные и признаки**: DVC, Feast, lakeFS - **Оркестрация**: Airflow, Kubeflow, Prefect, Dagster - **Сервинг**: KServe, BentoML, Triton, vLLM - **Мониторинг**: Evidently, Prometheus, Grafana **MLOps** (англ. *Machine Learning Operations*) — набор практик, процессов и инструментов, позволяющих надёжно доводить модели [машинного обучения](https://llmdocs.ru/wiki/machine-learning.md) от эксперимента до продакшена и поддерживать их работу. Это перенос идей DevOps — автоматизации, [CI/CD](https://llmdocs.ru/wiki/ci-cd.md), мониторинга, воспроизводимости — на системы, поведение которых определяется не только кодом, но и данными. Без MLOps типичная судьба модели — ноутбук на компьютере исследователя, который никто не может воспроизвести, или модель в продакшене, качество которой тихо деградирует месяцами. ## Почему ML сложнее обычного ПО В 2015 году инженеры Google опубликовали статью «Скрытый технический долг в системах машинного обучения»: код самой модели — лишь малая часть реальной ML-системы, а вокруг него — сбор и проверка данных, извлечение признаков, конфигурация, инфраструктура обслуживания и мониторинг.[1] Специфические трудности: - **Три артефакта вместо одного.** Результат зависит от кода, данных и гиперпараметров; изменение любого из них меняет модель. - **Тихие отказы.** Модель не падает с ошибкой — она просто начинает ошибаться чаще, когда меняются входные данные ([Дрейф данных](https://llmdocs.ru/wiki/data-drift.md)). - **Недетерминированность.** Повторное обучение даёт немного другую модель; без фиксации версий и случайных зёрен невозможно понять, что изменилось. - **Связь обучения и обслуживания.** Признаки должны вычисляться одинаково при обучении и в продакшене, иначе возникает перекос (*training-serving skew*). ## Жизненный цикл | Этап | Что делается | Инструменты | |---|---|---| | Данные | сбор, проверка, версионирование, разметка | [DVC](https://llmdocs.ru/wiki/dvc.md), lakeFS, Great Expectations | | Признаки | единые вычисления для обучения и инференса | [Feature store](https://llmdocs.ru/wiki/feature-store.md) (Feast) | | Эксперименты | обучение, логирование параметров и метрик | [MLflow](https://llmdocs.ru/wiki/mlflow.md), Weights & Biases | | Конвейер обучения | автоматическое переобучение | Airflow, Kubeflow Pipelines, Dagster | | Реестр моделей | версии, стадии (staging, production), метаданные | MLflow Model Registry | | Развёртывание | API, пакетная обработка, на устройстве | [KServe, BentoML, Triton](https://llmdocs.ru/wiki/model-serving.md), [Docker](https://llmdocs.ru/wiki/docker.md), [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) | | Мониторинг | качество, дрейф, задержки, стоимость | Evidently, [Prometheus](https://llmdocs.ru/wiki/prometheus.md), Grafana | ## Уровни зрелости Google описывает три уровня автоматизации:[2] - **Уровень 0 — ручной процесс.** Исследователь обучает модель в ноутбуке и передаёт файл инженерам; переобучение редкое и ручное. - **Уровень 1 — автоматизированный конвейер обучения.** Переобучение на свежих данных запускается по расписанию или по сигналу, модель проверяется и выкатывается автоматически (*continuous training*). - **Уровень 2 — CI/CD для конвейеров.** Сам конвейер обучения тестируется, собирается и развёртывается автоматически, что позволяет быстро проверять новые идеи. Мартин Фаулер и коллеги описали похожий подход под названием CD4ML — непрерывная поставка для машинного обучения.[3] ## Пример: отслеживание экспериментов ```python import mlflow from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import f1_score mlflow.set_experiment("churn") with mlflow.start_run(): params = {"n_estimators": 300, "max_depth": 8} model = RandomForestClassifier(**params).fit(X_train, y_train) mlflow.log_params(params) mlflow.log_metric("f1", f1_score(y_test, model.predict(X_test))) mlflow.sklearn.log_model(model, name="model", registered_model_name="churn-rf") ``` Каждый запуск сохраняет параметры, метрики и саму модель; в веб-интерфейсе MLflow запуски можно сравнить, а лучшую модель — перевести в продакшен через реестр.[4] ## Мониторинг В продакшене отслеживают несколько слоёв: 1. **Сервисные метрики** — задержка, ошибки, нагрузка, стоимость (как у любого сервиса, см. [Мониторинг и алертинг](https://llmdocs.ru/wiki/monitoring-alerting.md)). 2. **Данные на входе** — пропуски, выход значений за привычные диапазоны, сдвиг распределений признаков. 3. **Предсказания** — распределение ответов модели, доля уверенных предсказаний. 4. **Качество** — истинные метрики, когда становятся известны правильные ответы (часто с задержкой). Библиотеки вроде Evidently строят отчёты о дрейфе данных и качестве модели.[6] Сигнал о деградации запускает расследование или автоматическое переобучение. ## LLMOps С распространением [языковых моделей](https://llmdocs.ru/wiki/llm.md) появилось направление **LLMOps**. Модели обычно не обучают, а используют через API или дообучают; на первый план выходят версионирование промптов, [оценка качества](https://llmdocs.ru/wiki/llm-evals.md) на наборах тестовых вопросов, трассировка цепочек вызовов агентов, контроль стоимости токенов и защита от [prompt injection](https://llmdocs.ru/wiki/prompt-injection.md). Базовые принципы — воспроизводимость, автоматические проверки, мониторинг — остаются теми же.[5] ## См. также - [MLflow](https://llmdocs.ru/wiki/mlflow.md) - [Сервинг моделей](https://llmdocs.ru/wiki/model-serving.md) - [Дрейф данных](https://llmdocs.ru/wiki/data-drift.md) - [CI/CD](https://llmdocs.ru/wiki/ci-cd.md) - [Машинное обучение](https://llmdocs.ru/wiki/machine-learning.md) ## Источники 1. [D. Sculley et al. — Hidden Technical Debt in Machine Learning Systems (NeurIPS 2015)](https://papers.nips.cc/paper_files/paper/2015/hash/86df7dcfd896fcaf2674f757a2463eba-Abstract.html) 2. [Google Cloud — MLOps: Continuous delivery and automation pipelines in machine learning](https://cloud.google.com/architecture/mlops-continuous-delivery-and-automation-pipelines-in-machine-learning) 3. [Martin Fowler — Continuous Delivery for Machine Learning (CD4ML)](https://martinfowler.com/articles/cd4ml.html) 4. [MLflow — документация](https://mlflow.org/docs/latest/index.html) 5. [ml-ops.org — MLOps Principles](https://ml-ops.org/content/mlops-principles) 6. [Evidently — документация](https://docs.evidentlyai.com/) --- # Сервинг моделей > Развёртывание обученных ML-моделей для получения предсказаний в продакшене — онлайн через API, пакетно или потоково; инструменты, метрики и паттерны выката. Источник: https://llmdocs.ru/wiki/model-serving/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Режимы**: онлайн (REST/gRPC), пакетный (batch), потоковый, на устройстве - **Ключевые метрики**: задержка p50/p99, пропускная способность, стоимость запроса - **Универсальные серверы**: Triton, KServe, BentoML, Ray Serve, TorchServe - **Серверы LLM**: vLLM, TGI, SGLang, llama.cpp - **Форматы**: ONNX, TorchScript, SavedModel, GGUF **Сервинг моделей** (англ. *model serving*), или **инференс**, — этап [MLOps](https://llmdocs.ru/wiki/mlops.md), на котором обученная модель [машинного обучения](https://llmdocs.ru/wiki/machine-learning.md) разворачивается так, чтобы другие системы могли получать от неё предсказания. Обучение происходит редко и может длиться часами, а сервинг работает постоянно и должен отвечать быстро, надёжно и дёшево. Именно здесь модель начинает приносить пользу — и здесь же возникает большая часть инженерных проблем ML-систем.[5] ## Режимы | Режим | Как | Когда | |---|---|---| | **Онлайн** | синхронный запрос по [REST](https://llmdocs.ru/wiki/rest.md) или gRPC, ответ за миллисекунды | скоринг заявки, рекомендации, чат-бот | | **Пакетный** | периодический прогон по таблице, результат в БД | ночной прогноз спроса, рассылки | | **Потоковый** | обработка событий из очереди (Kafka) | антифрод, мониторинг | | **На устройстве** | модель внутри приложения или браузера | офлайн-работа, приватность, без затрат на сервер | Пакетный режим проще и дешевле; онлайн нужен, когда признаки появляются в момент запроса. Многие системы сочетают оба: тяжёлые признаки предвычисляются пакетно и кладутся в [Feature store](https://llmdocs.ru/wiki/feature-store.md), а лёгкая модель отвечает онлайн. ## Простейший вариант Модель загружается в веб-приложение один раз при старте: ```python # app.py — минимальный онлайн-сервинг import joblib from fastapi import FastAPI from pydantic import BaseModel model = joblib.load("model.joblib") app = FastAPI() class Features(BaseModel): age: int income: float city: str @app.post("/predict") def predict(f: Features): proba = model.predict_proba([[f.age, f.income, f.city]])[0, 1] return {"churn_probability": float(proba)} ``` Такой сервис на [FastAPI](https://llmdocs.ru/wiki/fastapi.md) упаковывают в [Docker](https://llmdocs.ru/wiki/docker.md)-образ и запускают в [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) за балансировщиком. Для небольших моделей этого достаточно. ## Специализированные серверы При росте нагрузки и числа моделей используют готовые серверы:[1][2][3] - **NVIDIA Triton** — много фреймворков и [ONNX](https://llmdocs.ru/wiki/onnx.md), динамический батчинг, несколько моделей на одном [GPU](https://llmdocs.ru/wiki/gpu-cuda.md), ансамбли. - **KServe** — стандартный протокол инференса поверх Kubernetes, автомасштабирование до нуля, канареечные выкаты. - **BentoML**, **Ray Serve** — упаковка Python-кода с моделями, композиция моделей в графы.[6] - **MLflow** — `mlflow models serve` для быстрого старта из [реестра моделей](https://llmdocs.ru/wiki/mlflow.md). Для языковых моделей — отдельный класс серверов с непрерывным батчингом и управлением KV-кэшем: [vLLM, TGI, SGLang](https://llmdocs.ru/wiki/vllm.md); для локального запуска — [llama.cpp и Ollama](https://llmdocs.ru/wiki/local-llm.md). ## Производительность - **Задержка** (latency) — важны хвосты распределения, p95 и p99, а не среднее. - **Пропускная способность** (throughput) — запросы или токены в секунду. - **Батчинг** — объединение запросов повышает загрузку GPU ценой небольшой задержки. - **Оптимизация модели** — [квантизация](https://llmdocs.ru/wiki/quantization.md), дистилляция, компиляция (TensorRT, ONNX Runtime, `torch.compile`). - **Холодный старт** — загрузка большой модели занимает минуты, что мешает масштабированию до нуля. ## Выкат и безопасность изменений Новые версии модели выкатывают постепенно:[4] - **Теневой режим** (shadow) — новая модель получает копию трафика, её ответы только журналируются. - **Канареечный выкат** — небольшая доля трафика, затем увеличение. - **A/B-тест** — сравнение по бизнес-метрикам. - **Быстрый откат** — переключение на предыдущую версию одной командой. ## Мониторинг Помимо обычных метрик сервиса (ошибки, задержка, ресурсы — см. [Мониторинг и алертинг](https://llmdocs.ru/wiki/monitoring-alerting.md)) нужно следить за качеством: распределение входных признаков и предсказаний меняется со временем — это [Дрейф данных](https://llmdocs.ru/wiki/data-drift.md). Частая ошибка — **расхождение обучения и сервинга** (training-serving skew): признаки в продакшене вычисляются иначе, чем при обучении, и модель тихо деградирует.[5] ## Стоимость Для нейросетей основная статья расходов — GPU, которые простаивают ночью и перегружены днём. Снижают затраты автомасштабирование по длине очереди запросов, размещение нескольких небольших моделей на одной карте, перенос нетребовательных моделей на CPU и кэширование повторяющихся ответов. Для языковых моделей стоимость считают в токенах: выгоднее всего короткие промпты, переиспользование префикса ([Кэширование промптов](https://llmdocs.ru/wiki/prompt-caching.md)) и выбор самой маленькой модели, которая справляется с задачей. Иногда дешевле не держать собственный сервер, а обращаться к внешнему API, — решение зависит от объёма трафика, требований к приватности данных и задержке. ## См. также - [MLOps](https://llmdocs.ru/wiki/mlops.md) - [MLflow](https://llmdocs.ru/wiki/mlflow.md) - [vLLM и инференс-серверы](https://llmdocs.ru/wiki/vllm.md) - [ONNX](https://llmdocs.ru/wiki/onnx.md) - [Дрейф данных](https://llmdocs.ru/wiki/data-drift.md) ## Источники 1. [NVIDIA Triton Inference Server — документация](https://docs.nvidia.com/deeplearning/triton-inference-server/user-guide/docs/) 2. [KServe — документация](https://kserve.github.io/website/) 3. [BentoML — документация](https://docs.bentoml.com/) 4. [Google Cloud — MLOps: Continuous delivery and automation pipelines in machine learning](https://cloud.google.com/architecture/mlops-continuous-delivery-and-automation-pipelines-in-machine-learning) 5. [Sculley et al. — Hidden Technical Debt in Machine Learning Systems (2015)](https://papers.nips.cc/paper/5656-hidden-technical-debt-in-machine-learning-systems) 6. [Ray Serve — документация](https://docs.ray.io/en/latest/serve/index.html) --- # Нейронная сеть > Модель машинного обучения из слоёв простых вычислительных элементов (нейронов), параметры которой подбираются по данным методом обратного распространения ошибки; основа глубокого обучения. Источник: https://llmdocs.ru/wiki/neural-network/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Первая модель нейрона**: Маккаллок и Питтс (1943) - **Перцептрон**: Фрэнк Розенблатт (1958) - **Обратное распространение**: Румельхарт, Хинтон, Уильямс (1986) - **Прорыв глубокого обучения**: AlexNet (2012) - **Основные архитектуры**: полносвязные, свёрточные (CNN), рекуррентные (RNN, LSTM), трансформеры - **Фреймворки**: PyTorch, JAX, TensorFlow - **Награды**: премия Тьюринга 2018 (Хинтон, Лекун, Бенджио), Нобелевская премия по физике 2024 (Хопфилд, Хинтон) **Нейронная сеть** (искусственная нейронная сеть, нейросеть) — модель [машинного обучения](https://llmdocs.ru/wiki/machine-learning.md), составленная из множества простых вычислительных элементов — **нейронов**, организованных в слои. Каждый нейрон вычисляет взвешенную сумму входов и пропускает её через нелинейную функцию; веса всех связей подбираются по данным так, чтобы сеть выдавала нужные ответы. Сети со многими слоями называют **глубокими**, а их обучение — **глубоким обучением**. Нейросети распознают изображения и речь, переводят тексты, рекомендуют контент и лежат в основе [больших языковых моделей](https://llmdocs.ru/wiki/llm.md). Идея вдохновлена биологическим мозгом, но современные сети — это прежде всего математические функции с миллиардами параметров. ## История Уоррен Маккаллок и Уолтер Питтс в 1943 году описали математическую модель нейрона как логического элемента. В 1958 году Фрэнк Розенблатт создал **перцептрон** — первую обучаемую сеть, распознававшую простые изображения.[2] Книга Минского и Пейперта «Перцептроны» (1969) показала ограничения однослойных сетей, и интерес к области надолго угас. Возрождение пришло в 1986 году, когда Дэвид Румельхарт, Джеффри Хинтон и Рональд Уильямс популяризировали **обратное распространение ошибки** для обучения многослойных сетей.[1] Ян Лекун применил свёрточные сети к распознаванию рукописных цифр, а Хохрайтер и Шмидхубер в 1997 году предложили LSTM для последовательностей. Настоящий прорыв случился в 2012 году: сеть AlexNet, обученная на GPU, выиграла конкурс ImageNet.[3] Хинтон, Лекун и Бенджио получили премию Тьюринга (2018), а Джон Хопфилд и Хинтон — Нобелевскую премию по физике (2024) за основополагающие работы по нейросетям.[5] ## Как устроена Нейрон получает входы `x₁…xₙ`, умножает их на веса `w₁…wₙ`, прибавляет смещение `b` и применяет **функцию активации**: `y = f(w·x + b)`. Нейроны объединены в слои: входной принимает данные, скрытые слои вычисляют промежуточные представления, выходной даёт ответ. Без нелинейной активации любая многослойная сеть сводилась бы к одной линейной функции. Популярные активации: | Функция | Формула | Где используется | |---|---|---| | ReLU | `max(0, x)` | скрытые слои, стандарт по умолчанию | | GELU, SiLU | гладкие варианты ReLU | трансформеры | | Сигмоида | `1 / (1 + e⁻ˣ)` | вероятность в бинарной классификации | | Softmax | нормированная экспонента | вероятности классов, распределение по токенам | Теорема об универсальной аппроксимации утверждает, что даже сеть с одним скрытым слоем достаточного размера может приблизить любую непрерывную функцию; на практике глубокие сети достигают того же гораздо экономнее. ## Обучение 1. **Прямой проход.** Данные проходят через сеть, получается предсказание. 2. **Функция потерь** измеряет ошибку: перекрёстная энтропия для классификации, среднеквадратичная ошибка для регрессии. 3. **Обратное распространение** по правилу дифференцирования сложной функции вычисляет градиент потерь по каждому весу. 4. **Шаг оптимизации.** Веса сдвигаются против градиента — [градиентный спуск](https://llmdocs.ru/wiki/gradient-descent.md) и его варианты (SGD с моментом, Adam, AdamW). Цикл повторяется на мини-пакетах данных тысячи и миллионы раз. Чтобы сеть не запомнила обучающие данные, применяют регуляризацию: dropout, затухание весов, аугментацию, раннюю остановку (см. [Переобучение и регуляризация](https://llmdocs.ru/wiki/overfitting-regularization.md)).[4] ## Пример Небольшая полносвязная сеть в [PyTorch](https://llmdocs.ru/wiki/pytorch.md):[6] ```python import torch from torch import nn model = nn.Sequential( nn.Linear(784, 256), nn.ReLU(), nn.Linear(256, 128), nn.ReLU(), nn.Linear(128, 10), # 10 классов, например цифры 0–9 ) loss_fn = nn.CrossEntropyLoss() optimizer = torch.optim.AdamW(model.parameters(), lr=1e-3) for x, y in train_loader: # x: [batch, 784], y: [batch] logits = model(x) # прямой проход loss = loss_fn(logits, y) optimizer.zero_grad() loss.backward() # обратное распространение optimizer.step() # обновление весов ``` ## Архитектуры | Архитектура | Идея | Применение | |---|---|---| | Полносвязная (MLP) | каждый нейрон связан со всеми нейронами предыдущего слоя | табличные данные, блоки внутри других сетей | | Свёрточная (CNN) | общие фильтры скользят по изображению, улавливая локальные признаки | компьютерное зрение | | Рекуррентная (RNN, LSTM, GRU) | состояние передаётся от шага к шагу последовательности | речь, временные ряды (до трансформеров) | | [Трансформер](https://llmdocs.ru/wiki/transformer.md) | механизм внимания связывает все элементы последовательности | языковые модели, зрение, звук | | Автокодировщики, диффузионные модели | сжатие и генерация данных | генерация изображений, [эмбеддинги](https://llmdocs.ru/wiki/embedding.md) | ## Практические аспекты Глубокие сети требуют много данных и вычислений, поэтому их обучают на [GPU](https://llmdocs.ru/wiki/gpu-cuda.md) и специализированных ускорителях. Чаще всего модель не обучают с нуля, а берут предобученную — например, с [Hugging Face](https://llmdocs.ru/wiki/hugging-face.md) — и дообучают под свою задачу ([fine-tuning](https://llmdocs.ru/wiki/fine-tuning-lora.md)). Для ускорения работы в продакшене применяют [квантизацию](https://llmdocs.ru/wiki/quantization.md) и экспорт в оптимизированные форматы. ## См. также - [Трансформер (архитектура)](https://llmdocs.ru/wiki/transformer.md) - [Градиентный спуск](https://llmdocs.ru/wiki/gradient-descent.md) - [PyTorch](https://llmdocs.ru/wiki/pytorch.md) - [Машинное обучение](https://llmdocs.ru/wiki/machine-learning.md) - [GPU и CUDA](https://llmdocs.ru/wiki/gpu-cuda.md) ## Источники 1. [D. Rumelhart, G. Hinton, R. Williams — Learning representations by back-propagating errors (Nature, 1986)](https://www.nature.com/articles/323533a0) 2. [F. Rosenblatt — The perceptron (Psychological Review, 1958)](https://psycnet.apa.org/doi/10.1037/h0042519) 3. [Y. LeCun, Y. Bengio, G. Hinton — Deep learning (Nature, 2015)](https://www.nature.com/articles/nature14539) 4. [I. Goodfellow, Y. Bengio, A. Courville — Deep Learning (MIT Press, 2016)](https://www.deeplearningbook.org/) 5. [The Nobel Prize in Physics 2024](https://www.nobelprize.org/prizes/physics/2024/summary/) 6. [PyTorch — torch.nn documentation](https://docs.pytorch.org/docs/stable/nn.html) --- # ONNX > Открытый формат представления моделей машинного обучения и среда ONNX Runtime; позволяет обучить модель в одном фреймворке и запускать её на любом железе и языке. Источник: https://llmdocs.ru/wiki/onnx/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Полное название**: Open Neural Network Exchange - **Создатели**: Microsoft и Facebook (2017) - **Управление**: LF AI & Data Foundation (с 2019) - **Формат**: Protocol Buffers, расширение .onnx - **Среда выполнения**: ONNX Runtime (C++, Python, C#, Java, JS) - **Экспорт из**: PyTorch, TensorFlow, scikit-learn, XGBoost, LightGBM - **Ускорители**: CUDA, TensorRT, OpenVINO, DirectML, CoreML, WebGPU **ONNX** (*Open Neural Network Exchange*) — открытый формат описания моделей машинного обучения в виде вычислительного графа из стандартных операторов. Модель, обученную в [PyTorch](https://llmdocs.ru/wiki/pytorch.md) или [scikit-learn](https://llmdocs.ru/wiki/scikit-learn.md), можно экспортировать в файл `.onnx` и затем выполнять без исходного фреймворка: на сервере, в мобильном приложении, в браузере или на специализированном ускорителе. Чаще всего модели запускают через **ONNX Runtime** — высокопроизводительную среду выполнения от Microsoft. ## История Формат представили Microsoft и Facebook в 2017 году, чтобы разорвать привязку моделей к фреймворку, в котором их обучили. Вскоре к проекту присоединились AWS, NVIDIA, Intel, AMD и другие. В 2019 году ONNX перешёл под управление LF AI & Data Foundation.[1] ONNX Runtime открыт в 2018 году и используется в продуктах Microsoft — Office, Bing, Windows. ## Устройство формата Файл ONNX — сериализованная в Protocol Buffers структура, содержащая:[2] - **граф** — узлы-операторы (`Conv`, `MatMul`, `Relu`, `Attention`…) и связи между ними; - **инициализаторы** — веса модели; - **описание входов и выходов** с типами и формами тензоров, включая динамические измерения (например, размер батча); - **opset** — версию набора операторов; новые версии добавляют операторы и меняют их семантику. Помимо нейросетевых операторов, есть домен `ai.onnx.ml` для классических моделей — деревьев решений, линейных моделей, предобработки. Модели больше 2 ГБ хранят веса во внешних файлах. ## Экспорт Из PyTorch:[4] ```python import torch model.eval() dummy = torch.randn(1, 3, 224, 224) torch.onnx.export( model, dummy, "resnet.onnx", input_names=["image"], output_names=["logits"], dynamic_axes={"image": {0: "batch"}, "logits": {0: "batch"}}, opset_version=17, ) ``` Новый экспортёр `torch.onnx.export(..., dynamo=True)` строит граф через `torch.export` и лучше справляется с современными моделями. Для scikit-learn используется **sklearn-onnx**, для XGBoost и LightGBM — **onnxmltools**, для моделей [Hugging Face](https://llmdocs.ru/wiki/hugging-face.md) — библиотека Optimum (`optimum-cli export onnx`).[5] Не каждая модель экспортируется гладко: динамический Python-код, нестандартные операции и управляющие конструкции, зависящие от данных, могут не иметь аналогов в ONNX. После экспорта модель проверяют: `onnx.checker.check_model` и сравнение выходов с исходной моделью на тестовых данных. ## ONNX Runtime ```python import numpy as np import onnxruntime as ort session = ort.InferenceSession("resnet.onnx", providers=["CUDAExecutionProvider", "CPUExecutionProvider"]) logits = session.run(None, {"image": np.random.rand(1, 3, 224, 224).astype(np.float32)})[0] ``` ONNX Runtime оптимизирует граф — сливает операторы, удаляет лишние узлы, подбирает раскладку памяти — и выполняет его через **execution providers**: CUDA и TensorRT для [NVIDIA](https://llmdocs.ru/wiki/gpu-cuda.md), OpenVINO для Intel, DirectML в Windows, CoreML на устройствах Apple, NNAPI в Android, WebAssembly и WebGPU в браузере.[6] Есть привязки к C++, C#, Java, JavaScript и Rust (`ort`). Поддерживается [квантизация](https://llmdocs.ru/wiki/quantization.md) в INT8 — статическая и динамическая — для ускорения на процессоре. ## Зачем использовать | Задача | Как помогает ONNX | |---|---| | Сервинг без Python | модель запускается из Java, C#, Go или Rust-сервиса | | Ускорение на CPU | часто в 1,5–3 раза быстрее исходного фреймворка с оптимизациями и INT8 | | Edge и мобильные | один файл для Android, iOS, Windows и встраиваемых систем | | Браузер | ONNX Runtime Web выполняет модель на клиенте | | Ускорители | TensorRT и OpenVINO принимают ONNX как входной формат | | Классический ML | деревья и пайплайны scikit-learn без зависимости от Python | ONNX — один из стандартных путей в [сервинге](https://llmdocs.ru/wiki/model-serving.md): его поддерживают NVIDIA Triton, KServe и облачные платформы. ## Ограничения ONNX хорошо подходит для моделей компьютерного зрения, классических моделей, энкодеров вроде BERT и моделей эмбеддингов. Для больших языковых моделей с генерацией по токенам, KV-кэшем и пакетной обработкой запросов обычно используют специализированные движки — [vLLM](https://llmdocs.ru/wiki/vllm.md), TensorRT-LLM или форматы вроде [GGUF](https://llmdocs.ru/wiki/gguf.md) для llama.cpp. ONNX Runtime GenAI закрывает часть этих сценариев, но экосистема там моложе. ## См. также - [PyTorch](https://llmdocs.ru/wiki/pytorch.md) - [Сервинг моделей](https://llmdocs.ru/wiki/model-serving.md) - [Квантизация моделей](https://llmdocs.ru/wiki/quantization.md) - [GGUF](https://llmdocs.ru/wiki/gguf.md) ## Источники 1. [ONNX — официальный сайт](https://onnx.ai/) 2. [ONNX — Operators specification](https://onnx.ai/onnx/operators/) 3. [ONNX Runtime Documentation](https://onnxruntime.ai/docs/) 4. [PyTorch — Exporting a model to ONNX](https://pytorch.org/docs/stable/onnx.html) 5. [sklearn-onnx Documentation](https://onnx.ai/sklearn-onnx/) 6. [ONNX Runtime — Execution Providers](https://onnxruntime.ai/docs/execution-providers/) --- # Переобучение и регуляризация > Переобучение — ситуация, когда модель запоминает обучающие данные вместо закономерностей; регуляризация — набор приёмов, ограничивающих сложность модели ради обобщения. Источник: https://llmdocs.ru/wiki/overfitting-regularization/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Противоположность**: недообучение (underfitting) - **Теоретическая рамка**: компромисс смещения и разброса (bias–variance) - **Диагностика**: разрыв между ошибкой на обучении и на валидации - **Методы для линейных моделей**: L1 (Lasso), L2 (Ridge), Elastic Net - **Методы для нейросетей**: dropout, weight decay, ранняя остановка, аугментация **Переобучение** (англ. *overfitting*) — состояние модели [машинного обучения](https://llmdocs.ru/wiki/machine-learning.md), при котором она хорошо работает на обучающих данных, но плохо — на новых: вместо общей закономерности модель запомнила шум и случайные особенности выборки. Противоположная ситуация — **недообучение** (*underfitting*): модель слишком проста и не улавливает даже основную зависимость. **Регуляризация** — общее название приёмов, которые ограничивают сложность модели или добавляют к обучению «штраф», чтобы улучшить обобщение.[1] ## Как распознать Данные делят на обучающую, валидационную и тестовую части и сравнивают ошибку на них:[4] | Картина | Ошибка на обучении | Ошибка на валидации | Диагноз | |---|---|---|---| | обе высокие | высокая | высокая | недообучение | | большой разрыв | низкая | высокая | переобучение | | обе низкие, близки | низкая | низкая | хорошо | У нейросетей это видно по **кривым обучения**: ошибка на обучении продолжает падать, а на валидации после некоторой эпохи начинает расти. Для надёжной оценки на небольших данных используют [кросс-валидацию](https://llmdocs.ru/wiki/cross-validation.md). Отдельная ловушка — **утечка данных** (data leakage): когда в признаки попадает информация из будущего или из ответа, модель выглядит превосходно на валидации и проваливается в продакшене. Это не переобучение в строгом смысле, но симптомы похожи. ## Смещение и разброс Классическое объяснение — компромисс **смещения и разброса** (bias–variance tradeoff). Ожидаемую ошибку модели можно разложить на три части: смещение (систематическая ошибка от слишком простых допущений), разброс (чувствительность к конкретной выборке) и неустранимый шум.[1] Простые модели имеют большое смещение, сложные — большой разброс; регуляризация сдвигает баланс в сторону меньшего разброса ценой небольшого смещения. Для очень больших нейросетей картина сложнее: при росте числа параметров далеко за порог «запоминания» ошибка на тесте может снова снижаться — эффект **двойного спуска** (double descent).[5] Поэтому современные сети обычно делают избыточно большими и регуляризуют, а не уменьшают. ## Методы регуляризации ### Штрафы на веса К функции потерь добавляется слагаемое, зависящее от величины весов $w$:[3] - **L2** (Ridge, *weight decay*): $\lambda \sum w_j^2$ — веса становятся меньше и равномернее. - **L1** (Lasso): $\lambda \sum |w_j|$ — многие веса обнуляются, модель сама отбирает признаки. - **Elastic Net** — сочетание обоих. Коэффициент $\lambda$ — гиперпараметр: подбирается по валидации. При обучении нейросетей оптимизатором Adam штраф лучше применять отдельно от градиентного шага (AdamW).[6] ```python from sklearn.linear_model import RidgeCV, LassoCV ridge = RidgeCV(alphas=[0.1, 1, 10, 100]).fit(X_train, y_train) lasso = LassoCV(cv=5).fit(X_train, y_train) print((lasso.coef_ != 0).sum(), "признаков осталось") ``` ### Для нейросетей - **Dropout** — на каждом шаге обучения случайно «выключается» часть нейронов, сеть не может полагаться на отдельные связи.[2] - **Ранняя остановка** — прекратить обучение, когда ошибка на валидации перестала снижаться. - **Аугментация данных** — искусственное расширение выборки: повороты и обрезка картинок, перефразирование текстов. - **Нормализация** (batch norm, layer norm) и сглаживание меток (label smoothing) также оказывают регуляризующий эффект. ### Для деревьев и ансамблей Ограничение глубины и минимального размера листа, случайный выбор подмножества признаков и объектов, малый темп обучения с большим числом деревьев — основные рычаги в [градиентном бустинге](https://llmdocs.ru/wiki/gradient-boosting.md) и случайном лесе. ### Данные Самый надёжный способ бороться с переобучением — больше разнообразных данных. Упрощение модели и отбор признаков — следующий шаг. ## В больших языковых моделях При дообучении LLM ([Fine-tuning и LoRA](https://llmdocs.ru/wiki/fine-tuning-lora.md)) переобучение проявляется как «заучивание» обучающих примеров и потеря общих навыков (катастрофическое забывание). Помогают малое число эпох, низкий темп обучения и методы, меняющие лишь малую часть параметров, вроде LoRA. ## См. также - [Градиентный спуск](https://llmdocs.ru/wiki/gradient-descent.md) - [Кросс-валидация](https://llmdocs.ru/wiki/cross-validation.md) - [Обучение с учителем и без](https://llmdocs.ru/wiki/supervised-unsupervised.md) - [Нейронная сеть](https://llmdocs.ru/wiki/neural-network.md) - [scikit-learn](https://llmdocs.ru/wiki/scikit-learn.md) ## Источники 1. [Hastie, Tibshirani, Friedman — The Elements of Statistical Learning, гл. 7](https://hastie.su.domains/ElemStatLearn/) 2. [Srivastava et al. — Dropout: A Simple Way to Prevent Neural Networks from Overfitting (2014)](https://jmlr.org/papers/v15/srivastava14a.html) 3. [scikit-learn — Linear models (Ridge, Lasso)](https://scikit-learn.org/stable/modules/linear_model.html) 4. [scikit-learn — Underfitting vs. Overfitting](https://scikit-learn.org/stable/auto_examples/model_selection/plot_underfitting_overfitting.html) 5. [Nakkiran et al. — Deep Double Descent (2019)](https://arxiv.org/abs/1912.02292) 6. [Loshchilov, Hutter — Decoupled Weight Decay Regularization (AdamW, 2017)](https://arxiv.org/abs/1711.05101) --- # PyTorch > Открытый фреймворк глубокого обучения на Python с тензорами, автоматическим дифференцированием и поддержкой GPU; стандарт исследований и основа большинства открытых языковых моделей. Источник: https://llmdocs.ru/wiki/pytorch/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: фреймворк глубокого обучения - **Разработчик**: Meta AI (FAIR), с 2022 — PyTorch Foundation (Linux Foundation) - **Первый выпуск**: 2016 - **Предшественник**: Torch (Lua) - **Языки**: Python, C++, CUDA - **Лицензия**: BSD-3-Clause - **Ключевые части**: тензоры, autograd, torch.nn, torch.compile, DataLoader - **Сайт**: pytorch.org **PyTorch** — открытый фреймворк для глубокого обучения на [Python](https://llmdocs.ru/wiki/python.md). Он предоставляет многомерные массивы — **тензоры** — с вычислениями на CPU и [GPU](https://llmdocs.ru/wiki/gpu-cuda.md), **автоматическое дифференцирование** для обучения моделей градиентными методами и набор готовых строительных блоков [нейронных сетей](https://llmdocs.ru/wiki/neural-network.md). PyTorch ценят за то, что модель — это обычный Python-код, который можно отлаживать построчно.[1] PyTorch — самый популярный фреймворк в научных статьях по машинному обучению; на нём обучено большинство открытых [языковых моделей](https://llmdocs.ru/wiki/llm.md), а библиотеки экосистемы [Hugging Face](https://llmdocs.ru/wiki/hugging-face.md) используют его по умолчанию. ## История PyTorch вырос из библиотеки Torch, написанной на языке Lua. В лаборатории Facebook AI Research (FAIR) его переписали с интерфейсом на Python; первый выпуск состоялся в 2016 году, широкий анонс — в начале 2017-го. Главным отличием от тогдашнего TensorFlow был **режим немедленного выполнения** (*eager mode*): граф вычислений строится на лету при выполнении кода, а не описывается заранее, поэтому работают обычные `if`, циклы и отладчик. В 2018 году с PyTorch объединили фреймворк Caffe2 для продакшена. В 2022 году проект перешёл под управление независимой PyTorch Foundation в составе Linux Foundation.[5] Версия 2.0 (2023) добавила компилятор `torch.compile`, ускоряющий модели без переписывания кода.[4] ## Основные понятия ### Тензоры ```python import torch x = torch.randn(32, 784) # пакет из 32 векторов по 784 числа w = torch.randn(784, 10, requires_grad=True) device = "cuda" if torch.cuda.is_available() else "cpu" # на Mac — "mps" x, w = x.to(device), w.detach().to(device).requires_grad_() y = x @ w # матричное умножение на GPU print(y.shape, y.dtype, y.device) # torch.Size([32, 10]) torch.float32 cuda:0 ``` Тензоры похожи на массивы NumPy и легко конвертируются в них, но умеют работать на ускорителях и запоминать операции для вычисления градиентов. ### Autograd Если у тензора установлен `requires_grad=True`, PyTorch записывает все операции над ним. Вызов `loss.backward()` проходит запись в обратном порядке и вычисляет градиенты по правилу дифференцирования сложной функции — это и есть обратное распространение ошибки. Градиенты появляются в атрибуте `.grad` и используются оптимизатором для [градиентного спуска](https://llmdocs.ru/wiki/gradient-descent.md). ### Модули и обучение ```python from torch import nn from torch.utils.data import DataLoader class Classifier(nn.Module): def __init__(self): super().__init__() self.net = nn.Sequential(nn.Linear(784, 256), nn.ReLU(), nn.Dropout(0.1), nn.Linear(256, 10)) def forward(self, x): return self.net(x) model = Classifier().to(device) opt = torch.optim.AdamW(model.parameters(), lr=3e-4) loss_fn = nn.CrossEntropyLoss() loader = DataLoader(train_dataset, batch_size=64, shuffle=True) for epoch in range(5): model.train() for xb, yb in loader: xb, yb = xb.to(device), yb.to(device) loss = loss_fn(model(xb), yb) opt.zero_grad() loss.backward() opt.step() torch.save(model.state_dict(), "model.pt") ``` Класс `nn.Module` хранит параметры и вложенные слои, `Dataset` и `DataLoader` подают данные пакетами, а цикл обучения пишется явно — это даёт полный контроль, хотя для типовых задач используют обёртки.[3] ## Производительность - **Смешанная точность** (`torch.autocast`, форматы bfloat16 и float16) ускоряет обучение и вдвое сокращает память. - **`torch.compile`** превращает модель в оптимизированные ядра, объединяя операции. - **Распределённое обучение** — `DistributedDataParallel` для нескольких GPU и машин, `FSDP` для моделей, не помещающихся в память одной карты. - **Поддержка ускорителей** — NVIDIA CUDA, AMD ROCm, Apple Silicon (MPS), Intel и другие. Установку под конкретную платформу и версию CUDA удобно подобрать в конфигураторе на сайте PyTorch.[6] ## Экосистема | Библиотека | Назначение | |---|---| | torchvision, torchaudio | наборы данных, модели и преобразования для изображений и звука | | Hugging Face Transformers | тысячи предобученных моделей для текста, изображений, звука | | PyTorch Lightning, Accelerate | обучение без шаблонного кода, масштабирование на кластеры | | PEFT | эффективное дообучение, в том числе [LoRA](https://llmdocs.ru/wiki/fine-tuning-lora.md) | | vLLM, TorchServe | инференс и [сервинг](https://llmdocs.ru/wiki/model-serving.md) моделей | | ONNX-экспорт, ExecuTorch | перенос моделей на другие среды выполнения и мобильные устройства (см. [ONNX](https://llmdocs.ru/wiki/onnx.md)) | ## PyTorch и другие фреймворки TensorFlow от Google долго лидировал в продакшене, но в исследованиях уступил PyTorch; Keras 3 теперь работает поверх нескольких бэкендов, включая PyTorch. JAX от Google популярен в крупных исследовательских проектах благодаря функциональному стилю и компилятору XLA. Для классического машинного обучения на табличных данных PyTorch обычно не нужен — там удобнее [scikit-learn](https://llmdocs.ru/wiki/scikit-learn.md) и библиотеки градиентного бустинга. Полная справка по API — в документации PyTorch.[2] ## См. также - [Нейронная сеть](https://llmdocs.ru/wiki/neural-network.md) - [GPU и CUDA](https://llmdocs.ru/wiki/gpu-cuda.md) - [Hugging Face](https://llmdocs.ru/wiki/hugging-face.md) - [Градиентный спуск](https://llmdocs.ru/wiki/gradient-descent.md) - [Fine-tuning и LoRA](https://llmdocs.ru/wiki/fine-tuning-lora.md) ## Источники 1. [A. Paszke et al. — PyTorch: An Imperative Style, High-Performance Deep Learning Library (NeurIPS 2019)](https://arxiv.org/abs/1912.01703) 2. [PyTorch Documentation](https://docs.pytorch.org/docs/stable/index.html) 3. [PyTorch Tutorials — Learn the Basics](https://docs.pytorch.org/tutorials/beginner/basics/intro.html) 4. [PyTorch — torch.compile tutorial](https://docs.pytorch.org/tutorials/intermediate/torch_compile_tutorial.html) 5. [PyTorch Foundation](https://pytorch.org/foundation/) 6. [PyTorch — Get Started (установка)](https://pytorch.org/get-started/locally/) --- # Квантизация моделей > Сжатие нейросетей переводом весов и активаций в числа пониженной точности (8, 4 бита и меньше) ради экономии памяти и ускорения инференса. Источник: https://llmdocs.ru/wiki/quantization/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Цель**: меньше памяти, выше скорость, ниже стоимость инференса - **Форматы чисел**: FP16, BF16, FP8, INT8, INT4, NF4 - **Подходы**: после обучения (PTQ), с учётом квантизации при обучении (QAT) - **Методы для LLM**: GPTQ, AWQ, bitsandbytes, k-квантизация GGUF - **Инструменты**: llama.cpp, bitsandbytes, AutoGPTQ, TensorRT, ONNX Runtime **Квантизация** (англ. *quantization*) — способ сжатия [нейросетей](https://llmdocs.ru/wiki/neural-network.md), при котором веса, а иногда и промежуточные значения (активации), хранятся и обрабатываются в числах пониженной точности: вместо 16 или 32 бит на число — 8, 4 или даже меньше. Модель становится в несколько раз меньше и быстрее при умеренной потере качества. Благодаря квантизации [большие языковые модели](https://llmdocs.ru/wiki/llm.md) запускаются на одной видеокарте, ноутбуке или телефоне.[1] ## Зачем Размер модели в памяти ≈ число параметров × байт на параметр: | Точность | Байт на параметр | Модель 8 млрд параметров | Модель 70 млрд | |---|---|---|---| | FP32 | 4 | ~32 ГБ | ~280 ГБ | | BF16 / FP16 | 2 | ~16 ГБ | ~140 ГБ | | INT8 / FP8 | 1 | ~8 ГБ | ~70 ГБ | | 4 бита | ~0,5 | ~4,5 ГБ | ~40 ГБ | При генерации текста скорость LLM ограничена в основном пропускной способностью памяти: на каждый токен нужно прочитать все веса. Поэтому сжатие весов вдвое почти вдвое ускоряет генерацию — помимо того, что модель вообще помещается в [видеопамять](https://llmdocs.ru/wiki/gpu-cuda.md). ## Как это работает Диапазон вещественных значений отображается на небольшое множество целых чисел с помощью **масштаба** (scale) и, возможно, **сдвига** (zero point): $$q = \mathrm{round}(x / s) + z, \qquad \hat{x} = s \cdot (q - z)$$ Чем мельче группы, для которых подбирается свой масштаб (по тензору, по каналу, по блокам из 32–128 значений), тем точнее приближение и тем больше накладных расходов на хранение масштабов. Главная трудность — **выбросы**: в трансформерах отдельные признаки принимают значения в сотни раз больше остальных, и общий масштаб «съедает» точность для всех прочих.[2] ## Подходы - **Квантизация после обучения** (PTQ, post-training quantization) — модель квантуется готовой, обычно с небольшим калибровочным набором данных. Быстро и дёшево — основной вариант для LLM. - **Обучение с учётом квантизации** (QAT, quantization-aware training) — округление имитируется во время обучения, и модель адаптируется к нему. Точнее, но требует ресурсов обучения; применяется для мобильных моделей и при агрессивном сжатии. - **Динамическая** и **статическая** квантизация активаций — масштабы вычисляются на лету или заранее.[6] ## Методы для LLM - **LLM.int8()** (bitsandbytes) — 8-битное умножение с выделением выбросов в 16-битную часть.[2] - **GPTQ** — послойная квантизация до 3–4 бит с компенсацией ошибки на основе приближённой информации второго порядка.[3] - **AWQ** — защищает около 1% «важных» весов, выбранных по величине активаций.[4] - **NF4 и QLoRA** — 4-битный формат, приспособленный к нормальному распределению весов; позволяет дообучать квантованную модель адаптерами LoRA (см. [Fine-tuning и LoRA](https://llmdocs.ru/wiki/fine-tuning-lora.md)).[5] - **k-квантизация в [GGUF](https://llmdocs.ru/wiki/gguf.md)** — семейство форматов llama.cpp (`Q4_K_M`, `Q5_K_M`, `Q8_0` и др.) со смешанной точностью разных слоёв; стандарт для локального запуска.[7] - **FP8 и FP4** — аппаратная поддержка на новых GPU позволяет и обучать, и обслуживать модели в 8-битных и 4-битных форматах с плавающей точкой. ```bash # llama.cpp: квантизовать модель до 4 бит llama-quantize model-f16.gguf model-Q4_K_M.gguf Q4_K_M ``` ```python # Transformers + bitsandbytes: загрузить модель сразу в 4 битах from transformers import AutoModelForCausalLM, BitsAndBytesConfig cfg = BitsAndBytesConfig(load_in_4bit=True, bnb_4bit_quant_type="nf4") model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen3-8B", quantization_config=cfg) ``` ## Качество Практическое правило для LLM: 8 бит почти неотличимы от исходной модели, 5–6 бит — потери едва заметны, 4 бита — разумный компромисс, ниже 3 бит качество падает заметно. Крупная модель в 4 битах обычно лучше маленькой модели той же памяти в 16 битах. Сильнее всего страдают точные задачи — математика, код, длинный контекст, — поэтому квантованную модель стоит проверять на своих задачах (см. [Оценка LLM (evals)](https://llmdocs.ru/wiki/llm-evals.md)). Квантуют также KV-кэш, чтобы вместить более длинное [контекстное окно](https://llmdocs.ru/wiki/context-window.md). ## См. также - [GGUF](https://llmdocs.ru/wiki/gguf.md) - [Локальный запуск LLM (llama.cpp, Ollama)](https://llmdocs.ru/wiki/local-llm.md) - [GPU и CUDA](https://llmdocs.ru/wiki/gpu-cuda.md) - [Fine-tuning и LoRA](https://llmdocs.ru/wiki/fine-tuning-lora.md) - [Сервинг моделей](https://llmdocs.ru/wiki/model-serving.md) ## Источники 1. [Hugging Face — Quantization overview](https://huggingface.co/docs/transformers/main/en/quantization/overview) 2. [Dettmers et al. — LLM.int8(): 8-bit Matrix Multiplication for Transformers at Scale (2022)](https://arxiv.org/abs/2208.07339) 3. [Frantar et al. — GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers (2022)](https://arxiv.org/abs/2210.17323) 4. [Lin et al. — AWQ: Activation-aware Weight Quantization (2023)](https://arxiv.org/abs/2306.00978) 5. [Dettmers et al. — QLoRA: Efficient Finetuning of Quantized LLMs (2023)](https://arxiv.org/abs/2305.14314) 6. [PyTorch — Quantization (torchao)](https://pytorch.org/ao/stable/index.html) 7. [llama.cpp — quantize tool](https://github.com/ggml-org/llama.cpp/tree/master/tools/quantize) --- # scikit-learn > Библиотека классического машинного обучения для Python с единым интерфейсом fit/predict — модели, предобработка, конвейеры и подбор гиперпараметров. Источник: https://llmdocs.ru/wiki/scikit-learn/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Автор**: Давид Курнапо (Google Summer of Code, 2007) - **Первый публичный выпуск**: 2010 (INRIA) - **Язык**: Python, Cython - **Зависимости**: NumPy, SciPy, joblib - **Лицензия**: BSD 3-Clause - **Импорт**: import sklearn - **Сайт**: scikit-learn.org **scikit-learn** (sklearn) — свободная библиотека [Python](https://llmdocs.ru/wiki/python.md) для классического [машинного обучения](https://llmdocs.ru/wiki/machine-learning.md): классификации, регрессии, кластеризации, понижения размерности, предобработки данных и оценки моделей. Она построена поверх [NumPy](https://llmdocs.ru/wiki/numpy.md) и SciPy и знаменита единообразным интерфейсом: любая модель обучается методом `fit` и делает предсказания методом `predict`. Для табличных данных среднего размера scikit-learn — стандартная отправная точка; глубокое обучение в ней не реализуется — для этого есть [PyTorch](https://llmdocs.ru/wiki/pytorch.md).[1] ## История Проект начал Давид Курнапо в 2007 году в рамках Google Summer of Code как дополнение («scikit») к SciPy. В 2010 году разработку подхватили исследователи французского института INRIA, выпустив первую публичную версию; статья в JMLR 2011 года стала одной из самых цитируемых в области.[2] Версия 1.0 вышла в 2021 году. Проект развивается сообществом при поддержке фонда и компании Probabl, созданной ключевыми разработчиками. ## Дизайн API Все объекты следуют нескольким соглашениям:[3] - **Оценщик** (estimator) — любой объект с методом `fit(X, y)`; гиперпараметры задаются в конструкторе. - **Предсказатель** — добавляет `predict`, для классификаторов также `predict_proba`, и `score`. - **Преобразователь** (transformer) — `transform` и `fit_transform`: масштабирование, кодирование, отбор признаков. - Выученные параметры имеют суффикс подчёркивания: `coef_`, `classes_`. - Данные — массивы NumPy, таблицы [pandas](https://llmdocs.ru/wiki/pandas.md) или разреженные матрицы. Благодаря этому модели взаимозаменяемы: сменить логистическую регрессию на случайный лес — одна строка. ## Что внутри | Раздел | Примеры | |---|---| | Линейные модели | `LinearRegression`, `Ridge`, `Lasso`, `LogisticRegression` | | Деревья и ансамбли | `DecisionTreeClassifier`, `RandomForestClassifier`, `HistGradientBoostingClassifier` | | Прочие модели | SVM, k ближайших соседей, наивный Байес | | Кластеризация | `KMeans`, `DBSCAN`, `AgglomerativeClustering` | | Понижение размерности | `PCA`, `TruncatedSVD` | | Предобработка | `StandardScaler`, `OneHotEncoder`, `SimpleImputer` | | Оценка | `train_test_split`, `cross_val_score`, `GridSearchCV`, метрики | Задачи с учителем и без разобраны в статье [Обучение с учителем и без](https://llmdocs.ru/wiki/supervised-unsupervised.md); выбрать подходящую модель помогает официальная «карта оценщиков».[5] ## Конвейеры `Pipeline` и `ColumnTransformer` объединяют предобработку и модель в один объект. Это не только удобно, но и защищает от **утечки данных**: масштабирование и заполнение пропусков обучаются только на обучающей части каждого фолда.[4] ```python from sklearn.compose import ColumnTransformer from sklearn.ensemble import HistGradientBoostingClassifier from sklearn.model_selection import GridSearchCV, train_test_split from sklearn.pipeline import Pipeline from sklearn.preprocessing import OneHotEncoder, StandardScaler pre = ColumnTransformer([ ("num", StandardScaler(), ["age", "income"]), ("cat", OneHotEncoder(handle_unknown="ignore"), ["city"]), ]) pipe = Pipeline([("pre", pre), ("clf", HistGradientBoostingClassifier())]) X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, random_state=0) search = GridSearchCV(pipe, {"clf__learning_rate": [0.05, 0.1], "clf__max_depth": [3, None]}, cv=5, scoring="roc_auc") search.fit(X_train, y_train) print(search.best_params_, search.score(X_test, y_test)) ``` Подбор гиперпараметров по [кросс-валидации](https://llmdocs.ru/wiki/cross-validation.md) (`GridSearchCV`, `RandomizedSearchCV`, `HalvingGridSearchCV`) — основной инструмент борьбы с [переобучением](https://llmdocs.ru/wiki/overfitting-regularization.md) при выборе модели. Метрики — в модуле `sklearn.metrics`, см. [Метрики качества классификации](https://llmdocs.ru/wiki/classification-metrics.md). ## Ограничения - Работает в памяти и в основном на CPU; данные порядка миллионов строк — предел комфортного использования. - Нет глубокого обучения и GPU (частичная поддержка через Array API). - Для соревнований на табличных данных чаще берут специализированные библиотеки [градиентного бустинга](https://llmdocs.ru/wiki/gradient-boosting.md) — они совместимы с API scikit-learn. ## Сохранение и продакшен Модели традиционно сохраняют через `joblib` или `pickle` — это быстро, но небезопасно для недоверенных файлов и привязано к версии библиотеки. Альтернативы — формат `skops` и экспорт в [ONNX](https://llmdocs.ru/wiki/onnx.md) для [сервинга](https://llmdocs.ru/wiki/model-serving.md).[6] Эксперименты и модели удобно отслеживать в [MLflow](https://llmdocs.ru/wiki/mlflow.md), у которого есть автологирование для scikit-learn. ## См. также - [NumPy](https://llmdocs.ru/wiki/numpy.md) - [pandas](https://llmdocs.ru/wiki/pandas.md) - [Обучение с учителем и без](https://llmdocs.ru/wiki/supervised-unsupervised.md) - [Градиентный бустинг (XGBoost, CatBoost, LightGBM)](https://llmdocs.ru/wiki/gradient-boosting.md) - [Jupyter](https://llmdocs.ru/wiki/jupyter.md) ## Источники 1. [scikit-learn — User Guide](https://scikit-learn.org/stable/user_guide.html) 2. [Pedregosa et al. — Scikit-learn: Machine Learning in Python (JMLR, 2011)](https://jmlr.org/papers/v12/pedregosa11a.html) 3. [Buitinck et al. — API design for machine learning software (2013)](https://arxiv.org/abs/1309.0238) 4. [scikit-learn — Common pitfalls and recommended practices](https://scikit-learn.org/stable/common_pitfalls.html) 5. [scikit-learn — Choosing the right estimator](https://scikit-learn.org/stable/machine_learning_map.html) 6. [scikit-learn — Model persistence](https://scikit-learn.org/stable/model_persistence.html) --- # Обучение с учителем и без > Основное деление задач машинного обучения — по размеченным примерам (классификация, регрессия) и без разметки (кластеризация, понижение размерности), плюс промежуточные виды. Источник: https://llmdocs.ru/wiki/supervised-unsupervised/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Обучение с учителем**: классификация, регрессия, ранжирование - **Обучение без учителя**: кластеризация, понижение размерности, поиск аномалий - **Промежуточные виды**: частичное (semi-supervised), самообучение (self-supervised) - **Отдельная парадигма**: обучение с подкреплением - **Типичные библиотеки**: scikit-learn, PyTorch, XGBoost **Обучение с учителем** (англ. *supervised learning*) и **обучение без учителя** (*unsupervised learning*) — две основные постановки задач [машинного обучения](https://llmdocs.ru/wiki/machine-learning.md), различающиеся наличием «правильных ответов» в данных. В первом случае у каждого примера есть метка (цена квартиры, «спам / не спам»), и модель учится предсказывать её по признакам. Во втором меток нет, и модель ищет структуру в самих данных: группы похожих объектов, скрытые факторы, выбросы.[3] ## Обучение с учителем Данные — пары «признаки → ответ» $(x_i, y_i)$. Модель подбирает функцию $f(x) \approx y$, минимизируя ошибку на обучающей выборке, а качество проверяется на отложенных примерах, которых модель не видела.[1] | Задача | Ответ | Примеры | Типичные модели | |---|---|---|---| | Классификация | класс | спам-фильтр, диагноз, тональность отзыва | логистическая регрессия, бустинг, нейросети | | Регрессия | число | цена, спрос, время доставки | линейная регрессия, бустинг | | Ранжирование | порядок | поисковая выдача, рекомендации | LambdaMART, двухбашенные сети | Главная трудность — **разметка**: её нужно собрать (логи, ручная разметка, краудсорсинг), и она бывает дорогой, шумной и смещённой. Вторая — **обобщение**: модель должна работать на новых данных, а не запоминать обучающие; см. [Переобучение и регуляризация](https://llmdocs.ru/wiki/overfitting-regularization.md). Качество классификаторов измеряют специальными метриками — см. [Метрики качества классификации](https://llmdocs.ru/wiki/classification-metrics.md). ## Обучение без учителя Данные — только признаки $x_i$. Основные задачи:[2] - **Кластеризация** — разбить объекты на группы похожих: сегменты клиентов, темы документов. Алгоритмы: k-means, DBSCAN, иерархическая кластеризация. - **Понижение размерности** — сжать сотни признаков до нескольких, сохранив структуру: PCA для предобработки, t-SNE и UMAP для визуализации. - **Поиск аномалий** — найти нетипичные объекты: мошеннические транзакции, сбои оборудования (Isolation Forest, One-Class SVM). - **Оценка плотности и порождающие модели** — описать распределение данных, чтобы генерировать новые примеры. Оценивать такие модели сложнее: «правильного» разбиения на кластеры нет, и качество часто проверяют косвенно — по пользе для последующей задачи или экспертной оценкой. ```python from sklearn.cluster import KMeans from sklearn.linear_model import LogisticRegression # без учителя: группы клиентов по поведению segments = KMeans(n_clusters=5, n_init="auto").fit_predict(X) # с учителем: предсказать отток по размеченной истории clf = LogisticRegression(max_iter=1000).fit(X_train, y_train) print(clf.score(X_test, y_test)) ``` ## Промежуточные виды - **Частичное обучение** (semi-supervised) — мало размеченных примеров и много неразмеченных; неразмеченные помогают уточнить границы классов (псевдоразметка, распространение меток). - **Самообучение** (self-supervised) — метки извлекаются из самих данных: предсказать пропущенное слово, следующий токен, закрытый фрагмент картинки. Формально это обучение с учителем, но без ручной разметки. Именно так предобучаются [трансформеры](https://llmdocs.ru/wiki/transformer.md) — BERT учился восстанавливать замаскированные слова[5], а [большие языковые модели](https://llmdocs.ru/wiki/llm.md) — предсказывать следующий [токен](https://llmdocs.ru/wiki/tokenization.md) на триллионах слов. Побочный продукт такого обучения — [эмбеддинги](https://llmdocs.ru/wiki/embedding.md), полезные для других задач. - **Слабая разметка** (weak supervision) — метки из эвристик и правил, заведомо неточные, но дешёвые. ## Обучение с подкреплением Отдельная парадигма: агент действует в среде и получает награду, а не правильный ответ на каждый шаг. Применяется в играх, робототехнике и для дообучения языковых моделей по человеческим предпочтениям (RLHF).[6] Современный путь LLM сочетает все виды: самообучение на текстах, обучение с учителем на примерах диалогов и подкрепление по оценкам. ## Как выбрать постановку Если есть ответ, который нужно предсказывать, и его можно получить для достаточного числа примеров, — это задача с учителем, и она почти всегда решается точнее. Обучение без учителя применяют для разведочного анализа, когда метки недоступны, или как этап подготовки признаков.[4] ## См. также - [Машинное обучение](https://llmdocs.ru/wiki/machine-learning.md) - [Переобучение и регуляризация](https://llmdocs.ru/wiki/overfitting-regularization.md) - [scikit-learn](https://llmdocs.ru/wiki/scikit-learn.md) - [Метрики качества классификации](https://llmdocs.ru/wiki/classification-metrics.md) - [Эмбеддинг](https://llmdocs.ru/wiki/embedding.md) ## Источники 1. [scikit-learn — Supervised learning](https://scikit-learn.org/stable/supervised_learning.html) 2. [scikit-learn — Unsupervised learning](https://scikit-learn.org/stable/unsupervised_learning.html) 3. [Hastie, Tibshirani, Friedman — The Elements of Statistical Learning](https://hastie.su.domains/ElemStatLearn/) 4. [Google — Machine Learning Crash Course](https://developers.google.com/machine-learning/crash-course) 5. [Devlin et al. — BERT: Pre-training of Deep Bidirectional Transformers (2018)](https://arxiv.org/abs/1810.04805) 6. [Ouyang et al. — Training language models to follow instructions with human feedback (2022)](https://arxiv.org/abs/2203.02155) --- # Трансформер (архитектура) > Архитектура нейронной сети на основе механизма внимания, предложенная в 2017 году в статье «Attention Is All You Need»; основа современных языковых моделей. Источник: https://llmdocs.ru/wiki/transformer/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: архитектура нейронной сети - **Авторы**: Ашиш Васвани и др. (Google Brain, Google Research) - **Публикация**: июнь 2017, «Attention Is All You Need» (NeurIPS 2017) - **Ключевая идея**: механизм самовнимания (self-attention) вместо рекуррентности - **Варианты**: энкодер (BERT), декодер (GPT, Claude, Llama), энкодер-декодер (T5) - **Сложность внимания**: квадратичная по длине последовательности - **Применение**: языковые модели, перевод, зрение (ViT), звук, мультимодальные модели **Трансформер** (англ. *Transformer*) — архитектура [нейронной сети](https://llmdocs.ru/wiki/neural-network.md) для обработки последовательностей, в основе которой лежит **механизм внимания** (*attention*): каждый элемент последовательности напрямую «смотрит» на все остальные и решает, какие из них важны для его представления. Архитектура предложена исследователями Google в 2017 году в статье «Attention Is All You Need»[1] и стала фундаментом почти всех современных [больших языковых моделей](https://llmdocs.ru/wiki/llm.md) — GPT, Claude, Gemini, Llama, — а также моделей для изображений, звука и биологии. ## Предыстория До трансформеров последовательности обрабатывали рекуррентными сетями (RNN, LSTM): они читают текст слово за словом, передавая состояние дальше. У этого подхода два недостатка: вычисления нельзя распараллелить по длине текста, а информация о далёких словах постепенно «размывается». В 2014–2015 годах к рекуррентным моделям перевода добавили механизм внимания, позволявший заглядывать в любое место исходной фразы. Авторы трансформера пошли дальше и полностью отказались от рекуррентности, оставив только внимание. Модель обучалась быстрее и превзошла лучшие системы машинного перевода того времени. ## Механизм внимания Каждый входной элемент — [токен](https://llmdocs.ru/wiki/tokenization.md), представленный вектором-[эмбеддингом](https://llmdocs.ru/wiki/embedding.md), — преобразуется в три вектора: **запрос** (*query*), **ключ** (*key*) и **значение** (*value*). Внимание вычисляется по формуле: ```text Attention(Q, K, V) = softmax(Q·Kᵀ / √d_k) · V ``` Скалярное произведение запроса одного токена с ключами всех токенов показывает, насколько они релевантны друг другу; softmax превращает оценки в веса, а результат — взвешенная сумма значений. Деление на `√d_k` стабилизирует обучение. Так слово «он» в предложении может получить большую часть информации от существительного, к которому относится, даже если оно стоит далеко. **Многоголовое внимание** (*multi-head attention*) выполняет несколько таких вычислений параллельно с разными проекциями: одни «головы» следят за синтаксисом, другие — за смысловыми связями или позициями. ## Устройство блока Трансформер — стопка одинаковых блоков. Каждый блок содержит: 1. слой многоголового **самовнимания**; 2. полносвязную сеть (*feed-forward*), применяемую к каждому токену отдельно; 3. **остаточные связи** (вход прибавляется к выходу) и **нормализацию слоя**, которые позволяют обучать очень глубокие стопки. Поскольку внимание само по себе не учитывает порядок, к токенам добавляют информацию о позиции. В оригинале это были синусоидальные позиционные кодировки; в современных моделях чаще используются вращательные позиционные эмбеддинги (RoPE).[6] В базовой модели 2017 года было 6 блоков энкодера и 6 блоков декодера с размерностью 512 и 8 головами внимания; современные LLM содержат десятки и сотни блоков и миллиарды параметров. ## Три семейства | Вариант | Как работает | Примеры | Для чего | |---|---|---|---| | Только энкодер | внимание во все стороны, видит весь текст сразу | BERT[2], модели эмбеддингов | классификация, поиск, [векторный поиск](https://llmdocs.ru/wiki/vector-search.md) | | Только декодер | **каузальное** внимание: токен видит только предыдущие | GPT[3], Claude, Llama | генерация текста, чат, код | | Энкодер-декодер | энкодер читает вход, декодер генерирует выход | исходный трансформер, T5 | перевод, суммаризация | Языковые модели-декодеры генерируют текст по одному токену: модель предсказывает распределение вероятностей следующего токена, выбранный токен добавляется к входу, и шаг повторяется. Чтобы не пересчитывать внимание для уже обработанных токенов, ключи и значения сохраняются в **KV-кэше**; на этом же основано [кэширование промптов](https://llmdocs.ru/wiki/prompt-caching.md). ## Ограничения и улучшения - **Квадратичная сложность.** Внимание сравнивает каждый токен с каждым, поэтому вычисления и память растут как квадрат длины. Это главный фактор, ограничивающий [контекстное окно](https://llmdocs.ru/wiki/context-window.md). FlashAttention ускоряет точное внимание за счёт эффективной работы с памятью GPU;[5] существуют и разреженные и линейные приближения. - **Смесь экспертов** (*Mixture of Experts*) активирует для каждого токена лишь часть полносвязных подсетей, увеличивая число параметров без пропорционального роста вычислений. - **Группированное внимание** (GQA, MQA) уменьшает размер KV-кэша при генерации. ## За пределами текста Vision Transformer (2020) разбивает изображение на квадратные фрагменты и обрабатывает их как токены.[7] Тот же принцип применяется к звуку, видео, белковым последовательностям и действиям роботов, а [мультимодальные модели](https://llmdocs.ru/wiki/multimodal-models.md) объединяют несколько типов данных в одной последовательности. Наглядное пошаговое объяснение архитектуры с иллюстрациями — «The Illustrated Transformer» Джея Аламмара.[4] ## См. также - [Большая языковая модель (LLM)](https://llmdocs.ru/wiki/llm.md) - [Нейронная сеть](https://llmdocs.ru/wiki/neural-network.md) - [Токен и токенизация](https://llmdocs.ru/wiki/tokenization.md) - [Контекстное окно](https://llmdocs.ru/wiki/context-window.md) - [Эмбеддинг](https://llmdocs.ru/wiki/embedding.md) ## Источники 1. [A. Vaswani et al. — Attention Is All You Need (2017)](https://arxiv.org/abs/1706.03762) 2. [J. Devlin et al. — BERT: Pre-training of Deep Bidirectional Transformers (2018)](https://arxiv.org/abs/1810.04805) 3. [A. Radford et al. — Improving Language Understanding by Generative Pre-Training (OpenAI, 2018)](https://cdn.openai.com/research-covers/language-unsupervised/language_understanding_paper.pdf) 4. [Jay Alammar — The Illustrated Transformer](https://jalammar.github.io/illustrated-transformer/) 5. [T. Dao et al. — FlashAttention (2022)](https://arxiv.org/abs/2205.14135) 6. [J. Su et al. — RoFormer: Enhanced Transformer with Rotary Position Embedding (2021)](https://arxiv.org/abs/2104.09864) 7. [A. Dosovitskiy et al. — An Image is Worth 16x16 Words: Transformers for Image Recognition (2020)](https://arxiv.org/abs/2010.11929) --- # Caddy > Веб-сервер и обратный прокси на Go с автоматическим HTTPS по умолчанию — сам получает и продлевает сертификаты, поддерживает HTTP/3 и настраивается простым Caddyfile или JSON API. Источник: https://llmdocs.ru/wiki/caddy/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: веб-сервер и обратный прокси - **Автор**: Мэтт Холт - **Первый выпуск**: 2015 - **Caddy 2**: май 2020 - **Язык**: Go - **Лицензия**: Apache 2.0 - **Ключевая особенность**: автоматический HTTPS (ACME) по умолчанию - **Конфигурация**: Caddyfile, JSON, REST API администрирования **Caddy** — веб-сервер и [обратный прокси](https://llmdocs.ru/wiki/reverse-proxy.md), написанный на [Go](https://llmdocs.ru/wiki/go.md). Его главная особенность — **автоматический HTTPS**: достаточно указать в конфигурации доменное имя, и Caddy сам получит сертификат по протоколу ACME (по умолчанию у [Let's Encrypt](https://llmdocs.ru/wiki/lets-encrypt-acme.md) и ZeroSSL), настроит [TLS](https://llmdocs.ru/wiki/tls.md) с безопасными параметрами, включит перенаправление с HTTP на HTTPS и будет продлевать сертификат без участия человека.[2] Caddy ценят за простую конфигурацию и разумные значения по умолчанию: HTTP/2 и HTTP/3, современные шифры, сжатие — всё работает «из коробки». Он распространяется как один бинарный файл без зависимостей. ## История Мэтт Холт выпустил Caddy в 2015 году; это был первый веб-сервер, включавший HTTPS автоматически и по умолчанию. В мае 2020 года вышла полностью переписанная версия **Caddy 2** с модульной архитектурой, внутренней конфигурацией в формате JSON и API для изменения настроек на лету.[6] Проект распространяется под лицензией Apache 2.0. ## Caddyfile Основной способ настройки — файл **Caddyfile** с лаконичным синтаксисом:[3] ```caddyfile # статический сайт с автоматическим HTTPS example.com { root * /var/www/example file_server encode zstd gzip } # обратный прокси к приложению с балансировкой api.example.com { reverse_proxy 127.0.0.1:8001 127.0.0.1:8002 { lb_policy least_conn health_uri /health } } # несколько путей на одном домене app.example.com { handle /api/* { reverse_proxy localhost:8000 } handle { root * /srv/frontend try_files {path} /index.html # одностраничное приложение file_server } } ``` Сравните с аналогичной конфигурацией [nginx](https://llmdocs.ru/wiki/nginx.md): не нужно указывать пути к сертификатам, слушать порт 80 для перенаправления и вручную передавать заголовки `X-Forwarded-*` — `reverse_proxy` делает это сам.[4] ```bash caddy run --config Caddyfile # запуск в терминале caddy reload --config Caddyfile # применить изменения без простоя caddy fmt --overwrite Caddyfile # отформатировать файл caddy reverse-proxy --from example.com --to localhost:8000 # прокси одной командой ``` ## Автоматический HTTPS Для каждого публичного доменного имени в конфигурации Caddy: 1. получает сертификат по ACME — через проверку HTTP-01 или TLS-ALPN-01, а при подключённом модуле DNS-провайдера — DNS-01 (нужно для wildcard); 2. хранит сертификаты и ключи в своём каталоге данных; 3. продлевает их заранее и повторяет попытки при сбоях; 4. включает перенаправление HTTP → HTTPS и HSTS-подобные настройки. Для `localhost` и внутренних имён Caddy создаёт **собственный локальный центр сертификации** и выпускает доверенные сертификаты для разработки, предложив установить корневой сертификат в систему. Режим **On-Demand TLS** выпускает сертификаты в момент первого обращения — удобно для платформ, где клиенты подключают свои домены. Условие для публичного сертификата — домен должен указывать на сервер ([запись A или AAAA](https://llmdocs.ru/wiki/dns-records.md)), а порты 80 и 443 должны быть доступны из интернета. ## JSON и API Внутри Caddy вся конфигурация — документ JSON; Caddyfile лишь преобразуется в него адаптером. Через административный API на `localhost:2019` конфигурацию можно читать и менять на лету, без перезапуска, что удобно для автоматизации и платформ.[5] ```bash curl localhost:2019/config/ # текущая конфигурация caddy adapt --config Caddyfile --pretty # посмотреть JSON, полученный из Caddyfile ``` ## Модули Возможности расширяются модулями на Go, которые вкомпилировываются в бинарный файл с помощью утилиты xcaddy или выбираются на странице загрузки: DNS-провайдеры для ACME, ограничение частоты запросов, аутентификация, кэш, интеграция с [Docker](https://llmdocs.ru/wiki/docker.md) через метки контейнеров. ```bash xcaddy build --with github.com/caddy-dns/cloudflare ``` ## Caddy и nginx | | Caddy | nginx | |---|---|---| | HTTPS | автоматически | вручную или через Certbot | | Конфигурация | короткий Caddyfile, JSON API | развитый, но многословный синтаксис | | HTTP/3 | по умолчанию | требует настройки | | Изменение на лету | API | reload с перечитыванием файлов | | Экосистема и примеры | меньше | огромная | | Производительность | высокая, обычно достаточная | максимальная, особенно для статики | Caddy — удачный выбор для небольших и средних проектов, личных серверов, сред разработки и платформ с множеством доменов; nginx — когда нужна максимальная производительность, тонкая настройка или совместимость с существующей инфраструктурой. Полное описание — в документации Caddy.[1] ## См. также - [nginx](https://llmdocs.ru/wiki/nginx.md) - [Обратный прокси (reverse proxy)](https://llmdocs.ru/wiki/reverse-proxy.md) - [Let's Encrypt и ACME](https://llmdocs.ru/wiki/lets-encrypt-acme.md) - [TLS](https://llmdocs.ru/wiki/tls.md) - [QUIC](https://llmdocs.ru/wiki/quic.md) ## Источники 1. [Caddy — документация](https://caddyserver.com/docs/) 2. [Caddy — Automatic HTTPS](https://caddyserver.com/docs/automatic-https) 3. [Caddy — The Caddyfile](https://caddyserver.com/docs/caddyfile) 4. [Caddy — reverse_proxy directive](https://caddyserver.com/docs/caddyfile/directives/reverse_proxy) 5. [Caddy — API](https://caddyserver.com/docs/api) 6. [caddyserver/caddy — GitHub](https://github.com/caddyserver/caddy) --- # CDN > Сеть распределённых по миру кеширующих серверов, которая отдаёт контент пользователю с ближайшей точки присутствия, снижая задержку и нагрузку на исходный сервер. Источник: https://llmdocs.ru/wiki/cdn/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Полное название**: Content Delivery Network - **Появление**: конец 1990-х (Akamai, 1998) - **Основа**: кеширующие обратные прокси в точках присутствия (PoP) - **Маршрутизация**: DNS (GeoDNS) или anycast - **Управление кешем**: заголовки Cache-Control, ETag, Age (RFC 9111) - **Примеры провайдеров**: Akamai, Cloudflare, Fastly, Amazon CloudFront, Google Cloud CDN **CDN** (англ. *Content Delivery Network* — сеть доставки контента) — распределённая сеть серверов, расставленных в дата-центрах по всему миру, которая хранит копии контента сайта и отдаёт их пользователю с ближайшего узла. Вместо того чтобы каждый запрос шёл через океан к исходному серверу (*origin*), браузер получает картинку, скрипт или видеофрагмент из точки присутствия в своём городе. Это сокращает задержку, разгружает origin и помогает переживать всплески трафика и DDoS-атаки. ## История Идея появилась в конце 1990-х, когда популярные сайты не выдерживали наплыва посетителей («эффект Slashdot»). В 1998 году исследователи MIT основали Akamai, построившую одну из первых коммерческих сетей доставки.[5] В 2000-х CDN стали стандартом для медиа и программных обновлений, а в 2010-х — и для обычных сайтов: Cloudflare, Fastly и облачные провайдеры (Amazon CloudFront, Google Cloud CDN) сделали подключение делом нескольких минут. Сегодня через CDN проходит большая часть веб-трафика, включая потоковое видео. ## Как работает CDN состоит из **точек присутствия** (PoP, *Point of Presence*) — площадок с кеширующими серверами. По сути каждый узел — это [обратный прокси](https://llmdocs.ru/wiki/reverse-proxy.md) с большим кешем. 1. Пользователь запрашивает `static.example.com`. Домен указывает на CDN — обычно через запись CNAME (см. [DNS-записи (A, AAAA, CNAME, MX, TXT)](https://llmdocs.ru/wiki/dns-records.md)). 2. CDN направляет запрос в ближайший PoP одним из двух способов: - **GeoDNS** — [DNS](https://llmdocs.ru/wiki/dns.md)-сервер CDN возвращает разные IP в зависимости от расположения резолвера; - **anycast** — один и тот же IP-адрес анонсируется по BGP из всех точек, и маршрутизация интернета сама доставляет пакеты к ближайшей.[6] 3. Узел проверяет кеш. Если объект есть и свежий — **попадание** (*cache hit*), ответ уходит сразу. Если нет — **промах** (*miss*): узел запрашивает объект у origin (часто через промежуточный уровень — *origin shield*), отдаёт пользователю и сохраняет. 4. На узле же обычно завершается [TLS](https://llmdocs.ru/wiki/tls.md): короткое рукопожатие с ближним сервером заметно ускоряет первую загрузку. Ключевая метрика — **cache hit ratio**, доля запросов, обслуженных из кеша. Чем она выше, тем меньше нагрузка на origin и быстрее ответы. ## Управление кешем Что и как долго хранить, CDN решает по стандартным заголовкам кеширования [HTTP](https://llmdocs.ru/wiki/http.md).[1][2] | Заголовок | Назначение | |---|---| | `Cache-Control: max-age=N` | сколько секунд ответ свежий для любого кеша | | `Cache-Control: s-maxage=N` | то же, но только для общих кешей (CDN, прокси) | | `Cache-Control: no-store` / `private` | не кешировать / кешировать только в браузере | | `ETag`, `Last-Modified` | валидаторы для условных запросов (`304 Not Modified`) | | `Vary` | от каких заголовков запроса зависит ответ (например, `Accept-Encoding`) | | `stale-while-revalidate` | разрешает отдать устаревшую копию, пока в фоне идёт обновление[3] | Ключ кеша по умолчанию — схема, хост, путь и строка запроса. Лишние параметры (`utm_source` и подобные) дробят кеш, поэтому их часто исключают из ключа в настройках CDN. Есть два способа обновлять контент: - **версионирование имён** — файлы собираются с хешем в имени (`app.3f9a1c.js`) и кешируются «навсегда» (`max-age=31536000, immutable`), а новая версия получает новое имя. Это предпочтительный путь; - **инвалидация** (*purge*) — явная команда CDN удалить объект или группу объектов по пути или тегу. Она нужна для HTML и контента, у которого адрес постоянный. ```bash # посмотреть, отдан ли ответ из кеша CDN curl -sI https://example.com/logo.png | grep -iE 'cache-control|age|x-cache|cf-cache-status' ``` Заголовок `Age` показывает, сколько секунд объект лежит в кеше; провайдеры добавляют свои — `X-Cache: HIT`, `CF-Cache-Status: HIT` и т. п. ## Что ещё делает CDN - **Защита от DDoS** — распределённая сеть поглощает объёмные атаки, а веб-фильтр (WAF) отсекает вредоносные запросы. - **Сжатие и оптимизация** — Brotli/gzip, преобразование изображений в WebP/AVIF, поддержка [HTTP/2 и HTTP/3](https://llmdocs.ru/wiki/http2-http3.md). - **Потоковое видео** — HLS и DASH нарезают видео на короткие сегменты, которые прекрасно кешируются. - **Вычисления на краю** (*edge computing*) — небольшие функции, исполняемые прямо в PoP (Cloudflare Workers, Fastly Compute, Lambda@Edge): редиректы, A/B-тесты, проверка токенов. ## Ограничения - Динамические персональные страницы кешировать нельзя или трудно — для них CDN даёт в основном выигрыш на TLS и маршруте. - Неверные заголовки опасны: кеширование ответа с `Set-Cookie` или персональными данными может показать чужую страницу другому пользователю. - CDN становится единой точкой отказа: сбой крупного провайдера выводит из строя тысячи сайтов одновременно. - Провайдер видит расшифрованный трафик, поскольку TLS завершается на его узлах. Для небольшого сайта, например [статического](https://llmdocs.ru/wiki/static-site-generators.md), CDN часто достаточно даже без собственного сервера: многие хостинги сами раскладывают файлы по своей сети. ## См. также - [Балансировка нагрузки](https://llmdocs.ru/wiki/load-balancing.md) - [nginx](https://llmdocs.ru/wiki/nginx.md) - [QUIC](https://llmdocs.ru/wiki/quic.md) - [Обратный прокси (reverse proxy)](https://llmdocs.ru/wiki/reverse-proxy.md) ## Источники 1. [RFC 9111 — HTTP Caching](https://www.rfc-editor.org/rfc/rfc9111) 2. [MDN — HTTP caching](https://developer.mozilla.org/en-US/docs/Web/HTTP/Caching) 3. [RFC 5861 — HTTP Cache-Control Extensions for Stale Content](https://www.rfc-editor.org/rfc/rfc5861) 4. [Cloudflare Learning — What is a CDN?](https://www.cloudflare.com/learning/cdn/what-is-a-cdn/) 5. [Nygren, Sitaraman, Sun — The Akamai Network: A Platform for High-Performance Internet Applications (2010)](https://dl.acm.org/doi/10.1145/1842733.1842736) 6. [RFC 4786 — Operation of Anycast Services](https://www.rfc-editor.org/rfc/rfc4786) --- # DNS-записи (A, AAAA, CNAME, MX, TXT) > Типы ресурсных записей DNS — A и AAAA (адреса), CNAME (псевдоним), MX (почта), TXT (произвольный текст, SPF, DKIM, проверка домена), NS, SOA, CAA, SRV, HTTPS — и их настройка. Источник: https://llmdocs.ru/wiki/dns-records/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Базовая спецификация**: RFC 1034, RFC 1035 (1987) - **Формат записи**: имя, TTL, класс, тип, данные - **Адреса**: A (IPv4), AAAA (IPv6, RFC 3596) - **Почта**: MX, а также TXT для SPF, DKIM, DMARC - **Новые типы**: CAA (RFC 8659), HTTPS и SVCB (RFC 9460, 2023) - **Инструменты**: dig, nslookup, host **DNS-записи** (ресурсные записи) — строки в зоне домена, которые хранят сведения о нём в системе доменных имён [DNS](https://llmdocs.ru/wiki/dns.md): на какой IP-адрес указывает имя, куда доставлять почту, какие серверы обслуживают зону, какие центры сертификации могут выпускать сертификаты. Каждая запись имеет **имя**, **тип**, **данные** и **TTL** — время в секундах, в течение которого резолверы могут кэшировать ответ.[1] Настройка записей — повседневная задача при запуске сайта, подключении почты, выпуске сертификатов и подтверждении владения доменом для внешних сервисов. ## Формат ```text ; имя TTL класс тип данные example.com. 3600 IN A 93.184.215.14 example.com. 3600 IN AAAA 2606:2800:21f:cb07:6820:80da:af6b:8b2c www.example.com. 3600 IN CNAME example.com. example.com. 3600 IN MX 10 mail.example.com. example.com. 3600 IN TXT "v=spf1 include:_spf.google.com -all" ``` Символ `@` в панелях управления обозначает сам домен (корень зоны, *apex*), точка в конце имени — полное имя, а класс почти всегда `IN` (интернет). ## Основные типы | Тип | Данные | Назначение | |---|---|---| | **A** | IPv4-адрес | имя → адрес IPv4 | | **AAAA** | IPv6-адрес | имя → адрес [IPv6](https://llmdocs.ru/wiki/ipv6.md)[2] | | **CNAME** | другое имя | псевдоним: «смотри туда» | | **MX** | приоритет и имя почтового сервера | куда доставлять почту домена | | **TXT** | произвольный текст | SPF, DKIM, DMARC, подтверждение владения | | **NS** | имя DNS-сервера | какие серверы авторитетны для зоны | | **SOA** | параметры зоны | основной сервер, контакт, серийный номер, таймеры | | **PTR** | имя | обратная запись: адрес → имя | | **SRV** | приоритет, вес, порт, хост | где находится служба (`_sip._tcp`) | | **CAA** | центр сертификации | кому разрешено выпускать сертификаты | | **HTTPS, SVCB** | параметры подключения | поддерживаемые протоколы (HTTP/3), альтернативные адреса, ключи ECH | ### A и AAAA Самые частые записи: связывают имя с адресом сервера. У одного имени может быть несколько записей A — клиенты выбирают из них, что даёт простейшую балансировку. Адресация описана в статье [IP-адрес и подсети (CIDR)](https://llmdocs.ru/wiki/ip-cidr.md). ### CNAME CNAME делает имя псевдонимом другого имени: `www.example.com CNAME example.com`, или `shop.example.com CNAME shops.platform.net` для внешнего сервиса. Ограничения: у имени с CNAME не может быть других записей, поэтому **CNAME нельзя поставить на корень домена**, где обязательно есть NS и SOA. Многие DNS-провайдеры обходят это псевдотипами ALIAS или ANAME («уплощение CNAME»), которые разрешают имя на своей стороне и отдают обычные A-записи. ### MX ```text example.com. MX 10 mx1.mail.example.com. example.com. MX 20 mx2.mail.example.com. ``` Меньшее число — выше приоритет; при недоступности первого сервера почта пойдёт на второй. MX должна указывать на имя с A/AAAA-записью, а не на CNAME или IP-адрес. ### TXT Универсальная запись для текстовых данных: - **SPF** — какие серверы могут отправлять почту от имени домена: `v=spf1 include:_spf.google.com -all`.[4] - **DKIM** — открытый ключ для проверки подписи писем, на имени вида `selector._domainkey.example.com`. - **DMARC** — политика обработки писем, не прошедших проверку: `_dmarc.example.com TXT "v=DMARC1; p=quarantine"`. - **Подтверждение владения** доменом для Google, поисковых систем, облачных сервисов и выпуска сертификатов через DNS-проверку ([Let's Encrypt и ACME](https://llmdocs.ru/wiki/lets-encrypt-acme.md)). ### CAA и HTTPS Запись **CAA** ограничивает круг центров сертификации: `example.com CAA 0 issue "letsencrypt.org"` — остальным выпуск запрещён.[5] Записи **HTTPS** (RFC 9460) сообщают браузеру ещё до подключения, что сервер поддерживает HTTP/3, и могут нести ключи для шифрования ClientHello.[3] ## TTL и распространение изменений Изменение записи не видно мгновенно: резолверы хранят старый ответ до истечения TTL. Перед переездом сервера TTL заранее уменьшают (например, до 300 секунд), а после переключения снова увеличивают. Выражение «DNS распространяется до 48 часов» описывает именно кэширование; при разумном TTL изменения расходятся за минуты. ## Проверка ```bash dig example.com A +short # адрес IPv4 dig example.com AAAA +short dig example.com MX dig _dmarc.example.com TXT +short dig example.com NS dig @1.1.1.1 example.com # спросить конкретный резолвер dig +trace example.com # пройти путь от корневых серверов dig -x 93.184.215.14 +short # обратная запись (PTR) ``` Полезно сравнивать ответы разных резолверов и авторитетных серверов зоны, чтобы понять, обновилась ли запись и не мешает ли кэш. Обзор типов записей с примерами — в справочнике Cloudflare.[6] ## Типичные ошибки - CNAME на корне домена или рядом с другими записями того же имени. - Несколько записей SPF вместо одной — проверка почты ломается. - Забытая точка в конце полного имени в файлах зон: `mail.example.com` превращается в `mail.example.com.example.com`. - Высокий TTL перед запланированным переездом. - Отсутствие обратной записи PTR для почтового сервера — письма попадают в спам. ## См. также - [DNS](https://llmdocs.ru/wiki/dns.md) - [IP-адрес и подсети (CIDR)](https://llmdocs.ru/wiki/ip-cidr.md) - [Let's Encrypt и ACME](https://llmdocs.ru/wiki/lets-encrypt-acme.md) - [IPv6](https://llmdocs.ru/wiki/ipv6.md) - [CDN](https://llmdocs.ru/wiki/cdn.md) ## Источники 1. [RFC 1035 — Domain Names: Implementation and Specification](https://www.rfc-editor.org/rfc/rfc1035) 2. [RFC 3596 — DNS Extensions to Support IP Version 6](https://www.rfc-editor.org/rfc/rfc3596) 3. [RFC 9460 — Service Binding and Parameter Specification via the DNS (SVCB and HTTPS)](https://www.rfc-editor.org/rfc/rfc9460) 4. [RFC 7208 — Sender Policy Framework (SPF)](https://www.rfc-editor.org/rfc/rfc7208) 5. [RFC 8659 — DNS Certification Authority Authorization (CAA)](https://www.rfc-editor.org/rfc/rfc8659) 6. [Cloudflare Learning — DNS records](https://www.cloudflare.com/learning/dns/dns-records/) --- # DNS > Распределённая иерархическая система, которая сопоставляет доменные имена с IP-адресами и другими данными. Источник: https://llmdocs.ru/wiki/dns/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Полное название**: Domain Name System - **Уровень модели OSI**: прикладной - **Порт**: 53 (UDP и TCP) - **Создан**: 1983 - **Автор**: Пол Мокапетрис - **Стандарт**: RFC 1034, RFC 1035 (1987) - **Защищённые варианты**: DNSSEC, DNS over TLS, DNS over HTTPS, DNS over QUIC **DNS** (англ. *Domain Name System* — система доменных имён) — распределённая иерархическая база данных, которая переводит понятные человеку имена вроде `example.com` в IP-адреса и хранит другие сведения о доменах: почтовые серверы, текстовые записи, псевдонимы. DNS — одна из базовых служб интернета: практически любое сетевое соединение начинается с DNS-запроса. ## История В ранней сети ARPANET соответствие имён и адресов хранилось в одном файле `HOSTS.TXT`, который вручную обновлял Сетевой информационный центр в Стэнфорде, а все узлы периодически его скачивали. С ростом сети такая схема перестала работать. В 1983 году Пол Мокапетрис описал систему доменных имён в RFC 882 и RFC 883, а в 1987 году их заменили RFC 1034 и RFC 1035, которые остаются основой протокола.[1][2] Пережитком старой схемы является файл `/etc/hosts`, который по-прежнему проверяется до обращения к DNS. ## Устройство Пространство имён DNS — дерево. Его вершина — **корневая зона** (обозначается точкой), ниже — домены верхнего уровня (`ru`, `com`, `org`), затем домены второго уровня (`example.com`) и так далее. Каждая часть дерева может быть **делегирована** отдельной организации: владелец домена сам управляет его зоной и может делегировать поддомены дальше. Корневую зону обслуживают 13 логических корневых серверов с именами от `a.root-servers.net` до `m.root-servers.net`. Ими управляют 12 организаций, а физически каждый «сервер» — это сотни узлов по всему миру, объединённых технологией anycast.[3] Различают два типа серверов: - **авторитетные** хранят данные своей зоны и отвечают на запросы о ней окончательно; - **рекурсивные резолверы** (у провайдера, в роутере, публичные) принимают запрос клиента, сами обходят иерархию и кешируют ответы. ## Разрешение имени Когда браузер запрашивает `docs.example.com`, происходит следующее (если ответа нет в кешах): 1. Приложение обращается к системному резолверу, тот — к рекурсивному серверу. 2. Рекурсивный сервер спрашивает корневой сервер и получает список серверов зоны `com`. 3. Сервер зоны `com` отвечает, какие серверы авторитетны для `example.com` (записи NS). 4. Авторитетный сервер `example.com` возвращает запись A или AAAA для `docs.example.com`. 5. Ответ кешируется на время, указанное в поле **TTL**, и возвращается клиенту. Обычно запросы идут по [UDP](https://llmdocs.ru/wiki/udp.md); [TCP](https://llmdocs.ru/wiki/tcp.md) используется для больших ответов и передачи зон между серверами. ## Типы записей | Тип | Назначение | Пример значения | |---|---|---| | A | IPv4-адрес | `192.0.2.10` | | AAAA | IPv6-адрес | `2001:db8::10` | | CNAME | псевдоним другого имени | `www → example.com.` | | MX | почтовый сервер с приоритетом | `10 mail.example.com.` | | NS | авторитетные серверы зоны | `ns1.example.net.` | | TXT | произвольный текст (SPF, проверка владения) | `"v=spf1 -all"` | | SOA | параметры зоны | серийный номер, таймеры | | CAA | какие центры сертификации могут выпускать сертификаты | `0 issue "letsencrypt.org"` | | SRV | расположение сервиса | приоритет, вес, порт, узел | Подробнее — в статье [DNS-записи (A, AAAA, CNAME, MX, TXT)](https://llmdocs.ru/wiki/dns-records.md). Звёздочка в имени (`*.example.com`) задаёт **wildcard-запись**, которая отвечает за все поддомены без собственной записи. ## Инструменты ```bash dig example.com A +short # адрес dig example.com MX # почтовые серверы с полным ответом dig +trace docs.example.com # пройти всю цепочку от корня dig @1.1.1.1 example.com # спросить конкретный резолвер nslookup example.com # кросс-платформенный аналог ``` ## Безопасность Классический DNS не шифрует и не подписывает данные, поэтому запросы видны всем на пути и могут быть подменены (атака «отравление кеша»). - **DNSSEC** (RFC 4033–4035, 2005) добавляет цифровые подписи записей и цепочку доверия от корня; корневая зона подписана в 2010 году.[4] DNSSEC защищает от подмены, но не скрывает содержимое запросов. - **DNS over TLS** (DoT, RFC 7858, порт 853) шифрует запросы с помощью [TLS](https://llmdocs.ru/wiki/tls.md).[5] - **DNS over HTTPS** (DoH, RFC 8484) передаёт запросы внутри [HTTPS](https://llmdocs.ru/wiki/http.md) и неотличим от обычного веб-трафика.[6] - **DNS over QUIC** (DoQ, RFC 9250) использует [QUIC](https://llmdocs.ru/wiki/quic.md).[7] ## См. также - [IP-адрес и подсети (CIDR)](https://llmdocs.ru/wiki/ip-cidr.md) - [TLS](https://llmdocs.ru/wiki/tls.md) - [Let's Encrypt и ACME](https://llmdocs.ru/wiki/lets-encrypt-acme.md) - [CDN](https://llmdocs.ru/wiki/cdn.md) ## Источники 1. [RFC 1034 — Domain Names: Concepts and Facilities](https://www.rfc-editor.org/rfc/rfc1034) 2. [RFC 1035 — Domain Names: Implementation and Specification](https://www.rfc-editor.org/rfc/rfc1035) 3. [Root Servers — IANA](https://www.iana.org/domains/root/servers) 4. [RFC 4033 — DNS Security Introduction and Requirements](https://www.rfc-editor.org/rfc/rfc4033) 5. [RFC 7858 — DNS over TLS](https://www.rfc-editor.org/rfc/rfc7858) 6. [RFC 8484 — DNS Queries over HTTPS (DoH)](https://www.rfc-editor.org/rfc/rfc8484) 7. [RFC 9250 — DNS over Dedicated QUIC Connections](https://www.rfc-editor.org/rfc/rfc9250) --- # IP-адрес и подсети (CIDR) > IP-адрес — числовой идентификатор узла в сети IP; CIDR — способ записи и распределения диапазонов адресов в виде «адрес/длина префикса». Источник: https://llmdocs.ru/wiki/ip-cidr/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Длина адреса IPv4**: 32 бита (4 октета) - **Длина адреса IPv6**: 128 бит - **Запись IPv4**: 192.0.2.10 - **CIDR**: RFC 1518/1519 (1993), RFC 4632 (2006) - **Частные диапазоны IPv4**: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 (RFC 1918) - **Распределение**: IANA → региональные регистраторы (RIPE NCC, ARIN, APNIC…) - **Исчерпание IPv4 у IANA**: февраль 2011 **IP-адрес** — числовой идентификатор сетевого интерфейса в сети, работающей по протоколу IP (см. [TCP/IP](https://llmdocs.ru/wiki/tcp-ip.md)). По нему маршрутизаторы доставляют пакеты получателю. **CIDR** (англ. *Classless Inter-Domain Routing* — «бесклассовая междоменная маршрутизация») — способ описывать и распределять **подсети**, то есть непрерывные диапазоны адресов, в форме `адрес/длина префикса`, например `192.168.1.0/24`. Подсети в нотации CIDR встречаются повсюду: в настройках файрволов и облачных сетей, в правилах доступа к базам данных, в конфигурации [Docker](https://llmdocs.ru/wiki/docker.md) и [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md), в списках разрешённых адресов API. ## Устройство адреса IPv4 Адрес IPv4 — 32-битное число, которое записывают как четыре десятичных октета через точку: `192.168.1.10`. Адрес делится на две части: **сетевую** (префикс, общий для всех узлов подсети) и **узловую** (номер конкретного узла). Где проходит граница, определяет длина префикса или эквивалентная ей **маска подсети**: ```text адрес 192.168.1.10 11000000.10101000.00000001.00001010 маска 255.255.255.0 11111111.11111111.11111111.00000000 (/24) сеть 192.168.1.0 первые 24 бита — сеть, последние 8 — узел ``` Два узла находятся в одной подсети, если их адреса совпадают в префиксной части; тогда они общаются напрямую, а иначе отправляют пакеты через маршрутизатор (шлюз по умолчанию). Адреса IPv6 устроены так же, только длиной 128 бит (см. [IPv6](https://llmdocs.ru/wiki/ipv6.md)). ## От классов к CIDR Изначально адреса делились на классы: A (сеть /8, 16,7 млн адресов), B (/16, 65 тыс.) и C (/24, 256). Организации, которой не хватало класса C, приходилось выдавать класс B, и адреса расходовались впустую, а таблицы маршрутизации разрастались. В 1993 году ввели CIDR: префикс может быть любой длины, а несколько соседних сетей можно объявить одним маршрутом — **агрегировать**.[1] ## Таблица префиксов | Префикс | Маска | Адресов | Пригодно для узлов | |---|---|---|---| | /8 | 255.0.0.0 | 16 777 216 | 16 777 214 | | /16 | 255.255.0.0 | 65 536 | 65 534 | | /24 | 255.255.255.0 | 256 | 254 | | /28 | 255.255.255.240 | 16 | 14 | | /30 | 255.255.255.252 | 4 | 2 | | /31 | 255.255.255.254 | 2 | 2 (точка-точка) | | /32 | 255.255.255.255 | 1 | один узел | В подсети из `2^(32 − n)` адресов первый — адрес самой сети, последний — широковещательный, поэтому узлам достаётся на два меньше (кроме /31 и /32). Запись `/32` используют, чтобы указать ровно один адрес, например в правиле файрвола. ## Особые диапазоны | Диапазон | Назначение | |---|---| | `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16` | частные сети (RFC 1918)[2] | | `127.0.0.0/8` | петлевой интерфейс (`127.0.0.1` — localhost) | | `169.254.0.0/16` | локальные адреса канала, автоматическая настройка без DHCP | | `100.64.0.0/10` | общее адресное пространство провайдеров (CGNAT)[4] | | `192.0.2.0/24`, `198.51.100.0/24`, `203.0.113.0/24` | для документации и примеров | | `224.0.0.0/4` | многоадресная рассылка (multicast) | | `0.0.0.0/0` | «любой адрес» — маршрут по умолчанию | Полный перечень ведёт IANA.[3] Частные адреса не маршрутизируются в интернете: чтобы устройства домашней или офисной сети выходили наружу, роутер подменяет их внешним адресом с помощью [NAT](https://llmdocs.ru/wiki/nat.md). ## Распределение адресов Адресами управляет IANA, раздающая крупные блоки пяти региональным интернет-регистраторам (для Европы, Ближнего Востока и России — RIPE NCC), а те выдают их провайдерам и организациям. Свободный пул IPv4 у IANA закончился в феврале 2011 года, у RIPE NCC — в 2019-м. С тех пор адреса IPv4 продают и сдают в аренду, а облачные провайдеры берут плату за публичные адреса. Долгосрочное решение — переход на IPv6. ## Практика ```bash ip -4 addr show # адреса и префиксы интерфейсов ip route # маршруты; default via ... — шлюз ipcalc 10.20.0.0/20 # границы подсети (утилита ipcalc) ``` В [Python](https://llmdocs.ru/wiki/python.md) с адресами удобно работать через модуль `ipaddress`:[6] ```python import ipaddress net = ipaddress.ip_network("10.20.0.0/20") print(net.num_addresses, net[1], net[-2]) # 4096 10.20.0.1 10.20.15.254 print(ipaddress.ip_address("10.20.7.9") in net) # True print(list(net.subnets(new_prefix=22))) # четыре подсети /22 ``` ## Типичные ошибки - Пересечение диапазонов: внутренняя сеть Docker (по умолчанию из `172.17.0.0/16`) или облачная VPC совпадает с офисной сетью или сетью VPN, и часть адресов становится недоступна. - Правило «открыть для `0.0.0.0/0`» в группе безопасности облака открывает сервис всему интернету. - Путаница между адресом подсети и адресом узла: в правиле `192.168.1.10/24` имеется в виду вся сеть `192.168.1.0/24`. ## См. также - [TCP/IP](https://llmdocs.ru/wiki/tcp-ip.md) - [IPv6](https://llmdocs.ru/wiki/ipv6.md) - [NAT](https://llmdocs.ru/wiki/nat.md) - [DNS](https://llmdocs.ru/wiki/dns.md) - [Модель OSI](https://llmdocs.ru/wiki/osi-model.md) ## Источники 1. [RFC 4632 — Classless Inter-domain Routing (CIDR)](https://www.rfc-editor.org/rfc/rfc4632) 2. [RFC 1918 — Address Allocation for Private Internets](https://www.rfc-editor.org/rfc/rfc1918) 3. [IANA — IPv4 Special-Purpose Address Registry](https://www.iana.org/assignments/iana-ipv4-special-registry/) 4. [RFC 6598 — IANA-Reserved IPv4 Prefix for Shared Address Space](https://www.rfc-editor.org/rfc/rfc6598) 5. [RFC 791 — Internet Protocol](https://www.rfc-editor.org/rfc/rfc791) 6. [Python documentation — ipaddress](https://docs.python.org/3/library/ipaddress.html) --- # IPv6 > Шестая версия интернет-протокола со 128-битными адресами; решает проблему нехватки адресов IPv4, упрощает заголовок и делает NAT необязательным. Источник: https://llmdocs.ru/wiki/ipv6/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Полное название**: Internet Protocol version 6 - **Уровень OSI**: сетевой (3) - **Стандарт**: RFC 8200 (2017), первоначально RFC 1883 (1995) - **Длина адреса**: 128 бит - **Запись**: восемь групп по 4 шестнадцатеричные цифры - **Предшественник**: IPv4 (32 бита) - **Автонастройка**: SLAAC, DHCPv6 - **DNS-запись**: AAAA **IPv6** (*Internet Protocol version 6*) — версия сетевого протокола интернета, пришедшая на смену IPv4. Главное отличие — длина адреса: 128 бит вместо 32, то есть около 3,4×10³⁸ адресов против 4,3 миллиарда. Этого хватает, чтобы выдать каждому устройству глобально уникальный адрес и обходиться без [NAT](https://llmdocs.ru/wiki/nat.md). Протокол также упрощает заголовок пакета, встраивает автонастройку адресов и заменяет широковещательные рассылки на групповые (multicast). Основы адресации и подсетей описаны в статье [IP-адрес и подсети (CIDR)](https://llmdocs.ru/wiki/ip-cidr.md). ## История Исчерпание адресов IPv4 предсказывали ещё в начале 1990-х. IETF выбрала проект нового протокола (рабочее название IPng) и в 1995 году опубликовала первую спецификацию IPv6 — RFC 1883; актуальная версия — RFC 8200 (2017).[1] Номер 5 был занят экспериментальным протоколом потоковой передачи ST. Внедрение шло медленно: NAT и CIDR продлили жизнь IPv4. Региональные регистраторы раздали последние свободные блоки IPv4 в 2011–2019 годах. По статистике Google, к середине 2020-х около 45–50% пользователей обращаются к его сервисам по IPv6; доля сильно различается по странам.[5] ## Запись адресов Адрес записывается восемью группами по 16 бит в шестнадцатеричном виде: ``` 2001:0db8:0000:0000:0000:ff00:0042:8329 ``` Правила сокращения (RFC 5952):[3] ведущие нули в группе опускаются, а одна самая длинная последовательность нулевых групп заменяется на `::`. Получается `2001:db8::ff00:42:8329`. Буквы пишутся строчными. В URL адрес заключают в квадратные скобки: `http://[2001:db8::1]:8080/`. Префикс сети обозначается так же, как в IPv4: `/64`. Типичная схема — провайдер выдаёт клиенту `/48` или `/56`, а каждая локальная сеть получает `/64`, где младшие 64 бита — идентификатор интерфейса. ## Типы адресов | Префикс | Тип | Назначение | |---|---|---| | `::1/128` | loopback | аналог `127.0.0.1` | | `::/128` | неопределённый | «ещё нет адреса» | | `fe80::/10` | link-local | есть на каждом интерфейсе, не маршрутизируется | | `fc00::/7` (на практике `fd00::/8`) | ULA | частные адреса, аналог `10.0.0.0/8` | | `2000::/3` | global unicast | публичные адреса | | `ff00::/8` | multicast | групповая рассылка | | `2001:db8::/32` | документация | для примеров | | `::ffff:0:0/96` | IPv4-mapped | IPv4-адрес внутри IPv6-сокета | В IPv6 нет широковещательных адресов: их роль выполняют multicast-группы, например `ff02::1` — все узлы сегмента.[2] ## Отличия от IPv4 - **Заголовок** фиксированной длины 40 байт; необязательные поля вынесены в цепочку дополнительных заголовков (extension headers). Нет контрольной суммы заголовка — её проверяют канальный и транспортный уровни. - **Фрагментацию** выполняет только отправитель; маршрутизаторы не дробят пакеты, а сообщают ICMPv6 «Packet Too Big». Поэтому блокировать ICMPv6 на файрволе нельзя — сломается определение MTU. - **ARP заменён** протоколом Neighbor Discovery (NDP) поверх ICMPv6: он же находит маршрутизаторы и обнаруживает конфликты адресов. - **Автонастройка SLAAC**: узел получает от маршрутизатора объявление с префиксом (Router Advertisement) и сам формирует адрес.[4] Для приватности используются временные случайные адреса (RFC 8981), а не MAC-адрес. DHCPv6 применяется, когда нужен централизованный контроль. ## Переход и сосуществование Интернет ещё долго будет двухпротокольным. Основные механизмы: - **Dual stack** — узел имеет и IPv4, и IPv6. Клиенты выбирают протокол по алгоритму *Happy Eyeballs*: пробуют IPv6 и через небольшую задержку IPv4, используя то соединение, что установилось первым.[6] - **NAT64/DNS64** — сеть только на IPv6 обращается к IPv4-ресурсам через транслятор; распространено в мобильных сетях. - **Туннели** (6in4, 6rd, исторические Teredo и 6to4) передают IPv6 поверх IPv4. В [DNS](https://llmdocs.ru/wiki/dns.md) адресу IPv6 соответствует запись `AAAA` (см. [DNS-записи (A, AAAA, CNAME, MX, TXT)](https://llmdocs.ru/wiki/dns-records.md)). ## Практика ```bash ip -6 addr show # адреса IPv6 на интерфейсах ip -6 route # маршруты ping -6 google.com # проверка связности curl -6 https://ifconfig.co # свой публичный IPv6 dig AAAA example.com +short # AAAA-запись ``` Отсутствие NAT не означает отсутствия защиты: каждый узел доступен из интернета по глобальному адресу, поэтому входящий трафик фильтрует файрвол (stateful firewall на маршрутизаторе). Частая ошибка — настроить правила только для IPv4 и оставить сервис открытым по IPv6. ## См. также - [IP-адрес и подсети (CIDR)](https://llmdocs.ru/wiki/ip-cidr.md) - [TCP/IP](https://llmdocs.ru/wiki/tcp-ip.md) - [NAT](https://llmdocs.ru/wiki/nat.md) - [Модель OSI](https://llmdocs.ru/wiki/osi-model.md) ## Источники 1. [RFC 8200 — Internet Protocol, Version 6 (IPv6) Specification](https://www.rfc-editor.org/rfc/rfc8200) 2. [RFC 4291 — IP Version 6 Addressing Architecture](https://www.rfc-editor.org/rfc/rfc4291) 3. [RFC 5952 — A Recommendation for IPv6 Address Text Representation](https://www.rfc-editor.org/rfc/rfc5952) 4. [RFC 4862 — IPv6 Stateless Address Autoconfiguration](https://www.rfc-editor.org/rfc/rfc4862) 5. [Google — IPv6 Statistics](https://www.google.com/intl/en/ipv6/statistics.html) 6. [RFC 8305 — Happy Eyeballs Version 2](https://www.rfc-editor.org/rfc/rfc8305) --- # Let's Encrypt и ACME > Let's Encrypt — бесплатный автоматизированный центр сертификации; ACME — открытый протокол, по которому программы автоматически получают и продлевают TLS-сертификаты. Источник: https://llmdocs.ru/wiki/lets-encrypt-acme/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: некоммерческий центр сертификации - **Оператор**: Internet Security Research Group (ISRG) - **Запуск**: первый сертификат — сентябрь 2015, публичная бета — декабрь 2015 - **Протокол**: ACME (RFC 8555, март 2019) - **Срок действия сертификата**: 90 дней - **Типы проверок**: HTTP-01, DNS-01, TLS-ALPN-01 - **Типы сертификатов**: DV, включая wildcard (через DNS-01) - **Клиенты**: Certbot, acme.sh, lego, Caddy, cert-manager **Let's Encrypt** — бесплатный, автоматизированный и открытый центр сертификации, выдающий сертификаты для [TLS](https://llmdocs.ru/wiki/tls.md). **ACME** (англ. *Automatic Certificate Management Environment*) — протокол, по которому программа на сервере сама доказывает владение доменом, получает сертификат и продлевает его без участия человека. Вместе они сделали HTTPS нормой: до их появления сертификат стоил денег и требовал ручной возни, а сегодня большая часть веб-страниц загружается по HTTPS.[6] ## История Проект основала некоммерческая организация Internet Security Research Group (ISRG) при участии Mozilla, Electronic Frontier Foundation, Мичиганского университета и других. Первый сертификат был выпущен в сентябре 2015 года, публичная бета открылась в декабре 2015-го, а в апреле 2016 года сервис вышел из беты. Протокол ACME, созданный для Let's Encrypt, был стандартизирован IETF как RFC 8555 в марте 2019 года.[2] В 2018 году со второй версией протокола появились wildcard-сертификаты (`*.example.com`). Let's Encrypt — один из крупнейших центров сертификации в мире: он обслуживает сотни миллионов сайтов.[6] Протокол ACME поддерживают и другие центры сертификации — ZeroSSL, Google Trust Services, Buypass, — поэтому клиент можно переключить на другого поставщика одной настройкой. ## Как работает ACME Let's Encrypt выдаёт сертификаты с проверкой домена (DV): он удостоверяет только, что заявитель контролирует доменное имя (подробнее — [Сертификат X.509 и центры сертификации](https://llmdocs.ru/wiki/x509-certificates.md)).[1] 1. Клиент создаёт учётную запись — пару ключей, которой подписывает все запросы к серверу ACME. 2. Клиент оформляет **заказ** на сертификат для одного или нескольких имён. 3. Для каждого имени сервер выдаёт **проверку** (*challenge*), и клиент её выполняет. 4. Сервер проверяет выполнение со своей стороны (с нескольких точек в интернете). 5. Клиент отправляет запрос на подпись сертификата (CSR) и получает цепочку сертификатов. 6. Примерно за треть срока до окончания клиент повторяет процедуру автоматически. ## Типы проверок | Проверка | Как подтверждается владение | Особенности | |---|---|---| | HTTP-01 | файл по адресу `http://<домен>/.well-known/acme-challenge/<токен>` | нужен доступ к порту 80; wildcard не поддерживает | | DNS-01 | TXT-запись `_acme-challenge.<домен>` | единственный способ для wildcard; работает для серверов, закрытых из интернета; нужен API DNS-провайдера | | TLS-ALPN-01 | особый сертификат при TLS-подключении к порту 443 | для прокси и балансировщиков, которым не нужен порт 80 | Подробности — в документации Let's Encrypt.[3] Для DNS-01 нужно создать [TXT-запись](https://llmdocs.ru/wiki/dns-records.md), поэтому клиенты поддерживают API десятков DNS-провайдеров. ## Короткий срок жизни Сертификаты Let's Encrypt действуют 90 дней, а не год или два, как было принято раньше. Это сделано сознательно: короткий срок уменьшает ущерб при утечке закрытого ключа и вынуждает автоматизировать продление — ручное продление раз в три месяца неудобно, поэтому его просто не делают вручную. Индустрия идёт дальше: Let's Encrypt предлагает и сертификаты на несколько дней, а требования браузеров к максимальному сроку действия сертификатов постепенно ужесточаются. ## Клиенты ```bash # Certbot (EFF): получить сертификат и настроить nginx sudo certbot --nginx -d example.com -d www.example.com sudo certbot renew --dry-run # проверить автопродление # acme.sh: wildcard через DNS-API провайдера acme.sh --issue --dns dns_cf -d example.com -d '*.example.com' ``` - **Certbot** — эталонный клиент от EFF, умеет сам настраивать [nginx](https://llmdocs.ru/wiki/nginx.md) и Apache и ставит таймер продления (см. [cron и таймеры systemd](https://llmdocs.ru/wiki/cron-systemd-timers.md)).[5] - **acme.sh** — клиент на чистом shell без зависимостей; **lego** — на Go. - **[Caddy](https://llmdocs.ru/wiki/caddy.md)** и Traefik получают и продлевают сертификаты сами, без отдельного клиента: достаточно указать домен в конфигурации. - **cert-manager** выпускает сертификаты для [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) и хранит их в объектах Secret.[7] ## Ограничения - Только проверка домена (DV): нет сертификатов с проверкой организации (OV/EV) и сертификатов для IP-адресов в классическом виде. - Лимиты на частоту выпуска: например, не больше 50 сертификатов на зарегистрированный домен в неделю и ограниченное число неудачных проверок. Для отладки используют тестовый сервер (*staging*) с мягкими лимитами.[4] - Перед выпуском центр сертификации проверяет DNS-запись CAA: если владелец домена разрешил выпуск только другому центру, Let's Encrypt откажет. - Все выпущенные сертификаты публикуются в журналах прозрачности сертификатов (Certificate Transparency) — по ним можно узнать имена поддоменов. Для внутренних имён это стоит учитывать или использовать wildcard. ## См. также - [TLS](https://llmdocs.ru/wiki/tls.md) - [Сертификат X.509 и центры сертификации](https://llmdocs.ru/wiki/x509-certificates.md) - [Caddy](https://llmdocs.ru/wiki/caddy.md) - [nginx](https://llmdocs.ru/wiki/nginx.md) - [DNS](https://llmdocs.ru/wiki/dns.md) ## Источники 1. [Let's Encrypt — How It Works](https://letsencrypt.org/how-it-works/) 2. [RFC 8555 — Automatic Certificate Management Environment (ACME)](https://www.rfc-editor.org/rfc/rfc8555) 3. [Let's Encrypt — Challenge Types](https://letsencrypt.org/docs/challenge-types/) 4. [Let's Encrypt — Rate Limits](https://letsencrypt.org/docs/rate-limits/) 5. [Certbot — EFF](https://certbot.eff.org/) 6. [Let's Encrypt — Statistics](https://letsencrypt.org/stats/) 7. [cert-manager — documentation](https://cert-manager.io/docs/) --- # Балансировка нагрузки > Распределение входящих запросов между несколькими серверами ради производительности и отказоустойчивости; бывает на уровне L4 (TCP/UDP) и L7 (HTTP). Источник: https://llmdocs.ru/wiki/load-balancing/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Назначение**: масштабирование и отказоустойчивость - **Уровни**: L4 (транспортный), L7 (прикладной) - **Алгоритмы**: round robin, least connections, хеширование, EWMA - **Программные**: HAProxy, nginx, Envoy, Traefik, IPVS - **Облачные**: AWS ELB (ALB/NLB), Google Cloud LB, Yandex NLB/ALB - **Связанные**: health checks, sticky sessions, Anycast **Балансировка нагрузки** (англ. *load balancing*) — распределение входящих запросов или соединений между несколькими экземплярами сервиса. Она решает две задачи: **масштабирование** (нагрузку, которую не выдержит один сервер, делят несколько) и **отказоустойчивость** (упавший экземпляр исключается, клиенты продолжают работать). Балансировщик обычно стоит перед группой серверов как единая точка входа и часто совмещает роль [обратного прокси](https://llmdocs.ru/wiki/reverse-proxy.md): завершает [TLS](https://llmdocs.ru/wiki/tls.md), кэширует, ограничивает частоту запросов. ## Уровни балансировки | | L4 (транспортный) | L7 (прикладной) | |---|---|---| | Что видит | IP-адреса и порты [TCP](https://llmdocs.ru/wiki/tcp.md)/[UDP](https://llmdocs.ru/wiki/udp.md) | HTTP-заголовки, пути, cookie, gRPC-методы | | Решение принимается | на соединение | на каждый запрос | | Скорость | очень высокая, возможна в ядре | ниже, нужен разбор протокола | | TLS | проходит насквозь | обычно завершается на балансировщике | | Примеры | IPVS, AWS NLB, HAProxy `mode tcp`, Maglev | nginx, HAProxy `mode http`, Envoy, AWS ALB | L7-балансировщик умеет маршрутизировать по содержимому: `/api` — на один пул, `/static` — на другой; переключать трафик между версиями (canary, blue-green); повторять неудачные запросы. L4 дешевле и универсальнее — подходит для баз данных, очередей и любых TCP-протоколов.[3] ## Алгоритмы - **Round robin** — по кругу; с весами — пропорционально мощности серверов. Простой и предсказуемый вариант по умолчанию.[1] - **Least connections** — на сервер с наименьшим числом активных соединений; хорош для долгих запросов и WebSocket. - **Power of two choices** — выбрать два случайных сервера и отдать запрос менее загруженному; почти так же хорош, как полный перебор, но масштабируется лучше (используется в Envoy). - **Хеширование** по IP клиента, URL или заголовку — один и тот же ключ всегда попадает на один сервер. **Консистентное хеширование** (кольцо, Maglev) минимизирует перераспределение ключей при добавлении или удалении серверов — важно для кэшей.[5] - **EWMA / least response time** — учитывает задержку ответов, отправляя меньше трафика медленным узлам. ## Проверки здоровья Балансировщик периодически опрашивает серверы (**health checks**): активно — открывает TCP-соединение или запрашивает `GET /healthz` — и пассивно, отслеживая ошибки в реальном трафике. Сервер, не прошедший несколько проверок подряд, выводится из ротации и возвращается после восстановления. При плановом выводе узла используют **draining**: новые соединения на него не идут, а текущие завершаются спокойно. ## Состояние и липкие сессии Если приложение хранит сессию в памяти конкретного сервера, пользователь должен каждый раз попадать на него — это **sticky sessions** (по cookie балансировщика или хешу IP). Такая привязка мешает равномерному распределению и теряет сессии при падении узла, поэтому предпочтительнее хранить состояние вне серверов — в Redis или базе данных (см. [Cookie и сессии](https://llmdocs.ru/wiki/cookies-sessions.md)). Сервисы без состояния масштабируются горизонтально простым добавлением экземпляров. ## Где балансируют - **DNS** — несколько A/AAAA-записей или ответы в зависимости от географии (GeoDNS). Грубо: кэширование [DNS](https://llmdocs.ru/wiki/dns.md) мешает быстро убрать упавший узел. - **Anycast** — один IP-адрес анонсируется из многих точек по BGP, трафик идёт в ближайшую; так работают [CDN](https://llmdocs.ru/wiki/cdn.md) и публичные DNS-резолверы. - **Выделенный балансировщик** — аппаратный (F5, Citrix) или программный (HAProxy, [nginx](https://llmdocs.ru/wiki/nginx.md), Envoy) перед группой серверов. Чтобы он сам не стал единой точкой отказа, ставят пару с общим виртуальным IP (keepalived, VRRP). - **Внутри кластера** — в [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) объект Service распределяет трафик между подами через kube-proxy (iptables/IPVS) или eBPF, а Ingress и Gateway API выполняют L7-маршрутизацию (см. [Service и Ingress](https://llmdocs.ru/wiki/service-ingress.md)).[4] - **На стороне клиента** — клиент сам получает список экземпляров (из service discovery) и выбирает; так устроены gRPC и service mesh (Envoy-сайдкары в Istio). ## Пример: nginx ```nginx upstream app { least_conn; server 10.0.0.11:8000 weight=2; server 10.0.0.12:8000; server 10.0.0.13:8000 backup; } server { listen 80; location / { proxy_pass http://app; proxy_next_upstream error timeout http_502; } } ``` Открытая версия nginx делает только пассивные проверки (`max_fails`, `fail_timeout`); активные проверки есть в nginx Plus, HAProxy и Envoy.[2] ## См. также - [Обратный прокси (reverse proxy)](https://llmdocs.ru/wiki/reverse-proxy.md) - [nginx](https://llmdocs.ru/wiki/nginx.md) - [CDN](https://llmdocs.ru/wiki/cdn.md) - [Service и Ingress](https://llmdocs.ru/wiki/service-ingress.md) ## Источники 1. [HAProxy Configuration Manual — balance](https://docs.haproxy.org/3.0/configuration.html#4.2-balance) 2. [nginx — HTTP Load Balancing](https://docs.nginx.com/nginx/admin-guide/load-balancer/http-load-balancer/) 3. [Envoy — Load balancing overview](https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/upstream/load_balancing/overview) 4. [Kubernetes — Service](https://kubernetes.io/docs/concepts/services-networking/service/) 5. [Google — Maglev: A Fast and Reliable Software Network Load Balancer (NSDI 2016)](https://research.google/pubs/maglev-a-fast-and-reliable-software-network-load-balancer/) 6. [RFC 7098 — Using the IPv6 Flow Label for Load Balancing in Server Farms](https://www.rfc-editor.org/rfc/rfc7098) --- # NAT > Трансляция сетевых адресов — подмена IP-адресов и портов в пакетах на маршрутизаторе, позволяющая многим устройствам с частными адресами выходить в интернет через один публичный адрес. Источник: https://llmdocs.ru/wiki/nat/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Полное название**: Network Address Translation - **Спецификации**: RFC 1631 (1994), RFC 3022 (2001) - **Основная форма**: NAPT — трансляция адресов и портов - **Виды**: SNAT (исходящий), DNAT (проброс портов), CGNAT (на стороне провайдера) - **Причина появления**: нехватка адресов IPv4 - **Обход NAT**: STUN, TURN, ICE, пробивка «дыр» - **В Linux**: iptables и nftables (MASQUERADE, DNAT) **NAT** (англ. *Network Address Translation* — трансляция сетевых адресов) — механизм, при котором маршрутизатор подменяет IP-адреса (и обычно порты) в проходящих пакетах. Самый частый случай — домашний роутер: ноутбук, телефон и телевизор получают частные адреса вида `192.168.1.x`, а в интернет выходят через один публичный адрес роутера. Роутер запоминает, какое внутреннее устройство открыло соединение, и возвращает ответы по назначению. NAT появился как временная мера против нехватки адресов IPv4 (см. [IP-адрес и подсети (CIDR)](https://llmdocs.ru/wiki/ip-cidr.md)) и стал одной из самых распространённых технологий интернета. Окончательное решение проблемы адресов — [IPv6](https://llmdocs.ru/wiki/ipv6.md), где NAT обычно не нужен. ## Как работает Наиболее распространённая форма — **NAPT** (трансляция адресов и портов, она же PAT или «маскарадинг»):[1] 1. Ноутбук `192.168.1.10` отправляет пакет с порта 51000 на `93.184.215.14:443`. 2. Роутер заменяет адрес отправителя на свой публичный `203.0.113.5`, а порт — на свободный, например 40001, и записывает соответствие в **таблицу трансляций**. 3. Ответ приходит на `203.0.113.5:40001`; роутер находит запись и отправляет пакет на `192.168.1.10:51000`. Благодаря портам за одним адресом могут работать тысячи устройств. Записи таблицы живут, пока соединение активно: для [TCP](https://llmdocs.ru/wiki/tcp.md) — до закрытия соединения, для [UDP](https://llmdocs.ru/wiki/udp.md) — короткое время после последнего пакета. ## Виды | Вид | Что подменяется | Пример | |---|---|---| | SNAT, маскарадинг | адрес отправителя исходящих пакетов | выход домашней сети в интернет | | DNAT, проброс портов | адрес получателя входящих пакетов | порт 8080 роутера → сервер `192.168.1.20:80` | | Статический NAT 1:1 | один внутренний адрес ↔ один внешний | облачные «публичные IP» виртуальных машин | | CGNAT | NAT на стороне провайдера | абоненты делят общий адрес; пространство `100.64.0.0/10`[2] | При **CGNAT** абонент оказывается за двумя NAT — своим и провайдерским — и не может принимать входящие соединения, даже настроив проброс портов на домашнем роутере. ## NAT в Linux и контейнерах ```bash # nftables: выпускать подсеть 10.0.0.0/24 в интернет через eth0 nft add table ip nat nft add chain ip nat postrouting '{ type nat hook postrouting priority 100; }' nft add rule ip nat postrouting ip saddr 10.0.0.0/24 oif eth0 masquerade # проброс порта 8080 на внутренний сервер nft add chain ip nat prerouting '{ type nat hook prerouting priority -100; }' nft add rule ip nat prerouting iif eth0 tcp dport 8080 dnat to 10.0.0.20:80 sysctl -w net.ipv4.ip_forward=1 # разрешить маршрутизацию ``` Правила NAT в Linux задаются через nftables или iptables.[5] [Docker](https://llmdocs.ru/wiki/docker.md) использует именно этот механизм: контейнеры получают адреса во внутренней сети, исходящий трафик маскируется, а `-p 8080:80` создаёт правило DNAT. В [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) kube-proxy трансляцией адресов направляет трафик сервисов на поды. Опасная деталь: правила Docker обходят многие настройки файрвола хоста, поэтому опубликованный порт может оказаться открытым всему интернету (см. [Файрвол (iptables, nftables)](https://llmdocs.ru/wiki/firewall.md)). ## Проблемы NAT - **Входящие соединения невозможны** без проброса портов: устройство за NAT нельзя «позвать» снаружи. Это ломает прямые соединения между пользователями — видеозвонки, игры, P2P. - **Нарушение сквозной связности.** Протоколы, передающие адреса внутри данных (FTP, SIP), требуют специальных помощников на роутере. - **Таймауты.** Простаивающие соединения выпадают из таблицы — долгоживущим соединениям нужны пакеты поддержки (keepalive). - **Общий адрес.** За одним адресом CGNAT — тысячи абонентов; блокировка адреса за злоупотребления одного задевает остальных, а журналы и расследования усложняются. ## Обход NAT Для прямых соединений между устройствами за NAT используют набор техник, стандартный для WebRTC:[4] - **STUN** — сервер сообщает клиенту его внешний адрес и порт.[3] - **Пробивка «дыр»** (*hole punching*) — обе стороны одновременно отправляют пакеты друг другу, создавая записи в своих NAT. - **TURN** — если прямое соединение невозможно, трафик идёт через ретранслятор. - **ICE** — перебирает кандидатов (локальные, внешние, ретранслируемые адреса) и выбирает работающий путь. Успех зависит от поведения NAT: «полноконусные» устройства легко пропускают такие соединения, а симметричные NAT, выделяющие новый внешний порт для каждого адресата, — нет. Требования к поведению NAT для UDP описаны в RFC 4787.[6] На этих же техниках построены mesh-VPN вроде Tailscale. ## NAT и безопасность NAT часто воспринимают как защиту, потому что он не пропускает входящие соединения. Но это побочный эффект, а не функция безопасности: исходящие соединения и ответы проходят свободно, а защиту должен обеспечивать файрвол. В IPv6 без NAT ту же роль играет правило «запрещать входящие соединения, кроме разрешённых». ## См. также - [IP-адрес и подсети (CIDR)](https://llmdocs.ru/wiki/ip-cidr.md) - [IPv6](https://llmdocs.ru/wiki/ipv6.md) - [Файрвол (iptables, nftables)](https://llmdocs.ru/wiki/firewall.md) - [TCP/IP](https://llmdocs.ru/wiki/tcp-ip.md) - [UDP](https://llmdocs.ru/wiki/udp.md) ## Источники 1. [RFC 3022 — Traditional IP Network Address Translator (Traditional NAT)](https://www.rfc-editor.org/rfc/rfc3022) 2. [RFC 6598 — IANA-Reserved IPv4 Prefix for Shared Address Space](https://www.rfc-editor.org/rfc/rfc6598) 3. [RFC 8489 — Session Traversal Utilities for NAT (STUN)](https://www.rfc-editor.org/rfc/rfc8489) 4. [RFC 8445 — Interactive Connectivity Establishment (ICE)](https://www.rfc-editor.org/rfc/rfc8445) 5. [nftables wiki — Performing Network Address Translation](https://wiki.nftables.org/wiki-nftables/index.php/Performing_Network_Address_Translation_(NAT)) 6. [RFC 4787 — NAT Behavioral Requirements for Unicast UDP](https://www.rfc-editor.org/rfc/rfc4787) --- # nginx > Высокопроизводительный веб-сервер и обратный прокси с событийной архитектурой, созданный Игорем Сысоевым; один из самых распространённых веб-серверов в мире. Источник: https://llmdocs.ru/wiki/nginx/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: веб-сервер, обратный прокси, балансировщик, почтовый и TCP/UDP-прокси - **Автор**: Игорь Сысоев - **Первый публичный выпуск**: октябрь 2004 - **Язык**: C - **Лицензия**: BSD-2-Clause - **Архитектура**: событийная, асинхронная, несколько рабочих процессов - **Владелец торговой марки**: F5 (с 2019, ранее Nginx, Inc.) - **Форки**: freenginx (2024), Angie (2022) **nginx** (произносится «энджин-икс», от *engine x*) — веб-сервер и [обратный прокси](https://llmdocs.ru/wiki/reverse-proxy.md) с открытым исходным кодом. Его отличает **событийная архитектура**: небольшое число рабочих процессов обслуживает десятки тысяч одновременных соединений, расходуя мало памяти. nginx отдаёт статические файлы, завершает [TLS](https://llmdocs.ru/wiki/tls.md), проксирует запросы к приложениям, балансирует нагрузку, кэширует ответы и проксирует TCP и UDP. nginx — один из самых распространённых веб-серверов в мире; он работает на огромной доле самых посещаемых сайтов, а его производные используются как Ingress-контроллеры [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) и основа многих CDN. ## История Игорь Сысоев, системный администратор компании «Рамблер», начал писать nginx в 2002 году, чтобы решить **проблему C10K** — обслуживание десяти тысяч одновременных соединений на одном сервере, с которой плохо справлялся Apache с моделью «процесс или поток на соединение».[5] Первый публичный выпуск состоялся в октябре 2004 года под лицензией BSD. В 2011 году Сысоев с соратниками основал компанию Nginx, Inc., выпустившую коммерческую версию NGINX Plus; в 2019 году её купила американская F5 Networks. В 2022 году Сысоев покинул проект. Часть бывших разработчиков создала совместимый форк **Angie**, а в 2024 году один из ключевых разработчиков, Максим Дунин, запустил некоммерческий форк **freenginx**.[6] ## Архитектура Главный процесс читает конфигурацию и управляет **рабочими процессами** — обычно по одному на ядро процессора. Каждый рабочий процесс в цикле событий (epoll в Linux, kqueue в BSD) неблокирующе обрабатывает тысячи соединений: пока один клиент медленно получает данные, процесс обслуживает остальных. Это та же идея, что у [asyncio](https://llmdocs.ru/wiki/asyncio.md) и Node.js (см. [Конкурентность и параллелизм](https://llmdocs.ru/wiki/concurrency-parallelism.md)). Конфигурацию можно перечитать без разрыва соединений: `nginx -s reload` запускает новые рабочие процессы, а старые дорабатывают текущие запросы. ## Конфигурация Конфигурация — иерархия блоков: `http` содержит блоки `server` (виртуальные хосты), а те — блоки `location` для путей.[2] ```nginx # /etc/nginx/conf.d/example.conf server { listen 80; server_name example.com www.example.com; return 301 https://example.com$request_uri; # всё на HTTPS } server { listen 443 ssl; http2 on; server_name example.com; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; root /var/www/example; index index.html; gzip on; gzip_types text/css application/javascript application/json; location / { try_files $uri $uri/ =404; # статический сайт } location /api/ { proxy_pass http://127.0.0.1:8000; # приложение proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } ``` Выбор блока `server` идёт по порту, затем по имени из заголовка `Host` или [SNI](https://llmdocs.ru/wiki/sni.md), а `location` — по правилам: точное совпадение `=`, затем самый длинный префикс, затем регулярные выражения по порядку.[4] ```bash sudo nginx -t # проверить синтаксис конфигурации sudo systemctl reload nginx # применить без простоя sudo tail -f /var/log/nginx/error.log ``` ## Основные возможности - **Статика** — отдача файлов с помощью `sendfile`, кэширующие заголовки, сжатие. - **Проксирование** — HTTP, [WebSocket](https://llmdocs.ru/wiki/websocket.md), gRPC, FastCGI (PHP), uwsgi. - **Балансировка** — группы `upstream` с алгоритмами round robin, `least_conn`, `ip_hash`, `hash` и пассивной проверкой здоровья.[3] - **Кэш ответов** бэкенда на диске (`proxy_cache`). - **Ограничения** — частоты запросов (`limit_req`), числа соединений, размера тела запроса. - **TCP/UDP-прокси** (модуль `stream`) — для баз данных, DNS и маршрутизации TLS по SNI без расшифровки. - **HTTP/2 и HTTP/3** — HTTP/3 поверх [QUIC](https://llmdocs.ru/wiki/quic.md) поддерживается с версии 1.25 (2023). Сертификаты [Let's Encrypt](https://llmdocs.ru/wiki/lets-encrypt-acme.md) обычно выпускает и продлевает Certbot, умеющий сам править конфигурацию nginx. ## Типичные ошибки - `proxy_pass http://app/` с косой чертой в конце и без неё ведут себя по-разному: с косой чертой префикс `location` вырезается из пути. - Директива `if` внутри `location` работает неочевидно («if is evil»); для перенаправлений лучше `return` и `try_files`. - Забытый `client_max_body_size` — загрузка файлов больше 1 МБ падает с кодом 413. - Без `proxy_set_header Host` бэкенд получает имя upstream вместо домена сайта. - Ошибки 502 и 504 обычно означают проблемы бэкенда, а не nginx: смотрите `error.log` и логи приложения ([journald и логи](https://llmdocs.ru/wiki/journald-logs.md)). ## nginx и альтернативы [Caddy](https://llmdocs.ru/wiki/caddy.md) проще в настройке и сам получает сертификаты; HAProxy специализируется на балансировке; Traefik и Envoy рассчитаны на динамические окружения с контейнерами. Apache HTTP Server остаётся популярным благодаря `.htaccess` и модулям. nginx же сочетает зрелость, производительность и огромное количество готовых примеров конфигурации; полная справка по директивам — в официальной документации.[1] ## См. также - [Обратный прокси (reverse proxy)](https://llmdocs.ru/wiki/reverse-proxy.md) - [Caddy](https://llmdocs.ru/wiki/caddy.md) - [TLS](https://llmdocs.ru/wiki/tls.md) - [Let's Encrypt и ACME](https://llmdocs.ru/wiki/lets-encrypt-acme.md) - [HTTP](https://llmdocs.ru/wiki/http.md) ## Источники 1. [nginx — документация](https://nginx.org/en/docs/) 2. [nginx — Beginner's Guide](https://nginx.org/en/docs/beginners_guide.html) 3. [nginx — ngx_http_upstream_module](https://nginx.org/en/docs/http/ngx_http_upstream_module.html) 4. [nginx — How nginx processes a request](https://nginx.org/en/docs/http/request_processing.html) 5. [Dan Kegel — The C10K problem](http://www.kegel.com/c10k.html) 6. [freenginx](https://freenginx.org/) --- # Модель OSI > Эталонная семиуровневая модель сетевого взаимодействия ISO, разделяющая передачу данных на уровни от физического до прикладного; используется как общий словарь для описания сетей. Источник: https://llmdocs.ru/wiki/osi-model/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Полное название**: Open Systems Interconnection Basic Reference Model - **Разработчик**: ISO и CCITT (ныне ITU-T) - **Стандарт**: ISO/IEC 7498-1, ITU-T X.200 - **Первая редакция**: 1984 - **Число уровней**: 7 - **Альтернатива**: модель TCP/IP (4 уровня) **Модель OSI** (англ. *Open Systems Interconnection* — «взаимодействие открытых систем») — эталонная модель, которая делит сетевое взаимодействие на семь **уровней**, от передачи битов по проводу до прикладных программ. Каждый уровень решает свою задачу, пользуется услугами нижележащего и предоставляет услуги вышележащему. Модель утверждена Международной организацией по стандартизации (ISO) в 1984 году.[2] Сами протоколы OSI почти не прижились — интернет построен на стеке [TCP/IP](https://llmdocs.ru/wiki/tcp-ip.md). Но модель осталась **общим языком** сетевых инженеров: выражения «проблема на втором уровне», «балансировщик L4» или «файрвол L7» отсылают именно к её нумерации. ## История В конце 1970-х сети разных производителей (IBM SNA, DECnet) были несовместимы друг с другом. ISO и международный консультативный комитет по телеграфии и телефонии CCITT (ныне ITU-T) взялись создать открытую архитектуру, в которой любая система сможет общаться с любой. Эталонная модель вышла как стандарт ISO 7498 (1984) и рекомендация X.200; действующая редакция — ISO/IEC 7498-1:1994.[1] Параллельно развивался стек TCP/IP, уже работавший в ARPANET и бесплатно распространявшийся вместе с BSD Unix. Протоколы OSI оказались сложными, а их реализации — запоздавшими и дорогими; к середине 1990-х так называемая «война протоколов» закончилась победой TCP/IP. Из мира OSI в широком употреблении остались модель уровней, служба каталогов X.500 (из неё вырос формат сертификатов X.509) и протокол маршрутизации IS-IS. ## Семь уровней | № | Уровень | Что делает | Единица данных | Примеры | |---|---|---|---|---| | 7 | Прикладной (application) | сетевые функции для приложений | сообщение | [HTTP](https://llmdocs.ru/wiki/http.md), [DNS](https://llmdocs.ru/wiki/dns.md), SMTP, [SSH](https://llmdocs.ru/wiki/ssh.md) | | 6 | Представления (presentation) | кодирование, сжатие, шифрование | | TLS (частично), MIME, ASN.1 | | 5 | Сеансовый (session) | установление и поддержание сеансов | | RPC, NetBIOS | | 4 | Транспортный (transport) | доставка между процессами, порты, надёжность | сегмент / датаграмма | [TCP](https://llmdocs.ru/wiki/tcp.md), [UDP](https://llmdocs.ru/wiki/udp.md), [QUIC](https://llmdocs.ru/wiki/quic.md) | | 3 | Сетевой (network) | адресация и маршрутизация между сетями | пакет | IP, ICMP | | 2 | Канальный (data link) | передача кадров в пределах одной сети, MAC-адреса | кадр | Ethernet, Wi-Fi, ARP | | 1 | Физический (physical) | биты в виде сигналов: напряжение, свет, радио | бит | витая пара, оптоволокно, радиоэфир | Для запоминания порядка снизу вверх в англоязычной литературе используют фразу *«Please Do Not Throw Sausage Pizza Away»*. ## Инкапсуляция При отправке данные спускаются по уровням, и каждый уровень добавляет свой **заголовок**: HTTP-запрос помещается в TCP-сегмент с номерами портов, сегмент — в IP-пакет с адресами отправителя и получателя ([IP-адреса](https://llmdocs.ru/wiki/ip-cidr.md)), пакет — в Ethernet-кадр с MAC-адресами. Получатель снимает заголовки в обратном порядке. Каждый уровень «разговаривает» только с одноимённым уровнем на другой стороне и ничего не знает о содержимом. ```text [ Ethernet | IP | TCP | HTTP-запрос | контрольная сумма кадра ] L2 L3 L4 L7 ``` ## OSI и TCP/IP Модель TCP/IP, описанная в RFC 1122, проще: в ней четыре уровня — канальный, межсетевой, транспортный и прикладной.[3] Три верхних уровня OSI соответствуют одному прикладному уровню TCP/IP, а физический и канальный объединены. Реальные протоколы плохо укладываются в строгую схему. [TLS](https://llmdocs.ru/wiki/tls.md) работает поверх TCP, но под прикладным протоколом — его относят то к шестому, то к четвёртому уровню. [QUIC](https://llmdocs.ru/wiki/quic.md) реализует надёжную доставку как транспортный протокол, но работает поверх UDP и включает шифрование. Создатели интернета прямо предупреждали, что слишком жёсткое разделение на уровни может вредить (RFC 3439).[4] Поэтому модель OSI полезна как система координат, а не как точное описание. ## Как используется на практике - **Классы оборудования.** Коммутатор работает на втором уровне (пересылает кадры по MAC-адресам), маршрутизатор — на третьем (пересылает пакеты по IP-адресам). - **Балансировщики и прокси.** Балансировщик L4 распределяет TCP- и UDP-соединения, не заглядывая внутрь; балансировщик L7, например [nginx](https://llmdocs.ru/wiki/nginx.md) в роли [обратного прокси](https://llmdocs.ru/wiki/reverse-proxy.md), читает HTTP-запросы и может маршрутизировать по пути URL или заголовкам. - **Безопасность.** Межсетевые экраны фильтруют по адресам и портам (L3–L4), а WAF анализирует содержимое HTTP (L7). DDoS-атаки делят на объёмные (L3–L4) и прикладные (L7).[5] - **Диагностика.** Поиск неисправности обычно идёт снизу вверх: есть ли физическое соединение, получен ли IP-адрес, проходит ли `ping`, открыт ли порт, отвечает ли приложение. ## См. также - [TCP/IP](https://llmdocs.ru/wiki/tcp-ip.md) - [TCP](https://llmdocs.ru/wiki/tcp.md) - [UDP](https://llmdocs.ru/wiki/udp.md) - [IP-адрес и подсети (CIDR)](https://llmdocs.ru/wiki/ip-cidr.md) - [HTTP](https://llmdocs.ru/wiki/http.md) ## Источники 1. [ITU-T X.200 — Open Systems Interconnection: Basic Reference Model](https://www.itu.int/rec/T-REC-X.200-199407-I/en) 2. [ISO/IEC 7498-1:1994 — OSI Basic Reference Model](https://www.iso.org/standard/20269.html) 3. [RFC 1122 — Requirements for Internet Hosts: Communication Layers](https://www.rfc-editor.org/rfc/rfc1122) 4. [RFC 3439 — Some Internet Architectural Guidelines and Philosophy](https://www.rfc-editor.org/rfc/rfc3439) 5. [Cloudflare Learning — What is the OSI model?](https://www.cloudflare.com/learning/ddos/glossary/open-systems-interconnection-model-osi/) --- # QUIC > Транспортный протокол поверх UDP со встроенным шифрованием TLS 1.3, мультиплексированием потоков без блокировки и быстрым установлением соединения; основа HTTP/3. Источник: https://llmdocs.ru/wiki/quic/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Разработка**: Google (Джим Роскинд, 2012), затем IETF - **Стандарт**: RFC 9000 (май 2021), RFC 9001 (TLS), RFC 9002 (потери и перегрузка) - **Поверх**: UDP - **Шифрование**: TLS 1.3, встроено и обязательно - **Установление соединения**: 1-RTT, при повторном — 0-RTT - **Особенности**: независимые потоки, миграция соединения, шифрование заголовков - **Применение**: HTTP/3 (RFC 9114, 2022), DNS over QUIC, SMB, туннели **QUIC** — транспортный протокол, работающий поверх [UDP](https://llmdocs.ru/wiki/udp.md) и объединяющий функции [TCP](https://llmdocs.ru/wiki/tcp.md) (надёжная упорядоченная доставка, управление перегрузкой) и [TLS](https://llmdocs.ru/wiki/tls.md) (шифрование) в одном слое. Он устанавливает защищённое соединение за один круг «туда-обратно», передаёт много независимых потоков без взаимной блокировки и сохраняет соединение при смене сети — например, при переходе телефона с Wi-Fi на мобильный интернет. Название изначально расшифровывалось как *Quick UDP Internet Connections*, но в стандарте IETF это просто имя.[1] QUIC — основа **HTTP/3** (см. [HTTP/2 и HTTP/3](https://llmdocs.ru/wiki/http2-http3.md)); его поддерживают все основные браузеры, Google, Cloudflare, Meta и крупные CDN, а значительная доля веб-трафика уже идёт через QUIC. ## История Инженер Google Джим Роскинд спроектировал QUIC в 2012 году; в 2013 году Google начала использовать его между Chrome и своими сервисами. Работа на масштабе интернета описана в статье на SIGCOMM 2017: QUIC заметно сократил задержки поиска и буферизацию видео YouTube, особенно в медленных сетях.[5] С 2016 года протокол стандартизировала IETF, существенно его переработав: IETF QUIC использует стандартный TLS 1.3 вместо собственной криптографии Google. Основные спецификации вышли в мае 2021 года (RFC 9000–9002), HTTP/3 — в июне 2022 года (RFC 9114).[4] ## Зачем нужен новый транспорт У связки TCP + TLS есть проблемы, которые трудно исправить: - **Блокировка начала очереди.** TCP — один упорядоченный поток. В HTTP/2 по одному соединению идут десятки запросов, и потеря одного пакета задерживает их все. - **Медленное установление.** Рукопожатие TCP плюс рукопожатие TLS — два круга «туда-обратно» до первых данных. - **Окостенение протокола.** TCP реализован в ядрах операционных систем и «понимается» множеством промежуточных устройств — файрволов, NAT, балансировщиков. Любое изменение TCP годами не может распространиться, потому что сетевое оборудование отбрасывает непривычные пакеты. QUIC решает это, работая в пространстве пользователя поверх UDP (который пропускают почти все сети) и шифруя почти весь заголовок, чтобы промежуточные устройства не могли на него опираться. ## Основные возможности | Возможность | Как работает | |---|---| | Быстрое установление | транспортное и криптографическое рукопожатие объединены: 1-RTT; при повторном подключении данные можно отправить сразу (0-RTT) | | Потоки | много независимых упорядоченных потоков в одном соединении; потеря пакета задерживает только свой поток | | Встроенное шифрование | TLS 1.3 обязателен; шифруются данные и большая часть заголовков[2] | | Миграция соединения | соединение определяется идентификатором, а не IP-адресом и портом, поэтому переживает смену сети | | Управление перегрузкой | как в TCP (по умолчанию алгоритм в духе NewReno, на практике CUBIC и BBR), но развивается в приложении[3] | Режим 0-RTT имеет оговорку: первые данные можно перехватить и **воспроизвести повторно**, поэтому в нём отправляют только идемпотентные запросы. ## HTTP/3 HTTP/3 — это семантика [HTTP](https://llmdocs.ru/wiki/http.md) поверх QUIC. Браузер узнаёт о поддержке HTTP/3 из заголовка `Alt-Svc` или DNS-записи HTTPS, после чего пробует подключиться по UDP на порт 443 и при неудаче возвращается к HTTP/2 поверх TCP. ```bash curl --http3 -I https://cloudflare.com # если curl собран с поддержкой HTTP/3 ``` В инструментах разработчика браузера (вкладка «Сеть», столбец «Протокол») HTTP/3 отображается как `h3`. ## Реализации Поскольку QUIC работает в пространстве пользователя, реализаций много: quiche (Cloudflare, Rust), msquic (Microsoft), ngtcp2 (C), quic-go (Go), quinn (Rust), а также встроенные в Chromium, Firefox и серверы. [nginx](https://llmdocs.ru/wiki/nginx.md) поддерживает HTTP/3 с версии 1.25, [Caddy](https://llmdocs.ru/wiki/caddy.md) — по умолчанию. Помимо HTTP/3 QUIC используют DNS over QUIC (RFC 9250),[6] протокол SMB в Windows, туннели и VPN (MASQUE). ## Недостатки и ограничения - **Нагрузка на процессор.** Обработка в пространстве пользователя и шифрование каждого пакета дороже, чем TCP с аппаратными оптимизациями ядра; разрыв сокращается. - **Блокировка UDP.** Некоторые корпоративные сети и провайдеры блокируют или ограничивают UDP, поэтому клиенты обязаны уметь откатываться на TCP. - **Наблюдаемость.** Зашифрованные заголовки затрудняют диагностику сети и работу систем, анализирующих трафик; отладка требует ключей TLS (`SSLKEYLOGFILE`) и поддержки QUIC в Wireshark. - **Фильтрация.** Поскольку QUIC шифрует почти всё, включая часть рукопожатия, системы фильтрации трафика нередко блокируют его целиком. ## См. также - [HTTP/2 и HTTP/3](https://llmdocs.ru/wiki/http2-http3.md) - [UDP](https://llmdocs.ru/wiki/udp.md) - [TCP](https://llmdocs.ru/wiki/tcp.md) - [TLS](https://llmdocs.ru/wiki/tls.md) - [Модель OSI](https://llmdocs.ru/wiki/osi-model.md) ## Источники 1. [RFC 9000 — QUIC: A UDP-Based Multiplexed and Secure Transport](https://www.rfc-editor.org/rfc/rfc9000) 2. [RFC 9001 — Using TLS to Secure QUIC](https://www.rfc-editor.org/rfc/rfc9001) 3. [RFC 9002 — QUIC Loss Detection and Congestion Control](https://www.rfc-editor.org/rfc/rfc9002) 4. [RFC 9114 — HTTP/3](https://www.rfc-editor.org/rfc/rfc9114) 5. [A. Langley et al. — The QUIC Transport Protocol: Design and Internet-Scale Deployment (SIGCOMM 2017)](https://dl.acm.org/doi/10.1145/3098822.3098842) 6. [RFC 9250 — DNS over Dedicated QUIC Connections](https://www.rfc-editor.org/rfc/rfc9250) --- # Обратный прокси (reverse proxy) > Сервер, принимающий запросы клиентов от имени одного или нескольких серверов приложений; завершает TLS, балансирует нагрузку, кэширует, сжимает и маршрутизирует трафик. Источник: https://llmdocs.ru/wiki/reverse-proxy/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Где стоит**: перед серверами приложений, на стороне сервера - **Функции**: завершение TLS, балансировка, кэш, сжатие, маршрутизация, ограничение частоты - **Популярные**: nginx, HAProxy, Caddy, Traefik, Envoy - **В облаке**: балансировщики нагрузки, CDN, API-шлюзы - **В Kubernetes**: Ingress-контроллеры, Gateway API - **Передача адреса клиента**: X-Forwarded-For, Forwarded (RFC 7239) **Обратный прокси** (англ. *reverse proxy*) — сервер, который стоит перед одним или несколькими серверами приложений и принимает запросы клиентов вместо них. Клиент обращается к прокси, как к самому сайту, прокси пересылает запрос подходящему внутреннему серверу (бэкенду), получает ответ и возвращает его клиенту. Клиент ничего не знает о бэкендах: их количество, адреса и технологии скрыты.[1] Обычный (прямой) прокси работает на стороне клиента и выходит в интернет от его имени; обратный — на стороне сервера и представляет сервис перед интернетом. Почти любой сайт работает за обратным прокси — [nginx](https://llmdocs.ru/wiki/nginx.md), [Caddy](https://llmdocs.ru/wiki/caddy.md), HAProxy, облачным балансировщиком или [CDN](https://llmdocs.ru/wiki/cdn.md). ## Зачем нужен | Функция | Что даёт | |---|---| | Завершение TLS | сертификаты и шифрование в одном месте; бэкенды работают по обычному HTTP во внутренней сети | | Балансировка нагрузки | распределение запросов между несколькими экземплярами приложения, исключение упавших | | Маршрутизация | `/api` → сервис API, `/` → фронтенд, `admin.example.com` → панель управления | | Кэширование и сжатие | статика и повторяющиеся ответы отдаются без обращения к приложению | | Защита | ограничение частоты запросов, размеров тел, фильтрация, скрытие внутренней структуры | | Буферизация | медленные клиенты не занимают процессы приложения | | Обновления без простоя | переключение трафика между версиями | Сервер приложения на [Python](https://llmdocs.ru/wiki/python.md) или Node.js обычно не стоит выставлять в интернет напрямую: он хуже справляется с тысячами медленных соединений, [TLS](https://llmdocs.ru/wiki/tls.md), сжатием и атаками, чем специализированный прокси. ## Пример: nginx ```nginx upstream app { server 127.0.0.1:8001; server 127.0.0.1:8002; # два экземпляра приложения } server { listen 443 ssl; http2 on; server_name example.com; ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem; location /static/ { root /var/www/example; # статику отдаёт сам прокси expires 30d; } location / { proxy_pass http://app; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } ``` Директива `proxy_pass` пересылает запросы группе `upstream`, а заголовки передают бэкенду сведения о настоящем клиенте.[2] В [Caddy](https://llmdocs.ru/wiki/caddy.md) та же задача решается одной строкой `reverse_proxy 127.0.0.1:8001 127.0.0.1:8002`, а сертификат выпускается автоматически. ## Адрес клиента и заголовки Для бэкенда все запросы приходят с адреса прокси. Настоящий адрес клиента и исходный протокол передают заголовками `X-Forwarded-For`, `X-Forwarded-Proto` и `X-Forwarded-Host` или стандартным `Forwarded` (RFC 7239).[3] Бэкенд должен **доверять этим заголовкам только от своего прокси**: иначе клиент подделает `X-Forwarded-For` и обойдёт ограничения по IP. Фреймворки для этого имеют настройки доверенных прокси (например, `--forwarded-allow-ips` в Uvicorn для [FastAPI](https://llmdocs.ru/wiki/fastapi.md)). Если бэкенд не знает, что исходный запрос был по HTTPS, он может строить ссылки и редиректы на `http://` — классическая ошибка «бесконечного редиректа», которую решает `X-Forwarded-Proto`. ## Балансировка Алгоритмы распределения запросов: по кругу (*round robin*), по наименьшему числу соединений, по хешу адреса клиента или ключа (чтобы клиент попадал на один и тот же бэкенд). Прокси проверяет здоровье бэкендов — пассивно по ошибкам или активно запросами к `/health` — и исключает неисправные. Балансировку на уровне TCP (L4) и HTTP (L7) различают по тому, читает ли прокси содержимое запросов (см. [Модель OSI](https://llmdocs.ru/wiki/osi-model.md)). ## Популярные решения | Прокси | Особенности | |---|---| | [nginx](https://llmdocs.ru/wiki/nginx.md) | веб-сервер и прокси, самый распространённый | | HAProxy | специализированный балансировщик L4/L7, высокая производительность[4] | | [Caddy](https://llmdocs.ru/wiki/caddy.md) | автоматический HTTPS, простая конфигурация | | Traefik | автоматическое обнаружение сервисов в Docker и Kubernetes[5] | | Envoy | прокси для микросервисов, основа service mesh, динамическая конфигурация через API[6] | В [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) роль обратного прокси выполняют Ingress-контроллеры и реализации Gateway API (см. [Service и Ingress](https://llmdocs.ru/wiki/service-ingress.md)), в облаке — управляемые балансировщики, а API-шлюзы добавляют аутентификацию, квоты и аналитику. ## Типичные проблемы - **Ошибки 502 и 504** — прокси не смог получить ответ от бэкенда: приложение упало, недоступно или отвечает дольше тайм-аута (см. [Коды состояния HTTP](https://llmdocs.ru/wiki/http-status-codes.md)). - **WebSocket и потоковые ответы** требуют настройки: передачи заголовков `Upgrade` и `Connection`, отключения буферизации для потоковой генерации. - **Ограничение размера тела** (`client_max_body_size` в nginx) — загрузка больших файлов падает с кодом 413. - **Двойное сжатие или кэширование** персональных ответов — кэш должен учитывать заголовки `Cache-Control` и `Vary`. ## См. также - [nginx](https://llmdocs.ru/wiki/nginx.md) - [Caddy](https://llmdocs.ru/wiki/caddy.md) - [Балансировка нагрузки](https://llmdocs.ru/wiki/load-balancing.md) - [CDN](https://llmdocs.ru/wiki/cdn.md) - [Service и Ingress](https://llmdocs.ru/wiki/service-ingress.md) ## Источники 1. [Cloudflare Learning — What is a reverse proxy?](https://www.cloudflare.com/learning/cdn/glossary/reverse-proxy/) 2. [nginx — ngx_http_proxy_module](https://nginx.org/en/docs/http/ngx_http_proxy_module.html) 3. [RFC 7239 — Forwarded HTTP Extension](https://www.rfc-editor.org/rfc/rfc7239) 4. [HAProxy Documentation](https://docs.haproxy.org/) 5. [Traefik Documentation](https://doc.traefik.io/traefik/) 6. [Envoy Proxy Documentation](https://www.envoyproxy.io/docs) --- # SNI > Расширение TLS, в котором клиент в начале рукопожатия сообщает имя сайта; позволяет держать много HTTPS-сайтов с разными сертификатами на одном IP-адресе. Передаётся открыто, его шифрует Encrypted Client Hello. Источник: https://llmdocs.ru/wiki/sni/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Полное название**: Server Name Indication - **Спецификация**: RFC 3546 (2003), действующая — RFC 6066 - **Где передаётся**: в сообщении ClientHello рукопожатия TLS - **Назначение**: виртуальный хостинг HTTPS на одном IP-адресе - **Видимость**: открытым текстом (кроме ECH) - **Шифрование имени**: Encrypted Client Hello (ECH) **SNI** (англ. *Server Name Indication* — указание имени сервера) — расширение протокола [TLS](https://llmdocs.ru/wiki/tls.md), с помощью которого клиент в самом первом сообщении рукопожатия (ClientHello) сообщает, к какому доменному имени он подключается. Сервер, обслуживающий много сайтов на одном IP-адресе, по этому имени выбирает нужный сертификат и конфигурацию.[1] Без SNI каждому HTTPS-сайту требовался бы отдельный IP-адрес. Сегодня SNI отправляют все браузеры и HTTP-клиенты, и именно он позволяет хостингам, [CDN](https://llmdocs.ru/wiki/cdn.md) и [обратным прокси](https://llmdocs.ru/wiki/reverse-proxy.md) обслуживать тысячи доменов на общих адресах. ## Проблема, которую решает SNI В обычном [HTTP](https://llmdocs.ru/wiki/http.md) сервер узнаёт сайт из заголовка `Host`, поэтому на одном адресе легко размещать много сайтов (*виртуальный хостинг*). В HTTPS заголовок `Host` передаётся уже внутри зашифрованного канала, а чтобы установить канал, сервер должен сначала предъявить сертификат — но какой, если он ещё не знает, какой сайт нужен клиенту? SNI решает это, передавая имя до выбора сертификата. Расширение описано в RFC 3546 в 2003 году, а сейчас — в RFC 6066.[2] Долгое время массовому использованию мешали старые клиенты — Internet Explorer на Windows XP и ранние версии Android, — но с их уходом SNI стал универсальным. ## Как это выглядит ```bash # подключиться к IP-адресу, указав имя сайта для SNI openssl s_client -connect 203.0.113.10:443 -servername example.com Стек сетевых протоколов, на котором построен интернет; IP обеспечивает адресацию и маршрутизацию пакетов, TCP и UDP — доставку данных между программами. Источник: https://llmdocs.ru/wiki/tcp-ip/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Полное название**: Internet Protocol Suite - **Авторы**: Винтон Серф, Роберт Кан - **Первая публикация**: 1974 - **Внедрение в ARPANET**: 1 января 1983 - **Уровни**: канальный, межсетевой, транспортный, прикладной - **Основные протоколы**: IP (v4, v6), TCP, UDP, ICMP - **Стандартизация**: IETF (документы RFC) **TCP/IP** (англ. *Internet Protocol Suite* — «набор протоколов интернета») — семейство сетевых протоколов, на котором работает интернет и почти все локальные сети. Название составлено из двух главных протоколов: **IP** (*Internet Protocol*) отвечает за адресацию и доставку пакетов между сетями, а **TCP** (*Transmission Control Protocol*) — за надёжную передачу потока данных между программами. Рядом с ними работают [UDP](https://llmdocs.ru/wiki/udp.md), ICMP и множество прикладных протоколов — [HTTP](https://llmdocs.ru/wiki/http.md), [DNS](https://llmdocs.ru/wiki/dns.md), [SSH](https://llmdocs.ru/wiki/ssh.md). Также TCP/IP называют четырёхуровневую модель, которая описывает этот стек и служит практической альтернативой [модели OSI](https://llmdocs.ru/wiki/osi-model.md). ## История В начале 1970-х в США работала сеть ARPANET, но она не умела соединяться с другими сетями — радио- и спутниковыми. В 1974 году Винтон Серф и Роберт Кан опубликовали статью «Протокол для межсетевого взаимодействия пакетных сетей» с идеей единого протокола поверх разнородных сетей.[1] Позже монолитный протокол разделили на два: IP для маршрутизации и TCP для надёжной доставки; так стало возможным добавить UDP для задач, которым надёжность не нужна. Спецификации IP и TCP вышли как RFC 791 и RFC 793 в 1981 году.[2] 1 января 1983 года ARPANET полностью перешла на TCP/IP — эту дату часто называют днём рождения интернета. Реализация стека в BSD Unix, свободно распространявшаяся университетам, сделала TCP/IP стандартом де-факто. В 2004 году Серф и Кан получили премию Тьюринга. Спецификация TCP в 2022 году была собрана заново в RFC 9293.[3] ## Уровни | Уровень | Задача | Протоколы | Аналог в OSI | |---|---|---|---| | Прикладной | обмен данными приложений | HTTP, DNS, [TLS](https://llmdocs.ru/wiki/tls.md), SMTP, SSH | 5–7 | | Транспортный | доставка между процессами (порты) | [TCP](https://llmdocs.ru/wiki/tcp.md), [UDP](https://llmdocs.ru/wiki/udp.md), [QUIC](https://llmdocs.ru/wiki/quic.md) (поверх UDP) | 4 | | Межсетевой | адресация и маршрутизация пакетов | IPv4, [IPv6](https://llmdocs.ru/wiki/ipv6.md), ICMP | 3 | | Канальный | передача в пределах одной сети | Ethernet, Wi-Fi, ARP | 1–2 | Описание модели с этими четырьмя уровнями дано в RFC 1122.[5] ## IP IP доставляет **пакеты** — порции данных с заголовком, где указаны адрес отправителя и получателя. Каждый маршрутизатор по пути смотрит на адрес назначения и решает, куда переслать пакет дальше. IP работает по принципу «наилучшей попытки» (*best effort*): пакеты могут теряться, дублироваться и приходить не по порядку, и протокол этого не исправляет. Используются две версии: IPv4 с 32-битными адресами (около 4,3 млрд) и [IPv6](https://llmdocs.ru/wiki/ipv6.md) со 128-битными.[6] Адреса IPv4 давно исчерпаны, и нехватку компенсирует [NAT](https://llmdocs.ru/wiki/nat.md) — трансляция многих внутренних адресов в один внешний. Адресация и разбиение на подсети описаны в статье [IP-адрес и подсети (CIDR)](https://llmdocs.ru/wiki/ip-cidr.md). ## TCP и UDP Программы на одном компьютере различаются **портами** — числами от 0 до 65535. Пара «IP-адрес и порт» с обеих сторон однозначно определяет соединение: веб-сервер слушает порт 443, а браузер подключается со случайного порта. | | TCP | UDP | |---|---|---| | Соединение | устанавливается тройным рукопожатием | нет | | Надёжность | подтверждения, повторная передача, порядок | нет | | Управление потоком и перегрузкой | есть | нет | | Единица | поток байтов | отдельные датаграммы | | Применение | веб, почта, SSH, базы данных | DNS, видеозвонки, игры, QUIC | TCP устанавливает соединение обменом SYN — SYN-ACK — ACK, нумерует байты, подтверждает полученное, повторяет потерянное и регулирует скорость, чтобы не перегрузить сеть.[3] UDP просто отправляет датаграммы — быстро и без гарантий.[4] На UDP построен [QUIC](https://llmdocs.ru/wiki/quic.md), основа HTTP/3: он переносит надёжность и шифрование в пространство пользователя и избавляется от задержек TCP. ## Путь запроса Когда браузер открывает `https://example.com`: 1. [DNS](https://llmdocs.ru/wiki/dns.md) превращает имя в IP-адрес. 2. TCP устанавливает соединение с портом 443 (или QUIC — по UDP). 3. TLS шифрует канал. 4. HTTP-запрос делится на сегменты, сегменты упаковываются в IP-пакеты, пакеты — в Ethernet- или Wi-Fi-кадры. 5. Маршрутизаторы пересылают пакеты от сети к сети до сервера, где всё распаковывается в обратном порядке. ## Инструменты ```bash ip addr # адреса интерфейсов (Linux) ip route # таблица маршрутизации ping -c 4 example.com # доступность по ICMP traceroute example.com # путь пакетов через маршрутизаторы ss -tlnp # какие процессы слушают TCP-порты nc -vz example.com 443 # открыт ли порт sudo tcpdump -i any port 53 # перехват пакетов DNS ``` Для анализа трафика с графическим интерфейсом используют Wireshark, а для HTTP-уровня — [curl](https://llmdocs.ru/wiki/curl.md). ## См. также - [Модель OSI](https://llmdocs.ru/wiki/osi-model.md) - [TCP](https://llmdocs.ru/wiki/tcp.md) - [UDP](https://llmdocs.ru/wiki/udp.md) - [IP-адрес и подсети (CIDR)](https://llmdocs.ru/wiki/ip-cidr.md) - [DNS](https://llmdocs.ru/wiki/dns.md) ## Источники 1. [V. Cerf, R. Kahn — A Protocol for Packet Network Intercommunication (IEEE, 1974)](https://ieeexplore.ieee.org/document/1092259) 2. [RFC 791 — Internet Protocol](https://www.rfc-editor.org/rfc/rfc791) 3. [RFC 9293 — Transmission Control Protocol (TCP)](https://www.rfc-editor.org/rfc/rfc9293) 4. [RFC 768 — User Datagram Protocol](https://www.rfc-editor.org/rfc/rfc768) 5. [RFC 1122 — Requirements for Internet Hosts: Communication Layers](https://www.rfc-editor.org/rfc/rfc1122) 6. [RFC 8200 — Internet Protocol, Version 6 (IPv6) Specification](https://www.rfc-editor.org/rfc/rfc8200) --- # TCP > Протокол управления передачей — транспортный протокол интернета, обеспечивающий надёжную упорядоченную доставку потока байтов между программами с управлением потоком и перегрузкой. Источник: https://llmdocs.ru/wiki/tcp/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Полное название**: Transmission Control Protocol - **Авторы**: Винтон Серф, Роберт Кан - **Спецификация**: RFC 793 (1981), актуальная — RFC 9293 (2022) - **Уровень**: транспортный (модели OSI и TCP/IP) - **Гарантии**: надёжность, порядок, целостность, управление потоком и перегрузкой - **Установление соединения**: тройное рукопожатие (SYN, SYN-ACK, ACK) - **Алгоритмы перегрузки**: Reno, CUBIC (по умолчанию в Linux), BBR **TCP** (англ. *Transmission Control Protocol* — протокол управления передачей) — транспортный протокол стека [TCP/IP](https://llmdocs.ru/wiki/tcp-ip.md), который превращает ненадёжную доставку пакетов протоколом IP в надёжный упорядоченный поток байтов между двумя программами. TCP гарантирует, что данные дойдут полностью, без искажений и в том порядке, в каком были отправлены, а скорость передачи подстроится под возможности получателя и сети. Поверх TCP работают [HTTP](https://llmdocs.ru/wiki/http.md)/1.1 и HTTP/2, [TLS](https://llmdocs.ru/wiki/tls.md), [SSH](https://llmdocs.ru/wiki/ssh.md), почтовые протоколы, протоколы баз данных — большая часть трафика интернета. Альтернатива для задач, где важнее скорость, чем гарантии, — [UDP](https://llmdocs.ru/wiki/udp.md). ## История Винтон Серф и Роберт Кан описали протокол в 1974 году; позже его разделили на IP (маршрутизация) и TCP (надёжная доставка). Спецификация вышла как RFC 793 в 1981 году, а в 2022 году её переработали и объединили с последующими исправлениями в RFC 9293.[1] В 1986 году интернет пережил серию «коллапсов перегрузки», когда полезная пропускная способность падала в тысячу раз; Ван Якобсон в 1988 году предложил алгоритмы управления перегрузкой, которые спасли сеть и с изменениями используются до сих пор.[2] ## Установление и завершение соединения TCP — протокол **с установлением соединения**. Перед передачей данных стороны обмениваются тремя сегментами — **тройное рукопожатие**: ```text Клиент Сервер | ------ SYN (seq=x) ---------> | | <---- SYN-ACK (seq=y, ack=x+1) | | ------ ACK (ack=y+1) -------> | | соединение установлено | ``` Рукопожатие занимает один круг «туда-обратно» (RTT) до отправки первых данных, а TLS поверх TCP добавляет ещё один круг. Завершение — обмен сегментами FIN и ACK с каждой стороны; сторона, закрывшая соединение первой, проводит некоторое время в состоянии **TIME_WAIT**, чтобы опоздавшие пакеты не попали в новое соединение. Сегмент **RST** обрывает соединение немедленно — например, при попытке подключиться к закрытому порту. ## Надёжность и порядок - **Номера последовательности.** Каждый байт потока имеет номер; получатель собирает данные по порядку, даже если пакеты пришли вразнобой, и отбрасывает дубликаты. - **Подтверждения.** Получатель сообщает, до какого байта всё получено (ACK). Неподтверждённые данные отправитель повторяет по таймауту или после трёх повторных подтверждений (*fast retransmit*). - **Контрольная сумма** выявляет повреждённые сегменты. ## Управление потоком и перегрузкой **Управление потоком** защищает получателя: в каждом подтверждении он сообщает размер **окна** — сколько ещё байтов готов принять. Медленный получатель автоматически притормаживает быстрого отправителя. **Управление перегрузкой** защищает сеть. Отправитель держит *окно перегрузки* и увеличивает его, пока сеть справляется: сначала экспоненциально (**медленный старт**), затем линейно. Потеря пакета воспринимается как сигнал перегрузки, и окно резко уменьшается. Алгоритмы: | Алгоритм | Сигнал | Где используется | |---|---|---| | Reno, NewReno | потери пакетов | классика, учебники | | CUBIC | потери; рост окна по кубической функции времени | по умолчанию в Linux, Windows, macOS[3] | | BBR | оценка пропускной способности и минимальной задержки | Google, YouTube; полезен на каналах с потерями[4] | ```bash sysctl net.ipv4.tcp_congestion_control # текущий алгоритм в Linux sudo sysctl -w net.ipv4.tcp_congestion_control=bbr # включить BBR ``` ## Порты и сокеты Соединение однозначно определяется четвёркой: IP-адрес и порт клиента, IP-адрес и порт сервера. Сервер слушает известный порт (443 для HTTPS, 22 для SSH, 5432 для PostgreSQL), а клиент получает случайный временный порт. ```bash ss -tlnp # слушающие TCP-сокеты и процессы ss -tn state established # установленные соединения ss -s # сводка, включая TIME_WAIT nc -vz example.com 443 # проверить, открыт ли порт ``` Утилита `ss` — современная замена `netstat`.[6] ## Проблемы и оптимизации - **Блокировка начала очереди** (*head-of-line blocking*). Поток строго упорядочен: потеря одного пакета задерживает все последующие данные, даже относящиеся к другим запросам. В HTTP/2 это тормозит все параллельные потоки — главная причина появления [QUIC](https://llmdocs.ru/wiki/quic.md). - **Задержка установления.** Рукопожатие TCP плюс TLS — два круга до первого байта данных. TCP Fast Open позволяет отправлять данные уже в SYN при повторных соединениях,[5] TLS 1.3 сокращает своё рукопожатие до одного круга. - **Алгоритм Нейгла** склеивает мелкие записи в один сегмент, экономя трафик, но добавляя задержку; интерактивные приложения отключают его опцией `TCP_NODELAY`. - **Keepalive.** Простаивающие соединения могут обрываться промежуточными устройствами (NAT, файрволы); периодические проверки поддерживают их и выявляют «мёртвые» соединения. ## TCP и приложения Для программиста TCP — это сокет, в который пишут и из которого читают поток байтов. Важно помнить, что это **поток, а не сообщения**: один вызов `send` не обязательно соответствует одному `recv` на другой стороне. Протокол приложения должен сам разделять сообщения — длиной в заголовке, разделителями или, как в HTTP, заголовком `Content-Length`. ## См. также - [UDP](https://llmdocs.ru/wiki/udp.md) - [QUIC](https://llmdocs.ru/wiki/quic.md) - [TCP/IP](https://llmdocs.ru/wiki/tcp-ip.md) - [Модель OSI](https://llmdocs.ru/wiki/osi-model.md) - [HTTP/2 и HTTP/3](https://llmdocs.ru/wiki/http2-http3.md) ## Источники 1. [RFC 9293 — Transmission Control Protocol (TCP)](https://www.rfc-editor.org/rfc/rfc9293) 2. [V. Jacobson — Congestion Avoidance and Control (SIGCOMM 1988)](https://dl.acm.org/doi/10.1145/52324.52356) 3. [RFC 9438 — CUBIC for Fast and Long-Distance Networks](https://www.rfc-editor.org/rfc/rfc9438) 4. [N. Cardwell et al. — BBR: Congestion-Based Congestion Control (ACM Queue, 2016)](https://queue.acm.org/detail.cfm?id=3022184) 5. [RFC 7413 — TCP Fast Open](https://www.rfc-editor.org/rfc/rfc7413) 6. [ss(8) — Linux manual page](https://man7.org/linux/man-pages/man8/ss.8.html) --- # TLS > Криптографический протокол, обеспечивающий шифрование, целостность и аутентификацию соединений поверх TCP; основа HTTPS. Источник: https://llmdocs.ru/wiki/tls/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Полное название**: Transport Layer Security - **Предшественник**: SSL (Netscape, 1995–1996) - **Текущая версия**: TLS 1.3 (RFC 8446, август 2018) - **Поддерживаемые версии**: TLS 1.2, TLS 1.3 - **Работает поверх**: TCP (вариант для UDP — DTLS, встроен в QUIC) - **Порт HTTPS**: 443 - **Стандартизация**: IETF - **Реализации**: OpenSSL, BoringSSL, LibreSSL, GnuTLS, rustls, Go crypto/tls **TLS** (англ. *Transport Layer Security* — протокол защиты транспортного уровня) — криптографический протокол, который защищает передачу данных между двумя программами: шифрует трафик, проверяет его целостность и подтверждает подлинность сервера (а при необходимости и клиента) с помощью сертификатов. TLS — то, что превращает [HTTP](https://llmdocs.ru/wiki/http.md) в HTTPS; он же защищает почту (SMTP, IMAP), [DNS](https://llmdocs.ru/wiki/dns.md) (DoT, DoH), базы данных и множество других протоколов. Часто его по старой памяти называют SSL. ## История Протокол SSL (*Secure Sockets Layer*) разработала компания Netscape для своего браузера: SSL 2.0 вышел в 1995 году, SSL 3.0 — в 1996-м. Затем стандарт перешёл в IETF и был переименован: | Версия | Год | Документ | Статус | |---|---|---|---| | SSL 3.0 | 1996 | RFC 6101 (исторический) | запрещён с 2015 (RFC 7568)[4] | | TLS 1.0 | 1999 | RFC 2246 | устарел, RFC 8996 (2021)[3] | | TLS 1.1 | 2006 | RFC 4346 | устарел, RFC 8996 | | TLS 1.2 | 2008 | RFC 5246[2] | поддерживается | | TLS 1.3 | 2018 | RFC 8446[1] | актуальный | Отказ от старых версий ускорили атаки на протокол и его реализации: BEAST (2011), CRIME (2012), POODLE (2014, против SSL 3.0). Широко известная уязвимость Heartbleed (2014) была ошибкой в библиотеке OpenSSL, а не в самом протоколе. ## Как работает Соединение состоит из двух фаз: **рукопожатия** (handshake), где стороны договариваются о параметрах и вырабатывают ключи, и **передачи записей** (record protocol), где данные шифруются согласованным симметричным алгоритмом. Упрощённое рукопожатие TLS 1.3 занимает один круг «туда-обратно» (1-RTT): 1. **ClientHello** — клиент отправляет поддерживаемые версии и шифронаборы, свою часть обмена ключами (key share) и расширения, в том числе имя сервера ([SNI](https://llmdocs.ru/wiki/sni.md)) и список прикладных протоколов (ALPN).[5][6] 2. **ServerHello** — сервер выбирает параметры и отвечает своей частью обмена ключами. С этого момента обе стороны вычисляют общий секрет, и всё дальнейшее шифруется. 3. Сервер присылает **сертификат**, подпись рукопожатия (CertificateVerify) и **Finished**. 4. Клиент проверяет цепочку сертификатов до доверенного центра сертификации (см. [Сертификат X.509 и центры сертификации](https://llmdocs.ru/wiki/x509-certificates.md)), отправляет свой Finished — и начинается обмен данными. Обмен ключами выполняется по алгоритму Диффи — Хеллмана на эллиптических кривых (ECDHE), поэтому даже кража закрытого ключа сервера в будущем не позволит расшифровать записанный ранее трафик — это свойство называется **прямой секретностью** (forward secrecy). ## Что изменилось в TLS 1.3 - Рукопожатие сокращено до 1-RTT; при повторном подключении возможен режим 0-RTT (с оговорками о повторном воспроизведении). - Удалены статический обмен ключами RSA, режим CBC, RC4, SHA-1, сжатие и пересогласование — источники многих атак. - Осталось пять шифронаборов, все с аутентифицированным шифрованием (AEAD), например `TLS_AES_128_GCM_SHA256` и `TLS_CHACHA20_POLY1305_SHA256` (см. [Симметричное шифрование (AES, ChaCha20)](https://llmdocs.ru/wiki/symmetric-encryption.md)). - Сертификат сервера передаётся уже в зашифрованном виде. Открытым остаётся имя сервера в ClientHello; расширение Encrypted Client Hello (ECH) шифрует его с помощью ключа, опубликованного в DNS. Браузеры и крупные сервисы внедряют гибридный постквантовый обмен ключами (X25519 в сочетании с ML-KEM), защищающий от расшифровки записанного трафика будущими квантовыми компьютерами. ## Сертификаты Подлинность сервера подтверждает сертификат X.509, подписанный центром сертификации, которому доверяет клиент. Бесплатные сертификаты с автоматическим продлением выдаёт [Let's Encrypt](https://llmdocs.ru/wiki/lets-encrypt-acme.md) по протоколу ACME. При **взаимной аутентификации** (mTLS) сертификат предъявляет и клиент — так часто защищают связь между внутренними сервисами. ## Практика ```bash # посмотреть рукопожатие и сертификат сервера openssl s_client -connect example.com:443 -servername example.com -tls1_3 /dev/null | openssl x509 -noout -enddate ``` Рекомендации по настройке серверов (наборы шифров, версии) публикует, например, Mozilla в виде профилей «Modern» и «Intermediate».[7] Веб-серверы с автоматическим TLS, такие как [Caddy](https://llmdocs.ru/wiki/caddy.md), включают безопасные значения по умолчанию. ## См. также - [Криптография с открытым ключом](https://llmdocs.ru/wiki/public-key-cryptography.md) - [SNI](https://llmdocs.ru/wiki/sni.md) - [HTTP/2 и HTTP/3](https://llmdocs.ru/wiki/http2-http3.md) - [SSH](https://llmdocs.ru/wiki/ssh.md) ## Источники 1. [RFC 8446 — The Transport Layer Security (TLS) Protocol Version 1.3](https://www.rfc-editor.org/rfc/rfc8446) 2. [RFC 5246 — The TLS Protocol Version 1.2](https://www.rfc-editor.org/rfc/rfc5246) 3. [RFC 8996 — Deprecating TLS 1.0 and TLS 1.1](https://www.rfc-editor.org/rfc/rfc8996) 4. [RFC 7568 — Deprecating Secure Sockets Layer Version 3.0](https://www.rfc-editor.org/rfc/rfc7568) 5. [RFC 6066 — TLS Extensions (Server Name Indication)](https://www.rfc-editor.org/rfc/rfc6066) 6. [RFC 7301 — TLS Application-Layer Protocol Negotiation Extension](https://www.rfc-editor.org/rfc/rfc7301) 7. [Mozilla — Server Side TLS recommendations](https://wiki.mozilla.org/Security/Server_Side_TLS) --- # UDP > Протокол пользовательских датаграмм — простой транспортный протокол без установления соединения и гарантий доставки; используется там, где важны скорость и низкая задержка — DNS, видеосвязь, игры, VPN, QUIC. Источник: https://llmdocs.ru/wiki/udp/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Полное название**: User Datagram Protocol - **Автор**: Джон Постел - **Спецификация**: RFC 768 (1980) - **Уровень**: транспортный - **Размер заголовка**: 8 байт - **Гарантии**: нет — ни доставки, ни порядка, ни защиты от дубликатов - **Применение**: DNS, DHCP, NTP, VoIP и видеосвязь, игры, WireGuard, QUIC и HTTP/3 **UDP** (англ. *User Datagram Protocol* — протокол пользовательских датаграмм) — транспортный протокол стека [TCP/IP](https://llmdocs.ru/wiki/tcp-ip.md), который отправляет отдельные сообщения — **датаграммы** — без установления соединения и без каких-либо гарантий: датаграмма может потеряться, прийти дважды или не по порядку, и протокол ничего с этим не делает. Взамен UDP прост, быстр и не добавляет задержек: никаких рукопожатий, подтверждений и повторных отправок. UDP выбирают, когда опоздавшие данные бесполезны (голос, видео, игры), когда запрос и ответ умещаются в один пакет ([DNS](https://llmdocs.ru/wiki/dns.md)) или когда приложение хочет реализовать собственную надёжность поверх него, как [QUIC](https://llmdocs.ru/wiki/quic.md). ## История Протокол описал Джон Постел в RFC 768 в 1980 году — документ занимает всего три страницы.[1] UDP появился, когда исходный монолитный протокол Серфа и Кана разделили на IP и TCP: стало ясно, что не всем приложениям нужна надёжная доставка, а некоторым — например, передаче речи — она даже вредит. ## Устройство Заголовок UDP занимает 8 байт и содержит четыре поля: | Поле | Размер | Назначение | |---|---|---| | Порт отправителя | 2 байта | куда отвечать (может быть нулевым) | | Порт получателя | 2 байта | какой программе доставить | | Длина | 2 байта | размер датаграммы с заголовком | | Контрольная сумма | 2 байта | проверка целостности | Для сравнения: заголовок [TCP](https://llmdocs.ru/wiki/tcp.md) — от 20 байт, плюс установление соединения, подтверждения и состояние на обеих сторонах. Каждая датаграмма UDP самостоятельна: границы сообщений сохраняются, в отличие от потока TCP. ## UDP и TCP | | UDP | TCP | |---|---|---| | Соединение | нет | тройное рукопожатие | | Доставка | не гарантирована | гарантирована, с повторами | | Порядок | не гарантирован | гарантирован | | Границы сообщений | сохраняются | поток байтов | | Управление перегрузкой | нет (ответственность приложения) | встроено | | Широковещание и мультикаст | да | нет | | Задержка | минимальная | выше, особенно при потерях | ## Где используется - **[DNS](https://llmdocs.ru/wiki/dns.md)** — короткий запрос и ответ помещаются в одну датаграмму; при потере клиент просто повторит запрос. - **DHCP** — получение IP-адреса при подключении к сети, когда адреса ещё нет и соединение установить невозможно. - **NTP** — синхронизация времени. - **Голос и видео** — RTP поверх UDP: потерянный фрагмент лучше пропустить, чем ждать повтора и получить заикание.[3] - **Онлайн-игры** — актуальное положение игроков важнее устаревшего. - **VPN** — WireGuard и OpenVPN работают поверх UDP: внутренние TCP-соединения сами обеспечивают надёжность, а двойные повторы TCP-внутри-TCP только вредят.[5] - **[QUIC](https://llmdocs.ru/wiki/quic.md) и HTTP/3** — современный веб-транспорт, реализующий надёжность, шифрование и управление перегрузкой поверх UDP.[4] - **Мультикаст** — рассылка одного потока многим получателям (IPTV, биржевые котировки). ## Пример ```python import socket # сервер srv = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) srv.bind(("0.0.0.0", 9999)) data, addr = srv.recvfrom(2048) # ждём одну датаграмму srv.sendto(b"pong", addr) # клиент cli = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) cli.settimeout(1.0) # ответа может и не быть cli.sendto(b"ping", ("127.0.0.1", 9999)) print(cli.recvfrom(2048)) ``` Нет ни `listen`, ни `accept`, ни `connect`: каждая датаграмма отправляется по адресу отдельно. Таймаут и повтор — забота приложения. ```bash nc -u -l 9999 # слушать UDP-порт echo hello | nc -u host 9999 # отправить датаграмму ss -ulnp # слушающие UDP-сокеты ``` ## Подводные камни - **Размер датаграммы.** Датаграмма больше MTU пути (обычно около 1500 байт для Ethernet) фрагментируется на уровне IP, а потеря любого фрагмента губит её целиком; многие сети фрагменты отбрасывают. Протоколы поверх UDP стараются укладываться примерно в 1200–1400 байт. - **Ответственность приложения.** Нужно самому решать, что делать с потерями, дубликатами и порядком, и не перегружать сеть: руководство RFC 8085 требует от протоколов поверх UDP собственного управления перегрузкой.[2] - **NAT и файрволы.** Без соединения промежуточные устройства держат состояние UDP-«потоков» недолго; приложения шлют периодические пакеты поддержки. - **Атаки с усилением.** Отправитель в UDP не проверяется, поэтому злоумышленник может подделать адрес жертвы и отправить маленький запрос к серверу, отвечающему большим ответом (открытые DNS-резолверы, NTP, memcached). Ответы обрушиваются на жертву — так устроены многие крупные DDoS-атаки.[6] ## См. также - [TCP](https://llmdocs.ru/wiki/tcp.md) - [QUIC](https://llmdocs.ru/wiki/quic.md) - [DNS](https://llmdocs.ru/wiki/dns.md) - [TCP/IP](https://llmdocs.ru/wiki/tcp-ip.md) - [NAT](https://llmdocs.ru/wiki/nat.md) ## Источники 1. [RFC 768 — User Datagram Protocol](https://www.rfc-editor.org/rfc/rfc768) 2. [RFC 8085 — UDP Usage Guidelines](https://www.rfc-editor.org/rfc/rfc8085) 3. [RFC 3550 — RTP: A Transport Protocol for Real-Time Applications](https://www.rfc-editor.org/rfc/rfc3550) 4. [RFC 9000 — QUIC: A UDP-Based Multiplexed and Secure Transport](https://www.rfc-editor.org/rfc/rfc9000) 5. [J. Donenfeld — WireGuard: Next Generation Kernel Network Tunnel](https://www.wireguard.com/papers/wireguard.pdf) 6. [Cloudflare Learning — UDP flood attack](https://www.cloudflare.com/learning/ddos/udp-flood-ddos-attack/) --- # WebSocket > Протокол двустороннего обмена сообщениями между браузером и сервером поверх одного TCP-соединения; начинается как HTTP-запрос и переключается на собственный формат кадров. Источник: https://llmdocs.ru/wiki/websocket/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Стандарт**: RFC 6455 (декабрь 2011) - **API браузера**: WHATWG WebSockets Standard - **Схемы URI**: ws:// (порт 80), wss:// (порт 443, поверх TLS) - **Работает поверх**: TCP; для HTTP/2 — RFC 8441, для HTTP/3 — RFC 9220 - **Установка**: HTTP Upgrade (код 101) - **Альтернативы**: Server-Sent Events, long polling, WebTransport **WebSocket** — сетевой протокол, который открывает между клиентом и сервером постоянный двусторонний канал поверх одного [TCP](https://llmdocs.ru/wiki/tcp.md)-соединения. В отличие от обычного [HTTP](https://llmdocs.ru/wiki/http.md), где клиент спрашивает, а сервер отвечает, по WebSocket любая сторона может отправить сообщение в любой момент. На нём строят чаты, совместное редактирование, биржевые котировки, многопользовательские игры, уведомления и потоковый вывод ответов языковых моделей. ## История До WebSocket «живые» веб-приложения обходились приёмами вроде частого опроса (polling), долгого опроса (long polling) и Comet — все они расходовали лишние запросы и заголовки. Протокол появился в рамках HTML5 в 2008–2010 годах, после нескольких несовместимых черновиков был стандартизирован IETF как RFC 6455 в 2011 году.[1] Браузерный интерфейс `WebSocket` поддерживает WHATWG.[2] Сегодня его поддерживают все браузеры и серверные платформы. ## Установка соединения Соединение начинается с обычного HTTP/1.1-запроса с просьбой «сменить протокол»: ```http GET /chat HTTP/1.1 Host: example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== Sec-WebSocket-Version: 13 Origin: https://example.com ``` Сервер отвечает кодом `101 Switching Protocols` и заголовком `Sec-WebSocket-Accept` — хешем SHA-1 от присланного ключа с фиксированной строкой. Это не защита, а проверка, что сервер действительно понимает WebSocket. После этого то же TCP-соединение используется для кадров WebSocket. Для [HTTP/2 и HTTP/3](https://llmdocs.ru/wiki/http2-http3.md) определены свои способы открыть WebSocket внутри потока (RFC 8441, RFC 9220).[4] ## Формат кадров Данные передаются **кадрами** (frames) с компактным заголовком от 2 до 14 байт: | Поле | Назначение | |---|---| | FIN | последний ли это фрагмент сообщения | | Opcode | тип: текст (UTF-8), двоичные данные, продолжение, close, ping, pong | | Mask | маскирован ли полезный груз (клиент → сервер — всегда) | | Payload length | длина: 7 бит, 16 или 64 бита | Маскирование кадров от клиента случайным ключом защищает промежуточные прокси от атак отравления кэша. Управляющие кадры **ping/pong** проверяют, что соединение живо, а **close** с кодом причины (например, 1000 — нормальное закрытие, 1001 — уход со страницы) завершает его корректно. Расширение `permessage-deflate` сжимает сообщения.[5] ## API в браузере ```javascript const ws = new WebSocket("wss://example.com/chat"); ws.addEventListener("open", () => ws.send(JSON.stringify({type: "hello"}))); ws.addEventListener("message", (event) => { const msg = JSON.parse(event.data); console.log("получено:", msg); }); ws.addEventListener("close", (e) => console.log("закрыто", e.code)); ``` Обмен обычно ведут в формате [JSON](https://llmdocs.ru/wiki/json.md). API не умеет само переподключаться — это делает приложение, с экспоненциальной задержкой между попытками.[3] ## Сервер На сервере WebSocket поддерживают все основные стеки: `ws` и Socket.IO в [Node.js](https://llmdocs.ru/wiki/nodejs.md), `websockets` и Starlette в Python ([FastAPI](https://llmdocs.ru/wiki/fastapi.md)), gorilla/websocket и `nhooyr.io/websocket` в Go, `tokio-tungstenite` в Rust. Socket.IO — не сам WebSocket, а надстройка со своим протоколом: комнаты, подтверждения, автоматическое переподключение и откат на long polling. Каждое соединение долгоживущее, поэтому серверу нужна асинхронная модель ввода-вывода, а при нескольких экземплярах — общая шина сообщений (Redis Pub/Sub, NATS), чтобы событие с одного сервера дошло до клиентов, подключённых к другому. ## За прокси и балансировщиком [Обратный прокси](https://llmdocs.ru/wiki/reverse-proxy.md) должен пробрасывать заголовки `Upgrade` и `Connection` и не закрывать неактивные соединения слишком рано. Для [nginx](https://llmdocs.ru/wiki/nginx.md):[6] ```nginx location /ws/ { proxy_pass http://backend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_read_timeout 1h; } ``` При [балансировке](https://llmdocs.ru/wiki/load-balancing.md) важно, что соединение закреплено за одним сервером на всё время жизни; алгоритм least connections распределяет такие соединения лучше, чем round robin. ## Безопасность - Используйте `wss://` — WebSocket поверх TLS; незашифрованный `ws://` легко перехватить и блокируется многими сетями. - Политика same-origin на WebSocket не распространяется: сервер обязан проверять заголовок `Origin`, иначе возможна атака Cross-Site WebSocket Hijacking. - Аутентификацию выполняют при установке (cookie, токен в первом сообщении); токен в URL попадает в логи. - Ограничивайте размер сообщений и частоту — открытое соединение легко превратить в канал перегрузки. ## Альтернативы - **Server-Sent Events (SSE)** — односторонний поток событий от сервера по обычному HTTP; проще, работает через любые прокси, переподключается сам. Именно SSE используют многие API языковых моделей для потокового вывода. - **Long polling** — запасной вариант для очень старых сред. - **WebTransport** — новый API поверх HTTP/3 и [QUIC](https://llmdocs.ru/wiki/quic.md) с несколькими потоками и ненадёжными датаграммами. ## См. также - [HTTP](https://llmdocs.ru/wiki/http.md) - [TCP](https://llmdocs.ru/wiki/tcp.md) - [Node.js](https://llmdocs.ru/wiki/nodejs.md) - [HTTP/2 и HTTP/3](https://llmdocs.ru/wiki/http2-http3.md) ## Источники 1. [RFC 6455 — The WebSocket Protocol](https://www.rfc-editor.org/rfc/rfc6455) 2. [WHATWG — WebSockets Standard](https://websockets.spec.whatwg.org/) 3. [MDN — The WebSocket API](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) 4. [RFC 8441 — Bootstrapping WebSockets with HTTP/2](https://www.rfc-editor.org/rfc/rfc8441) 5. [RFC 7692 — Compression Extensions for WebSocket](https://www.rfc-editor.org/rfc/rfc7692) 6. [nginx — WebSocket proxying](https://nginx.org/en/docs/http/websocket.html) --- # Сертификат X.509 и центры сертификации > Цифровой сертификат X.509 связывает открытый ключ с доменом или организацией и подписан центром сертификации; цепочки доверия от корневых центров лежат в основе HTTPS и PKI. Источник: https://llmdocs.ru/wiki/x509-certificates/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Стандарт**: ITU-T X.509 (1988), версия 3 (1996) - **Профиль для интернета**: RFC 5280 - **Структура доверия**: корневой → промежуточный → конечный сертификат - **Правила для публичных CA**: CA/Browser Forum Baseline Requirements - **Типы проверки**: DV, OV, EV - **Прозрачность**: Certificate Transparency (RFC 6962, 2013) - **Форматы файлов**: PEM, DER, PKCS#12 (.pfx) **Сертификат X.509** — цифровой документ, который связывает открытый ключ с владельцем: доменным именем, организацией или человеком. Сертификат подписан **центром сертификации** (*Certificate Authority*, CA) — организацией, которой доверяют браузеры и операционные системы. Когда браузер подключается к сайту по [TLS](https://llmdocs.ru/wiki/tls.md), сервер предъявляет сертификат, и браузер проверяет подпись, срок действия и совпадение имени. Так пользователь убеждается, что разговаривает именно с `bank.example`, а не с подставным сервером. Система центров сертификации, корневых хранилищ и правил выпуска называется **инфраструктурой открытых ключей** (PKI). Её основа — [Криптография с открытым ключом](https://llmdocs.ru/wiki/public-key-cryptography.md). ## Происхождение Формат X.509 появился в 1988 году как часть стандартов каталогов X.500 Международного союза электросвязи.[2] Для интернета важна третья версия (1996) с расширениями, а правила её использования описывает профиль RFC 5280.[1] Хотя каталоги X.500 так и не прижились, формат сертификатов стал стандартом для HTTPS, подписи кода, электронной почты (S/MIME) и электронной подписи. ## Что внутри ```bash openssl x509 -in cert.pem -noout -text echo | openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \ | openssl x509 -noout -subject -issuer -dates -ext subjectAltName ``` | Поле | Значение | |---|---| | Subject | кому выдан (для сайтов значимы не оно, а SAN) | | Subject Alternative Name (SAN) | доменные имена, для которых действителен сертификат, включая wildcard `*.example.com` | | Issuer | кто выдал | | Validity | даты начала и окончания действия | | Public Key | открытый ключ владельца (RSA, ECDSA, Ed25519) | | Key Usage, Extended Key Usage | для чего можно использовать ключ (сервер TLS, подпись кода) | | Basic Constraints | может ли сертификат сам выпускать сертификаты | | Signature | подпись центра сертификации | ## Цепочка доверия Корневые центры не подписывают сертификаты сайтов напрямую — их ключи хранятся офлайн. Используется цепочка: ```text Корневой сертификат (в хранилище браузера или ОС, самоподписан) └─ Промежуточный сертификат (подписан корневым) └─ Сертификат сайта (подписан промежуточным) ``` Сервер отправляет свой сертификат вместе с промежуточными, а браузер достраивает цепочку до одного из доверенных корней в своём хранилище (их около полутора сотен). **Самая частая ошибка настройки** — сервер не отдаёт промежуточный сертификат: часть браузеров достроит цепочку сама, а [curl](https://llmdocs.ru/wiki/curl.md), мобильные приложения и другие клиенты — нет. Поэтому серверу указывают файл с полной цепочкой (`fullchain.pem`). ## Типы проверки | Тип | Что проверяет CA | Применение | |---|---|---| | DV (Domain Validation) | контроль над доменом | большинство сайтов, [Let's Encrypt](https://llmdocs.ru/wiki/lets-encrypt-acme.md) | | OV (Organization Validation) | контроль над доменом и существование организации | корпоративные сайты | | EV (Extended Validation) | расширенная проверка организации | раньше — «зелёная строка» в браузере | Браузеры перестали выделять EV-сертификаты в интерфейсе, поскольку пользователи не замечали разницы, поэтому для шифрования и аутентификации домена DV-сертификатов достаточно. ## Правила и прозрачность Публичные центры сертификации подчиняются требованиям **CA/Browser Forum** — консорциума центров и разработчиков браузеров: как проверять заявителя, как хранить ключи, каков максимальный срок действия.[3] С 2020 года публичные сертификаты не могут действовать дольше 398 дней, и срок продолжают сокращать, подталкивая к автоматическому продлению. Нарушения караются исключением из корневых хранилищ: после взлома нидерландского центра DigiNotar (2011), выпустившего поддельные сертификаты Google, ему перестали доверять; в 2017–2018 годах браузеры поэтапно отказались от сертификатов Symantec за систематические нарушения. Чтобы такие инциденты обнаруживались быстро, существует **Certificate Transparency**: все публичные сертификаты записываются в открытые журналы только для добавления, и браузеры не принимают сертификаты без доказательства такой записи.[4][5] Владелец домена может искать в журналах все выпущенные на него сертификаты, например на crt.sh.[6] ## Отзыв Если закрытый ключ скомпрометирован, сертификат нужно отозвать. Механизмы — списки отзыва (CRL) и протокол OCSP — на практике работают ненадёжно: браузеры часто не проверяют отзыв из-за задержек. Поэтому отрасль делает ставку на короткие сроки действия: украденный сертификат быстро истечёт сам. ## Частные PKI Внутри компаний разворачивают собственные центры сертификации — для внутренних сервисов, взаимной аутентификации (mTLS) между микросервисами, VPN и устройств. Инструменты — step-ca, HashiCorp Vault, cert-manager в [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md). Корневой сертификат частного CA устанавливают в хранилища доверия своих машин; самоподписанные сертификаты без CA годятся только для разработки. ## См. также - [TLS](https://llmdocs.ru/wiki/tls.md) - [Let's Encrypt и ACME](https://llmdocs.ru/wiki/lets-encrypt-acme.md) - [Криптография с открытым ключом](https://llmdocs.ru/wiki/public-key-cryptography.md) - [SNI](https://llmdocs.ru/wiki/sni.md) - [Хеш-функция](https://llmdocs.ru/wiki/hash-function.md) ## Источники 1. [RFC 5280 — Internet X.509 Public Key Infrastructure Certificate and CRL Profile](https://www.rfc-editor.org/rfc/rfc5280) 2. [ITU-T Recommendation X.509](https://www.itu.int/rec/T-REC-X.509) 3. [CA/Browser Forum — Baseline Requirements](https://cabforum.org/working-groups/server/baseline-requirements/documents/) 4. [RFC 6962 — Certificate Transparency](https://www.rfc-editor.org/rfc/rfc6962) 5. [Certificate Transparency — certificate.transparency.dev](https://certificate.transparency.dev/) 6. [crt.sh — поиск по журналам Certificate Transparency](https://crt.sh/) --- # asyncio > Модуль стандартной библиотеки Python для асинхронного ввода-вывода на основе цикла событий и сопрограмм async/await. Источник: https://llmdocs.ru/wiki/asyncio/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: модуль стандартной библиотеки - **Язык**: Python - **Появился в**: Python 3.4 (2014) - **Основные PEP**: PEP 3156, PEP 492 - **Модель**: однопоточный цикл событий, кооперативная многозадачность - **Альтернативы**: Trio, AnyIO, gevent - **Документация**: [docs.python.org/3/library/asyncio](https://docs.python.org/3/library/asyncio.html) **asyncio** — модуль стандартной библиотеки [Python](https://llmdocs.ru/wiki/python.md) для написания конкурентного кода с помощью синтаксиса `async`/`await`. Он реализует цикл событий (event loop), который в одном потоке переключается между множеством задач, пока те ждут ввода-вывода: ответа сети, базы данных, файла. asyncio лежит в основе асинхронных веб-фреймворков ([FastAPI](https://llmdocs.ru/wiki/fastapi.md), aiohttp), драйверов баз данных и многих клиентов API. ## История До asyncio асинхронный ввод-вывод в Python обеспечивали сторонние библиотеки — Twisted, Tornado, gevent — с несовместимыми между собой моделями. В 2012 году Гвидо ван Россум предложил единый стандарт (PEP 3156, кодовое имя Tulip), и в Python 3.4 (2014) модуль вошёл в стандартную библиотеку.[2] Первоначально сопрограммы писались на генераторах с `yield from`. В Python 3.5 появились ключевые слова `async def` и `await` (PEP 492),[3] сделав сопрограммы отдельной сущностью языка. Дальнейшие важные изменения: - 3.7 — функция `asyncio.run()`, ставшая стандартной точкой входа; - 3.9 — `asyncio.to_thread()` для вызова блокирующего кода в потоке; - 3.11 — `TaskGroup` и `asyncio.timeout()`, структурированная конкурентность.[4] ## Основные понятия **Сопрограмма** (coroutine) — функция, объявленная через `async def`. Её вызов не выполняет код, а возвращает объект-сопрограмму; выполнение начинается, когда её ожидают через `await` или оборачивают в задачу. **Цикл событий** — планировщик, который хранит готовые к выполнению задачи и следит за сокетами через механизмы ОС (epoll, kqueue, IOCP). Когда задача доходит до `await` на незавершённой операции, она добровольно отдаёт управление, и цикл запускает следующую. Это **кооперативная** многозадачность: переключение происходит только в точках `await`. **Задача** (Task) — сопрограмма, запущенная в цикле событий конкурентно с другими (`asyncio.create_task()`). **Future** — низкоуровневый объект «результат появится позже»; задачи являются его подклассом. ## Пример ```python import asyncio import time async def fetch(name: str, delay: float) -> str: await asyncio.sleep(delay) # имитация сетевого запроса return f"{name}: готово за {delay} с" async def main() -> None: start = time.perf_counter() async with asyncio.TaskGroup() as tg: # Python 3.11+ tasks = [tg.create_task(fetch(f"запрос {i}", 1.0)) for i in range(3)] for t in tasks: print(t.result()) print(f"всего: {time.perf_counter() - start:.1f} с") # ≈ 1.0, а не 3.0 asyncio.run(main()) ``` Три «запроса» по одной секунде выполняются примерно за секунду, потому что ожидание перекрывается. Если одна из задач в `TaskGroup` завершится исключением, остальные будут отменены, а ошибки собраны в `ExceptionGroup`. ## Инструменты модуля | Средство | Назначение | |---|---| | `asyncio.gather()` | дождаться нескольких awaitable и собрать результаты | | `asyncio.TaskGroup` | структурированный запуск группы задач с отменой при ошибке | | `asyncio.timeout()`, `wait_for()` | ограничение времени ожидания | | `asyncio.Queue` | очередь производитель — потребитель | | `asyncio.Semaphore`, `Lock`, `Event` | примитивы синхронизации | | `asyncio.to_thread()` | выполнить блокирующую функцию в отдельном потоке | | `loop.run_in_executor()` | то же для пула потоков или процессов | | потоки (`open_connection`) | высокоуровневая работа с TCP | ## Типичные ошибки - **Блокирующий вызов внутри сопрограммы.** `time.sleep()`, синхронный HTTP-клиент или тяжёлый расчёт останавливают весь цикл событий. Их нужно заменять асинхронными аналогами или выносить в `to_thread()`. - **Забытый `await`.** Вызов сопрограммы без `await` ничего не делает; Python выдаёт предупреждение «coroutine was never awaited». - **Потерянные задачи.** Задача, созданная `create_task()` без сохранения ссылки, может быть удалена сборщиком мусора; документация рекомендует хранить ссылки или использовать `TaskGroup`.[1] - **Ожидание ускорения расчётов.** asyncio не распараллеливает вычисления на ядра процессора — для этого нужны процессы или сборка без GIL (см. [GIL и free-threading (PEP 703)](https://llmdocs.ru/wiki/gil-free-threading.md)). Режим отладки (`asyncio.run(main(), debug=True)` или переменная окружения `PYTHONASYNCIODEBUG=1`) сообщает о медленных обратных вызовах и неожиданных сопрограммах.[5] ## asyncio, потоки и процессы | Подход | Когда подходит | |---|---| | asyncio | тысячи одновременных сетевых соединений, I/O-нагрузка | | потоки (`threading`) | умеренное число блокирующих операций, совместимость со старыми библиотеками | | процессы (`multiprocessing`) | вычисления на нескольких ядрах | Подробнее о различии понятий — в статье [Конкурентность и параллелизм](https://llmdocs.ru/wiki/concurrency-parallelism.md). ## Альтернативы **Trio** предложил идею «детских садов» (nurseries) — предшественника `TaskGroup`. **AnyIO** даёт единый API поверх asyncio и Trio. **uvloop** — замена стандартного цикла событий на основе libuv, ускоряющая сетевой код. ## См. также - [Python](https://llmdocs.ru/wiki/python.md) - [Генераторы и итераторы](https://llmdocs.ru/wiki/generators-iterators.md) - [Промисы и async/await (JS)](https://llmdocs.ru/wiki/js-promises-async.md) - [Конкурентность и параллелизм](https://llmdocs.ru/wiki/concurrency-parallelism.md) ## Источники 1. [asyncio — Asynchronous I/O (Python documentation)](https://docs.python.org/3/library/asyncio.html) 2. [PEP 3156 — Asynchronous IO Support Rebooted: the asyncio Module](https://peps.python.org/pep-3156/) 3. [PEP 492 — Coroutines with async and await syntax](https://peps.python.org/pep-0492/) 4. [Coroutines and Tasks — Task Groups](https://docs.python.org/3/library/asyncio-task.html#task-groups) 5. [Developing with asyncio](https://docs.python.org/3/library/asyncio-dev.html) --- # Контекстные менеджеры > Объекты Python, задающие действия при входе в блок with и выходе из него; гарантируют освобождение ресурсов — файлов, соединений, блокировок — даже при исключениях. Источник: https://llmdocs.ru/wiki/context-managers/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Синтаксис**: with expr as name — блок - **Протокол**: __enter__ и __exit__ (async — __aenter__ и __aexit__) - **Введены**: Python 2.5, PEP 343 (2006) - **Модуль-помощник**: contextlib - **Типичные применения**: файлы, блокировки, транзакции, временные изменения, тайм-ауты - **Аналоги в других языках**: try-with-resources (Java), using (C#), defer (Go), RAII и Drop (C++, Rust) **Контекстный менеджер** — объект [Python](https://llmdocs.ru/wiki/python.md), который определяет, что происходит при входе в блок `with` и при выходе из него. Главная задача — гарантированно освободить ресурс (закрыть файл, вернуть соединение в пул, отпустить блокировку, откатить транзакцию), как бы ни завершился блок: нормально, через `return` или с исключением. Оператор `with` появился в Python 2.5 по PEP 343.[1] ## Зачем нужен Без контекстного менеджера освобождение ресурса приходится писать в `try/finally`: ```python f = open("data.txt", encoding="utf-8") try: text = f.read() finally: f.close() ``` С ним то же самое короче и надёжнее — забыть закрытие невозможно: ```python with open("data.txt", encoding="utf-8") as f: text = f.read() # здесь файл уже закрыт ``` Несколько менеджеров можно объединить в одном `with`; с Python 3.10 официально поддерживаются скобки для переноса строк:[2] ```python with ( open("in.csv") as src, open("out.csv", "w") as dst, ): dst.write(src.read()) ``` ## Протокол Контекстный менеджер — любой объект с двумя методами:[4] - `__enter__(self)` — вызывается при входе; его результат присваивается переменной после `as`; - `__exit__(self, exc_type, exc, tb)` — вызывается при выходе; если блок завершился исключением, аргументы описывают его, иначе все три равны `None`. Если метод вернёт истинное значение, исключение будет **подавлено**. ```python import time class Timer: def __enter__(self): self.start = time.perf_counter() return self def __exit__(self, exc_type, exc, tb): self.elapsed = time.perf_counter() - self.start print(f"{self.elapsed:.3f} с") return False # исключения не глотаем with Timer() as t: sum(range(10_000_000)) ``` ## contextlib Модуль `contextlib` избавляет от написания классов.[3] Декоратор `@contextmanager` превращает [генератор](https://llmdocs.ru/wiki/generators-iterators.md) в контекстный менеджер: код до `yield` — вход, после — выход. ```python from contextlib import contextmanager import os @contextmanager def chdir_tmp(path): old = os.getcwd() os.chdir(path) try: yield path finally: os.chdir(old) # выполнится и при исключении ``` `try/finally` вокруг `yield` обязателен — иначе при исключении в блоке восстановление не выполнится. Сам `@contextmanager` — пример [декоратора](https://llmdocs.ru/wiki/decorators.md). Другие полезные инструменты: | Инструмент | Что делает | |---|---| | `suppress(FileNotFoundError)` | подавляет указанные исключения | | `closing(obj)` | вызывает `obj.close()` у объектов без протокола | | `redirect_stdout(buf)` | временно перенаправляет вывод | | `chdir(path)` (3.11+) | временно меняет рабочий каталог | | `nullcontext()` | «пустой» менеджер для условного кода | | `ExitStack` | динамический набор менеджеров, например список файлов неизвестной длины | | `asynccontextmanager` | то же, что `@contextmanager`, для асинхронного кода | ```python from contextlib import ExitStack with ExitStack() as stack: files = [stack.enter_context(open(p)) for p in paths] ... # все файлы закроются в обратном порядке ``` ## Асинхронные контекстные менеджеры В [asyncio](https://llmdocs.ru/wiki/asyncio.md) вход и выход могут требовать ожидания — например, открыть сетевое соединение. Для этого есть `async with` и методы `__aenter__`/`__aexit__` (PEP 492):[5] ```python import asyncio, httpx async def main(): async with httpx.AsyncClient() as client: r = await client.get("https://example.com") async with asyncio.timeout(5): # Python 3.11+ await slow_operation() async with asyncio.TaskGroup() as tg: # структурная конкурентность tg.create_task(job(1)) tg.create_task(job(2)) ``` ## Где встречаются - **Файлы и сокеты** — `open()`, `socket.socket`, `zipfile.ZipFile`, `tempfile.TemporaryDirectory()`. - **Блокировки** — `with threading.Lock():` захватывает и гарантированно отпускает мьютекс (см. [Состояние гонки и блокировки](https://llmdocs.ru/wiki/race-conditions-locks.md)). - **Транзакции БД** — в `sqlite3` соединение как менеджер фиксирует транзакцию при успехе и откатывает при исключении; аналогично `with session.begin():` в SQLAlchemy (см. [Транзакция и ACID](https://llmdocs.ru/wiki/transaction-acid.md)). - **Тесты** — `pytest.raises(ValueError)` проверяет, что блок бросил исключение, `unittest.mock.patch` временно подменяет объект (см. [pytest](https://llmdocs.ru/wiki/pytest.md)).[6] - **Временные настройки** — `decimal.localcontext()`, `warnings.catch_warnings()`, `np.errstate()` в [NumPy](https://llmdocs.ru/wiki/numpy.md), `torch.no_grad()` в [PyTorch](https://llmdocs.ru/wiki/pytorch.md). ## Подводные камни - Объект, созданный в `with`, после блока остаётся доступен по имени, но ресурс уже закрыт — повторное чтение закрытого файла даст `ValueError`. - Возвращать `True` из `__exit__` нужно осознанно: случайное подавление исключений прячет ошибки. - Генератор в `@contextmanager` должен выдавать `yield` ровно один раз. - Менеджер обычно одноразовый; переиспользуемые (`Lock`) и повторно входимые (`RLock`, `ExitStack`) — исключения. ## Аналоги в других языках Идея «ресурс освобождается при выходе из области видимости» реализована по-разному: `try-with-resources` в Java, `using` в C#, `defer` в [Go](https://llmdocs.ru/wiki/go.md), RAII в C++ и трейт `Drop` в [Rust](https://llmdocs.ru/wiki/rust.md), где освобождение привязано к [владению](https://llmdocs.ru/wiki/ownership-borrowing.md). ## См. также - [Генераторы и итераторы](https://llmdocs.ru/wiki/generators-iterators.md) - [Декораторы](https://llmdocs.ru/wiki/decorators.md) - [asyncio](https://llmdocs.ru/wiki/asyncio.md) - [Обработка ошибок в Go](https://llmdocs.ru/wiki/go-errors.md) ## Источники 1. [PEP 343 — The "with" Statement](https://peps.python.org/pep-0343/) 2. [Python Language Reference — The with statement](https://docs.python.org/3/reference/compound_stmts.html#the-with-statement) 3. [Python — contextlib: Utilities for with-statement contexts](https://docs.python.org/3/library/contextlib.html) 4. [Python Data Model — With Statement Context Managers](https://docs.python.org/3/reference/datamodel.html#context-managers) 5. [PEP 492 — Coroutines with async and await syntax (async with)](https://peps.python.org/pep-0492/) 6. [Python — unittest.mock.patch](https://docs.python.org/3/library/unittest.mock.html#patch) --- # CPython > Эталонная реализация языка Python, написанная на C, — компилятор в байт-код и интерпретатор с подсчётом ссылок. Источник: https://llmdocs.ru/wiki/cpython/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: реализация языка программирования - **Язык**: Python - **Написан на**: C и Python - **Разработчик**: core-разработчики Python, Python Software Foundation - **Управление памятью**: подсчёт ссылок + циклический сборщик мусора - **Репозиторий**: [github.com/python/cpython](https://github.com/python/cpython) - **Лицензия**: PSF License **CPython** — эталонная и самая распространённая реализация языка [Python](https://llmdocs.ru/wiki/python.md), написанная на языке C. Именно её скачивают с python.org, именно она входит в дистрибутивы [Linux](https://llmdocs.ru/wiki/linux.md) и macOS, и именно в ней первыми появляются новые возможности языка. Название подчёркивает язык реализации и отличает её от альтернатив — PyPy, Jython, GraalPy, MicroPython. ## История CPython — исходная реализация, которую Гвидо ван Россум начал писать в 1989 году; название «CPython» появилось позже, когда возникли другие реализации. Долгое время проект жил в системе контроля версий Mercurial, а в 2017 году переехал на [GitHub](https://llmdocs.ru/wiki/github.md) (PEP 512). Разработкой занимаются несколько десятков core-разработчиков, решения о крупных изменениях принимаются через [PEP](https://llmdocs.ru/wiki/pep.md). ## Как исполняется код Запуск программы в CPython проходит несколько стадий:[1] 1. **Токенизация и разбор** — исходный текст превращается в абстрактное синтаксическое дерево (AST). С версии 3.9 используется PEG-парсер. 2. **Компиляция** — AST переводится в **байт-код**: последовательность инструкций стековой виртуальной машины, упакованных в объекты кода. 3. **Кеширование** — байт-код импортируемых модулей сохраняется в файлы `.pyc` в каталоге `__pycache__` (PEP 3147), чтобы не компилировать их заново.[6] 4. **Интерпретация** — главный цикл (`ceval.c`) выбирает инструкции по одной и исполняет их. Байт-код можно посмотреть модулем `dis`:[7] ```python import dis def add(a, b): return a + b dis.dis(add) # RESUME 0 # LOAD_FAST_LOAD_FAST (a, b) # BINARY_OP 0 (+) # RETURN_VALUE ``` Точный набор инструкций меняется от версии к версии и не является частью спецификации языка. ## Управление памятью Каждый объект хранит **счётчик ссылок**; когда он падает до нуля, память освобождается немедленно. Это делает поведение предсказуемым (файл закрывается сразу после потери последней ссылки), но не справляется с циклами — например, двумя объектами, ссылающимися друг на друга. Для них работает дополнительный **циклический сборщик мусора** по поколениям (модуль `gc`). Подробнее — в статье [Сборка мусора](https://llmdocs.ru/wiki/garbage-collection.md). ## GIL и многопоточность Подсчёт ссылок не потокобезопасен, поэтому исторически CPython защищает интерпретатор **глобальной блокировкой** (GIL): в каждый момент Python-байт-код исполняет только один поток. Потоки полезны для ввода-вывода (блокировка отпускается при ожидании), но не ускоряют вычисления на нескольких ядрах. PEP 703 предложил сборку без GIL.[4] В версии 3.13 она появилась как экспериментальная (исполняемый файл `python3.13t`), в 3.14 получила статус официально поддерживаемой (PEP 779), хотя по умолчанию по-прежнему поставляется сборка с GIL.[5] Подробности — в статье [GIL и free-threading (PEP 703)](https://llmdocs.ru/wiki/gil-free-threading.md). ## Ускорение интерпретатора Начиная с 3.11 проект Faster CPython заметно ускорил интерпретатор: | Версия | Изменение | |---|---| | 3.11 | специализирующий адаптивный интерпретатор (PEP 659): «горячие» инструкции заменяются версиями под конкретные типы[2] | | 3.12 | «бессмертные» объекты (PEP 683), отдельная блокировка на каждый субинтерпретатор (PEP 684) | | 3.13 | экспериментальный JIT-компилятор по схеме copy-and-patch (PEP 744)[3], экспериментальная сборка без GIL | | 3.14 | официально поддерживаемая сборка без GIL, модуль субинтерпретаторов в стандартной библиотеке | ## C API и расширения CPython предоставляет C API, через который пишутся модули расширения — так устроены [NumPy](https://llmdocs.ru/wiki/numpy.md), драйверы баз данных и многие быстрые библиотеки. Это источник силы экосистемы и одновременно ограничение: альтернативным реализациям трудно поддерживать совместимость с расширениями, завязанными на внутренности CPython. Для генерации расширений используют Cython, pybind11, а для Rust — PyO3. ## Сравнение с другими реализациями | Реализация | Особенность | |---|---| | CPython | эталон, максимальная совместимость с расширениями на C | | PyPy | трассирующий JIT, быстрее на «чистом» Python, совместимость с C API частичная | | MicroPython | урезанная реализация для микроконтроллеров | | GraalPy | на GraalVM, взаимодействие с Java | ## См. также - [Python](https://llmdocs.ru/wiki/python.md) - [Компилятор и интерпретатор](https://llmdocs.ru/wiki/compiler-interpreter.md) - [GIL и free-threading (PEP 703)](https://llmdocs.ru/wiki/gil-free-threading.md) - [Сборка мусора](https://llmdocs.ru/wiki/garbage-collection.md) ## Источники 1. [Python Developer's Guide — Internals](https://devguide.python.org/internals/) 2. [PEP 659 — Specializing Adaptive Interpreter](https://peps.python.org/pep-0659/) 3. [PEP 744 — JIT Compilation](https://peps.python.org/pep-0744/) 4. [PEP 703 — Making the Global Interpreter Lock Optional in CPython](https://peps.python.org/pep-0703/) 5. [PEP 779 — Criteria for supported status for free-threaded Python](https://peps.python.org/pep-0779/) 6. [PEP 3147 — PYC Repository Directories](https://peps.python.org/pep-3147/) 7. [dis — Disassembler for Python bytecode](https://docs.python.org/3/library/dis.html) --- # Dataclasses и Pydantic > dataclasses — модуль стандартной библиотеки Python для лаконичного описания классов-контейнеров данных; Pydantic — библиотека, которая по тем же аннотациям проверяет и преобразует входные данные. Источник: https://llmdocs.ru/wiki/dataclasses-pydantic/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **dataclasses**: стандартная библиотека, PEP 557, Python 3.7 (2018) - **Автор dataclasses**: Эрик Смит - **Pydantic**: Сэмюэл Колвин, с 2017 - **Pydantic v2**: 2023, ядро pydantic-core на Rust - **Лицензия Pydantic**: MIT - **Предшественник и альтернатива**: attrs (2015), msgspec - **Используют Pydantic**: FastAPI, LangChain, SDK многих API **dataclasses** — модуль стандартной библиотеки [Python](https://llmdocs.ru/wiki/python.md), который по аннотациям полей автоматически генерирует для класса конструктор `__init__`, строковое представление `__repr__`, сравнение `__eq__` и другие служебные методы. **Pydantic** — сторонняя библиотека, которая по тем же [аннотациям типов](https://llmdocs.ru/wiki/type-hints.md) **проверяет и преобразует данные во время выполнения**: строку `"42"` из [JSON](https://llmdocs.ru/wiki/json.md) превращает в число, а некорректный email отвергает с понятной ошибкой. Проще говоря, dataclass описывает структуру данных внутри программы, а Pydantic охраняет границу, через которую в программу приходят данные извне: HTTP-запросы, файлы конфигурации, ответы API и языковых моделей. ## dataclasses Модуль появился в Python 3.7 (PEP 557, 2018); автор — Эрик Смит, вдохновлялся сторонней библиотекой attrs.[1][6] ```python from dataclasses import dataclass, field @dataclass(slots=True, kw_only=True) class Order: id: int customer: str items: list[str] = field(default_factory=list) # изменяемое значение — только через фабрику paid: bool = False @property def size(self) -> int: return len(self.items) o = Order(id=1, customer="Алиса", items=["книга"]) print(o) # Order(id=1, customer='Алиса', items=['книга'], paid=False) print(o == Order(id=1, customer="Алиса", items=["книга"])) # True ``` Основные параметры декоратора:[2] | Параметр | Действие | |---|---| | `frozen=True` | неизменяемые экземпляры, пригодные как ключи словаря | | `slots=True` | `__slots__`: меньше памяти, быстрее доступ к атрибутам (3.10+) | | `kw_only=True` | все поля только именованными аргументами (3.10+) | | `order=True` | сравнение `<`, `>` по полям | Dataclass **не проверяет типы**: `Order(id="один", customer=None)` создастся без ошибок — несоответствие найдёт только статический анализатор ([mypy и pyright](https://llmdocs.ru/wiki/mypy-pyright.md)). Для валидации есть метод `__post_init__`, но для сложных правил удобнее Pydantic. ## Pydantic Сэмюэл Колвин выпустил Pydantic в 2017 году. Библиотека стала стандартом валидации данных в Python благодаря [FastAPI](https://llmdocs.ru/wiki/fastapi.md), который построил на ней обработку запросов. Pydantic v2 (2023) переписал ядро на [Rust](https://llmdocs.ru/wiki/rust.md) (pydantic-core), ускорив валидацию в разы; при переходе изменилась часть API.[4] ```python from datetime import datetime from pydantic import BaseModel, EmailStr, Field, ValidationError class User(BaseModel): id: int email: EmailStr # требует пакет email-validator name: str = Field(min_length=1, max_length=100) tags: list[str] = [] created_at: datetime data = {"id": "42", "email": "alice@example.com", "name": "Алиса", "created_at": "2026-11-09T10:00:00Z"} user = User.model_validate(data) # "42" → 42, строка → datetime print(user.model_dump_json()) # обратно в JSON try: User.model_validate({"id": "x", "email": "нет", "name": "", "created_at": "вчера"}) except ValidationError as e: print(e.error_count(), "ошибки") # все ошибки сразу, с путями к полям ``` Возможности:[3] - **Приведение типов** в нестрогом режиме и строгий режим, где `"42"` для `int` — ошибка. - **Валидаторы** полей и моделей (`@field_validator`, `@model_validator`) для своих правил. - **Вложенные модели**, списки и словари моделей, объединения типов с дискриминатором. - **JSON Schema** по модели — основа документации OpenAPI в FastAPI и описаний инструментов для языковых моделей (см. [Tool use / function calling](https://llmdocs.ru/wiki/tool-use.md), [Структурированный вывод (JSON mode)](https://llmdocs.ru/wiki/structured-output.md)). - **Настройки приложения** — пакет pydantic-settings читает конфигурацию из [переменных окружения](https://llmdocs.ru/wiki/environment-variables.md) и файлов `.env` с проверкой типов.[5] - **Проверка обычных dataclass** — декоратор `pydantic.dataclasses.dataclass` и `TypeAdapter` для любых типов. ## Сравнение | | dataclasses | Pydantic | attrs | |---|---|---|---| | Где | стандартная библиотека | сторонняя | сторонняя | | Проверка во время выполнения | нет | да, с приведением типов | по желанию (валидаторы) | | Сериализация в JSON | вручную (`asdict`) | встроена | через cattrs | | JSON Schema | нет | да | нет | | Скорость создания объектов | высокая | ниже (идёт проверка) | высокая | | Типичное применение | внутренние структуры | данные извне, API, конфигурация | внутренние структуры с расширенными возможностями | Для максимальной скорости сериализации и проверки существует msgspec, а для схем в базе данных — ORM-модели вроде SQLAlchemy или SQLModel (гибрид SQLAlchemy и Pydantic). ## Как выбирать - Данные создаёт сам код и им можно доверять — **dataclass**: без зависимостей и накладных расходов. - Данные приходят снаружи — запросы, JSON, YAML, ответы LLM, переменные окружения — **Pydantic** на границе системы; внутрь передаются уже проверенные объекты. - Не стоит проверять одни и те же данные на каждом слое: валидация на входе, дальше — обычные типизированные объекты. ## См. также - [Типизация в Python (type hints, PEP 484)](https://llmdocs.ru/wiki/type-hints.md) - [FastAPI](https://llmdocs.ru/wiki/fastapi.md) - [mypy и pyright](https://llmdocs.ru/wiki/mypy-pyright.md) - [JSON](https://llmdocs.ru/wiki/json.md) - [Декораторы](https://llmdocs.ru/wiki/decorators.md) ## Источники 1. [PEP 557 — Data Classes](https://peps.python.org/pep-0557/) 2. [Python — dataclasses](https://docs.python.org/3/library/dataclasses.html) 3. [Pydantic — документация](https://docs.pydantic.dev/latest/) 4. [Pydantic — Migration Guide (v1 → v2)](https://docs.pydantic.dev/latest/migration/) 5. [Pydantic — Settings Management](https://docs.pydantic.dev/latest/concepts/pydantic_settings/) 6. [attrs — документация](https://www.attrs.org/) --- # Декораторы > Синтаксис Python @decorator для обёртывания функций и классов другими функциями — добавляет поведение (кэширование, логирование, проверку доступа, регистрацию) без изменения исходного кода. Источник: https://llmdocs.ru/wiki/decorators/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Синтаксис**: @имя над def или class - **Введены**: PEP 318 (Python 2.4, 2004) - **Декораторы классов**: PEP 3129 (Python 3.0) - **Произвольные выражения**: PEP 614 (Python 3.9) - **Типизация**: ParamSpec (PEP 612) - **Встроенные**: property, staticmethod, classmethod, functools.cache, dataclass **Декоратор** в [Python](https://llmdocs.ru/wiki/python.md) — функция, которая принимает другую функцию (или класс) и возвращает её изменённую или обёрнутую версию. Синтаксис `@decorator` над определением функции — сокращение для присваивания `func = decorator(func)`. Декораторы позволяют добавлять общее поведение — кэширование, логирование, замер времени, проверку прав, повторные попытки, регистрацию обработчиков — не трогая код самой функции. Декораторы повсюду в экосистеме Python: маршруты в [FastAPI](https://llmdocs.ru/wiki/fastapi.md) и [Flask](https://llmdocs.ru/wiki/flask.md) (`@app.get("/")`), фикстуры [pytest](https://llmdocs.ru/wiki/pytest.md) (`@pytest.fixture`), `@dataclass`, `@property`. ## История Обёртывание функций было возможно всегда, но выглядело громоздко: `method = staticmethod(method)` после определения. PEP 318 ввёл синтаксис с символом `@` в Python 2.4 (2004);[1] выбор символа долго обсуждали, рассматривая десятки вариантов. В Python 3.0 декораторы распространили на классы (PEP 3129),[2] а с Python 3.9 после `@` можно писать любое выражение (PEP 614).[6] ## Как работает Функции в Python — обычные объекты: их можно передавать как аргументы и возвращать из других функций. Декоратор пользуется этим и **замыканием** — вложенная функция запоминает переменные внешней: ```python import functools, time def timed(func): @functools.wraps(func) # сохранить имя, docstring и сигнатуру оригинала def wrapper(*args, **kwargs): start = time.perf_counter() try: return func(*args, **kwargs) finally: print(f"{func.__name__}: {time.perf_counter() - start:.3f} с") return wrapper @timed # то же, что load = timed(load) def load(path): ... ``` `functools.wraps` копирует в обёртку имя, документацию и другие атрибуты исходной функции; без него отладка, трассировки и документация показывали бы `wrapper` вместо настоящего имени.[4] ## Декораторы с параметрами Если декоратору нужны аргументы, добавляется ещё один уровень: внешняя функция принимает параметры и возвращает сам декоратор. ```python def retry(times: int = 3, delay: float = 1.0, exceptions=(Exception,)): def decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): for attempt in range(1, times + 1): try: return func(*args, **kwargs) except exceptions: if attempt == times: raise time.sleep(delay * 2 ** (attempt - 1)) # экспоненциальная пауза return wrapper return decorator @retry(times=5, exceptions=(ConnectionError, TimeoutError)) def fetch(url): ... ``` Несколько декораторов применяются снизу вверх: в записи `@a` над `@b` над `def f` получается `f = a(b(f))`. ## Встроенные и стандартные декораторы | Декоратор | Назначение | |---|---| | `@property` | метод, читаемый как атрибут; с `@x.setter` — управляемая запись | | `@staticmethod`, `@classmethod` | методы без экземпляра; с классом вместо экземпляра | | `@functools.cache`, `@functools.lru_cache(maxsize=…)` | запоминание результатов (мемоизация), см. [Кэш (вычисления)](https://llmdocs.ru/wiki/cache.md) | | `@functools.cached_property` | свойство, вычисляемое один раз на экземпляр | | `@functools.singledispatch` | разные реализации функции в зависимости от типа аргумента | | `@dataclasses.dataclass` | генерация `__init__`, `__repr__`, `__eq__` по полям (см. [Dataclasses и Pydantic](https://llmdocs.ru/wiki/dataclasses-pydantic.md)) | | `@contextlib.contextmanager` | генератор как [контекстный менеджер](https://llmdocs.ru/wiki/context-managers.md) | | `@typing.override`, `@typing.final` | пометки для анализаторов типов | ```python from functools import cache @cache def fib(n: int) -> int: return n if n < 2 else fib(n - 1) + fib(n - 2) fib(200) # мгновенно: каждое значение вычисляется один раз ``` ## Декораторы классов и регистрация Декоратор может не оборачивать функцию, а лишь зарегистрировать её и вернуть без изменений — так фреймворки собирают маршруты, команды CLI и обработчики событий: ```python HANDLERS = {} def on(event: str): def register(func): HANDLERS[event] = func return func return register @on("user.created") def send_welcome(user): ... ``` Декораторы классов получают класс целиком и могут добавлять методы или проверять его определение — как `@dataclass`. ## Типизация декораторов Обёртка с `*args, **kwargs` скрывает сигнатуру исходной функции от анализаторов типов. `ParamSpec` (PEP 612) позволяет сохранить её:[5] ```python from collections.abc import Callable def logged[**P, R](func: Callable[P, R]) -> Callable[P, R]: @functools.wraps(func) def wrapper(*args: P.args, **kwargs: P.kwargs) -> R: print("вызов", func.__name__) return func(*args, **kwargs) return wrapper ``` Теперь [mypy и pyright](https://llmdocs.ru/wiki/mypy-pyright.md) проверяют аргументы при вызове обёрнутой функции так же, как исходной (см. [Типизация в Python (type hints, PEP 484)](https://llmdocs.ru/wiki/type-hints.md)). ## Советы - Всегда используйте `functools.wraps` в обёртках. - Не прячьте в декораторах важную бизнес-логику: поведение, неочевидное из вызова, затрудняет чтение кода. - Обёртка добавляет накладные расходы на вызов — для горячих функций в тесных циклах это заметно. - Для асинхронных функций обёртка тоже должна быть `async def` и использовать `await`. Определение и примеры — в глоссарии Python.[3] ## См. также - [Генераторы и итераторы](https://llmdocs.ru/wiki/generators-iterators.md) - [Контекстные менеджеры](https://llmdocs.ru/wiki/context-managers.md) - [Dataclasses и Pydantic](https://llmdocs.ru/wiki/dataclasses-pydantic.md) - [pytest](https://llmdocs.ru/wiki/pytest.md) - [FastAPI](https://llmdocs.ru/wiki/fastapi.md) ## Источники 1. [PEP 318 — Decorators for Functions and Methods](https://peps.python.org/pep-0318/) 2. [PEP 3129 — Class Decorators](https://peps.python.org/pep-3129/) 3. [Python Glossary — decorator](https://docs.python.org/3/glossary.html#term-decorator) 4. [Python — functools](https://docs.python.org/3/library/functools.html) 5. [PEP 612 — Parameter Specification Variables](https://peps.python.org/pep-0612/) 6. [PEP 614 — Relaxing Grammar Restrictions On Decorators](https://peps.python.org/pep-0614/) --- # Django > Полнофункциональный веб-фреймворк на Python «с батарейками» — ORM, миграции, админка, шаблоны, формы, аутентификация и защита от типовых атак из коробки. Источник: https://llmdocs.ru/wiki/django/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Язык**: Python - **Первый выпуск**: июль 2005 - **Авторы**: Адриан Головати, Саймон Уиллисон (газета Lawrence Journal-World) - **Разработчик**: Django Software Foundation - **Архитектура**: MTV (модель — шаблон — представление) - **Лицензия**: BSD-3-Clause - **Выпуски**: новая версия раз в 8 месяцев, LTS — каждая третья (.2) **Django** — веб-фреймворк на [Python](https://llmdocs.ru/wiki/python.md) для быстрой разработки сайтов и веб-приложений, работающий по принципу «батарейки в комплекте». Из коробки он даёт [ORM](https://llmdocs.ru/wiki/orm.md) и [миграции](https://llmdocs.ru/wiki/schema-migrations.md), автоматическую панель администратора, шаблонизатор, формы с валидацией, аутентификацию, кэширование, интернационализацию и защиту от распространённых атак.[1] На Django написаны (или начинались) Instagram, Pinterest, Disqus, Mozilla Developer Network, сайты многих СМИ и госорганов. ## История Фреймворк создали в 2003–2005 годах Адриан Головати и Саймон Уиллисон в редакции газеты Lawrence Journal-World (Канзас), где нужно было быстро выпускать новостные сервисы под жёсткие дедлайны. В июле 2005 года код открыли под лицензией BSD и назвали в честь джазового гитариста Джанго Рейнхардта. С 2008 года проект развивает некоммерческий фонд Django Software Foundation. Новые версии выходят примерно раз в восемь месяцев; каждая версия с номером `.2` (4.2, 5.2) — LTS с поддержкой около трёх лет.[2] ## Архитектура Django использует схему **MTV** — вариант MVC с другими названиями: - **Model** — классы данных, отображаемые на таблицы [реляционной БД](https://llmdocs.ru/wiki/relational-database.md); - **Template** — HTML-шаблоны с собственным языком (`{{ var }}`, `{% for %}`); - **View** — функции или классы, принимающие [HTTP](https://llmdocs.ru/wiki/http.md)-запрос и возвращающие ответ. Проект состоит из **приложений** (apps) — переиспользуемых модулей со своими моделями, представлениями и шаблонами. Маршруты задаются в `urls.py`, настройки — в `settings.py`, а управляющая утилита `manage.py` создаёт миграции, запускает сервер разработки и тесты. ## Быстрый пример ```bash uv add django uv run django-admin startproject mysite . uv run python manage.py startapp blog ``` ```python # blog/models.py from django.db import models class Post(models.Model): title = models.CharField(max_length=200) body = models.TextField() published = models.DateTimeField(auto_now_add=True) def __str__(self): return self.title ``` ```python # blog/views.py from django.shortcuts import render, get_object_or_404 from .models import Post def post_list(request): posts = Post.objects.order_by("-published")[:10] return render(request, "blog/list.html", {"posts": posts}) def post_detail(request, pk): return render(request, "blog/detail.html", {"post": get_object_or_404(Post, pk=pk)}) ``` ```bash uv run python manage.py makemigrations && uv run python manage.py migrate uv run python manage.py createsuperuser uv run python manage.py runserver ``` Зарегистрировав модель в `admin.py` одной строкой `admin.site.register(Post)`, получаем готовый интерфейс для создания и редактирования записей. ## ORM и миграции ORM Django строит [SQL](https://llmdocs.ru/wiki/sql.md)-запросы из цепочек методов: `Post.objects.filter(title__icontains="python").exclude(body="")`. Запросы ленивые и выполняются при первом обращении к результату. Связи (`ForeignKey`, `ManyToManyField`) загружаются отдельными запросами, поэтому для списков важно использовать `select_related` и `prefetch_related`, иначе возникает проблема «N+1 запросов». Поддерживаются [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md), [MySQL/MariaDB](https://llmdocs.ru/wiki/mysql-mariadb.md), [SQLite](https://llmdocs.ru/wiki/sqlite.md) и Oracle. Изменения моделей фиксируются **миграциями** — Python-файлами, которые генерирует `makemigrations` и применяет `migrate`; их хранят в репозитории вместе с кодом.[4] ## Безопасность Django включает защиту по умолчанию:[3] - параметризованные запросы в ORM против [SQL-инъекций](https://llmdocs.ru/wiki/sql-injection.md); - автоматическое экранирование в шаблонах против [XSS](https://llmdocs.ru/wiki/xss.md); - токен против [CSRF](https://llmdocs.ru/wiki/csrf.md) в формах; - [хеширование паролей](https://llmdocs.ru/wiki/password-storage.md) PBKDF2 с возможностью перейти на Argon2; - защита от кликджекинга, проверка заголовка `Host`, настройки HTTPS и HSTS. Перед выкладкой стоит запустить `manage.py check --deploy` — команда проверяет `DEBUG = False`, `SECRET_KEY`, cookie и другие пункты чек-листа.[7] ## API и асинхронность Для [REST](https://llmdocs.ru/wiki/rest.md) API почти всегда используют **Django REST framework** (DRF) — сериализаторы, наборы представлений, аутентификацию, пагинацию и браузерный интерфейс API;[5] более лёгкая альтернатива с типами в стиле [FastAPI](https://llmdocs.ru/wiki/fastapi.md) — Django Ninja. Начиная с версии 3.0 Django поддерживает ASGI и асинхронные представления (`async def`), а с 4.1 — асинхронные методы ORM, хотя сам ORM внутри всё ещё во многом синхронный.[6] ## Развёртывание В продакшене Django запускают через WSGI-сервер (Gunicorn, uWSGI) или ASGI-сервер (Uvicorn, Daphne) за [обратным прокси](https://llmdocs.ru/wiki/reverse-proxy.md) вроде [nginx](https://llmdocs.ru/wiki/nginx.md); статику собирают командой `collectstatic` и отдают прокси или CDN. Фоновые задачи традиционно выносят в Celery или RQ, в Django 6.0 появился встроенный фреймворк задач. ## Django, Flask или FastAPI Django удобен, когда нужен полноценный сайт с базой, админкой, пользователями и формами — многое уже решено. [Flask](https://llmdocs.ru/wiki/flask.md) — минималистичное ядро, к которому всё подключается отдельно. [FastAPI](https://llmdocs.ru/wiki/fastapi.md) ориентирован на API с типами и асинхронностью. Цена «батареек» Django — больше соглашений и меньше свободы в устройстве проекта. ## См. также - [Flask](https://llmdocs.ru/wiki/flask.md) - [FastAPI](https://llmdocs.ru/wiki/fastapi.md) - [ORM](https://llmdocs.ru/wiki/orm.md) - [Python](https://llmdocs.ru/wiki/python.md) ## Источники 1. [Django documentation](https://docs.djangoproject.com/en/stable/) 2. [Django — Download and supported versions](https://www.djangoproject.com/download/) 3. [Django — Security in Django](https://docs.djangoproject.com/en/stable/topics/security/) 4. [Django — Migrations](https://docs.djangoproject.com/en/stable/topics/migrations/) 5. [Django REST framework](https://www.django-rest-framework.org/) 6. [Django — Asynchronous support](https://docs.djangoproject.com/en/stable/topics/async/) 7. [Django — Deployment checklist](https://docs.djangoproject.com/en/stable/howto/deployment/checklist/) --- # FastAPI > Современный асинхронный веб-фреймворк для создания API на Python; использует аннотации типов для валидации данных через Pydantic и автоматически генерирует документацию OpenAPI. Источник: https://llmdocs.ru/wiki/fastapi/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: веб-фреймворк для API - **Автор**: Себастьян Рамирес - **Первый выпуск**: декабрь 2018 - **Основа**: Starlette (веб), Pydantic (данные) - **Интерфейс сервера**: ASGI - **Серверы**: Uvicorn, Hypercorn, Granian - **Лицензия**: MIT - **Документация API**: OpenAPI, Swagger UI, ReDoc — автоматически **FastAPI** — веб-фреймворк для создания API на [Python](https://llmdocs.ru/wiki/python.md). Параметры обработчиков описываются обычными [аннотациями типов](https://llmdocs.ru/wiki/type-hints.md), и по ним FastAPI сам проверяет входящие данные, преобразует их, сериализует ответы и строит интерактивную документацию [API](https://llmdocs.ru/wiki/rest.md) в формате OpenAPI. Фреймворк асинхронный, работает поверх интерфейса ASGI и по скорости близок к серверам на Node.js и Go.[1] FastAPI стал одним из самых популярных Python-фреймворков для бэкендов, микросервисов, сервинга моделей машинного обучения и инструментов для языковых моделей. ## История Себастьян Рамирес, известный в сети как tiangolo, выпустил FastAPI в декабре 2018 года, объединив лучшие идеи существующих инструментов: лёгкость Flask, сериализаторы Django REST Framework, автодокументацию из мира API. Фреймворк собран из двух библиотек: **Starlette** отвечает за веб-часть (маршрутизация, запросы, WebSocket),[4] **Pydantic** — за данные (см. [Dataclasses и Pydantic](https://llmdocs.ru/wiki/dataclasses-pydantic.md)). Ключевой идеей стало использование стандартных аннотаций Python, которые уже понимают редакторы и анализаторы типов. ## Пример ```python # main.py from fastapi import FastAPI, HTTPException, Query from pydantic import BaseModel, Field app = FastAPI(title="Каталог") class ItemIn(BaseModel): name: str = Field(min_length=1, max_length=100) price: float = Field(gt=0) tags: list[str] = [] class Item(ItemIn): id: int DB: dict[int, Item] = {} @app.post("/items", response_model=Item, status_code=201) async def create_item(data: ItemIn) -> Item: item = Item(id=len(DB) + 1, **data.model_dump()) DB[item.id] = item return item @app.get("/items/{item_id}") async def get_item(item_id: int) -> Item: if item_id not in DB: raise HTTPException(status_code=404, detail="Не найдено") return DB[item_id] @app.get("/items") async def list_items(limit: int = Query(20, le=100), tag: str | None = None) -> list[Item]: items = [i for i in DB.values() if tag is None or tag in i.tags] return items[:limit] ``` ```bash uv add "fastapi[standard]" uv run fastapi dev main.py # сервер разработки с автоперезагрузкой # документация: http://127.0.0.1:8000/docs (Swagger UI) и /redoc ``` Из аннотаций FastAPI понимает, что `item_id` берётся из пути и должен быть целым числом, `limit` и `tag` — из строки запроса, а `data` — из тела запроса в [JSON](https://llmdocs.ru/wiki/json.md). Запрос `GET /items/abc` получит ответ `422` с описанием ошибки, а не исключение в коде (см. [Коды состояния HTTP](https://llmdocs.ru/wiki/http-status-codes.md)).[2] ## Внедрение зависимостей Механизм `Depends` позволяет объявлять общие ресурсы — сессию базы данных, текущего пользователя, настройки — и получать их в обработчиках:[3] ```python from typing import Annotated from fastapi import Depends, Header async def get_db(): async with SessionLocal() as session: yield session # закрывается после ответа async def current_user(authorization: Annotated[str, Header()], db=Depends(get_db)): user = await db.get_user_by_token(authorization.removeprefix("Bearer ")) if not user: raise HTTPException(status_code=401) return user @app.get("/me") async def me(user=Depends(current_user)): return user ``` Зависимости кэшируются в рамках запроса, могут зависеть друг от друга и легко подменяются в тестах. На них же строятся проверки [аутентификации и прав](https://llmdocs.ru/wiki/authn-authz.md). ## ASGI и асинхронность FastAPI — ASGI-приложение: асинхронный аналог старого стандарта WSGI, поддерживающий WebSocket, потоковые ответы и долгие соединения.[5] Запускается сервером Uvicorn или аналогами.[6] - Обработчики `async def` выполняются в цикле событий [asyncio](https://llmdocs.ru/wiki/asyncio.md) — их стоит использовать с асинхронными библиотеками (httpx, asyncpg, SQLAlchemy async). - Обычные `def`-обработчики FastAPI запускает в пуле потоков, поэтому блокирующий код в них не останавливает сервер. - Главная ошибка — блокирующий вызов (`requests.get`, `time.sleep`, синхронный драйвер БД) внутри `async def`: он замораживает все запросы. ## Возможности - Автоматическая документация OpenAPI — её используют фронтенд-разработчики, генераторы клиентов и [агенты](https://llmdocs.ru/wiki/ai-agent.md) при вызове API. - Фоновые задачи, WebSocket, потоковые ответы (в том числе для генерации текста LLM по токенам). - Безопасность: схемы OAuth2, ключи API, интеграция с JWT ([OAuth 2.0 и OpenID Connect](https://llmdocs.ru/wiki/oauth-oidc.md)). - `TestClient` для тестов с [pytest](https://llmdocs.ru/wiki/pytest.md) без запуска сервера. - Middleware, [CORS](https://llmdocs.ru/wiki/cors.md), обработчики исключений, подключение подприложений. ## Развёртывание В продакшене приложение запускают в [Docker](https://llmdocs.ru/wiki/docker.md)-контейнере командой `fastapi run` или через Uvicorn с несколькими рабочими процессами, за [обратным прокси](https://llmdocs.ru/wiki/reverse-proxy.md) вроде [nginx](https://llmdocs.ru/wiki/nginx.md) или [Caddy](https://llmdocs.ru/wiki/caddy.md), либо в [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md). ## Сравнение | | FastAPI | [Flask](https://llmdocs.ru/wiki/flask.md) | [Django](https://llmdocs.ru/wiki/django.md) | |---|---|---|---| | Модель | асинхронный (ASGI) | синхронный (WSGI) | синхронный, частично асинхронный | | Валидация данных | встроена (Pydantic) | расширения | формы, DRF | | Документация API | автоматически | расширения | через DRF и пакеты | | ORM и админка | нет, выбор свой | нет | встроены | | Сильная сторона | API и микросервисы | простота и гибкость | полноценные сайты «из коробки» | ## См. также - [Dataclasses и Pydantic](https://llmdocs.ru/wiki/dataclasses-pydantic.md) - [REST](https://llmdocs.ru/wiki/rest.md) - [asyncio](https://llmdocs.ru/wiki/asyncio.md) - [Flask](https://llmdocs.ru/wiki/flask.md) - [Django](https://llmdocs.ru/wiki/django.md) ## Источники 1. [FastAPI — документация](https://fastapi.tiangolo.com/) 2. [FastAPI — Tutorial: User Guide](https://fastapi.tiangolo.com/tutorial/) 3. [FastAPI — Dependencies](https://fastapi.tiangolo.com/tutorial/dependencies/) 4. [Starlette](https://www.starlette.io/) 5. [ASGI Documentation](https://asgi.readthedocs.io/) 6. [Uvicorn](https://www.uvicorn.org/) --- # Flask > Минималистичный веб-фреймворк на Python — маршрутизация, запросы и шаблоны Jinja2 в ядре, всё остальное через расширения; популярен для небольших сервисов, API и прототипов. Источник: https://llmdocs.ru/wiki/flask/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Язык**: Python - **Автор**: Армин Ронахер - **Первый выпуск**: апрель 2010 - **Разработчик**: Pallets Projects - **Основа**: Werkzeug (WSGI), Jinja2 (шаблоны), Click (CLI) - **Тип**: микрофреймворк, WSGI - **Лицензия**: BSD-3-Clause **Flask** — минималистичный веб-фреймворк на [Python](https://llmdocs.ru/wiki/python.md), так называемый *микрофреймворк*. Его ядро умеет немногое: маршрутизацию URL, обработку [HTTP](https://llmdocs.ru/wiki/http.md)-запросов и ответов, шаблоны Jinja2, сессии на подписанных cookie и встроенный сервер разработки. Базу данных, формы, аутентификацию и прочее подключают расширениями или собственным кодом.[1] Благодаря простоте Flask популярен для небольших сервисов, внутренних инструментов, API, прототипов и обёрток над ML-моделями. ## История Flask написал австрийский программист Армин Ронахер. Он вырос из первоапрельской шутки 2010 года — фреймворка Denied, упакованного в один файл, — которая неожиданно понравилась сообществу. Flask собрал воедино две уже существовавшие библиотеки того же автора: **Werkzeug** — набор утилит для WSGI[6] — и шаблонизатор **Jinja2**.[5] Сегодня проект развивает сообщество Pallets, куда также входят Click, MarkupSafe и ItsDangerous; версия 1.0 вышла в 2018 году, 2.0 (с поддержкой `async`) — в 2021-м, 3.0 — в 2023-м. ## Минимальное приложение ```python from flask import Flask, jsonify, request, abort app = Flask(__name__) TODOS = {1: "купить молоко"} @app.get("/todos") def list_todos(): return jsonify(TODOS) @app.post("/todos") def add_todo(): text = (request.get_json() or {}).get("text") if not text: abort(400, "text required") new_id = max(TODOS, default=0) + 1 TODOS[new_id] = text return {"id": new_id}, 201 ``` ```bash uv add flask uv run flask --app app run --debug ``` Маршруты объявляются [декораторами](https://llmdocs.ru/wiki/decorators.md), функция-обработчик возвращает строку, словарь (автоматически превращается в [JSON](https://llmdocs.ru/wiki/json.md)), кортеж с кодом состояния или объект `Response`. Объекты `request`, `session` и `g` — **контекстные локальные**: выглядят как глобальные, но указывают на данные текущего запроса. ## Шаблоны Jinja2 поддерживает наследование шаблонов, циклы, фильтры и макросы; HTML-экранирование включено по умолчанию, что защищает от [XSS](https://llmdocs.ru/wiki/xss.md). ```html {% extends "base.html" %} {% block content %}
    {% for t in todos %}
  • {{ t.text }}
  • {% endfor %}
{% endblock %} ``` ## Структура больших приложений - **Фабрика приложений** — функция `create_app()`, которая создаёт и настраивает экземпляр; удобно для тестов и разных конфигураций.[2] - **Blueprints** — модули с собственными маршрутами, шаблонами и статикой, которые регистрируются в приложении: `app.register_blueprint(auth_bp, url_prefix="/auth")`.[3] - Конфигурация — из объекта, файла или [переменных окружения](https://llmdocs.ru/wiki/environment-variables.md) (`app.config.from_prefixed_env()`). ## Экосистема расширений | Задача | Расширение | |---|---| | ORM и БД | Flask-SQLAlchemy, Flask-Migrate (Alembic) | | Формы и CSRF | Flask-WTF | | Вход пользователей | Flask-Login | | JWT | Flask-JWT-Extended | | REST API и OpenAPI | flask-smorest, APIFlask | | CORS | Flask-CORS | | Кэш | Flask-Caching | Свобода выбора — главное достоинство и главный недостаток: каждый проект собирает свой стек, и решения о безопасности (например, защита от [CSRF](https://llmdocs.ru/wiki/csrf.md)) остаются на разработчике. ## Тестирование Flask предоставляет тестовый клиент, который отправляет запросы без запуска сервера; его удобно использовать с [pytest](https://llmdocs.ru/wiki/pytest.md): ```python def test_add(client): r = client.post("/todos", json={"text": "проверить"}) assert r.status_code == 201 ``` ## Асинхронность С версии 2.0 обработчики можно объявлять через `async def`, но Flask остаётся WSGI-фреймворком: каждая асинхронная функция выполняется в отдельном цикле событий внутри потока, и выигрыша в конкурентности, как у ASGI-фреймворков, это не даёт.[4] Для полностью асинхронного кода есть совместимый по API **Quart**, а для новых API часто выбирают [FastAPI](https://llmdocs.ru/wiki/fastapi.md). ## Развёртывание Встроенный сервер (`flask run`) предназначен только для разработки. В продакшене приложение запускают WSGI-сервером — Gunicorn, uWSGI, Waitress — за [обратным прокси](https://llmdocs.ru/wiki/reverse-proxy.md) ([nginx](https://llmdocs.ru/wiki/nginx.md), [Caddy](https://llmdocs.ru/wiki/caddy.md)), часто в контейнере [Docker](https://llmdocs.ru/wiki/docker.md).[7] ```bash gunicorn -w 4 -b 127.0.0.1:8000 "app:create_app()" ``` ## Сравнение | | Flask | [Django](https://llmdocs.ru/wiki/django.md) | [FastAPI](https://llmdocs.ru/wiki/fastapi.md) | |---|---|---|---| | Подход | минимальное ядро | всё в комплекте | API с типами | | Протокол | WSGI | WSGI/ASGI | ASGI | | ORM, админка | расширения | встроены | нет | | Валидация | вручную/расширения | формы | Pydantic | | Документация API | расширения | DRF | OpenAPI автоматически | ## См. также - [Django](https://llmdocs.ru/wiki/django.md) - [FastAPI](https://llmdocs.ru/wiki/fastapi.md) - [REST](https://llmdocs.ru/wiki/rest.md) - [Dataclasses и Pydantic](https://llmdocs.ru/wiki/dataclasses-pydantic.md) ## Источники 1. [Flask documentation](https://flask.palletsprojects.com/) 2. [Flask — Application Factories](https://flask.palletsprojects.com/en/stable/patterns/appfactories/) 3. [Flask — Modular Applications with Blueprints](https://flask.palletsprojects.com/en/stable/blueprints/) 4. [Flask — Using async and await](https://flask.palletsprojects.com/en/stable/async-await/) 5. [Jinja documentation](https://jinja.palletsprojects.com/) 6. [Werkzeug documentation](https://werkzeug.palletsprojects.com/) 7. [Flask — Deploying to Production](https://flask.palletsprojects.com/en/stable/deploying/) --- # Генераторы и итераторы > Итератор — объект, выдающий элементы по одному через протокол __iter__/__next__; генератор — функция с yield, которая лениво производит последовательность значений, не храня её целиком в памяти. Источник: https://llmdocs.ru/wiki/generators-iterators/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Протокол итератора**: методы __iter__ и __next__, исключение StopIteration - **Итераторы**: PEP 234 (Python 2.1) - **Генераторы**: PEP 255 (Python 2.2, 2001) - **Генераторные выражения**: PEP 289 (Python 2.4) - **send и throw**: PEP 342 (Python 2.5) - **yield from**: PEP 380 (Python 3.3) - **Стандартная библиотека**: itertools **Итератор** в [Python](https://llmdocs.ru/wiki/python.md) — объект, который выдаёт элементы последовательности по одному и помнит, где остановился. **Генератор** — самый удобный способ создать итератор: это функция с ключевым словом `yield`, которая при каждом обращении вычисляет и отдаёт следующее значение, а затем «засыпает» до следующего запроса. Генераторы работают **лениво**: значения появляются только тогда, когда нужны, и последовательность не хранится в памяти целиком. На итераторах построен цикл `for`, распаковка, `zip`, `map`, `enumerate`, чтение файлов построчно и обработка потоков данных любого размера. ## Протокол итерации Объект **итерируемый** (*iterable*), если у него есть метод `__iter__`, возвращающий итератор. **Итератор** имеет метод `__next__`, который возвращает следующий элемент или выбрасывает `StopIteration`, когда элементы кончились.[2] Цикл `for x in data` разворачивается примерно так: ```python it = iter(data) # вызывает data.__iter__() while True: try: x = next(it) # вызывает it.__next__() except StopIteration: break ... # тело цикла ``` Списки, кортежи, строки, словари, множества, файлы — итерируемые объекты. Различие важно: список можно обойти сколько угодно раз, а итератор — только один, после чего он исчерпан. ## Генераторные функции Генераторы появились в Python 2.2 (PEP 255, 2001).[1] Функция, содержащая `yield`, при вызове не выполняет тело, а возвращает объект-генератор. Каждый `next()` выполняет код до следующего `yield`: ```python def read_records(path): with open(path, encoding="utf-8") as f: for line in f: # файл читается построчно line = line.strip() if line and not line.startswith("#"): yield line.split(",") def countdown(n): while n > 0: yield n n -= 1 gen = countdown(3) print(next(gen), next(gen), next(gen)) # 3 2 1 # следующий next(gen) выбросит StopIteration ``` `read_records` обработает файл на десятки гигабайт, держа в памяти одну строку. Без генератора пришлось бы писать класс с методами `__iter__` и `__next__` и вручную хранить состояние. ## Генераторные выражения Генераторное выражение похоже на списковое включение, но в круглых скобках и вычисляется лениво (PEP 289):[6] ```python squares_list = [x * x for x in range(10_000_000)] # список: сотни мегабайт памяти сразу squares_gen = (x * x for x in range(10_000_000)) # генератор: байты, значения по запросу total = sum(x * x for x in range(10_000_000)) # скобки функции можно не дублировать ``` ## Конвейеры обработки Генераторы удобно соединять в цепочки, где каждый этап обрабатывает элементы по одному — как [конвейеры](https://llmdocs.ru/wiki/pipes-redirection.md) в Unix: ```python import itertools records = read_records("events.csv") errors = (r for r in records if r[1] == "ERROR") messages = (r[2] for r in errors) for msg in itertools.islice(messages, 10): # первые 10 ошибок; файл дальше не читается print(msg) ``` Модуль `itertools` содержит готовые строительные блоки: `islice` (срез итератора), `chain` (склейка), `groupby` (группировка подряд идущих), `batched` (пакеты по *n*, Python 3.12), `product` и `permutations` (комбинаторика), `count` и `cycle` (бесконечные последовательности).[5] ## Расширенные возможности - **`yield from`** (PEP 380, Python 3.3) делегирует выдачу значений вложенному генератору или итерируемому объекту: `yield from walk(subdir)` в рекурсивном обходе дерева.[3] - **`send()`, `throw()`, `close()`** (PEP 342) превращают генератор в сопрограмму, принимающую значения извне. Исторически на этом были построены первые асинхронные фреймворки, а затем и [asyncio](https://llmdocs.ru/wiki/asyncio.md); сегодня для асинхронности используют `async def` и `await`. - **Асинхронные генераторы** (`async def` с `yield`) и `async for` — для потоков данных, приходящих по сети. - **Генераторы как [контекстные менеджеры](https://llmdocs.ru/wiki/context-managers.md)** — декоратор `contextlib.contextmanager` превращает генератор с одним `yield` в менеджер для оператора `with`. ## Типичные ошибки - **Повторное использование исчерпанного итератора.** Второй проход по генератору ничего не выдаст — нужно создать его заново или сохранить результат в список. - **Ленивость скрывает ошибки.** Код генератора не выполняется до первого `next()`, поэтому исключение возникнет позже, чем ожидается, — например, когда файл уже закрыт. - **`len()` и индексация** для генераторов недоступны: длину можно узнать только пройдя его целиком. - **Ненужная ленивость.** Для маленьких коллекций, которые обходятся несколько раз, список проще и быстрее. Подробнее о функциональном стиле с итераторами — в руководстве Functional Programming HOWTO.[4] ## См. также - [Декораторы](https://llmdocs.ru/wiki/decorators.md) - [Контекстные менеджеры](https://llmdocs.ru/wiki/context-managers.md) - [asyncio](https://llmdocs.ru/wiki/asyncio.md) - [Python](https://llmdocs.ru/wiki/python.md) - [Конвейеры и перенаправление (pipes)](https://llmdocs.ru/wiki/pipes-redirection.md) ## Источники 1. [PEP 255 — Simple Generators](https://peps.python.org/pep-0255/) 2. [PEP 234 — Iterators](https://peps.python.org/pep-0234/) 3. [PEP 380 — Syntax for Delegating to a Subgenerator](https://peps.python.org/pep-0380/) 4. [Python — Functional Programming HOWTO](https://docs.python.org/3/howto/functional.html) 5. [Python — itertools](https://docs.python.org/3/library/itertools.html) 6. [PEP 289 — Generator Expressions](https://peps.python.org/pep-0289/) --- # GIL и free-threading (PEP 703) > GIL — глобальная блокировка интерпретатора CPython, не позволяющая потокам выполнять Python-код параллельно; PEP 703 делает её необязательной, открывая настоящую многопоточность. Источник: https://llmdocs.ru/wiki/gil-free-threading/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **GIL**: мьютекс, разрешающий выполнять байт-код Python только одному потоку - **Появилась**: в CPython с поддержкой потоков (1992) - **PEP 703**: Сэм Гросс (Meta), принят в 2023 году - **Python 3.13**: экспериментальная сборка без GIL (python3.13t) - **Python 3.14**: сборка без GIL официально поддерживается (PEP 779) - **Альтернативы**: multiprocessing, субинтерпретаторы, asyncio, расширения на C и Rust **GIL** (англ. *Global Interpreter Lock* — глобальная блокировка интерпретатора) — механизм в [CPython](https://llmdocs.ru/wiki/cpython.md), основной реализации [Python](https://llmdocs.ru/wiki/python.md), который разрешает выполнять байт-код Python только одному потоку в каждый момент времени. Даже на 16-ядерном процессоре несколько потоков Python, занятых вычислениями, работают по очереди, а не одновременно. **Free-threading** («свободная многопоточность») — сборка CPython без GIL, ставшая возможной благодаря **PEP 703**: в ней потоки выполняют Python-код по-настоящему параллельно.[1] ## Зачем был нужен GIL CPython управляет памятью с помощью подсчёта ссылок: у каждого объекта есть счётчик, и объект удаляется, когда счётчик падает до нуля. Если два потока одновременно меняют счётчик без синхронизации, он испортится — объект удалится раньше времени или никогда. GIL, появившийся в 1992 году вместе с поддержкой потоков, решал это просто: один замок на весь интерпретатор. Это давало быстрый однопоточный код, простую реализацию и лёгкое написание расширений на C, которые могли не думать о потокобезопасности. Цена — невозможность ускорить вычисления потоками. Попытки убрать GIL предпринимались с конца 1990-х, но каждая замедляла однопоточные программы, и их отвергали. ## Когда GIL мешает, а когда нет | Задача | Влияние GIL | |---|---| | Ожидание сети, диска, базы данных | почти не мешает: на время ввода-вывода GIL отпускается | | Вычисления в NumPy, PyTorch, сжатие, хеширование | не мешает: код на C отпускает GIL на время работы | | Вычисления на чистом Python в потоках | мешает: потоки выполняются по очереди | Поэтому для веб-серверов и парсеров потоки и [asyncio](https://llmdocs.ru/wiki/asyncio.md) работают хорошо, а для тяжёлых вычислений на Python традиционно использовали процессы (см. [Конкурентность и параллелизм](https://llmdocs.ru/wiki/concurrency-parallelism.md)). ## PEP 703 В 2021–2023 годах Сэм Гросс из Meta показал прототип CPython без GIL с приемлемыми потерями производительности. Ключевые приёмы: - **Смещённый подсчёт ссылок** (*biased reference counting*): поток-владелец меняет счётчик объекта быстро, без атомарных операций, а остальные потоки — через отдельный атомарный счётчик. - **Бессмертные объекты**: у `None`, `True`, малых чисел счётчик не меняется вовсе. - **Аллокатор mimalloc** и блокировки на уровне отдельных объектов вместо одной глобальной. В октябре 2023 года руководящий совет Python принял PEP 703 с поэтапным планом: сначала экспериментальная сборка, затем официальная поддержка и, если экосистема будет готова, — переход по умолчанию. | Версия | Статус | |---|---| | 3.13 (2024) | экспериментальная сборка без GIL, заметное замедление однопоточного кода[4] | | 3.14 (2025) | официально поддерживаемая сборка (PEP 779), замедление сокращено[2] | | будущее | возможный переход на сборку без GIL по умолчанию | ## Как попробовать ```bash uv python install 3.14t # сборка без GIL (суффикс t — threaded) uv run --python 3.14t python -c "import sys; print(sys._is_gil_enabled())" # False ``` ```python import threading, time def work(n: int) -> int: return sum(i * i for i in range(n)) start = time.perf_counter() threads = [threading.Thread(target=work, args=(10_000_000,)) for _ in range(4)] for t in threads: t.start() for t in threads: t.join() print(f"{time.perf_counter() - start:.1f} с") # с GIL — примерно как 4 последовательных вызова; без GIL — заметно быстрее на 4 ядрах ``` Если в процесс загружается расширение на C, не объявившее поддержку free-threading, интерпретатор по умолчанию включает GIL обратно и предупреждает об этом; переменная окружения `PYTHON_GIL=0` позволяет принудительно отключить его.[3] ## Что меняется для разработчиков - **Гонки данных становятся реальностью.** Код, «случайно» корректный благодаря GIL, может сломаться: общий счётчик, словарь-кэш, ленивая инициализация требуют блокировок (`threading.Lock`) или потокобезопасных структур (см. [Состояние гонки и блокировки](https://llmdocs.ru/wiki/race-conditions-locks.md)). Встроенные типы — `list`, `dict` — защищены от повреждения, но последовательность операций над ними атомарной не становится. - **Расширения на C и Rust** должны быть проверены и пересобраны под новую сборку; сообщество отслеживает готовность популярных пакетов.[6] - **Однопоточный код** в сборке без GIL работает немного медленнее. ## Альтернативы - **multiprocessing и ProcessPoolExecutor** — отдельные процессы, каждый со своим GIL; надёжно, но данные приходится сериализовать. - **Субинтерпретаторы** — несколько интерпретаторов в одном процессе, каждый со своим GIL (PEP 684, Python 3.12);[5] в Python 3.14 появился модуль `concurrent.interpreters`. - **asyncio** — для задач с ожиданием ввода-вывода GIL не помеха. - **Вынос горячего кода** в NumPy, Numba, Cython или расширения на [Rust](https://llmdocs.ru/wiki/rust.md), отпускающие GIL. ## См. также - [Конкурентность и параллелизм](https://llmdocs.ru/wiki/concurrency-parallelism.md) - [CPython](https://llmdocs.ru/wiki/cpython.md) - [asyncio](https://llmdocs.ru/wiki/asyncio.md) - [Состояние гонки и блокировки](https://llmdocs.ru/wiki/race-conditions-locks.md) - [PEP](https://llmdocs.ru/wiki/pep.md) ## Источники 1. [PEP 703 — Making the Global Interpreter Lock Optional in CPython](https://peps.python.org/pep-0703/) 2. [PEP 779 — Criteria for supported status for free-threaded Python](https://peps.python.org/pep-0779/) 3. [Python HOWTO — Python support for free threading](https://docs.python.org/3/howto/free-threading-python.html) 4. [What's New In Python 3.13](https://docs.python.org/3/whatsnew/3.13.html) 5. [PEP 684 — A Per-Interpreter GIL](https://peps.python.org/pep-0684/) 6. [Python free-threading guide (py-free-threading.github.io)](https://py-free-threading.github.io/) --- # Jupyter > Экосистема интерактивных блокнотов — документов из ячеек с кодом, результатами, графиками и текстом; стандартный инструмент анализа данных, ML-экспериментов и обучения. Источник: https://llmdocs.ru/wiki/jupyter/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Название**: от Julia, Python и R - **Предшественник**: IPython Notebook (2011) - **Выделение в Project Jupyter**: 2014 - **Формат файла**: .ipynb (JSON) - **Интерфейсы**: JupyterLab, Jupyter Notebook 7, VS Code, Google Colab, Kaggle - **Ядра**: IPython (Python) и более 100 других языков - **Лицензия**: BSD-3-Clause **Jupyter** — открытая экосистема для интерактивных вычислений, центральное понятие которой — **блокнот** (*notebook*): документ из последовательности ячеек с кодом, результатами его выполнения (таблицами, графиками, изображениями) и текстом в [Markdown](https://llmdocs.ru/wiki/markdown.md). Блокноты стали стандартным инструментом анализа данных, экспериментов в [машинном обучении](https://llmdocs.ru/wiki/machine-learning.md), научных расчётов и обучения программированию.[1] ## История В 2001 году Фернандо Перес создал **IPython** — улучшенную интерактивную оболочку [Python](https://llmdocs.ru/wiki/python.md). В 2011 году к ней добавился веб-интерфейс IPython Notebook. Поскольку архитектура позволяла подключать и другие языки, в 2014 году языконезависимые части выделили в **Project Jupyter**; название составлено из трёх первых поддерживаемых языков — Julia, Python и R — и отсылает к записям Галилея о спутниках Юпитера. В 2017 году проект получил премию ACM Software System Award. ## Архитектура - **Фронтенд** — интерфейс в браузере или редакторе: **JupyterLab** (основная среда с вкладками, файловым менеджером и терминалом), классический Jupyter Notebook (с версии 7 построен на компонентах JupyterLab), а также VS Code, PyCharm, Google Colab и Kaggle Notebooks.[2] - **Ядро** (*kernel*) — отдельный процесс, который выполняет код и хранит состояние: переменные, импорты, загруженные данные. Стандартное ядро — IPython; существуют ядра для R, Julia, Go, Rust, JavaScript, SQL и более сотни других языков.[4] - **Сервер** (Jupyter Server) соединяет фронтенд и ядра по протоколу обмена сообщениями поверх ZeroMQ и WebSocket. - **JupyterHub** — многопользовательский вариант для команд и учебных курсов: каждый пользователь получает свой сервер, в том числе в [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md). ## Формат .ipynb Блокнот хранится в файле `.ipynb` — это [JSON](https://llmdocs.ru/wiki/json.md) со списком ячеек, их исходным кодом, результатами выполнения (включая картинки в base64) и метаданными ядра.[3] Отсюда типичные неудобства: огромные диффы в [Git](https://llmdocs.ru/wiki/git.md), конфликты слияния, «тяжёлые» файлы. Помогают: - **nbstripout** — очистка результатов перед коммитом; - **Jupytext** — синхронизация блокнота с обычным `.py` или `.md` файлом, который удобно ревьюить;[5] - **nbdime** — дифф и слияние с пониманием структуры блокнота. ## Работа с блокнотом ```bash uv add --dev jupyterlab ipykernel uv run jupyter lab ``` Чтобы блокнот видел пакеты нужного [виртуального окружения](https://llmdocs.ru/wiki/venv.md), в нём регистрируют ядро: ```bash uv run python -m ipykernel install --user --name myproject ``` IPython добавляет к Python «магические команды»: ```python %timeit sorted(data) # замер времени %load_ext autoreload %autoreload 2 # перезагрузка изменённых модулей %%sql # ячейка на SQL (расширение jupysql) !pip list | head # команда оболочки ``` Последнее выражение ячейки выводится автоматически; таблицы [pandas](https://llmdocs.ru/wiki/pandas.md) отображаются в HTML, графики matplotlib и plotly — прямо под ячейкой. ## Проблемы воспроизводимости Ячейки можно выполнять в любом порядке, а состояние ядра сохраняется между ними. Поэтому блокнот, который «работал вчера», может не работать при запуске сверху вниз: переменная была определена в удалённой ячейке или код перезапускался в другом порядке. Исследование 1,4 млн блокнотов с GitHub показало, что лишь около четверти из них выполняются без ошибок, а повторное выполнение дало тот же результат лишь у 4 %.[6] Практики: - перед коммитом — «Restart Kernel and Run All»; - фиксировать зависимости (`pyproject.toml`, lock-файл); - выносить повторно используемый код в модули и импортировать его; - параметризовать и запускать блокноты как задачи через **papermill**, превращать в отчёты через **nbconvert** или **Quarto**. ## Безопасность Jupyter-сервер даёт полный доступ к выполнению кода на машине. Его нельзя открывать в интернет без пароля или токена; по умолчанию сервер слушает `localhost` и генерирует токен.[7] Для удалённой работы безопаснее проброс порта через [SSH](https://llmdocs.ru/wiki/ssh.md) (`ssh -L 8888:localhost:8888 server`). Открывать чужие блокноты тоже нужно с осторожностью: выполнение ячеек — это запуск чужого кода. ## Альтернативы и развитие - **Google Colab** и **Kaggle Notebooks** — бесплатные облачные блокноты с GPU. - **marimo** — реактивные блокноты в виде `.py`-файлов, где зависимые ячейки пересчитываются автоматически, что решает проблему скрытого состояния. - **Quarto** — публикация блокнотов как статей, книг и сайтов. - Интеграции с [LLM](https://llmdocs.ru/wiki/llm.md) — Jupyter AI, ассистенты в Colab и VS Code. В [MLOps](https://llmdocs.ru/wiki/mlops.md) блокноты обычно используют для исследования, а обучение и сервинг моделей переносят в обычный код и пайплайны. ## См. также - [pandas](https://llmdocs.ru/wiki/pandas.md) - [NumPy](https://llmdocs.ru/wiki/numpy.md) - [MLflow](https://llmdocs.ru/wiki/mlflow.md) - [Python](https://llmdocs.ru/wiki/python.md) ## Источники 1. [Project Jupyter documentation](https://docs.jupyter.org/) 2. [JupyterLab documentation](https://jupyterlab.readthedocs.io/) 3. [The Jupyter Notebook Format (nbformat)](https://nbformat.readthedocs.io/en/latest/format_description.html) 4. [Jupyter — Kernels (programming languages)](https://docs.jupyter.org/en/latest/projects/kernels.html) 5. [Jupytext documentation](https://jupytext.readthedocs.io/) 6. [Pimentel et al. — A Large-scale Study about Quality and Reproducibility of Jupyter Notebooks (MSR 2019)](https://doi.org/10.1109/MSR.2019.00077) 7. [Jupyter Server — Security](https://jupyter-server.readthedocs.io/en/latest/operators/security.html) --- # mypy и pyright > Статические анализаторы типов для Python — проверяют аннотации типов без запуска программы и находят ошибки до выполнения кода. Источник: https://llmdocs.ru/wiki/mypy-pyright/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: статические анализаторы типов - **mypy**: Юкка Лехтосало, с 2012; написан на Python, лицензия MIT - **pyright**: Microsoft (Эрик Траут), с 2019; написан на TypeScript, лицензия MIT - **Основа**: PEP 484 и спецификация типизации Python - **Интеграция**: VS Code (Pylance), PyCharm, Neovim, CI - **Новые анализаторы**: ty (Astral), Pyrefly (Meta) — на Rust **mypy** и **pyright** — два самых распространённых статических анализатора типов для [Python](https://llmdocs.ru/wiki/python.md). Они читают исходный код вместе с [аннотациями типов](https://llmdocs.ru/wiki/type-hints.md) и, не запуская программу, находят несоответствия: передачу строки туда, где ожидается число, обращение к атрибуту, которого нет, забытую проверку на `None`. Интерпретатор Python аннотации не проверяет, поэтому без анализатора они остаются лишь документацией. Анализатор подключают в редакторе — ошибки подсвечиваются при наборе — и в конвейере [CI/CD](https://llmdocs.ru/wiki/ci-cd.md), чтобы код с ошибками типов не попадал в основную ветку. ## История **mypy** начинался в 2012 году как диссертационный проект Юкки Лехтосало: сначала это был отдельный язык с похожим на Python синтаксисом, затем — анализатор для обычного Python. Гвидо ван Россум увидел потенциал проекта, и идеи mypy легли в основу PEP 484 (2014). Позже разработку поддерживала Dropbox, где mypy проверял миллионы строк кода. mypy считается эталонной реализацией и развивается в организации python на GitHub.[2] **pyright** выпустила Microsoft в 2019 году; основной автор — Эрик Траут. Он написан на TypeScript ради скорости и интеграции с редакторами и лежит в основе расширения Pylance для VS Code. Сообщество поддерживает форк basedpyright с дополнительными проверками и открытой языковой поддержкой. В 2025 году появились анализаторы на Rust — **ty** от Astral (авторов [Ruff](https://llmdocs.ru/wiki/ruff.md) и [uv](https://llmdocs.ru/wiki/uv.md)) и **Pyrefly** от Meta, — делающие ставку на скорость на больших кодовых базах. ## Пример ```python from dataclasses import dataclass @dataclass class User: id: int email: str | None def domain(user: User) -> str: return user.email.split("@")[1] # ошибка: email может быть None def find(users: list[User], uid: int) -> User: for u in users: if u.id == uid: return u # ошибка: функция может завершиться без return, т. е. вернуть None ``` ```text $ mypy app.py app.py:9: error: Item "None" of "str | None" has no attribute "split" [union-attr] app.py:11: error: Missing return statement [return] ``` Обе ошибки проявились бы только во время выполнения, на конкретных данных. Анализатор находит их сразу и для всех путей выполнения. ## Сравнение | | mypy | pyright | |---|---|---| | Язык реализации | Python (частично скомпилирован mypyc) | TypeScript (Node.js) | | Скорость | медленнее, есть инкрементальный кэш и демон `dmypy` | быстрее, рассчитан на проверку при наборе | | Функции без аннотаций | по умолчанию не проверяет тело | выводит типы и проверяет | | Вывод типов | консервативнее | агрессивнее, сужение типов по коду | | Плагины | есть (Django, Pydantic, SQLAlchemy) | нет, опора на стандартные механизмы | | Редактор | через расширения | встроен в Pylance (VS Code) | Различия в поведении на одном и том же коде подробно описаны в документации pyright.[4] На практике многие команды используют pyright в редакторе, а в CI запускают тот анализатор, под который настроен проект. ## Настройка Оба инструмента читают настройки из [pyproject.toml](https://llmdocs.ru/wiki/pyproject-toml.md): ```toml [tool.mypy] python_version = "3.13" strict = true # набор строгих проверок warn_unused_ignores = true exclude = ["migrations/"] [[tool.mypy.overrides]] module = ["legacy.*"] ignore_errors = true # старый код — постепенно [tool.pyright] typeCheckingMode = "standard" # off | basic | standard | strict pythonVersion = "3.13" ``` ```bash uv add --dev mypy pyright uv run mypy src/ uv run pyright ``` Режим `strict` требует аннотаций у всех функций и запрещает неявный `Any`. В существующем проекте строгость наращивают постепенно: сначала базовый режим для всего кода, затем строгий для новых и критичных модулей.[1][3] ## Полезные приёмы - **`reveal_type(x)`** — анализатор покажет, какой тип он вывел для выражения; незаменимо при отладке типов. - **Сужение типов.** После `if x is not None:` или `isinstance(x, str)` анализатор знает, что тип стал уже. Для своих проверок есть `TypeGuard` и `TypeIs`. - **`# type: ignore[код-ошибки]`** — точечно подавить ошибку, указав её код; `warn_unused_ignores` напомнит удалить устаревшие подавления. - **Заглушки типов.** Для библиотек без аннотаций ставят пакеты `types-*` из typeshed — общего репозитория аннотаций для стандартной библиотеки и популярных пакетов.[6] - **`py.typed`.** Библиотека, распространяющая встроенные аннотации, кладёт в пакет пустой файл-маркер `py.typed`. ## Ограничения Статический анализ не заменяет тесты: он проверяет согласованность типов, но не логику. Динамические приёмы — `getattr` по строке, monkey-patching, метаклассы — анализатор понимает плохо, а `Any` выключает проверку для всего, что через него проходит. Для проверки данных извне — JSON из API, конфигурации — нужны проверки во время выполнения, например Pydantic (см. [Dataclasses и Pydantic](https://llmdocs.ru/wiki/dataclasses-pydantic.md)). Общие правила для всех анализаторов собраны в документации проекта typing.[5] ## См. также - [Типизация в Python (type hints, PEP 484)](https://llmdocs.ru/wiki/type-hints.md) - [Ruff](https://llmdocs.ru/wiki/ruff.md) - [Dataclasses и Pydantic](https://llmdocs.ru/wiki/dataclasses-pydantic.md) - [pyproject.toml](https://llmdocs.ru/wiki/pyproject-toml.md) - [pytest](https://llmdocs.ru/wiki/pytest.md) ## Источники 1. [mypy documentation](https://mypy.readthedocs.io/) 2. [python/mypy — GitHub](https://github.com/python/mypy) 3. [Pyright documentation](https://microsoft.github.io/pyright/) 4. [Pyright — Differences between Pyright and mypy](https://github.com/microsoft/pyright/blob/main/docs/mypy-comparison.md) 5. [Static Typing with Python — typing.python.org](https://typing.python.org/en/latest/) 6. [python/typeshed — GitHub](https://github.com/python/typeshed) --- # NumPy > Фундаментальная библиотека научных вычислений на Python — многомерные массивы ndarray, векторизованные операции, трансляция (broadcasting) и линейная алгебра; основа pandas, scikit-learn и большинства инструментов анализа данных. Источник: https://llmdocs.ru/wiki/numpy/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: библиотека численных вычислений - **Автор**: Тревис Олифант - **Первый выпуск**: 2006 (предшественники — Numeric с 1995, Numarray) - **Языки**: Python, C - **Лицензия**: BSD - **Ключевой объект**: ndarray — многомерный однородный массив - **NumPy 2.0**: июнь 2024 - **Сайт**: numpy.org **NumPy** (от *Numerical Python*) — библиотека для численных вычислений на [Python](https://llmdocs.ru/wiki/python.md). Её центральный объект — **ndarray**, многомерный массив чисел одного типа, хранящихся в памяти подряд. Операции над такими массивами выполняются в скомпилированном коде на C сразу над всеми элементами — это называется **векторизацией** — и работают в десятки и сотни раз быстрее циклов на Python.[1] NumPy — фундамент научного стека Python: на нём построены [pandas](https://llmdocs.ru/wiki/pandas.md), SciPy, [scikit-learn](https://llmdocs.ru/wiki/scikit-learn.md), Matplotlib, а интерфейс массивов NumPy повторяют [PyTorch](https://llmdocs.ru/wiki/pytorch.md), JAX и CuPy. ## История В 1995 году Джим Хьюгунин создал пакет Numeric для работы с массивами в Python; позже появился конкурирующий Numarray, лучше справлявшийся с большими массивами. В 2005–2006 годах Тревис Олифант объединил их в один проект — NumPy, — покончив с расколом сообщества. В 2020 году вклад NumPy в науку отметила статья в журнале Nature: библиотека использовалась, в частности, при получении первого изображения чёрной дыры и обнаружении гравитационных волн.[1] Версия NumPy 2.0 (июнь 2024) стала первым крупным обновлением за 18 лет, очистив API и изменив правила приведения типов.[5] ## Массивы ```python import numpy as np a = np.array([1, 2, 3, 4]) # из списка m = np.zeros((3, 4)) # матрица 3×4 из нулей r = np.arange(0, 1, 0.25) # [0. , 0.25, 0.5 , 0.75] x = np.linspace(0, 2 * np.pi, 100) # 100 точек на отрезке rng = np.random.default_rng(42) data = rng.normal(size=(1000, 3)) # 1000 строк, 3 столбца print(data.shape, data.dtype, data.ndim) # (1000, 3) float64 2 ``` У массива есть **форма** (`shape`) — размер по каждой оси, и **тип данных** (`dtype`): `int64`, `float32`, `bool`, `complex128` и другие. Все элементы одного типа, поэтому массив занимает в разы меньше памяти, чем список Python, где каждое число — отдельный объект.[3] ## Векторизация ```python prices = np.array([100.0, 250.0, 80.0]) qty = np.array([3, 1, 10]) total = prices * qty # поэлементно: [300., 250., 800.] print(total.sum(), total.mean()) # агрегаты print(np.sqrt(prices), prices > 90) # функции и сравнения тоже поэлементные # вместо цикла: нормализация каждого столбца normalized = (data - data.mean(axis=0)) / data.std(axis=0) ``` Параметр `axis` указывает, вдоль какой оси выполнять агрегацию: `axis=0` — по строкам (для каждого столбца), `axis=1` — по столбцам (для каждой строки). ## Трансляция (broadcasting) Массивы разной формы автоматически «растягиваются» до общей, если их размеры совместимы: сравнение идёт с последней оси, и размеры должны совпадать или один из них равняться 1.[4] Так из матрицы 1000×3 вычитается вектор средних длины 3 — без копирования данных и циклов. Трансляция — мощный, но коварный механизм: ошибка в форме иногда не вызывает исключения, а молча даёт неверный результат. ## Индексация ```python data[0] # первая строка data[:, 1] # второй столбец data[10:20, :2] # срез строк и столбцов — представление, без копирования data[data[:, 0] > 2] # логическая маска: строки, где первый столбец больше 2 data[[1, 5, 7]] # выборка по списку индексов — копия ``` Срезы возвращают **представления** (*view*) исходного массива: изменение среза меняет оригинал. Логическая и списочная индексация создают копию. ## Линейная алгебра и прочее - `@` и `np.matmul` — матричное умножение; `np.linalg` — обращение матриц, решение систем, собственные значения, разложения (SVD, QR) поверх оптимизированных библиотек BLAS и LAPACK. - `np.random.default_rng()` — генераторы случайных чисел с воспроизводимостью по зерну. - `np.fft` — быстрое преобразование Фурье. - Сохранение и загрузка: `np.save`, `np.load` (формат `.npy`), `np.savez_compressed`. Векторный поиск по [эмбеддингам](https://llmdocs.ru/wiki/embedding.md) в простейшем виде — одна строка NumPy: `scores = vectors @ query`, а затем `np.argsort(-scores)[:5]`. ## Экосистема | Библиотека | Связь с NumPy | |---|---| | [pandas](https://llmdocs.ru/wiki/pandas.md) | таблицы поверх массивов NumPy (и Apache Arrow) | | SciPy | оптимизация, статистика, обработка сигналов | | [scikit-learn](https://llmdocs.ru/wiki/scikit-learn.md) | принимает и возвращает массивы NumPy | | Matplotlib | графики из массивов | | Numba | компиляция циклов над массивами в машинный код | | CuPy, JAX, [PyTorch](https://llmdocs.ru/wiki/pytorch.md) | NumPy-подобные массивы на [GPU](https://llmdocs.ru/wiki/gpu-cuda.md) | Чтобы код мог работать с разными библиотеками массивов, сообщество разработало общий стандарт Array API.[6] ## Советы - Избегайте циклов Python по элементам массива — ищите векторизованную функцию или трансляцию. - Следите за `dtype`: целочисленные массивы переполняются молча, а `float32` вдвое экономнее `float64`. - Не добавляйте элементы в массив в цикле (`np.append` копирует весь массив) — собирайте список и превращайте в массив один раз или выделяйте память заранее. Полная справка — в документации NumPy.[2] ## См. также - [pandas](https://llmdocs.ru/wiki/pandas.md) - [scikit-learn](https://llmdocs.ru/wiki/scikit-learn.md) - [PyTorch](https://llmdocs.ru/wiki/pytorch.md) - [Python](https://llmdocs.ru/wiki/python.md) - [Машинное обучение](https://llmdocs.ru/wiki/machine-learning.md) ## Источники 1. [C. R. Harris et al. — Array programming with NumPy (Nature, 2020)](https://www.nature.com/articles/s41586-020-2649-2) 2. [NumPy Documentation](https://numpy.org/doc/stable/) 3. [NumPy — the absolute basics for beginners](https://numpy.org/doc/stable/user/absolute_beginners.html) 4. [NumPy — Broadcasting](https://numpy.org/doc/stable/user/basics.broadcasting.html) 5. [NumPy 2.0 migration guide](https://numpy.org/doc/stable/numpy_2_0_migration_guide.html) 6. [Python array API standard](https://data-apis.org/array-api/latest/) --- # pandas > Библиотека Python для анализа табличных данных — объекты DataFrame и Series, чтение CSV, Excel и SQL, фильтрация, группировка, объединение и работа с временными рядами. Источник: https://llmdocs.ru/wiki/pandas/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: библиотека анализа данных - **Автор**: Уэс Маккинни - **Создана**: 2008 (AQR Capital), открыт код в 2009 - **Языки**: Python, Cython, C - **Лицензия**: BSD-3-Clause - **Основные объекты**: DataFrame (таблица), Series (столбец) - **Основа**: NumPy, Apache Arrow (опционально) - **Альтернативы**: Polars, DuckDB **pandas** — библиотека [Python](https://llmdocs.ru/wiki/python.md) для работы с табличными данными. Её основной объект — **DataFrame**, таблица со строками и именованными столбцами разных типов, похожая на лист Excel или таблицу [базы данных](https://llmdocs.ru/wiki/relational-database.md), но управляемая кодом. pandas читает данные из CSV, Excel, JSON, Parquet и SQL, позволяет фильтровать, группировать, объединять и переформатировать их и сохранять результат обратно. pandas — стандартный инструмент аналитиков и специалистов по данным: на нём делается очистка данных, разведочный анализ в [Jupyter](https://llmdocs.ru/wiki/jupyter.md) и подготовка признаков для [машинного обучения](https://llmdocs.ru/wiki/machine-learning.md). ## История Уэс Маккинни начал писать pandas в 2008 году в инвестиционной компании AQR Capital, где ему не хватало удобных средств анализа финансовых данных в Python; в 2009 году код открыли. Название происходит от термина эконометрики *panel data* и от «Python data analysis». Маккинни написал о библиотеке книгу «Python for Data Analysis», третье издание которой доступно бесплатно онлайн.[3] pandas построена на массивах [NumPy](https://llmdocs.ru/wiki/numpy.md); с версии 2.0 (2023) столбцы можно хранить и в формате Apache Arrow, что ускоряет работу со строками и пропусками.[6] ## Основы ```python import pandas as pd df = pd.read_csv("orders.csv", parse_dates=["created_at"]) df.head() # первые строки df.info() # столбцы, типы, пропуски df.describe() # статистика по числовым столбцам paid = df[df["status"] == "paid"] # фильтрация строк big = df.query("total > 5000 and city == 'Москва'") # то же строкой запроса df["total_with_vat"] = df["total"] * 1.2 # новый столбец df.loc[df["total"] < 0, "total"] = 0 # изменение по условию ``` **Series** — один столбец с индексом, **DataFrame** — набор Series с общим индексом. Индексация `df.loc[строки, столбцы]` работает по меткам, `df.iloc[...]` — по позициям.[2] ## Группировка и агрегация ```python summary = ( df.groupby("city") .agg(orders=("id", "count"), revenue=("total", "sum"), avg_check=("total", "mean")) .sort_values("revenue", ascending=False) ) monthly = df.set_index("created_at").resample("MS")["total"].sum() # выручка по месяцам pivot = df.pivot_table(index="city", columns="status", values="total", aggfunc="sum") ``` Схема «разделить — применить — объединить» (*split-apply-combine*) — основа анализа: данные делятся на группы, к каждой применяется функция, результаты собираются в таблицу. Это аналог `GROUP BY` в [SQL](https://llmdocs.ru/wiki/sql.md). ## Объединение таблиц ```python customers = pd.read_sql("SELECT id, name, segment FROM customers", engine) merged = df.merge(customers, left_on="customer_id", right_on="id", how="left") both = pd.concat([df_2025, df_2026], ignore_index=True) ``` `merge` — аналог `JOIN` в SQL (`how="inner" | "left" | "right" | "outer"`), `concat` склеивает таблицы по строкам или столбцам. ## Пропуски и типы Пропуски обозначаются `NaN`, `None` или `pd.NA`; их находят `isna()`, удаляют `dropna()` и заполняют `fillna()`. Правильные типы экономят память и ускоряют работу: `category` для столбцов с небольшим числом значений, даты вместо строк, типы с поддержкой пропусков (`Int64`, `string`) вместо `object`. ## Производительность - **Векторизация вместо циклов.** `df.apply` и особенно `iterrows()` выполняют Python-код для каждой строки и медленны; операции над целыми столбцами и встроенные методы — в разы быстрее. - **Форматы.** Parquet читается быстрее CSV, хранит типы и сжимает данные. - **Copy-on-Write.** Новая модель копирования делает поведение предсказуемым: изменение производной таблицы не меняет исходную, а предупреждение `SettingWithCopyWarning` уходит в прошлое.[4] - **Объём.** pandas держит данные в памяти одной машины; для таблиц, которые в неё не помещаются, нужны другие инструменты. ## Polars и другие альтернативы | Инструмент | Особенности | |---|---| | pandas | самая большая экосистема, привычный API, огромное число примеров | | Polars | написан на [Rust](https://llmdocs.ru/wiki/rust.md), многопоточный, ленивые запросы с оптимизатором, обычно заметно быстрее[5] | | DuckDB | встраиваемая аналитическая СУБД: SQL прямо по файлам Parquet и CSV и по таблицам pandas | | PySpark, Dask | распределённая обработка на кластерах | Многие задачи удобно решать комбинацией: DuckDB или Polars для тяжёлых преобразований, pandas — для финальной обработки и совместимости с библиотеками визуализации и машинного обучения. Обмен данными между ними почти без копирования обеспечивает формат Apache Arrow. ## Советы - Начинайте анализ с `df.info()` и `df.describe()`, проверяйте типы и пропуски сразу после загрузки. - Пишите преобразования цепочками методов — их легче читать и отлаживать. - Фиксируйте версии pandas в проекте: поведение некоторых операций меняется между мажорными версиями. Краткое введение — руководство «10 minutes to pandas», полная справка — документация pandas.[2][1] ## См. также - [NumPy](https://llmdocs.ru/wiki/numpy.md) - [Jupyter](https://llmdocs.ru/wiki/jupyter.md) - [SQL](https://llmdocs.ru/wiki/sql.md) - [scikit-learn](https://llmdocs.ru/wiki/scikit-learn.md) - [Колоночное хранение](https://llmdocs.ru/wiki/columnar-storage.md) ## Источники 1. [pandas — документация](https://pandas.pydata.org/docs/) 2. [pandas — 10 minutes to pandas](https://pandas.pydata.org/docs/user_guide/10min.html) 3. [Wes McKinney — Python for Data Analysis, 3rd ed. (open access)](https://wesmckinney.com/book/) 4. [pandas — Copy-on-Write](https://pandas.pydata.org/docs/user_guide/copy_on_write.html) 5. [Polars — документация](https://pola.rs/) 6. [Apache Arrow](https://arrow.apache.org/) --- # PEP 8 > Руководство по стилю кода на Python — отступы, длина строк, импорты, именование и пробелы. Источник: https://llmdocs.ru/wiki/pep-8/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Название**: Style Guide for Python Code - **Авторы**: Гвидо ван Россум, Барри Уорсо, Алисса Коглан - **Создан**: 5 июля 2001 - **Тип PEP**: Process - **Статус**: Active - **Средства проверки**: pycodestyle, flake8, Ruff - **Форматировщики**: Black, Ruff format, autopep8 - **Текст**: [peps.python.org/pep-0008](https://peps.python.org/pep-0008/) **PEP 8** — официальное руководство по стилю кода на [Python](https://llmdocs.ru/wiki/python.md). Документ описывает, как оформлять отступы, переносить длинные строки, располагать импорты, ставить пробелы и называть переменные, функции и классы. PEP 8 не является требованием интерпретатора — код с нарушениями работает, — но фактически стал общим стандартом сообщества: ему следуют стандартная библиотека, большинство открытых проектов и автоматические инструменты. ## История PEP 8 создан в июле 2001 года на основе эссе Гвидо ван Россума о стиле и руководства Барри Уорсо; позже соавтором стала Алисса Коглан.[1] Документ остаётся «живым»: его уточняют по мере развития языка, например после появления аннотаций типов и f-строк. Соглашения о строках документации вынесены в отдельный PEP 257.[2] ## Главная идея Ключевая мысль сформулирована в разделе с ироничным названием «Глупая последовательность — пугало ограниченных умов»: код читают гораздо чаще, чем пишут, поэтому важна прежде всего читаемость.[1] Согласованность внутри проекта важнее согласованности с PEP 8, а согласованность внутри модуля или функции — важнее всего. Руководство прямо разрешает отступать от правил, если следование им ухудшает читаемость или ломает совместимость со старым кодом. ## Основные правила **Отступы и строки** - 4 пробела на уровень отступа, без табуляции. - Максимальная длина строки — 79 символов, для комментариев и строк документации — 72. Команды могут договориться о большем лимите (до 99). - Длинные выражения переносятся внутри скобок, а не обратной косой чертой; бинарный оператор лучше ставить в начале новой строки. - Две пустые строки вокруг функций и классов верхнего уровня, одна — между методами. **Импорты** - Каждый импорт на отдельной строке, в начале файла. - Порядок групп: стандартная библиотека, сторонние пакеты, модули проекта; между группами — пустая строка. - Избегать `from module import *`. **Пробелы** ```python # правильно spam(ham[1], {eggs: 2}) x = 1 def complex(real, imag=0.0): ... result = func(a, key=value) # неправильно spam( ham[ 1 ], { eggs: 2 } ) x=1 def complex(real, imag = 0.0): ... ``` **Сравнения** - С `None` сравнивают через `is` / `is not`, а не `==`. - Пустые последовательности проверяют как ложные: `if not items:` вместо `if len(items) == 0:`. - Типы проверяют через `isinstance()`, а не сравнением `type()`. ## Именование | Что | Стиль | Пример | |---|---|---| | модули, пакеты | короткие, строчные | `mymodule` | | функции, переменные, методы | `snake_case` | `load_config` | | классы, исключения | `CapWords` | `HttpClient`, `ParseError` | | константы | `UPPER_CASE` | `MAX_RETRIES` | | «внутренние» имена | ведущее подчёркивание | `_cache` | | избежание конфликта с ключевым словом | завершающее подчёркивание | `class_` | | первый аргумент метода | `self`, у методов класса `cls` | | Имена из двойного подчёркивания по краям (`__init__`) зарезервированы для специальных методов языка; придумывать собственные не следует. ## Инструменты Следить за стилем вручную непрактично, поэтому используют автоматические средства: | Инструмент | Что делает | |---|---| | pycodestyle | проверка соответствия PEP 8 (до 2016 года назывался `pep8`)[3] | | flake8 | pycodestyle + поиск ошибок (pyflakes) + плагины | | Black | форматировщик без настроек, строки до 88 символов[4] | | [Ruff](https://llmdocs.ru/wiki/ruff.md) | быстрый линтер и форматировщик на Rust, включает правила pycodestyle (коды `E`, `W`)[5] | | autopep8 | автоматическое исправление нарушений | ```bash ruff check . # найти нарушения ruff check --fix . # исправить то, что можно ruff format . # отформатировать код ``` Форматировщики снимают споры о стиле в код-ревью: оформление определяет инструмент, а люди обсуждают логику. Обычно их подключают к редактору, к Git-хукам (см. [Git-хуки](https://llmdocs.ru/wiki/git-hooks.md)) и к [конвейеру CI](https://llmdocs.ru/wiki/ci-cd.md). ## Сравнение с другими языками Похожие соглашения есть у большинства языков, но степень формализации разная: в [Go](https://llmdocs.ru/wiki/go.md) стиль навязывает утилита `gofmt` без вариантов, в Rust — `rustfmt`, в JavaScript принято выбирать конфигурацию ESLint и Prettier. PEP 8 ближе к руководству, чем к закону, а жёсткость добавляют уже инструменты вроде Black. ## См. также - [PEP](https://llmdocs.ru/wiki/pep.md) - [Ruff](https://llmdocs.ru/wiki/ruff.md) - [Python](https://llmdocs.ru/wiki/python.md) - [mypy и pyright](https://llmdocs.ru/wiki/mypy-pyright.md) ## Источники 1. [PEP 8 — Style Guide for Python Code](https://peps.python.org/pep-0008/) 2. [PEP 257 — Docstring Conventions](https://peps.python.org/pep-0257/) 3. [pycodestyle documentation](https://pycodestyle.pycqa.org/) 4. [Black — The uncompromising code formatter](https://black.readthedocs.io/) 5. [Ruff — Rules](https://docs.astral.sh/ruff/rules/) --- # PEP > Python Enhancement Proposal — документ, через который предлагаются, обсуждаются и принимаются изменения в языке Python. Источник: https://llmdocs.ru/wiki/pep/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Полное название**: Python Enhancement Proposal - **Появились**: 2000 - **Описание процесса**: PEP 1 - **Кто принимает решения**: руководящий совет Python (PEP 13) - **Типы**: Standards Track, Informational, Process - **Обсуждение**: discuss.python.org - **Каталог**: [peps.python.org](https://peps.python.org/) **PEP** (англ. *Python Enhancement Proposal* — «предложение по улучшению Python») — проектный документ, в котором описывается новая возможность языка [Python](https://llmdocs.ru/wiki/python.md), изменение процесса разработки или информация для сообщества. PEP содержит техническую спецификацию и обоснование, фиксирует ход обсуждения и итоговое решение. Через PEP прошли почти все крупные изменения Python за последние двадцать с лишним лет — от стиля кода до аннотаций типов и отказа от GIL. ## История Процесс появился в 2000 году, когда разработка Python перешла от небольшой группы к широкому сообществу. Его описывает **PEP 1** «Назначение и правила PEP», за образец были взяты документы RFC, по которым принимаются стандарты интернета.[1] Номер 0 зарезервирован за индексом всех PEP.[2] До 2018 года окончательное решение принимал Гвидо ван Россум. После острого спора вокруг оператора присваивания в выражениях `:=` (PEP 572)[5] он отказался от этой роли, и сообщество выбрало новую модель управления: решения принимает выборный **руководящий совет** (Steering Council) из пяти человек, переизбираемый после каждого выпуска (PEP 13, PEP 8016).[3][4] ## Типы PEP | Тип | Назначение | Примеры | |---|---|---| | **Standards Track** | новая возможность языка или стандартной библиотеки | PEP 484 (аннотации типов), PEP 634 (сопоставление с образцом) | | **Informational** | рекомендации и сведения без обязательных изменений | PEP 20 («Дзен Python»), PEP 257 (строки документации) | | **Process** | изменение процессов вокруг Python | PEP 602 (ежегодный цикл выпусков), PEP 13, [PEP 8](https://llmdocs.ru/wiki/pep-8.md) (формально отнесён к процессным) | ## Жизненный цикл 1. Идея обсуждается на форуме discuss.python.org, чтобы понять, нужна ли она и не предлагалась ли раньше. 2. Автор пишет черновик по шаблону PEP 1 и находит **спонсора** среди core-разработчиков. 3. Редакторы присваивают номер, PEP получает статус **Draft**. 4. Идёт публичное обсуждение, текст дорабатывается. 5. Руководящий совет или назначенный им **PEP-делегат** принимает решение. Основные статусы:[1] - **Draft** — черновик в обсуждении; - **Accepted** — принят, реализация ещё не завершена; - **Provisional** — принят условно, API может измениться; - **Final** — принят и реализован; - **Rejected**, **Withdrawn**, **Deferred** — отклонён, отозван автором, отложен; - **Superseded** — заменён более новым PEP; - **Active** — информационный или процессный документ, который действует постоянно. Отклонённые PEP не удаляются: они остаются в каталоге как запись о том, почему идея не была принята, и экономят время тем, кто захочет предложить её снова. ## Структура документа Каждый PEP начинается с заголовка с метаданными: ```text PEP: 8 Title: Style Guide for Python Code Author: Guido van Rossum, Barry Warsaw, Alyssa Coghlan Status: Active Type: Process Created: 05-Jul-2001 ``` Далее следуют обязательные разделы: аннотация, мотивация, обоснование, спецификация, обратная совместимость, вопросы безопасности, «как этому учить», эталонная реализация, отвергнутые идеи и открытые вопросы. ## Известные PEP | Номер | Тема | |---|---| | 8 | стиль кода, см. [PEP 8](https://llmdocs.ru/wiki/pep-8.md) | | 20 | «Дзен Python» (`import this`) | | 257 | соглашения о строках документации | | 405 | виртуальные окружения, см. [Виртуальные окружения (venv)](https://llmdocs.ru/wiki/venv.md) | | 484 | аннотации типов, см. [Типизация в Python (type hints, PEP 484)](https://llmdocs.ru/wiki/type-hints.md) | | 492 | `async`/`await`, см. [asyncio](https://llmdocs.ru/wiki/asyncio.md) | | 572 | оператор `:=` | | 621 | метаданные проекта в [pyproject.toml](https://llmdocs.ru/wiki/pyproject-toml.md) | | 703 | отключаемый GIL, см. [GIL и free-threading (PEP 703)](https://llmdocs.ru/wiki/gil-free-threading.md) | ## Аналоги в других проектах Схема «предложение — обсуждение — решение» распространилась далеко за пределы Python: в Rust действуют RFC, в Java — JEP, в [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) — KEP, в JavaScript — предложения комитета TC39 со стадиями от 0 до 4. Общая идея — зафиксировать не только решение, но и его мотивы, чтобы через годы было понятно, почему язык устроен именно так. ## См. также - [Python](https://llmdocs.ru/wiki/python.md) - [PEP 8](https://llmdocs.ru/wiki/pep-8.md) - [CPython](https://llmdocs.ru/wiki/cpython.md) - [Семантическое версионирование](https://llmdocs.ru/wiki/semver.md) ## Источники 1. [PEP 1 — PEP Purpose and Guidelines](https://peps.python.org/pep-0001/) 2. [PEP 0 — Index of Python Enhancement Proposals](https://peps.python.org/) 3. [PEP 13 — Python Language Governance](https://peps.python.org/pep-0013/) 4. [PEP 8016 — The Steering Council Model](https://peps.python.org/pep-8016/) 5. [PEP 572 — Assignment Expressions](https://peps.python.org/pep-0572/) --- # pip и PyPI > pip — стандартный установщик пакетов Python, PyPI — центральный публичный каталог пакетов, откуда pip их скачивает. Источник: https://llmdocs.ru/wiki/pip-pypi/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **pip — тип**: установщик пакетов - **pip — появился**: 2008 - **PyPI — запущен**: 2003 - **Сопровождение**: Python Packaging Authority (PyPA), PSF - **Форматы пакетов**: wheel (.whl), sdist (.tar.gz) - **Входит в Python**: с 3.4 через ensurepip (PEP 453) - **Лицензия pip**: MIT - **Сайты**: [pip.pypa.io](https://pip.pypa.io/), [pypi.org](https://pypi.org/) **pip** — стандартный установщик пакетов для [Python](https://llmdocs.ru/wiki/python.md), а **PyPI** (*Python Package Index*) — центральный публичный каталог, в котором разработчики публикуют свои библиотеки и откуда pip их по умолчанию скачивает. Вместе они образуют основу экосистемы: команда `pip install requests` находит пакет на PyPI, выбирает подходящую версию и файл под текущую платформу, устанавливает его и все зависимости. ## История PyPI запущен в 2003 году; среди разработчиков он долго носил шутливое имя Cheese Shop по скетчу «Монти Пайтона». В 2018 году каталог переехал на новую платформу Warehouse, на которой работает pypi.org. Первым массовым установщиком был `easy_install` из пакета setuptools. В 2008 году Ян Бикинг выпустил pip как его замену: с удалением пакетов, файлами требований и понятными ошибками. Начиная с Python 3.4 pip поставляется вместе с интерпретатором через модуль `ensurepip` (PEP 453).[2] В версии pip 20.3 (2020) появился полноценный **резолвер зависимостей**, который отказывается ставить несовместимые наборы версий, а не устанавливает их молча.[4] ## Форматы пакетов | Формат | Что это | |---|---| | **wheel** (`.whl`) | готовый к установке архив, в том числе с уже скомпилированными расширениями под конкретную платформу (PEP 427)[3] | | **sdist** (`.tar.gz`) | исходный код; при установке pip собирает его, что может потребовать компилятора | В имени wheel-файла зашиты версия Python, ABI и платформа, например `numpy-2.1.0-cp312-cp312-manylinux_2_17_x86_64.whl`. pip выбирает наиболее подходящий wheel и обращается к sdist, только если подходящего нет. ## Основные команды ```bash python -m pip install requests # установить последнюю версию python -m pip install "django>=5,<6" # с ограничением версии python -m pip install -r requirements.txt # из файла требований python -m pip install -e . # проект в режиме разработки python -m pip list --outdated # устаревшие пакеты python -m pip freeze > requirements.txt # зафиксировать текущие версии python -m pip uninstall requests ``` Вызов через `python -m pip` гарантирует, что пакет поставится именно для того интерпретатора, который вы запускаете. Ставить пакеты рекомендуется внутри [виртуального окружения](https://llmdocs.ru/wiki/venv.md). ## Файлы зависимостей - `requirements.txt` — простой список пакетов с версиями, по строке на пакет; - [pyproject.toml](https://llmdocs.ru/wiki/pyproject-toml.md) — стандартное описание проекта и его зависимостей (PEP 621); - **constraints**-файлы (`-c constraints.txt`) ограничивают версии, не добавляя пакеты; - режим проверки хешей (`--require-hashes`) защищает от подмены файлов. pip не создаёт файл блокировки (lockfile) с полным деревом зависимостей; эту задачу решают pip-tools, Poetry, PDM или [uv](https://llmdocs.ru/wiki/uv.md). ## Публикация на PyPI Пакет собирается командой `python -m build` (появляются sdist и wheel) и загружается утилитой `twine` или средствами менеджера проекта. С 2023 года PyPI поддерживает **доверенную публикацию** (Trusted Publishing): конвейер CI, например [GitHub Actions](https://llmdocs.ru/wiki/github-actions.md), получает кратковременный токен по OpenID Connect, и долгоживущие пароли API хранить не нужно.[5] С 1 января 2024 года двухфакторная аутентификация обязательна для всех, кто публикует пакеты. ## Безопасность Любой может опубликовать пакет на PyPI, поэтому существуют риски цепочки поставок: - **тайпсквоттинг** — пакеты с именами, похожими на популярные (`reqeusts` вместо `requests`), содержащие вредоносный код; - **выполнение кода при установке** — сборка sdist запускает произвольный код, поэтому предпочтительнее wheel; - **подмена зависимостей** — внутренний пакет компании перекрывается одноимённым публичным. Меры: проверять имена пакетов, фиксировать версии и хеши, использовать частные индексы и зеркала (`--index-url`), сканировать зависимости на известные уязвимости. ## Альтернативы [uv](https://llmdocs.ru/wiki/uv.md) совместим с интерфейсом pip (`uv pip install`) и работает в разы быстрее; Poetry и PDM управляют зависимостями проекта целиком; conda использует собственные каналы пакетов. Аналоги в других языках — npm (см. [npm](https://llmdocs.ru/wiki/npm.md)), Cargo (см. [Cargo и crates.io](https://llmdocs.ru/wiki/cargo.md)), Go-модули. ## См. также - [Виртуальные окружения (venv)](https://llmdocs.ru/wiki/venv.md) - [pyproject.toml](https://llmdocs.ru/wiki/pyproject-toml.md) - [uv (менеджер пакетов)](https://llmdocs.ru/wiki/uv.md) - [Семантическое версионирование](https://llmdocs.ru/wiki/semver.md) ## Источники 1. [pip documentation](https://pip.pypa.io/en/stable/) 2. [PEP 453 — Explicit bootstrapping of pip in Python installations](https://peps.python.org/pep-0453/) 3. [PEP 427 — The Wheel Binary Package Format](https://peps.python.org/pep-0427/) 4. [pip — Dependency Resolution](https://pip.pypa.io/en/stable/topics/dependency-resolution/) 5. [PyPI Docs — Trusted Publishers](https://docs.pypi.org/trusted-publishers/) 6. [Python Packaging User Guide](https://packaging.python.org/) --- # pyproject.toml > Стандартный файл конфигурации Python-проекта — система сборки, метаданные пакета, зависимости и настройки инструментов. Источник: https://llmdocs.ru/wiki/pyproject-toml/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: файл конфигурации проекта - **Формат**: TOML - **Язык**: Python - **Стандарты**: PEP 518 (2016), PEP 517, PEP 621 (2020), PEP 735 - **Основные таблицы**: `[build-system]`, `[project]`, `[dependency-groups]`, `[tool.*]` - **Бэкенды сборки**: setuptools, hatchling, flit-core, pdm-backend, poetry-core, maturin - **Спецификация**: [packaging.python.org](https://packaging.python.org/en/latest/specifications/pyproject-toml/) **pyproject.toml** — стандартный файл конфигурации проекта на [Python](https://llmdocs.ru/wiki/python.md), размещаемый в корне репозитория. В нём указываются система сборки пакета, его метаданные (имя, версия, зависимости, точки входа) и настройки инструментов разработки — линтеров, форматировщиков, тестовых фреймворков. Файл пришёл на смену разрозненным `setup.py`, `setup.cfg`, `requirements.txt` и множеству отдельных конфигов, объединив их в одном месте. ## История Долгое время пакет Python описывался исполняемым скриптом `setup.py`. Чтобы узнать хотя бы зависимости, нужно было запустить произвольный код, а сам скрипт требовал заранее установленного setuptools. Стандартизация шла в несколько шагов: | PEP | Год | Что добавил | |---|---|---| | PEP 518 | 2016 | файл `pyproject.toml` и таблицу `[build-system]`: какие пакеты нужны для сборки[2] | | PEP 517 | 2017 | единый интерфейс между установщиком и **бэкендом сборки**[3] | | PEP 621 | 2020 | таблицу `[project]` со стандартными метаданными[4] | | PEP 660 | 2021 | установку в режиме разработки (editable) через бэкенд | | PEP 735 | 2024 | `[dependency-groups]` — группы зависимостей для разработки, не попадающие в пакет[5] | Формат TOML выбран за простоту и однозначность; с Python 3.11 его чтение встроено в стандартную библиотеку (модуль `tomllib`).[7] ## Структура ```toml [build-system] requires = ["hatchling"] build-backend = "hatchling.build" [project] name = "weather-cli" version = "0.3.0" description = "Прогноз погоды в терминале" readme = "README.md" requires-python = ">=3.11" license = "MIT" authors = [{ name = "Иван Петров" }] dependencies = [ "httpx>=0.27", "rich>=13", ] [project.optional-dependencies] yaml = ["pyyaml>=6"] [project.scripts] weather = "weather_cli.main:run" [dependency-groups] dev = ["pytest>=8", "ruff"] [tool.ruff] line-length = 100 [tool.pytest.ini_options] testpaths = ["tests"] ``` ## Таблицы **`[build-system]`** сообщает установщику, какие пакеты поставить во временное окружение и какой бэкенд вызвать, чтобы собрать wheel или sdist. Благодаря этому [pip](https://llmdocs.ru/wiki/pip-pypi.md) может собрать любой проект, не зная, каким инструментом он сделан. **`[project]`** — стандартные метаданные:[1] - `name`, `version` (или `dynamic = ["version"]`, если версию вычисляет бэкенд, например из тега [Git](https://llmdocs.ru/wiki/git.md)); - `dependencies` — зависимости в формате спецификаторов версий; - `optional-dependencies` — «экстра», устанавливаемые как `pip install weather-cli[yaml]`; - `requires-python` — поддерживаемые версии интерпретатора; - `scripts` — консольные команды, создаваемые при установке; - `license` — выражение SPDX (см. [Лицензии ПО (MIT, GPL, Apache, CC)](https://llmdocs.ru/wiki/software-licenses.md)). **`[dependency-groups]`** хранит зависимости, нужные только при разработке (тесты, линтеры, документация), — они не публикуются вместе с пакетом. **`[tool.<имя>]`** — пространство для настроек сторонних инструментов: [Ruff](https://llmdocs.ru/wiki/ruff.md), [pytest](https://llmdocs.ru/wiki/pytest.md), [mypy](https://llmdocs.ru/wiki/mypy-pyright.md), coverage, Black и других. Каждый инструмент читает только свою таблицу. ## Бэкенды сборки | Бэкенд | Особенность | |---|---| | setuptools | исторический стандарт, поддерживает расширения на C | | hatchling | современный, по умолчанию в Hatch | | flit-core | минималистичный, для чистого Python | | pdm-backend | бэкенд менеджера PDM | | poetry-core | бэкенд Poetry | | maturin | сборка расширений на Rust (PyO3) | Менеджеры проектов — Poetry, PDM, Hatch, [uv](https://llmdocs.ru/wiki/uv.md) — используют `pyproject.toml` как основной файл. Точные версии всего дерева зависимостей при этом хранятся отдельно, в файле блокировки (`uv.lock`, `poetry.lock`), который самим `pyproject.toml` не заменяется. ## Типичные ошибки - Указание зависимостей одновременно в `pyproject.toml` и `requirements.txt` с расхождениями. - Отсутствие таблицы `[build-system]` — тогда инструменты по умолчанию предполагают setuptools. - Жёсткая фиксация версий (`==`) в `dependencies` библиотеки: это мешает пользователям совмещать её с другими пакетами. Фиксируют версии приложения в файле блокировки, а в библиотеке задают диапазоны. ## Аналоги Похожую роль играют `package.json` в мире [Node.js](https://llmdocs.ru/wiki/nodejs.md), `Cargo.toml` в Rust (см. [Cargo и crates.io](https://llmdocs.ru/wiki/cargo.md)) и `go.mod` в Go (см. [Go-модули (go.mod)](https://llmdocs.ru/wiki/go-modules.md)). ## См. также - [pip и PyPI](https://llmdocs.ru/wiki/pip-pypi.md) - [uv (менеджер пакетов)](https://llmdocs.ru/wiki/uv.md) - [Виртуальные окружения (venv)](https://llmdocs.ru/wiki/venv.md) - [PEP](https://llmdocs.ru/wiki/pep.md) ## Источники 1. [pyproject.toml specification — Python Packaging User Guide](https://packaging.python.org/en/latest/specifications/pyproject-toml/) 2. [PEP 518 — Specifying Minimum Build System Requirements](https://peps.python.org/pep-0518/) 3. [PEP 517 — A build-system independent format for source trees](https://peps.python.org/pep-0517/) 4. [PEP 621 — Storing project metadata in pyproject.toml](https://peps.python.org/pep-0621/) 5. [PEP 735 — Dependency Groups in pyproject.toml](https://peps.python.org/pep-0735/) 6. [TOML specification](https://toml.io/en/) 7. [tomllib — Parse TOML files](https://docs.python.org/3/library/tomllib.html) --- # pytest > Самый популярный фреймворк тестирования для Python — простые тесты на обычных assert, фикстуры, параметризация и большая экосистема плагинов. Источник: https://llmdocs.ru/wiki/pytest/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: фреймворк тестирования - **Автор**: Хольгер Крекель - **Появился**: 2004 (как py.test) - **Лицензия**: MIT - **Ключевые возможности**: assert с подробными отчётами, фикстуры, параметризация, маркеры - **Плагины**: pytest-cov, pytest-xdist, pytest-asyncio, pytest-mock, hypothesis - **Альтернатива**: unittest (стандартная библиотека) **pytest** — фреймворк для написания и запуска тестов на [Python](https://llmdocs.ru/wiki/python.md), самый популярный в экосистеме. Тест в pytest — обычная функция, имя которой начинается с `test_`, а проверки — обычный оператор `assert`; при падении pytest показывает подробности: какие значения сравнивались и чем они отличаются. Мощь фреймворка — в **фикстурах** для подготовки окружения, **параметризации** для прогона одного теста на многих наборах данных и сотнях плагинов. pytest используют и для модульных тестов, и для интеграционных, и для проверки API, баз данных, веб-интерфейсов; он запускает и тесты, написанные на стандартном `unittest`. ## История Хольгер Крекель начал разработку в 2004 году в рамках проекта PyPy под названием `py.test` — частью библиотеки `py`. Позже pytest выделился в самостоятельный проект, команда запуска стала называться `pytest`, а сам фреймворк вытеснил `unittest` в большинстве новых проектов. Сейчас pytest развивает сообщество под организацией pytest-dev, распространяется под лицензией MIT.[1] ## Первые тесты ```python # test_pricing.py import pytest from shop.pricing import apply_discount def test_discount_reduces_price(): assert apply_discount(1000, percent=10) == 900 def test_negative_percent_rejected(): with pytest.raises(ValueError, match="percent"): apply_discount(1000, percent=-5) ``` ```bash uv add --dev pytest uv run pytest # найдёт файлы test_*.py и функции test_* uv run pytest -x -q # остановиться на первой ошибке, краткий вывод uv run pytest -k discount # только тесты, в имени которых есть «discount» uv run pytest --lf # перезапустить упавшие в прошлый раз ``` pytest переписывает `assert` при импорте тестов, поэтому сообщение об ошибке показывает обе стороны сравнения, а для списков, словарей и строк — построчную разницу. Не нужно запоминать десятки методов вроде `assertEqual`, `assertIn`, `assertDictEqual`, как в unittest.[4][5] ## Фикстуры Фикстура — функция, которая готовит ресурс для теста и при необходимости убирает его после. Тест получает фикстуру, просто указав её имя в параметрах:[2] ```python import pytest @pytest.fixture def db(tmp_path): conn = connect(tmp_path / "test.sqlite") # tmp_path — встроенная фикстура: временный каталог conn.migrate() yield conn # всё до yield — подготовка, после — очистка conn.close() @pytest.fixture def user(db): # фикстуры могут зависеть от других фикстур return db.create_user(email="alice@example.com") def test_user_can_place_order(db, user): order = db.create_order(user_id=user.id, total=500) assert order.status == "new" ``` - **Область действия** (`scope="function" | "module" | "session"`) задаёт, как часто создаётся фикстура: например, одна база данных на весь прогон и транзакция с откатом на каждый тест. - **`conftest.py`** — файл с общими фикстурами для каталога и вложенных каталогов, без импортов в тестах. - **Встроенные фикстуры**: `tmp_path` (временный каталог), `monkeypatch` (подмена атрибутов и [переменных окружения](https://llmdocs.ru/wiki/environment-variables.md)), `capsys` (перехват вывода), `caplog` (логи). ## Параметризация ```python @pytest.mark.parametrize( ("price", "percent", "expected"), [ (1000, 0, 1000), (1000, 10, 900), (999, 33, 669), pytest.param(1000, 100, 0, id="full-discount"), ], ) def test_apply_discount(price, percent, expected): assert apply_discount(price, percent=percent) == expected ``` Каждый набор становится отдельным тестом с собственным именем в отчёте, поэтому видно, какие именно случаи упали.[3] ## Маркеры и конфигурация Маркеры помечают тесты: `@pytest.mark.skip`, `@pytest.mark.skipif(sys.platform == "win32", reason=...)`, `@pytest.mark.xfail` для известных ошибок и пользовательские метки вроде `slow` или `integration`, чтобы запускать группы тестов (`pytest -m "not slow"`). Настройки хранятся в [pyproject.toml](https://llmdocs.ru/wiki/pyproject-toml.md): ```toml [tool.pytest.ini_options] testpaths = ["tests"] addopts = "-ra --strict-markers" markers = ["slow: долгие тесты", "integration: требуют внешних сервисов"] ``` ## Плагины | Плагин | Назначение | |---|---| | pytest-cov | покрытие кода тестами | | pytest-xdist | параллельный запуск на нескольких ядрах (`-n auto`)[6] | | pytest-asyncio, anyio | тесты асинхронного кода ([asyncio](https://llmdocs.ru/wiki/asyncio.md)) | | pytest-mock | удобная обёртка над `unittest.mock` | | hypothesis | тестирование на основе свойств: генерирует сотни случайных входов и находит граничные случаи | | pytest-django, pytest-httpx | интеграция с фреймворками и HTTP-клиентами | ## Практика - Тесты запускаются в [CI/CD](https://llmdocs.ru/wiki/ci-cd.md) при каждом pull request; быстрые модульные тесты — отдельно от медленных интеграционных. - Один тест — одно поведение; имя теста описывает ожидаемый результат. - Внешние сервисы в модульных тестах подменяют, а интеграционные тесты гоняют против настоящих зависимостей, например в контейнерах [Docker](https://llmdocs.ru/wiki/docker.md). - Покрытие — ориентир, а не цель: 100% строк не гарантируют проверку важных случаев. ## См. также - [Python](https://llmdocs.ru/wiki/python.md) - [CI/CD](https://llmdocs.ru/wiki/ci-cd.md) - [pyproject.toml](https://llmdocs.ru/wiki/pyproject-toml.md) - [Декораторы](https://llmdocs.ru/wiki/decorators.md) - [Ruff](https://llmdocs.ru/wiki/ruff.md) ## Источники 1. [pytest — документация](https://docs.pytest.org/en/stable/) 2. [pytest — How to use fixtures](https://docs.pytest.org/en/stable/how-to/fixtures.html) 3. [pytest — How to parametrize fixtures and test functions](https://docs.pytest.org/en/stable/how-to/parametrize.html) 4. [pytest — How to write and report assertions in tests](https://docs.pytest.org/en/stable/how-to/assert.html) 5. [Python — unittest](https://docs.python.org/3/library/unittest.html) 6. [pytest-xdist — документация](https://pytest-xdist.readthedocs.io/) --- # Python > Высокоуровневый язык программирования общего назначения с динамической типизацией и упором на читаемость кода. Источник: https://llmdocs.ru/wiki/python/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Класс языка**: мультипарадигменный (объектно-ориентированный, императивный, функциональный) - **Появился в**: 1991 - **Автор**: Гвидо ван Россум - **Разработчик**: Python Software Foundation - **Расширение файлов**: `.py`, `.pyi`, `.pyc` - **Выпуск версий**: ежегодно, в октябре (PEP 602) - **Типизация**: динамическая, строгая, утиная; необязательные аннотации типов - **Основная реализация**: CPython - **Другие реализации**: PyPy, MicroPython, GraalPy, Jython - **Лицензия**: PSF License - **Сайт**: [python.org](https://www.python.org/) **Python** (произносится «пайтон», в русской среде часто «питон») — высокоуровневый язык программирования общего назначения с динамической типизацией и автоматическим управлением памятью. Язык ориентирован на читаемость кода: блоки выделяются отступами, а синтаксис намеренно минималистичен. Python применяется в веб-разработке, автоматизации, анализе данных, [машинном обучении](https://llmdocs.ru/wiki/machine-learning.md) и научных вычислениях и стабильно входит в число самых популярных языков мира. ## История Работу над языком Гвидо ван Россум начал в конце 1989 года в нидерландском исследовательском институте CWI как над преемником учебного языка ABC. Первая публичная версия 0.9.0 вышла в феврале 1991 года.[2] Название взято не от змеи, а от британского комедийного шоу «Летающий цирк Монти Пайтона». Ключевые вехи: | Год | Событие | |---|---| | 1994 | Python 1.0 | | 2000 | Python 2.0: сборщик циклических ссылок, списковые включения | | 2001 | основана некоммерческая Python Software Foundation (PSF) | | 2008 | Python 3.0 — несовместимая с 2.x версия, исправившая ранние решения (строки Unicode, `print()` как функция) | | 2019 | управление передано выборному руководящему совету из пяти человек (PEP 13)[4] | | 2020 | 1 января прекращена поддержка Python 2.7 | До 2018 года ван Россум носил шуточный титул «великодушного пожизненного диктатора» (BDFL) и принимал окончательные решения по развитию языка. Переход на ветку 3.x растянулся более чем на десятилетие и стал хрестоматийным примером того, насколько дорого обходится нарушение обратной совместимости. С версии 3.9 выпуски выходят ежегодно в октябре, каждая ветка получает около двух лет исправлений ошибок и ещё три года — исправлений безопасности.[3] ## Особенности языка Философию языка кратко описывает «Дзен Python» (PEP 20): «явное лучше неявного», «простое лучше сложного», «читаемость имеет значение».[7] Его можно вывести командой `import this`. - **Отступы как синтаксис.** Вложенность блоков задаётся отступом, а не фигурными скобками; стиль оформления закреплён в [PEP 8](https://llmdocs.ru/wiki/pep-8.md). - **Динамическая строгая типизация.** Тип связан со значением, а не с переменной, но неявных преобразований вроде `"1" + 1` язык не делает. С версии 3.5 поддерживаются аннотации типов, которые проверяют внешние анализаторы ([mypy и pyright](https://llmdocs.ru/wiki/mypy-pyright.md)). - **«Батарейки в комплекте».** Обширная стандартная библиотека покрывает работу с файлами, сетью, JSON, регулярными выражениями, многопоточностью и асинхронностью ([asyncio](https://llmdocs.ru/wiki/asyncio.md)). - **Всё — объект.** Функции, классы и модули являются объектами первого класса, что упрощает [декораторы](https://llmdocs.ru/wiki/decorators.md) и метапрограммирование. - **Итераторы и генераторы** — ленивые последовательности, см. [Генераторы и итераторы](https://llmdocs.ru/wiki/generators-iterators.md). Пример: ```python from collections import Counter def top_words(text: str, n: int = 3) -> list[tuple[str, int]]: words = (w.strip(".,!?").lower() for w in text.split()) return Counter(w for w in words if w).most_common(n) print(top_words("Явное лучше неявного. Простое лучше сложного.")) # [('лучше', 2), ('явное', 1), ('неявного', 1)] ``` ## Реализации и производительность Эталонная реализация — [CPython](https://llmdocs.ru/wiki/cpython.md), написанная на C: она компилирует исходный код в байт-код и исполняет его на виртуальной машине. Исторически её главным ограничением была глобальная блокировка интерпретатора (GIL), не позволяющая потокам одновременно исполнять Python-код на разных ядрах (см. [GIL и free-threading (PEP 703)](https://llmdocs.ru/wiki/gil-free-threading.md)). В последних версиях производительность заметно выросла: проект Faster CPython ускорил интерпретатор начиная с 3.11, в 3.13 появились экспериментальные JIT-компилятор и сборка без GIL,[5] а в 3.14 сборка без GIL получила статус официально поддерживаемой.[6] Альтернативные реализации: **PyPy** (трассирующий JIT, часто в разы быстрее на «чистом» Python), **MicroPython** (микроконтроллеры), **GraalPy** (JVM/GraalVM). ## Экосистема Пакеты публикуются в каталоге PyPI и устанавливаются через [pip](https://llmdocs.ru/wiki/pip-pypi.md); проекты изолируют зависимости в [виртуальных окружениях](https://llmdocs.ru/wiki/venv.md), а метаданные описывают в [pyproject.toml](https://llmdocs.ru/wiki/pyproject-toml.md). Набирают популярность быстрые инструменты на Rust: менеджер пакетов [uv](https://llmdocs.ru/wiki/uv.md) и линтер [Ruff](https://llmdocs.ru/wiki/ruff.md). Основные области и библиотеки: - данные и наука: [NumPy](https://llmdocs.ru/wiki/numpy.md), [pandas](https://llmdocs.ru/wiki/pandas.md), [Jupyter](https://llmdocs.ru/wiki/jupyter.md); - машинное обучение: [PyTorch](https://llmdocs.ru/wiki/pytorch.md), [scikit-learn](https://llmdocs.ru/wiki/scikit-learn.md); - веб: [Django](https://llmdocs.ru/wiki/django.md), [Flask](https://llmdocs.ru/wiki/flask.md), [FastAPI](https://llmdocs.ru/wiki/fastapi.md); - тестирование: [pytest](https://llmdocs.ru/wiki/pytest.md). Изменения в языке проходят через процедуру [PEP](https://llmdocs.ru/wiki/pep.md) — документы с обоснованием, обсуждением и решением руководящего совета. ## Критика Чаще всего Python критикуют за скорость исполнения «чистого» кода (на порядок и более ниже компилируемых языков вроде [Go](https://llmdocs.ru/wiki/go.md) и [Rust](https://llmdocs.ru/wiki/rust.md)), за долгое отсутствие настоящей многопоточности из-за GIL и за исторически запутанную систему упаковки. На практике тяжёлые вычисления выносят в библиотеки на C, C++ или Rust, а Python остаётся «клеем» между ними. ## См. также - [CPython](https://llmdocs.ru/wiki/cpython.md) - [asyncio](https://llmdocs.ru/wiki/asyncio.md) - [PEP 8](https://llmdocs.ru/wiki/pep-8.md) - [Компилятор и интерпретатор](https://llmdocs.ru/wiki/compiler-interpreter.md) ## Источники 1. [The Python Tutorial](https://docs.python.org/3/tutorial/) 2. [History and License — Python documentation](https://docs.python.org/3/license.html) 3. [PEP 602 — Annual Release Cycle for Python](https://peps.python.org/pep-0602/) 4. [PEP 13 — Python Language Governance](https://peps.python.org/pep-0013/) 5. [PEP 703 — Making the Global Interpreter Lock Optional in CPython](https://peps.python.org/pep-0703/) 6. [What's New in Python 3.14](https://docs.python.org/3/whatsnew/3.14.html) 7. [PEP 20 — The Zen of Python](https://peps.python.org/pep-0020/) --- # Ruff > Чрезвычайно быстрый линтер и форматер кода для Python, написанный на Rust компанией Astral; заменяет Flake8, isort, pyupgrade, Black и десятки плагинов одним инструментом. Источник: https://llmdocs.ru/wiki/ruff/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: линтер и форматер кода Python - **Автор**: Чарли Марш (Astral) - **Первый выпуск**: 2022 - **Язык**: Rust - **Лицензия**: MIT - **Правил**: более 800 - **Заменяет**: Flake8 и плагины, isort, pyupgrade, pydocstyle, autoflake, Black - **Сайт**: docs.astral.sh/ruff **Ruff** — линтер и форматер кода для [Python](https://llmdocs.ru/wiki/python.md), написанный на [Rust](https://llmdocs.ru/wiki/rust.md). Линтер находит ошибки и подозрительные места — неиспользуемые импорты, необъявленные имена, изменяемые значения по умолчанию, устаревший синтаксис, — а форматер приводит код к единому стилю. Главная особенность Ruff — скорость: он работает в десятки и сотни раз быстрее инструментов на Python, проверяя крупный проект за доли секунды, поэтому его можно запускать при каждом сохранении файла.[1] Ruff объединяет в одном инструменте функции целого набора утилит: Flake8 с плагинами, isort, pyupgrade, pydocstyle, autoflake и форматер Black. Его используют FastAPI, pandas, Apache Airflow и тысячи других проектов. ## История Чарли Марш выпустил первую версию в августе 2022 года как эксперимент: можно ли переписать линтер Python на Rust и сделать его на порядки быстрее. Проект быстро набрал популярность, и Марш основал компанию **Astral**, которая развивает инструменты для Python на Rust: в 2023 году в Ruff появился форматер, совместимый с Black, в 2024 году Astral выпустила менеджер пакетов [uv](https://llmdocs.ru/wiki/uv.md), а в 2025 году — анализатор типов ty.[5] ## Линтер ```bash uv add --dev ruff uv run ruff check . # найти проблемы uv run ruff check --fix . # исправить то, что можно исправить автоматически uv run ruff check --watch # проверять при каждом изменении ``` ```text app.py:1:8: F401 [*] `os` imported but unused app.py:5:20: B006 Do not use mutable data structures for argument defaults app.py:9:5: UP035 [*] `typing.List` is deprecated, use `list` instead Found 3 errors. [*] 2 fixable with the `--fix` option. ``` Правила сгруппированы по префиксам, повторяющим исходные инструменты:[2] | Префикс | Источник | Что проверяет | |---|---|---| | `F` | Pyflakes | неиспользуемые импорты и переменные, необъявленные имена | | `E`, `W` | pycodestyle | стиль по [PEP 8](https://llmdocs.ru/wiki/pep-8.md) | | `I` | isort | порядок импортов | | `UP` | pyupgrade | устаревший синтаксис для выбранной версии Python | | `B` | flake8-bugbear | вероятные ошибки и плохие практики | | `SIM` | flake8-simplify | упрощение конструкций | | `S` | flake8-bandit | проблемы безопасности | | `N`, `D` | pep8-naming, pydocstyle | имена и строки документации | | `RUF` | собственные правила Ruff | разное | По умолчанию включены только `E` (частично) и `F`; остальные наборы подключают явно, постепенно расширяя список. ## Форматер ```bash uv run ruff format . # отформатировать uv run ruff format --check . # только проверить (для CI) ``` Форматер стремится давать результат, практически идентичный Black, так что переход не меняет историю кода массово.[3] Как и Black, он почти не настраивается — это сознательное решение: споры о стиле заканчиваются, код у всех выглядит одинаково. ## Настройка Конфигурация хранится в [pyproject.toml](https://llmdocs.ru/wiki/pyproject-toml.md) или в `ruff.toml`:[4] ```toml [tool.ruff] line-length = 100 target-version = "py313" extend-exclude = ["migrations"] [tool.ruff.lint] select = ["E", "F", "I", "UP", "B", "SIM", "RUF"] ignore = ["E501"] # длину строк контролирует форматер [tool.ruff.lint.per-file-ignores] "tests/**" = ["S101"] # assert в тестах разрешён [tool.ruff.format] quote-style = "double" ``` Отдельную строку можно исключить из проверки комментарием `# noqa: B006`, а правило `RUF100` подскажет, какие подавления уже не нужны. ## Интеграция - **Редакторы** — официальное расширение для VS Code и языковой сервер для других редакторов: подсветка и исправления при наборе. - **pre-commit** — хук `ruff-pre-commit` проверяет и форматирует изменённые файлы перед коммитом (см. [Git-хуки](https://llmdocs.ru/wiki/git-hooks.md)).[6] - **CI** — `ruff check` и `ruff format --check` в конвейере [CI/CD](https://llmdocs.ru/wiki/ci-cd.md) за секунды; есть готовое действие для [GitHub Actions](https://llmdocs.ru/wiki/github-actions.md). ```yaml # .pre-commit-config.yaml repos: - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.14.0 hooks: - id: ruff-check args: [--fix] - id: ruff-format ``` ## Что Ruff не делает Ruff не проверяет типы — для этого нужны анализаторы вроде [mypy и pyright](https://llmdocs.ru/wiki/mypy-pyright.md) или ty — и не заменяет тесты ([pytest](https://llmdocs.ru/wiki/pytest.md)). Он также не реализует некоторые сложные проверки Pylint, требующие анализа всей программы. Типичный набор инструментов современного проекта на Python: uv для зависимостей, Ruff для линтинга и форматирования, анализатор типов и pytest. ## См. также - [PEP 8](https://llmdocs.ru/wiki/pep-8.md) - [uv (менеджер пакетов)](https://llmdocs.ru/wiki/uv.md) - [mypy и pyright](https://llmdocs.ru/wiki/mypy-pyright.md) - [pyproject.toml](https://llmdocs.ru/wiki/pyproject-toml.md) - [pytest](https://llmdocs.ru/wiki/pytest.md) ## Источники 1. [Ruff — документация](https://docs.astral.sh/ruff/) 2. [Ruff — Rules](https://docs.astral.sh/ruff/rules/) 3. [Ruff — The Ruff Formatter](https://docs.astral.sh/ruff/formatter/) 4. [Ruff — Configuring Ruff](https://docs.astral.sh/ruff/configuration/) 5. [astral-sh/ruff — GitHub](https://github.com/astral-sh/ruff) 6. [astral-sh/ruff-pre-commit](https://github.com/astral-sh/ruff-pre-commit) --- # Типизация в Python (type hints, PEP 484) > Необязательные аннотации типов в Python, введённые PEP 484 в версии 3.5; не влияют на выполнение, но позволяют статическим анализаторам находить ошибки и улучшают подсказки в редакторе. Источник: https://llmdocs.ru/wiki/type-hints/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Основа**: PEP 484 (2014), Python 3.5 - **Авторы PEP 484**: Гвидо ван Россум, Юкка Лехтосало, Лукаш Ланга - **Синтаксис аннотаций**: PEP 3107 (Python 3.0) - **Подход**: постепенная (gradual) типизация - **Модуль**: typing - **Проверка**: mypy, pyright, ty, Pyrefly - **Проверка во время выполнения**: Pydantic, beartype **Типизация в Python** — система необязательных **аннотаций типов** (*type hints*), с помощью которых программист указывает, какие типы ожидают функции и хранят переменные. [Python](https://llmdocs.ru/wiki/python.md) остаётся языком с динамической типизацией: интерпретатор аннотации не проверяет и выполняет код так же, как без них. Зато статические анализаторы — [mypy, pyright](https://llmdocs.ru/wiki/mypy-pyright.md) и другие — находят по ним ошибки до запуска, а редакторы дают точное автодополнение и навигацию по коду. Основу системы заложил **PEP 484** (2014), вошедший в Python 3.5.[1] Подход называют **постепенной типизацией**: аннотации можно добавлять по частям, начиная с самых важных модулей, а неаннотированный код просто не проверяется. ## История Синтаксис аннотаций функций появился ещё в Python 3.0 (PEP 3107, 2006), но без определённого смысла. Юкка Лехтосало начал разрабатывать статический анализатор mypy в рамках диссертации в 2012 году; его идеи легли в основу PEP 484, написанного вместе с Гвидо ван Россумом и Лукашем Лангой. Дальше систему развивали десятки PEP (см. [PEP](https://llmdocs.ru/wiki/pep.md)): | Версия | Изменение | |---|---| | 3.5 | PEP 484: модуль `typing`, обобщённые типы, `Optional`, `Union` | | 3.6 | PEP 526: аннотации переменных `x: int = 0` | | 3.8 | PEP 544: протоколы (структурная типизация), `Literal`, `TypedDict`, `Final` | | 3.9 | PEP 585: `list[int]` вместо `typing.List[int]` | | 3.10 | PEP 604: `int \| None` вместо `Optional[int]` | | 3.12 | PEP 695: синтаксис параметров типов `def f[T](x: T) -> T` и оператор `type`[4] | | 3.14 | PEP 649: отложенное вычисление аннотаций[7] | Правила, общие для всех анализаторов, собраны в спецификацию системы типов Python.[3] ## Синтаксис ```python from collections.abc import Iterable, Callable from typing import Literal, TypedDict, Protocol def greet(name: str, times: int = 1) -> str: return ", ".join([f"Привет, {name}"] * times) def first_or_none(items: list[str]) -> str | None: # значение может отсутствовать return items[0] if items else None def total(prices: Iterable[float]) -> float: # принимает любой итерируемый объект return sum(prices) Mode = Literal["r", "w", "a"] # только эти строки class User(TypedDict): # словарь с известными ключами id: int email: str def apply[T](func: Callable[[T], T], value: T) -> T: # обобщённая функция (3.12+) return func(value) class SupportsClose(Protocol): # структурный тип: «что угодно с close()» def close(self) -> None: ... ``` Протоколы описывают «утиную типизацию» статически: класс подходит под протокол, если у него есть нужные методы, без явного наследования.[5] Аннотировать стоит прежде всего публичные функции — параметры и возвращаемые значения; типы локальных переменных анализатор обычно выводит сам. ## Проверка ```bash uv add --dev mypy uv run mypy src/ # статическая проверка ``` ```python def double(x: int) -> int: return x * 2 double("5") # mypy: Argument 1 to "double" has incompatible type "str"; expected "int" ``` Без анализатора этот вызов выполнится и вернёт `"55"` — ошибку найдёт только тест или пользователь. Популярные анализаторы: - **mypy** — эталонная реализация, развивается вместе со стандартом;[6] - **pyright** от Microsoft — быстрый, лежит в основе Pylance в VS Code; - **ty** от Astral (авторов [Ruff](https://llmdocs.ru/wiki/ruff.md) и [uv](https://llmdocs.ru/wiki/uv.md)) и **Pyrefly** от Meta — новые анализаторы на Rust, ориентированные на скорость. Анализатор запускают в редакторе и в [CI/CD](https://llmdocs.ru/wiki/ci-cd.md), а строгость наращивают постепенно — например, включая строгий режим для новых модулей. ## Типы во время выполнения Аннотации доступны программе во время выполнения, и библиотеки используют их для поведения: [dataclasses](https://llmdocs.ru/wiki/dataclasses-pydantic.md) генерируют конструкторы по аннотациям полей, Pydantic проверяет и преобразует входные данные, [FastAPI](https://llmdocs.ru/wiki/fastapi.md) строит по типам параметров валидацию запросов и описание OpenAPI. ```python from pydantic import BaseModel class Order(BaseModel): id: int amount: float status: Literal["new", "paid"] = "new" Order.model_validate({"id": "42", "amount": "9.5"}) # строки приведены к int и float ``` ## Практические советы - Используйте современный синтаксис: `list[int]`, `X | None`, абстрактные типы из `collections.abc` для параметров. - Принимайте общие типы (`Iterable`, `Mapping`), возвращайте конкретные (`list`, `dict`). - Избегайте `Any` — он отключает проверку; если тип действительно неизвестен, лучше `object`. - Для сторонних библиотек без аннотаций ставьте пакеты-заглушки `types-*` из репозитория typeshed. - Аннотации — ещё и документация: код с типами проще читать людям и языковым моделям. Полный справочник — документация модуля `typing`.[2] ## См. также - [mypy и pyright](https://llmdocs.ru/wiki/mypy-pyright.md) - [Dataclasses и Pydantic](https://llmdocs.ru/wiki/dataclasses-pydantic.md) - [PEP](https://llmdocs.ru/wiki/pep.md) - [FastAPI](https://llmdocs.ru/wiki/fastapi.md) - [Python](https://llmdocs.ru/wiki/python.md) ## Источники 1. [PEP 484 — Type Hints](https://peps.python.org/pep-0484/) 2. [Python — typing module documentation](https://docs.python.org/3/library/typing.html) 3. [Python typing specification](https://typing.python.org/en/latest/spec/index.html) 4. [PEP 695 — Type Parameter Syntax](https://peps.python.org/pep-0695/) 5. [PEP 544 — Protocols: Structural subtyping](https://peps.python.org/pep-0544/) 6. [mypy documentation](https://mypy.readthedocs.io/) 7. [PEP 649 — Deferred Evaluation Of Annotations Using Descriptors](https://peps.python.org/pep-0649/) --- # uv (менеджер пакетов) > Быстрый менеджер пакетов и проектов Python на Rust от компании Astral — замена pip, virtualenv, pip-tools, pipx и pyenv. Источник: https://llmdocs.ru/wiki/uv/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: менеджер пакетов и проектов - **Разработчик**: Astral (Чарли Марш) - **Первый выпуск**: февраль 2024 - **Написан на**: Rust - **Заменяет**: pip, pip-tools, virtualenv, pipx, pyenv, частично Poetry - **Файл блокировки**: `uv.lock` - **Лицензия**: MIT / Apache 2.0 - **Сайт**: [docs.astral.sh/uv](https://docs.astral.sh/uv/) **uv** — менеджер пакетов и проектов для [Python](https://llmdocs.ru/wiki/python.md), написанный на [Rust](https://llmdocs.ru/wiki/rust.md) компанией Astral. Он объединяет в одном исполняемом файле функции нескольких инструментов: установщика [pip](https://llmdocs.ru/wiki/pip-pypi.md), создания [виртуальных окружений](https://llmdocs.ru/wiki/venv.md), фиксации зависимостей, установки консольных утилит и управления версиями самого Python. Главная отличительная черта — скорость: по замерам разработчиков, установка зависимостей выполняется в 10–100 раз быстрее, чем у pip.[2] ## История Компания Astral, основанная Чарли Маршем, стала известна линтером [Ruff](https://llmdocs.ru/wiki/ruff.md), тоже написанным на Rust. В феврале 2024 года она выпустила uv как быструю замену `pip` и `pip-tools` с совместимым интерфейсом `uv pip`.[2] В августе того же года uv превратился в полноценный менеджер проектов: появились команды `uv init`, `uv add`, `uv run`, кроссплатформенный файл блокировки `uv.lock`, установка версий Python и запуск утилит через `uvx`.[3] Инструмент быстро набрал популярность и стал одним из самых используемых средств упаковки в экосистеме Python. ## Почему быстрый - реализация на Rust и параллельная загрузка и распаковка пакетов; - глобальный кеш, из которого файлы в окружения ставятся жёсткими ссылками или копированием с поддержкой copy-on-write — повторная установка почти мгновенна; - собственный резолвер зависимостей на основе алгоритма PubGrub; - чтение метаданных пакета без скачивания всего архива, где это позволяет индекс. ## Работа с проектом ```bash uv init myapp && cd myapp # создать проект с pyproject.toml uv add httpx "fastapi>=0.110" # добавить зависимости, обновить uv.lock uv add --dev pytest ruff # зависимости для разработки uv run python main.py # запустить в окружении проекта uv run pytest # то же для любой команды uv sync # привести .venv в точное соответствие с uv.lock uv lock --upgrade # обновить версии в файле блокировки ``` Зависимости описываются в стандартном [pyproject.toml](https://llmdocs.ru/wiki/pyproject-toml.md), а точные версии всего дерева — в `uv.lock`, который коммитят в репозиторий. Окружение `.venv` создаётся и синхронизируется автоматически при `uv run`, поэтому активировать его вручную не нужно. ## Другие режимы | Команда | Что заменяет | |---|---| | `uv pip install`, `uv pip compile` | pip и pip-tools, тот же формат `requirements.txt` | | `uv venv` | `python -m venv`, virtualenv | | `uv python install 3.13` | pyenv: скачивает готовые сборки Python | | `uvx ruff check .` / `uv tool install` | pipx: запуск и установка утилит в изолированных окружениях | | `uv run script.py` с метаданными в начале файла | запуск одиночных скриптов с зависимостями (PEP 723)[4] | Пример одиночного скрипта с зависимостями прямо в файле: ```python # /// script # requires-python = ">=3.12" # dependencies = ["httpx"] # /// import httpx print(httpx.get("https://pypi.org/simple/").status_code) ``` Команда `uv run script.py` сама создаст временное окружение, установит `httpx` и выполнит скрипт. ## Сравнение | | pip + venv | Poetry | uv | |---|---|---|---| | Скорость установки | базовая | сопоставима с pip | в разы выше | | Файл блокировки | нет (нужен pip-tools) | `poetry.lock` | `uv.lock` | | Управление версиями Python | нет | нет | есть | | Стандартный `pyproject.toml` | да | да (с 2.0) | да | | Зависимость от установленного Python | нужен | нужен | не нужен, один бинарный файл | ## Ограничения и критика uv развивает коммерческая компания, что вызывает у части сообщества вопросы о долгосрочной независимости инструмента; код при этом открыт под лицензиями MIT и Apache 2.0.[5] Поскольку uv заменяет сразу много инструментов, в старых проектах переход может потребовать переписать скрипты сборки и CI. Некоторые возможности pip поддерживаются не полностью, а поведение по умолчанию местами отличается — например, `uv pip install` по умолчанию требует виртуальное окружение. ## См. также - [pip и PyPI](https://llmdocs.ru/wiki/pip-pypi.md) - [Виртуальные окружения (venv)](https://llmdocs.ru/wiki/venv.md) - [pyproject.toml](https://llmdocs.ru/wiki/pyproject-toml.md) - [Ruff](https://llmdocs.ru/wiki/ruff.md) ## Источники 1. [uv documentation](https://docs.astral.sh/uv/) 2. [uv: Python packaging in Rust — Astral blog (2024)](https://astral.sh/blog/uv) 3. [uv: Unified Python packaging — Astral blog (2024)](https://astral.sh/blog/uv-unified-python-packaging) 4. [PEP 723 — Inline script metadata](https://peps.python.org/pep-0723/) 5. [astral-sh/uv — GitHub](https://github.com/astral-sh/uv) --- # Виртуальные окружения (venv) > Изолированные каталоги с собственным интерпретатором Python и набором пакетов, отдельные для каждого проекта. Источник: https://llmdocs.ru/wiki/venv/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: модуль стандартной библиотеки - **Язык**: Python - **Появился в**: Python 3.3 (2012) - **Стандарт**: PEP 405 - **Предшественник**: virtualenv (2007) - **Команда**: `python -m venv .venv` - **Альтернативы**: virtualenv, conda, uv, Poetry - **Документация**: [docs.python.org/3/library/venv](https://docs.python.org/3/library/venv.html) **Виртуальное окружение** в [Python](https://llmdocs.ru/wiki/python.md) — изолированный каталог со ссылкой на интерпретатор и собственным набором установленных пакетов. Каждый проект получает своё окружение, поэтому разные проекты могут использовать разные версии одних и тех же библиотек, не мешая друг другу и системному Python. Стандартный инструмент для их создания — модуль `venv` из стандартной библиотеки. ## Зачем нужны Без окружений все пакеты ставятся в одну общую папку `site-packages`. Это порождает типичные проблемы: - проекту A нужна библиотека версии 1.x, проекту B — 2.x, а установить можно только одну; - установка пакетов в системный Python может сломать утилиты операционной системы, написанные на Python; - нельзя точно воспроизвести набор зависимостей на другой машине; - для установки в системные каталоги нужны права администратора. Окружение решает всё это: пакеты ставятся внутрь каталога проекта, а удалить окружение можно простым удалением папки. ## История Изолированные окружения появились как сторонний инструмент **virtualenv**, созданный Яном Бикингом в 2007 году. Подход оказался настолько востребованным, что поддержку встроили в сам интерпретатор: PEP 405 добавил модуль `venv` в Python 3.3 (2012).[2] virtualenv продолжает развиваться как более быстрая и гибкая альтернатива.[5] В 2021 году PEP 668 ввёл понятие **внешне управляемого окружения**: дистрибутивы Linux могут пометить системный Python, и тогда `pip install` вне виртуального окружения завершается ошибкой `externally-managed-environment`.[3] Так поступают, например, Debian 12 и Ubuntu 23.04 и более новые версии. Это сделало виртуальные окружения фактически обязательными. ## Использование ```bash python3 -m venv .venv # создать окружение в папке .venv source .venv/bin/activate # активировать (Linux, macOS) .venv\Scripts\activate # активировать (Windows) python -m pip install requests # пакет ставится внутрь .venv deactivate # выйти из окружения ``` Активация лишь добавляет каталог `bin` окружения в начало переменной `PATH` (см. [Переменные окружения](https://llmdocs.ru/wiki/environment-variables.md)) и меняет приглашение оболочки. Её можно не выполнять, а вызывать интерпретатор напрямую: `.venv/bin/python script.py` — так обычно делают в скриптах, cron и юнитах [systemd](https://llmdocs.ru/wiki/systemd.md). Каталог `.venv` не добавляют в [Git](https://llmdocs.ru/wiki/git.md): вместо него в репозитории хранят список зависимостей (`requirements.txt`, [pyproject.toml](https://llmdocs.ru/wiki/pyproject-toml.md) или файл блокировки), по которому окружение можно пересоздать. ## Устройство Окружение — обычная папка:[1] ```text .venv/ ├── pyvenv.cfg # путь к базовому интерпретатору и версия ├── bin/ # python, pip, activate, консольные скрипты пакетов └── lib/python3.X/site-packages/ # установленные пакеты ``` Файл `pyvenv.cfg` сообщает интерпретатору при запуске, что он находится в окружении. Внутри окружения `sys.prefix` указывает на `.venv`, а `sys.base_prefix` — на базовую установку Python; по их различию код может определить, что работает в окружении. Сам интерпретатор не копируется, а подключается символической ссылкой, поэтому окружение привязано к конкретному базовому Python и при его обновлении или переносе папки может сломаться — тогда его пересоздают. Полезные параметры: `--system-site-packages` (видеть пакеты базовой установки), `--upgrade-deps` (обновить pip при создании), `--prompt` (имя в приглашении оболочки). ## Альтернативы | Инструмент | Особенность | |---|---| | `venv` | встроен в Python, без зависимостей | | virtualenv | быстрее, поддерживает больше версий Python | | [uv](https://llmdocs.ru/wiki/uv.md) | `uv venv` создаёт окружение за доли секунды, сам управляет версиями Python | | Poetry, PDM, Hatch | окружение создаётся автоматически вместе с управлением зависимостями проекта | | conda | окружения с пакетами не только Python (C-библиотеки, CUDA), популярна в науке о данных | Для полной изоляции от операционной системы, включая системные библиотеки, применяют контейнеры (см. [Docker](https://llmdocs.ru/wiki/docker.md)); внутри образа виртуальное окружение часто всё равно используют, чтобы отделить приложение от системного Python. ## См. также - [pip и PyPI](https://llmdocs.ru/wiki/pip-pypi.md) - [uv (менеджер пакетов)](https://llmdocs.ru/wiki/uv.md) - [pyproject.toml](https://llmdocs.ru/wiki/pyproject-toml.md) - [Docker](https://llmdocs.ru/wiki/docker.md) ## Источники 1. [venv — Creation of virtual environments](https://docs.python.org/3/library/venv.html) 2. [PEP 405 — Python Virtual Environments](https://peps.python.org/pep-0405/) 3. [PEP 668 — Marking Python base environments as externally managed](https://peps.python.org/pep-0668/) 4. [Python Packaging User Guide — Installing packages using pip and virtual environments](https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/) 5. [virtualenv documentation](https://virtualenv.pypa.io/) --- # Аутентификация и авторизация > Аутентификация — проверка того, кто перед системой; авторизация — решение, что ему разрешено. Две разные задачи безопасности, которые часто путают. Источник: https://llmdocs.ru/wiki/authn-authz/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Аутентификация (AuthN)**: кто вы? — пароль, ключ, токен, биометрия - **Авторизация (AuthZ)**: что вам можно? — роли, права, политики - **Факторы аутентификации**: знание, владение, свойство - **Модели доступа**: ACL, RBAC, ABAC, ReBAC - **Протоколы**: OAuth 2.0, OpenID Connect, SAML, WebAuthn (passkeys) - **Типичные ошибки**: нарушение контроля доступа — первое место OWASP Top 10 **Аутентификация** (англ. *authentication*, сокращённо AuthN) — проверка подлинности: действительно ли пользователь, сервис или устройство тот, за кого себя выдаёт. **Авторизация** (*authorization*, AuthZ) — решение о том, какие действия разрешены уже установленному субъекту. Аутентификация отвечает на вопрос «кто вы?», авторизация — «что вам можно?». Перед ними иногда выделяют **идентификацию** — заявление о том, кто вы (ввод логина). Аналогия: на проходной офиса охранник проверяет пропуск с фотографией — это аутентификация; то, что пропуск открывает только третий этаж, а серверную — нет, — авторизация. Путаница между понятиями закрепилась даже в протоколе [HTTP](https://llmdocs.ru/wiki/http.md): код `401 Unauthorized` на самом деле означает «не аутентифицирован», а отказ в правах — это `403 Forbidden` (см. [Коды состояния HTTP](https://llmdocs.ru/wiki/http-status-codes.md)). ## Аутентификация ### Факторы | Фактор | Примеры | |---|---| | Знание | пароль, PIN-код, ответ на секретный вопрос | | Владение | телефон с приложением-аутентификатором, аппаратный ключ, SIM-карта, закрытый ключ | | Свойство (биометрия) | отпечаток пальца, лицо, голос | Использование двух факторов разных типов — [двухфакторная аутентификация](https://llmdocs.ru/wiki/two-factor-auth.md) — резко снижает риск взлома при утечке пароля. ### Способы - **Пароли.** Хранятся на сервере только в виде медленного хеша с солью — bcrypt, scrypt, Argon2 (см. [Хранение паролей (bcrypt, Argon2)](https://llmdocs.ru/wiki/password-storage.md)). Современные рекомендации NIST — длинные пароли без принудительной периодической смены и без требований «обязательно цифра и спецсимвол», проверка по базам утёкших паролей.[1] - **Passkeys и WebAuthn.** Устройство хранит закрытый ключ, а сервер — открытый; вход подтверждается отпечатком или PIN-кодом устройства. Ключ привязан к домену сайта, поэтому фишинг не срабатывает (см. [Криптография с открытым ключом](https://llmdocs.ru/wiki/public-key-cryptography.md)).[6] - **Одноразовые коды** — TOTP в приложении, SMS (слабее из-за подмены SIM), ссылки на почту. - **Вход через внешнего провайдера** — [OpenID Connect](https://llmdocs.ru/wiki/oauth-oidc.md) или SAML: приложение доверяет проверку личности провайдеру (Google, корпоративный каталог, VK ID).[7] - **Для машин** — ключи API, клиентские сертификаты (mTLS), ключи [SSH](https://llmdocs.ru/wiki/ssh.md), краткоживущие токены сервисных учётных записей. ### Сессии и токены После успешного входа нужно помнить пользователя между запросами, ведь HTTP не хранит состояние: | | Сессия на сервере | Самодостаточный токен (JWT) | |---|---|---| | Где состояние | в хранилище сервера; клиенту — идентификатор в cookie | в самом токене, подписанном сервером[5] | | Отзыв | мгновенный — удалить сессию | сложен до истечения срока; нужны короткий срок и обновление | | Масштабирование | нужно общее хранилище сессий | любой сервер проверяет подпись | | Типичное применение | веб-приложения | API, связь между сервисами | Cookie сессии ставят с флагами `HttpOnly`, `Secure` и `SameSite`, защищаясь от кражи скриптом и [CSRF](https://llmdocs.ru/wiki/csrf.md) (см. [Cookie и сессии](https://llmdocs.ru/wiki/cookies-sessions.md)). ## Авторизация ### Модели доступа - **ACL** (списки контроля доступа) — у каждого объекта список, кому и что разрешено; так устроены [права в файловых системах](https://llmdocs.ru/wiki/unix-permissions.md). - **RBAC** (ролевая модель) — права выдаются ролям (`admin`, `editor`, `viewer`), а роли — пользователям. Самая распространённая модель в приложениях. - **ABAC** (на основе атрибутов) — решение по правилам над атрибутами пользователя, ресурса и контекста: «менеджер может видеть заказы своего региона в рабочее время». - **ReBAC** (на основе отношений) — права следуют из связей: «редактировать документ может владелец и те, с кем он поделился»; так устроен доступ в Google Docs. ### Как реализовывать ```python # проверка на сервере для каждого запроса, а не только скрытие кнопки в интерфейсе @app.delete("/projects/{project_id}") def delete_project(project_id: int, user: User = Depends(current_user)): project = repo.get(project_id) or raise_404() if project.owner_id != user.id and "admin" not in user.roles: raise HTTPException(status_code=403) repo.delete(project) ``` Главные правила:[3] 1. **Проверять на сервере при каждом запросе.** Скрытая кнопка в интерфейсе — не защита: запрос можно отправить напрямую. 2. **Запрещено всё, что явно не разрешено** (*deny by default*). 3. **Проверять доступ к конкретному объекту**, а не только к типу операции. Классическая уязвимость IDOR: пользователь меняет в адресе `/orders/1001` на `/orders/1002` и видит чужой заказ. 4. **Минимальные права** — и для людей, и для сервисов, и для ИИ-агентов ([Принцип наименьших привилегий](https://llmdocs.ru/wiki/least-privilege.md)). 5. **Централизовать логику** — одна библиотека или сервис политик вместо проверок, разбросанных по коду. Нарушение контроля доступа занимает первое место в рейтинге самых распространённых уязвимостей веб-приложений [OWASP Top 10](https://llmdocs.ru/wiki/owasp-top-10.md).[4] ## Типичные ошибки аутентификации - Сообщения, раскрывающие, существует ли пользователь («неверный пароль» вместо «неверный логин или пароль»). - Отсутствие ограничения попыток входа — подбор паролей. - Токены и ключи в коде, логах и URL; их место — в хранилище секретов ([Управление секретами](https://llmdocs.ru/wiki/secrets-management.md)). - Самописная криптография и проверка JWT без проверки подписи и алгоритма. Надёжнее использовать проверенные библиотеки и готовых провайдеров.[2] ## См. также - [OAuth 2.0 и OpenID Connect](https://llmdocs.ru/wiki/oauth-oidc.md) - [Двухфакторная аутентификация](https://llmdocs.ru/wiki/two-factor-auth.md) - [Хранение паролей (bcrypt, Argon2)](https://llmdocs.ru/wiki/password-storage.md) - [Принцип наименьших привилегий](https://llmdocs.ru/wiki/least-privilege.md) - [Cookie и сессии](https://llmdocs.ru/wiki/cookies-sessions.md) ## Источники 1. [NIST SP 800-63B — Digital Identity Guidelines: Authentication and Lifecycle Management](https://pages.nist.gov/800-63-3/sp800-63b.html) 2. [OWASP — Authentication Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html) 3. [OWASP — Authorization Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Authorization_Cheat_Sheet.html) 4. [OWASP Top 10 — A01 Broken Access Control](https://owasp.org/Top10/A01_2021-Broken_Access_Control/) 5. [RFC 7519 — JSON Web Token (JWT)](https://www.rfc-editor.org/rfc/rfc7519) 6. [W3C — Web Authentication (WebAuthn)](https://www.w3.org/TR/webauthn-2/) 7. [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html) --- # CSRF > Межсайтовая подделка запроса — атака, при которой чужой сайт заставляет браузер жертвы отправить запрос с её cookie; защита — SameSite cookie, CSRF-токены, проверка Origin. Источник: https://llmdocs.ru/wiki/csrf/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Полное название**: Cross-Site Request Forgery - **Классификация**: CWE-352 - **Условие атаки**: аутентификация по cookie, которые браузер прикладывает автоматически - **Последствия**: смена пароля и почты, переводы, изменение настроек от имени жертвы - **Защита**: SameSite cookie, синхронизирующий токен, проверка Origin, Fetch Metadata - **Не защищает**: CORS сам по себе, секретная cookie, POST вместо GET **CSRF** (*Cross-Site Request Forgery*, межсайтовая подделка запроса) — атака, при которой сайт злоумышленника заставляет браузер жертвы отправить запрос на другой сайт, где жертва уже вошла в систему. Браузер автоматически прикладывает к запросу [cookie](https://llmdocs.ru/wiki/cookies-sessions.md) целевого сайта, и сервер воспринимает его как действие самого пользователя: смену пароля или почты, перевод денег, удаление данных. В отличие от [XSS](https://llmdocs.ru/wiki/xss.md), злоумышленник не читает ответ и не выполняет код на сайте — он лишь «нажимает кнопку» руками жертвы. ## Как работает Пользователь вошёл в интернет-банк, сессия хранится в cookie. Затем он открывает страницу злоумышленника, где есть скрытая форма: ```html
``` Браузер отправляет POST-запрос на `bank.example` вместе с сессионной cookie. Если сервер проверяет только cookie, перевод выполнится. Для GET-запросов достаточно даже ``.[1] Атака возможна, когда одновременно выполняются три условия: действие имеет ценность для злоумышленника, аутентификация основана только на том, что браузер прикладывает сам (cookie, HTTP Basic, клиентские сертификаты), и все параметры запроса злоумышленник может угадать. ## Чем защищаться ### SameSite cookie Атрибут `SameSite` указывает браузеру, отправлять ли cookie при запросах с других сайтов:[3] | Значение | Поведение | |---|---| | `Strict` | cookie не отправляется ни при каких межсайтовых запросах, даже при переходе по ссылке | | `Lax` | отправляется только при навигации верхнего уровня методом GET (переход по ссылке) | | `None` | отправляется всегда; требует `Secure` | ```http Set-Cookie: session=abc123; Secure; HttpOnly; SameSite=Lax; Path=/ ``` Современные браузеры по умолчанию считают cookie без атрибута как `Lax`, что закрыло большинство классических атак. Но полагаться только на это не стоит: поведение по умолчанию различается между браузерами, «сайт» определяется по регистрируемому домену (поддомены одного сайта считаются своими), а GET-запросы, меняющие состояние, `Lax` не защищает. ### CSRF-токены Классическая защита — **синхронизирующий токен**: сервер генерирует случайное непредсказуемое значение, связанное с сессией, и вставляет его в каждую форму. При запросе, меняющем состояние, сервер сверяет токен; сайт злоумышленника не может его узнать. ```html
...
``` Для одностраничных приложений токен передают в заголовке (`X-CSRF-Token`). Вариант без хранения на сервере — **double submit cookie**: токен лежит и в cookie, и в заголовке, сервер сравнивает их; надёжнее подписанная версия, привязанная к сессии. Большинство фреймворков включают защиту из коробки: Django, Rails, Laravel, Spring Security; в Flask — расширение Flask-WTF.[5] ### Проверка Origin и Fetch Metadata Браузер добавляет к межсайтовым запросам заголовки, которые нельзя подделать из JavaScript: - `Origin` — с какого сайта отправлен запрос; сервер сравнивает его со списком разрешённых; - `Sec-Fetch-Site: same-origin | same-site | cross-site | none` — заголовки **Fetch Metadata** позволяют одной проверкой отклонить все межсайтовые запросы к изменяющим методам.[4] ```python if request.method not in ("GET", "HEAD", "OPTIONS"): if request.headers.get("Sec-Fetch-Site") not in (None, "same-origin", "none"): abort(403) ``` ## Частые заблуждения - **«У нас POST, а не GET»** — формы прекрасно отправляют POST. - **«У нас настроен CORS»** — [CORS](https://llmdocs.ru/wiki/cors.md) ограничивает чтение ответа JavaScript-кодом, но простые запросы (формы) всё равно доходят до сервера и выполняются. - **«API принимает JSON»** — запрос с `Content-Type: application/json` с чужого сайта требует preflight и обычно блокируется, но сервер, который принимает и `text/plain` или form-encoded, уязвим. - **«Токен в cookie — секретный»** — злоумышленнику не нужно знать cookie, их отправляет браузер. ## Когда CSRF не страшен Если API аутентифицирует запросы токеном в заголовке `Authorization: Bearer ...`, который JavaScript приложения добавляет явно (см. [OAuth 2.0 и OpenID Connect](https://llmdocs.ru/wiki/oauth-oidc.md)), браузер не приложит его к чужому запросу, и классический CSRF невозможен. Однако хранение такого токена в `localStorage` повышает ущерб от XSS — компромисс между угрозами. Кроме того, любая XSS-уязвимость обходит CSRF-защиту: скрипт на самом сайте может прочитать токен. Поэтому эти защиты дополняют, а не заменяют друг друга. ## Рекомендуемый набор 1. `SameSite=Lax` (или `Strict`) и `Secure`, `HttpOnly` для сессионных cookie. 2. Встроенная CSRF-защита фреймворка для всех изменяющих запросов. 3. Никаких изменений состояния через GET. 4. Проверка `Origin` или `Sec-Fetch-Site` как дополнительный слой. 5. Повторный ввод пароля или [второй фактор](https://llmdocs.ru/wiki/two-factor-auth.md) для критичных действий — смены почты, пароля, вывода денег. ## См. также - [XSS (как защищаться)](https://llmdocs.ru/wiki/xss.md) - [Cookie и сессии](https://llmdocs.ru/wiki/cookies-sessions.md) - [CORS](https://llmdocs.ru/wiki/cors.md) - [OWASP Top 10](https://llmdocs.ru/wiki/owasp-top-10.md) ## Источники 1. [OWASP — Cross-Site Request Forgery Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html) 2. [CWE-352: Cross-Site Request Forgery (CSRF)](https://cwe.mitre.org/data/definitions/352.html) 3. [MDN — SameSite cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value) 4. [web.dev — Protect your resources from web attacks with Fetch Metadata](https://web.dev/articles/fetch-metadata) 5. [Django Docs — Cross Site Request Forgery protection](https://docs.djangoproject.com/en/stable/ref/csrf/) --- # Fail2ban > Утилита, которая читает логи сервисов и временно блокирует в файрволе IP-адреса с повторяющимися неудачными попытками входа; защита от перебора паролей SSH, веб-форм и почты. Источник: https://llmdocs.ru/wiki/fail2ban/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Первый выпуск**: 2004 - **Язык**: Python - **Лицензия**: GPLv2 - **Принцип**: логи → фильтр (regex) → действие (бан в файрволе) - **Источники логов**: файлы, systemd journal - **Действия**: iptables, nftables, firewalld, ufw, Cloudflare, почта - **Конфигурация**: /etc/fail2ban/jail.local - **Альтернатива**: CrowdSec **Fail2ban** — программа для Linux-серверов, которая следит за журналами сервисов и, обнаружив много неудачных попыток входа с одного IP-адреса, временно блокирует этот адрес в [файрволе](https://llmdocs.ru/wiki/firewall.md). Любой сервер с публичным IP уже через несколько минут после запуска начинают атаковать боты, перебирающие пароли к [SSH](https://llmdocs.ru/wiki/ssh.md), почте и веб-панелям. Fail2ban не делает слабый пароль надёжным, но резко снижает шум в логах, нагрузку и шансы перебора. ## Как работает Fail2ban построен из трёх понятий:[1] | Понятие | Что это | Пример | |---|---|---| | **Фильтр** (filter) | регулярные выражения для строк лога о неудаче | `Failed password for .* from ` | | **Действие** (action) | что сделать с адресом | добавить в набор nftables, отправить письмо | | **Джейл** (jail) | связка: какой лог, какой фильтр, какие пороги и действие | `[sshd]` | Демон читает логи (файлы или [systemd journal](https://llmdocs.ru/wiki/journald-logs.md)), находит совпадения, и если с одного адреса за время `findtime` набралось `maxretry` неудач, выполняет действие бана на срок `bantime`. По истечении срока адрес разблокируется автоматически. Фильтры для десятков популярных сервисов — sshd, [nginx](https://llmdocs.ru/wiki/nginx.md), Postfix, Dovecot, vsftpd, WordPress — поставляются в комплекте. ## Установка и настройка ```bash sudo apt install fail2ban # Debian/Ubuntu sudo dnf install fail2ban # Fedora/RHEL (EPEL) ``` Файлы `jail.conf` и `filter.d/*.conf` перезаписываются при обновлении пакета, поэтому собственные настройки кладут в `/etc/fail2ban/jail.local` или `/etc/fail2ban/jail.d/*.local`:[2] ```ini [DEFAULT] bantime = 1h findtime = 10m maxretry = 5 ignoreip = 127.0.0.1/8 ::1 203.0.113.10 backend = systemd banaction = nftables-multiport # повторно попавшимся — дольше bantime.increment = true bantime.maxtime = 1w [sshd] enabled = true port = ssh [nginx-http-auth] enabled = true logpath = /var/log/nginx/error.log ``` В `ignoreip` обязательно добавляют собственный статический адрес, чтобы случайно не заблокировать себя. После правки — `sudo systemctl restart fail2ban` (служба управляется [systemd](https://llmdocs.ru/wiki/systemd.md)). ## Управление ```bash sudo fail2ban-client status # список джейлов sudo fail2ban-client status sshd # счётчики и забаненные адреса sudo fail2ban-client set sshd unbanip 198.51.100.7 sudo fail2ban-client banned # все баны sudo fail2ban-regex /var/log/auth.log /etc/fail2ban/filter.d/sshd.conf # проверить фильтр ``` `fail2ban-regex` незаменим при написании собственного фильтра: он показывает, сколько строк лога совпало и какие адреса были бы заблокированы. ## Свой фильтр Например, для приложения, пишущего в лог `LOGIN FAILED ip=1.2.3.4 user=admin`: ```ini # /etc/fail2ban/filter.d/myapp.conf [Definition] failregex = ^.*LOGIN FAILED ip= .*$ ignoreregex = ``` ```ini # /etc/fail2ban/jail.d/myapp.local [myapp] enabled = true logpath = /var/log/myapp/auth.log maxretry = 10 findtime = 5m ``` Важно, чтобы приложение логировало реальный IP клиента: за [обратным прокси](https://llmdocs.ru/wiki/reverse-proxy.md) или CDN в логах окажется адрес прокси, и бан заблокирует всех сразу. В таком случае нужно настроить передачу `X-Forwarded-For` или банить на уровне CDN через соответствующее действие. ## Ограничения - **Распределённые атаки.** Ботнет с тысячами адресов, каждый из которых делает пару попыток, пороги не превысит. - **IPv6.** Злоумышленник легко меняет адрес внутри своей подсети /64; блокировка отдельных адресов малоэффективна. - **Реакция по логам.** Fail2ban реагирует уже после неудачных попыток и не защищает от уязвимостей в самом сервисе. - **Риск самоблокировки** при неверно настроенном `ignoreip` или общем адресе офиса. ## Fail2ban — не главная защита SSH Перебор пароля SSH надёжнее всего предотвращается отказом от паролей:[5] ``` # /etc/ssh/sshd_config PasswordAuthentication no KbdInteractiveAuthentication no PermitRootLogin prohibit-password ``` Вход только по ключам делает перебор бессмысленным; Fail2ban в этом случае лишь уменьшает шум в логах. Дополнительно помогают ограничение доступа к порту SSH по списку адресов в файрволе, вход через VPN-сеть или бастион и [принцип наименьших привилегий](https://llmdocs.ru/wiki/least-privilege.md) для учётных записей. ## Альтернативы **CrowdSec** — современная альтернатива с похожей идеей: агент анализирует логи по сценариям, а решения о блокировке применяют отдельные «вышибалы» (bouncers) на файрволе, nginx или CDN. Главная особенность — общая база репутации: адреса, атакующие других участников, блокируются заранее.[4] Для веб-приложений также используют ограничение частоты запросов в nginx (`limit_req`), WAF и капчу. ## См. также - [Файрвол (iptables, nftables)](https://llmdocs.ru/wiki/firewall.md) - [SSH](https://llmdocs.ru/wiki/ssh.md) - [journald и логи](https://llmdocs.ru/wiki/journald-logs.md) - [Принцип наименьших привилегий](https://llmdocs.ru/wiki/least-privilege.md) ## Источники 1. [Fail2ban — репозиторий и wiki](https://github.com/fail2ban/fail2ban) 2. [Fail2ban — jail.conf (man page)](https://manpages.debian.org/stable/fail2ban/jail.conf.5.en.html) 3. [ArchWiki — fail2ban](https://wiki.archlinux.org/title/Fail2ban) 4. [CrowdSec Documentation](https://docs.crowdsec.net/) 5. [OpenSSH — sshd_config(5)](https://man.openbsd.org/sshd_config) --- # Файрвол (iptables, nftables) > Межсетевой экран — фильтрация сетевых пакетов по правилам; в Linux реализован подсистемой netfilter и настраивается через iptables, nftables или обёртки ufw и firewalld. Источник: https://llmdocs.ru/wiki/firewall/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Назначение**: пропускать или отбрасывать пакеты по правилам - **Подсистема ядра Linux**: netfilter - **Классический интерфейс**: iptables (с 2001, ядро 2.4) - **Современный интерфейс**: nftables (с 2014, ядро 3.13) - **Обёртки**: ufw (Ubuntu), firewalld (RHEL/Fedora) - **Ключевая возможность**: отслеживание соединений (conntrack, stateful) **Файрвол** (межсетевой экран, брандмауэр; англ. *firewall*) — программа или устройство, которое пропускает или отбрасывает сетевые пакеты по заданным правилам: по адресам, портам, протоколу и состоянию соединения. В [Linux](https://llmdocs.ru/wiki/linux.md) фильтрацию выполняет подсистема ядра **netfilter**, а правила задаются утилитами **iptables** (классический интерфейс) или **nftables** (современный).[1] Поверх них работают упрощённые обёртки — ufw и firewalld. ## Как устроен netfilter Netfilter встраивает в сетевой стек ядра точки перехвата (*hooks*), через которые проходит каждый пакет: - **prerouting** — сразу после получения, до решения о маршрутизации ([DNAT](https://llmdocs.ru/wiki/nat.md), проброс портов); - **input** — пакеты, адресованные самой машине; - **forward** — пакеты, проходящие транзитом (маршрутизатор, контейнеры); - **output** — пакеты, созданные локальными процессами; - **postrouting** — перед отправкой (SNAT, маскарадинг). Ключевой механизм — **conntrack**, отслеживание соединений. Благодаря ему файрвол работает «с состоянием» (stateful): достаточно разрешить входящий запрос, а ответные пакеты того же соединения пропускаются правилом `established,related`. Без этого пришлось бы вручную описывать трафик в обе стороны. ## iptables Iptables появился в ядре 2.4 (2001). Правила организованы в **таблицы** (`filter`, `nat`, `mangle`, `raw`) и **цепочки** (`INPUT`, `FORWARD`, `OUTPUT` и т. д.); пакет проходит правила цепочки сверху вниз до первого совпадения, а если ни одно не сработало — применяется политика цепочки.[3] ```bash iptables -P INPUT DROP iptables -A INPUT -i lo -j ACCEPT iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT iptables -A INPUT -p tcp --dport 22 -j ACCEPT iptables -A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT ``` Для IPv6 используется отдельная утилита `ip6tables` с дублирующими правилами. В современных дистрибутивах команда `iptables` обычно является совместимым интерфейсом `iptables-nft`, который транслирует правила в nftables. ## nftables Nftables вошёл в ядро 3.13 (2014) и заменяет iptables, ip6tables, arptables и ebtables одной утилитой `nft` с единым синтаксисом.[2] Преимущества: общие правила для IPv4 и IPv6 (семейство `inet`), встроенные множества (*sets*) и словари, атомарная загрузка всего набора правил из файла, более быстрая обработка больших списков. Таблицы и цепочки не предопределены — их создаёт администратор.[4] Типовой конфигурационный файл `/etc/nftables.conf` для сервера: ```nft #!/usr/sbin/nft -f flush ruleset table inet filter { set admin_ips { type ipv4_addr; elements = { 203.0.113.10 } } chain input { type filter hook input priority 0; policy drop; iif lo accept ct state established,related accept ct state invalid drop meta l4proto { icmp, ipv6-icmp } accept ip saddr @admin_ips tcp dport 22 accept tcp dport { 80, 443 } accept udp dport 443 accept # HTTP/3 (QUIC) } chain forward { type filter hook forward priority 0; policy drop; } chain output { type filter hook output priority 0; policy accept; } } ``` ```bash nft -c -f /etc/nftables.conf # проверить синтаксис systemctl enable --now nftables # загрузить и включить при старте nft list ruleset # показать действующие правила ``` ## Обёртки - **ufw** (*Uncomplicated Firewall*) в Ubuntu: `ufw allow 22/tcp`, `ufw allow 443`, `ufw enable`.[5] - **firewalld** в RHEL, Fedora, openSUSE оперирует **зонами** (`public`, `internal`) и сервисами: `firewall-cmd --permanent --add-service=https`, затем `--reload`.[6] Обёртки удобны для типовых задач; смешивать их с ручными правилами nft в одной системе не стоит. ## Практические правила - Политика по умолчанию для входящих — **запрет**, разрешения — явные (см. [Принцип наименьших привилегий](https://llmdocs.ru/wiki/least-privilege.md)). - Перед применением правил на удалённой машине убедиться, что [SSH](https://llmdocs.ru/wiki/ssh.md) остаётся разрешённым, и держать запасной путь: консоль провайдера или отложенный откат (`at now + 5 min` с командой восстановления старых правил). - Не забывать про IPv6: открытый по IPv6 порт так же доступен из интернета. - Сервисы, которые нужны только локально (базы данных, Redis), лучше слушать на `127.0.0.1`, а не полагаться только на файрвол. - Для защиты от перебора паролей файрвол дополняют [Fail2ban](https://llmdocs.ru/wiki/fail2ban.md) или ограничением частоты (`limit rate` в nftables). - **Docker** сам добавляет правила в netfilter, и проброшенные порты (`-p 8080:80`) обходят правила ufw в цепочке INPUT; фильтровать их нужно в цепочке `DOCKER-USER` или публиковать порты только на `127.0.0.1`.[7] ## Облачные и сетевые файрволы Помимо файрвола на хосте, есть файрволы уровня сети: группы безопасности в облаках, правила у хостинг-провайдера, аппаратные шлюзы, а в [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) — NetworkPolicy, которые реализуют сетевые плагины (CNI). Хорошая практика — сочетать оба уровня. ## См. также - [TCP](https://llmdocs.ru/wiki/tcp.md) - [UDP](https://llmdocs.ru/wiki/udp.md) - [IP-адрес и подсети (CIDR)](https://llmdocs.ru/wiki/ip-cidr.md) - [NAT](https://llmdocs.ru/wiki/nat.md) ## Источники 1. [netfilter project — nftables wiki](https://wiki.nftables.org/) 2. [nft(8) — Linux manual page](https://www.netfilter.org/projects/nftables/manpage.html) 3. [iptables(8) — Linux manual page](https://man7.org/linux/man-pages/man8/iptables.8.html) 4. [Arch Wiki — nftables](https://wiki.archlinux.org/title/Nftables) 5. [Ubuntu — Uncomplicated Firewall (ufw)](https://documentation.ubuntu.com/server/how-to/security/firewalls/) 6. [firewalld documentation](https://firewalld.org/documentation/) 7. [Docker docs — Packet filtering and firewalls](https://docs.docker.com/engine/network/packet-filtering-firewalls/) --- # Хеш-функция > Функция, отображающая данные произвольной длины в значение фиксированного размера; криптографические хеши (SHA-2, SHA-3, BLAKE3) защищают целостность, некриптографические ускоряют хеш-таблицы. Источник: https://llmdocs.ru/wiki/hash-function/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Вход**: данные произвольной длины - **Выход**: дайджест фиксированной длины (например, 256 бит) - **Криптографические**: SHA-256, SHA-512, SHA-3, BLAKE2, BLAKE3 - **Устаревшие**: MD5, SHA-1 (найдены коллизии) - **Некриптографические**: xxHash, MurmurHash, SipHash, CRC32 - **Стандарты**: FIPS 180-4 (SHA-2), FIPS 202 (SHA-3), ГОСТ Р 34.11-2012 «Стрибог» **Хеш-функция** — функция, которая превращает данные любой длины в значение фиксированного размера, называемое **хешем**, **дайджестом** или **контрольной суммой**. Одинаковые входные данные всегда дают одинаковый хеш, а малейшее изменение входа меняет хеш до неузнаваемости. Хеш-функции бывают двух классов: **криптографические** (SHA-256, SHA-3, BLAKE3) гарантируют, что подделать данные с тем же хешем практически невозможно, и защищают целостность и подписи; **некриптографические** (xxHash, MurmurHash) просто быстро и равномерно распределяют ключи — например, в [хеш-таблицах](https://llmdocs.ru/wiki/hash-table.md).[1] ## Свойства криптографических хешей | Свойство | Смысл | |---|---| | Стойкость к поиску прообраза | по хешу нельзя найти входные данные | | Стойкость ко второму прообразу | для данного сообщения нельзя найти другое с тем же хешем | | Стойкость к коллизиям | нельзя найти никакую пару разных сообщений с одинаковым хешем | | Лавинный эффект | изменение одного бита меняет примерно половину бит хеша | Коллизии неизбежно существуют (входов бесконечно много, выходов — конечное число), но найти их должно быть вычислительно невозможно. Из-за «парадокса дней рождения» для хеша длиной $n$ бит коллизия находится примерно за $2^{n/2}$ попыток, поэтому 256 бит дают 128-битную стойкость. ## История и семейства - **MD5** (1992) — сломан: коллизии находятся за секунды; с 2008 года на его коллизиях подделывали сертификаты. Годится только для некриптографических контрольных сумм. - **SHA-1** (1995) — практическая коллизия получена в 2017 году (атака SHAttered: два разных PDF с одинаковым хешем).[3] Браузеры и [Git](https://llmdocs.ru/wiki/git.md) уходят от него — Git переходит на SHA-256. - **SHA-2** (2001) — SHA-224/256/384/512, основной стандарт сегодня.[1] - **SHA-3** (2015) — победитель открытого конкурса NIST, алгоритм Keccak с иной конструкцией («губка»), запасной вариант на случай слабостей SHA-2.[2] - **BLAKE2, BLAKE3** — быстрее SHA-2 на обычных процессорах; BLAKE3 распараллеливается на много ядер.[5] - **«Стрибог»** (ГОСТ Р 34.11-2012) — российский стандарт, 256 и 512 бит.[7] ## Применение - **Целостность файлов.** Публикуется хеш дистрибутива; пользователь сверяет его после загрузки. Пакетные менеджеры ([pip](https://llmdocs.ru/wiki/pip-pypi.md), npm, Cargo) фиксируют хеши зависимостей в lock-файлах. - **Адресация по содержимому.** Git идентифицирует объекты по хешу, [образы контейнеров](https://llmdocs.ru/wiki/oci-image.md) — по дайджесту `sha256:…`, так же работают системы дедупликации и [бэкапов](https://llmdocs.ru/wiki/backup-3-2-1.md). - **Цифровые подписи.** Подписывается не документ, а его хеш (см. [Криптография с открытым ключом](https://llmdocs.ru/wiki/public-key-cryptography.md)); на этом основаны сертификаты [TLS](https://llmdocs.ru/wiki/tls.md). - **HMAC** — хеш с секретным ключом для проверки подлинности сообщений: подписи вебхуков, токены, API-запросы.[4] - **Выработка ключей** (HKDF) и генерация псевдослучайных чисел. - **Хранение паролей** — только специальными медленными функциями, а не обычными хешами (см. ниже). ```bash sha256sum ubuntu.iso # Linux shasum -a 256 ubuntu.iso # macOS echo -n "hello" | sha256sum # 2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 ``` ```python import hashlib, hmac hashlib.sha256(b"hello").hexdigest() hashlib.blake2b(b"hello", digest_size=32).hexdigest() sig = hmac.new(b"secret", b"payload", hashlib.sha256).hexdigest() hmac.compare_digest(sig, received_sig) # сравнение за постоянное время ``` ## Частые ошибки - **Хранить пароли как SHA-256.** Обычные хеши рассчитаны на скорость: видеокарта перебирает миллиарды вариантов в секунду. Для паролей нужны медленные функции с солью — bcrypt, scrypt, Argon2 (см. [Хранение паролей (bcrypt, Argon2)](https://llmdocs.ru/wiki/password-storage.md)). - **Самодельный MAC** вида `sha256(key + message)` уязвим к атаке удлинения сообщения для SHA-2; нужно использовать HMAC. - **Сравнение хешей через `==`** в проверке подписи даёт утечку по времени; нужно сравнение за постоянное время. - **MD5 и SHA-1** в новых системах безопасности. ## Некриптографические хеши Для хеш-таблиц, фильтров Блума, шардирования и проверки от случайных повреждений важна скорость, а не стойкость: xxHash, MurmurHash, CityHash, CRC32. Для таблиц со входом от пользователя применяют SipHash — он защищает от атак, специально создающих коллизии для замедления сервиса; его используют Python, Rust и другие языки.[6] ## См. также - [Хеш-таблица](https://llmdocs.ru/wiki/hash-table.md) - [Хранение паролей (bcrypt, Argon2)](https://llmdocs.ru/wiki/password-storage.md) - [Криптография с открытым ключом](https://llmdocs.ru/wiki/public-key-cryptography.md) - [Симметричное шифрование (AES, ChaCha20)](https://llmdocs.ru/wiki/symmetric-encryption.md) - [Git](https://llmdocs.ru/wiki/git.md) ## Источники 1. [NIST FIPS 180-4 — Secure Hash Standard (SHA-2)](https://csrc.nist.gov/pubs/fips/180-4/upd1/final) 2. [NIST FIPS 202 — SHA-3 Standard](https://csrc.nist.gov/pubs/fips/202/final) 3. [Stevens et al. — The first collision for full SHA-1 (SHAttered, 2017)](https://shattered.io/) 4. [RFC 2104 — HMAC: Keyed-Hashing for Message Authentication](https://www.rfc-editor.org/rfc/rfc2104) 5. [BLAKE3 — specification](https://github.com/BLAKE3-team/BLAKE3-specs) 6. [Python — hashlib](https://docs.python.org/3/library/hashlib.html) 7. [ГОСТ Р 34.11-2012 — функция хэширования (RFC 6986)](https://www.rfc-editor.org/rfc/rfc6986) --- # Принцип наименьших привилегий > Принцип безопасности, по которому каждый пользователь, процесс и сервис получает только те права, которые необходимы для его задачи, и только на нужное время. Источник: https://llmdocs.ru/wiki/least-privilege/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Формулировка**: Зальцер и Шрёдер, 1975 - **Суть**: минимум прав, минимум времени, минимум области действия - **Смежные идеи**: разделение обязанностей, защита в глубину, Zero Trust - **Примеры в Linux**: отдельные пользователи сервисов, sudo, capabilities, systemd-песочница - **Примеры в облаке**: IAM-роли, сервисные аккаунты, RBAC в Kubernetes **Принцип наименьших привилегий** (англ. *principle of least privilege*, PoLP) — правило проектирования систем, по которому каждый субъект — пользователь, программа, процесс, сервисный аккаунт — получает **только те права, которые необходимы** для выполнения своей задачи, и только на то время, пока они нужны. Принцип не предотвращает взлом сам по себе, но ограничивает его последствия: скомпрометированный компонент может навредить ровно в пределах своих прав. ## История Принцип сформулировали Джером Зальцер и Майкл Шрёдер в статье «The Protection of Information in Computer Systems» (1975) — среди восьми принципов проектирования защищённых систем: «каждая программа и каждый пользователь системы должны работать с наименьшим набором привилегий, необходимым для выполнения работы».[1] Сегодня он закреплён в стандартах, например как мера AC-6 в каталоге NIST SP 800-53,[2] и лежит в основе модели Zero Trust, где ни один запрос не считается доверенным только из-за своего места в сети.[3] ## Три измерения 1. **Что** — набор действий: чтение вместо записи, одна таблица вместо всей базы, одна команда вместо полного root. 2. **Где** — область: один бакет, один namespace, один проект, а не «всё». 3. **Когда** — время: временные права «по запросу» (just-in-time) вместо постоянных, короткоживущие токены вместо вечных ключей. ## Примеры ### Linux - Сервисы запускаются от отдельных непривилегированных пользователей (`www-data`, `postgres`), а не от root; [права на файлы](https://llmdocs.ru/wiki/unix-permissions.md) выдаются ровно на нужные каталоги. - Администраторы работают под обычной учёткой и повышают права через `sudo` для конкретных команд. - **Capabilities** дробят всемогущество root: чтобы слушать порт 80, программе достаточно `CAP_NET_BIND_SERVICE`. - [systemd](https://llmdocs.ru/wiki/systemd.md) позволяет запирать сервис в песочницу:[5] ```ini [Service] User=app DynamicUser=yes NoNewPrivileges=yes ProtectSystem=strict ProtectHome=yes PrivateTmp=yes ReadWritePaths=/var/lib/app CapabilityBoundingSet=CAP_NET_BIND_SERVICE ``` Команда `systemd-analyze security app.service` оценивает, насколько сервис изолирован. ### Контейнеры и Kubernetes - Процесс в контейнере — не root (`USER app` в [Dockerfile](https://llmdocs.ru/wiki/dockerfile.md)), файловая система только для чтения, лишние capabilities сброшены (`--cap-drop=ALL`), без `--privileged`. - В [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) — RBAC с `Role` на конкретный namespace вместо `ClusterRole`, отдельный ServiceAccount на каждое приложение, отключённый автоматический монтаж токена там, где API не нужен, Pod Security Standards уровня `restricted`.[4] ### Базы данных Учётная запись приложения получает `SELECT, INSERT, UPDATE` на свои таблицы — без `DROP`, без прав владельца и суперпользователя. Отдельная роль для миграций, отдельная — только для чтения для аналитики. Это заметно уменьшает ущерб от [SQL-инъекции](https://llmdocs.ru/wiki/sql-injection.md). ### Облако и CI - IAM-политики перечисляют конкретные действия и ресурсы вместо `"Action": "*"`; анализаторы доступа подсказывают, какие права реально использовались.[6] - Пайплайны [CI/CD](https://llmdocs.ru/wiki/ci-cd.md) получают короткоживущие учётные данные через OIDC вместо долгоживущих ключей; токен в GitHub Actions ограничивают блоком `permissions:`. ```yaml permissions: contents: read id-token: write # только для обмена на облачные креды ``` ### ИИ-агенты Принцип особенно важен для [агентов](https://llmdocs.ru/wiki/ai-agent.md) с доступом к инструментам: агенту, который читает почту и пишет сводку, не нужны права на отправку писем и удаление файлов. Так снижается ущерб от [prompt injection](https://llmdocs.ru/wiki/prompt-injection.md). ## Смежные принципы - **Разделение обязанностей** — критичная операция требует участия двух людей или ролей (например, автор кода не может сам вливать его в main без ревью). - **Защита в глубину** — несколько независимых слоёв защиты, каждый из которых ограничивает ущерб при отказе другого. - **Запрет по умолчанию** — всё, что явно не разрешено, запрещено; так строятся [правила файрвола](https://llmdocs.ru/wiki/firewall.md) и политики доступа. ## Трудности Минимальные права требуют знать, что именно нужно программе, а это меняется со временем. Отсюда типичный дрейф: права выдают «с запасом», чтобы всё заработало, и никогда не отзывают. Помогают регулярный пересмотр доступов, автоматическое истечение временных прав, журналирование и инструменты, которые сравнивают выданные права с реально использованными. ## См. также - [Аутентификация и авторизация](https://llmdocs.ru/wiki/authn-authz.md) - [Управление секретами](https://llmdocs.ru/wiki/secrets-management.md) - [Namespaces и cgroups](https://llmdocs.ru/wiki/namespaces-cgroups.md) - [OWASP Top 10](https://llmdocs.ru/wiki/owasp-top-10.md) ## Источники 1. [Saltzer, Schroeder — The Protection of Information in Computer Systems (1975)](https://web.mit.edu/Saltzer/www/publications/protection/) 2. [NIST SP 800-53 Rev. 5 — AC-6 Least Privilege](https://csrc.nist.gov/pubs/sp/800/53/r5/upd1/final) 3. [NIST SP 800-207 — Zero Trust Architecture](https://csrc.nist.gov/pubs/sp/800/207/final) 4. [Kubernetes — Role Based Access Control Good Practices](https://kubernetes.io/docs/concepts/security/rbac-good-practices/) 5. [systemd.exec — sandboxing options](https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html) 6. [AWS IAM — Apply least-privilege permissions](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html) --- # OWASP Top 10 > Рейтинг десяти наиболее критичных категорий рисков безопасности веб-приложений, который публикует фонд OWASP; стандартная точка отсчёта для разработчиков и аудиторов. Источник: https://llmdocs.ru/wiki/owasp-top-10/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Издатель**: OWASP Foundation (некоммерческий фонд) - **Первая версия**: 2003 - **Редакции**: 2003, 2004, 2007, 2010, 2013, 2017, 2021, 2025 - **Основа**: данные о найденных уязвимостях (CWE) и опрос сообщества - **Родственные проекты**: ASVS, Cheat Sheet Series, OWASP Top 10 for LLM Applications, ZAP - **Лицензия**: CC BY-SA 4.0 **OWASP Top 10** — документ фонда OWASP (*Open Worldwide Application Security Project*), перечисляющий десять наиболее критичных категорий рисков безопасности веб-приложений.[1] Это не стандарт и не полный чек-лист, а «документ осведомлённости»: он показывает, с чего начинать, и задаёт общий язык для разработчиков, тестировщиков и аудиторов. Каждая категория объединяет несколько слабостей из каталога CWE.[6] ## История Первый список вышел в 2003 году; с тех пор он обновляется раз в три–четыре года. Ранние редакции возглавляли инъекции и [XSS](https://llmdocs.ru/wiki/xss.md), к 2021 году на первое место вышли ошибки контроля доступа. Начиная с 2017 года рейтинг строится на статистике — данных о сотнях тысяч протестированных приложений, которые присылают компании, — а две–три позиции добавляются по опросу сообщества, чтобы учесть новые риски, ещё не попавшие в статистику. ## Редакция 2021 | № | Категория | Суть | |---|---|---| | A01 | Broken Access Control | пользователь получает доступ к чужим данным или функциям | | A02 | Cryptographic Failures | данные передаются или хранятся без шифрования или со слабым | | A03 | Injection | [SQL](https://llmdocs.ru/wiki/sql-injection.md), команды ОС, LDAP, XSS | | A04 | Insecure Design | ошибки в самой архитектуре, а не в реализации | | A05 | Security Misconfiguration | открытые панели, учётки по умолчанию, лишние сервисы | | A06 | Vulnerable and Outdated Components | библиотеки с известными уязвимостями | | A07 | Identification and Authentication Failures | слабые пароли, перебор, утечка сессий | | A08 | Software and Data Integrity Failures | непроверенные обновления, небезопасная десериализация, CI/CD | | A09 | Security Logging and Monitoring Failures | атаку никто не заметил | | A10 | Server-Side Request Forgery (SSRF) | сервер ходит по URL, заданному атакующим | В редакции 2025 года[2] контроль доступа остался на первом месте, ошибки конфигурации поднялись на второе, категория уязвимых компонентов расширилась до **цепочки поставок ПО** (Software Supply Chain Failures), SSRF вошла в A01, а появилась новая категория о неправильной обработке исключительных ситуаций (Mishandling of Exceptional Conditions). ## Ключевые категории подробнее **Нарушение контроля доступа.** Классика — IDOR (*insecure direct object reference*): `GET /api/orders/1042` возвращает чужой заказ, если сервер проверил, что пользователь вошёл, но не проверил, что заказ его. Проверка прав должна выполняться на сервере для каждого объекта, по умолчанию — запрет (см. [Аутентификация и авторизация](https://llmdocs.ru/wiki/authn-authz.md) и [Принцип наименьших привилегий](https://llmdocs.ru/wiki/least-privilege.md)). **Криптографические ошибки.** HTTP без [TLS](https://llmdocs.ru/wiki/tls.md), пароли в MD5 вместо [Argon2 или bcrypt](https://llmdocs.ru/wiki/password-storage.md), самодельное шифрование, ключи в коде. **Инъекции.** Данные пользователя попадают в интерпретатор как код. Защита — параметризованные запросы, экранирование по контексту, безопасные API вместо склейки строк. **Ошибки конфигурации.** Включённый режим отладки в продакшене, подробные трассировки в ответах, открытый наружу Redis или панель администратора, бакет хранилища с публичным доступом. **Уязвимые компоненты и цепочка поставок.** Большая часть кода приложения — зависимости. Нужны инвентаризация (SBOM), автоматическое обновление и сканеры (Dependabot, Renovate, `pip-audit`, `npm audit`, Trivy). **Целостность ПО и данных.** Сборка из непроверенных источников, скомпрометированный пайплайн [CI/CD](https://llmdocs.ru/wiki/ci-cd.md), десериализация `pickle` из недоверенных данных. ## Как применять - Как **учебный минимум**: каждый веб-разработчик должен понимать все десять категорий и знать типовую защиту. - Как **основу для чек-листа ревью** — но для формальных требований есть более подробный стандарт ASVS (Application Security Verification Standard) с тремя уровнями строгости.[3] - Практические рецепты по каждой теме собраны в OWASP Cheat Sheet Series.[4] - Для тестирования есть бесплатный сканер ZAP и учебные уязвимые приложения (Juice Shop). Не стоит использовать Top 10 как исчерпывающий список: «соответствие Top 10» не означает защищённости, а риски конкретного продукта определяет моделирование угроз. ## Другие списки OWASP Кроме веб-версии, OWASP выпускает отдельные рейтинги для API (API Security Top 10), мобильных приложений и приложений на основе больших языковых моделей — OWASP Top 10 for LLM Applications,[5] где первое место занимает [prompt injection](https://llmdocs.ru/wiki/prompt-injection.md). ## См. также - [SQL-инъекция (как защищаться)](https://llmdocs.ru/wiki/sql-injection.md) - [CSRF](https://llmdocs.ru/wiki/csrf.md) - [Управление секретами](https://llmdocs.ru/wiki/secrets-management.md) - [HTTP](https://llmdocs.ru/wiki/http.md) ## Источники 1. [OWASP Top 10:2021](https://owasp.org/Top10/) 2. [OWASP Top 10:2025](https://owasp.org/Top10/2025/) 3. [OWASP Application Security Verification Standard (ASVS)](https://owasp.org/www-project-application-security-verification-standard/) 4. [OWASP Cheat Sheet Series](https://cheatsheetseries.owasp.org/) 5. [OWASP Top 10 for Large Language Model Applications](https://genai.owasp.org/llm-top-10/) 6. [MITRE — Common Weakness Enumeration (CWE)](https://cwe.mitre.org/) --- # Хранение паролей (bcrypt, Argon2) > Как сервер хранит пароли пользователей — не в открытом виде и не простым хешем, а медленной функцией с солью: Argon2id, scrypt, bcrypt, PBKDF2. Источник: https://llmdocs.ru/wiki/password-storage/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Задача**: хранить проверочное значение, по которому нельзя быстро восстановить пароль - **Рекомендуется**: Argon2id (RFC 9106) - **Альтернативы**: scrypt, bcrypt, PBKDF2 (для FIPS) - **Обязательно**: уникальная соль на каждый пароль - **Нельзя**: открытый текст, обратимое шифрование, MD5/SHA-1/SHA-256 без растяжения - **Стандарты**: NIST SP 800-63B, OWASP Password Storage Cheat Sheet **Хранение паролей** — набор приёмов, с помощью которых сервер запоминает пароли пользователей так, чтобы проверять их при входе, но не иметь возможности (и не давать её взломщику) восстановить исходный пароль. Современная практика — хранить результат **медленной функции хеширования паролей** с уникальной солью: Argon2id, scrypt, bcrypt или PBKDF2.[1] Это часть [аутентификации](https://llmdocs.ru/wiki/authn-authz.md), и одна из самых частых ошибок в ней. ## Почему не просто хеш Базы пользователей утекают регулярно. Если пароли лежат открытым текстом или зашифрованы обратимо (ключ обычно лежит рядом), утечка сразу раскрывает их все — а люди повторяют пароли на разных сайтах. Обычная [криптографическая хеш-функция](https://llmdocs.ru/wiki/hash-function.md) (SHA-256, тем более MD5 или SHA-1) тоже не годится. Она спроектирована быть **быстрой**: современная видеокарта перебирает миллиарды SHA-256 в секунду, поэтому словарь из популярных паролей и их вариаций проверяется за минуты. Кроме того, одинаковые пароли дают одинаковые хеши, и заранее посчитанные таблицы (радужные таблицы) работают против всех пользователей сразу. Поэтому функция для паролей должна обладать тремя свойствами: 1. **Соль** — случайная строка (16+ байт), уникальная для каждого пароля и хранимая рядом с хешем. Она делает одинаковые пароли разными и обесценивает заранее посчитанные таблицы. 2. **Растяжение** (work factor) — настраиваемая стоимость вычисления: проверка одного пароля занимает десятки–сотни миллисекунд вместо наносекунд. 3. **Затраты памяти** (memory-hardness) — функция требует много оперативной памяти, что мешает массовому параллельному перебору на GPU и ASIC. ## Алгоритмы | Алгоритм | Год | Память | Комментарий | |---|---|---|---| | PBKDF2 | 2000 (RFC 2898) | нет | много итераций HMAC; нужен там, где требуется FIPS-140 | | bcrypt | 1999[4] | 4 КБ | основан на шифре Blowfish, параметр cost; пароль обрезается до 72 байт | | scrypt | 2009 (RFC 7914)[5] | да | первая популярная memory-hard функция | | Argon2id | 2015 (RFC 9106)[2] | да | победитель Password Hashing Competition; рекомендация по умолчанию | OWASP рекомендует Argon2id с параметрами не ниже 19 МиБ памяти, 2 итерации, 1 поток; при его отсутствии — scrypt, затем bcrypt с cost ≥ 10, а PBKDF2-HMAC-SHA256 — с 600 000 итераций.[1] Параметры подбирают так, чтобы проверка занимала заметное, но терпимое время на своём железе, и периодически повышают. Результат обычно хранится в одной строке в формате, который содержит алгоритм, параметры и соль: ```text $argon2id$v=19$m=65536,t=3,p=4$c29tZXNhbHQ$RdescudvJCsgt3ub+b+dWRWJTmaaJObG $2b$12$R9h/cIPz0gi.URNNX3kh2OPST9/PgBkqquzi.Ss7KIUgO2t0jWMUW ``` Благодаря этому параметры можно менять со временем: при следующем успешном входе пароль перехешируется с новыми настройками. ## Пример на Python ```python from argon2 import PasswordHasher from argon2.exceptions import VerifyMismatchError ph = PasswordHasher() # параметры по умолчанию — разумные stored = ph.hash("correct horse battery staple") def check(password: str, stored: str) -> bool: try: ph.verify(stored, password) except VerifyMismatchError: return False if ph.check_needs_rehash(stored): ... # сохранить ph.hash(password) вместо старого значения return True ``` Библиотека argon2-cffi сама генерирует соль и сравнивает значения за постоянное время.[6] В других языках есть аналогичные готовые функции (`password_hash` в PHP, `golang.org/x/crypto/argon2` и `bcrypt` в Go, `passlib`/`bcrypt` в Python); писать свою схему не нужно. ## Перец и прочие детали - **Перец** (pepper) — дополнительный секрет, общий для всех паролей и хранящийся отдельно от базы (в [хранилище секретов](https://llmdocs.ru/wiki/secrets-management.md) или HSM). Утечка одной базы без перца не позволяет даже начать перебор. - Сравнивать хеши нужно функцией постоянного времени, чтобы не создавать утечку по времени ответа. - Медленное хеширование делает форму входа удобной целью для перегрузки: нужны ограничения частоты запросов. - Ограничение bcrypt в 72 байта иногда обходят предварительным хешированием пароля, но это надо делать аккуратно (в base64), иначе нулевые байты обрежут вход. ## Политика паролей NIST SP 800-63B (редакция 4) пересмотрел привычные правила:[3] требовать длину не менее 8 символов (лучше 15 при однофакторном входе), разрешать длинные пароли (64+ символа) и любые символы Unicode, **не** требовать обязательной смены по расписанию и «состава» (заглавная, цифра, спецсимвол), зато проверять пароль по спискам утёкших и популярных. Лучшая защита от последствий утечек — [Двухфакторная аутентификация](https://llmdocs.ru/wiki/two-factor-auth.md) и passkeys, при которых сервер вообще не хранит общий секрет. ## См. также - [Хеш-функция](https://llmdocs.ru/wiki/hash-function.md) - [Аутентификация и авторизация](https://llmdocs.ru/wiki/authn-authz.md) - [OWASP Top 10](https://llmdocs.ru/wiki/owasp-top-10.md) - [Криптография с открытым ключом](https://llmdocs.ru/wiki/public-key-cryptography.md) ## Источники 1. [OWASP — Password Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Password_Storage_Cheat_Sheet.html) 2. [RFC 9106 — Argon2 Memory-Hard Function for Password Hashing](https://www.rfc-editor.org/rfc/rfc9106) 3. [NIST SP 800-63B — Digital Identity Guidelines: Authentication](https://pages.nist.gov/800-63-4/sp800-63b.html) 4. [Provos, Mazières — A Future-Adaptable Password Scheme (bcrypt, USENIX 1999)](https://www.usenix.org/legacy/events/usenix99/provos/provos.pdf) 5. [RFC 7914 — The scrypt Password-Based Key Derivation Function](https://www.rfc-editor.org/rfc/rfc7914) 6. [Python — argon2-cffi documentation](https://argon2-cffi.readthedocs.io/) --- # Криптография с открытым ключом > Асимметричная криптография, использующая пару связанных ключей — открытый и закрытый; лежит в основе TLS, SSH, цифровых подписей и обмена ключами. Источник: https://llmdocs.ru/wiki/public-key-cryptography/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Принцип**: пара ключей — открытый публикуется, закрытый хранится в секрете - **Основные задачи**: обмен ключами, цифровая подпись, шифрование - **Изобретение (открытое)**: Диффи и Хеллман (1976), RSA (1977) - **Алгоритмы**: RSA, ECDH/X25519, ECDSA, Ed25519 - **Постквантовые стандарты**: ML-KEM (FIPS 203), ML-DSA (FIPS 204), SLH-DSA (FIPS 205), 2024 - **Применение**: TLS, SSH, PGP, подпись кода и обновлений, криптовалюты **Криптография с открытым ключом** (асимметричная криптография) — раздел криптографии, в котором используются пары математически связанных ключей: **открытый** (публичный) ключ можно свободно распространять, а **закрытый** (приватный) владелец хранит в секрете. Что зашифровано открытым ключом, расшифрует только владелец закрытого; что подписано закрытым ключом, любой может проверить открытым. Вычислить закрытый ключ по открытому практически невозможно. Асимметричная криптография решила задачу, веками ограничивавшую шифрование: как договориться о секретном ключе с незнакомцем по открытому каналу. На ней построены [TLS](https://llmdocs.ru/wiki/tls.md) и HTTPS, [SSH](https://llmdocs.ru/wiki/ssh.md), подписи обновлений и пакетов, сертификаты и электронная подпись. ## История В 1976 году Уитфилд Диффи и Мартин Хеллман опубликовали статью «Новые направления в криптографии», где описали обмен ключами по открытому каналу и идею цифровой подписи.[1] В 1977 году Рональд Ривест, Ади Шамир и Леонард Адлеман предложили алгоритм **RSA**, пригодный и для шифрования, и для подписи.[2] Позже выяснилось, что в британской спецслужбе GCHQ Джеймс Эллис, Клиффорд Кокс и Малкольм Уильямсон пришли к тем же идеям несколькими годами раньше, но работа была засекречена до 1997 года. Авторы RSA получили премию Тьюринга в 2002 году, Диффи и Хеллман — в 2015-м. В 1985 году Нил Коблиц и Виктор Миллер независимо предложили **криптографию на эллиптических кривых**, дающую ту же стойкость при гораздо более коротких ключах. Кривые Curve25519 и Ed25519 Дэниела Бернстайна и коллег стали стандартом де-факто в современных протоколах.[3][4] ## Три основные задачи | Задача | Что делает | Алгоритмы | |---|---|---| | Обмен ключами | две стороны вырабатывают общий секрет по открытому каналу | Диффи — Хеллман, ECDH, X25519, ML-KEM | | Цифровая подпись | доказывает авторство и целостность данных | RSA-PSS, ECDSA, Ed25519, ML-DSA | | Шифрование | зашифровать данные для владельца ключа | RSA-OAEP, гибридные схемы (HPKE) | На практике асимметричные алгоритмы медленные, поэтому большие объёмы данных ими не шифруют. Используется **гибридная схема**: с помощью асимметричного обмена стороны договариваются об общем ключе, а данные шифруются быстрым [симметричным шифром](https://llmdocs.ru/wiki/symmetric-encryption.md) — AES или ChaCha20. Так работает TLS 1.3: обмен ключами по ECDHE, подпись сервера в сертификате, данные — через AEAD-шифр.[6] ## Как это работает: обмен Диффи — Хеллмана Упрощённо: стороны публично договариваются о параметрах. Алиса выбирает секретное число *a* и отправляет результат вычисления *g^a*, Боб — секретное *b* и отправляет *g^b*. Каждый возводит полученное значение в свою секретную степень: оба получают *g^(ab)*. Наблюдатель видит *g^a* и *g^b*, но вычислить по ним *g^(ab)* не может — это задача дискретного логарифма. В эллиптическом варианте операции выполняются над точками кривой. Если для каждого соединения генерируются новые временные ключи, кража долговременного ключа сервера не позволит расшифровать записанный ранее трафик — это свойство **прямой секретности** (*forward secrecy*). ## Подписи и доверие Цифровая подпись — это хеш данных (см. [Хеш-функция](https://llmdocs.ru/wiki/hash-function.md)), обработанный закрытым ключом. Проверка открытым ключом подтверждает, что данные подписал владелец ключа и что они не изменились. Но остаётся вопрос: откуда известно, что открытый ключ принадлежит именно тому, за кого себя выдаёт? Решения: - **Инфраструктура открытых ключей (PKI)** — центры сертификации подписывают сертификаты, связывающие ключ с доменом или организацией (см. [Сертификат X.509 и центры сертификации](https://llmdocs.ru/wiki/x509-certificates.md), [Let's Encrypt и ACME](https://llmdocs.ru/wiki/lets-encrypt-acme.md)). - **Доверие при первом подключении** (TOFU) — как в SSH: отпечаток ключа сервера запоминается при первом входе. - **Сеть доверия** — как в PGP: пользователи подписывают ключи друг друга. ## Практика ```bash ssh-keygen -t ed25519 -C "alice@laptop" # пара ключей для SSH openssl genpkey -algorithm ed25519 -out key.pem # закрытый ключ openssl pkey -in key.pem -pubout -out pub.pem # открытый ключ из закрытого git config --global gpg.format ssh # подпись коммитов Git SSH-ключом ``` Закрытый ключ нужно хранить с правами только для владельца, по возможности защищать паролем или держать в аппаратном модуле (YubiKey, TPM, HSM). Утечка закрытого ключа означает, что ключ нужно немедленно отозвать и заменить. ## Квантовая угроза Алгоритм Шора (1994) позволит достаточно мощному квантовому компьютеру взломать RSA и эллиптическую криптографию. Таких компьютеров пока нет, но зашифрованный трафик можно записать сейчас и расшифровать позже. В 2024 году NIST утвердил первые **постквантовые стандарты**: ML-KEM для обмена ключами и ML-DSA и SLH-DSA для подписей.[5] Браузеры и крупные сервисы уже используют гибридный обмен ключами X25519 + ML-KEM в TLS, а OpenSSH включил постквантовый обмен ключами по умолчанию. ## См. также - [TLS](https://llmdocs.ru/wiki/tls.md) - [SSH](https://llmdocs.ru/wiki/ssh.md) - [Хеш-функция](https://llmdocs.ru/wiki/hash-function.md) - [Симметричное шифрование (AES, ChaCha20)](https://llmdocs.ru/wiki/symmetric-encryption.md) - [Сертификат X.509 и центры сертификации](https://llmdocs.ru/wiki/x509-certificates.md) ## Источники 1. [W. Diffie, M. Hellman — New Directions in Cryptography (1976)](https://ee.stanford.edu/~hellman/publications/24.pdf) 2. [R. Rivest, A. Shamir, L. Adleman — A Method for Obtaining Digital Signatures and Public-Key Cryptosystems (CACM, 1978)](https://dl.acm.org/doi/10.1145/359340.359342) 3. [RFC 7748 — Elliptic Curves for Security (X25519, X448)](https://www.rfc-editor.org/rfc/rfc7748) 4. [RFC 8032 — Edwards-Curve Digital Signature Algorithm (EdDSA)](https://www.rfc-editor.org/rfc/rfc8032) 5. [NIST — FIPS 203, Module-Lattice-Based Key-Encapsulation Mechanism Standard](https://csrc.nist.gov/pubs/fips/203/final) 6. [RFC 8446 — The Transport Layer Security (TLS) Protocol Version 1.3](https://www.rfc-editor.org/rfc/rfc8446) --- # Управление секретами > Практики и инструменты для хранения, передачи, ротации и аудита паролей, API-ключей, токенов и закрытых ключей так, чтобы они не попадали в код, логи и репозитории. Источник: https://llmdocs.ru/wiki/secrets-management/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Что такое секрет**: пароль БД, API-ключ, токен, закрытый ключ, сертификат - **Главное правило**: не хранить секреты в коде и git - **Хранилища**: HashiCorp Vault / OpenBao, AWS Secrets Manager, GCP Secret Manager, Azure Key Vault - **Шифрование в git**: SOPS, age, git-crypt, Sealed Secrets - **Поиск утечек**: gitleaks, trufflehog, GitHub secret scanning - **В Kubernetes**: Secret, External Secrets Operator, CSI Secrets Store **Управление секретами** (англ. *secrets management*) — совокупность практик и инструментов для работы с чувствительными учётными данными: паролями баз данных, API-ключами, токенами доступа, закрытыми ключами [TLS](https://llmdocs.ru/wiki/tls.md) и [SSH](https://llmdocs.ru/wiki/ssh.md). Задача — чтобы секрет был доступен ровно тем программам и людям, которым он нужен, не утекал в исходный код, логи и образы, мог быть быстро заменён и чтобы каждое обращение к нему оставляло след.[1] ## Почему это проблема Самая частая утечка — секрет, закоммиченный в [Git](https://llmdocs.ru/wiki/git.md). Удаление файла следующим коммитом не помогает: значение остаётся в истории, в форках и клонах, а публичные репозитории сканируются ботами в течение минут после пуша. Другие типичные пути утечки — образы контейнеров со скопированным `.env`, логи и трассировки ошибок, переменные в выводе CI, общие чаты и вики, ноутбуки Jupyter. ## Жизненный цикл секрета 1. **Создание** — генерация достаточно длинного случайного значения (не придуманного человеком). 2. **Хранение** — в зашифрованном виде, в одном доверенном месте. 3. **Доставка** — приложению во время запуска, а не во время сборки. 4. **Использование** — с [минимальными правами](https://llmdocs.ru/wiki/least-privilege.md): у каждого сервиса свой ключ. 5. **Ротация** — регулярная замена и немедленная замена при подозрении на утечку. 6. **Отзыв и аудит** — журнал: кто, когда и какой секрет прочитал. ## Способы хранения ### Переменные окружения и файлы Методология Twelve-Factor App предлагает отделять конфигурацию от кода через [переменные окружения](https://llmdocs.ru/wiki/environment-variables.md).[7] Это лучше, чем константы в коде, но переменные видны дочерним процессам, попадают в дампы и `/proc//environ`, а файл `.env` легко случайно закоммитить. Распространённый компромисс — `.env` только локально и в `.gitignore`, а в рабочей среде — файл с правами `0600` или монтируемый том в памяти (tmpfs). ### Шифрование в репозитории Секреты можно хранить в git зашифрованными. **SOPS** шифрует значения в YAML/JSON/ENV-файлах, оставляя ключи читаемыми, что удобно для ревью и diff; ключи берутся из age, PGP или облачного KMS.[3] ```bash sops --encrypt --age age1q...xyz secrets.yaml > secrets.enc.yaml sops exec-env secrets.enc.yaml './run-app' ``` Аналоги — git-crypt, а в [Kubernetes](https://llmdocs.ru/wiki/kubernetes.md) — Sealed Secrets, где шифрованный ресурс расшифровывает только контроллер в кластере. ### Централизованные хранилища **HashiCorp Vault** (и его открытый форк **OpenBao**) — сервер, который хранит секреты зашифрованными, выдаёт их по политикам после аутентификации клиента (токен, Kubernetes ServiceAccount, облачная роль, OIDC) и ведёт журнал аудита.[2] Его сильная сторона — **динамические секреты**: вместо постоянного пароля к [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) Vault создаёт для каждого клиента временного пользователя БД с ограниченным сроком жизни и сам удаляет его по истечении. Облачные аналоги — AWS Secrets Manager, GCP Secret Manager, Azure Key Vault, Yandex Lockbox. ### Kubernetes Объект [Secret](https://llmdocs.ru/wiki/configmap-secret.md) по умолчанию хранится в etcd лишь в base64 — это кодирование, а не шифрование. Рекомендации:[4] включить шифрование etcd, ограничить RBAC-доступ к секретам, монтировать их как файлы, а не переменные, и синхронизировать из внешнего хранилища через External Secrets Operator или CSI Secrets Store Driver. ## Секреты в CI/CD Системы [CI/CD](https://llmdocs.ru/wiki/ci-cd.md) имеют встроенные хранилища (GitHub Actions secrets, GitLab CI variables) и маскируют значения в логах — но маскировка ломается при любом преобразовании строки. Лучше вообще не хранить долгоживущие облачные ключи: GitHub Actions и GitLab CI умеют получать **OIDC-токен** и обменивать его на короткоживущие облачные учётные данные. Секреты не должны быть доступны сборкам из форков. ## Обнаружение утечек - **pre-commit** с gitleaks или trufflehog не даёт закоммитить строку, похожую на ключ.[6] - GitHub secret scanning и push protection проверяют пуши и уведомляют провайдеров, которые автоматически отзывают найденные ключи.[5] - Периодическое сканирование истории и образов контейнеров. ## Если секрет утёк 1. **Сначала отозвать и заменить** — это единственное, что действительно помогает. 2. Проверить журналы использования за период утечки. 3. Только потом чистить историю (`git filter-repo`), понимая, что копии уже могли разойтись. 4. Разобрать причину: почему секрет оказался там, где его не должно быть. ## См. также - [Хранение паролей (bcrypt, Argon2)](https://llmdocs.ru/wiki/password-storage.md) - [Криптография с открытым ключом](https://llmdocs.ru/wiki/public-key-cryptography.md) - [GitHub Actions](https://llmdocs.ru/wiki/github-actions.md) - [Infrastructure as Code](https://llmdocs.ru/wiki/infrastructure-as-code.md) ## Источники 1. [OWASP — Secrets Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html) 2. [HashiCorp Vault documentation](https://developer.hashicorp.com/vault/docs) 3. [SOPS — Secrets OPerationS](https://getsops.io/) 4. [Kubernetes — Good practices for Kubernetes Secrets](https://kubernetes.io/docs/concepts/security/secrets-good-practices/) 5. [GitHub Docs — About secret scanning](https://docs.github.com/en/code-security/secret-scanning/introduction/about-secret-scanning) 6. [gitleaks](https://github.com/gitleaks/gitleaks) 7. [The Twelve-Factor App — III. Config](https://12factor.net/config) --- # SQL-инъекция (как защищаться) > Уязвимость, при которой данные пользователя попадают в текст SQL-запроса как код; главная защита — параметризованные запросы, дополнительная — белые списки, ORM и минимальные права в БД. Источник: https://llmdocs.ru/wiki/sql-injection/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Тип**: инъекция кода (CWE-89) - **Категория OWASP**: A03:2021 Injection - **Причина**: склейка SQL-запроса из строк с пользовательскими данными - **Главная защита**: параметризованные (подготовленные) запросы - **Дополнительно**: белые списки для имён, ORM, минимальные права, WAF - **Инструменты проверки**: sqlmap, Semgrep, Bandit **SQL-инъекция** (англ. *SQL injection*, SQLi) — уязвимость, при которой данные, пришедшие от пользователя, попадают в текст [SQL](https://llmdocs.ru/wiki/sql.md)-запроса и интерпретируются базой данных как часть команды.[2] Атакующий может прочитать чужие данные, обойти проверку пароля, изменить или удалить таблицы, а в некоторых СУБД — выполнить команды операционной системы. Инъекции десятилетиями входят в [OWASP Top 10](https://llmdocs.ru/wiki/owasp-top-10.md) (категория A03:2021).[3] ## Как возникает Причина всегда одна — запрос собирается склейкой строк: ```python # УЯЗВИМО name = request.args["name"] cur.execute(f"SELECT * FROM users WHERE name = '{name}'") ``` Если передать `name = ' OR '1'='1`, запрос станет ```sql SELECT * FROM users WHERE name = '' OR '1'='1' ``` и вернёт всех пользователей. Значение `'; DROP TABLE users; --` в драйверах, допускающих несколько команд в одном вызове, удалит таблицу. На практике чаще встречаются более тонкие варианты: - **UNION-инъекция** — к исходному запросу дописывается `UNION SELECT` из другой таблицы, например с хешами паролей. - **Слепая инъекция** — результат не виден, но атакующий задаёт вопросы «да/нет» и наблюдает за разницей в ответе или временем (`pg_sleep(5)`). - **Инъекция второго порядка** — значение сначала безопасно сохраняется в базу, а потом другой код достаёт его и склеивает в новый запрос. - Инъекции в `ORDER BY`, имена столбцов и таблиц, `LIMIT` — там, где обычные параметры не работают. ## Главная защита: параметризованные запросы В **параметризованном** (подготовленном, *prepared*) запросе текст SQL и данные передаются в СУБД раздельно. База сначала разбирает запрос с заполнителями, а значения подставляет как данные — они никогда не станут кодом, какие бы кавычки в них ни были.[1] ```python # Python, psycopg (PostgreSQL) cur.execute("SELECT * FROM users WHERE name = %s", (name,)) # sqlite3 cur.execute("SELECT * FROM users WHERE name = ?", (name,)) ``` ```go // Go, database/sql row := db.QueryRowContext(ctx, "SELECT id FROM users WHERE name = $1", name) ``` Стиль заполнителей зависит от драйвера (`?`, `%s`, `$1`, `:name` — их перечисляет PEP 249[4]), но принцип один: **никогда не форматировать SQL строковыми операциями** — ни f-строками, ни `%`, ни `+`, ни `.format()`. Важно: `%s` в psycopg — это заполнитель драйвера, а не форматирование Python; значение передаётся вторым аргументом.[5] ## Когда параметры не помогают Заполнителем можно заменить только **значение**, но не идентификатор (имя таблицы или столбца) и не ключевое слово (`ASC`/`DESC`). Для таких мест: - **Белый список**: сопоставить ввод с заранее известными вариантами. ```python SORT = {"name": "name", "date": "created_at"} col = SORT.get(request.args.get("sort"), "created_at") order = "DESC" if request.args.get("dir") == "desc" else "ASC" cur.execute(f"SELECT * FROM posts ORDER BY {col} {order} LIMIT %s", (limit,)) ``` - Если нужен динамический идентификатор, использовать безопасный построитель драйвера, например `psycopg.sql.Identifier`, который корректно экранирует имя. Ручное экранирование кавычек (`replace("'", "''")`) — ненадёжная и устаревшая защита: легко забыть место, ошибиться с кодировкой или контекстом. ## ORM и построители запросов [ORM](https://llmdocs.ru/wiki/orm.md) (SQLAlchemy, Django ORM, GORM, Prisma) параметризуют запросы автоматически, поэтому обычный код через них безопасен. Уязвимости возвращаются, когда разработчик спускается к «сырому» SQL: `text(f"...")`, `.raw()`, `.extra()`, `whereRaw` со склейкой строк. Правило то же — сырые запросы только с параметрами. ## Эшелонированная защита Параметризация устраняет причину; остальные меры уменьшают ущерб, если где-то ошибка всё же осталась: - **Минимальные права** учётной записи приложения в БД: только нужные таблицы и операции, без `DROP`, без прав суперпользователя и доступа к файловой системе (см. [Принцип наименьших привилегий](https://llmdocs.ru/wiki/least-privilege.md)). - Запрет нескольких команд в одном вызове на уровне драйвера. - Скрытие подробных ошибок СУБД от пользователя — они сильно облегчают слепые инъекции. - Валидация типов на входе (число — это число, UUID — это UUID). - Статический анализ: Semgrep, Bandit (правило B608), CodeQL находят склейку строк в `execute`. - Тестирование: sqlmap автоматически ищет и эксплуатирует инъекции — применять только к своим системам.[6] - WAF отсекает типовые полезные нагрузки, но легко обходится и не заменяет исправления кода. ## Родственные уязвимости Тот же класс ошибок — смешение кода и данных — встречается в командах ОС (shell injection), шаблонизаторах (SSTI), запросах к NoSQL-базам (операторы `$where`, `$ne` в MongoDB), LDAP и XPath. В приложениях с языковыми моделями аналогом стала [prompt injection](https://llmdocs.ru/wiki/prompt-injection.md), у которой, в отличие от SQL, нет полного решения вроде параметризации. ## См. также - [OWASP Top 10](https://llmdocs.ru/wiki/owasp-top-10.md) - [PostgreSQL](https://llmdocs.ru/wiki/postgresql.md) - [XSS (как защищаться)](https://llmdocs.ru/wiki/xss.md) - [Транзакция и ACID](https://llmdocs.ru/wiki/transaction-acid.md) ## Источники 1. [OWASP — SQL Injection Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/SQL_Injection_Prevention_Cheat_Sheet.html) 2. [MITRE CWE-89 — Improper Neutralization of Special Elements used in an SQL Command](https://cwe.mitre.org/data/definitions/89.html) 3. [OWASP Top 10:2021 — A03 Injection](https://owasp.org/Top10/A03_2021-Injection/) 4. [Python DB-API — PEP 249](https://peps.python.org/pep-0249/) 5. [psycopg — Passing parameters to SQL queries](https://www.psycopg.org/psycopg3/docs/basic/params.html) 6. [sqlmap — automatic SQL injection tool](https://sqlmap.org/) --- # Симметричное шифрование (AES, ChaCha20) > Шифрование, при котором один и тот же секретный ключ используется для зашифрования и расшифрования; современные алгоритмы AES и ChaCha20 в режимах аутентифицированного шифрования. Источник: https://llmdocs.ru/wiki/symmetric-encryption/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Принцип**: общий секретный ключ у отправителя и получателя - **Основные алгоритмы**: AES (128/192/256 бит), ChaCha20 - **Режимы**: GCM, CTR, CBC (устаревающий), XTS (диски) - **Аутентифицированное шифрование**: AES-GCM, ChaCha20-Poly1305 - **Устаревшие**: DES, 3DES, RC4 - **Российские стандарты**: «Кузнечик», «Магма» (ГОСТ Р 34.12-2015) **Симметричное шифрование** — класс алгоритмов, в которых один и тот же секретный ключ используется и для зашифрования, и для расшифрования данных. Оно на порядки быстрее [асимметричного](https://llmdocs.ru/wiki/public-key-cryptography.md) и поэтому шифрует практически весь реальный трафик и хранимые данные: в [TLS](https://llmdocs.ru/wiki/tls.md) и [SSH](https://llmdocs.ru/wiki/ssh.md) асимметричная криптография лишь договаривается об общем ключе, а дальше данные шифруются симметрично. Сегодняшние стандарты — **AES** и **ChaCha20**, применяемые в режимах **аутентифицированного шифрования** (AEAD), которые одновременно скрывают содержимое и обнаруживают подделку.[4] ## История Стандарт DES (1977) с 56-битным ключом к концу 1990-х стал уязвим к перебору — в 1998 году специальная машина взломала его за 56 часов. Временной заменой служил 3DES. В 1997 году NIST объявил открытый конкурс, победителем которого в 2000 году стал алгоритм **Rijndael** бельгийских криптографов Йоана Дамена и Винсента Рэймена; в 2001 году он был утверждён как **AES**.[1] **ChaCha20** — потоковый шифр Дэниела Бернстайна (2008), вместе с кодом аутентификации Poly1305 стандартизированный IETF и вошедший в TLS 1.3.[2] Потоковый шифр RC4, долго применявшийся в SSL и Wi-Fi (WEP), запрещён из-за статистических слабостей. ## Блочные и потоковые шифры - **Блочный шифр** (AES) преобразует блок фиксированного размера — 128 бит — под управлением ключа. Чтобы шифровать данные произвольной длины, нужен **режим работы**. - **Потоковый шифр** (ChaCha20) генерирует из ключа и одноразового числа (nonce) псевдослучайную гамму, которая складывается с данными по XOR. ## Режимы работы | Режим | Свойства | Применение | |---|---|---| | ECB | одинаковые блоки дают одинаковый шифртекст | **не использовать** | | CBC | цепочка блоков, нужен случайный IV и отдельный MAC | устаревшие системы | | CTR | блочный шифр как потоковый | основа GCM | | **GCM** | CTR + аутентификация (GHASH) | TLS, IPsec, большинство API[3] | | XTS | шифрование секторов диска | FileVault, BitLocker, LUKS | Классическая иллюстрация опасности ECB — зашифрованное изображение, на котором по-прежнему видны контуры исходной картинки. ## Аутентифицированное шифрование Шифрование без проверки целостности опасно: злоумышленник может менять шифртекст, и в ряде режимов это предсказуемо меняет расшифрованные данные или даёт атаку через сообщения об ошибках (padding oracle). **AEAD** (*authenticated encryption with associated data*) объединяет шифрование и код аутентификации и позволяет защитить от подделки также незашифрованные «связанные данные» — например, заголовки пакета.[4] - **AES-GCM** — очень быстр на процессорах с аппаратными инструкциями AES-NI (практически все современные x86 и ARM). - **ChaCha20-Poly1305** — быстр в программной реализации, безопаснее на устройствах без аппаратного AES и менее подвержен атакам по времени; предпочтителен на мобильных и встроенных системах. ## Одноразовые числа Оба AEAD требуют **nonce** (обычно 96 бит), который **никогда не должен повторяться** с тем же ключом. Повтор nonce в GCM катастрофичен: раскрывает XOR открытых текстов и позволяет подделывать сообщения. Решения: счётчик, случайный nonce при умеренном числе сообщений на ключ, или варианты с увеличенным nonce — XChaCha20-Poly1305 (192 бита) и AES-GCM-SIV, устойчивый к повторам. ```python from cryptography.hazmat.primitives.ciphers.aead import ChaCha20Poly1305 import os key = ChaCha20Poly1305.generate_key() # 256 бит aead = ChaCha20Poly1305(key) nonce = os.urandom(12) ct = aead.encrypt(nonce, b"secret message", b"header-v1") pt = aead.decrypt(nonce, ct, b"header-v1") # исключение при подделке ``` Высокоуровневые библиотеки вроде libsodium (`crypto_secretbox`, `crypto_aead_xchacha20poly1305`) и Fernet в Python выбирают алгоритм и nonce за программиста — это предпочтительнее, чем собирать конструкцию из примитивов самому.[5][6] ## Длина ключа AES-128 по-прежнему считается стойким; AES-256 и ChaCha20 (256 бит) выбирают с запасом, в том числе на случай квантовых компьютеров: алгоритм Гровера сокращает стойкость перебора примерно вдвое по битам, так что 256-битный ключ остаётся надёжным. Ключи генерируют криптографически стойким генератором, а из паролей выводят специальными функциями (Argon2, scrypt; см. [Хранение паролей (bcrypt, Argon2)](https://llmdocs.ru/wiki/password-storage.md)). Хранение и ротация ключей — отдельная задача [управления секретами](https://llmdocs.ru/wiki/secrets-management.md). ## Российские стандарты ГОСТ Р 34.12-2015 определяет блочные шифры «Кузнечик» (128-битный блок) и «Магма» (64-битный блок, наследник ГОСТ 28147-89) с 256-битным ключом.[7] Они обязательны в ряде государственных систем и поддерживаются в отечественных сборках OpenSSL и TLS. ## См. также - [Криптография с открытым ключом](https://llmdocs.ru/wiki/public-key-cryptography.md) - [Хеш-функция](https://llmdocs.ru/wiki/hash-function.md) - [TLS](https://llmdocs.ru/wiki/tls.md) - [Управление секретами](https://llmdocs.ru/wiki/secrets-management.md) - [SSH](https://llmdocs.ru/wiki/ssh.md) ## Источники 1. [NIST FIPS 197 — Advanced Encryption Standard (AES)](https://csrc.nist.gov/pubs/fips/197/final) 2. [RFC 8439 — ChaCha20 and Poly1305 for IETF Protocols](https://www.rfc-editor.org/rfc/rfc8439) 3. [NIST SP 800-38D — Galois/Counter Mode (GCM)](https://csrc.nist.gov/pubs/sp/800/38/d/final) 4. [RFC 5116 — An Interface and Algorithms for Authenticated Encryption](https://www.rfc-editor.org/rfc/rfc5116) 5. [libsodium — документация](https://doc.libsodium.org/) 6. [Python cryptography — AEAD](https://cryptography.io/en/latest/hazmat/primitives/aead/) 7. [RFC 7801 — GOST R 34.12-2015: Block Cipher Kuznyechik](https://www.rfc-editor.org/rfc/rfc7801) --- # Двухфакторная аутентификация > Подтверждение входа двумя независимыми факторами — знанием, владением и биометрией; одноразовые коды SMS и TOTP, push, аппаратные ключи и passkeys. Источник: https://llmdocs.ru/wiki/two-factor-auth/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Факторы**: знание (пароль), владение (телефон, ключ), неотъемлемость (биометрия) - **Одноразовые коды**: HOTP (RFC 4226), TOTP (RFC 6238) - **Стойкие к фишингу**: FIDO2/WebAuthn — аппаратные ключи, passkeys - **Слабые варианты**: SMS, звонок, коды по email - **Приложения TOTP**: Google Authenticator, Яндекс Ключ, Aegis, 2FAS, менеджеры паролей **Двухфакторная аутентификация** (2FA), или в общем случае **многофакторная** (MFA), — способ подтверждения личности, при котором пользователь предъявляет два или более доказательства **разных типов**: что-то, что он знает (пароль), что-то, чем он владеет (телефон, аппаратный ключ), или что-то, чем он является (отпечаток пальца, лицо). Утечка пароля сама по себе тогда не даёт доступа к аккаунту. По оценкам крупных провайдеров, включённая MFA блокирует подавляющее большинство автоматизированных атак на учётные записи, поэтому её требуют для администраторов, разработчиков, банков и всё чаще — для всех пользователей.[7] Общая картина проверки личности и прав — в статье [Аутентификация и авторизация](https://llmdocs.ru/wiki/authn-authz.md). ## Факторы | Фактор | Примеры | Слабости | |---|---|---| | Знание | пароль, PIN, ответ на секретный вопрос | фишинг, утечки, повторное использование | | Владение | телефон с приложением, SIM-карта, аппаратный ключ, смарт-карта | потеря, кража, перевыпуск SIM | | Неотъемлемость | отпечаток, Face ID | нельзя сменить; обычно лишь разблокирует локальный ключ | Пароль и секретный вопрос — это два знания, а не два фактора. Биометрия в современных системах почти всегда проверяется локально на устройстве и разблокирует криптографический ключ, а не отправляется на сервер. ## Способы второго фактора От слабых к сильным: - **SMS и звонок** — код приходит на номер телефона. Уязвимы к перевыпуску SIM-карты мошенниками (SIM swap), перехвату через уязвимости сети SS7 и фишингу; NIST относит их к ограниченно допустимым.[5] Тем не менее это намного лучше, чем один пароль. - **Код по email** — безопасность равна безопасности почтового ящика. - **TOTP** — приложение-аутентификатор генерирует шестизначный код, меняющийся каждые 30 секунд.[1] - **Push-подтверждение** — запрос «Это вы входите?» в приложении. Уязвимо к «бомбардировке» запросами (MFA fatigue), пока пользователь не нажмёт «да»; помогает показ числа, которое нужно ввести. - **Аппаратные ключи и passkeys** (FIDO2/WebAuthn) — криптографическая проверка, устойчивая к фишингу.[3] ## Как работает TOTP При включении сервер и приложение получают общий секрет — обычно через QR-код с URI `otpauth://totp/…?secret=…`. Код вычисляется как [HMAC](https://llmdocs.ru/wiki/hash-function.md) от секрета и номера текущего 30-секундного интервала, усечённый до 6 цифр. Предшественник — **HOTP** — использует счётчик вместо времени.[2] Серверу нужно принимать коды из соседних интервалов на случай расхождения часов и запрещать повторное использование кода. ```python import pyotp secret = pyotp.random_base32() # хранить зашифрованным uri = pyotp.TOTP(secret).provisioning_uri(name="user@example.ru", issuer_name="llmdocs") # → QR-код pyotp.TOTP(secret).verify("492039", valid_window=1) ``` TOTP не защищает от фишинга: поддельный сайт просит ввести код и тут же использует его на настоящем (атаки типа adversary-in-the-middle с инструментами вроде Evilginx). ## FIDO2, WebAuthn и passkeys Стандарты FIDO Alliance и W3C WebAuthn заменяют общий секрет парой ключей [асимметричной криптографии](https://llmdocs.ru/wiki/public-key-cryptography.md). При регистрации устройство создаёт ключ, привязанный к домену сайта, и отдаёт серверу только открытую часть; при входе подписывает случайный вызов сервера. Браузер сам сообщает устройству домен, поэтому на фишинговом сайте ключ просто не сработает — это главное преимущество.[6] - **Аппаратные ключи** (YubiKey, Рутокен MFA и аналоги) — ключ не покидает устройство. - **Passkeys** — те же ключи FIDO, синхронизируемые через облако Apple, Google, менеджер паролей; могут заменить пароль целиком, объединяя владение (устройство) и биометрию или PIN.[4] ## Восстановление доступа Слабое место любой MFA — сценарий «потерял телефон». Обычные меры: одноразовые **резервные коды**, несколько зарегистрированных ключей, восстановление через поддержку с проверкой личности. Если восстановление сводится к SMS или email, общая стойкость падает до их уровня. Секреты TOTP и резервные коды на стороне сервера хранятся зашифрованными, как и другие [секреты](https://llmdocs.ru/wiki/secrets-management.md). ## Для разработчиков и администраторов - Включить MFA на [GitHub](https://llmdocs.ru/wiki/github.md), у облачного провайдера, регистратора доменов и в почте — компрометация этих аккаунтов ведёт ко всему остальному. - Для [SSH](https://llmdocs.ru/wiki/ssh.md) — ключи вместо паролей, при необходимости ключи на FIDO-токене (`ssh-keygen -t ed25519-sk`). - В своём сервисе — поддержать TOTP и WebAuthn, ограничить число попыток ввода кода, требовать повторную проверку для опасных действий (смена пароля, вывод средств). - При входе через внешних провайдеров по [OAuth 2.0 и OpenID Connect](https://llmdocs.ru/wiki/oauth-oidc.md) MFA обеспечивает провайдер. ## См. также - [Аутентификация и авторизация](https://llmdocs.ru/wiki/authn-authz.md) - [Хранение паролей (bcrypt, Argon2)](https://llmdocs.ru/wiki/password-storage.md) - [OAuth 2.0 и OpenID Connect](https://llmdocs.ru/wiki/oauth-oidc.md) - [Криптография с открытым ключом](https://llmdocs.ru/wiki/public-key-cryptography.md) - [OWASP Top 10](https://llmdocs.ru/wiki/owasp-top-10.md) ## Источники 1. [RFC 6238 — TOTP: Time-Based One-Time Password Algorithm](https://www.rfc-editor.org/rfc/rfc6238) 2. [RFC 4226 — HOTP: An HMAC-Based One-Time Password Algorithm](https://www.rfc-editor.org/rfc/rfc4226) 3. [W3C — Web Authentication (WebAuthn) Level 3](https://www.w3.org/TR/webauthn-3/) 4. [FIDO Alliance — Passkeys](https://fidoalliance.org/passkeys/) 5. [NIST SP 800-63B — Digital Identity Guidelines: Authentication](https://pages.nist.gov/800-63-4/sp800-63b.html) 6. [CISA — Implementing Phishing-Resistant MFA](https://www.cisa.gov/sites/default/files/publications/fact-sheet-implementing-phishing-resistant-mfa-508c.pdf) 7. [OWASP — Multifactor Authentication Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Multifactor_Authentication_Cheat_Sheet.html) --- # XSS (как защищаться) > Межсайтовый скриптинг — внедрение вредоносного JavaScript в страницу сайта; защита — контекстное экранирование, безопасные API шаблонов, санитизация HTML и Content Security Policy. Источник: https://llmdocs.ru/wiki/xss/ · обновлено 2026-11-09 · лицензия CC BY-SA 4.0 - **Полное название**: Cross-Site Scripting - **Классификация**: CWE-79; OWASP Top 10 — A03 Injection - **Виды**: хранимый, отражённый, DOM-based - **Последствия**: кража сессии, действия от имени пользователя, фишинг - **Основная защита**: контекстное экранирование вывода - **Дополнительная защита**: CSP, HttpOnly cookie, Trusted Types - **Библиотеки**: DOMPurify, nh3 / bleach (Python) **XSS** (*Cross-Site Scripting*, межсайтовый скриптинг) — уязвимость веб-приложения, при которой злоумышленник добивается выполнения своего [JavaScript](https://llmdocs.ru/wiki/javascript.md)-кода в браузере других пользователей в контексте уязвимого сайта. Такой скрипт видит всё, что видит пользователь: может прочитать данные страницы, отправить запросы от его имени, подменить форму входа или украсть токен. XSS — одна из самых распространённых веб-уязвимостей; в [OWASP Top 10](https://llmdocs.ru/wiki/owasp-top-10.md) она входит в категорию инъекций.[4] ## Как возникает Причина — данные из недоверенного источника попадают в HTML-страницу без правильной обработки, и браузер интерпретирует их как код. Классический пример на сервере: ```python # уязвимо: строка вставляется в HTML как есть return f"

Результаты поиска: {request.args['q']}

" ``` Запрос `?q=` превращает страницу в инструмент атаки — достаточно заманить жертву по ссылке. ## Виды | Вид | Где живёт полезная нагрузка | Пример | |---|---|---| | **Отражённый** (reflected) | в запросе, возвращается в ответе | параметр поиска в URL | | **Хранимый** (stored) | в базе данных сайта | комментарий, имя профиля, сообщение в чате | | **DOM-based** | обрабатывается JavaScript на клиенте | `location.hash` вставляется через `innerHTML` | Хранимый XSS опаснее всего: срабатывает у каждого, кто откроет страницу, включая администраторов. DOM XSS не доходит до сервера, и серверные фильтры его не видят.[2] ## Главная защита — экранирование по контексту Данные должны вставляться в страницу так, чтобы браузер видел в них только текст. Способ экранирования зависит от **контекста**, куда попадают данные:[1] | Контекст | Что делать | |---|---| | Текст внутри HTML-элемента | HTML-экранирование: `<` → `<`, `&` → `&` и т. д. | | Значение атрибута | экранирование атрибута, значение всегда в кавычках | | URL в `href`, `src` | проверять схему (только `http:`/`https:`), запрещать `javascript:` | | Внутри ` ``` - `` включает стандартный режим отображения. - В `` — метаданные: кодировка (только [UTF-8](https://llmdocs.ru/wiki/unicode-utf8.md)), заголовок вкладки, стили, описание для поисковиков. - В `` — видимое содержимое. - Атрибут `lang` помогает экранным дикторам и переводчикам, `viewport` — корректному отображению на телефонах. ## Семантика Хорошая разметка описывает **смысл**, а не оформление. Вместо безликих `
` для всего подряд используют элементы, говорящие о роли содержимого: | Элемент | Назначение | |---|---| | `
`, `