commit e324c5a253d63ccbb7e7962617b5b9675630c6df Author: Struchkov Mark Date: Sat Jan 11 10:37:51 2025 +0300 Initial commit diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 00000000..88835409 --- /dev/null +++ b/.drone.yml @@ -0,0 +1,71 @@ +--- +kind: pipeline +type: docker +name: docker-build-and-push + +clone: + disable: true + +trigger: + branch: + - master + +image_pull_secrets: + - DOCKER_AUTH + +steps: + - name: build site + # https://hub.docker.com/r/library/docker + pull: always + image: docker.struchkov.dev/quartz:develop + environment: + GITHUB_SSH: + from_secret: GITHUB_SSH + commands: + - eval $(ssh-agent -s) + - mkdir -p ~/.ssh + - chmod 700 ~/.ssh + - echo "$GITHUB_SSH" >> ~/.ssh/id_rsa + - chmod 600 ~/.ssh/id_rsa + - ssh-keyscan github.com >> ~/.ssh/known_hosts + - chmod 644 ~/.ssh/known_hosts + - git clone --depth 1 --single-branch --branch master https://git.struchkov.dev/upagge/digital-garden.git /usr/src/app/content + - cd /usr/src/app/content +# - git remote add github git@github.com:uPagge/digital-garden.git +# - git push github + - cd /usr/src/app + - cp ./content/.quartz/quartz.config.ts . + - cp ./content/.quartz/quartz.layout.ts . + - npx quartz build + - mv public /drone/src + - name: publish to server + image: private.docker.struchkov.dev/mkdocs:latest + environment: + SSH_DEPLOY_KEY: + from_secret: SSH_DEPLOY_KEY + SSH_DEPLOY_HOST: + from_secret: SSH_DEPLOY_HOST + SSH_DEPLOY_PORT: + from_secret: SSH_DEPLOY_PORT + SSH_DEPLOY_PATH: + from_secret: SSH_DEPLOY_PATH + SSH_DEPLOY_USER: + from_secret: SSH_DEPLOY_USER + commands: + - eval $(ssh-agent -s) + - mkdir -p ~/.ssh + - echo "$SSH_DEPLOY_KEY" >> ~/.ssh/id_rsa + - chmod 700 ~/.ssh + - chmod 600 ~/.ssh/id_rsa + - ssh-keyscan -p $SSH_DEPLOY_PORT $SSH_DEPLOY_HOST >> ~/.ssh/known_hosts + - chmod 644 ~/.ssh/known_hosts + - tar czf - -C ./public . | ssh -p $SSH_DEPLOY_PORT $SSH_DEPLOY_USER@$SSH_DEPLOY_HOST "cd $SSH_DEPLOY_PATH/ru-new && tar xzf -" + - ssh -p $SSH_DEPLOY_PORT $SSH_DEPLOY_USER@$SSH_DEPLOY_HOST "rm -rf $SSH_DEPLOY_PATH/ru/* && mv $SSH_DEPLOY_PATH/ru-new/* $SSH_DEPLOY_PATH/ru" + + +# drone sign --save upagge/digital-garden +--- +kind: signature +hmac: 136d4effa27f318fb6ff0cf16bc1bf7b20b428610832f7bdd8224c164a804e69 + +... diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..35dd76a8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +.obsidian/workspace.json +.obsidian/workspace-mobile.json + +# Ignore Smart Connections folder because embeddings file is large and updated frequently +.smart-connections + +.DS_Store +.idea/ +/meta/files/zip_image.sh +/meta/files/zip_image_compression.log +/meta/files/zip_image_error.log \ No newline at end of file diff --git a/.quartz/quartz.config.ts b/.quartz/quartz.config.ts new file mode 100644 index 00000000..8b457835 --- /dev/null +++ b/.quartz/quartz.config.ts @@ -0,0 +1,91 @@ +import { QuartzConfig } from "./quartz/cfg" +import * as Plugin from "./quartz/plugins" + +/** + * Quartz 4.0 Configuration + * + * See https://quartz.jzhao.xyz/configuration for more information. + */ +const config: QuartzConfig = { + configuration: { + pageTitle: "Struchkov's Garden 🪴", + enableSPA: false, + enablePopovers: true, + locale: "ru-RU", + baseUrl: "garden.struchkov.dev/ru", + ignorePatterns: ["private", "templates", ".obsidian"], + defaultDateType: "modified", + theme: { + fontOrigin: "googleFonts", + cdnCaching: true, + typography: { + header: "Montserrat", + body: "Noto Sans", + code: "Fira Code", + }, + colors: { + lightMode: { + light: "#faf8f8", + lightgray: "#e5e5e5", + gray: "#b8b8b8", + darkgray: "#292929", + dark: "#2b2b2b", + secondary: "#2c678d", + tertiary: "#84a59d", + highlight: "rgba(0, 80, 219, 0.15)", + textHighlight: "#fff3bc", + shareIcon: "https://garden.struchkov.dev/ru/static/social-sprite-color.svg" + }, + darkMode: { + light: "#161618", + lightgray: "#393639", + gray: "#646464", + darkgray: "#d4d4d4", + dark: "#ebebec", + secondary: "#7b97aa", + tertiary: "#84a59d", + highlight: "rgba(143, 159, 169, 0.15)", + textHighlight: "#8b651d", + shareIcon: "https://garden.struchkov.dev/ru/static/social-sprite.svg" + }, + }, + }, + }, + plugins: { + transformers: [ + Plugin.FrontMatter(), + Plugin.CreatedModifiedDate({ + priority: ["git", "frontmatter"], + }), + Plugin.SyntaxHighlighting({ + theme: { + light: "github-light", + dark: "vitesse-dark", + }, + keepBackground: false, + }), + Plugin.HardLineBreaks(), + Plugin.ObsidianFlavoredMarkdown({ enableInHtmlEmbed: false }), + Plugin.GitHubFlavoredMarkdown(), + Plugin.TableOfContents(), + Plugin.CrawlLinks({ markdownLinkResolution: "relative", lazyLoad: true }), + Plugin.Description(), + ], + filters: [Plugin.RemoveDrafts()], + emitters: [ + Plugin.AliasRedirects(), + Plugin.ComponentResources(), + Plugin.ContentPage(), + Plugin.FolderPage(), + Plugin.TagPage(), + Plugin.ContentIndex({ + enableSiteMap: true, + enableRSS: true, + }), + Plugin.Assets(), + Plugin.Static(), + Plugin.NotFoundPage(), + ], + }, +} +export default config diff --git a/.quartz/quartz.layout.ts b/.quartz/quartz.layout.ts new file mode 100644 index 00000000..2cdf3911 --- /dev/null +++ b/.quartz/quartz.layout.ts @@ -0,0 +1,64 @@ +import {PageLayout, SharedLayout} from "./quartz/cfg" +import * as Component from "./quartz/components" + +// components shared across all pages +export const sharedPageComponents: SharedLayout = { + head: Component.Head(), + header: [], + afterBody: [ + Component.Backlinks(), + // Component.SocialShare(), + Component.Remark({ + options: { + host: 'https://comments.struchkov.dev', + siteId: 'gardenru', + locale: 'ru', + } + }), + Component.YandexMetrika(), + ], + footer: Component.Footer({ + links: { + "About Me": "https://mark.struchkov.dev/cv/", + "B.log": "https://struchkov.dev", + "Telegram": "https://t.me/struchkov_dev", + }, + }), +} +const githubSourceConfig = { + repoLink: "https://github.com/upagge/digital-garden", + branch: "master" +} +// components for pages that display a single page (e.g. a single note) +export const defaultContentPageLayout: PageLayout = { + beforeBody: [ + Component.Breadcrumbs({showCurrentPage: false}), + Component.ArticleTitle(), + Component.ContentMeta({showReadingTime: false}), + Component.TagList() + ], + left: [ + Component.PageTitle(), + Component.MobileOnly(Component.Spacer()), + Component.Search(), + Component.DesktopOnly(Component.RecentNotes({ showTags: false, limit: 4 })), + Component.DesktopOnly(Component.Ads()), + Component.Darkmode(), + ], + right: [ + Component.DesktopOnly(Component.TableOfContents()), + Component.DesktopOnly(Component.GithubSource(githubSourceConfig)), + ], +} + +// components for pages that display lists of pages (e.g. tags or folders) +export const defaultListPageLayout: PageLayout = { + beforeBody: [Component.Breadcrumbs(), Component.ArticleTitle(), Component.ContentMeta()], + left: [ + Component.PageTitle(), + Component.MobileOnly(Component.Spacer()), + Component.Search(), + Component.Darkmode(), + ], + right: [], +} diff --git a/awareness/Медитация.md b/awareness/Медитация.md new file mode 100644 index 00000000..e445df91 --- /dev/null +++ b/awareness/Медитация.md @@ -0,0 +1,33 @@ +--- +tags: + - maturity/🌱 +date: "[[2023-09-20]]" +aliases: + - медитация + - релаксация + - релакс + - медитацией + - медитацию + - медитации +--- +Медитация работает на физиологическом уровне: замедляет дыхание и частоту сердечных сокращений. [Замедляет](https://www.psychologytoday.com/blog/the-mysteries-love/201503/how-deep-relaxation-affects-brain-chemistry) [[../../../knowledge/human/строение/Симпатическая нервная система|симпатическую нервную систему]]. Как результат - снижается уровень [кортизола](Кортизол.md). + +После сессии медитации меняется даже активность мозга во время сна - это видно в исследованиях, проведенных с использованием ЭЭГ. Также эффективный и [доказанный](https://www.researchgate.net/publication/227735096_Practitioners_of_vipassana_meditation_exhibit_enhanced_slow_wave_sleep_and_REM_sleep_states_across_different_age_groups) способ увеличить долю ценного [глубокого сна](Фазы%20сна.md). + +Помимо влияния на сон, медитация имеет много других подтвержденных эффектов, влияющих на продуктивность и не только. В англоязычной Википедии есть [большая статья,](https://en.wikipedia.org/wiki/Research_on_meditation) посвященная не в целом медитации, а именно ее научно доказанным свойствам. В частности, она очень эффективна против [стресса](Стресс.md). А в [[2019]] году в течение 3-недельного эксперимента благодаря медитации испытуемые [стали удерживать внимание на 24% эффективнее.](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC6329416/) + +Многие ошибочно полагают, что медитировать можно только сидя в позе лотоса, с закрытыми глазами и обязательно под музыку или речь диктора. Но это совсем не так. Медитировать и тренировать внимание можно во время любых действий, которые обычно делаешь на [[Режим автопилота мозга|автоматизме]]. + +Медитация помогает расслабиться и эмоционально, за счет [удаления](https://academic.oup.com/scan/article/2/4/259/1676806/Mindfulness-training-and-neural-integration) ранее сформированных нервных связей. + +*** +## Мета информация +**Область**:: [[../meta/zero/00 Осознанность|00 Осознанность]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2023-09-20]] +### Дополнительные материалы +- [Effects of meditation - Wikipedia](https://en.wikipedia.org/wiki/Effects_of_meditation#Changes_in_the_brain) +### Дочерние заметки + diff --git a/awareness/Практики осознанности.md b/awareness/Практики осознанности.md new file mode 100644 index 00000000..b3a10b3b --- /dev/null +++ b/awareness/Практики осознанности.md @@ -0,0 +1,21 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2025-01-11 +--- +Практики осознанности имеют отличную доказанную эффективность в этом деле, что было показано во [многих исследованиях.](https://en.wikipedia.org/wiki/Effects_of_meditation#cite_note-Walsh_e10844-18) К примеру, в [[2019]] году в течение 3-недельного эксперимента благодаря [[Медитация|медитации]] испытуемые [стали удерживать внимание на 24% эффективнее.](https://www.ncbi.nlm.nih.gov/pmc/articles/PMC6329416/) + +*** +## Мета информация +**Область**:: [[../meta/zero/00 Осознанность|00 Осознанность]] +**Родитель**:: [[../Практики|Практики]] +**Источник**:: +**Создана**:: [[2025-01-11]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/awareness/Режим автопилота мозга.md b/awareness/Режим автопилота мозга.md new file mode 100644 index 00000000..70387a99 --- /dev/null +++ b/awareness/Режим автопилота мозга.md @@ -0,0 +1,24 @@ +--- +aliases: + - автопилот + - автопилоте + - автопилота + - автоматизме +tags: + - maturity/🌱 +date: "[[2023-10-18]]" +--- +Существенная часть жизни людей проходит в «режиме автопилота». Человеческий мозг стремится к оптимизации и экономии [[../../../knowledge/human/ресурсы/Энергия организма|энергии]]. Чтобы делать твое существование более эффективным, часть действий [не осознается](https://www.researchgate.net/publication/227344004_Mindless_Eating_The_200_Daily_Food_Decisions_We_Overlook) и предпринимается на автомате. + +В общем и целом, такой режим весьма полезен — он позволяет не тратить [мыслетопливо](Мыслетопливо.md) на повторяющуюся [рутину](Рутина.md). Но некоторые так сильно привыкают к автопилоту, что ручное управление уже просто не включается. Практики [осознанности](../../../garden/ru/meta/zero/00%20Осознанность.md) как раз помогают сосредоточить свое внимание на текущем моменте и прожить его полноценно. +*** +## Мета информация +**Область**:: [[../meta/zero/00 Осознанность|00 Осознанность]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2023-10-18]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/Code Review.md b/dev/Code Review.md new file mode 100644 index 00000000..e0351587 --- /dev/null +++ b/dev/Code Review.md @@ -0,0 +1,52 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-11-03 +--- +![[../../../meta/files/Pasted image 20241103220651.png]] + +- **Code Style (Стиль кода)**: + - Применен ли стиль форматирования проекта? + - Достаточно ли [[Читаемый код|читаем код]] (длина методов и т.п.)? + - Соблюдается ли принцип DRY (Don't Repeat Yourself)? + - Соответствует ли именование общепринятым соглашениям? +- **Tests (Тесты)**: + - Проходят ли все тесты? + - Новые функции протестированы? + - Покрыты ли крайние случаи? + - Используются ли юнит-тесты и интеграционные тесты? + - Есть ли тесты для нефункциональных требований, например, производительность? +- **Documentation (Документация)**: + - Есть ли документация для новых функций? + - Покрыты ли различные виды документации: README, API, user guide и др.? + - Понятны ли документы, нет ли ошибок в типографике и грамматике? +- **Implementation Semantics (Семантика реализации)**: + - Соответствует ли реализация исходным требованиям? + - Корректна ли логика? + - Нет ли излишней сложности? + - Надежна ли реализация (вопросы конкурентности, обработки ошибок и т.д.)? + - Хорошая ли производительность? + - Безопасна ли (например, отсутствие SQL-инъекций)? + - Можно ли наблюдать за реализацией (метрики, логирование и т.д.)? + - Тянут ли новые зависимости свой вес, приемлема ли их лицензия? +- **API Semantics (Семантика API)**: + - Насколько компактно API, оно достаточно большое или наоборот? + - Есть ли один способ достижения цели, без множественных подходов? + - API предсказуемо, следует ли оно принципу наименьшего удивления? + - Являются ли внутренности API скрытыми от пользователя? + - Нет ли изменений, ломающих обратную совместимость? + - Насколько полезно и не слишком специфично API? +*** +## Мета информация +**Область**:: [[../meta/zero/00 Разработка|00 Разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-03]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/GraphQL.md b/dev/GraphQL.md new file mode 100644 index 00000000..f209c9ff --- /dev/null +++ b/dev/GraphQL.md @@ -0,0 +1,29 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-11-03 +--- +![[../meta/files/images/Pasted image 20241103004648.png]] + +- Предоставляет клиентам единую конечную точку для запроса именно тех данных, которые им нужны. +- Клиенты указывают точные поля, требуемые во вложенных запросах, и сервер возвращает оптимизированный ответ, содержащую только эти поля. +- Поддерживает модификации для изменения данных и подписки на уведомления в режиме реального времени. +- Отлично подходит для объединения данных из нескольких источников и хорошо работает с быстро меняющимися требованиями к интерфейсу. +- Однако это переносит сложность на сторону клиента и может допускать некорректные запросы, если они не защищены должным образом. +- Стратегии кэширования могут быть более сложными, чем [[architecture/Representation State Transfer|REST]]. + + +*** +## Мета информация +**Область**:: [[../meta/zero/00 Архитектура ИС|00 Архитектура ИС]] +**Родитель**:: [[architecture/Протоколы коммуникаций|Протоколы коммуникаций]] +**Источник**:: +**Создана**:: [[2024-11-03]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/Key-Value хранилище.md b/dev/Key-Value хранилище.md new file mode 100644 index 00000000..7a894535 --- /dev/null +++ b/dev/Key-Value хранилище.md @@ -0,0 +1,21 @@ +--- +aliases: + - ключ-значение +tags: + - maturity/🌱 +date: 2024-11-24 +--- + +*** +## Мета информация +**Область**:: [[../meta/zero/00 Разработка|00 Разработка]] +**Родитель**:: [[Тип хранилища данных|Тип хранилища данных]] +**Источник**:: +**Создана**:: [[2024-11-24]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/Tombstone.md b/dev/Tombstone.md new file mode 100644 index 00000000..3ca8442f --- /dev/null +++ b/dev/Tombstone.md @@ -0,0 +1,33 @@ +--- +aliases: + - софт-удаление + - мягкое удаление + - soft-удаление +tags: + - maturity/🌱 +date: 2024-10-31 +--- +**Tombstone** — это маркер, указывающий, что запись удалена логически, но физически все еще находится в базе данных. Такой подход позволяет системе лучше справляться с репликацией и конфликтами данных, а также обеспечивает корректное выполнение запросов к данным, которые могли быть удалены. + +**Плюсы:** +- **Репликация данных**: Tombstones упрощают [[architecture/highload/Репликация БД|репликацию]]. Поскольку данные могут реплицироваться между множеством узлов, простое удаление записи на одном узле не гарантирует, что она будет удалена на всех узлах. Tombstone помогает согласовать состояние данных между узлами. +- **История данных**: В системах, где данные удаляются, но запросы могут возвращаться к старым версиям данных, tombstones позволяют системе правильно обрабатывать такие запросы, показывая, что данные были удалены, а не просто отсутствуют. + +**Особенности:** +- **Процесс Compaction**: Со временем, когда гарантируется, что все узлы системы обновили свое состояние и больше не требуется хранение информации об удалении, tombstones могут быть удалены, чтобы освободить место и улучшить производительность системы. Этот процесс называется compaction. +- **Проблема накопления tombstones**: Накопление большого количества tombstones может замедлить производительность базы данных, так как системе приходится пропускать эти маркеры при выполнении запросов. Это особенно актуально для систем с высокой частотой удаления записей. + - [[database/Частичный индекс|Частичный индекс]] + +*** +## Мета информация +**Область**:: [[../meta/zero/00 Реляционная база данных|00 Реляционная база данных]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-10-31]] +**Автор**:: [[2024-10-31]] +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/Universal Unique IDentifier.md b/dev/Universal Unique IDentifier.md new file mode 100644 index 00000000..211814b8 --- /dev/null +++ b/dev/Universal Unique IDentifier.md @@ -0,0 +1,147 @@ +--- +aliases: + - UUID +tags: + - maturity/🌱 +date: 2023-11-12 +zero-link: +parents: +linked: +--- +**UUID (Universal Unique IDentifier)** — это 128-битный идентификатор, представленный в виде строки. Однако для пользовательских данных доступно только 122 бита, так как 6 бит зарезервировано: +- 4 бита используются для указания версии UUID; +- 2 бита определяют вариант UUID. + +![](../meta/files/images/Pasted%20image%2020231112132644.png) + +**Заполнение 122 бит зависит от версии UUID:** +- **Специальные UUID**: + - **Nil UUID** — все биты равны 0. + - **Max UUID** — все биты равны 1 (или “f” в шестнадцатеричной записи). +- **Стандартные версии UUID** (по спецификации RFC 4122) — всего 5 версий. +- **Новые версии** — три дополнительных варианта, не описанных в RFC 4122. + +## UUID V1 +![](../meta/files/images/Pasted%20image%2020231112133236.png) + +UUID версии 1 использует текущее время по григорианскому календарю и имеет следующие особенности: +- Время записывается в обратном порядке, что делает невозможной сортировку UUID по времени создания. +- Включает случайную компоненту для увеличения уникальности. +- Node ID привязан к сетевому оборудованию (обычно к MAC-адресу). Это значение рекомендуется подменять на псевдослучайное для повышения конфиденциальности. + +**Недостатки:** +- Не подходит для сортировки по времени. + +**Преимущества:** +- Быстрая вставка в базу данных, независимо от размера данных. +- UUID сложно перебрать за счет высокой энтропии. +- Возможность извлечь метку времени из идентификатора. +## UUID V3 +![](../meta/files/images/Pasted%20image%2020231112133916.png) + +UUID версии 3 (V3) — это идентификатор, основанный на алгоритме хеширования [[cryptography/MD5|MD5]]. В отличие от UUID версии 1, который использует текущее время, UUID V3 генерируется на основе имени (строки) и пространства имен (namespace). Основная идея заключается в том, что при использовании одинаковых имени и пространства имен результатом всегда будет один и тот же UUID. + +**Пример использования:** Когда нужно сгенерировать уникальный идентификатор для имени домена в сети, применяется UUID V3 с пространством имен **DNS** и строкой, содержащей доменное имя. Например: + +``` +UUID(DNS, "example.com") → 5df41881-3aed-3515-88a7-2f4a814cf09e +``` + +**Преимущества:** +- **Детерминированность**: один и тот же вход (имя + пространство имен) всегда генерирует одинаковый UUID, что удобно, если требуется уникальный идентификатор для конкретного объекта, который может быть повторно создан. + +**Недостатки:** +- **Зависимость от MD5**: Алгоритм [[cryptography/MD5|MD5]] считается криптографически уязвимым, что делает UUID V3 неподходящим для использования в приложениях, требующих высокой безопасности. +- **Не случайный**: В отличие от UUID версии 1 или 4, UUID V3 предсказуем, так как основывается на статическом входе. +## UUID V4 +![](../meta/files/images/Pasted%20image%2020231112133824.png) + +UUID версии 4 (V4) — это случайный идентификатор, где большинство битов генерируются случайным образом. Вся структура UUID V4 почти полностью случайна, за исключением 6 бит, зарезервированных для указания версии и варианта. + +**Преимущества:** +- **Сложность перебора**: Из-за случайной природы UUID V4 крайне сложно предугадать следующий идентификатор или перебрать все возможные значения. Всего существует 2^{122} возможных вариантов UUID V4, что делает их практически уникальными в реальных условиях. +- **Простота генерации**: Процесс создания UUID V4 не требует внешних данных (время, имя или пространство имен), что делает его проще в реализации и использовании. +- **Конфиденциальность**: Поскольку в UUID V4 нет привязки к времени или аппаратному обеспечению (в отличие от V1), он не раскрывает никакой дополнительной информации, такой как метка времени или MAC-адрес устройства. + +**Недостатки:** +- **Не сортируемый**: UUID V4 нельзя отсортировать по времени или другим критериям, так как он полностью основан на случайных данных. +- **Замедленная вставка в БД**: В больших базах данных, по мере увеличения количества записей, время вставки новых записей с UUID V4 может расти. Это связано с тем, что случайные значения распределяются неравномерно, что может вызывать фрагментацию [[database/Индекс базы данных|индексов]], особенно при использовании кластеризованных индексов. +- **Не содержит полезной информации**: В отличие от UUID версий 1 и 3, UUID V4 не хранит никаких дополнительных данных (например, метку времени или привязку к конкретному объекту). +## UUID V5 +![](../meta/files/images/Pasted%20image%2020231112134012.png) + +UUID версии 5 (V5) очень похож на UUID версии 3 (V3), с той лишь разницей, что вместо [[cryptography/Хеш-функция|хеш-функции]] [[cryptography/MD5|MD5]] используется более современная и безопасная [[cryptography/Хеш-функция|хеш-функция]] SHA-1. Как и в случае с V3, UUID V5 генерируется на основе входных данных — имени и пространства имен (namespace). + +**Преимущества:** +- **Детерминированность**: Как и UUID V3, версия 5 всегда генерирует один и тот же UUID для одного и того же сочетания имени и пространства имен. +- **Современная хеш-функция**: В отличие от устаревшего и криптографически слабого [[cryptography/MD5|MD5]], SHA-1 обеспечивает более высокую безопасность, хотя и не является идеальной для криптографических приложений в наше время. +- **Уникальность в пределах пространства имен**: Гарантирует уникальность идентификаторов при использовании различных пространств имен. + +**Недостатки:** +- **Время вставки в базу данных**: В больших базах данных с увеличением количества записей может увеличиваться время вставки, особенно если UUID используется как индекс. Это связано с неравномерностью распределения случайных значений. +- **Не сортируемый**: Как и UUID V4, идентификаторы версии 5 не могут быть отсортированы по времени или другим логическим критериям, поскольку они зависят от хеширования входных данных. +- **Не хранит полезной информации**: UUID V5 не содержит дополнительных данных, таких как метка времени, информация о хосте или устройстве. +## UUID V6 +![](../meta/files/images/Pasted%20image%2020231112133512.png) + +UUID версии 6 (V6) был разработан для устранения одного из ключевых недостатков UUID версии 1 (V1) — невозможности сортировки. UUID V6 сохраняет идею использования времени для генерации идентификатора, но изменяет порядок записи временной метки, что позволяет идентификаторам быть сортируемыми по времени. + +**Преимущества:** +- **Сортируемость**: Главное отличие UUID V6 от V1 — это возможность сортировки идентификаторов по времени их создания. UUID V6 можно отсортировать по времени. +- **Метка времени**: UUID V6 сохраняет возможность извлечения метки времени из идентификатора, что полезно для некоторых приложений, где важно отслеживать время создания записи. +- **Конфиденциальность**: Как и в V1, UUID V6 может включать привязку к оборудованию (например, MAC-адрес), но рекомендуется использовать псевдослучайные данные для повышения конфиденциальности. + +**Недостатки:** +- **Сложность в использовании с кластеризованными индексами**: Хотя UUID V6 улучшает сортировку, время вставки в базу данных может увеличиваться при большом количестве записей, особенно если используется кластеризованный индекс, который требует поддержания порядка. +- **Не случайный**: В отличие от UUID V4, версия 6 не является полностью случайной, что может быть недостатком в сценариях, где важна непредсказуемость. +## UUID V7 +![](Pasted%20image%2020231112133651.png) + +UUID версии 7 (V7) представляет собой новую версию UUID, которая использует Unix-время вместо григорианского, применяемого в UUID версии 1 (V1). Такой подход делает UUID V7 более компактным и эффективным для хранения временных меток, поскольку Unix-время занимает меньше места по сравнению с григорианским временем. + +**Преимущества:** +- **Сортируемость**: UUID V7 сохраняет временные метки в формате Unix, что делает его естественно сортируемым по времени создания. Это полезно для реляционных баз данных, где важен порядок записей. +- **Константное время вставки**: Поскольку UUID V7 монотонно увеличивается со временем и включает случайные данные, вставка в базу данных происходит с постоянным временем. +- **Метка времени**: UUID V7 сохраняет метку времени, что позволяет извлечь момент создания идентификатора. +- **Сложность перебора**: UUID V7 сохраняет высокий уровень уникальности за счет случайных битов, что делает его труднопредсказуемым и сложным для перебора. + +**Недостатки:** +- **Меньшая случайность в начальной части**: Поскольку первые биты связаны с временной меткой, это снижает уровень случайности в первой части UUID. Однако это компенсируется случайной частью идентификатора. + +UUID V7 может иметь несколько типов генерации, в зависимости от требуемого уровня случайности и последовательности. +1. **Тип 1 (по умолчанию)**: `UuidCreator.getTimeOrderedEpoch();` + - **Плюсы**: Сортируемый, достаточно быстрый, подходит для большинства приложений, где важна как уникальность, так и последовательность. + - **Минусы**: Более низкий уровень случайности по сравнению с другими типами. +2. **Тип 2 (плюс 1)**: `UuidCreator.getTimeOrderedEpochPlus1();` + - Обеспечивает более высокую уникальность и последовательность за счет монотонного увеличения. + - **Плюсы**: Подходит для приложений, требующих строгого соблюдения порядка идентификаторов. + - **Минусы**: Менее случаен, чем Тип 3. + - **Производительность**: Генерируется в 20 раз быстрее, чем `UUID.randomUUID()`. +3. **Тип 3 (плюс n)**: `UuidCreator.getTimeOrderedEpochPlusN()`; + - **Особенности**: Максимальная уникальность за счет случайного увеличения.` + - **Плюсы**: Подходит для сценариев, требующих высокой уникальности без строгих требований к последовательности. + - **Минусы**: Меньшая предсказуемость и последовательность по сравнению с Типами 1 и 2. + - **Производительность**: Генерируется в два раза быстрее, чем `UUID.randomUUID()`. +## Производительность +Генерируем по 200000 идентификаторов в цикле, после чего вставляем эти данные. + +![](../meta/files/images/Pasted%20image%2020231112141139.png) + +Массовое чтение, через IN +![](../meta/files/images/Pasted%20image%2020231112141352.png) + +![](../meta/files/images/Pasted%20image%2020231112141530.png) + +*** +## Мета информация +**Область**:: [[../meta/zero/00 Разработка|00 Разработка]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2023-11-12]] +### Дополнительные материалы +- [ID-баттл: UUID vs автоинкремент / Валентин Удальцов - YouTube](https://www.youtube.com/watch?v=Xr_SNd9LIng&t=1762s) +- [Библиотека для генерации UUID в Java. Все версии](https://github.com/f4b6a3/uuid-creator) +- [[../../../_inbox/Автоинкремент|Автоинкремент]] +### Дочерние заметки + diff --git a/dev/algorithm/Adaptive Replacement Cache.md b/dev/algorithm/Adaptive Replacement Cache.md new file mode 100644 index 00000000..dcf3a9f4 --- /dev/null +++ b/dev/algorithm/Adaptive Replacement Cache.md @@ -0,0 +1,28 @@ +--- +aliases: +tags: + - maturity/🌱 +date: + - - 2024-06-17 +zero-link: + - "[[../../meta/zero/00 Алгоритм|00 Алгоритм]]" +parents: + - "[[Алгоритм вытеснения кэша]]" +linked: +--- +Объединяет преимущества: [Last Frequently Used](Last%20Frequently%20Used.md) и [Least Recently Used](Least%20Recently%20Used.md). + +Принцип работы: +- Сохраняет два списка: недавно используемые элементы и давно не используемые +- Может динамически менять размер этих списков +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Алгоритм|00 Алгоритм]] +**Родитель**:: [[Алгоритм вытеснения кэша]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-06-17]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/algorithm/GZIP.md b/dev/algorithm/GZIP.md new file mode 100644 index 00000000..eaa4d4ff --- /dev/null +++ b/dev/algorithm/GZIP.md @@ -0,0 +1,46 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-09-14 +zero-link: + - "[[../../meta/zero/00 Разработка|00 Разработка]]" +parents: + - "[[../fundamental/Сжатие данных|Сжатие данных]]" +linked: +--- +GZIP (GNU ZIP) — это формат сжатия данных и программное обеспечение, разработанное для сжатия и распаковки файлов. GZIP был создан в 1992 году Жан-Лу Гейли и Марком Адлером как замена более ранних программ сжатия данных, таких как Compress. GZIP основан на алгоритме DEFLATE, который сочетает в себе методы LZ77 (Lempel-Ziv 1977) и кодирование Хаффмана для эффективного сжатия данных. + +**Основные характеристики GZIP:** +- **Эффективное сжатие**: GZIP обеспечивает высокую степень сжатия данных, что позволяет значительно уменьшить размер файлов, особенно текстовых. +- **Скорость**: GZIP работает быстро и является эффективным как для сжатия, так и для распаковки данных. +- **Поддержка различных форматов**: GZIP сжимает данные в формате .gz, но не сохраняет структуру файлов и директорий (для этого используются архиваторы вроде tar). +- **Универсальность**: GZIP широко поддерживается в Unix-подобных системах (Linux, BSD), а также доступен на Windows и других платформах. +- **Использование заголовков**: GZIP добавляет к сжатому файлу заголовок, который содержит метаданные, такие как имя оригинального файла, временная метка и контрольная сумма CRC32 для проверки целостности данных. + +**Применения GZIP:** +- **Сжатие файлов**: Используется для сжатия отдельных файлов, что экономит место на диске и уменьшает время передачи данных. +- **Веб-технологии**: GZIP часто используется для сжатия веб-контента (HTML, CSS, JavaScript) перед отправкой с сервера на клиент, что ускоряет загрузку веб-страниц. +- **Архивирование**: В Unix-подобных системах GZIP часто используется вместе с утилитой tar для создания архивов (tar.gz или .tgz), которые содержат несколько файлов и директорий. +- **Протоколы передачи данных**: Протоколы, такие как HTTP и FTP, поддерживают сжатие GZIP для уменьшения объема передаваемых данных. + +**Реализации:** +- [[../../../../_inbox/Реализация GZIP в Java|Реализация GZIP в Java]] +- [[../devops/nginx/GZIP сжатие в Nginx|GZIP сжатие в Nginx]] + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Разработка|00 Разработка]] +**Родитель**:: [[../fundamental/Сжатие данных|Сжатие данных]] +**Источник**:: +**Создана**:: [[2024-09-14]] +**Автор**:: +### Дополнительные материалы +- +### Дочерние заметки + + +- [[Реализация GZIP в Java]] +- [[GZIP сжатие в Nginx]] + + diff --git a/dev/algorithm/Last Frequently Used.md b/dev/algorithm/Last Frequently Used.md new file mode 100644 index 00000000..79687c35 --- /dev/null +++ b/dev/algorithm/Last Frequently Used.md @@ -0,0 +1,26 @@ +--- +aliases: + - LFU +tags: + - maturity/🌱 +date: + - - 2024-06-17 +zero-link: + - "[[../../meta/zero/00 Алгоритм|00 Алгоритм]]" +parents: + - "[[Алгоритм вытеснения кэша]]" +linked: + - "[[Most Recently Used]]" +--- +Наиболее редко используемые данные вытесняются. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Алгоритм|00 Алгоритм]] +**Родитель**:: [[Алгоритм вытеснения кэша]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-06-17]] +### Дополнительные материалы +- [[Most Recently Used]] +### Дочерние заметки + diff --git a/dev/algorithm/Least Recently Used.md b/dev/algorithm/Least Recently Used.md new file mode 100644 index 00000000..83b283e9 --- /dev/null +++ b/dev/algorithm/Least Recently Used.md @@ -0,0 +1,45 @@ +--- +aliases: + - LRU +tags: + - maturity/🌱 +date: + - - 2024-05-24 +zero-link: + - "[[../../meta/zero/00 Алгоритм|00 Алгоритм]]" +parents: + - "[[Алгоритм вытеснения кэша]]" +linked: + - "[[Most Recently Used]]" + - "[[Псевдо-LRU]]" +--- +Least Recently Used (LRU) — это алгоритм управления кэш-памятью, который выбирает для удаления тот элемент, который давно не использовался. Этот алгоритм часто используется в системах, где ограничены ресурсы памяти, и необходимо эффективно управлять кэшированием данных. + +**Принцип работы:** +1. **Отслеживание использования**: Каждый элемент в кэше имеет метку времени или счетчик, который обновляется каждый раз, когда элемент используется. +2. **Удаление устаревших элементов**: Когда необходимо освободить место в кэше для нового элемента, удаляется элемент с наименьшим значением метки времени или счетчика, то есть наименее недавно использованный элемент. + +**Преимущества**: +- Эффективное управление памятью. +- Простота реализации и понятная логика работы. + +**Недостатки**: +- Высокие накладные расходы на обновление меток времени или счетчиков. Поэтому чаще всего используют [Псевдо-LRU](Псевдо-LRU.md). +- Возможность неэффективной работы в некоторых специфических случаях, когда часто используемые элементы могут вытесняться из кэша. + +**Примеры использования:** +- [[../architecture/Кэширование|Кэширование]] страниц в веб-браузерах. +- Управление оперативной памятью в [[../../../../knowledge/dev/pc/Операционная система|операционных системах]]. +- Кэширование данных в базах данных и других системах хранения. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Алгоритм|00 Алгоритм]] +**Родитель**:: [[Алгоритм вытеснения кэша]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-05-24]] +### Дополнительные материалы +- [[Most Recently Used]] +- [[Псевдо-LRU]] +### Дочерние заметки + diff --git a/dev/algorithm/Most Recently Used.md b/dev/algorithm/Most Recently Used.md new file mode 100644 index 00000000..78fd7c69 --- /dev/null +++ b/dev/algorithm/Most Recently Used.md @@ -0,0 +1,34 @@ +--- +aliases: + - MRU +tags: + - maturity/🌱 +date: + - - 2024-06-17 +zero-link: + - "[[../../meta/zero/00 Алгоритм|00 Алгоритм]]" +parents: + - "[[Алгоритм вытеснения кэша]]" +linked: + - "[[Least Recently Used]]" +--- +Наименее редко используемые данные вытесняются. + +**Принцип работы:** + +**Преимущества**: + +**Недостатки**: + +**Примеры использования:** +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Алгоритм|00 Алгоритм]] +**Родитель**:: [[Алгоритм вытеснения кэша]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-06-17]] +### Дополнительные материалы +- [[Least Recently Used]] +### Дочерние заметки + diff --git a/dev/algorithm/Алгоритм вытеснения кэша.md b/dev/algorithm/Алгоритм вытеснения кэша.md new file mode 100644 index 00000000..b5d1d185 --- /dev/null +++ b/dev/algorithm/Алгоритм вытеснения кэша.md @@ -0,0 +1,41 @@ +--- +aliases: + - алгоритмы замещения кэша + - Алгоритмы вытеснения + - алгоритмов замещения +tags: + - maturity/🌱 +date: 2024-09-11 +zero-link: + - "[[../../meta/zero/00 Алгоритм|00 Алгоритм]]" +parents: + - "[[../architecture/highload/Инвалидация кэша|Инвалидация кэша]]" +linked: +--- +Алгоритмы вытеснения кэша определяют, какие данные должны быть удалены из кэша, когда он заполняется. + +- Алгоритм Белади. Несуществующий идеальный алгоритм. Храним только нужную информацию, не нужную не храним. +- [Least Recently Used](Least%20Recently%20Used.md). Один из наиболее популярных. Отслеживает, какие данные использовались недавно, и удаляет те, которые не использовались дольше всего +- [Псевдо-LRU](Псевдо-LRU.md) +- [Most Recently Used](Most%20Recently%20Used.md) +- [Last Frequently Used](Last%20Frequently%20Used.md) +- [Adaptive Replacement Cache](Adaptive%20Replacement%20Cache.md) +- **FIFO (First In, First Out)** работает по принципу "первым пришел — первым ушел", удаляя данные в том порядке, в котором они были загружены в кэш. Хотя этот алгоритм проще, он не всегда эффективен, так как не учитывает, что старые данные могут по-прежнему быть востребованными. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Алгоритм|00 Алгоритм]] +**Родитель**:: [[../architecture/highload/Инвалидация кэша|Инвалидация кэша]] +**Источник**:: +**Создана**:: [[2024-09-11]] +**Автор**:: +### Дополнительные материалы +- +### Дочерние заметки + + +- [[Adaptive Replacement Cache]] +- [[Last Frequently Used]] +- [[Least Recently Used]] +- [[Most Recently Used]] +- [[Псевдо-LRU]] + diff --git a/dev/algorithm/Бинарный поиск.md b/dev/algorithm/Бинарный поиск.md new file mode 100644 index 00000000..9de217c6 --- /dev/null +++ b/dev/algorithm/Бинарный поиск.md @@ -0,0 +1,38 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-04-07 +zero-link: + - "[[../../meta/zero/00 Алгоритм|00 Алгоритм]]" +parents: +linked: +--- +Один их самых простых алгоритмов – это поиск элемента в отсортированном массиве. Это самая базовая алгоритмическая задача, которую нередко спрашивают на собеседованиях. + +С одной стороны, для подобных алгоритмов используют уже готовые функции стандартной библиотеки, с другой – подобные вопросы на собеседованиях позволяют узнать полезное о кандидате. + +Первое что приходи на ум: перебор элементов в массиве до нужного, тогда если количество элементов равно n и нужный нам элемент будет последним, нам потребуется сделать n проверок элементов до нахождения нужного, про такой случай и говорят что сложность алгоритма равна O(n). + +Рассмотрим другой подход - бинарный поиск – возьмем средний элемент отсортированного массива и сравним его c искомым. Если элемент меньше – продолжим поиск в левой части массива, если больше в правой, пока не останется нужный элемент. Таким образом нам понадобится число операций равное тому, сколько раз нам нужно поделить массив размером n пополам. + +Например, для массива в 16 элементов мы сначала поделим его на два по 8, потом 8 на два по 4, потом 4 на два по 2 и на конец 2 пополам, те всего 4 операции в худшем случае. Такое число равно двоичному логарифму. + +Реализации: +- [Бинарный поиск на Java](../java/Бинарный%20поиск%20на%20Java.md) + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Алгоритм|00 Алгоритм]] +**Родитель**:: +**Источник**:: +**Автор**:: [[2024-04-07]] +**Создана**:: +### Дополнительные материалы +- +### Дочерние заметки + + +- [[Бинарный поиск на Java]] + + diff --git a/dev/algorithm/Псевдо-LRU.md b/dev/algorithm/Псевдо-LRU.md new file mode 100644 index 00000000..9255f603 --- /dev/null +++ b/dev/algorithm/Псевдо-LRU.md @@ -0,0 +1,31 @@ +--- +aliases: +tags: + - maturity/🌱 +date: + - - 2024-06-18 +zero-link: + - "[[../../meta/zero/00 Алгоритм|00 Алгоритм]]" +parents: + - "[[Алгоритм вытеснения кэша]]" +linked: + - "[[Least Recently Used]]" +--- +В отличие от [LRU](Least%20Recently%20Used.md) уменьшает накладные расчеты на обновление меток времени и счетчиков. + +**Принцип работы:** +- У каждого ключа есть какой-то бит данных +- В цикле бегут потоки и снимают бит этим ключам +- Когда данные по ключу читаются бит помечается прочитанным +- Если нам нужно вытеснить информацию из кэша, то мы идем по ключам в поиске ключей со снятым битиком. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Алгоритм|00 Алгоритм]] +**Родитель**:: [[Алгоритм вытеснения кэша]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-06-18]] +### Дополнительные материалы +- [[Least Recently Used]] +### Дочерние заметки + diff --git a/dev/architecture/12-Factor App.md b/dev/architecture/12-Factor App.md new file mode 100644 index 00000000..2674472c --- /dev/null +++ b/dev/architecture/12-Factor App.md @@ -0,0 +1,57 @@ +--- +aliases: + - двенадцатифакторное приложение +tags: + - maturity/🌱 + - content/experience +date: 2024-12-08 +--- +**Двенадцатифакторное приложение (12-Factor App)** — это методология разработки приложений, предложенная инженерами Heroku. Она описывает набор из 12 принципов, которые помогают создавать программное обеспечение, подходящее для облачных сред. + +Основные цели этой методологии: +- Простое масштабирование. +- Портативность между средами. +- Упрощение разработки и развертывания. + +Эти принципы применимы ко всем видам приложений, но особенно полезны для веб-приложений и микросервисов. + +**Принципы двенадцатифакторного приложения** + +**Единая кодовая база** должна управляться в системе контроля версий и использоваться во всех средах. Все ветки и деплойменты одного микросервиса привязаны к одному репозиторию. Не должно быть такого, чтобы на один стенд деплой происходил из одного репозитория, а на другой из другого. + +> Думал, а как можно нарушить этот принцип. И вспомнил случай. После переименования сервиса в GitLab пришлось сделать для одного стенда форк репозитория, чтобы собраться со старым названием для фикса. Это было связано с тем, что все стенды зависели от названия репозитория, поэтому было невозможно переименовать сервис только для одного стенда. + +**Зависимости**. Явное объявление и изоляция зависимостей. Используйте менеджеры зависимостей. + +**Конфигурация**. Храните конфигурацию отдельно от кода. Используйте переменные окружения для настройки среды. Пример: URL базы данных, секреты или ключи API задаются через ENV, а не в коде. + +**Внешние ресурсы**. Базы данных, очереди, файловые хранилища рассматриваются как прикрепляемые ресурсы. Пример: База данных PostgreSQL или очередь RabbitMQ могут быть заменены без изменения кода. + +**Сборка, выпуск, выполнение**. Четкое разделение стадий: сборка приложения, создание релиза и его выполнение. + +**Процессы**. Приложение должно быть построено из одного или нескольких независимых процессов. Каждый процесс приложения отвечает за свою задачу (например, обработка HTTP-запросов, фоновые задания). + +**Stateless**. Приложение не должно хранить данные или состояние внутри процессов. Все состояния хранятся во внешних ресурсах. Пример: Сессии пользователей сохраняются в Redis, а не в оперативной памяти приложения. Если процесс падает или перезапускается, состояние не теряется, так как оно хранится в Redis, базе данных или другой внешней системе. + +**Привязка портов**. Приложение экспортирует HTTP (или другой) сервис через привязанный порт. + +**Параллелизм**. Процессы должны быть разделены на масштабируемые модули. + +**Среда разработки = среда продакшена**. Минимизируйте различия между стендами разработки и продакшеном. + +**Журналирование**. Приложение пишет события в поток вывода (stdout), а обработкой логов занимается внешняя система. Пример: Логи собираются через Elasticsearch или Datadog. + +**Административные задачи**. Запускайте административные задачи, такие как миграции базы данных, вместе с запуском сервиса. +*** +## Мета информация +**Область**:: [[../../../../wiki/zero/00 Микросервисная архитектура|00 Микросервисная архитектура]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-12-08]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/architecture/API Gateway.md b/dev/architecture/API Gateway.md new file mode 100644 index 00000000..91ba0a98 --- /dev/null +++ b/dev/architecture/API Gateway.md @@ -0,0 +1,29 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-11-03 +--- +![[../../meta/files/images/Pasted image 20241103020227.png|600]] + +**Шаг 1**: Клиент отправляет [[../network/HyperText Transfer Protocol|HTTP]]-запрос на API-шлюз. +**Шаг 2**: API-шлюз анализирует и проверяет атрибуты запроса. +**Шаг 3**: API-шлюз выполняет проверки по спискам разрешений и запретов (allow-list/deny-list). +**Шаг 4**: API-шлюз взаимодействует с поставщиком идентификаций для аутентификации и авторизации. +**Шаг 5**: К запросу применяются правила ограничения скорости. Если превышен лимит, запрос отклоняется. +**Шаги 6 и 7**: После прохождения базовых проверок API-шлюз ищет нужный сервис для маршрутизации, сопоставляя путь запроса. +**Шаг 8**: API-шлюз преобразует запрос в нужный протокол и отправляет его на [[бэкенд]] микросервисов. +**Шаги 9-12**: API-шлюз обрабатывает ошибки и справляется с длительными сбоями (circuit break). Также он может использовать стек ELK (Elastic-Logstash-Kibana) для логирования и мониторинга. Иногда данные кэшируются в самом API-шлюзе. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-03]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/architecture/Architecture Significant Requirement.md b/dev/architecture/Architecture Significant Requirement.md new file mode 100644 index 00000000..0661149f --- /dev/null +++ b/dev/architecture/Architecture Significant Requirement.md @@ -0,0 +1,40 @@ +--- +aliases: + - ASR +tags: + - maturity/🌱 +date: 2024-09-17 +--- +Architecture Significant Requirement (ASR), или архитектурно значимое требование, — это требование, которое существенно влияет на архитектурные решения системы. ASR определяет, какие аспекты архитектуры должны быть приоритетными для обеспечения нужных характеристик системы: +- Производительность +- Доступность +- Поддерживаемость +- Масштабируемость +- Удобство использования +- Совместимость +- Тестируемость +- Модифицируемость +- Переносимость +- Функциональность +- Переиспользуемость +- Диагностируемость +- Надежность + +**Основные характеристики ASR:** +- **Влияние на архитектуру:** Эти требования требуют определённых архитектурных решений или ограничений, чтобы обеспечить нужное поведение системы. Например, требование к высокой доступности системы может повлиять на выбор распределённой архитектуры. +- **Непосредственное влияние на атрибуты качества:** ASR нацелены на достижение или улучшение одного или нескольких атрибутов качества системы. Например, требования к времени отклика будут влиять на решения, касающиеся оптимизации производительности. +- **Долгосрочный эффект:** ASR обычно имеют долговременные последствия, так как изменение архитектурных решений позднее в процессе разработки может быть сложным и дорогостоящим. + + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-09-17]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + diff --git a/dev/architecture/Bottlneck.md b/dev/architecture/Bottlneck.md new file mode 100644 index 00000000..2d909c4a --- /dev/null +++ b/dev/architecture/Bottlneck.md @@ -0,0 +1,32 @@ +--- +aliases: + - узкое место +tags: + - maturity/🌱 +date: 2024-12-01 +--- +Узкое место (bottleneck) — компонент системы, ограничивающий её производительность или пропускную способность. Даже один неэффективный элемент может стать причиной снижения эффективности всей [[../../../../_inbox/Информационная система|информационной системы]]. + +Боттлнеки могут скрываться в любом элементе системы. Вот некоторые возможные области: +- [[highload/Балансировка нагрузки|Балансировщик нагрузки]]. Проблемы с распределением трафика. +- [[Бэкенд|Приложение]]. Ограничения на уровне кода или инфраструктуры. +- [[../../meta/zero/00 Реляционная база данных|База данных]]. Медленная обработка запросов, нехватка соединений. +- Распределенный [[Кэширование|кэш]]. Недостаток ресурсов или медленный доступ. +- [[Брокер сообщений]]. Ограничения на пропускную способность. +- Пропускная способность диска. Узкие места в файловых системах. + +**Пример в** [[../../../../wiki/zero/00 Микросервисная архитектура|микросервисной архитектуре]]. +Рассмотрим систему с несколькими микросервисами и сервисом аутентификации. Если общий объем запросов составляет 1000 rps, а сервис аутентификации может обработать только 100 rps, то он становится узким местом, замедляя работу всей системы. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 HighLoad|00 HighLoad]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-12-01]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/architecture/Bounded Context.md b/dev/architecture/Bounded Context.md new file mode 100644 index 00000000..803fddf0 --- /dev/null +++ b/dev/architecture/Bounded Context.md @@ -0,0 +1,43 @@ +--- +aliases: + - Ограниченный контекст + - ограниченных контекстов + - ограниченного контекста +tags: + - maturity/🌱 +date: 2024-11-24 +--- +Ограниченный контекст (Bounded Context) — это ==логическая граница, внутри которой используется своя уникальная модель предметной области.== Он применяется в разработке для структурирования сложных систем, особенно когда бизнес-логика состоит из множества разрозненных частей. + +Основные характеристики: +- **Локализация моделей:** Модель, используемая внутри одного контекста, не должна быть напрямую применима в других контекстах. Например, "Заказ клиента" в контексте управления складом может включать данные о весе и объеме, а в контексте бухгалтерии — только финансовую информацию. +- **Изоляция логики и терминологии:**. Один и тот же термин может означать разные вещи в разных контекстах. Например, "Клиент" в маркетинговом контексте — это целевая аудитория, а в контексте продаж — это покупатель с историей заказов. +- **Границы и ответственность:** Каждый контекст имеет свои четко определенные границы, и все, что относится к этому контексту (термины, сущности, события), остается внутри этих границ. +- **Интеграция контекстов:** Разные контексты взаимодействуют через явно определенные способы, такие как события, API, шины сообщений. Это позволяет минимизировать зависимость между контекстами. + +Представим систему интернет-магазина. Возможные ограниченные контексты: +- **Каталог продуктов** — управление списком товаров и их характеристиками. +- **Управление заказами** — отслеживание состояния заказов. +- **Склад** — управление инвентарем и логистикой. +- **Бухгалтерия** — расчеты, счета и налоги. + +Каждый из этих контекстов оперирует своей моделью данных и логикой, при этом данные могут пересекаться. Например, "Товар" есть в каталоге и на складе, но в каждом из контекстов он будет описан по-разному. + + +Польза +- [[../efficiency/Снижение когнитивной нагрузки при разработке|Снижение когнитивной нагрузки]] за счет локализации сложных моделей. +- Улучшение читаемости и тестируемости кода. +- Уменьшение зависимости между различными частями системы. +*** +## Мета информация +**Область**:: +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-24]] +**Автор**:: +### Дополнительные материалы +- [[Single Responsibility Principle]] + +### Дочерние заметки + + diff --git a/dev/architecture/Builder Pattern.md b/dev/architecture/Builder Pattern.md new file mode 100644 index 00000000..cfe67741 --- /dev/null +++ b/dev/architecture/Builder Pattern.md @@ -0,0 +1,318 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-10-04 +zero-link: +parents: +linked: +--- +Builder Pattern — это [[порождающий паттерн проектирования]], который используется для пошагового создания сложных объектов. Этот паттерн особенно полезен, когда объект может иметь множество конфигураций или параметров, которые делают его создание через конструкторы неудобным или даже невозможным. + +Основные концепции +- **Разделение построения и представления**. Билдер позволяет отделить логику создания объекта от его конечной структуры. Это делает код более чистым и поддерживаемым. +- **Пошаговая сборка**. Позволяет добавлять параметры или части объекта последовательно, при этом сам процесс создания может контролироваться и меняться независимо от основной логики объекта. +- **Иммутабельность**. Паттерн билдер часто применяется для создания неизменяемых объектов. После сборки объекта его нельзя изменить, что улучшает предсказуемость и безопасность. + +## Пример применения +Рассмотрим создание объекта `Car`, у которого много настроек, таких как тип двигателя, количество дверей, цвет и т.д. + +Без использования паттерна «Билдер» мы можем столкнуться с такой проблемой: необходимо создавать различные конструкторы, что ухудшает читаемость и поддержку кода. Паттерн «Билдер» помогает избежать этого, при этом используя [[Fluent API|fluent API]] стиль — подход, при котором методы возвращают сам объект билдера, позволяя вызывать их цепочкой. Это делает код более выразительным и легким для чтения. + +```java +public class Car { + private String engine; + private int doors; + private String color; + + private Car(CarBuilder builder) { + this.engine = builder.engine; + this.doors = builder.doors; + this.color = builder.color; + } + + public static class CarBuilder { + private String engine; + private int doors; + private String color; + + public CarBuilder setEngine(String engine) { + this.engine = engine; + return this; + } + + public CarBuilder setDoors(int doors) { + this.doors = doors; + return this; + } + + public CarBuilder setColor(String color) { + this.color = color; + return this; + } + + public Car build() { + return new Car(this); + } + } + +} +``` + +Использование паттерна: +```java +Car car = new Car.CarBuilder() + .setEngine("V8") + .setDoors(4) + .setColor("Red") + .build(); + +System.out.println(car); +``` + +**Преимущества** +1. **Чистый код**. Конфигурация объектов становится ясной и понятной, даже если у объекта множество параметров. +2. **Гибкость в создании объектов**. Можно не указывать все параметры сразу, а добавлять их по мере необходимости, что делает процесс сборки более гибким. +3. **Поддержка иммутабельности**. Объекты могут быть неизменяемыми после создания, так как параметры устанавливаются только в процессе сборки. +4. **Минимизация перегрузок конструкторов**. Это позволяет избежать множества конструкторов для различных комбинаций параметров. + +**Недостатки** +- **Усложнение кода**. Добавление класса-билдера может увеличить объем кода, особенно если объект не настолько сложен, чтобы оправдать использование паттерна. +- **Многословность**. Если объект требует только нескольких параметров, то использование билдера может казаться излишним и создавать ненужную многословность. + +**Когда применять?** +- Когда объект имеет множество конфигураций и параметров. +- Когда нужен гибкий процесс создания объектов с возможностью пошагового добавления параметров. +- Когда объект должен быть неизменяемым, и после сборки его состояние не должно меняться. + +## Продвинутый билдер +### Обязательные поля +Одной из распространенных проблем является ==отсутствие явного указания на обязательные поля== при использовании билдера. Если объект имеет поля, которые обязательны для заполнения (например, идентификатор или имя), но их установка не контролируется билдером, это может привести к созданию некорректных или невалидных объектов. + +**Решение**: +- Обязательные поля можно передавать через конструктор билдера, чтобы их указание было обязательным. Остальные параметры можно указывать через цепочку методов. + +Пример: +```java +public class Car { + private final String engine; // Обязательное поле + private final String model; // Обязательное поле + private int doors; // Необязательное поле + private String color; // Необязательное поле + + // Приватный конструктор для сборки объекта через билдер + private Car(CarBuilder builder) { + this.engine = builder.engine; + this.model = builder.model; + this.doors = builder.doors; + this.color = builder.color; + } + + // Статический метод для создания билдера с обязательными полями + public static CarBuilder builder(String engine, String model) { + return new CarBuilder(engine, model); + } + + public static class CarBuilder { + private final String engine; // Обязательное поле + private final String model; // Обязательное поле + private int doors = 4; // Значение по умолчанию + private String color = "Black"; // Значение по умолчанию + + // Конструктор билдера с обязательными полями + public CarBuilder(String engine, String model) { + if (engine == null || engine.isEmpty()) { + throw new IllegalArgumentException("Engine is required"); + } + if (model == null || model.isEmpty()) { + throw new IllegalArgumentException("Model is required"); + } + this.engine = engine; + this.model = model; + } + + // Методы для установки необязательных полей + public CarBuilder setDoors(int doors) { + this.doors = doors; + return this; + } + + public CarBuilder setColor(String color) { + this.color = color; + return this; + } + + // Метод для сборки объекта Car + public Car build() { + return new Car(this); + } + } +} +``` + +Теперь обязательные поля передаются при создании билдера: +```java +Car car = Car.builder("V8", "Sedan") // Передача обязательных полей через статический метод + .setDoors(2) // Опциональные поля + .setColor("Red") + .build(); +``` +### Валидация создания объекта +Ещё одна частая проблема заключается в том, что во время процесса построения ==не проверяются ограничения на совместимость полей.== Например, не всегда проверяется корректность значений или логика взаимодействия между параметрами, что может привести к созданию некорректного объекта. + +**Решение**: +Добавляйте в билдер логику валидации и проверки состояния перед созданием объекта. Это позволит убедиться, что все параметры совместимы и объект корректен. + +Пример: +```java +public Car build() { + if (doors < 2 || doors > 6) { + throw new IllegalArgumentException("Invalid number of doors"); + } + return new Car(this); +} +``` +### Многократный вызов методов +Когда методы билдера вызываются несколько раз, каждый вызов может перезаписывать значение параметра, что может остаться незамеченным или вызвать непредсказуемое поведение. + +Предположим, что у нас есть билдер для создания объекта `Car`, и метод для установки количества дверей (`setDoors`) был вызван дважды: +```java +Car car = new Car.CarBuilder("V8") + .setDoors(4) + .setDoors(2) // Этот вызов перезапишет предыдущее значение + .setColor("Red") + .build(); +``` + +В результате объект car будет создан с двумя дверями, хотя программист мог ожидать, что будет 4 двери (из-за первого вызова). Такая ситуация особенно распространена, когда объект конфигурируется динамически, или когда несколько разработчиков работают с билдером, не зная всех деталей. +#### Возможные решения проблемы +**Введение проверок на повторный вызов.** Чтобы избежать многократных вызовов одного и того же метода, можно добавить логику проверки, которая будет отслеживать, был ли метод уже вызван ранее. Если метод вызывается повторно, можно выбросить исключение или проигнорировать повторный вызов. + +```java +public static class CarBuilder { + private String engine; + private int doors; + private String color; + private boolean doorsSet = false; // Флаг, указывающий на то, что метод setDoors уже был вызван + + public CarBuilder(String engine) { + this.engine = engine; + } + + public CarBuilder setDoors(int doors) { + if (doorsSet) { + throw new IllegalStateException("Doors can only be set once"); + } + this.doors = doors; + doorsSet = true; + return this; + } + + public CarBuilder setColor(String color) { + this.color = color; + return this; + } + + public Car build() { + return new Car(this); + } +} +``` + +**Логирование перезаписи параметров.** Если необходимо разрешить многократные вызовы методов, но при этом важно отслеживать перезапись параметров, можно добавлять логирование, чтобы было видно, когда параметр перезаписывается новым значением. + +```java +public CarBuilder setDoors(int doors) { + if (this.doors != 0) { + System.out.println("Warning: Doors value is being overwritten from " + this.doors + " to " + doors); + } + this.doors = doors; + return this; +} +``` + + **Использование** [[Fluent API#Step building|Fluent API Step building]]. Позволит конфигурировать объект в определенной последовательности. + +```java +public class Car { + private final String engine; // Обязательное поле + private final int doors; // Обязательное поле + private final String color; // Обязательное поле + + // Приватный конструктор для сборки через пошаговую сборку + private Car(String engine, int doors, String color) { + this.engine = engine; + this.doors = doors; + this.color = color; + } + + // Интерфейс для первого шага: выбор двигателя + public interface EngineStep { + DoorsStep setEngine(String engine); + } + + // Интерфейс для второго шага: выбор дверей + public interface DoorsStep { + ColorStep setDoors(int doors); + } + + // Интерфейс для третьего шага: выбор цвета + public interface ColorStep { + BuildStep setColor(String color); + } + + // Интерфейс для финального шага: завершение сборки + public interface BuildStep { + Car build(); + } + + // Класс, который реализует пошаговую сборку + public static class Builder implements EngineStep, DoorsStep, ColorStep, BuildStep { + private String engine; + private int doors; + private String color; + + @Override + public DoorsStep setEngine(String engine) { + this.engine = engine; + return this; + } + + @Override + public ColorStep setDoors(int doors) { + this.doors = doors; + return this; + } + + @Override + public BuildStep setColor(String color) { + this.color = color; + return this; + } + + @Override + public Car build() { + return new Car(engine, doors, color); + } + } + + // Метод для запуска пошаговой сборки + public static EngineStep builder() { + return new Builder(); + } +} +``` + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Разработка|00 Разработка]] +**Родитель**:: [[Порождающий паттерн проектирования]] +**Источник**:: +**Создана**:: [[2024-10-04]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/architecture/CAP теорема.md b/dev/architecture/CAP теорема.md new file mode 100644 index 00000000..d37e1303 --- /dev/null +++ b/dev/architecture/CAP теорема.md @@ -0,0 +1,28 @@ +--- +aliases: +tags: + - maturity/🌱 +date: + - - 2024-03-12 +--- +![[../../meta/files/images/Pasted image 20241103022605.png]] + +CAP теорема — это принцип, описывающий фундаментальные ограничения, с которыми сталкиваются распределённые вычислительные системы в контексте обеспечения следующих трёх свойств: +- **Согласованность (Consistency)**: Каждый раз, когда данные читаются, возвращается самое последнее записанное значение или ошибка. С другими словами, операции с данными выглядят так, будто выполняются в некоторой строгой последовательности, одна за другой +- Доступность ([[../../../../_inbox/Availability|Availability]]): Каждый запрос на получение или запись данных получает ответ, независимо от состояния системы, даже если некоторые части системы вышли из строя. +- **Устойчивость к разделению (Partition Tolerance)**: Система продолжает функционировать, даже если произошло "разделение" — потеря связи между узлами в распределённой сети. То есть система способна переносить произвольное число сообщений, которые задерживаются или теряются в сети. + +==Согласно теореме CAP, в любой момент времени система может обеспечивать только два из этих трёх свойств.== Это означает, что при разработке системы приходится принимать компромисс между этими свойствами в зависимости от требований приложения и условий эксплуатации. Например, если для системы критически важна согласованность данных и её устойчивость к разделению, возможно придётся пожертвовать её доступностью в некоторых сценариях. +## Свободные заметки +- Google заявляет, что их продукт Google Spanner якобы нарушает CAP теорему. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-03-12]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/architecture/Database per service.md b/dev/architecture/Database per service.md new file mode 100644 index 00000000..b3f400ad --- /dev/null +++ b/dev/architecture/Database per service.md @@ -0,0 +1,41 @@ +--- +aliases: + - separate data store + - своя база данных +tags: + - maturity/🌱 +date: 2024-11-24 +--- +В [[../../../../wiki/zero/00 Микросервисная архитектура|микросервисной архитектуре]] [[Паттерн проектирования|паттерн]] "Database per Service" означает, что у каждого сервиса есть своя собственная, независимая [[../../meta/zero/00 Реляционная база данных|база данных]]. Это позволяет полностью изолировать данные, что обеспечивает независимость и автономность каждого микросервиса. При таком подходе, на этапе выполнения, сервисы не блокируют друг друга, и ни одному из них не приходится ждать из-за конкуренции за доступ к общей базе данных. + +Этот паттерн подразумевает, что каждый [[микросервис]] владеет своим хранилищем данных и несёт ответственность за его структуру и управление. ==Это не означает, что для каждого сервиса необходимо выделять отдельный сервер базы данных — вполне возможно использование одного физического сервера с несколькими логически изолированными базами данных== или базой с разными схемами для разных сервисов. + +**Преимущества подхода:** +1. **Изоляция данных**. Каждый сервис владеет своими данными, и другие сервисы не имеют прямого доступа к этим данным. Это повышает безопасность и уменьшает вероятность ошибок, вызванных некорректным использованием данных другими сервисами. +2. **Независимость разработки и деплоя**. Каждый микросервис может развиваться, тестироваться и развёртываться независимо, так как изменение структуры данных в одном сервисе не затрагивает другие. +3. **Устранение конкуренции за ресурсы**. Сервис не будет блокирован другим сервисом, который интенсивно использует общую базу данных. Это улучшает производительность и уменьшает задержки. +4. **Масштабируемость**. Каждый сервис может масштабироваться независимо, в том числе и его база данных. Это позволяет учитывать конкретные требования к нагрузке каждого сервиса. + +Проблемы +- **Невозможность глобальных транзакций (ACID)**. В случае, когда бизнес-логика требует согласованности данных на уровне нескольких микросервисов, использование ACID-транзакций на уровне всего приложения становится невозможным. Для решения этой проблемы применяются паттерны, такие как [Saga](Реализация%20повествования%20(Saga).md), которые позволяют координировать распределённые транзакции через цепочку локальных операций. +- [[Избыточность данных|Избыточность данных]] и консистентность. Поскольку каждый микросервис владеет своими данными, иногда возникает необходимость дублирования данных между сервисами для обеспечения эффективной работы. Это может привести к проблемам с поддержанием консистентности данных и усложняет управление изменениями. +- **Усложнение запросов**. Если бизнес-логика требует данных из нескольких микросервисов, выполнение сложных запросов становится трудной задачей, поскольку прямое обращение к базе данных другого сервиса не разрешено. В таких случаях приходится использовать API или механизмы синхронизации данных, что усложняет архитектуру. + +Лучшие практики +- **Чёткие границы владения данными**. Определите чёткие границы владения данными для каждого сервиса, - [[Bounded Context|Ограниченный контекст]]. Это помогает избежать пересечений и зависимостей между сервисами, а также упрощает управление данными. +- [[Событийно-ориентированная архитектура|Событийно-ориентированная архитектура]]. Для обеспечения согласованности данных между микросервисами можно использовать события. Например, при изменении данных в одном сервисе он отправляет событие, на которое подписаны другие сервисы, которым эти данные могут быть нужны. +- **Реализация паттернов для согласованности**. Используйте паттерны, такие как [Saga](Реализация%20повествования%20(Saga).md), чтобы координировать действия между несколькими микросервисами и гарантировать согласованность данных без использования глобальных транзакций. +- **API вместо прямого доступа к данным**. Доступ к данным одного микросервиса другими должен осуществляться только через публичные API. Это помогает соблюдать [[Инкапсуляция|инкапсуляцию]] и обеспечивает безопасное взаимодействие между сервисами. +*** +## Мета информация +**Область**:: [[../../../../wiki/zero/00 Микросервисная архитектура|00 Микросервисная архитектура]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-24]] +**Автор**:: +### Дополнительные материалы +- [[Shared Database|Shared Database]] + +### Дочерние заметки + + diff --git a/dev/architecture/Dependency Injection.md b/dev/architecture/Dependency Injection.md new file mode 100644 index 00000000..d6e37358 --- /dev/null +++ b/dev/architecture/Dependency Injection.md @@ -0,0 +1,70 @@ +--- +aliases: + - DI + - внедрение зависимостей +tags: + - maturity/🌱 +date: 2023-10-26 +zero-link: + - "[[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]]" +parents: + - "[[Inversion of Control]]" + - "[[Паттерн проектирования]]" +linked: +--- +**Dependency Injection (DI)** — это паттерн проектирования, который используется для реализации принципа [[Inversion of Control]] (IoC). DI позволяет передавать зависимости объектам извне, вместо того чтобы объекты сами создавали их. Это ослабляет связь между компонентами системы, что делает код более гибким и удобным для поддержки. + +В **Java** DI часто используется через фреймворки, такие как [[../../meta/zero/00 SpringBoot|Spring]] или [[../../meta/zero/00 Quarkus|Quarkus]], где зависимости внедряются автоматически. Основные способы внедрения зависимостей включают: +- **Внедрение через конструктор**: зависимости передаются через параметры конструктора. +- **Внедрение через сеттеры**: зависимости устанавливаются через методы. +- **Внедрение через поля**: зависимости могут быть внедрены напрямую в поля класса с использованием аннотаций. + +Пример внедрения через конструктор с использованием Spring: + +```java +import org.springframework.stereotype.Component; +import org.springframework.beans.factory.annotation.Autowired; + +@Component +class Engine { + public void start() { + System.out.println("Engine started"); + } +} + +@Component +class Car { + private final Engine engine; + + @Autowired + public Car(Engine engine) { + this.engine = engine; + } + + public void drive() { + engine.start(); + System.out.println("Car is moving"); + } +} +``` + +В этом примере Spring автоматически создаёт и инжектирует объект Engine в Car, благодаря аннотации `@Autowired`. Это упрощает управление зависимостями и позволяет легче изменять их без изменения логики программы. + +Главные преимущества DI: +- **Лёгкость тестирования**: можно подменять зависимости, что упрощает создание модульных тестов. +- **Масштабируемость**: система легче адаптируется к изменениям. +- **Упрощение архитектуры**: бизнес-логика отделена от процесса создания зависимостей. + + + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: [[Inversion of Control]], [[Паттерн проектирования]] +**Источник**:: +**Автор**:: +**Создана**:: [[2023-10-06]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/architecture/Dependency Inversion Principle.md b/dev/architecture/Dependency Inversion Principle.md new file mode 100644 index 00000000..07f21f95 --- /dev/null +++ b/dev/architecture/Dependency Inversion Principle.md @@ -0,0 +1,101 @@ +--- +aliases: + - DIP + - Принцип инверсии зависимостей +tags: + - maturity/🌱 +date: 2024-09-27 +zero-link: + - "[[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]]" +parents: + - "[[SOLID|SOLID]]" +linked: +--- +**Принцип инверсии зависимостей (Dependency Inversion Principle, DIP)** гласит: [[высокоуровневые модули]] не должны зависеть от низкоуровневых модулей. Оба должны зависеть от абстракций. Это означает, что вместо использования конкретных реализаций, классы должны работать с абстракциями — интерфейсами или абстрактными классами. DIP делает код более гибким, модульным и легко расширяемым. + +**Как соблюдать DIP** +1. **Работайте с абстракциями:** Замените зависимости на интерфейсы или абстрактные классы. +2. **Инвертируйте зависимости:** Используйте внедрение зависимостей ([[Dependency Injection]]) через конструктор, сеттер или контейнеры. +3. Минимизируйте жёсткую [[связанность]]: Высокоуровневые модули должны оставаться независимыми от деталей реализации низкоуровневых модулей. + +**Преимущества соблюдения DIP** +1. **Гибкость:** Замена низкоуровневых модулей (реализаций) не требует изменения высокоуровневых модулей. +2. **Улучшенная тестируемость:** Высокоуровневые модули можно тестировать с помощью моков или заглушек, так как они зависят от абстракций. +3. **Снижение связанности:** Высокоуровневый код становится независимым от деталей реализации. +4. **Расширяемость:** Новые реализации интерфейсов можно добавлять без изменений в существующем коде. +## Пример нарушения DIP +Рассмотрим пример с выключателем, который управляет лампой: + +```java +public class Lamp { + public void turnOn() { + // Лампа включена + } +} + +public class Switch { + private Lamp lamp; + + public Switch(Lamp lamp) { + this.lamp = lamp; + } + + public void toggle() { + lamp.turnOn(); // Нарушение DIP — жёсткая зависимость от класса Lamp + } +} +``` + +В данном случае класс `Switch` напрямую зависит от конкретной реализации класса `Lamp`. Если потребуется заменить лампу на другое устройство (например, вентилятор), придётся модифицировать код `Switch`. + +Используем интерфейс для абстрагирования устройств: + +```java +public interface Switchable { + void turnOn(); +} + +public class Lamp implements Switchable { + @Override + public void turnOn() { + // Лампа включена + } +} + +public class Fan implements Switchable { + @Override + public void turnOn() { + // Вентилятор включен + } +} +``` + +Теперь `Switch` зависит от интерфейса `Switchable`, а не от конкретного класса: + +```java +public class Switch { + private Switchable device; + + public Switch(Switchable device) { + this.device = device; + } + + public void toggle() { + device.turnOn(); // Зависимость инверсирована — Switch работает с абстракцией + } +} +``` + +Для изменения устройства достаточно передать новую реализацию интерфейса `Switchable` при создании объекта `Switch`, не модифицируя его код. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: [[SOLID]] +**Источник**:: +**Создана**:: [[2024-09-27]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + diff --git a/dev/architecture/Event Loop.md b/dev/architecture/Event Loop.md new file mode 100644 index 00000000..c71b5115 --- /dev/null +++ b/dev/architecture/Event Loop.md @@ -0,0 +1,50 @@ +--- +aliases: + - событийного цикла + - событийный цикл + - single-threaded execution loop +tags: + - maturity/🌱 +date: 2023-10-26 +zero-link: + - "[[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]]" +parents: + - "[[Реактивное программирование]]" +linked: +--- +**Event loop** (цикл событий) — это фундаментальная концепция в асинхронном программировании, которая позволяет системе обрабатывать большое количество задач без создания множества [[../fundamental/Поток процесса ОС|потоков]]. + +По сути, Event Loop - это реализация [шаблона Reactor](http://design-pattern.ru/patterns/reactor.html). Он используется в языках и фреймворках, которые должны обрабатывать большое количество операций [[../../../../_inbox/Ввод-вывод|ввода-вывода]] (I/O) эффективно, минимизируя затраты на создание и управление потоками. Цикл событий стал особенно популярным в таких технологиях, как JavaScript (Node.js), Python (asyncio), и современных реактивных фреймворках на Java (Vert.x, [[../../meta/zero/00 Quarkus|Quarkus]]). + +Цикл событий представляет собой непрерывную петлю, которая ожидает появления событий, таких как запросы клиентов, завершение операций I/O, сигналы от системных ресурсов и другие задачи. Когда событие происходит, цикл событий вызывает соответствующий обработчик, который выполняется без блокировки основной петли ([[../../../../_inbox/Не блокирующийся ввод-вывод|неблокирующийся ввод-вывод]]). + +![](../../meta/files/images/Pasted%20image%2020231026115508.png) + +Основные шаги работы event loop: +1. **Ожидание событий.** Цикл событий ожидает появления новых задач (например, клиентских запросов, ответов от базы данных, сообщений от других сервисов). +2. **Помещение задачи в очередь.** Когда событие происходит (например, пришел запрос от клиента), оно добавляется в очередь задач, ожидающих обработки. +3. **Выполнение задачи.** Цикл событий начинает обработку задачи, извлекая её из очереди и вызывая соответствующий обработчик. +4. **Завершение задачи.** Когда задача завершена (например, отправлен ответ клиенту), цикл переходит к следующему событию в очереди. + +**Преимущества** +- **Эффективное использование ресурсов.** Event loop позволяет системе обрабатывать большое количество запросов без необходимости создания множества потоков. Это снижает накладные расходы на память и процессорное время. +- **Масштабируемость.** Благодаря асинхронной модели, event loop может обрабатывать сотни тысяч запросов одновременно, что делает его идеальным решением для [[../../meta/zero/00 HighLoad|высоконагруженных систем]]. +- **Неблокирующее выполнение.** В отличие от традиционных моделей, где операции ввода-вывода блокируют поток ([[Блокирующий вызов]]), в модели event loop такие операции выполняются асинхронно, освобождая поток для выполнения других задач. +- Минимум [[../fundamental/Переключение контекста|контекстных переключений]]. Цикл событий снижает количество переключений между потоками, что снижает накладные расходы на переключение контекста и увеличивает производительность. + +**Недостатки** +- **Ограниченная поддержка CPU-ориентированных задач.** Модель event loop идеально подходит для операций ввода-вывода, но для задач, требующих интенсивных вычислений, такая модель не так эффективна. В таком случае ==поток может быть занят длительное время, блокируя выполнение других задач.== +- **Сложность управления.** Асинхронные операции требуют управления состояниями и корректной обработки событий, что усложняет разработку и отладку. ==Ошибки в одном обработчике могут затронуть другие запросы, обрабатываемые тем же циклом событий.== +- **“Заблокированный” цикл.** Если цикл событий заблокирован долгой синхронной операцией, это может затормозить выполнение всех задач, так как весь поток будет занят одной задачей. + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: [[Реактивное программирование|Реактивное программирование]] +**Источник**:: +**Автор**:: +**Создана**:: +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/architecture/Event Sourcing.md b/dev/architecture/Event Sourcing.md new file mode 100644 index 00000000..1906e22f --- /dev/null +++ b/dev/architecture/Event Sourcing.md @@ -0,0 +1,43 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-12-02 +--- +Event Sourcing — это [[архитектурный паттерн]], при котором состояние системы не сохраняется напрямую, а восстанавливается путем воспроизведения последовательности событий. Каждое событие отражает изменение в системе и сохраняется в неизменяемом журнале событий (event log). + +**Принципы:** +- **Неизменяемость событий**. Каждое событие записывается единожды и не подлежит изменению. +- **Воспроизведение событий**. Текущее состояние объекта вычисляется путем последовательного применения событий, начиная с исходного состояния. +- **Хранилище событий**. Все события хранятся в базе данных, которая может быть оптимизирована для их последовательной записи. + +**Преимущества:** +- **Аудит и прозрачность**. Хранилище событий предоставляет полный лог изменений, что упрощает аудит и диагностику. +- **Производительность и масштабирование**. Увеличение производительности за счет использования хранилища событий и построения проекций для чтения. +- **Восстановление состояния**. Легкость восстановления системы после сбоя путем проигрывания всех событий. +- **Возможности для анализа**. Хранилище событий может использоваться для ретроспективного анализа данных. + +**Ограничения:** +- **Усложнение системы**. Требуется дополнительная логика для обработки событий, создания проекций и управления хранилищем событий. +- **Версионирование событий**. Необходимость в управлении версиями событий при изменении их структуры. +- **Увеличение объема данных**. Хранение всех событий может привести к быстрому росту объема данных. +- **Задержка восстановления состояния**. При большом числе событий восстановление состояния может занимать много времени. + +**Применение:** +1. **Финансовые системы**. Для учета транзакций и обеспечения полного логирования операций. +2. **E-commerce**. Хранение всех изменений корзины пользователя или заказов. +3. **IoT**. Сохранение событий от датчиков для анализа в реальном времени или ретроспективы. +4. Паттерн [[../../../../knowledge/dev/архитектура/паттерн/CQRS|CQRS]]. Часто используется совместно с Event Sourcing для разделения операций чтения и записи. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]] +**Родитель**:: [[Архитектурный паттерн]] +**Источник**:: +**Создана**:: [[2024-12-02]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/architecture/Fingerprint.md b/dev/architecture/Fingerprint.md new file mode 100644 index 00000000..c08d938a --- /dev/null +++ b/dev/architecture/Fingerprint.md @@ -0,0 +1,27 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-09-10 +zero-link: + - "[[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]]" +parents: + - "[[highload/Инвалидация кэша|Инвалидация кэша]]" +linked: [] +--- +При реализации [[highload/Кэширование на стороне браузера|кэширования на стороне браузера]] важно иметь механизм [[highload/Инвалидация кэша|инвалидации кэша]]. Иначе пользователи могут продолжить видеть неактуальные JS-скрипты и CSS-стили, что приведет к проблемам. + +Fingerprint — это метод, при котором при каждом изменении файла его название изменяется. Обычно это делается путем добавления префикса или суффикса, сгенерированного на основе хэша файла. Например, для файла стилей `style.css` можно вычислить его [[../cryptography/MD5|MD5]]-хэш и добавить его к имени файла. В итоге получится файл с именем `style.e626dd36e0085927f334adbe3eb38e7a.css`. + +Каждый раз, когда файл изменяется, хэш пересчитывается, и файл получает новое имя. Это заставляет браузер скачать актуальную версию файла, игнорируя старую кэшированную копию. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]] +**Родитель**:: [[highload/Инвалидация кэша|Инвалидация кэша]] +**Источник**:: +**Создана**:: [[2024-09-10]] +**Автор**:: +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/architecture/Fluent API.md b/dev/architecture/Fluent API.md new file mode 100644 index 00000000..e656a019 --- /dev/null +++ b/dev/architecture/Fluent API.md @@ -0,0 +1,356 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-10-04 +zero-link: +parents: +linked: +--- +**Fluent API** — это стиль проектирования API, в котором ==методы возвращают объект, к которому они принадлежат==, позволяя вызывать методы цепочкой (chaining). + +**Основные концепции** +- **Method Chaining**. Fluent API позволяет вызывать методы один за другим, что уменьшает количество промежуточных переменных и улучшает читаемость. +- **Самоописывающийся код**. Использование цепочки методов делает код более понятным и логичным, приближая его к естественному языку. + +**Где встречается?** +- Фреймворки с реактивным подходом. +- Java Stream +- **Библиотеки для работы с базами данных**. Такие фреймворки, как JPA или Hibernate, используют Fluent API для создания запросов. Например, запросы могут выглядеть так + +```java +CriteriaBuilder builder = entityManager.getCriteriaBuilder(); +CriteriaQuery query = builder.createQuery(Car.class); +query.select(query.from(Car.class)) + .where(builder.equal(root.get("color"), "Red")); +``` + +- **Настройка объектов**. Fluent API часто используется в [[../../../../garden/ru/dev/architecture/Builder Pattern|Builder Pattern]], где объект строится поэтапно через цепочку методов. +- Конфигурация. Например Spring Security, Kafka Streams +- **Фреймворки для тестирования**. Например, в JUnit или AssertJ можно строить цепочки утверждений: + +Fluent API часто используется для построения специфических языков (DSL), которые имитируют человеческий язык и делают код максимально самоописательным. + +Пример императивного кода +```java +Instant start = Instant.now(); +Duration timeout = Duration.ofSeconds(10); +do { + Thread.sleep(200); + var entity = repo.get("id"); + if ("EXPECTED".equals(entity.status)) { + return; + } +} while (Instant.now().isBefore(start.plus(timeout))); +throw new AssertionError("Status was not updated to EXPECTED"); +``` + +И аналогичный в стиле Fluent API +```java +Awaitility.await("Entity status should be updated to EXPECTED") + .atMost(Duration.ofSeconds(10)) + .pollDelay(Duration.ofMillis(200)) + .until(() -> "EXPECTED".equals(repo.get("id").status)); +``` +## Приемы и подходы +### Method chaining +**Method chaining** — это техника, при которой методы возвращают текущий объект (обычно через `this`), позволяя вызывать несколько методов последовательно в одной строке. + +```java {7, 12} +public class Car { + private String engine; + private int doors; + + public Car setEngine(String engine) { + this.engine = engine; + return this; // Возвращаем текущий объект + } + + public Car setDoors(int doors) { + this.doors = doors; + return this; + } +} +``` +### Смена контекста +#### С помощью method chaining +Представим, что мы настраиваем серверное приложение с несколькими аспектами: базовая настройка, настройка безопасности, логирования и т.д. Здесь каждый вызов метода переключает нас на новый “контекст”, где мы продолжаем настраивать приложение, но в рамках другой области (например, с безопасности переключаемся на логирование). + +```java +public class ServerConfig { + + public ServerConfig http() { + System.out.println("HTTP basic configuration"); + return this; // Возвращаем тот же объект для продолжения цепочки + } + + public ServerConfig security() { + System.out.println("Security configuration"); + return this; // Переключение на контекст безопасности + } + + public ServerConfig authorizeRequests() { + System.out.println("Authorization configuration"); + return this; // Переключение на настройку авторизации запросов + } + + public ServerConfig requestMatchers(String pattern) { + System.out.println("Configuring request matchers for: " + pattern); + return this; // Продолжение работы в контексте авторизации + } + + public ServerConfig csrf() { + System.out.println("CSRF protection disabled"); + return this; // Переключение на настройку защиты CSRF + } + + public ServerConfig exceptionHandling() { + System.out.println("Exception handling configuration"); + return this; // Переключение на обработку исключений + } + + public Server build() { + System.out.println("Server is configured and built"); + return new Server(); + } +} + +class Server { + // Имитация запущенного сервера +} +``` + +```java +Server server = new ServerConfig() + .http() // Контекст базовой настройки HTTP + .security() // Переключение на контекст безопасности + .authorizeRequests() // Настройка авторизации запросов + .requestMatchers("/") // Настройка доступа для главной страницы + .requestMatchers("/api") // Настройка доступа к API + .csrf() // Отключение CSRF + .exceptionHandling() // Настройка обработки исключений + .build(); // Завершаем конфигурацию и запускаем сервер +``` +#### С помощью лямбда-выражений +```java +public class ServerConfig { + + public ServerConfig http(Consumer httpConfig) { + System.out.println("Entering HTTP configuration context"); + httpConfig.accept(new HttpConfig()); + return this; // Возвращаем тот же объект для дальнейшей конфигурации + } + + public ServerConfig security(Consumer securityConfig) { + System.out.println("Entering Security configuration context"); + securityConfig.accept(new SecurityConfig()); + return this; // Переключение на контекст безопасности + } + + public ServerConfig logging(Consumer loggingConfig) { + System.out.println("Entering Logging configuration context"); + loggingConfig.accept(new LoggingConfig()); + return this; // Переключение на контекст логирования + } + + public Server build() { + System.out.println("Server is configured and built"); + return new Server(); // Финальный этап — запуск сервера + } + + // Вложенные классы конфигураций для разных контекстов + public static class HttpConfig { + public HttpConfig enableHttp2() { + System.out.println("HTTP/2 enabled"); + return this; + } + + public HttpConfig port(int port) { + System.out.println("Server will listen on port: " + port); + return this; + } + } + + public static class SecurityConfig { + public SecurityConfig enableTLS() { + System.out.println("TLS enabled"); + return this; + } + + public SecurityConfig authorizeRequests(Consumer authorizationConfig) { + System.out.println("Authorizing requests..."); + authorizationConfig.accept(new RequestAuthorization()); + return this; + } + } + + public static class LoggingConfig { + public LoggingConfig level(String level) { + System.out.println("Logging level set to: " + level); + return this; + } + } + + public static class RequestAuthorization { + public RequestAuthorization permitAll() { + System.out.println("All requests are permitted"); + return this; + } + + public RequestAuthorization authenticated() { + System.out.println("Authenticated requests only"); + return this; + } + } +} +``` + +```java +Server server = new ServerConfig() + .http(http -> http.enableHttp2().port(8080)) // Настройка HTTP с использованием лямбда-выражения + .security(security -> security + .enableTLS() // Настройка безопасности + .authorizeRequests(auth -> auth.authenticated())) // Смена контекста внутри лямбды + .logging(log -> log.level("INFO")) // Настройка логирования с помощью лямбда + .build(); // Финальная сборка сервера +``` + +### Step building +Позволяет организовать процесс создания объектов или выполнения операций через строго упорядоченные шаги. Хотя этот подход часто используется в [[../../../../garden/ru/dev/architecture/Builder Pattern|Builder Pattern]], он применим и в других контекстах, например, при вызове API, конфигурации сложных процессов, построении запросов и даже в рабочих процессах (workflow). + +**Основные концепции** +- **Упорядоченные шаги**. Процесс выполнения операции или создания объекта разделен на несколько этапов (шагов), которые должны выполняться в определённой последовательности. Каждый шаг может представлять собой настройку, изменение состояния или выполнение отдельной операции. +- **Контроль обязательных шагов**. Пошаговая сборка гарантирует, что определенные важные шаги не будут пропущены. Это особенно полезно для процессов, где важно соблюдение последовательности действий или конфигурации обязательных параметров. + +**Примеры применения пошаговой сборки** + +**Построение SQL-запросов** + +```java +public interface SelectStep { + FromStep select(String... columns); +} + +public interface FromStep { + WhereStep from(String table); +} + +public interface WhereStep { + OrderByStep where(String condition); +} + +public interface OrderByStep { + BuildStep orderBy(String column); +} + +public interface BuildStep { + String build(); +} + +public class SqlQueryBuilder implements SelectStep, FromStep, WhereStep, OrderByStep, BuildStep { + private String query; + + @Override + public FromStep select(String... columns) { + query = "SELECT " + String.join(", ", columns); + return this; + } + + @Override + public WhereStep from(String table) { + query += " FROM " + table; + return this; + } + + @Override + public OrderByStep where(String condition) { + query += " WHERE " + condition; + return this; + } + + @Override + public BuildStep orderBy(String column) { + query += " ORDER BY " + column; + return this; + } + + @Override + public String build() { + return query; + } + + public static SelectStep start() { + return new SqlQueryBuilder(); + } +} +``` + +### Самообобщение +Когда мы используем наследование для создания подклассов, возникает проблема, что методы Fluent API могут возвращать не подкласс, а базовый класс, разрывая цепочку вызовов. **Самообобщение** решает эту проблему, позволяя методам возвращать правильный тип подкласса. + +**Пример проблемы без самообобщения**. Допустим, у нас есть базовый класс с цепочкой методов, и мы хотим унаследовать этот класс. + +```java +class BaseBuilder { + public BaseBuilder setName(String name) { + System.out.println("Name set to: " + name); + return this; + } +} + +class AdvancedBuilder extends BaseBuilder { + public AdvancedBuilder setFeature(String feature) { + System.out.println("Feature set to: " + feature); + return this; + } +} + +public class Main { + public static void main(String[] args) { + AdvancedBuilder builder = new AdvancedBuilder(); + builder.setName("MyObject") + .setFeature("AdvancedFeature"); // Ошибка: возвращается BaseBuilder + } +} +``` + +В этом примере `setName()` возвращает тип `BaseBuilder`, поэтому попытка вызвать `setFeature()` на результат этого вызова приведет к ошибке. Метод `setFeature()` будет недоступен. + +**Решение с использованием самообобщения (Self-type Generics)**. Мы можем решить эту проблему, используя самообобщение с помощью обобщений (generics). Это позволит методам возвращать **самый специфичный тип**. + +```java +class BaseBuilder> { + public T setName(String name) { + System.out.println("Name set to: " + name); + return (T) this; // Возвращаем текущий объект с типом T + } +} + +class AdvancedBuilder extends BaseBuilder { + public AdvancedBuilder setFeature(String feature) { + System.out.println("Feature set to: " + feature); + return this; // Возвращаем текущий объект с типом AdvancedBuilder + } +} + +public class Main { + public static void main(String[] args) { + AdvancedBuilder builder = new AdvancedBuilder(); + builder.setName("MyObject") + .setFeature("AdvancedFeature"); // Теперь работает правильно + } +} +``` +*** +## Мета информация +**Область**:: [[../../../../garden/ru/meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-10-04]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/architecture/Infrastructure as Code.md b/dev/architecture/Infrastructure as Code.md new file mode 100644 index 00000000..0f43fae2 --- /dev/null +++ b/dev/architecture/Infrastructure as Code.md @@ -0,0 +1,39 @@ +--- +aliases: + - IaC +tags: + - maturity/🌱 +date: 2024-12-21 +--- +Infrastructure as Code (IaC) — это практика управления, конфигурирования и автоматизации вычислительных ресурсов (серверов, сетей, баз данных и т.д.) с использованием программного кода. Она позволяет инфраструктуре быть определённой в виде описания, которое можно сохранить в системе контроля версий, автоматически применять и изменять. + +Пример: создание сервера не вручную через облачный интерфейс, а с использованием скрипта, который можно запустить и повторить в любой момент. + +**Принципы** +- **Декларативность или императивность.** Инфраструктура описывается либо в виде желаемого состояния (декларативный подход), либо через последовательность команд (императивный подход). +- **Контроль версий.** Код инфраструктуры хранится в системах контроля версий (например, Git), что позволяет отслеживать изменения и возвращаться к предыдущим состояниям. +- [[Идемпотентность]]. Повторное выполнение кода приводит к одному и тому же результату, что важно для стабильности. + +**Преимущества** +- **Стандартизация.** Все ресурсы управляются одинаково, снижается риск ошибок. +- **Ускорение разработки.** Быстрое развёртывание и настройка инфраструктуры. +- [[Масштабирование информационной системы|Масштабируемость]]. Удобное управление инфраструктурой даже в крупных системах. +- Упрощение [[highload/Disaster recovery|восстановления]]. Код инфраструктуры позволяет восстановить её после сбоев. + +**Недостатки** +- **Кривая обучения.** Требуется время на изучение инструментов и практик IaC. +- **Сложность внедрения.** Для небольших команд или простых систем реализация IaC может быть излишней. +- **Необходимость дисциплины.** Некорректное управление кодом может привести к нестабильности. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]] +**Родитель**:: [[Архитектурная концепция]] +**Источник**:: +**Создана**:: [[2024-12-21]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/architecture/Interface Segregation Principle.md b/dev/architecture/Interface Segregation Principle.md new file mode 100644 index 00000000..5a8ee4f8 --- /dev/null +++ b/dev/architecture/Interface Segregation Principle.md @@ -0,0 +1,93 @@ +--- +aliases: + - ISP +tags: + - maturity/🌱 +date: 2024-09-27 +--- +Принцип разделения интерфейсов (Interface Segregation Principle, ISP) гласит: ==лучше создать несколько специализированных интерфейсов, чем один универсальный,== который заставляет классы реализовывать методы, не относящиеся к их функциональности. Каждый интерфейс должен описывать только те действия, которые действительно нужны конкретному клиенту. Этот принцип помогает избежать ненужной связанности и упрощает поддержку кода. + +**Для реализации ISP следует:** +- Создавать узкоспециализированные интерфейсы, соответствующие конкретным задачам. +- Избегать универсальных интерфейсов с множеством методов, которые могут быть неактуальны для некоторых реализаций. +- Делить интерфейсы на логически связанные группы методов. + +**Преимущества соблюдения ISP** +1. **Снижение связанности:** Реализации зависят только от методов, которые они используют. +2. **Повышенная гибкость:** Интерфейсы можно изменять или добавлять новые без влияния на классы, которым эти изменения не нужны. +3. **Упрощение тестирования:** Тестировать реализацию узких интерфейсов проще, так как они охватывают только необходимый функционал. +4. **Улучшенная читаемость:** Логически разделенные интерфейсы делают код более понятным и структурированным. +## Пример нарушения ISP +Рассмотрим интерфейс `Worker`, который описывает как работу, так и прием пищи: + +```java +public interface Worker { + void work(); + void eat(); +} + +public class RobotWorker implements Worker { + @Override + public void work() { + // Робот работает + } + + @Override + public void eat() { + // Робот не ест — нарушение ISP + throw new UnsupportedOperationException("Robots do not eat"); + } +} + +``` + +Класс `RobotWorker` вынужден реализовывать метод `eat`, который ему не нужен. Это нарушение ISP, так как интерфейс содержит лишние методы, не применимые ко всем клиентам. + +Разделим интерфейс на два более специализированных: + +```java +public interface Worker { + void work(); +} + +public interface Eater { + void eat(); +} + +``` + +Теперь каждый класс реализует только те интерфейсы, которые ему нужны: + +```java +public class HumanWorker implements Worker, Eater { + @Override + public void work() { + // Человек работает + } + + @Override + public void eat() { + // Человек ест + } +} + +public class RobotWorker implements Worker { + @Override + public void work() { + // Робот работает + } +} + +``` +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: [[SOLID]] +**Источник**:: +**Создана**:: [[2024-09-27]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + diff --git a/dev/architecture/Inversion of Control.md b/dev/architecture/Inversion of Control.md new file mode 100644 index 00000000..f8005ee5 --- /dev/null +++ b/dev/architecture/Inversion of Control.md @@ -0,0 +1,99 @@ +--- +aliases: + - IoC +tags: + - maturity/🌱 +date: 2023-10-26 +zero-link: + - "[[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]]" +parents: + - "[[Архитектурная концепция]]" +linked: +--- +Inversion of Control (IoC) — это [[архитектурная концепция]], которая заключается в передаче управления зависимостями программы от самого кода к внешней системе. Обычно, если один объект зависит от другого, он сам создаёт или запрашивает его. В IoC этот процесс контролируется извне, что позволяет программам быть более гибкими и легко расширяемыми. + +Простой пример: допустим, у вас есть класс, который зависит от другого класса для выполнения своей работы. В обычном подходе класс сам создаёт объект-зависимость. + +```java +class Engine { + public void start() { + System.out.println("Engine started"); + } +} + +class Car { + private Engine engine; + + public Car() { + // Класс Car сам создает зависимость + this.engine = new Engine(); + } + + public void drive() { + engine.start(); + System.out.println("Car is moving"); + } +} + +public class Main { + public static void main(String[] args) { + Car car = new Car(); + car.drive(); + } +} +``` + +С использованием **IoC**, создание объекта Engine передаётся внешнему компоненту. Теперь Car не отвечает за создание своей зависимости: + +```java +class Engine { + public void start() { + System.out.println("Engine started"); + } +} + +class Car { + private Engine engine; + + // Зависимость передается через конструктор (IoC) + public Car(Engine engine) { + this.engine = engine; + } + + public void drive() { + engine.start(); + System.out.println("Car is moving"); + } +} + +public class Main { + public static void main(String[] args) { + // Создание зависимостей осуществляется снаружи + Engine engine = new Engine(); + Car car = new Car(engine); + car.drive(); + } +} +``` + +IoC помогает реализовать принципы [[../../../../garden/ru/dev/architecture/SOLID|SOLID]], особенно [[../../../../garden/ru/dev/architecture/Dependency Inversion Principle|Принцип инверсии зависимостей]] (Dependency Inversion Principle, DIP), согласно которому высокоуровневые модули не должны зависеть от низкоуровневых модулей напрямую. Оба типа модулей должны зависеть от абстракций. В контексте IoC это означает, что классы не должны напрямую создавать свои зависимости, а получать их через интерфейсы или внешние механизмы. Такой подход упрощает замену реализаций, тестирование и расширение приложения. + +**Преимущества IoC** +- **Ослабление связности кода**. Поскольку классы не создают свои зависимости напрямую, их связь с конкретными реализациями уменьшается. Это облегчает изменение или замену зависимостей без изменения самого класса. +- **Упрощение тестирования**. IoC позволяет легко заменять реальные зависимости на тестовые (например, mock-объекты), что упрощает процесс модульного тестирования. Вы можете изолировать классы и тестировать их независимо от реальных зависимостей. +- **Лучшая расширяемость**. Система, построенная на принципах IoC, легче адаптируется к изменениям и новым требованиям. Новые зависимости могут быть добавлены или изменены без значительного изменения существующего кода. +- **Разделение ответственности**. С IoC создаётся чёткое разделение между бизнес-логикой и управлением зависимостями. Это помогает сосредоточить внимание на основной функциональности класса, не отвлекаясь на вопросы создания объектов. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: [[Архитектурная концепция]] +**Источник**:: +**Автор**:: +**Создана**:: [[2023-10-26]] +### Дополнительные материалы +- +### Дочерние заметки + + +- [[Dependency Injection]] + diff --git a/dev/architecture/Latency.md b/dev/architecture/Latency.md new file mode 100644 index 00000000..eddff8db --- /dev/null +++ b/dev/architecture/Latency.md @@ -0,0 +1,41 @@ +--- +aliases: + - задержка + - время отклика + - задержки +tags: + - maturity/🌱 +date: + - - 2024-03-12 +zero-link: + - "[[../../meta/zero/00 HighLoad|00 HighLoad]]" +parents: +linked: +--- +Latency - это время, необходимое для выполнения какой-либо операции или передачи данных от одной точки к другой. В более широком смысле, это период времени между началом действия и моментом, когда его результаты становятся заметны. + +**Что влияет?** +- **Расстояние**: Физическое расстояние между отправителем и получателем данных напрямую влияет на время передачи сигнала, особенно при больших расстояниях. +- **Скорость передачи данных среды**: Скорость, с которой данные передаются через физическую среду (например, медные кабели, оптоволокно, беспроводные каналы), также влияет на задержку. +- **Пропускная способность сети**: Высокая загруженность сети и ограниченная пропускная способность могут приводить к задержкам из-за ожидания доступа к сетевым ресурсам. +- **Обработка данных**: Время, необходимое для обработки данных устройствами, такими как маршрутизаторы, коммутаторы и серверы, также вносит свой вклад в общую задержку. +- **Количество прыжков (хопов) в сети**: Количество устройств (например, маршрутизаторов и коммутаторов), через которые данные должны пройти от источника к пункту назначения, увеличивает общее время задержки. +- **Эффективность используемых протоколов**. Например, дополнительные шаги рукопожатия создают задержку + +**Что поможет уменьшить значение:** +- **Оптимизация производительности сервера**: Улучшение аппаратных характеристик сервера, таких как процессор, оперативная память и системы хранения, может сократить время обработки запросов. +- **Использование кэширования**: [[Кэширование]] часто запрашиваемых данных на сервере или ближе к клиенту может существенно сократить время доступа к этим данным, поскольку избавляет от необходимости каждый раз обращаться к основному источнику данных. +- **Оптимизация базы данных**: Индексация, оптимизация запросов и структур данных, а также выбор подходящего типа базы данных могут снизить время доступа к данным +- **Минимизация расстояния**: Размещение серверов ближе к конечным пользователям или использование сети доставки контента ([CDN](highload/Content%20Delivery%20Network.md)) может снизить физическую задержку, связанную с расстоянием, которое должны преодолеть данные. +- **Сокращение объема передаваемых данных**: Минимизация размера данных, передаваемых между клиентом и сервером (например, [[../fundamental/Сжатие данных|сжатие данных]] и изображений), может уменьшить время их передачи. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 HighLoad|00 HighLoad]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-03-12]] +### Дополнительные материалы +- [[Throughput]] +### Дочерние заметки + diff --git a/dev/architecture/Liskov Substitution Principle.md b/dev/architecture/Liskov Substitution Principle.md new file mode 100644 index 00000000..1d4d86eb --- /dev/null +++ b/dev/architecture/Liskov Substitution Principle.md @@ -0,0 +1,81 @@ +--- +aliases: + - LSP + - Принцип подстановки Барбары Лисков +tags: + - maturity/🌱 +date: 2024-09-27 +--- +Принцип подстановки Лисков (Liskov Substitution Principle, LSP) утверждает, что ==объекты подклассов должны быть взаимозаменяемы с объектами базового класса без изменения поведения программы==. Это означает, что ==подклассы не должны нарушать контракт базового класса или изменять его логику==. LSP является третьим принципом в набор[[SOLID|е SOL]]ID и играет ключевую роль в создании устойчивой и понятной иерархии классов. + +**Чтобы соответствовать LSP:** +- Подклассы должны расширять функциональность базового класса, не изменяя его поведение. +- [[Контракт взаимодействия|Контракты]], задаваемые базовыми классами, должны строго соблюдаться. +- Следует избегать переопределения методов, если это изменяет их ожидаемое поведение. + +**Преимущества соблюдения LSP:** +1. **Предсказуемость:** Код, использующий базовый класс, будет работать одинаково независимо от того, какие подклассы используются. +2. **Упрощение тестирования:** Система становится менее подверженной ошибкам, так как базовый контракт всегда соблюдается. +3. **Гибкость и масштабируемость:** Добавление новых подклассов не требует модификации существующего кода, если соблюден принцип LSP. +4. **Улучшенная читаемость:** Четкое разделение обязанностей между базовыми и дочерними классами упрощает понимание системы. +## Пример нарушения LSP +Рассмотрим иерархию классов для птиц: + +```java +public class Bird { + public void fly() { + // Логика полета + System.out.println("I can fly!"); + } +} + +public class Penguin extends Bird { + @Override + public void fly() { + // Пингвин не может летать — нарушение LSP + throw new UnsupportedOperationException("Penguins cannot fly"); + } +} + +``` + +В данном случае класс `Penguin` нарушает контракт базового класса `Bird`. Код, который ожидает, что любой объект типа `Bird` может летать, перестанет работать корректно при использовании `Penguin`. Это ведет к непредсказуемому поведению программы и увеличивает сложность сопровождения. + +Для устранения нарушения следует пересмотреть иерархию классов, чтобы явно выделить летающих и нелетающих птиц: + +```java +public abstract class Bird { + // Общие свойства и методы для всех птиц +} + +public interface Flyable { + void fly(); +} + +public class FlyingBird extends Bird implements Flyable { + @Override + public void fly() { + // Реализация полета + System.out.println("I can fly!"); + } +} + +public class Penguin extends Bird { + // Пингвин остается нелетающей птицей +} + +``` + +Теперь поведение каждой птицы становится очевидным, и программа корректно работает с летающими и нелетающими птицами, не нарушая LSP. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: [[SOLID]] +**Источник**:: +**Создана**:: [[2024-09-27]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + diff --git a/dev/architecture/Long polling.md b/dev/architecture/Long polling.md new file mode 100644 index 00000000..92c3b57a --- /dev/null +++ b/dev/architecture/Long polling.md @@ -0,0 +1,29 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-11-03 +--- +**Long polling** — это метод опроса сервера, при котором клиент отправляет запрос и остается подключенным к серверу, ожидая ответа до тех пор, пока не появятся новые данные. Если серверу нечего отправить, он удерживает запрос открытым, пока не произойдет обновление, или пока не истечет тайм-аут. После получения ответа клиент сразу отправляет новый запрос для продолжения ожидания. + +**Преимущества:** +- Меньше нагрузка на сервер по сравнению с [[Short polling]], так как запросы отправляются реже, только когда есть новые данные. +- Обеспечивает более оперативное получение обновлений, чем при обычном коротком опросе. + +**Недостатки:** +- Задержка может быть непредсказуемой, особенно если данные появляются нерегулярно. +- Удержание открытого соединения может быть менее эффективным для серверов с ограниченными ресурсами, особенно при большом количестве клиентов. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-03]] +**Автор**:: +### Дополнительные материалы +- [[Short polling]] +- [[Webhook]] + +### Дочерние заметки + + diff --git a/dev/architecture/Open Closed Principle.md b/dev/architecture/Open Closed Principle.md new file mode 100644 index 00000000..73ab935b --- /dev/null +++ b/dev/architecture/Open Closed Principle.md @@ -0,0 +1,106 @@ +--- +aliases: + - Open/Closed Principle + - OCP + - Принцип открытости/закрытости +tags: + - maturity/🌱 +date: 2024-09-27 +--- +Классы и модули должны быть **открыты для расширения, но закрыты для модификации**. Это означает, что функциональность можно добавлять без изменения существующего кода. Такой подход позволяет минимизировать риск возникновения ошибок в уже работающей системе при внедрении новых функций. **Принцип открытости/закрытости (Open-Closed Principle, OCP)** является вторым из пяти [[SOLID]]-принципов и способствует созданию гибкой и поддерживаемой архитектуры. + +Обычно для реализации принципа используются: +- **Интерфейсы** или **абстрактные классы**, которые задают общую структуру поведения. +- [[Полиморфизм]], позволяющий создавать новые реализации без изменения базового кода. + +Следование OCP снижает [[связанность]] модулей, делает код проще в тестировании и облегчает внедрение новых функций. + +**Преимущества соблюдения OCP:** +1. **Гибкость кода:** Добавление нового функционала не требует изменений существующего кода, что снижает риск ошибок. +2. **Улучшенная тестируемость:** Изолированные реализации проще тестировать независимо друг от друга. +3. **Снижение связанности:** Код становится более модульным, и изменения в одной части системы не затрагивают другие. +4. **Поддерживаемость:** Разработчики могут легко добавлять новые возможности без угрозы сломать существующий функционал. + +## Пример нарушения OCP +Рассмотрим класс, который обрабатывает оплату, поддерживая только один способ оплаты через кредитную карту: + +```java +public class PaymentProcessor { + public void processPayment(String type, double amount) { + if (type.equals("credit_card")) { + // Логика оплаты через кредитную карту + } + } +} + +``` + +Если требуется добавить поддержку нового способа оплаты, например, PayPal, придется модифицировать метод `processPayment`: + +```java +public class PaymentProcessor { + public void processPayment(String type, double amount) { + if (type.equals("credit_card")) { + // Логика оплаты через кредитную карту + } else if (type.equals("paypal")) { + // Логика оплаты через PayPal + } + } +} + +``` + +Такой подход нарушает OCP, так как для добавления нового функционала приходится изменять уже существующий код. Это увеличивает риск ошибок и затрудняет сопровождение. + +Используем интерфейсы для реализации разных способов оплаты: + +```java +public interface PaymentMethod { + void pay(double amount); +} + +public class CreditCardPayment implements PaymentMethod { + @Override + public void pay(double amount) { + // Оплата через кредитную карту + } +} + +public class PayPalPayment implements PaymentMethod { + @Override + public void pay(double amount) { + // Оплата через PayPal + } +} +``` + +Теперь процессор оплаты будет работать с интерфейсом `PaymentMethod`, не завися от конкретных реализаций: + +```java +public class PaymentProcessor { + private PaymentMethod paymentMethod; + + public PaymentProcessor(PaymentMethod paymentMethod) { + this.paymentMethod = paymentMethod; + } + + public void processPayment(double amount) { + paymentMethod.pay(amount); + } +} + +``` + +Для добавления нового способа оплаты достаточно создать новую реализацию `PaymentMethod`, не изменяя код процессора. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: [[SOLID|SOLID]] +**Источник**:: +**Создана**:: [[2024-09-27]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + diff --git a/dev/architecture/Remote Procedure Call.md b/dev/architecture/Remote Procedure Call.md new file mode 100644 index 00000000..67a67de2 --- /dev/null +++ b/dev/architecture/Remote Procedure Call.md @@ -0,0 +1,27 @@ +--- +aliases: + - RPC +tags: + - maturity/🌱 +date: 2024-11-03 +--- +RPC (удалённый вызов процедур) — это **общая концепция и протокол**, позволяющая программе вызывать функции или методы, которые выполняются на удалённом сервере, так, как будто они выполняются локально. В RPC клиент запрашивает сервер, чтобы тот выполнил определённую функцию и вернул результат. Концепция RPC используется для создания распределённых систем, и её можно реализовать разными способами и технологиями. + +![[../../meta/files/images/Pasted image 20241103005803.png]] + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-03]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + +- [[gRPC]] + + diff --git a/dev/architecture/Representation State Transfer.md b/dev/architecture/Representation State Transfer.md new file mode 100644 index 00000000..e0c72e11 --- /dev/null +++ b/dev/architecture/Representation State Transfer.md @@ -0,0 +1,32 @@ +--- +aliases: + - REST + - REST API + - RESTful +tags: + - maturity/🌱 +date: 2024-11-03 +--- +Representation State Transfer (REST) - способ взаимодействия компонентов распределенного приложения в сети. + +![[../../meta/files/images/Pasted image 20241103004607.png]] + +- Использует стандартные HTTP-методы, такие как GET, POST, PUT, DELETE, для операций CRUD. +- Хорошо работает, когда вам нужны простые, единообразные интерфейсы между отдельными сервисами / приложениями. +- Стратегии кэширования просты в реализации. +- Недостатком является то, что для сбора связанных данных из отдельных конечных точек может потребоваться несколько обходов. + +![[../../meta/files/images/Pasted image 20241103020635.png]] +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]] +**Родитель**:: [[../architecture/Протоколы коммуникаций|Протоколы коммуникаций]] +**Источник**:: +**Создана**:: [[2024-11-03]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/architecture/Rеverse proxy.md b/dev/architecture/Rеverse proxy.md new file mode 100644 index 00000000..8bf1ad67 --- /dev/null +++ b/dev/architecture/Rеverse proxy.md @@ -0,0 +1,30 @@ +--- +aliases: +tags: + - maturity/🌱 +date: + - - 2024-04-13 +zero-link: + - "[[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]]" +parents: + - "[[../garden/ru/dev/architecture/Фронтенд|Фронтенд]]" +linked: +--- +Rеverse proxy позволяет снять часть задач с [[Бэкенд|бэкенда]]. + +Rеverse proxy решает следующие проблемы: +- **Организация https шифрования.** Клиенты подключаются к Reverse proxy по https, а прокси подключается к бэкенду по http. +- Буферизация запросов и ответов. +- Валидация http +- Борьба с медленными клиентами. Клиенты с плохим интернет соединением могут долго удерживать канал. Reverse proxy с бэкендом быстро обмениваются данными, Reverse Proxy буферизирует ответ с бэкенда и может довольно долго удерживать соединение с клиентом скармливая ему ответ. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]] +**Родитель**:: [[Фронтенд]] +**Источник**:: +**Автор**:: +**Создана**:: +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/architecture/SOLID.md b/dev/architecture/SOLID.md new file mode 100644 index 00000000..96aab879 --- /dev/null +++ b/dev/architecture/SOLID.md @@ -0,0 +1,37 @@ +--- +aliases: + - S.O.L.I.D. +tags: + - maturity/🌱 +date: 2024-09-27 +--- +**SOLID** — это набор из пяти принципов объектно-ориентированного проектирования, предложенных Робертом Мартином (Robert C. Martin), которые помогают создавать более понятные, гибкие и поддерживаемые системы. Эти принципы направлены на улучшение структуры кода и снижение его сложности, что упрощает расширение и поддержку проекта. + +- [[Single Responsibility Principle]] +- [[Open Closed Principle|Open/Closed Principle]] +- [[Liskov Substitution Principle]] +- [[Interface Segregation Principle]] +- [[Dependency Inversion Principle]] + +> [!WARNING] Недостижимый идеал +> Важно не применять принципы слепо, а учитывать контекст проекта и потребности системы. SOLID это идеал, к которому стоит стремиться, но который не достижим в реальной жизни. + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-09-27]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + +- [[Dependency Inversion Principle]] +- [[Interface Segregation Principle]] +- [[Liskov Substitution Principle]] +- [[Open Closed Principle]] +- [[Single Responsibility Principle]] + diff --git a/dev/architecture/Serverless.md b/dev/architecture/Serverless.md new file mode 100644 index 00000000..fc01dac8 --- /dev/null +++ b/dev/architecture/Serverless.md @@ -0,0 +1,53 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-12-08 +--- +**Serverless-архитектура** — это модель разработки приложений, при которой серверы все еще существуют, но управление ими полностью скрыто от разработчиков. Вместо этого, разработчики пишут небольшие, автономные функции, которые исполняются в облачной среде. Инфраструктурой управляет провайдер (например, AWS, Azure, Google Cloud). + +Несмотря на название, серверы в Serverless есть, но разработчики: +- Не управляют серверами напрямую. +- Не занимаются их настройкой, мониторингом или масштабированием. +- Платят только за фактическое время выполнения кода (pay-as-you-go). + +**Основные принципы** +- **Вызов на основе событий**. Код (функция) запускается в ответ на событие: HTTP-запрос, запись в базу данных, загрузка файла и т. д. Пример: загрузка изображения в облако запускает функцию для изменения его размера. +- **Автоматическое масштабирование**. Серверная инфраструктура автоматически увеличивает или уменьшает количество ресурсов в зависимости от нагрузки. Пример: при росте числа запросов добавляются новые инстансы функции. +- **Оплата за использование**. Вы платите только за фактическое время выполнения кода, а не за простаивающие серверы. Пример: если функция исполняется 200 мс, вы платите только за эти миллисекунды. +- **Фокус на коде**. Разработчики сосредотачиваются на написании бизнес-логики, а не на настройке инфраструктуры. + +**Преимущества Serverless** +- **Снижение затрат**. Отсутствие расходов на простаивающие ресурсы. Вы платите только за выполнение кода. +- **Автоматическое масштабирование**. Приложение автоматически адаптируется к изменяющимся нагрузкам. +- **Быстрота разработки**. Упрощённое управление инфраструктурой позволяет сосредоточиться на бизнес-логике. +- **Упрощённое развертывание**. Разработчики могут быстро выкатывать изменения, так как управление серверами осуществляется провайдером. + +**Недостатки** +- **Задержки холодного старта**. При запуске функции, которая долгое время не использовалась, может возникнуть задержка из-за необходимости инициализации контейнера. +- **Ограниченная гибкость**. Провайдеры накладывают ограничения на использование определённых языков, библиотек и объёма ресурсов. +- **Трудности отладки**. Локальное тестирование может быть сложным из-за особенностей облачных платформ. +- **Зависимость от провайдера**. Использование специфичных для платформы инструментов может усложнить переносимость приложения. +- **Высокая стоимость при больших нагрузках**. Для очень нагруженных систем Serverless может оказаться дороже традиционной модели. + +Serverless подходит, если: +- Вы разрабатываете приложения с переменной нагрузкой. +- Вам нужна быстрая обработка событий (ETL, IoT, уведомления). +- Вы хотите минимизировать управление инфраструктурой. + +Serverless может быть не лучшим выбором, если: +- Требуется минимальная задержка (например, в высоконагруженных системах реального времени). +- Вы работаете с задачами, требующими долгого выполнения или сложных вычислений. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]] +**Родитель**:: [[Архитектурный паттерн]] +**Источник**:: +**Создана**:: [[2024-12-08]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/architecture/Shared Database.md b/dev/architecture/Shared Database.md new file mode 100644 index 00000000..1421d892 --- /dev/null +++ b/dev/architecture/Shared Database.md @@ -0,0 +1,36 @@ +--- +aliases: + - общей базы данных +tags: + - maturity/🌱 +date: 2024-11-24 +--- +Подход "Shared Database" предполагает, что все микросервисы используют одну общую базу данных для хранения данных. Сервисы взаимодействуют напрямую с таблицами, которые принадлежат другим сервисам, что создает зависимости на уровне данных и разрушает [[Инкапсуляция|инкапсуляцию]] между микросервисами. + +Наличие одной базы данных для всех сервисов увеличивает [[Связность|связность]] системы и создаёт [[Bottlneck|узкое место]]. + +В [[../../../../wiki/zero/00 Микросервисная архитектура|микросервисной архитектуре]] подход, при котором все сервисы общаются с одной общей базой данных, считается скорее анти-паттерном. Несмотря на то, что в некоторых случаях это может показаться более простым решением, такой подход ведет к серьёзным ограничениям и проблемам, особенно в масштабируемых системах. Использование общей базы данных приводит к проблемам с разделением ответственности и нарушает принципы слабой [[Связанность|связанности]] и высокой [[Связность|связности]], которые являются основными в микросервисной архитектуре. + +**Проблемы подхода Shared Database** +- Сильная [[связанность]] между сервисами. Общая база данных приводит к явным и неявным зависимостям между сервисами. Это может проявляться через использование триггеров или процедур, которые затрагивают данные разных сервисов. Например, один сервис может использовать процедуру, изменяющую данные, которые принадлежат другому сервису. Такие зависимости делают каждый сервис уязвимым к изменениям в других сервисах. +- **Отсутствие независимости**. Микросервисы должны быть автономными, чтобы их можно было разрабатывать, тестировать и развёртывать независимо друг от друга. Использование общей базы данных приводит к необходимости координации изменений между разными сервисами, что нарушает эту независимость и замедляет процесс разработки. +- **Проблемы с масштабируемостью**. Когда все сервисы используют одну базу данных, её сложно масштабировать. Один сервис может использовать значительное количество ресурсов, создавая нагрузку на базу данных и замедляя работу остальных сервисов. Это делает независимое масштабирование отдельных компонентов практически невозможным. +- **Трудности с тестированием**. Тестирование сервисов в изолированном окружении становится гораздо сложнее, так как все они зависят от одной базы данных. Чтобы протестировать один сервис, нужно воссоздать всю структуру данных, что может потребовать значительных усилий. + +**Лучшие практики для избежания Shared Database** +- [[Database per Service]]. Каждый микросервис должен владеть своей собственной базой данных. Это позволяет сохранять автономность сервисов и исключает возможность прямого доступа к данным другого сервиса. +- **Событийная синхронизация.** Если данные одного сервиса нужны другому, лучше использовать [[Событийно-ориентированная архитектура|событийную архитектуру]]. Сервис, владеющий данными, может отправлять события, на которые подписываются другие сервисы, что помогает синхронизировать информацию без необходимости прямого доступа к общей базе данных. +- **Использование API для доступа к данным**. Вместо того чтобы обращаться к базе данных другого сервиса напрямую, следует использовать публичные API. Это позволяет соблюсти инкапсуляцию данных и уменьшить связанность между сервисами. +*** +## Мета информация +**Область**:: [[../../../../wiki/zero/00 Микросервисная архитектура|00 Микросервисная архитектура]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-24]] +**Автор**:: +### Дополнительные материалы +- [[Database per service]] + +### Дочерние заметки + + diff --git a/dev/architecture/Short polling.md b/dev/architecture/Short polling.md new file mode 100644 index 00000000..864bef86 --- /dev/null +++ b/dev/architecture/Short polling.md @@ -0,0 +1,33 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-11-03 +--- +**Short polling** — это метод опроса сервера, при котором клиент периодически отправляет запросы для проверки обновлений или новых данных. В отличие от постоянного соединения, клиент инициирует запросы через заданные интервалы, например, каждую секунду или каждые несколько секунд. + +![[../../meta/files/images/Pasted image 20241103010806.png|600]] + +**Преимущества:** +- Простая реализация, подходит для приложений, где данные обновляются редко. + +**Недостатки:** +- Высокая нагрузка на сервер и сеть из-за частых запросов, даже если данные не изменились. +- Может приводить к задержкам в получении данных, так как обновления видны только при очередном запросе. + + + +*** +## Мета информация +**Область**:: +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-03]] +**Автор**:: +### Дополнительные материалы +- [[../architecture/Long polling]] +- [[Webhook]] + +### Дочерние заметки + + diff --git a/dev/architecture/Single Responsibility Principle.md b/dev/architecture/Single Responsibility Principle.md new file mode 100644 index 00000000..a60d149d --- /dev/null +++ b/dev/architecture/Single Responsibility Principle.md @@ -0,0 +1,79 @@ +--- +aliases: + - SRP + - принцип единственной ответственности + - Single Responsibility + - единственная ответственность + - единственной ответственности +tags: + - maturity/🌱 +date: 2024-09-27 +--- +Каждый класс или метод должен иметь **только одну причину для изменения**, то есть решать одну задачу. Этот принцип называется **Принципом единственной ответственности (SRP)** и входит в набор [[SOLID]]-принципов, которые помогают создавать качественный и поддерживаемый код. + +> [!EXAMPLE] Причина для изменения +> Под "причиной для изменения" подразумевается аспект функциональности, который может измениться из-за изменения бизнес-требований. Например, класс, управляющий пользователями, должен модифицироваться только при изменении требований к управлению пользователями, но не из-за обновлений в логике отправки уведомлений. + +Классы или методы, выполняющие несколько задач, усложняют их поддержку. Любое изменение может неожиданно затронуть другие области, увеличивая вероятность ошибок и сложность тестирования. + +Каждый класс или метод должен иметь **только одну** причину для изменения, то есть решать лишь одну задачу. + +Преимущества: +1. **Упрощенная поддержка:** Изменения в одной части системы не влияют на другие, снижая риск побочных эффектов. +2. **Повышенная переиспользуемость:** Узкоспециализированные классы можно легко применять повторно. Например, класс `EmailService` можно использовать в разных модулях для отправки уведомлений без доработок. +3. **Улучшенная читаемость:** Четко определенные обязанности классов упрощают понимание кода для текущих и будущих разработчиков. +4. **Снижение риска ошибок:** Разделение ответственности на изолированные компоненты помогает уменьшить вероятность ошибок, так как изменения в одной области не затрагивают другую. +5. **Упрощение тестирования:** Можно протестировать независимо каждый компонент. + +## Пример нарушения SRP +Рассмотрим класс, который одновременно управляет данными пользователя и отправляет сообщения по электронной почте: + +```java +public class UserManager { + private String userData; + + public void updateUser(String data) { + // Логика управления пользователем + this.userData = data; + } + + public void sendEmail(String email, String message) { + // Логика отправки сообщений + System.out.println("Sending email to: " + email); + } +} + +``` + +Класс `UserManager` выполняет две разные задачи: управление данными пользователя и отправку уведомлений. ==Это нарушает принцип единственной ответственности, так как задачи имеют разные причины для изменения.== Такой подход увеличивает [[связанность]] кода, усложняет его поддержку и повышает риск ошибок. + +Разделите обязанности на отдельные классы: + +```java +public class UserService { + public void updateUser(String data) { + // Логика управления пользователем + } +} + +public class EmailService { + public void sendEmail(String email, String message) { + // Логика отправки сообщений + } +} + +``` + +Теперь каждое изменение будет затрагивать только соответствующий класс. Это улучшает читаемость, тестируемость и устойчивость к изменениям. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: [[SOLID]] +**Источник**:: +**Создана**:: [[2024-09-27]] +**Автор**:: +### Дополнительные материалы +- [[Bounded Context|Ограниченный контекст]] + +### Дочерние заметки + diff --git a/dev/architecture/Single point of failure.md b/dev/architecture/Single point of failure.md new file mode 100644 index 00000000..2864c7f4 --- /dev/null +++ b/dev/architecture/Single point of failure.md @@ -0,0 +1,42 @@ +--- +aliases: + - SPOF + - точка отказа + - единственная точка отказа +tags: + - maturity/🌱 +date: 2024-12-08 +--- +**Single Point of Failure (SPOF)** — это любой компонент [[../../../../_inbox/Информационная система|системы]], отказ которого приводит к её недоступности или снижению работоспособности. Такие компоненты являются критически важными для функционирования системы, и их выход из строя может иметь катастрофические последствия. + +SPOF часто встречается в системах с центральным узлом, на который приходится вся нагрузка или от которого зависит доступность других компонентов. + +**Примеры Single Point of Failure:** +- **Единственный сервер**. Если сервер, обрабатывающий запросы, выходит из строя, система перестает отвечать. +- База данных без [[highload/Репликация|репликации]]. При отказе центральной базы данных все операции, зависящие от неё, останавливаются. +- **Сетевой маршрутизатор или коммутатор**. Если устройство выходит из строя, теряется связь между частями системы. +- [[Централизованный сервис|Централизованный сервис]]. Например, единственная точка авторизации (Auth Service) может остановить работу всей системы при её отказе. +- **Единый источник питания**. Если отсутствует резервное питание, система будет недоступна при отключении электричества. + +**Методы устранения Single Point of Failure** +- [[highload/Репликация|Репликация]]. Создание копий компонентов (например, баз данных, серверов) для обеспечения их доступности при отказе одного из них. +- **Резервирование**. Установка резервного оборудования или программного обеспечения, которое автоматически включается в работу при отказе основного. +- **Распределение нагрузки**. Использование балансировщиков нагрузки для равномерного распределения запросов между несколькими серверами или сервисами. +- **Отказоустойчивые архитектуры**. Проектирование системы так, чтобы она могла продолжать работу, даже если один из компонентов выйдет из строя. +- [[Масштабирование информационной системы|Масштабирование]]. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-12-08]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + +- [[Централизованный сервис]] + + diff --git a/dev/architecture/Throughput.md b/dev/architecture/Throughput.md new file mode 100644 index 00000000..82af8019 --- /dev/null +++ b/dev/architecture/Throughput.md @@ -0,0 +1,46 @@ +--- +aliases: + - пропускная способность + - пропускной способности +tags: + - maturity/🌱 +date: + - - 2024-03-12 +zero-link: + - "[[../../meta/zero/00 HighLoad|00 HighLoad]]" +parents: +linked: +--- +Throughput - пропускная способность системы, то есть количество работы, которое система или процесс может выполнить в единицу времени. + +**В чем можно измерять:** +- Для web-систем + - Количество запросов в единицу времени + - Requests per seconds (RPS) + - Request per minute (RPM) + - Количество данных в единицу времени + - Packets per seconds (PPS) + - Мегабит в секунду (MB/s) + - Количество одновременно обслуживаемых соединений + - Simultaneous connections + - Cuncurrency +- Для баз данных + - транзакциях в секунду (т/с) + - операциях в секунду (оп/с) + +Что влияет на значение Throughput: +- Аппаратные ресурсы +- **Сетевая инфраструктура**: В сетевых системах скорость и пропускная способность сети, задержки, [потеря пакетов](Потеря%20пакетов.md), а также эффективность протоколов передачи данных играют ключевую роль в определении общей пропускной способности системы. +- **Масштабирование**: Способность системы к [горизонтальному](highload/Горизонтальное%20масштабирование.md) и [вертикальному масштабированию](highload/Вертикальное%20масштабирование.md) также влияет на Throughput. Горизонтальное масштабирование путем добавления дополнительных узлов может увеличить пропускную способность, но также добавляет накладные расходы на синхронизацию и управление. +- **Конфигурация системы**: Настройки и конфигурация системы, включая размеры пула соединений, размеры буферов и кэшей, могут влиять на производительность и пропускную способность. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 HighLoad|00 HighLoad]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-03-12]] +### Дополнительные материалы +- [[Latency]] +### Дочерние заметки + diff --git a/dev/architecture/Transactional Outbox.md b/dev/architecture/Transactional Outbox.md new file mode 100644 index 00000000..6f40d7d8 --- /dev/null +++ b/dev/architecture/Transactional Outbox.md @@ -0,0 +1,55 @@ +--- +aliases: + - transactional outbox + - транзакционный аутбокс +tags: + - maturity/🌱 +date: 2024-11-15 +--- +Transactional Outbox — это [[Паттерн проектирования|шаблон проектирования]], используемый в распределённых системах для обеспечения гарантированной отправки сообщений, особенно при интеграции с [[Брокер сообщений|брокерами сообщений]]. Этот шаблон помогает решить [[Отправка сообщений в Kafka из транзакции БД| проблему атомарности между изменениями в базе данных и отправкой событий]], гарантируя, что сообщение будет отправлено только после успешного выполнения транзакции в базе данных. + +**Схема работы:** +1. При выполнении бизнес-операции, например, при изменении данных в базе данных, создаётся запись в таблице `outbox`. Эта запись содержит сообщение, которое нужно отправить другим сервисам. +2. Операция создания записи в таблице `outbox` происходит в одной транзакции с основной бизнес-операцией. Это гарантирует, что и изменение данных, и запись сообщения будут выполнены атомарно. +3. После успешной фиксации транзакции фоновый процесс или отдельный компонент читает сообщения из таблицы `outbox` и отправляет их в [[брокер сообщений]]. +4. После успешной отправки сообщения запись в таблице outbox помечается как обработанная и спустя какое-то время удаляется. + +**Преимущества:** +- **Гарантированная доставка сообщений**: сообщения фиксируются вместе с бизнес-операциями, что предотвращает ситуацию, когда данные в базе данных обновлены, а сообщение не отправлено. +- **Упрощение архитектуры**: использование таблицы `outbox` вместо распределённых транзакций (2PC) значительно упрощает архитектуру и позволяет избежать сложных механизмов блокировки. + +**Недостатки:** +- **Дополнительная задержка**: отправка сообщений через фоновый процесс может вызвать небольшую задержку в доставке сообщений, по сравнению с немедленной отправкой. +- **Увеличение нагрузки на базу данных**: таблица `outbox` требует дополнительного хранения и управления, что увеличивает нагрузку на базу данных, особенно при большом объёме сообщений. + +Сначала необходимо создать таблицу `outbox` в вашей базе данных для хранения сообщений, ожидающих отправки в Kafka. + +Возможная структура `outbox` таблицы +```sql +CREATE TABLE outbox ( + id BIGSERIAL PRIMARY KEY, + topic VARCHAR(255) NOT NULL, + payload TEXT NOT NULL, + status VARCHAR(20) DEFAULT 'PENDING', + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); +``` +- `id`: Уникальный идентификатор записи. +- `topic`: Название топика/очереди, в который должно быть отправлено событие. +- `payload`: данные события. +- `status`: Статус обработки (`PENDING`, `SENT`, `FAILED`). +- `created_at` и `updated_at`: Временные метки для отслеживания создания и обновления записи. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: [[Паттерн проектирования]] +**Источник**:: +**Создана**:: [[2024-11-15]] +**Автор**:: +### Дополнительные материалы +- [[../../../../_inbox/Transactional Inbox|Transactional Inbox]] + +### Дочерние заметки + + diff --git a/dev/architecture/Webhook.md b/dev/architecture/Webhook.md new file mode 100644 index 00000000..bdd2a04a --- /dev/null +++ b/dev/architecture/Webhook.md @@ -0,0 +1,31 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-11-03 +--- +**Webhook** — это метод взаимодействия между системами, при котором один сервер автоматически отправляет HTTP-запрос на другой сервер, когда происходит определенное событие. В отличие от [[../architecture/Long polling|Long polling]] или [[../architecture/Short polling|Short polling]], клиенту не нужно регулярно проверять наличие обновлений; вместо этого он получает уведомление от сервера в режиме реального времени. + +![[../../meta/files/images/Pasted image 20241103010806.png|600]] + +**Преимущества:** +- Мгновенная доставка данных при возникновении события. +- Снижение нагрузки на сервер, так как нет необходимости в регулярных запросах. + +**Недостатки:** +- Требует настройки безопасности для предотвращения нежелательных вызовов (например, использование токенов или подписи). +- Сложнее тестировать и отлаживать, так как вебхуки зависят от событий, происходящих на сервере. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]] +**Родитель**:: [[../architecture/Протоколы коммуникаций]] +**Источник**:: +**Создана**:: [[2024-11-03]] +**Автор**:: +### Дополнительные материалы +- [[../architecture/Short polling]] +- [[../architecture/Long polling]] + +### Дочерние заметки + + diff --git a/dev/architecture/highload/CacheMissRate.md b/dev/architecture/highload/CacheMissRate.md new file mode 100644 index 00000000..6d1ca851 --- /dev/null +++ b/dev/architecture/highload/CacheMissRate.md @@ -0,0 +1,34 @@ +--- +aliases: +tags: + - maturity/🌱 +date: + - - 2024-06-18 +zero-link: + - "[[../../../meta/zero/00 HighLoad|00 HighLoad]]" +parents: + - "[[../Кэширование|Кэширование]]" +linked: + - "[[Оценка эффективности кэша|Оценка эффективности кэша]]" +--- +CacheMissRate показывает, насколько часто кэш не справляется с задачей хранения нужных данных и приходится обращаться к базе данных. Обычно рассчитывается как отношение количества промахов мимо кэша к общему количеству запросов на чтение данных. Формула для CacheMissRate выглядит так: + +``` +CacheMissRate= Количество промахов / Количество запросов. +``` + +Где: +• **Количество промахов** — это число случаев, когда данные не были найдены в кэше и потребовался доступ к базе данных. +• **Общее количество запросов** — это общее количество запросов на чтение данных, которые могут быть обслужены кэшем. + +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]] +**Родитель**:: [[../Кэширование|Кэширование]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-06-18]] +### Дополнительные материалы +- [[Оценка эффективности кэша]] +### Дочерние заметки + diff --git a/dev/architecture/highload/Content Delivery Network.md b/dev/architecture/highload/Content Delivery Network.md new file mode 100644 index 00000000..c443c5e5 --- /dev/null +++ b/dev/architecture/highload/Content Delivery Network.md @@ -0,0 +1,31 @@ +--- +aliases: + - CDN +tags: + - maturity/🌱 +date: + - - 2024-01-11 +zero-link: + - "[[../../../meta/zero/00 HighLoad|00 HighLoad]]" +parents: + - "[[../Кэширование|Кэширование]]" +linked: +--- +Распределенная географическая сеть кэширующих серверов по всему миру, которая позволяет доставлять контент до пользователей быстрее за счет более близкого расположения сервера к клиенту. + +Бывают push и pull реализации. В push CDN мы должны сами отправить данные, которые будут доступны из cdn. В pull модели CDN сама сходит на сервер за нужными данными. + +**Плюсы:** +- Географически распределенный кэш +- Уменьшает количество запросов на сервера +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]] +**Родитель**:: [[../Кэширование|Кэширование]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-01-11]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/architecture/highload/Disaster recovery.md b/dev/architecture/highload/Disaster recovery.md new file mode 100644 index 00000000..dab4e47c --- /dev/null +++ b/dev/architecture/highload/Disaster recovery.md @@ -0,0 +1,40 @@ +--- +aliases: + - DR + - восстановления + - восстановление +tags: + - maturity/🌱 +date: + - - 2024-03-05 +--- +Disaster Recovery (восстановление после сбоев) — это совокупность мер, направленных на восстановление [[Информационная система|ИТ-систем]] и операций после серьёзных сбоев, включая аппаратные отказы, кибератаки, природные катастрофы и ошибки пользователей. DR-планы разрабатываются для снижения времени простоя, минимизации потерь данных и обеспечения непрерывности бизнеса. + +Одна из ключевых проблем в DR — это потеря данных. В большинстве сценариев невозможно полностью избежать этой потери, особенно если системы не были спроектированы с высокой степенью [[Reliability|отказоустойчивости]]. Тем не менее, применение современных технологий может значительно сократить объём утраченных данных. + +Для оценки эффективности DR используются следующие метрики: +- **RTO (Recovery Time Objective).** Максимально допустимое время восстановления системы. +- **RPO (Recovery Point Objective).** Максимально допустимый объём данных, который можно потерять без критического ущерба. + +Разработка эффективного DR-плана включает: +1. **Анализ рисков.** Выявление возможных угроз и их последствий. +2. **Выбор стратегии.** Определение метрик RTO и RPO, а также подходящих технологий восстановления. +3. **Создание документации.** Подробный план действий в случае сбоя. +4. **Тестирование.** Регулярное проведение тестов на соответствие плана реальным угрозам. +5. **Обновление.** Корректировка плана в зависимости от изменений в инфраструктуре или бизнес-процессах. + +**Методы и инструменты DR** +- Резервное копирование + - [[Резервное копирование БД]] +- [[Репликация|Репликация]] +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-04-05]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/architecture/highload/Асинхронная репликация.md b/dev/architecture/highload/Асинхронная репликация.md new file mode 100644 index 00000000..399418ae --- /dev/null +++ b/dev/architecture/highload/Асинхронная репликация.md @@ -0,0 +1,53 @@ +--- +aliases: +tags: + - maturity/🌱 +date: + - - 2024-06-07 +zero-link: + - "[[../../../meta/zero/00 HighLoad|00 HighLoad]]" +parents: + - "[[Репликация БД]]" +linked: + - "[[Синхронная репликация]]" + - "[[Полу-синхронная репликация]]" +--- +Изменения записываются на master и пересылаются на slaves с некоторой задержкой. Этот метод отличается от синхронной репликации тем, что подтверждение транзакции возвращается клиенту до того, как изменения применены на всех репликах, что позволяет улучшить производительность, но может привести к несогласованности данных. + +Быстро, но не надежно. Возможно используется по умолчанию. Реализовано в [MySQL](../../../meta/zero/00%20MySQL.md), [PostgreSQL](../../../meta/zero/00%20PostgreSQL.md) + +Схема выполнения на MySQL. +![](../../../meta/files/images/Pasted%20image%2020240206195611.png) + +**Как работает** +- Подготовка транзакции в движке БД: Транзакция начинается на главном сервере, где собираются все изменения данных. +- Запись транзакции в лог: Все изменения записываются в журнал транзакций (например, Write-Ahead Log в PostgreSQL). +- Завершение транзакции в движке БД: Транзакция завершается на master. +- Возврат результата клиенту: Клиент получает подтверждение о завершении транзакции +- Пересылка лога репликам: Журнал транзакций отправляется на реплики для асинхронного применения изменений. +- Воспроизведение транзакции на репликах: Реплики получают журнал и применяют изменения к своим копиям данных, но это может произойти с задержкой. + +**Преимущества** +- Высокая производительность: Поскольку подтверждение транзакции возвращается клиенту до её применения на репликах, время отклика уменьшается, что улучшает производительность системы. +- Уменьшенная нагрузка на сеть: Пересылка изменений на реплики происходит асинхронно, что снижает нагрузку на сеть и позволяет более эффективно использовать сетевые ресурсы. +- Гибкость в использовании: Асинхронная репликация позволяет использовать реплики для различных задач, таких как отчеты или резервное копирование, без влияния на производительность главного сервера. + +**Минусы** +- Потеря данных при сбое: Если master выходит из строя до пересылки изменений на реплики, данные могут быть потеряны. Это может привести к несогласованности данных и необходимости восстановления системы. +- [Отставание реплики БД](Отставание%20реплики%20БД.md): Задержка в применении изменений на репликах может привести к отставанию реплик от master, что может затруднить выполнение некоторых операций, требующих актуальных данных. +- Проблемы с консистентностью данных: Каждая реплика может отставать по разному, из-за этого данные могут быть несогласованными между репликами. Например, пользователь может получить разные результаты для одного и того же запроса. + +## Примеры использования +Асинхронная репликация широко используется в системах, где высокая производительность и низкое время отклика имеют приоритет над полной консистентностью данных. Например, в системах аналитики и отчетности, где задержки в обновлении данных не критичны, асинхронная репликация позволяет эффективно распределять нагрузку и использовать реплики для выполнения сложных запросов, не влияя на производительность основного сервера. +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]] +**Родитель**:: [[Репликация БД]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-06-07]] +### Дополнительные материалы +- [[Синхронная репликация]] +- [[Полу-синхронная репликация|Полу-синхронная репликация]] +### Дочерние заметки + diff --git a/dev/architecture/highload/Балансировка нагрузки.md b/dev/architecture/highload/Балансировка нагрузки.md new file mode 100644 index 00000000..1ac4bbd6 --- /dev/null +++ b/dev/architecture/highload/Балансировка нагрузки.md @@ -0,0 +1,34 @@ +--- +aliases: + - балансировку нагрузки + - Балансировщик нагрузки + - балансировщики нагрузки + - балансировщиком нагрузки + - балансировщиком +tags: + - maturity/🌱 +date: 2024-06-13 +--- +![[../../../meta/files/images/Pasted image 20241103021050.png]] + +**Статические алгоритмы** +- **Round robin**. Запросы от клиентов отправляются поочередно разным экземплярам сервиса. Как правило, сервисы должны быть stateless (не сохранять состояние между запросами). +- **Sticky round-robin** Улучшенная версия алгоритма round robin. Если первый запрос от Алисы попал на сервис A, то и все последующие её запросы будут отправляться на этот же сервис A. +- **Weighted round-robin** Администратор может задать вес для каждого сервиса. Сервисы с большим весом будут обрабатывать больше запросов, чем другие. +- **Hash (Хеширование)** Этот алгоритм применяет хеш-функцию к IP-адресу или URL запроса. Запросы направляются на соответствующие экземпляры сервиса в зависимости от результата [[../../cryptography/Хеш-функция|хеш-функции]]. + +**Динамические алгоритмы** +- **Least connections**. Новый запрос отправляется экземпляру сервиса с наименьшим числом текущих соединений. +- **Least response time.** Новый запрос отправляется на экземпляр сервиса с самым быстрым временем отклика. + +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-06-13]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/architecture/highload/Безмастерная репликация.md b/dev/architecture/highload/Безмастерная репликация.md new file mode 100644 index 00000000..11cd4cdc --- /dev/null +++ b/dev/architecture/highload/Безмастерная репликация.md @@ -0,0 +1,67 @@ +--- +aliases: + - безмастерной репликацией +tags: + - maturity/🌱 +date: + - - 2024-06-04 +zero-link: + - "[[../../../meta/zero/00 Реляционная база данных|00 Реляционная база данных]]" +parents: + - "[[Репликация БД|Репликация БД]]" +linked: +--- +Безмастерная репликация — это метод репликации в котором отсутствует главный master. Все узлы системы являются равноправными. + +Клиентские приложения могут записывать данные на любой узел системы. Более того ==запросы отправляются сразу на все реплики, но применяются только на тех, которые доступны в данный момент.== + +Для успешного завершения операции записи требуется подтверждение от определенного количества реплик (W). Если количество успешных записей превышает значение W, операция считается успешной. ==Если их меньше, но не 0, отката транзакции не будет.== + +Клиентские приложения читают данные со всех доступных в данный момент реплик. Для успешного чтения требуется подтверждение от определенного количества реплик (R). Если количество ответивших реплик превышает значение R, операция считается успешной. + +![800](../../../meta/files/images/Pasted%20image%2020240226135429.png) + +Формула расчета кворума: W + R > number of replics +- W - в каком количестве реплик должна примениться запись, чтобы мы считали ее успешной +- R - со скольки реплик мы должны прочитать значение ключа, чтобы считать, что чтение прошло успешным + +**Преимущества:** +- **Высокая доступность:** Поскольку все узлы являются равноправными, система не имеет единой точки отказа. Даже если несколько узлов выйдут из строя, остальные узлы продолжают обслуживать запросы. +- **Горизонтальное масштабирование:** Безмастерная репликация позволяет легко добавлять новые узлы для повышения производительности и масштабируемости системы. +- **Гибкость конфигурации:** Система может быть настроена для достижения различных уровней консистентности и доступности, в зависимости от требований приложений. + +**Проблемы:** +- [Нестрогий кворум](Нестрогий%20кворум.md). Возможно чтение старых данных при W+R < N +- Проблемы с откатом транзакций: В безмастерной репликации отсутствует механизм отката транзакций, что может усложнить управление ошибками и восстановление данных. + - Как в таком случае работает обновление при чтении или противодействие энтропии, ведь эти данные становятся новыми. +- Проблемы с консистентностью данных: Поскольку запись данных может происходить на нескольких узлах одновременно, возникает риск конфликтов и несогласованности данных. Для разрешения конфликтов используются различные методы, такие как Last Write Wins или версионирование данных. +- Конфликт записей и [Потерянное обновление](Потерянное%20обновление.md). +- Проблемы с линеаризуемостью. + +**Поддержание консистентности:** +- Анти-энтропия. Реплики могут периодически синхронизоваться друг с другом, чтобы обеспечить консистентность данных. +- Противодействие энтропии. Внешний клиент опрашивает все ноды, находит устаревшие данные и обновляет их. +- Обновление при чтении (Set on read). Берем последнюю версию после чтения и отправляем в реплики с устаревшими данными. +- Last write wins. Кто последний записал, те данные и верные. +- [Happens before](Happens%20before.md). +- Векторы версий. +- [Tombstone](../../Tombstone.md) + +Такая репликация есть в: +- DynamoDB +- [[Cassandra]] +- Scylla (Переписанная на C++ Cassandra) +- Riak +- Voldemort + +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]] +**Родитель**:: [[Репликация БД|Репликация БД]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-06-04]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/architecture/highload/Вертикальное масштабирование.md b/dev/architecture/highload/Вертикальное масштабирование.md new file mode 100644 index 00000000..200ace3b --- /dev/null +++ b/dev/architecture/highload/Вертикальное масштабирование.md @@ -0,0 +1,35 @@ +--- +aliases: + - вертикальном масштабировании + - вертикальному масштабированию + - scale-up +tags: + - maturity/🌱 +date: + - - 2024-03-12 +--- +Вертикальное масштабирование представляет собой увеличение мощности существующей машины или сервера путем добавления более мощных процессоров, большего объема оперативной памяти, большей емкости хранения данных и так далее, без добавления дополнительных машин в систему. Это противоположность [горизонтального масштабирования](Горизонтальное%20масштабирование.md), при котором мощность системы увеличивается за счет добавления дополнительных узлов. + +**Плюсы:** +1. **Простота управления**: Управление одной машиной обычно проще, чем управление кластером машин, что упрощает администрирование и техническое обслуживание. +2. **Совместимость с приложениями**: Вертикальное масштабирование часто не требует изменений в архитектуре или конфигурации приложений, что делает его более простым в реализации для некоторых систем. +3. **Меньшая сложность**: Отсутствие необходимости в распределенной обработке данных упрощает архитектуру и может обеспечить более высокую производительность для определенных типов задач. +4. **Немедленное улучшение производительности**: Добавление ресурсов к существующему серверу может обеспечить немедленное улучшение производительности без необходимости перераспределения данных или изменения архитектуры системы. +- Самый простой способ масштабирования + +**Проблемы:** +1. **Ограничения аппаратного обеспечения**: Существует предел, до которого можно улучшить аппаратные характеристики одной машины, что ограничивает максимально достижимое масштабирование. +2. **Высокие затраты**: Мощное аппаратное обеспечение может быть значительно дороже, особенно когда речь идет о высокопроизводительных компонентах. Каждое следующее обновление железа обходится дороже предыдущего. +3. **Риск сбоев**: Увеличение зависимости от одного сервера повышает риск того, что сбой этого сервера приведет к полной недоступности системы. +4. **Простои при апгрейде**: Улучшение аппаратных характеристик сервера часто требует временного отключения и простоя, что может негативно сказаться на доступности сервиса. +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]] +**Родитель**:: [[../Масштабирование информационной системы|Масштабирование информационной системы]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-03-12]] +### Дополнительные материалы +- [[Горизонтальное масштабирование]] +### Дочерние заметки + diff --git a/dev/architecture/highload/Горизонтальное масштабирование.md b/dev/architecture/highload/Горизонтальное масштабирование.md new file mode 100644 index 00000000..35db53db --- /dev/null +++ b/dev/architecture/highload/Горизонтальное масштабирование.md @@ -0,0 +1,39 @@ +--- +aliases: + - горизонтального масштабирования +tags: + - maturity/🌱 +date: + - - 2024-03-12 +--- +Горизонтальное масштабирование это процесс увеличения мощности системы за счет добавления дополнительных узлов в распределенную сеть, а не за счет увеличения мощности уже существующих узлов (как это происходит при [вертикальном масштабировании](Вертикальное%20масштабирование.md)). + +**Плюсы:** +- **Масштабируемость**: Горизонтальное масштабирование позволяет системе легко масштабироваться в соответствии с увеличением нагрузки, добавляя больше машин в кластер. Теоретически бесконечно, но физически есть пределы. +- **Гибкость**: Можно добавлять дополнительные ресурсы по мере необходимости, что позволяет лучше адаптироваться к изменяющимся требованиям без простоев. +- **Надежность и доступность**: Распределение нагрузки и данных между множеством узлов может улучшить общую надежность и доступность системы, так как отказ одного узла не приведет к сбою всей системы. +- **Географическое распределение**: Узлы могут быть географически распределены, что помогает минимизировать задержки и улучшить производительность для пользователей в разных регионах. + +**Проблемы:** +1. **Сложность управления**: Управление множеством узлов и их координация может быть значительно сложнее, чем управление одним мощным сервером. Нужно делать балансировку вызовов. +2. **Сложность разработки**: Разработка приложений, способных эффективно использовать ресурсы в распределенной среде, может быть более сложной, а значит программисты обходятся дороже. +3. **Согласованность данных**: Обеспечение согласованности данных между множеством узлов может представлять собой вызов, особенно в системах, где требуется высокий уровень согласованности. +4. **Затраты на сеть**: Горизонтальное масштабирование может повлечь за собой увеличенные затраты на сетевое оборудование и управление сетью, особенно если узлы географически распределены. + +Частные проблемы: +- [[../Проблема горизонтального масштабирования Websocket|Проблема горизонтального масштабирования Websocket]] +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]] +**Родитель**:: [[../Масштабирование информационной системы|Масштабирование информационной системы]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-03-12]] +### Дополнительные материалы +- [[Вертикальное масштабирование]] +### Дочерние заметки + + +- [[Репликация]] +- [[Проблема горизонтального масштабирования Websocket]] + diff --git a/dev/architecture/highload/Групповая репликация.md b/dev/architecture/highload/Групповая репликация.md new file mode 100644 index 00000000..bf9920ff --- /dev/null +++ b/dev/architecture/highload/Групповая репликация.md @@ -0,0 +1,40 @@ +--- +aliases: +tags: + - maturity/🌱 +date: + - - 2024-06-05 +zero-link: + - "[[../../../meta/zero/00 HighLoad|00 HighLoad]]" +parents: + - "[[Репликация БД]]" +linked: +--- +Работает как [Репликация master-master](Репликация%20master-master.md), но при количестве узлов больше 2 + +- Все транзакции чтения и записи фиксируются только после того, как они были одобрены группой. +- Read-only транзакции не требуют координации внутри группы и фиксируются немедленно +- Групповая репликация - eventual consistency система + +![](../../../meta/files/images/Pasted%20image%2020240605091036.png) + +## Консенсус +- Когда транзакция read-write готова к фиксации на исходном сервере, сервер атомарно передает значения записи (строки, которые были изменены) и соответствующий набор записи (уникальные идентификаторы строк, которые были обновлены). +- Транзакция отправляется через атомарную broadcast рассылку, транзакцию получают либо все серверы в группе, либо ни один. +- Если они его получат, то все они получат его в том же порядке относительно других транзакций, которые были отправлены ранее. + +Таким образом, все серверы получают один и тот же набор транзакций в одном и том же порядке, и для транзакций устанавливается глобальный общий порядок. + +## Дополнительные материалы +- [MySQL 20.1.1.2 Group Replication](https://dev.mysql.com/doc/refman/8.0/en/group-replication-summary.html) +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]] +**Родитель**:: [[Репликация БД]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-06-05]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/architecture/highload/Идемпотентность на базе уникального идентификатора.md b/dev/architecture/highload/Идемпотентность на базе уникального идентификатора.md new file mode 100644 index 00000000..2c6031a9 --- /dev/null +++ b/dev/architecture/highload/Идемпотентность на базе уникального идентификатора.md @@ -0,0 +1,33 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-11-12 +--- +При реализации [[../Идемпотентность|идемпотентности]] в системах, где требуется многократная обработка событий или вызовов, [[../../../meta/zero/00 Redis|Redis]] может быть использован как ключевой инструмент для предотвращения повторной обработки сообщений. Данное решение подходит для различных систем обмена сообщениями, таких как [[../../../../../_inbox/00 Kafka|Kafka]], [[../../gRPC|gRPC]], [[../../network/HyperText Transfer Protocol|HTTP]], и других видов асинхронных или синхронных вызовов. +### Основной подход +Каждое сообщение или запрос должен иметь уникальный идентификатор, обычно называемый **requestId**. Этот идентификатор присваивается при создании сообщения или вызова и передаётся вместе с ним в процессе обработки. Потребитель, получая сообщение, сначала проверяет наличие **requestId** в Redis. Этот подход позволяет контролировать, было ли сообщение уже обработано и в каком оно состоянии. + +Алгоритм выглядит следующим образом: +1. **Получение сообщения**: Потребитель получает сообщение, извлекает **requestId** и проверяет его наличие в Redis. + 1. Если **requestId** уже существует в Redis и статус обработки указывает на **COMPLETED**, потребитель ничего не делает и отправляет **ack** (подтверждение) в Kafka (или другой источник). +2. **Обработка сообщения**: Если **requestId** отсутствует в Redis или статус обработки указывает на **FAILED**, потребитель, то потребитель обрабатывает сообщение. Перед обработкой статус в Redis обновляется на **IN_PROGRESS** с TTL, например, 40 секунд. +3. **Запись результата**: + - После успешной обработки статус в Redis обновляется на **COMPLETED**, и устанавливается длительный TTL, например, на 3-24 часа, чтобы сигнализировать, что это сообщение уже было успешно обработано и повторная обработка не требуется. + - Если при обработке возникает ошибка, статус обновляется на **FAILED** и потребитель отправляет **nack** в Kafka (или другой источник). +### Рекомендации по реализации +- **Уникальность requestId**: Генерируйте **requestId** таким образом, чтобы обеспечить его уникальность в пределах всей системы, например, используя UUID или другие подходящие алгоритмы. +- **Оптимальный TTL**: Выберите TTL в зависимости от требований к ретеншену данных. Слишком короткий TTL может привести к потере информации об обработке, а слишком длинный — к переполнению Redis. +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]] +**Родитель**:: [[../Идемпотентность|Идемпотентность]] +**Источник**:: +**Создана**:: [[2024-11-12]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/architecture/highload/Инвалидация кэша.md b/dev/architecture/highload/Инвалидация кэша.md new file mode 100644 index 00000000..275419cf --- /dev/null +++ b/dev/architecture/highload/Инвалидация кэша.md @@ -0,0 +1,65 @@ +--- +aliases: + - инвалидации кэша +tags: + - maturity/🌱 +date: + - - 2024-06-18 +zero-link: + - "[[../../../meta/zero/00 HighLoad|00 HighLoad]]" +parents: + - "[[../Кэширование|Кэширование]]" +linked: +--- +Инвалидация кэша это процесс удаления данных из кэша при изменении состояния источника. Причем очень желательно, чтобы кэш сбрасывался сразу же за изменением. Например, мы закэшировали выборку из БД, рано или поздно исходные данные таблицы изменятся, и кэш перестает быть валидным. + +**Способы инвалидации:** +- По истечению срока действия - TTL. + - Самая простая реализация. + - При малом TTL будет высокий [CacheMissRate](CacheMissRate.md) + - При большом TTL данные могут быть не консистентны +- По событию + - Опасно из-за риска мгновенной инвалидации и сопутствующей [[Перестройка кэша|перестройки кэша]] +- Использование [[../../algorithm/Алгоритм вытеснения кэша|алгоритмов вытеснения]] + +Дополнительно для работы со статическими файлами можно отменить [[../Fingerprint|Fingerprint]]. + +## Инвалидация по TTL +Один из подходов это инвалидация по времени. Для кэшированных данных устанавливается TTL, и по прошествию времени кэш удаляется. Такое вариант подходит для редко изменяемых данных, устаревание которых не приводит к серьезным проблемам в бизнес-логике, например словари. + +При таком варианте важно подобрать оптимальное время жизни кэша, слишком маленькое время жизни будет давать плохую производительность, слишком большое ухудшит опыт пользователей. В оценке эффективности кэша поможет метрика [[CacheMissRate]]. +## Инвалидация по событию +В этом случае мы удаляем данные кэша по какому-то событию. Например, при вызове метода обновления данных можно удалить кэш, который связан с этими данными. В некоторых случаях можно не удалять, а сразу класть новые данные в кэш, если понимаете, что они скоро потребуются. + +Инвалидацию по событию можно комбинировать с TTL. В таком случае при запросе данных из кэша можно проверять оставшееся время жизни, и если оно меньше, чем некоторое заданное значение, то установить TTL заново. Таким образом данные остаются в кэше, если ими активно пользуются. + +Пример реализации механизма обновления TTL на Lua: +```lua +local key = KEYS[1]; +local threshold = tonumber(ARGV[1]); +local new_ttl = tonumber(ARGV[2]); +local value = redis.call('get', key); +if value then + local ttl = redis.call('pttl', key); + if ttl >= 0 and ttl <= threshold then + redis.call('pexpire', key, new_ttl); + end; +end; +return value; +``` +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]] +**Родитель**:: [[../Кэширование|Кэширование]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-06-18]] +### Дополнительные материалы +- +### Дочерние заметки + + +- [[Алгоритм вытеснения кэша]] +- [[Fingerprint]] + + diff --git a/dev/architecture/highload/Ключ кэширования.md b/dev/architecture/highload/Ключ кэширования.md new file mode 100644 index 00000000..072b408f --- /dev/null +++ b/dev/architecture/highload/Ключ кэширования.md @@ -0,0 +1,63 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-09-13 +zero-link: + - "[[../../../meta/zero/00 HighLoad|00 HighLoad]]" +parents: + - "[[Кэширование]]" +linked: +--- +Представим, что нам нужно кэшировать результат работы следующего метода: + +```java +public List getUsersByType(String userType, Set userIds) +``` + +Метод принимает 2 аргумента: строку и коллекцию. Ключ кэширования должен учитывать значения этих входящих аргументов и должен обладать следующими свойствами: +- При изменении параметров, ключ кэширования также должен изменяться. В данном случае, если изменятся значения аргументов `userType` и `userIds`, мы должны получить новое значение ключа. +- По параметрам ключ должен определяться однозначно, то есть для одних и тех же значений аргументов ключ кэширования должен принимать только одно значение. Иначе мы рискуем понизить эффективность процесса кэширования, создавая несколько кэшей для одной и той же выборки. + +Сформируем ключ кэширования для нашего метода. В качестве хранилища будем использовать [[../../../meta/zero/00 Redis]]. + +В начале ключа я обычно обязательно указываю какой-то уникальный префикс сервиса, чтобы не получить коллизию между разными сервисами. Пускай в данном случае префикс будет `USER_SERVICE`. Также добавляю уникальный префикс метода, в данном случае будет `USERS`. + +В качестве разделителей рекомендую использовать `:`, в [[../../../meta/zero/00 Redis|00 Redis]] это позволяет визуально сгруппировать ключи. Это позволяет визуально группировать ключи при использовании UI клиента. Таким образом начало нашего ключа выглядит следующим образом: `USER_SERVICE:USERS:`. + +Значения аргументов метода также должны попасть в ключ. Возьмем наш первый аргумент `String userType`. Для аргумента также можно использовать префиксы, но это не обязательно. В данном случае пусть будет `USER_TYPE`. А вот для самого значения параметра есть несколько вариантов: +- Оставить строкой и просто выполнить конкатенацию. +- Использовать [[../../cryptography/Хеш-функция|хеш-функцию]] с фиксированной длиной выхода, например [[../../cryptography/MD5|MD5]]. Фиксированная длина выхода нужна, чтобы иметь предсказуемую и ограниченную длину ключа. + +Оставим просто строкой, так как тип пользователя вряд ли может быть длинным. В итоге пока наш ключ выглядит как-то так: `USER_SERVICE:USERS:USER_TYPE:VIP:`. + +Переходим ко второму аргументу `Set userIds`. С коллекцией все будет сложнее. Мы точно должны использовать какую-нибудь [[../../cryptography/Хеш-функция|хеш-функцию]], но как? + +> [!WARNING] Disclamer +> Этот способ я придумал сам, возможно он не самый удачный, но он работает. Если вы придумаете лучше, напишите в комментариях ниже 👇 + +Во-первых, коллекцию необходимо предварительно отсортировать. Иначе на одинаковые параметры коллекций мы будем получать разные результаты [[../../cryptography/Хеш-функция|хеш-функции]]. + +Во-вторых, нужно представить коллекцию как что-то понятное для [[../../cryptography/Хеш-функция|хеш-функции]]. Для этого я преобразую коллекцию в JSON. JSON используется, потому что ваша коллекция может быть из сложных объектов. + +Теперь используем [[../../cryptography/SHA-256|SHA-256]], чтобы из нашей строки получить какой-то хеш. И уже этот хеш мы добавляем к нашему ключу, получается примерно такое: + +``` +USER_SERVICE:USERS:USER_TYPE:VIP:USER_ID:315f5bdb76d078c43b8ac0064e4a0164612b1fce77c869345bfc94c75894edd3 +``` + +> [!QUESTION] Почему SHA-256, а не MD5? +> [[../../cryptography/MD5|MD5]] подвержен коллизиям, [[../../cryptography/SHA-256|SHA-256]] считается более устойчивым к коллизиям. + + +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]] +**Родитель**:: [[../Кэширование|Кэширование]] +**Источник**:: +**Создана**:: [[2024-09-13]] +**Автор**:: +### Дополнительные материалы +- [[../../snippet/Реализация SHA-256 на Java|Реализация SHA-256 на Java]] +### Дочерние заметки + diff --git a/dev/architecture/highload/Кэширование на стороне браузера.md b/dev/architecture/highload/Кэширование на стороне браузера.md new file mode 100644 index 00000000..a51fcf83 --- /dev/null +++ b/dev/architecture/highload/Кэширование на стороне браузера.md @@ -0,0 +1,48 @@ +--- +aliases: [] +tags: + - maturity/🌱 +date: + - - 2024-06-17 +zero-link: + - "[[../../../meta/zero/00 HighLoad|00 HighLoad]]" +parents: + - "[[../Кэширование|Кэширование]]" +linked: +--- +Статический контент — это элементы веб-сайта, которые остаются неизменными на протяжении долгого времени на всех страницах. К такому контенту относятся файлы изображений, CSS и JavaScript. Поскольку эти файлы редко изменяются, их можно сохранять в кэше браузера пользователя. Это позволяет браузеру загружать локальные копии файлов, а не запрашивать их каждый раз с сервера, что ускоряет работу сайта. + +Обычно кэшируются только GET запросы, так как они должны быть [[../Идемпотентность|идемпотентны]]. + +Управление кэшированием часто осуществляется с помощью http-заголовков. Заголовки для кэширования: +- ETAG. Тег, который позволяет указать версию файла. Можно использовать [[../../cryptography/MD5|MD5]]. +- [[../../network/Условный GET запрос|If-Modified-Since]]. Дата изменения файла. +- Cache-Control. Передает инструкции по выполнению кэширования. + - public - Сохранять может не только браузер, но и промежуточные узлы + - private - Сохранять может только браузер клиента + - no-store - не кэшируем. ==не уверен что правильно записал== + - no-cache - Сохранять только в браузере, не сохранять на промежуточных серверах. ==не уверен что правильно записал== + - max-age - Сколько нужно хранить файл в памяти +- LocalStorage. Можно через JS складывать данные. + + +![](../../../meta/files/images/Pasted%20image%2020240619083856.png) + +Инвалидация: +- Самый простой вариант указывать версию в GET параметрах. +- Для статики можно использовать [[../Fingerprint|Fingerprint]] + +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]] +**Родитель**:: [[../Кэширование|Кэширование]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-06-17]] +### Дополнительные материалы +- [[../../devops/nginx/Кэширование статики в Nginx]] +### Дочерние заметки + + +- [[Кэширование статики в Nginx]] + diff --git a/dev/architecture/highload/Монотонное чтение.md b/dev/architecture/highload/Монотонное чтение.md new file mode 100644 index 00000000..b7aa1691 --- /dev/null +++ b/dev/architecture/highload/Монотонное чтение.md @@ -0,0 +1,26 @@ +--- +aliases: +tags: + - maturity/🌱 +date: + - - 2024-06-07 +zero-link: + - "[[../../../meta/zero/00 HighLoad|00 HighLoad]]" +parents: + - "[[Репликация БД]]" +linked: +--- +Монотонное чтение — это проблема, возникающая при репликации данных, когда пользователи могут получить несогласованные результаты при выполнении последовательных запросов. Это происходит, когда изменения на мастере не успевают синхронизироваться с репликами, и разные запросы пользователя могут попадать на реплики с различными состояниями данных. +## Пример проблемы монотонного чтения +Рассмотрим ситуацию, когда пользователь запрашивает список комментариев к статье. Если новый комментарий был добавлен и записан на мастер, но ещё не успел синхронизироваться со всеми репликами, пользователь может столкнуться с несогласованными результатами: + +1. Пользователь делает первый запрос и получает список комментариев без нового комментария. +2. Пользователь делает второй запрос и получает список комментариев, включающий новый комментарий. +3. При следующем запросе пользователь снова может не увидеть новый комментарий, если его запрос попадает на другую реплику. + +![](../../../meta/files/images/Pasted%20image%2020240607211612.png) + +## Методы решения проблемы монотонного чтения +- Привязка пользователя к конкретной реплике (stickiness): Один из способов решения проблемы монотонного чтения — это привязка пользователя к конкретной реплике для всех последовательных запросов. Это можно реализовать с помощью сессий или токенов, обеспечивая пользователю доступ к одной и той же реплике, пока она доступна. +- Настройка задержек при чтении: Можно настроить задержки при чтении данных с реплик, чтобы обеспечить их синхронизацию с мастером. Например, задержка может быть настроена таким образом, чтобы реплики всегда отставали от мастера на фиксированное время, достаточное для синхронизации данных. +- Использование кворумных чтений: В системах с [[Безмастерная репликация|безмастерной репликацией]] можно использовать кворумные чтения, когда запросы выполняются на нескольких репликах одновременно, и результат считается успешным только если он подтвержден большинством реплик. Это повышает вероятность получения актуальных данных. \ No newline at end of file diff --git a/dev/architecture/highload/Отставание реплики БД.md b/dev/architecture/highload/Отставание реплики БД.md new file mode 100644 index 00000000..2c9e3f56 --- /dev/null +++ b/dev/architecture/highload/Отставание реплики БД.md @@ -0,0 +1,37 @@ +--- +aliases: + - лаг репликации + - задержки репликации + - задержка репликации +tags: + - maturity/🌱 +date: + - - 2024-06-04 +zero-link: + - "[[../../../meta/zero/00 HighLoad|00 HighLoad]]" +parents: + - "[[Репликация БД]]" +linked: +--- +Отставание реплики (или лаг репликации) — это проблема, возникающая, когда изменения, выполненные на мастере, не успевают применяться на репликах вовремя. Это может привести к несогласованности данных между мастером и репликами и затруднить выполнение операций, требующих актуальных данных. + +В нормальной ситуации отставание может достигать 1 секунды. + +![](../../../meta/files/images/Pasted%20image%2020240219184314.png) + +Так как в [[../../../meta/zero/00 PostgreSQL|PostgreSQL]] мы передаем не сам запрос, а блоки данных, то отставание по идее должно быть меньше, чем в [[../../../meta/zero/00 MySQL|MySQL]]. + +Что может приводить к лагу: +- Медленные и сложные запросы: Если реплики выполняют сложные или ресурсоемкие запросы, это может замедлить процесс применения изменений. +- Сетевые проблемы: Задержки в сети могут замедлить передачу журнала транзакций (WAL) от мастера к репликам. +- Размер журнала транзакций: Большие объемы изменений могут создать нагрузку на систему репликации, увеличивая время обработки. +- Проблемы с дисковой подсистемой: Медленные дисковые операции на репликах могут замедлить процесс применения изменений. + +Рекомендации: +- Оптимизация запросов: Оптимизация сложных запросов может снизить нагрузку на реплики и ускорить процесс применения изменений. Это включает в себя индексацию, переработку запросов и использование эффективных алгоритмов. + - Убивайте медленные запросы. Если запрос висит уже 10 секунд, то лучше его прибить. +- Использование выделенных реплик: Для выполнения сложных запросов или резервного копирования можно использовать выделенные реплики, что позволит снизить нагрузку на основные реплики, обеспечивающие актуальность данных. +- Подумайте о кросс-СУБД репликации Репликация из реляционной бд в NoSQL +- Избегайте [[../../database/Write-read pattern|Write-read pattern]] +- Выделить отдельный жесткий диск под [Журнал БД](../../database/Журнал%20БД.md), чтобы обеспечить эксклюзивный доступ к ресурсам диска, тем самым улучшая производительность. Менее актуально для SSD. +- Настройка параметров репликации: Оптимизация параметров репликации, таких как размер WAL и частота его отправки, может помочь уменьшить лаг репликации. В PostgreSQL, например, можно настроить параметры wal_level и max_wal_senders для оптимизации процесса репликации. \ No newline at end of file diff --git a/dev/architecture/highload/Оценка эффективности кэша.md b/dev/architecture/highload/Оценка эффективности кэша.md new file mode 100644 index 00000000..5ade225e --- /dev/null +++ b/dev/architecture/highload/Оценка эффективности кэша.md @@ -0,0 +1,40 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-09-11 +zero-link: + - "[[../../../meta/zero/00 HighLoad|00 HighLoad]]" +parents: + - "[[../Кэширование|Кэширование]]" +linked: + - "[[CacheMissRate|CacheMissRate]]" +--- +По формуле можно рассчитать среднее время доступа к данным. + +``` +AverageTime = CacheAccessTime + DbAccessTime * CacheMissRate +``` + +Где: +- AverageTime - среднее время жизни кэша +- CacheAccessTime - время доступа к кэшу +- DbAccessTime - время доступа к БД +- [[CacheMissRate|CacheMissRate]] - количество промахов мимо кэша. От 0 до 1. + +Например, пусть +- DbAccessTime = 100ms +- CacheAccessTime = 20ms +- Тогда при [[CacheMissRate|CacheMissRate]] > 0.8 - кэш вреден. + +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]] +**Родитель**:: [[../Кэширование|Кэширование]] +**Источник**:: +**Создана**:: [[2024-09-11]] +**Автор**:: +### Дополнительные материалы +- [[CacheMissRate|CacheMissRate]] +### Дочерние заметки + diff --git a/dev/architecture/highload/Перестройка кэша.md b/dev/architecture/highload/Перестройка кэша.md new file mode 100644 index 00000000..69c5ba8e --- /dev/null +++ b/dev/architecture/highload/Перестройка кэша.md @@ -0,0 +1,35 @@ +--- +aliases: + - thundering herd +tags: + - maturity/🌱 +date: + - - 2024-06-18 +zero-link: + - "[[../../../meta/zero/00 HighLoad|00 HighLoad]]" +parents: + - "[[../Кэширование|Кэширование]]" +linked: +--- +Представим, что у нас 3 реплики сервиса, которые выполняют какие-то вычисления раз в 30 секунд, а в вычислениях используется кэшированные значения. При [[Инвалидация кэша|инвалидации кэша]] может сложиться ситуация при которой все 3 реплики начнут наперегонки обновлять значение в кэше. Это приводит как минимум к лишней нагрузке на базу данных, а как максимум к отказу в обслуживании. + +Решить эту проблему можно с использованием [[../../fundamental/Блокировка|блокировок]]: +- Получаем доступ к кэшу, его срок жизни истёк. Пытаемся заблокироваться по ключу. + - Не удалось получить блокировку + - Ждём снятия [[../../fundamental/Блокировка|блокировки]]. + - Если не дождались, возвращаем старые данные кэша + - Если дождались, значит кто-то построил кэш за нас, выбираем значения ключа заново, возвращаем новые данные. + - Удалось получить блокировку + - Строим кэш самостоятельно + - Снимаем блокировку +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]] +**Родитель**:: [[../Кэширование|Кэширование]] +**Источник**:: +**Автор**:: +**Создана**:: +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/architecture/highload/Полу-синхронная репликация.md b/dev/architecture/highload/Полу-синхронная репликация.md new file mode 100644 index 00000000..c0e1b7ba --- /dev/null +++ b/dev/architecture/highload/Полу-синхронная репликация.md @@ -0,0 +1,53 @@ +--- +aliases: + - semi-sync +tags: + - maturity/🌱 +date: + - - 2024-06-07 +zero-link: + - "[[../../../meta/zero/00 HighLoad|00 HighLoad]]" +parents: + - "[[Репликация БД]]" +linked: + - "[[Асинхронная репликация]]" + - "[[Синхронная репликация]]" +--- +Полу-синхронная репликация — это компромиссный метод между [[Синхронная репликация|синхронной]] и [[Асинхронная репликация|асинхронной]] репликацией. Он обеспечивает более высокую надежность данных по сравнению с асинхронной репликацией, но при этом снижает время отклика по сравнению с синхронной. + +Комит прошел на одной реплике, но данные по транзакции были скопированы во все остальные реплики, но еще не были применены. + +Реализовано в [MySQL](../../../meta/zero/00%20MySQL.md) + +Схема выполнения на MySQL ![](../../../meta/files/images/Pasted%20image%2020240206195639.png) + +**Как работает** +- Подготовка транзакции в движке БД: Транзакция начинается на master, где собираются все изменения данных. +- Запись транзакции в лог: Все изменения записываются в журнал транзакций. +- Пересылка лога репликам: Журнал транзакций отправляется на реплики. Master ждет подтверждения от как минимум одной реплики о получении журнала, но не обязательно его применении. +- Завершение транзакции в движке БД: После получения подтверждения от одной или нескольких реплик транзакция завершается на master, и клиент получает подтверждение. +- Воспроизведение транзакции на репликах: Реплики применяют полученные изменения к своим копиям данных, но это может произойти с задержкой. + +**Преимущества** +- Баланс между надежностью и производительностью: Полу-синхронная репликация обеспечивает более высокую надежность данных по сравнению с асинхронной репликацией, так как master ждет подтверждения от реплик перед завершением транзакции. Это снижает риск потери данных при сбое. +- Сниженное время отклика: В отличие от синхронной репликации, master не ждет подтверждения от всех реплик, что снижает время отклика и повышает производительность системы. +- Меньшая вероятность отставания данных: Благодаря ожиданию подтверждения от реплик перед завершением транзакции, вероятность отставания данных на репликах уменьшается. + +**Минусы** +- Проблемы с консистентностью данных: Хотя master ждет подтверждения от одной или нескольких реплик, данные на других репликах могут оставаться несогласованными до применения изменений, что может привести к проблемам с консистентностью. [Фантомное чтение](Фантомное%20чтение.md). +- Сложность управления: Полу-синхронная репликация требует более сложной настройки и управления по сравнению с асинхронной репликацией, так как необходимо следить за подтверждениями от реплик и управлять задержками. +- Увеличенное время отклика по сравнению с асинхронной репликацией: Несмотря на снижение времени отклика по сравнению с синхронной репликацией, полу-синхронная репликация все же медленнее асинхронной, так как требует ожидания подтверждений от реплик. +## Примеры использования +Полу-синхронная репликация часто используется в системах, где требуется баланс между надежностью данных и производительностью. Например, в финансовых системах, где важна высокая доступность и консистентность данных, но при этом необходимо обеспечить приемлемое время отклика для клиентов. Полу-синхронная репликация позволяет снизить риск потери данных при сбоях и поддерживать консистентность данных на более высоком уровне, чем асинхронная репликация. +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]] +**Родитель**:: [[Репликация БД]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-06-07]] +### Дополнительные материалы +- [[Асинхронная репликация]] +- [[Синхронная репликация]] +### Дочерние заметки + diff --git a/dev/architecture/highload/Репликация master-master.md b/dev/architecture/highload/Репликация master-master.md new file mode 100644 index 00000000..09fed559 --- /dev/null +++ b/dev/architecture/highload/Репликация master-master.md @@ -0,0 +1,55 @@ +--- +aliases: +tags: + - maturity/🌱 +date: + - - 2024-03-10 +zero-link: + - "[[../../../meta/zero/00 HighLoad|00 HighLoad]]" +parents: + - "[[Репликация БД]]" +linked: + - "[[Репликация master-slave]]" +--- +Все реплики являются ведущими (master). Во все реплики можно писать изменения, а они каким-то образом синхронизируются между собой. Ведущие реплики могут также иметь дополнительные реплики в режиме [[Репликация master-slave|репликации master-slave]]. + +![](Pasted%20image%2020240206194251.png) + +**Плюсы**: +- Нет единой точки отказа +- Дает максимальный [Availability](../../../../../_inbox/Availability.md). +- Легкий failover + +**Минусы:** +- Нет консистентности. Могут возникать конфликты при одновременной работе с одним и тем же набором данных на разных репликах. +- Усложнение логики. Встречается редко. +- Все равно не масштабирует запись. Для масштабирования нужно использовать [шардирование](Шардирование%20БД.md). + +**Варианты применения:** +- Географическая распределенность. Репликация между ЦОД-ами в разных странах. Улучшается производительность, так как пользователь из страны работает с ближайшим ЦОД. Вы устойчивы к потере ЦОД и к сетевым проблемам, так как данные есть в других ЦОД-ах. +- Hot-standby реплика (VIP). Второй мастер всегда на готове, на случай если упадет основной. Во время штатной работы второй мастер не используется. +- Offline клиенты. При плохом или вовсе временно отсутвующем интерент соединении для ассинхронного объединения данных. CouchDB является примером такой БД. + +Варианты реализаций: +- Amazon Aurora +- Google Spanner +## Решение конфликтов +- Избегайте конфликтов. Организуйте взаимодействие так, чтобы конфликты не возникали. +- Last write wins. Выигрывает последняя запись. Но обычно сложно определить кто был первым. +- Ранг реплик. Выигрывает запись от старейшей реплки. +- Слияние. Автоматическое объединение конфликтных данных. +- Решение конфликтов на клиенте. +- Conflict-free replicated data types (CRDT). +- Mergeable persistent data structures. + - В этом режиме работает [00 Git](../../../meta/zero/00%20Git.md) +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]] +**Родитель**:: [[Репликация БД]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-03-10]] +### Дополнительные материалы +- [[Репликация master-slave]] +### Дочерние заметки + diff --git a/dev/architecture/highload/Репликация master-slave.md b/dev/architecture/highload/Репликация master-slave.md new file mode 100644 index 00000000..6e18930f --- /dev/null +++ b/dev/architecture/highload/Репликация master-slave.md @@ -0,0 +1,38 @@ +--- +aliases: + - репликации master-slave +tags: + - maturity/🌱 +date: + - - 2024-03-10 +zero-link: + - "[[../../../meta/zero/00 HighLoad|00 HighLoad]]" +parents: + - "[[Репликация БД|Репликация БД]]" +linked: + - "[[Репликация master-master]]" +--- +В такой схеме у нас есть одна ведущая реплика (master) в которую пишутся изменения и несколько ведомых реплик (slave), на которые эти изменения копируются, из них можно только читать. Это наиболее распространенный подход репликации, так как он относительно прост и понятен. + +![](Pasted%20image%2020240206194227.png) + +**Проблемы и недостатки:** +- Мастер обязательно когда-нибудь упадет. И нужно будет как-то выбрать из slaves нового master. +- Как и другие способы репликации не ускоряет операции вставки данных. +- Этот способ никогда не даст 99,9999 [Availability](../../../../../_inbox/Availability.md). + +Управление master-slave: +- MHA (MySQL Master HA) +- MySQL Failover (Oracle) +- Orchestrator +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]] +**Родитель**:: [[Репликация БД|Репликация БД]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-03-10]] +### Дополнительные материалы +- [[Репликация master-master|Репликация master-master]] +### Дочерние заметки + diff --git a/dev/architecture/highload/Репликация БД.md b/dev/architecture/highload/Репликация БД.md new file mode 100644 index 00000000..6ec5b4d7 --- /dev/null +++ b/dev/architecture/highload/Репликация БД.md @@ -0,0 +1,100 @@ +--- +aliases: + - репликация базы данных + - репликацию бд +tags: + - maturity/🌱 +date: + - - 2024-03-10 +zero-link: + - "[[../../../meta/zero/00 HighLoad|00 HighLoad]]" + - "[[../../../meta/zero/00 DevOps|00 DevOps]]" + - "[[../../../meta/zero/00 Реляционная база данных|00 Реляционная база данных]]" +parents: + - "[[Репликация|Репликация]]" +linked: +--- +## Тезисы +- Репликация это копирование измененных данных с одного сервера БД на другой. +- Не отменяет первоначального копирования БД. Сначала нужно первый раз скопировать данные, а потом уже запустить репликацию. +- Репликация не является [резервной копией БД](../../../../../_inbox/Резервное%20копирование%20БД.md). +- Обычно реализуются на базе [[../../database/Журнал БД|журнала БД]]. +- Плюсы: + - Помогает улучшить [Availability](../../../../../_inbox/Availability.md). Помогает при падении. + - Ускоряет чтение данных +- Проблемы: + - Не ускоряет запись в БД + - [Отставание реплики БД](Отставание%20реплики%20БД.md) + - [[Монотонное чтение|Монотонное чтение]] + - Репликация это ресурсозатратно. +- Репликации БД: + - [Репликация в MySQL](../../database/mysql/Репликация%20в%20MySQL.md) + - [Репликация в PostgreSQL](../../database/postgresql/Репликация%20в%20PostgreSQL.md) +*** +Репликация позволяет сделать N копий одной БД. Обычно есть одна ведущая копия, которую называют master, и есть N ведомых реплик, которые называют slaves. + +Репликация не отменяет первоначального копирования БД. Сначала нужно первый раз скопировать данные, а потом уже запустить репликацию. + +**Для чего делают репликацию?** +- [[../../../../../_inbox/Availability|Availability]]. Если один сервер выходит из строя, другие реплики продолжают обслуживать запросы, обеспечивая непрерывный доступ к данным. +- **Масштабирование чтения**. Нагрузка на чтение может быть распределена между несколькими репликами, что улучшает производительность системы. +- **Распределение нагрузки**. Сложные аналитические запросы для построения отчетов и асинхронное [резервное копирование БД](../../../../../_inbox/Резервное%20копирование%20БД.md) могут выполняться на отдельных репликах, не нагружая основной сервер. +- **Географическое распределение**. Реплики могут быть размещены ближе к пользователям в разных регионах, уменьшая задержки доступа к данным. + +**Недостатки репликации:** +- Не позволяет получить увеличение производительности запросов на вставку данных. Для этого нужно использовать [[../../../../../_inbox/Шардирование БД|шардирование]]. +- **Сложность управления**. Управление несколькими репликами требует дополнительных ресурсов и сложной конфигурации. Это включает настройку синхронизации данных, мониторинг состояния реплик и управление конфликтами. +- **Ресурсозатратность**. Поддержание нескольких копий данных требует дополнительных ресурсов, что может значительно увеличить расходы на инфраструктуру. +- **Проблемы консистентности:** В асинхронной репликации данные на разных репликах могут быть несогласованными, что может привести к проблемам с консистентностью. Например, пользователь может получить разные результаты для одного и того же запроса, если реплики не успели синхронизироваться. +## Роль журнала БД в репликации +Прямой способ сделать репликацию - это скопировать [[../../database/Журнал БД|журнал БД]] с master на slave и применить его. PostgreSQL работает именно так используя журнал [WAL](../../database/postgresql/Write-Ahead%20Log.md). Однако, не все так просто. Формат и возможности журнала напрямую зависят от СУБД. + +![](Pasted%20image%2020240531083508.png) +## Классификация репликаций +- **По синхронизации.** Гарантия наличия и доступности. + - [Синхронная репликация](Синхронная%20репликация.md) + - [Асинхронная репликация](Асинхронная%20репликация.md) + - [Полу-синхронная репликация](Полу-синхронная%20репликация.md) +- **По уровню работы** + - Физическая репликация. Работа на уровне хранилища, мы работаем напрямую со страницами памяти + - [Write-Ahead Log](../../database/postgresql/Write-Ahead%20Log.md) в PostgreSQL + - [InnoDB Undo/Redo Log](../../database/mysql/Журналы%20в%20MySQL.md#InnoDB%20Undo/Redo%20Log) в MySQL + - Логическая репликация. Работает с кортежами. Мы храним набор кортежей до и после. + - [Row-based Binary Log](../../database/mysql/Журналы%20в%20MySQL.md#Row-based%20Binary%20Log) в MySQL + - [Statement-based Binary Log](../../database/mysql/Журналы%20в%20MySQL.md#Statement-based%20Binary%20Log) недоразумение, которое работает на уровне запросов. Для такой репликации нужно выполнять запрос на слейве, и если запрос выполнялся 30 минут, то и на слейве он будет выполняться 30 минут. Также присутсвует зависимость в функциях, например функция времени вернет одно значение на мастере и совершенно другое на слейве. +- **По расспространению изменений** + - push. мастер сует, слейву пофиг. Реализуется редко. (Postgres) + - pull. слейв качает, мастеру пофиг. (MySQL) +- **По количеству точек записи** + - [Репликация master-slave](Репликация%20master-slave.md) + - [Репликация master-master](Репликация%20master-master.md) + - [Безмастерная репликация](Безмастерная%20репликация.md) + - [Групповая репликация](Групповая%20репликация.md). Реализовано в MySQL. +## Проблемы +- [Отставание реплики БД](Отставание%20реплики%20БД.md) +- [Монотонное чтение](Монотонное%20чтение.md) +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]], [[../../../meta/zero/00 DevOps|00 DevOps]], [[../../../meta/zero/00 Реляционная база данных|00 Реляционная база данных]] +**Родитель**:: [[../../../../../source/курсы/otus/Архитектор высоких нагрузок 2019/Лекция. Репликация|Лекция. Репликация]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-03-10]] +### Дополнительные материалы +- +### Дочерние заметки + + +- [[Асинхронная репликация]] +- [[Безмастерная репликация]] +- [[Групповая репликация]] +- [[Монотонное чтение]] +- [[Отставание реплики БД]] +- [[Полу-синхронная репликация]] +- [[Репликация master-master]] +- [[Репликация master-slave]] +- [[Синхронная репликация]] +- [[Согласованное префиксное чтение]] +- [[Репликация в MySQL]] +- [[Репликация в PostgreSQL]] + diff --git a/dev/architecture/highload/Репликация.md b/dev/architecture/highload/Репликация.md new file mode 100644 index 00000000..a2713bb3 --- /dev/null +++ b/dev/architecture/highload/Репликация.md @@ -0,0 +1,38 @@ +--- +aliases: + - зеркалирование + - репликацию + - репликации +tags: + - maturity/🌱 +date: + - - 2024-06-05 +zero-link: + - "[[../../../meta/zero/00 HighLoad|00 HighLoad]]" +linked: +--- +Один из видов [горизонтального масштабирования](Горизонтальное%20масштабирование.md), который позволяет создать несколько копий одного узла системы. + +**Плюсы:** +- Помогает при падениях +- Можно размазать нагрузку по узлам + +**Минусы:** +- Всегда ресурсозатратно. + +**Виды репликации:** +- [Репликация БД](Репликация%20БД.md) +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]] +**Родитель**:: [[Горизонтальное масштабирование]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-06-05]] +### Дополнительные материалы +- +### Дочерние заметки + + +- [[Репликация БД]] + diff --git a/dev/architecture/highload/Синхронная репликация.md b/dev/architecture/highload/Синхронная репликация.md new file mode 100644 index 00000000..a3e2666f --- /dev/null +++ b/dev/architecture/highload/Синхронная репликация.md @@ -0,0 +1,45 @@ +--- +aliases: +tags: + - maturity/🌱 +date: + - - 2024-06-07 +zero-link: + - "[[../../../meta/zero/00 Реляционная база данных|00 Реляционная база данных]]" +parents: + - "[[Репликация БД]]" +linked: + - "[[Асинхронная репликация]]" + - "[[Полу-синхронная репликация]]" +--- +При получении запроса от клиента master ожидает, пока все реплики получат новые данные и подтвердят их применение у себя, и только после этого сообщает клиенту, что запрос успешно выполнен. Работает надежно, но медленно. + +Реализовано в [PostgreSQL](../../../meta/zero/00%20PostgreSQL.md). + +**Механизм работы**: +- Подготовка транзакции в движке БД: Транзакция начинается на главном сервере (мастере), где собираются все изменения данных. +- Запись транзакции в лог: Все изменения записываются в журнал транзакций, что обеспечивает возможность восстановления данных в случае сбоя. +- Пересылка лога репликам: Журнал транзакций отправляется на все реплики для синхронного применения изменений. +- Выполнение транзакций на репликах: Реплики применяют полученные изменения к своим копиям данных. +- Завершение транзакции в движке БД: После успешного применения изменений на всех репликах транзакция завершается. +- Возврат результата клиенту: Клиент получает подтверждение о завершении транзакции только после того, как изменения применены на всех репликах. + +**Плюсы:** +- Высокая надежность данных: Данные не теряются даже в случае сбоя одного из серверов, так как изменения применяются на всех репликах одновременно. +- Консистентность данных: Обеспечивается консистентность данных на всех репликах, что исключает возможность получения различных результатов для одного и того же запроса. + +**Минусы:** +- Увеличенное время отклика: Поскольку подтверждение транзакции возвращается клиенту только после её завершения на всех репликах, время отклика увеличивается. Это может негативно сказаться на производительности системы, особенно при большом количестве реплик. +- Высокая вероятность сбоев: С увеличением числа реплик общая вероятность сбоя возрастает, так как транзакция завершается только при успешном выполнении на всех репликах. Если хотя бы одна реплика не отвечает, транзакция не может быть завершена. +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]] +**Родитель**:: [[Репликация БД]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-06-07]] +### Дополнительные материалы +- [[Асинхронная репликация|Асинхронная репликация]] +- [[Полу-синхронная репликация|Полу-синхронная репликация]] +### Дочерние заметки + diff --git a/dev/architecture/highload/Согласованное префиксное чтение.md b/dev/architecture/highload/Согласованное префиксное чтение.md new file mode 100644 index 00000000..0b6c26fd --- /dev/null +++ b/dev/architecture/highload/Согласованное префиксное чтение.md @@ -0,0 +1,32 @@ +--- +aliases: +tags: + - maturity/🌱 +date: + - - 2024-06-07 +zero-link: + - "[[../../../meta/zero/00 HighLoad|00 HighLoad]]" +parents: + - "[[Репликация БД]]" +linked: +--- +Ситуация, которая возникает при наличии нескольких master-ов ([[Репликация master-master]] или [[Групповая репликация]]) или при [Шардирование БД](Шардирование%20БД.md). + +У нас есть 2 участника чата и один сторонний наблюдатель. Сначала один пользователь пишет в чат, а следом другой пользователь пишет в чат. Далее наблюдатель читает сообщения из реплики, в которую сначала пришло второе сообщение, а потом только первое. + +![](../../../meta/files/images/Pasted%20image%2020240607212223.png) + +**Возможные решения:** +- Сортировка по какому-то монотонному полю. +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]] +**Родитель**:: [[Репликация БД]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-06-07]] +### Дополнительные материалы +- +### Дочерние заметки + + diff --git a/dev/architecture/highload/Старт с холодным кэшем.md b/dev/architecture/highload/Старт с холодным кэшем.md new file mode 100644 index 00000000..eba5cdf9 --- /dev/null +++ b/dev/architecture/highload/Старт с холодным кэшем.md @@ -0,0 +1,29 @@ +--- +aliases: +tags: + - maturity/🌱 +date: + - - 2024-06-18 +zero-link: + - "[[../../../meta/zero/00 HighLoad|00 HighLoad]]" +parents: + - "[[../Кэширование|Кэширование]]" +linked: +--- +После аварии кэш, скорее всего будет [[Инвалидация кэша|инвалидирован]]. А в случае не персистентных хранилищ кэша не будет точно после отключения питания. Для некоторых систем подняться с не прогретым кэшом сложная задача. + +Что может помочь: +- Заранее напишите скрипт прогрева кэшей +- Возвращайте нагрузку плавно +- Помните о том, что нагрузку стоит уметь держать без кэш +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 HighLoad|00 HighLoad]] +**Родитель**:: [[../Кэширование|Кэширование]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-06-18]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/architecture/Архитектура as Code.md b/dev/architecture/Архитектура as Code.md new file mode 100644 index 00000000..9c836ec1 --- /dev/null +++ b/dev/architecture/Архитектура as Code.md @@ -0,0 +1,40 @@ +--- +aliases: + - AaC +tags: + - maturity/🌱 +date: 2024-12-21 +--- +Архитектура as Code (AaC) — это методология, при которой архитектурные решения и схемы описываются с использованием программного кода. Подход вдохновлен концепцией [[Infrastructure as Code]] (IaC), но применяется к более высокоуровневым аспектам системы, таким как взаимодействие сервисов, модули, [[Контракт взаимодействия|контракты]] и зависимости. + +Пример: вместо создания диаграммы вручную, архитектура описывается в YAML или JSON-файле, который затем может быть интерпретирован для создания визуализации или проверки соответствия системе. + +**Основные принципы** +- **Декларативность.** Архитектура описывается в виде декларативного файла, который служит источником правды для всей команды. +- **Автоматизация.** Использование кода для автоматической проверки архитектурных решений и их применения. +- **Интеграция.** Возможность связки с CI/CD пайплайнами для проверки соответствия архитектурным стандартам. +- **Версионность.** Все изменения архитектуры фиксируются в системе контроля версий, что позволяет отслеживать её эволюцию. + +**Ограничения** +- **Сложность внедрения.** Требуются опыт и компетенции команды для реализации подхода. +- **Обучение.** Необходимо обучать специалистов работать с инструментами AaC. +- **Необходимость дисциплины.** Без четкого подхода может возникнуть хаос в коде архитектуры. + +**Инструменты** +- [Structurizr](https://structurizr.com) — для описания архитектуры на основе C4-модели. +- OpenAPI/AsyncAPI — для описания API. +- Terraform, Pulumi — для связи архитектурного описания с инфраструктурой. +- DSL (Domain-Specific Languages) — собственные языки для описания архитектуры. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-12-21]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/architecture/Архитектурная карта.md b/dev/architecture/Архитектурная карта.md new file mode 100644 index 00000000..9c79f65f --- /dev/null +++ b/dev/architecture/Архитектурная карта.md @@ -0,0 +1,48 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-11-26 +--- +Архитектурные карты — это **визуальное представление** системы, ее структуры, связей и компонентов. Они служат инструментом для анализа, проектирования и коммуникации, упрощая понимание системы всеми заинтересованными сторонами: разработчиками, аналитиками, архитекторами и бизнес-заказчиками. + +Архитектурная карта может включать в себя несколько [[Архитектурная схема|архитектурных схем]]. + +**Зачем нужны архитектурные карты?** +- **Упрощение коммуникации**. Карты выступают общим языком между командами. Например, разработчики и бизнес могут быстрее обсуждать проблемы и принимать решения, опираясь на общее визуальное представление системы. +- **Целостное видение системы**. Архитектурные карты помогают увидеть всю систему как единое целое, включая связи между компонентами и взаимодействие с внешними системами. +- **Выявление “слепых зон”**. Визуализация выявляет незадокументированные связи, зависимости и потенциальные уязвимости. +- **Анализ и планирование изменений**. Карты позволяют моделировать изменения, предсказывать их влияние и оценивать риски. + +**Виды архитектурных карт** +- **Концептуальные карты**. Они описывают общую идею системы и ее назначение. + - Упор на крупные блоки системы (например, модули или бизнес-процессы). + - Подходят для общения с бизнес-заказчиками. +- **Логические карты**. Подробное описание структуры системы: модули, компоненты и их взаимодействие. + - Включают элементы архитектуры ПО, не зависящие от конкретной реализации. + - Используются для проектирования и анализа решений на уровне разработки. +- **Физические карты**. Описывают конкретную реализацию системы: сервера, базы данных, сети и прочее. + - Применяются при развертывании и поддержке системы. + - Подходят для DevOps, инфраструктурных инженеров и архитекторов. + +**Как создавать и поддерживать карты?** +- **Определите цель карты**. Например, если задача — объяснить бизнесу назначение системы, стоит сделать концептуальную карту. +- **Используйте подходящие инструменты**. Для создания архитектурных карт популярны инструменты вроде Lucidchart, Draw.io, PlantUML и [[ArchiMate]]. +- **Обеспечьте актуальность**. Регулярно обновляйте карты при изменении системы, чтобы они оставались полезными и точными. +- **Уточняйте уровень детализации**. Для разных целей нужны разные уровни абстракции. Например, высокоуровневый обзор для презентаций и более детальная схема для команды разработки. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-26]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + +- [[Архитектурная схема]] + + diff --git a/dev/architecture/Архитектурная концепция.md b/dev/architecture/Архитектурная концепция.md new file mode 100644 index 00000000..655d19ab --- /dev/null +++ b/dev/architecture/Архитектурная концепция.md @@ -0,0 +1,43 @@ +--- +aliases: + - архитектурных принципов + - архитектурный принцип +tags: + - maturity/🌱 +date: 2024-10-01 +--- +Архитектурная концепция это общая идея или принцип построения архитектуры системы или отдельного компонента системы. + +**Цель**: +- Определить базовые принципы, которые будут направлять разработку всей системы. +- Решать проблемы на уровне системы, а не отдельных компонентов. +## Классификация +- [[Архитектурный паттерн]] +- [[Паттерн проектирования]] + +Прочие концепции: +- [[Inversion of Control]] +- [[Infrastructure as Code]] +- [[Один клиент — один поток]] +- [[Много клиентов — один поток]] +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-10-01]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + +- [[Inversion of Control]] +- [[Архитектурный паттерн]] +- [[Большой комок грязи]] +- [[Много клиентов — один поток]] +- [[Один клиент — один поток]] +- [[Паттерн проектирования]] +- [[Infrastructure as Code]] + diff --git a/dev/architecture/Архитектурная схема.md b/dev/architecture/Архитектурная схема.md new file mode 100644 index 00000000..dd75cfca --- /dev/null +++ b/dev/architecture/Архитектурная схема.md @@ -0,0 +1,54 @@ +--- +aliases: + - архитектурные схемы + - архитектурных схем +tags: + - maturity/🌱 +date: 2024-11-26 +--- +Архитектурная схема — это детализированное визуальное представление структуры и функционирования системы. Она помогает понять, как устроена система, какие компоненты входят в её состав и как они взаимодействуют друг с другом. + +Архитектурная схема позволяет уменьшить [[../../psychology/Семантический разрыв|семантический разрыв]] при технических обсуждениях. + +**Основная цель архитектурной схемы** +- **Технической документации** — фиксации текущего состояния системы. +- **Разработки и тестирования** — схемы позволяют командам лучше понимать структуру системы и её компоненты. +- **Оптимизации и масштабирования** — упрощают анализ узких мест и прогнозирование последствий изменений. +- **Устранения ошибок** — помогают найти и исправить проблемы благодаря наглядности взаимодействий. + +**Виды архитектурных схем** +- **Модульная схема**. Отображает модули системы и их взаимодействия. + - Применяется для анализа высокоуровневой структуры ПО. + - Удобна на этапе проектирования или реструктуризации системы. +- **Компонентная схема**. Фокусируется на более детальном описании архитектуры компонентов и их связей. + - Используется для анализа взаимозависимостей и проектирования новых компонентов. +- **Схема потоков данных (Data Flow Diagram)**. Показывает, как данные перемещаются между модулями и компонентами. Полезна для проектирования интеграции и анализа производительности. +- **Инфраструктурная схема** Описывает физическую реализацию системы: сервера, сети, базы данных и т.д. Используется для DevOps и управления инфраструктурой. + +**Основные элементы архитектурной схемы** +- **Компоненты** — отдельные части системы, такие как модули, сервисы или базы данных. +- **Интерфейсы** — точки взаимодействия между компонентами (например, API). +- **Связи** — связи или зависимости между компонентами, указывающие на передачу данных или управление. +- **Процессы и потоки данных** — движения информации внутри системы. + +**Как создать архитектурную схему?** +- **Определите цель**. Зачем создается схема? Для документации, обсуждения с командой или анализа системы? От цели зависит уровень детализации. +- **Соберите информацию**. Перечислите все компоненты системы, их взаимодействия и внешние зависимости. +- **Выберите инструмент**. Для создания схем можно использовать инструменты, такие как Draw.io, PlantUML, Lucidchart или Visio. +- **Обеспечьте ясность**. Убедитесь, что схема легко читается, избегайте избыточной детализации. Используйте условные обозначения и комментарии. +- **Актуализируйте схему**. При изменении системы своевременно вносите изменения в схему, чтобы она оставалась полезной. + +Лучше всего использовать подход [[Архитектура as Code]], чтобы иметь возможность видеть эволюцию схемы. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]] +**Родитель**:: [[Архитектурная карта]] +**Источник**:: +**Создана**:: [[2024-11-26]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/architecture/Архитектурный паттерн.md b/dev/architecture/Архитектурный паттерн.md new file mode 100644 index 00000000..2da88e69 --- /dev/null +++ b/dev/architecture/Архитектурный паттерн.md @@ -0,0 +1,35 @@ +--- +aliases: + - архитектурный шаблон + - Architectural Pattern + - архитектурный подход +tags: + - maturity/🌱 +date: 2024-12-02 +--- +Архитектуры: +- [[../../../../wiki/zero/00 Микросервисная архитектура|Микросервисная архитектура]] +- [[Монолитная архитектура]] +- [[Serverless|Serverless]] +- [[Событийно-ориентированная архитектура]] + +- [[Event Sourcing]] +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]] +**Родитель**:: [[Архитектурная концепция]] +**Источник**:: +**Создана**:: [[2024-12-02]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + +- [[Event Sourcing]] +- [[Serverless]] +- [[Монолитная архитектура]] +- [[00 Микросервисная архитектура]] + + diff --git a/dev/architecture/Архитектурный слой.md b/dev/architecture/Архитектурный слой.md new file mode 100644 index 00000000..8a5ad0a9 --- /dev/null +++ b/dev/architecture/Архитектурный слой.md @@ -0,0 +1,48 @@ +--- +aliases: + - архитектурного слоя + - слой + - слоями + - слоями приложения + - архитектурными слоями +tags: + - maturity/🌱 +date: 2024-09-27 +zero-link: + - "[[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]]" +parents: +linked: +--- +Архитектурный слой — это уровень абстракции, который разделяет систему на части (слои), обеспечивая логическую организацию компонентов. Каждый слой отвечает за выполнение конкретных задач и взаимодействует с другими слоями через четко определённые интерфейсы. + +Пример классической многослойной архитектуры — это разделение на уровни представления (интерфейс пользователя), бизнес-логики (основные процессы) и данных (хранение и управление информацией). Это облегчает разработку, поддержку и масштабирование системы. + +Основные идеи использования слоёв в архитектуре: +- **Чёткое разделение ответственности (Separation of Concerns)**: Каждый слой должен быть сосредоточен на выполнении одной задачи (например, UI, бизнес-логика, доступ к данным). Например, слой бизнес-логики не должен заниматься задачами, связанными с пользовательским интерфейсом, и наоборот. Это упрощает изменения, поддержку и тестирование. +- **Минимизация связности между слоями**: Взаимодействие между слоями должно происходить через хорошо определённые интерфейсы или API. Это снижает зависимость слоёв друг от друга и облегчает замену или обновление слоёв. +- **Инверсия зависимостей**: Верхние слои не должны зависеть от реализации нижних слоёв. Использование абстракций (интерфейсов) помогает избежать жестких зависимостей и улучшает тестируемость. +- **Логика не должна просачиваться между слоями**: Каждая бизнес-логика или специфическая реализация должны быть строго в том слое, к которому они относятся, чтобы избежать смешивания задач. +- **Использование принципов** [[SOLID|SOLID]]: Следование принципам объектно-ориентированного проектирования, таким как единая ответственность ([[Single Responsibility Principle|Single Responsibility]]) и открытость/закрытость ([[Open Closed Principle|Open/Closed Principle]]), помогает создать гибкие и легко расширяемые архитектуры. + +Преимущества: +- **Модульность**: Легче модифицировать или заменять части системы без влияния на весь код. +- **Повторное использование**: Логика, размещённая в одном слое, может быть использована различными частями системы. +- **Упрощение тестирования**: Благодаря разделению задач, тестирование может быть сосредоточено на отдельных слоях. + +Частые ошибки: +- **Слои как простая формальность**: Иногда разработчики создают слои, но не используют их как абстракции. Это приводит к тому, что слои теряют свой смысл и становятся перегруженными логикой, не относящейся к их роли. +- **Слишком много слоёв**: Перегруженная многослойная архитектура может стать трудной для понимания и сопровождения. Использование слишком большого количества слоёв увеличивает сложность без явных преимуществ. +- [[Необоснованное использование ORM в слое бизнес-логики]]: Когда объекты из слоя данных (например, сущности ORM) напрямую используются в бизнес-слое, это нарушает принцип [[Инкапсуляция|инкапсуляции]] и ведёт к избыточным зависимостям. + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-09-27]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + diff --git a/dev/architecture/Асинхронное программирование.md b/dev/architecture/Асинхронное программирование.md new file mode 100644 index 00000000..ee23cf40 --- /dev/null +++ b/dev/architecture/Асинхронное программирование.md @@ -0,0 +1,22 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-10-08 +--- +Асинхронность позволяет задачам выполняться в фоновом режиме, не блокируя основной поток программы, тем самым реализуя [[Concurrency]]. В синхронных операциях задача должна завершиться, прежде чем начнётся следующая, тогда как асинхронные задачи могут выполняться независимо, что особенно полезно для [[../architecture/Блокирующий вызов|блокирующих операций]]. + +Асинхронное программирование делает программы более отзывчивыми, позволяя основному потоку продолжать выполнение других задач, пока асинхронная операция выполняется. После завершения такой операции программа может вернуться к её результатам. В Java для этого используется класс `CompletableFuture`. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: [[../Парадигма разработки|Парадигма разработки]] +**Источник**:: +**Создана**:: [[2024-10-08]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/architecture/Бизнес-логика.md b/dev/architecture/Бизнес-логика.md new file mode 100644 index 00000000..ec183f0f --- /dev/null +++ b/dev/architecture/Бизнес-логика.md @@ -0,0 +1,32 @@ +--- +aliases: + - бизнес-логике + - бизнес-логику + - бизнес-логики +tags: + - maturity/🌱 +date: 2024-10-16 +--- +Бизнес-логика — это совокупность правил, процессов и операций, которые определяют, как бизнес-приложение или [[Информационная система|система]] обрабатывает данные и выполняет свои функции в соответствии с требованиями бизнеса. Она описывает последовательность действий, условия и правила, которые управляют поведением системы при выполнении бизнес-задач. + +Основные аспекты бизнес-логики: + +- **Правила и ограничения**: Определяют, что можно и нельзя делать в системе. +- **Процессы и операции**: Описывают последовательность шагов для достижения определенного результата. +- **Валидация данных**: Проверяет корректность и целостность вводимых или обрабатываемых данных. +- **Взаимодействие с данными**: Определяет, как данные создаются, читаются, обновляются и удаляются. + +Бизнес-логика отделена от пользовательского интерфейса и технической инфраструктуры, что позволяет легко вносить изменения в систему при изменении бизнес-требований без необходимости переписывать всю программу. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-10-16]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/architecture/Блокирующий вызов.md b/dev/architecture/Блокирующий вызов.md new file mode 100644 index 00000000..d5cc099c --- /dev/null +++ b/dev/architecture/Блокирующий вызов.md @@ -0,0 +1,43 @@ +--- +aliases: + - блокирующие операции + - блокирующая операция + - блокирующий вызов + - блокирующий ввод-вывод + - блокирующего + - блокирующей операции + - блокирующих операций +tags: + - maturity/🌱 +date: 2024-01-28 +zero-link: + - "[[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]]" +parents: +linked: + - "[[Блокирующий вызов]]" +--- +Блокирующий вызов блокирует [поток](../fundamental/Поток%20процесса%20ОС.md) до того момента, как будут-получены данные. Во время блокировки [процесс](../fundamental/Процесс%20ОС.md) не потребляет процессорное время, но потребляет память. Например, для выполнения запроса к БД из пула потоков берётся поток, далее он ожидает, пока БД выполнит запрос и вернёт результат. + +Это одна из основных проблем императивного программирования. ==Если вычисление результата займёт 5 минут, то поток всё это время будет недоступен для других операций.== Это может привести к снижению производительности сервиса, особенно если многие потоки будут блокироваться в ожидании завершения долго выполняющихся запросов к базе данных. В какой-то момент у вас просто могут закончиться потоки в пуле, и обработка новых запросов просто остановится. + +![](../../meta/files/images/Pasted%20image%2020240319200211.png) + +## Почему простаивание потока — это проблема? +Каждый поток нуждается в памяти для хранения своего стека вызовов и других связанных с ним структур данных. ==Когда поток простаивает, он продолжает потреблять ресурсы для поддержания своего состояния.== + +Кроме того, процессорное время, которое выделяется неработающим потокам, могло бы быть использовано для других задач. Если большое количество потоков простаивает, это может привести к увеличению загрузки процессора и снижению производительности, так как операционная система будет тратить больше времени на [[../fundamental/Переключение контекста|переключение между потоками]]. + +![](../../meta/files/images/Pasted%20image%2020240413205842.png) + +Если посмотреть на соотношение скорости [[../fundamental/Центральный процессор|процессора]] и возможности сетевых соединений, то отличия – на пару порядков. Например, на этом слайде сжатие 1 Кб данных занимает 3 мкс, в то время как round trip в одну сторону даже внутри одного дата-центра – это уже 0,5 мс. Любое сетевое взаимодействие, которое нужно бэкенду (например, отправка запроса в БД), потребует, как минимум 2х round trip-ов и по сравнению с тем процессорным временем, которое он тратит на обработку данных, – это совершенно незначительно. Большую часть времени обработки запроса [бэкенд](Бэкенд.md) ничего не делает, просто ждет. +## Заметки +- Чтение с диска в linux может быть только блокирующим. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-01-28]] +### Дочерние заметки + \ No newline at end of file diff --git a/dev/architecture/Большой комок грязи.md b/dev/architecture/Большой комок грязи.md new file mode 100644 index 00000000..4995594a --- /dev/null +++ b/dev/architecture/Большой комок грязи.md @@ -0,0 +1,40 @@ +--- +aliases: + - Big ball of mud +tags: + - maturity/🌱 +date: 2024-04-04 +--- +**Большой комок грязи** (Big Ball of Mud) — это термин, описывающий программную систему с нераспознаваемой архитектурой. Такие системы не имеют чёткой структуры, их сложно поддерживать и развивать. + +Ключевым последствием появления большой системы с неясной архитектурой является значительное замедление разработки. Это связано с тем, что: +- **Сложность понимания кода**: Новые разработчики вынуждены тратить много времени на разбор устаревших и запутанных участков. +- **Повышенная вероятность ошибок**: Внесение изменений в одну часть системы часто непредсказуемо влияет на другие. +- **Снижение гибкости**: Система становится менее адаптируемой к новым требованиям бизнеса. + +В результате работа над новыми функциями или изменениями превращается в долгий и трудозатратный процесс. + +Одним из ярких примеров большого комка грязи является [[Распределенный монолит|распределённый монолит]]. Это система, которая внешне представлена как набор микросервисов, но на практике они сильно связаны между собой. Такая архитектура унаследовала все проблемы монолитных систем, добавив к ним сложности, связанные с распределёнными взаимодействиями. + +**Почему возникают большие комки грязи?** +- **Давление сроков**: Когда бизнес требует быстрых результатов, разработчики часто жертвуют качеством архитектуры ради скорости. +- **Отсутствие единого видения**: Если в команде нет согласованного подхода к архитектурным решениям, код становится хаотичным. +- **Текучка кадров**: Новые разработчики могут не понимать оригинального замысла системы и добавлять решения, противоречащие существующей структуре. +- **Рост системы**: По мере увеличения объёма кода его поддержка становится всё сложнее, особенно если архитектура изначально была слабой. + +**Как избежать появления большого комка грязи?** +- **Создавать архитектурные стандарты**: Документировать основные принципы построения системы и регулярно их пересматривать. +- [[../efficiency/Рефакторинг кода|Рефакторинг]] на ранних этапах: Регулярно пересматривать код и устранять хаотичные или устаревшие участки. +- **Обучение команды**: Убедиться, что все разработчики понимают выбранный подход к проектированию. +- **Разумное планирование сроков**: Учитывать время, необходимое для создания качественной архитектуры, вместо того чтобы ориентироваться только на скорость. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: [[Архитектурная концепция]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-04-04]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/architecture/Брокер сообщений.md b/dev/architecture/Брокер сообщений.md new file mode 100644 index 00000000..d57cb6bc --- /dev/null +++ b/dev/architecture/Брокер сообщений.md @@ -0,0 +1,55 @@ +--- +aliases: + - брокерами сообщений + - очереди сообщений + - брокеры сообщений +tags: + - maturity/🌱 +date: 2024-07-02 +--- +Брокеры способны обрабатывать 10000+ сообщений в секунду + +Для чего используются: +- Межсервисное общение +- Асинхронная запись логов приложения +- Тяжелые ассинхронные задачи + +Требования к брокерам: +- гарантия доставки сообщений + - at least once delivery. Гарантируется, что наше сообщение получит хотя бы один клиент. + - at most once delivery. Не гарантирует доставку. + - exactly once delivery. Гарантируется, что только один получатель получит сообщение. +- порядок передачи сообщений +- управление размером очереди +- зеркалирование +- масштабирование + +**Терминология:** +- Брокер - это приложение, которое реализует модель [AMQP](Advanced%20Message%20Queuing%20Protocol.md). Которое принимает соединения клиентов для маршрутизации сообщений и т.п. +- Сообщение (message) - это единица передаваемых данных. Включая мета-информацию. +- Потребитель (consumer) - приложение, которое читает сообщения из очереди. +- Производитель (producer) - приложение, которое отправляет сообщения в брокер. + +Примеры реализаций брокеров сообщений: +- [00 RabbitMQ](00%20RabbitMQ.md) +- [00 Kafka](00%20Kafka.md) +- [[../../../../_inbox/NATS|NATS]] +- [00 Redis](../../meta/zero/00%20Redis.md) (pub/sub, stream) + +![[../../meta/files/images/Pasted image 20241103222905.png]] +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-07-02]] +### Дополнительные материалы +- +### Дочерние заметки + + +- [[00 RabbitMQ]] +- [[Advanced Message Queuing Protocol]] +- [[NATS]] + diff --git a/dev/architecture/Бэкенд.md b/dev/architecture/Бэкенд.md new file mode 100644 index 00000000..bc1dbdb8 --- /dev/null +++ b/dev/architecture/Бэкенд.md @@ -0,0 +1,32 @@ +--- +aliases: + - бэкенде + - backend + - бэкенда + - бэкенду + - Приложение +tags: + - maturity/🌱 +date: + - - 2024-04-13 +zero-link: + - "[[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]]" +parents: +linked: +--- +Бэкенд – один из самых больших бездельников в веб-архитектуре. У него есть всего 2 задачи: +- Сетевой ввод-вывод. Обычно сводится к общению с [Rеverse proxy](Rеverse%20proxy.md) – прием http-запроса и ответ на него, и со всевозможными сервисами, которые хранят данные – это могут быть БД, очереди, memcaсhed и т.п. +- Склеивание строк – сериализовать данные в JSON, сформировать шаблон на основе html, посчитать sh1 или md5? выполнить сжатие данных. + +А что такое [[бизнес-логика]] в бэкенде? Это проверки наподобие "если значение переменных больше 3-х, делай это", "если пользователь авторизован, покажи одно, если не авторизован – покажи другое". Бывают, конечно, отдельные задачи, например, по изменению размера картинки, преобразования видео, но чаще всего такие задачи решаются вне бэкенда с использованием очередей, воркеров и т.д. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-04-13]] +### Дополнительные материалы +- [[Блокирующий вызов|Блокирующий вызов]] +### Дочерние заметки + diff --git a/dev/architecture/Высокоуровневые модули.md b/dev/architecture/Высокоуровневые модули.md new file mode 100644 index 00000000..c6228be8 --- /dev/null +++ b/dev/architecture/Высокоуровневые модули.md @@ -0,0 +1,32 @@ +--- +aliases: + - Высокоуровневые компоненты + - высокоуровневых модулей +tags: + - maturity/🌱 +date: 2024-11-23 +--- +**Высокоуровневые модули** — это компоненты [[Информационная система|системы]], которые реализуют [[Бизнес-логика|бизнес-логику]] или основные функции приложения. Они определяют, что делает система, и взаимодействуют с абстрактными концепциями. Такие модули управляют процессами, принимают решения, организуют взаимодействие между компонентами. + +**Примеры:** +- Контроллеры в архитектуре [[MVC]], управляющие потоком данных и действиями пользователя. +- Модуль, обрабатывающий заказы в интернет-магазине +- Система отчетности, объединяющая данные из разных источников. + +**Особенности:** + +- Высокоуровневые модули зависят от абстракций, а не от деталей реализации. +- Их изменения определяются требованиями бизнеса, а не техническими деталями [[Низкоуровневые модули|низкоуровневых модулей]]. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-23]] +**Автор**:: +### Дополнительные материалы +- [[Низкоуровневые модули]] + +### Дочерние заметки + + diff --git a/dev/architecture/Декомпозиция на микросервисы.md b/dev/architecture/Декомпозиция на микросервисы.md new file mode 100644 index 00000000..06d8e657 --- /dev/null +++ b/dev/architecture/Декомпозиция на микросервисы.md @@ -0,0 +1,53 @@ +--- +aliases: + - размер микросервиса + - гранулярность микросервисов + - декомпозиции на микросервисы + - декомпозиции системы +tags: + - maturity/🌱 +date: 2024-11-24 +--- +Гранулярность микросервисов — это один из ключевых вопросов при проектировании распределённых систем. От неё зависит многое: гибкость архитектуры, масштабируемость, время разработки и стоимость поддержки. Однако определение оптимального размера каждого сервиса — задача не из лёгких. + +Гранулярность в контексте микросервисной архитектуры — это уровень разделения логики системы на отдельные сервисы. Слишком крупные сервисы рискуют превратиться в [[Монолитная архитектура|монолиты]], теряя преимущества микросервисного подхода. Слишком мелкие, наоборот, создают сложности в управлении и коммуникации, что приводит к росту накладных расходов. + +Основной вызов заключается в нахождении оптимального баланса. Микросервисы должны быть достаточно маленькими, чтобы можно было легко управлять их жизненным циклом и развивать независимо от других компонентов. В то же время они должны оставаться самодостаточными и функциональными. + +**Принципы определения гранулярности** +1. **Бизнес-ориентированность**. Микросервис должен отражать конкретный бизнес-процесс или функциональную область. Если сервис охватывает слишком много бизнес-логики, его стоит разделить на более специализированные компоненты. Например, в системе для интернет-магазина логика управления заказами и обработка платежей должны быть разделены на два сервиса. +2. Правило [[Single Responsibility Principle|единственной ответственности]]. Каждый микросервис должен выполнять одну задачу и делать это хорошо. Если сервис отвечает за множество разнородных функций, вероятно, его стоит разделить. Например, сервис, отвечающий и за авторизацию, и за управление профилем пользователя, нарушает принцип единственной ответственности. +3. Слабая [[связанность]] и высокая [[Связность|связность]]. Сервисы должны быть слабо связаны друг с другом, чтобы изменения в одном не требовали изменений в других. В то же время внутренняя логика сервиса должна быть максимально когерентной — все функции должны быть тесно связаны и иметь смысл как единое целое. +4. **Коммуникационные накладные расходы**. При излишнем разделении микросервисов коммуникация между ними может стать значительной проблемой. Каждое взаимодействие требует сетевых запросов, которые увеличивают время отклика и усложняют тестирование. Избежать этого можно, объединяя сервисы, которые часто взаимодействуют друг с другом. +5. **Масштабируемость и независимость деплоя**. Один из ключевых факторов в пользу микросервисов — возможность масштабировать и развертывать сервисы независимо друг от друга. При этом важно помнить, что слишком мелкие микросервисы могут превратиться в головную боль для команды DevOps из-за увеличения количества деплоя и инфраструктурных задач. + +**Подходы к выбору гранулярности** +- Разбиение по [[Доменная область|доменным областям]]. Этот подход предполагает разделение микросервисов по бизнес-доменам. Например, в системе для электронной коммерции могут существовать отдельные сервисы для управления каталогом товаров, работы с корзиной и обработкой платежей. +- **Использование событий**. [[Событийно-ориентированная архитектура|Событийная архитектура]] позволяет разделять микросервисы на основе того, как данные движутся через систему. Это помогает уменьшить связанность, так как каждый сервис реагирует только на те события, которые ему необходимы. +- **Практика "Strangler Fig"**. Этот метод подразумевает постепенное выделение функциональности из монолита в микросервисы. Это помогает определить оптимальную гранулярность, анализируя, какие части системы требуют частых изменений и могут быть разделены без излишних коммуникационных накладных расходов. + +**Ошибки, которых следует избегать** +1. **Слишком крупные сервисы (микромонолиты)**. Они теряют преимущество независимости и приводят к тому, что разработчики вновь оказываются в рамках монолита, но с более сложной архитектурой деплоя и управления. +2. **Излишняя гранулярность**. Чрезмерное разделение приводит к лавине коммуникаций и делает систему неуправляемой. Это может также вызвать рост сложности в управлении транзакциями и согласованностью данных. +3. **Игнорирование бизнес-логики**. Определение границ микросервисов только на основе технических аспектов, без учёта бизнес-логики, приводит к нарушению когезии и снижению эффективности разработки. + +**Практические рекомендации** +- **Начинайте с более крупных сервисов** и постепенно выделяйте их части, когда возникает потребность в независимом развитии и деплое. Это поможет избежать излишней сложности на начальных этапах. +- **Анализируйте связи между сервисами**. Регулярный анализ зависимостей и коммуникационных потоков поможет понять, не стали ли отдельные сервисы слишком тесно связаны и не следует ли их объединить. + +*** +## Мета информация +**Область**:: [[../../../../wiki/zero/00 Микросервисная архитектура|00 Микросервисная архитектура]] +**Родитель**:: [[Микросервис]] +**Источник**:: +**Создана**:: [[2024-11-24]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + +- [[Объединение данных из разных микросервисов]] + + diff --git a/dev/architecture/Доменная область.md b/dev/architecture/Доменная область.md new file mode 100644 index 00000000..9b2537f5 --- /dev/null +++ b/dev/architecture/Доменная область.md @@ -0,0 +1,34 @@ +--- +aliases: + - домена + - доменных областях + - доменным областям +tags: + - maturity/🌱 +date: 2024-09-27 +zero-link: + - "[[../garden/ru/meta/zero/00 Архитектура ПО|00 Архитектура ПО]]" +parents: +linked: +--- +**Домен** — это предметная область, в которой работает ваша [[../../../../_inbox/Информационная система|система]]. Это набор знаний, правил, процессов и объектов, которые описывают конкретную сферу деятельности. Домены могут быть разными в зависимости от сферы бизнеса, например: финансы, медицина, логистика, образование и т.д. + +Другими словами, домен — это всё, что касается бизнес-логики, которой занимается [[../../../../_inbox/Информационная система|система]]. Разработчики, создающие приложения, должны глубоко понимать предметную область, чтобы адекватно моделировать её в коде. + +> [!EXAMPLE] Пример домена +> Для интернет-магазина домен будет включать такие элементы, как товары, заказы, корзина, покупатели, процесс оплаты и доставки. Все эти сущности и их взаимодействия составляют домен электронной коммерции. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-09-27]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + +- [[Модель]] + diff --git a/dev/architecture/Зависимости микросервисов.md b/dev/architecture/Зависимости микросервисов.md new file mode 100644 index 00000000..eeeb8419 --- /dev/null +++ b/dev/architecture/Зависимости микросервисов.md @@ -0,0 +1,56 @@ +--- +aliases: + - связи микросервисов +tags: + - maturity/🌱 +date: 2024-11-26 +--- +В [[../../../../wiki/zero/00 Микросервисная архитектура|микросервисной архитектуре]] каждый [[Микросервис|сервис]] имеет зависимости, которые можно разделить на **входящие** и **исходящие**: +- **Входящие зависимости** — это другие сервисы или клиенты, которые полагаются на данный сервис для выполнения своих задач. +- **Исходящие зависимости** — это внешние системы или микросервисы, от которых данный сервис зависит для выполнения своих функций. +## Входящие зависимости +Сервисы с высокой входящей зависимостью обычно выполняют функции, на которых завязаны многие другие компоненты. Отказ такого сервиса может привести к масштабным сбоям, поэтому требуется масштабируемость, мониторинг и резервирование. + +Чем больше входящих зависимостей, тем выше вероятность перегрузки сервиса, особенно в моменты пиковых запросов. Например, сервис авторизации, на который завязаны все остальные микросервисы. +## Исходящие зависимости +Сервисы с множеством исходящих зависимостей сильно зависят от доступности и стабильности внешних систем. + +Чем больше исходящих зависимостей, тем сложнее проводить изолированные тесты сервиса. Для таких случаев требуются mock-объекты или тестовые среды. + +Высокое число исходящих зависимостей может замедлять работу сервиса из-за сетевых задержек, ограничения пропускной способности или API-лимитов. +## Типы микросервисов на основе зависимостей +- **Центральные (Hub)** + - Много входящих зависимостей, мало исходящих. + - Выполняют ключевые функции, от которых зависят другие. + - Пример: [[API Gateway]] или сервис аутентификации. +- **Агрегаторы** + - Много исходящих зависимостей, среднее число входящих. + - Сбор и обработка данных из множества источников. + - Пример: сервис аналитики или отчётности. +- **Специализированные (Leaf)** + - Мало входящих и исходящих зависимостей. + - Выполняют автономные задачи, минимально влияя на другие части системы. + - Пример: сервис генерации отчетов. +- **Мосты (Bridge)** + - Баланс между входящими и исходящими зависимостями. + - Соединяют разные домены или внешние API с внутренними сервисами. +- Пример: сервис интеграции с внешней платежной системой. +## Рекомендации +- **Минимизируйте исходящие зависимости**. Ограничьте количество внешних систем, от которых зависит сервис. Агрегируйте зависимости, чтобы уменьшить количество прямых связей. +- **Делайте отказоустойчивые сервисы с высокой входящей зависимостью**. Используйте [[кэширование]], [[highload/Балансировка нагрузки|балансировщики нагрузки]] и [[highload/Горизонтальное масштабирование|горизонтальное масштабирование]], чтобы снизить риски. +- **Используйте асинхронные коммуникации**. Асинхронные подходы (например, через [[Брокер сообщений|брокеры сообщений]]) помогают уменьшить плотность зависимостей и снизить нагрузку. +- **Мониторьте зависимости**. Отслеживайте состояние входящих и исходящих зависимостей с помощью [[Архитектурная схема|архитектурных схем]], чтобы своевременно выявлять узкие места и проблемы. +- **Сегментируйте систему** Разделение архитектуры на домены помогает уменьшить плотность зависимостей и сделать систему более управляемой. +*** +## Мета информация +**Область**:: [[../../../../wiki/zero/00 Микросервисная архитектура|00 Микросервисная архитектура]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-26]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/architecture/Идемпотентность.md b/dev/architecture/Идемпотентность.md new file mode 100644 index 00000000..5f92b052 --- /dev/null +++ b/dev/architecture/Идемпотентность.md @@ -0,0 +1,35 @@ +--- +aliases: + - идемпотентны + - идемпотентной + - идемпотентности + - идемпотентную + - идемпотентные +tags: + - maturity/🌱 +date: 2024-09-11 +--- +Идемпотентность — это свойство операции, при котором многократное выполнение этой операции с одинаковыми входными данными не изменяет результат после первого выполнения. Иными словами, независимо от того, сколько раз вы выполните операцию, итог будет одним и тем же. + +Примером идемпотентной операции может быть запрос на установку значения, например, «установить цену товара в 100». Если отправить этот запрос несколько раз, цена останется 100, и результат не изменится. В противоположность этому, операция «увеличить цену на 10» не является идемпотентной, так как каждое выполнение увеличивает цену, и результат меняется. + +Идемпотентность позволяет системе быть устойчивой к ошибкам и повторам — если запрос случайно повторится, это не приведет к нежелательным изменениям. + +**Примеры реализации:** +- [[highload/Идемпотентность на базе уникального идентификатора|Идемпотентность на базе уникального идентификатора]] +- Логика приложения устроена таким образом, что выполнение запроса с одними и теми же параметрами всегда приводит к одному и тому же результату. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-09-11]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + +- [[Идемпотентность на базе уникального идентификатора]] + diff --git a/dev/architecture/Избыточность данных.md b/dev/architecture/Избыточность данных.md new file mode 100644 index 00000000..8028fc4a --- /dev/null +++ b/dev/architecture/Избыточность данных.md @@ -0,0 +1,44 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-11-24 +--- +В [[../../meta/zero/00 HighLoad|высоконагруженных системах]] часто возникает необходимость хранить одни и те же данные в разных формах, чтобы оптимизировать работу различных частей системы. Это один из архитектурных [[Паттерн проектирования|паттернов]], который позволяет справиться с разными требованиями к доступу и обработке данных. Избыточность данных может быть полезной для повышения производительности и удобства работы с различными типами запросов. + +Представим ситуацию, когда система хранит переписку между пользователями. Допустим, эта переписка отображается только двум участникам, и в интерфейсе показывается сразу вся история общения. В этом случае данные можно хранить в одном месте — например, даже в виде файла, который легко доступен для обоих пользователей. + +Но что если нам нужно вывести список всех переписок пользователя с отображением только последнего сообщения каждой из них? Хранение всей переписки в одном файле становится неудобным, так как для получения последнего сообщения нам нужно будет прочитать все файлы и выбрать необходимую информацию, что занимает много времени и ресурсов. + +Правильное решение в такой ситуации — ввести избыточность. Это означает, что вместо попытки хранить все данные в одном месте, необходимо создавать дополнительные структуры данных, которые оптимизированы под разные сценарии использования. + +В случае с перепиской можно хранить данные следующим образом: +1. **Основное хранилище для переписок**. Вся история переписки между двумя пользователями хранится в одном месте, что позволяет удобно отображать её целиком, когда это необходимо. +2. **Индекс с последними сообщениями**. Дополнительно создаётся индекс, в котором хранятся только идентификаторы переписок и последние сообщения из каждой из них. Это позволяет быстро получать список переписок с последними сообщениями для отображения на экране. + +Преимущества избыточности данных +1. **Оптимизация под разные схемы доступа**. Хранение данных в разных формах позволяет оптимизировать производительность системы под различные сценарии использования. Например, быстрый доступ к последним сообщениям, не читая всю историю переписки. +2. **Увеличение скорости работы**. Избыточность помогает сократить количество операций чтения и уменьшить время выполнения запросов. В случае переписки пользователю не нужно ждать, пока система обработает весь массив данных для получения последних сообщений. +3. **Повышение отказоустойчивости**. Хранение данных в нескольких местах и формах также помогает повысить устойчивость к сбоям. В случае потери одного источника данных, другой может частично компенсировать потерю информации. + +Недостатки избыточности данных +1. **Сложность синхронизации**. Поддержание согласованности между несколькими копиями данных — сложная задача. Необходимо следить за тем, чтобы все изменения, внесённые в одну копию, корректно синхронизировались с другими копиями. +2. **Увеличение объёма хранилища**. Хранение данных в нескольких формах требует больше места в хранилище. Для высоконагруженных систем с большими объёмами данных это может стать значительным фактором. + +Лучшие практики для работы с избыточностью данных +1. **Продуманная архитектура синхронизации**. Используйте [[Событийно-ориентированная архитектура|событийную архитектуру]], чтобы поддерживать согласованность данных. Например, при добавлении нового сообщения можно отправить событие, которое обновит индекс последних сообщений. +2. **Оценка необходимости избыточности**. Вводите избыточность только там, где это действительно необходимо для повышения производительности или удобства работы. Не стоит избыточно усложнять систему там, где этого можно избежать. +3. **Мониторинг консистентности**. Внедряйте механизмы проверки и восстановления консистентности данных между копиями. Это поможет вовремя обнаружить и устранить расхождения. + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 HighLoad|00 HighLoad]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-24]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + \ No newline at end of file diff --git a/dev/architecture/Инкапсуляция.md b/dev/architecture/Инкапсуляция.md new file mode 100644 index 00000000..1f834504 --- /dev/null +++ b/dev/architecture/Инкапсуляция.md @@ -0,0 +1,62 @@ +--- +aliases: + - инкапсуляцию + - инкапсуляции +tags: + - maturity/🌱 +date: 2024-09-27 +zero-link: + - "[[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]]" +parents: + - "[[../garden/ru/dev/architecture/ООП|ООП]]" +linked: +--- +Инкапсуляция — один из ключевых принципов [[ООП|объектно-ориентированного программирования]] (ООП), который обеспечивает контроль доступа к данным и методам объекта, скрывая внутреннюю реализацию и предоставляя только необходимые интерфейсы для взаимодействия с внешним миром. + +Основные идеи инкапсуляции: +- **Сокрытие данных**: Внутренние детали реализации объекта, такие как его состояние или внутренние методы, не должны быть доступны напрямую из внешнего кода. Это позволяет избежать прямого изменения данных объекта извне и защищает его от некорректного использования. +- **Чёткие интерфейсы**: Объект предоставляет только те методы и свойства, которые необходимы для работы с ним, скрывая всю сложную внутреннюю логику. Это упрощает работу с объектом и делает его использование безопасным. +- **Управляемое изменение состояния**: Изменение состояния объекта происходит через методы, которые контролируют корректность этих изменений и могут проводить валидацию, логику или вызовы других методов. + +Частые ошибки: +- **Избыточная доступность**: Если данные и методы не скрыты должным образом, это приводит к увеличению связности компонентов и нарушению принципа инкапсуляции. +- **Смешивание ответственности**: Когда внутренние данные объекта предоставляются другим компонентам, появляется риск того, что ответственность за управление состоянием будет распределена между разными частями системы. + +## Пример инкапсуляции +Представьте, что у вас есть объект `BankAccount`, который хранит баланс пользователя. Чтобы обеспечить безопасность, прямой доступ к балансу невозможен. Вместо этого объект предоставляет методы `deposit()` и `withdraw()`, которые корректно изменяют баланс и проверяют возможность транзакции: + +```java +public class BankAccount { + private double balance; + + public void deposit(double amount) { + if (amount > 0) { + balance += amount; + } + } + + public void withdraw(double amount) { + if (amount > 0 && balance >= amount) { + balance -= amount; + } + } + + public double getBalance() { + return balance; + } +} +``` + +Таким образом, инкапсуляция помогает управлять состоянием объекта, делая его использование безопасным и устойчивым к ошибкам. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: [[ООП]] +**Источник**:: +**Создана**:: [[2024-09-27]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + diff --git a/dev/architecture/Контракт взаимодействия.md b/dev/architecture/Контракт взаимодействия.md new file mode 100644 index 00000000..839e40d3 --- /dev/null +++ b/dev/architecture/Контракт взаимодействия.md @@ -0,0 +1,46 @@ +--- +aliases: + - Контракты + - контракт +tags: + - maturity/🌱 +date: 2024-09-27 +zero-link: + - "[[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]]" + - "[[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]]" +--- +В контексте разработки программного обеспечения **контракт** — это соглашение или набор правил, определяющий, как различные части системы (например, компоненты, классы или модули) взаимодействуют друг с другом. Контракт описывает обязанности и ожидания каждой из сторон (поставщика и потребителя), гарантируя, что при соблюдении этих условий взаимодействие будет корректным и предсказуемым. + +Основные элементы контракта: +- **Предусловия**: Условия, которые должны быть выполнены перед вызовом метода или началом взаимодействия. Например, входные данные метода должны быть корректными, а ресурс должен быть доступен. +- **Постусловия**: Результаты, которые гарантируются после выполнения метода или операции, если предусловия были выполнены. Это может включать возвращаемое значение метода или состояние объекта после вызова. +- **Инварианты**: Условия, которые остаются неизменными в течение жизни объекта. Например, допустимые диапазоны значений переменных или непротиворечивость состояния системы. +## Примеры контрактов +**Контракт в объектно-ориентированном программировании**: В [[ООП|ООП]] контракт может выражаться через интерфейсы или абстрактные классы, которые определяют набор методов, обязательных для реализации. Это позволяет программным компонентам общаться на основе общих соглашений, не зная конкретную реализацию. + +Пример интерфейса как контракта: + ```java + public interface Shape { + double calculateArea(); // контракт: любой класс, реализующий Shape, обязан иметь этот метод + } + ``` + +**Контракт API**: В контексте API контрактом является описание того, как клиент может взаимодействовать с API. Это включает в себя форматы запросов и ответов, методы HTTP, параметры, типы данных, кодировки и обработку ошибок. + +Пример контракта [[Representation State Transfer|REST]] API: +- Метод: `POST /users` +- Входные данные: JSON-объект с полями `name` и `email` +- Ответ: код 201 (Created) и объект пользователя +- Ошибки: код 400 (Bad Request) при некорректных данных +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]], [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-09-27]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + diff --git a/dev/architecture/Кэширование в приложении.md b/dev/architecture/Кэширование в приложении.md new file mode 100644 index 00000000..ac119ec9 --- /dev/null +++ b/dev/architecture/Кэширование в приложении.md @@ -0,0 +1,33 @@ +--- +aliases: +tags: + - maturity/🌱 +date: + - - 2024-06-17 +zero-link: + - "[[../../meta/zero/00 HighLoad|00 HighLoad]]" +parents: + - "[[Кэширование]]" +--- +Поход в базу данных может быть достаточно дорогим, в этом случае имеет смысл сохранять данные в кэш. Ускорить сложные запросы может кэширование: мы помещаем результат вычислений в некоторое хранилище, которое обладает отличными характеристиками по времени доступа к информации. Теперь вместо обращений к медленным, сложным и тяжелым backend’ам нам достаточно выполнить запрос к быстрому кэшу. + +Самые распространенные варианты хранения: +- Внутри сервиса. Хранение в ОЗУ +- За сервисом + - [Memcached](Memcached.md) + - [[../../meta/zero/00 Redis|Redis]] + +![](../../meta/files/images/Pasted%20image%2020240617184722.png) + + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 HighLoad|00 HighLoad]] +**Родитель**:: [[Кэширование]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-06-17]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/architecture/Кэширование.md b/dev/architecture/Кэширование.md new file mode 100644 index 00000000..16bc2687 --- /dev/null +++ b/dev/architecture/Кэширование.md @@ -0,0 +1,78 @@ +--- +aliases: + - кэш + - кэша + - кеш +tags: + - maturity/🌱 +date: + - - 2024-05-24 +zero-link: + - "[[../../meta/zero/00 HighLoad|00 HighLoad]]" +parents: +linked: +--- +Для каждого ресурса критичной для пользователя является такая характеристика, как [[Latency|время отклика]] сервера. Увеличение времени отклика сервера приводит к оттоку посетителей. Следовательно, необходимо минимизировать [[Latency|время отклика]]: для этого необходимо уменьшать время, требуемое на формирование ответа пользователю, при этом для формирования ответа пользователю необходимо получить данные из каких-то внешних ресурсов ([Бэкенд](Бэкенд.md)). + + +> [!TIP] Работа без кэша +> Хорошая система должна уметь выдерживать нагрузку и без кэша. Задача кэша ускорить ответ, а не держать нагрузку. + +Сами данные можно разделить на несколько категорий: +- **Можно потерять**. К этой категории относятся кэши выборок из базы данных. Потеря таких ключей не так страшна, потому что мы можем легко восстановить их значения, обратившись заново к backend’у. Однако частые потери кэшей приводят к излишним обращениям к БД. +- **Не хотелось бы потерять**. Здесь можно упомянуть счетчики посетителей сайта, просмотров ресурсов и т.п. Хоть и восстановить эти значения иногда напрямую невозможно, но значения этих ключей имеют ограниченный по времени смысл: через несколько минут их значение уже неактуально, и будет рассчитано заново. +- **Совсем не должны терять**. Кэш удобен для хранения сессий пользователей. Однако содержимое сессий не хотелось бы терять никогда – иначе пользователей на сайте будет «разлогинивать». Как попытаться избежать? Можно кластеризовать систему кэширования, так вероятность потери снижается. + +==Системы используемые для кэширования обычно не являются надежными, так что не следует хранить только там какие-то важные данные.== +## Уровни кэширования +![](../../meta/files/images/Pasted%20image%2020240617195054.png) + +![[../../meta/files/images/Pasted image 20241103033544.png]] + +Уровни кэширования: +- [Кэширование на стороне браузера](highload/Кэширование%20на%20стороне%20браузера.md). Ответы HTTP могут кэшироваться браузером. При первом запросе данных по HTTP они возвращаются с политикой истечения срока действия в заголовке HTTP. При повторном запросе данных клиентское приложение сначала пытается получить их из кэша браузера. +- [Кэширование на стороне Nginx](../devops/nginx/Кэширование%20на%20стороне%20Nginx.md) +- [Content Delivery Network](highload/Content%20Delivery%20Network.md). CDN кэширует статические веб-ресурсы. Клиенты могут получать данные с ближайшего узла CDN. +- **Балансировщик нагрузки**: Балансировщик также может кэшировать ресурсы. +- [Кэширование в приложении](Кэширование%20в%20приложении.md). В сервисах есть несколько уровней кэша. Если данные не находятся в кэше процессора, сервис пытается получить их из памяти. Иногда в сервисе есть вторичный уровень кэша для хранения данных на диске. +- **Распределённый кэш**: Распределённые кэши, такие как Redis, хранят пары ключ-значение в памяти для множества сервисов. Это обеспечивает значительно лучшую производительность чтения и записи по сравнению с базой данных. +- **База данных**: Даже в базе данных есть различные уровни кэша + +**Виды кэширования:** +- Сквозное. Все запросы проходят через кэш. [Схема](../../meta/files/images/Pasted%20image%2020240617194731.png). +- Кэширование на стороне сервиса. [Схема](../../meta/files/images/Pasted%20image%2020240617194759.png). +- Опережающее. Кладем данные в кэш заранее. [Схема](../../meta/files/images/Pasted%20image%2020240617194938.png). + +Чаще всего кэш реализуется на основе [[../fundamental/structure/Хеш-таблица|хеш-таблиц]] и использует [принцип локальности](../fundamental/Принцип%20локальности.md). Для работы с хеш-таблицей вам необходим [[highload/Ключ кэширования|ключ кэширования]] и сами данные. По ключу данные кладутся и забираются из таблицы. + +Для хранения результатов кэширования я обычно использую JSON. Использую для этого библиотеку [[../../../../knowledge/dev/java/other/Jackson|Jackson]], но есть один [[../snippet/Преобразование Json из коллекции в Java объект при помощи Jackson|нюанс при работе с коллекциям]], который стоит учитывать. + +При желании результат кэширования можно сжать используя [[../algorithm/GZIP|GZIP]]. Однако, приходится использовать [[../other/Base64|Base64]], чтобы преобразовать байты полученные от gzip в строку, и уже в таком виде положить в Redis. Не смотря на то, что Base64 увеличивает размер строки на 33% все равно получается намного компактнее, чем просто JSON. + +Рано или поздно исходные данные изменяются, и кэш перестает быть валидным. Часто важно, чтобы кэш сбрасывался сразу же за изменением. За это отвечает [[highload/Инвалидация кэша|Инвалидация кэша]]. + +![[../../meta/files/images/Pasted image 20241103035011.png]] +*** +## Мета информация +**Область**:: [[../../meta/zero/00 HighLoad|00 HighLoad]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-05-24]] +### Дополнительные материалы +- [[highload/Оценка эффективности кэша|Оценка эффективности кэша]] +- [Старт с холодным кэшем](highload/Старт%20с%20холодным%20кэшем.md) +### Дочерние заметки + + +- [[CacheMissRate]] +- [[Content Delivery Network]] +- [[Инвалидация кэша]] +- [[Ключ кэширования]] +- [[Кэширование на стороне браузера]] +- [[Оценка эффективности кэша]] +- [[Перестройка кэша]] +- [[Старт с холодным кэшем]] +- [[Кэширование в приложении]] +- [[Кэширование на стороне Nginx]] + diff --git a/dev/architecture/Масштабирование информационной системы.md b/dev/architecture/Масштабирование информационной системы.md new file mode 100644 index 00000000..c8bb5210 --- /dev/null +++ b/dev/architecture/Масштабирование информационной системы.md @@ -0,0 +1,44 @@ +--- +aliases: + - масштабирование + - масштабировании + - масштабируемости + - масштабируемость +tags: + - maturity/🌱 +date: 2024-12-03 +--- +**Масштабирование информационных систем** — это процесс увеличения [[Throughput|пропускной способности]] [[../../../../_inbox/Информационная система|информационной системы]] для обработки растущих объемов данных, запросов или пользователей. Этот процесс позволяет системе сохранять стабильность и производительность при росте нагрузки. + +Существует три ключевых подхода к масштабированию: +1. [[highload/Вертикальное масштабирование|Вертикальное масштабирование]] (scale-up). Увеличение ресурсов одного узла, например, за счет добавления памяти или замены процессора на более мощный. Этот подход прост в реализации, но ограничен возможностями оборудования. +2. [[highload/Горизонтальное масштабирование|Горизонтальное масштабирование]] (scale-out). Добавление новых узлов в систему для распределения нагрузки. Этот способ требует дополнительной настройки архитектуры, но обеспечивает практически неограниченное расширение. +3. [[Масштабирование по осям X, Y и Z|Куб масштабирования приложений]] (cube scaling). Совмещение вертикального и горизонтального масштабирования с учетом сетевой архитектуры, контейнеризации и других современных технологий. + +**Когда нужно задуматься над масштабированием:** +- **Растущая нагрузка**: Увеличение числа пользователей или объема обрабатываемых данных. +- Необходимость высокой [[../../../../_inbox/Reliability|отказоустойчивости]]: Системы должны работать без перебоев, даже при сбоях отдельных компонентов. +- **Требование оптимизации ресурсов**: Гибкое добавление мощности для сокращения расходов. + +При выборе подхода важно учитывать: +- **Тип системы**: [[Монолитная архитектура|Монолитные приложения]] чаще масштабируются вертикально, а [[../../../../wiki/zero/00 Микросервисная архитектура|микросервисные]] — [[highload/Горизонтальное масштабирование|горизонтально]]. +- **Сложность архитектуры**: Простые системы легче масштабировать вертикально, в то время как сложные системы требуют горизонтального подхода. +- **Бюджет и долгосрочные цели**: Вертикальное масштабирование может быть дорого при достижении аппаратных лимитов, тогда как горизонтальное требует инвестиций в инфраструктуру. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-12-03]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + +- [[Вертикальное масштабирование]] +- [[Горизонтальное масштабирование]] +- [[Масштабирование по осям X, Y и Z]] + + diff --git a/dev/architecture/Масштабирование по осям X, Y и Z.md b/dev/architecture/Масштабирование по осям X, Y и Z.md new file mode 100644 index 00000000..03ac8a51 --- /dev/null +++ b/dev/architecture/Масштабирование по осям X, Y и Z.md @@ -0,0 +1,60 @@ +--- +aliases: + - cube scaling + - Куб масштабирования приложений +tags: + - maturity/🌱 +date: + - - 2024-04-12 +--- +Для [[../../meta/zero/00 HighLoad|систем с высокой нагрузкой]] [[Масштабирование информационной системы|масштабирование]] является ключевым аспектом архитектурного проектирования. Концепция масштабирования по осям X, Y и Z помогает понять, как распределить нагрузку и обеспечить стабильность работы приложения. + +![](../../meta/files/images/cfac08bc-c9b0-4894-ab40-7e319c5bc13b.jpg) +## Масштабирование по оси Х +Масштабирование по оси X — это увеличение количества одинаковых экземпляров приложения, работающих за [[highload/Балансировка нагрузки|балансировщиком нагрузки]]. Этот подход соответствует понятию [[highload/Горизонтальное масштабирование|горизонтального масштабирования]]. + +**Как это работает**: Запросы от клиентов распределяются [[highload/Балансировка нагрузки|балансировщиком]] между несколькими идентичными экземплярами системы. + +**Основная цель**: +- Увеличение [[Throughput|пропускной способности]]. +- Повышение [[../../../../_inbox/Reliability|отказоустойчивости]] за счет резервирования. + +**Пример применения**: [[Монолитная архитектура|Монолитные приложения]], где запуск дополнительных экземпляров не требует изменения кода. + +![](../../meta/files/images/df56a7dd-ec73-4188-9502-8b6db06762f6.jpg) +## Масштабирование по оси Z +Масштабирование по оси Z предполагает разделение системы на подмножества данных, где каждый экземпляр приложения отвечает за обработку определенного набора данных. + +**Как это работает**: Входящий запрос направляется маршрутизатором к соответствующему экземпляру на основании определенного атрибута (например, `userid` или региона). + +**Основная цель**: +- Уменьшение нагрузки на каждый экземпляр. +- Ускорение обработки запросов за счет уменьшения объема данных, с которыми работает каждый узел. + +**Пример применения**: [[../../../../_inbox/Шардирование БД|Шардирование]] баз данных, где данные распределяются между разными серверами. + +![](../../meta/files/images/Pasted%20image%2020240412202007.png) + +## Масштабирование по оси Y +Масштабирование по оси Y основывается на функциональной [[Декомпозиция на микросервисы|декомпозиции системы]]. Вместо дублирования или разделения данных приложение разбивается на отдельные модули или сервисы. + +**Как это работает**: Монолитное приложение делится на самостоятельные модули или микросервисы, каждый из которых отвечает за свою часть функционала. + +**Основная цель**: +- Упрощение разработки и поддержки системы. +- Устранение узких мест, связанных с усложнением монолита. + +**Пример применения**: [[../../../../wiki/zero/00 Микросервисная архитектура|Микросервисная архитектура]], где каждый сервис обрабатывает свои задачи (например, управление пользователями, обработка платежей, логирование). + +![](../../meta/files/images/99a03ca9-8253-4085-912e-459dd62f839d.jpg) +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]] +**Родитель**:: [[Масштабирование информационной системы]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-04-12]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/architecture/Межсервисное взаимодействие.md b/dev/architecture/Межсервисное взаимодействие.md new file mode 100644 index 00000000..6c16874a --- /dev/null +++ b/dev/architecture/Межсервисное взаимодействие.md @@ -0,0 +1,28 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-11-27 +--- +Примитивные каналы, такие как [[брокер сообщений]], или прямое взаимодействие с помощью легковесных протоколов наподобие [[Representation State Transfer|REST]] или [[../gRPC|gRPC]]. + +Чем больше вызовов нужно сделать, тем меньшую [[Reliability|отказоустойчивость]] получаем. + +![[../../../../meta/files/Pasted image 20241127200019.png]] + +Взаиможействие бывает двух основных видов: +- Асинхронные вызовы +- Синхронные вызовы +*** +## Мета информация +**Область**:: [[../../../../wiki/zero/00 Микросервисная архитектура|00 Микросервисная архитектура]] +**Родитель**:: [[Микросервис]] +**Источник**:: +**Создана**:: [[2024-11-27]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/architecture/Микросервис.md b/dev/architecture/Микросервис.md new file mode 100644 index 00000000..14fc0555 --- /dev/null +++ b/dev/architecture/Микросервис.md @@ -0,0 +1,32 @@ +--- +aliases: + - микросервисы + - сервис + - микросервисов + - сервисов +tags: + - maturity/🌱 +date: 2024-11-24 +--- +Идеальный микросервис: +- [[Single Responsibility Principle|Единственная ответственность]] и [[Bounded Context|Ограниченный контекст]]. Микросервисы часто строятся вокруг ограниченных контекстов. Один контекст может соответствовать одному микросервису, что упрощает его разбиение, разработку и поддержку. Однако, важно помнить, что ограниченный контекст — это не архитектурный паттерн, а концепция предметной области. Поэтому очень часто за обработку данных одного контекста отвечает множество сервисов. +- Низкая [[Связанность|связанность]] и высокая [[связность]] + +- [[Зависимости микросервисов]] +## Заметки +- Сервис имеет входящие и исходящие зависимости на другие сервисы. Чем более общий сервис мы строим, тем меньше входящих зависимостей должно быть, то есть сервис не должен зависеть от других сервисов. Например, сервис хранения настроек других сервисов или сервис хранения файлов, он практически не должны зависеть от других сервисов. + + +*** +## Мета информация +**Область**:: [[../../../../wiki/zero/00 Микросервисная архитектура|00 Микросервисная архитектура]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-24]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/architecture/Много клиентов — один поток.md b/dev/architecture/Много клиентов — один поток.md new file mode 100644 index 00000000..6aff4c95 --- /dev/null +++ b/dev/architecture/Много клиентов — один поток.md @@ -0,0 +1,45 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-10-02 +zero-link: + - "[[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]]" +parents: + - "[[Архитектурная концепция]]" +linked: +--- +Концепция “много клиентов — один поток” предполагает, что один [[../fundamental/Поток процесса ОС|поток]] может обрабатывать множество клиентских запросов. Это возможно благодаря асинхронному или [[Событийно-ориентированная архитектура|событийно-ориентированному подходу]], где поток не привязывается к одному запросу, а может переключаться между задачами в зависимости от их состояния (например, ожидания данных). Такой подход широко используется для решения проблем масштабируемости и производительности в современных [[../../meta/zero/00 HighLoad|высоконагруженных системах]]. + +В отличие от модели “[[один клиент — один поток]]”, где для каждого запроса создается отдельный поток, в модели “много клиентов — один поток” используется один или ограниченное количество потоков для обслуживания множества клиентов. Этот подход достигается за счет использования [[../../../../_inbox/Не блокирующийся ввод-вывод|неблокирующего ввода/вывода]] (non-blocking I/O) и [[Event Loop|событийного цикла]]. Когда клиентский запрос инициирует операцию, например обращение к базе данных, поток может освободиться и перейти к следующей задаче, вместо того чтобы блокироваться и ждать завершения операции. + +Обычно используется неблокирующая модель обработки событий: когда запрос клиента инициируется, он может находиться в очереди событий и быть выполнен в момент, когда необходимые ресурсы будут готовы, при этом один поток обрабатывает множество событий последовательно или параллельно. + +**Плюсы подхода** +- **Масштабируемость.** Один из ключевых плюсов модели — значительно лучшая масштабируемость по сравнению с моделью “один клиент — один поток”. Благодаря неблокирующему вводу/выводу и использованию небольшого количества потоков, такие системы могут обрабатывать тысячи и даже миллионы клиентских запросов, не создавая избыточного потребления ресурсов. +- **Эффективное использование ресурсов.** Один поток может выполнять множество задач последовательно, освобождаясь от блокировки в ожидании внешних ресурсов (например, базы данных или сети). Это позволяет максимально эффективно использовать доступные системные ресурсы, такие как память и процессорное время. +- Меньше [[../fundamental/Переключение контекста|контекстных переключений]]. Поскольку количество потоков минимально, система тратит меньше времени на контекстные переключения, что снижает накладные расходы на процессор и повышает общую производительность. +- **Высокая производительность при высоких нагрузках.** Эта модель отлично подходит для [[../../meta/zero/00 HighLoad|высоконагруженных систем]], таких как веб-сервера, системы обработки сообщений и стриминговые платформы, где каждый клиент может генерировать множество мелких запросов. + +**Минусы подхода** +- **Сложность реализации.** Асинхронная модель требует более сложной архитектуры и управления состояниями. Разработчикам нужно работать с обратными вызовами (callbacks) или реактивными потоками, что увеличивает сложность кода и повышает риск ошибок. +- **Отладка и поддержка.** Из-за использования асинхронности и событийной обработки отладка таких систем может быть сложнее. Потоки могут переключаться между задачами в произвольные моменты времени, что затрудняет поиск и исправление ошибок. +- **Изоляция ошибок.** Если происходит ошибка в одном потоке, она может повлиять на множество запросов, поскольку один поток обслуживает сразу несколько клиентов. В таких случаях важно предусмотреть механизмы обработки ошибок и защиты от сбоев. + +**Кто использует этот подход** +- [[../../meta/zero/00 Nginx|Nginx]]. Один из самых известных примеров событийно-ориентированного сервера, использующий асинхронный подход. Nginx эффективно обрабатывает множество клиентских запросов с минимальными затратами ресурсов. +- **Node.js.** Однопоточная архитектура с использованием событийной петли, которая позволяет одному потоку обрабатывать множество запросов одновременно. Node.js широко применяется для построения масштабируемых серверов и микросервисов. +- Vert.x и [[../../meta/zero/00 Quarkus|Quarkus]]. Эти фреймворки используют реактивные подходы для обработки запросов, обеспечивая высокую производительность и асинхронную обработку данных в [[../../../../wiki/zero/00 Микросервисная архитектура|микросервисной архитектуре]]. +- Netty. Асинхронный сетевой фреймворк, который широко используется для создания высокопроизводительных сетевых приложений на Java, таких как серверы и клиентские приложения. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: [[Архитектурная концепция]] +**Источник**:: +**Создана**:: [[2024-10-02]] +**Автор**:: +### Дополнительные материалы +- [[Один клиент — один поток]] + +### Дочерние заметки + diff --git a/dev/architecture/Модель.md b/dev/architecture/Модель.md new file mode 100644 index 00000000..edceed6e --- /dev/null +++ b/dev/architecture/Модель.md @@ -0,0 +1,26 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-09-27 +zero-link: + - "[[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]]" +parents: + - "[[Доменная область|Доменная область]]" +linked: +--- +**Модель** — это представление [[Доменная область|домена]] в коде. Она описывает, как сущности и объекты [[Доменная область|домена]] связаны между собой и взаимодействуют в системе. Модель может включать классы, структуры данных, правила валидации, бизнес-логику и отношения между объектами. + +Хорошо спроектированная модель точно описывает доменные объекты и их поведение. Основная задача модели — предоставлять разработчику инструменты для работы с объектами [[Доменная область|домена]], обеспечивая соответствие бизнес-правилам и логике. +*** +## Мета информация +**Область**:: +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-09-27]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + diff --git a/dev/architecture/Монолитная архитектура.md b/dev/architecture/Монолитная архитектура.md new file mode 100644 index 00000000..3a82a71c --- /dev/null +++ b/dev/architecture/Монолитная архитектура.md @@ -0,0 +1,39 @@ +--- +aliases: + - монолит + - монолиты + - монолитного приложения + - Монолитные приложения +tags: + - maturity/🌱 +date: 2024-04-04 +--- +Монолитная архитектура — это способ проектирования, разработки и деплоя [[../../../../_inbox/Информационная система|информационной системы]] как единого целого. Все компоненты приложения — от пользовательского интерфейса до базы данных — объединены в одном приложении. Такой подход остаётся популярным для многих проектов из-за его простоты на начальных этапах. + +Преимущества: +- **Простота разработки**. Все инструменты разработки (например, IDE) сосредоточены на создании единого приложения. Это упрощает работу команды, особенно если проект небольшой и команда ограничена в ресурсах. +- **Лёгкость внесения радикальных изменений**. В монолитной архитектуре вы можете одновременно менять код и структуру базы данных. После этого достаточно пересобрать и развернуть новое приложение. +- **Простота тестирования**. Сквозное тестирование охватывает всю систему сразу. Инструменты, такие как Selenium, позволяют тестировать пользовательский интерфейс, API и внутреннюю логику в одном процессе. +- **Упрощённое развертывание**. Разработчику достаточно скопировать один WAR-файл (или аналог) на сервер с установленным приложением, например Tomcat. +- **Масштабирование путём клонирования**. Для увеличения производительности можно развернуть несколько экземпляров приложения за балансировщиком нагрузки, распределяя трафик между ними. + +Несмотря на простоту, монолитный подход имеет **ряд ограничений**, которые могут стать критическими при увеличении размера приложения или масштабировании бизнеса: +- **Трудности с масштабированием**. Программные модули конкурируют за ресурсы. Например, модуль обработки изображений, нагружающий CPU, может негативно влиять на стабильность других модулей. +- **Единые технологии для всех задач**. Монолит ограничивает возможность использовать разные технологии для разных частей системы. Например, вы не сможете использовать Java для одних модулей, а C++ — для других. +- **Проблемы с надёжностью и стабильностью**. Утечка памяти в одном модуле может вызвать сбой всей системы, поскольку в монолите все компоненты тесно связаны. +- **Проблемы масштабируемости и сложности управления**. Популярные приложения часто перерастают монолитную архитектуру. Это приводит к увеличению времени сборки, сложности управления и проблемам с разделением ответственности в команде. В конечном итоге проект может оказаться в состоянии так называемого “[[Монолитный ад|монолитного ада]]”. + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]] +**Родитель**:: [[Архитектурный паттерн]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-04-04]] +### Дополнительные материалы +- +### Дочерние заметки + + +- [[Монолитный ад]] + diff --git a/dev/architecture/Монолитный ад.md b/dev/architecture/Монолитный ад.md new file mode 100644 index 00000000..046152fb --- /dev/null +++ b/dev/architecture/Монолитный ад.md @@ -0,0 +1,45 @@ +--- +aliases: + - монолитном аду + - монолитного ада +tags: + - maturity/🌱 +date: + - - 2024-04-04 +--- +**Монолитный ад** — это состояние [[Монолитная архитектура|монолитного приложения]], в котором его сложность и размеры становятся настолько большими, что разработка, поддержка и развитие системы превращаются в серьёзную проблему. Приложение становится практически непонятным для одного разработчика, а любая попытка изменить код или добавить новую функциональность усиливает хаос. + +**Основные симптомы монолитного ада** +- **Медленная разработка**. Сборка кода занимает слишком много времени. Большое приложение долго запускается, что затягивает цикл разработки: написание, сборка, запуск, тестирование. +- **Медленные и сложные релизы**. Разные команды работают над одной кодовой базой. Даже если монолит разбит на модули, выпуск релиза невозможен, пока все команды не завершат свои изменения. Это приводит к задержкам и конфликтам. +- **Постепенное устаревание технологий**. Переход на новые фреймворки или инструменты в монолите становится практически невозможным. Нельзя точечно обновить технологии для одного модуля, например, использовать Spring для модуля оплаты и Quarkus для управления пользователями. + +![](../../meta/files/images/a46f1a15-51d7-4007-8116-0d6b936c5cd1.png) + +**Причины возникновения монолитного ада** +- **Рост команды и кодовой базы**. Чем больше разработчиков работает над проектом и чем больше кода добавляется, тем сложнее становится система. При этом сложность системы обычно растёт экспоненциально, что усугубляет ситуацию. +- **Плохая архитектура и низкая читаемость кода**. Когда кодовая база плохо структурирована, разработчики не могут вносить изменения корректно. Это приводит к новым ошибкам и ещё большей путанице. +- **Увеличение технического долга**. Непродуманные изменения ради краткосрочных целей делают код менее поддерживаемым, что в долгосрочной перспективе замедляет разработку. + +**Последствия монолитного ада** +- [[Большой комок грязи]]. Проблемы монолита приводят к тому, что система превращается в плохо структурированный, запутанный код, который трудно понять и поддерживать. +- **Снижение производительности команды**. Разработчики вынуждены тратить больше времени на понимание существующего кода, чем на реализацию новых функций. +- **Повышенные риски отказов**. Ошибка или сбой в одной части системы может полностью нарушить её работу, так как все модули тесно связаны. +- **Замедление внедрения инноваций**. Устаревший стек технологий и сложность внедрения изменений препятствуют использованию современных подходов, что снижает конкурентоспособность продукта. + +**Как избежать монолитного ада?** +- Планомерный [[../efficiency/Рефакторинг кода|рефакторинг]]. Регулярное улучшение кода и упрощение архитектуры позволяют снизить сложность системы и избежать накопления технического долга. +- Переход на [[../../../../wiki/zero/00 Микросервисная архитектура|микросервисную архитектуру]]. Если приложение становится слишком сложным, можно начать выделять отдельные модули в микросервисы. Это разделяет ответственность и снижает связность системы. +- [[../efficiency/Стандартизация подходов в разработке|Стандартизация подходов в разработке]]. Использование единых стандартов и инструментов помогает команде работать более эффективно и избежать хаоса. +- **Контроль за качеством кода**. Внедрение строгих код-ревью, тестирования и анализа статического кода позволяет предотвращать появление проблем ещё на этапе разработки. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]] +**Родитель**:: [[Монолитная архитектура]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-04-04]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/architecture/Низкоуровневые модули.md b/dev/architecture/Низкоуровневые модули.md new file mode 100644 index 00000000..a8e5fe49 --- /dev/null +++ b/dev/architecture/Низкоуровневые модули.md @@ -0,0 +1,31 @@ +--- +aliases: + - Низкоуровневые компоненты + - низкоуровневых модулей +tags: + - maturity/🌱 +date: 2024-11-23 +--- +**Низкоуровневые модули** — это компоненты, которые отвечают за технические детали и реализацию. Они предоставляют конкретный функционал, необходимый для выполнения задач, определенных высокоуровневыми модулями. + +**Примеры** +1. База данных или ее драйвер. +2. Реализация отправки HTTP-запросов. + +**Особенности:** +- Низкоуровневые модули реализуют интерфейсы или абстракции, которые используют [[высокоуровневые модули]]. +- Они должны быть заменяемыми без изменений в высокоуровневом коде. + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-23]] +**Автор**:: +### Дополнительные материалы +- [[Высокоуровневые модули]] + +### Дочерние заметки + + diff --git a/dev/architecture/ООП.md b/dev/architecture/ООП.md new file mode 100644 index 00000000..7eadce65 --- /dev/null +++ b/dev/architecture/ООП.md @@ -0,0 +1,33 @@ +--- +aliases: + - объектно-ориентированного программирования + - объектно ориентированного программирования + - объектно ориентированное программирование + - объектно-ориентированное программирование + - объектно-ориентированном программировании +tags: + - maturity/🌱 +date: 2024-09-27 +zero-link: + - "[[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]]" +parents: +linked: +--- +- [[Полиморфизм]] +- [[Инкапсуляция|Инкапсуляция]] +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-09-27]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + +- [[Инкапсуляция]] +- [[Полиморфизм]] + diff --git a/dev/architecture/Объединение данных из разных микросервисов.md b/dev/architecture/Объединение данных из разных микросервисов.md new file mode 100644 index 00000000..906fb6c0 --- /dev/null +++ b/dev/architecture/Объединение данных из разных микросервисов.md @@ -0,0 +1,34 @@ +--- +aliases: + - объединять данные из разных микросервисов +tags: + - maturity/🌱 +date: 2024-12-02 +--- +При проектировании микросервисной архитектуры ключевой задачей является правильная [[Декомпозиция на микросервисы]]. Однако в процессе разработки может возникнуть ситуация, когда данные, необходимые для выполнения одного бизнес-процесса, распределяются между несколькими сервисами. Это усложняет обработку данных, увеличивает [[Latency|время отклика]] системы и создает дополнительные точки отказа. + +Объединение данных между сервисами становится необходимым, когда: +- Один бизнес-процесс требует данных из нескольких микросервисов. +- Логика обработки данных не соответствует границам ответственности сервисов. +- Архитектурные решения не учитывают изначально взаимосвязанные данные. + +![[../../meta/files/images/Pasted image 20241202191611.png]] + +Если в системе часто возникают ситуации, требующие объединения данных, это может быть сигналом неправильного выбора границ микросервисов. Основные признаки: +- Частые запросы между сервисами для синхронизации данных. +- Высокая сложность реализации бизнес-логики из-за разрозненности данных. +- Замедление работы системы из-за межсервисного взаимодействия. + +*** +## Мета информация +**Область**:: [[../../../../wiki/zero/00 Микросервисная архитектура|00 Микросервисная архитектура]] +**Родитель**:: [[Декомпозиция на микросервисы|Декомпозиция на микросервисы]] +**Источник**:: +**Создана**:: [[2024-12-02]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/architecture/Один клиент — один поток.md b/dev/architecture/Один клиент — один поток.md new file mode 100644 index 00000000..41669331 --- /dev/null +++ b/dev/architecture/Один клиент — один поток.md @@ -0,0 +1,52 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-10-02 +zero-link: + - "[[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]]" +parents: + - "[[Архитектурная концепция]]" +linked: +--- +“Один клиент — один поток” — это концепция обработки запросов, в которой для каждого клиента или запроса выделяется отдельный [[../fundamental/Поток процесса ОС|поток]] выполнения. Этот подход исторически использовался в многопоточных серверных архитектурах для обработки клиентских соединений. Концепция проста в реализации и часто применяется в традиционных системах, однако с ростом нагрузки и требованиями к масштабируемости начинают проявляться ее недостатки. + +Суть концепции заключается в том, что на каждый новый клиентский запрос создается отдельный поток в системе. ==Этот поток обрабатывает запрос от начала до конца==, включая этапы получения данных, выполнения логики и возврата ответа клиенту. Как только запрос обработан, поток освобождается или завершает выполнение. Таким образом, каждый клиент имеет свой “личный” поток выполнения, изолированный от других клиентов. + +**Плюсы** +- **Простота реализации.** Каждый запрос выполняется в отдельном потоке, что делает архитектуру интуитивно понятной для разработчиков. Легче управлять состоянием внутри потока, так как нет необходимости беспокоиться о синхронизации между потоками. +- **Изоляция ошибок.** Ошибка, возникшая в одном потоке, как правило, не затрагивает другие потоки. Это снижает риск влияния одного сбойного запроса на остальные. +- **Четкое распределение ресурсов.** При каждом запросе сервер выделяет четко определённое количество ресурсов (один поток), что может упростить мониторинг и управление системой. + +**Недостатки** +- **Проблемы с масштабируемостью.** Основной недостаток концепции — это плохая масштабируемость. Потоки требуют выделения значительных системных ресурсов, таких как память и процессорное время. При увеличении числа клиентов нагрузка на процессор и оперативную память возрастает, а также увеличивается количество контекстных переключений между потоками, что снижает общую производительность системы. +- **Потребление ресурсов.** Для каждого клиента выделяется не только поток, но и сопутствующие ресурсы, такие как стеки вызовов, которые могут занимать значительное количество памяти. Системы, работающие с тысячами или миллионами клиентов, могут столкнуться с исчерпанием ресурсов. +- [[../fundamental/Переключение контекста|Переключение контекста]] Каждый раз, когда система переключается между потоками, происходит контекстное переключение, которое добавляет накладные расходы на процессор. Эти переключения могут значительно замедлять работу системы при большом количестве потоков. +- [[Блокирующий вызов|Блокирующий вызов]]. Даже если клиентский запрос простаивает (например, ожидает ответа от базы данных или другого сервиса), поток остается занятым и не может быть использован для других задач, что приводит к неэффективному использованию ресурсов. + +**Кто использует этот подход** +Подход “один клиент — один поток” использовался в ранних версиях популярных серверов и библиотек: + +- **Apache HTTP Server (классический режим работы).** В старых конфигурациях Apache каждый запрос обрабатывался отдельным потоком или процессом. +- **Tomcat (до перехода на NIO).** В классическом Tomcat для каждого HTTP-запроса создавался отдельный поток для его обработки. + +Однако с ростом числа пользователей и нагрузки такие серверы начали испытывать проблемы с производительностью. Поэтому многие современные серверы перешли к более эффективным асинхронным моделям обработки запросов. + +**Современные альтернативы** +С ростом масштабов приложений, особенно в веб-разработке, стали популярны асинхронные и реактивные подходы, где один поток может обслуживать множество клиентов, не создавая новый поток для каждого запроса. Такие подходы позволяют лучше использовать ресурсы системы: + +- **Асинхронные модели.** Серверы, такие как [[../../meta/zero/00 Nginx|Nginx]], используют [[Событийно-ориентированная архитектура|событийно-ориентированную архитектуру]], где запросы обрабатываются без необходимости создавать новый поток на каждый запрос. Это снижает потребление памяти и улучшает масштабируемость. +- [[Реактивное программирование|Реактивное программирование]]. В таких фреймворках, как [[../../meta/zero/00 Quarkus|Quarkus]], Vert.x или [[../../meta/zero/00 SpringBoot|Spring]] WebFlux, запросы обрабатываются асинхронно с использованием реактивных потоков, что позволяет эффективно распределять ресурсы даже при высокой нагрузке. + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: [[Архитектурная концепция]] +**Источник**:: +**Создана**:: [[2024-10-02]] +**Автор**:: +### Дополнительные материалы +- [[Много клиентов — один поток]] + +### Дочерние заметки + diff --git a/dev/architecture/Отправка сообщений в Kafka из транзакции БД.md b/dev/architecture/Отправка сообщений в Kafka из транзакции БД.md new file mode 100644 index 00000000..214b4043 --- /dev/null +++ b/dev/architecture/Отправка сообщений в Kafka из транзакции БД.md @@ -0,0 +1,29 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-11-15 +--- +Отправка сообщений в [[00 Kafka|Kafka]] из [[Транзакция БД|транзакций базы данных]] приводит к проблемам с согласованностью данных между системами, особенно в условиях распределённых систем. Если сначала происходит отправка сообщения в Kafka, а затем транзакция в БД откатывается, то сообщение останется в Kafka, но база данных не зафиксирует изменений, что приведёт к рассинхронизации данных. + +Для обеспечения согласованности данных между базой данных и Kafka необходимо использовать следующие подходы: + +- [[Transactional Outbox|Transactional Outbox]]. Этот подход позволяет отделить запись в базу данных от отправки сообщения в брокер. Изменения сначала фиксируются в основной таблице базы данных, а затем записываются в специальную таблицу "Outbox". Отдельный процесс или сервис асинхронно считывает из таблицы "Outbox" и отправляет сообщения в Kafka, что гарантирует согласованность данных. +- Change Data Capture (CDC). Использование CDC с инструментами вроде Debezium позволяет отслеживать изменения в базе данных и публиковать их в Kafka. Это решение подходит для случаев, когда необходимо обеспечить автоматическую синхронизацию изменений, но может потребовать дополнительных настроек и ресурсов. +- Распределённые транзакции (двухфазный коммит). Этот метод позволяет гарантировать согласованность между базой данных и Kafka за счёт координации транзакций между ними. Однако этот подход часто считается сложным и менее масштабируемым, особенно в распределённых системах. + +Другая серьёзная проблема связана с возможностью двойной обработки. В случае сбоя приложения или инфраструктуры транзакции могут повторяться, приводя к дублированию событий в Kafka. Дублирование событий может вызвать некорректное состояние системы, повторное выполнение операций. Чтобы предотвратить дублирование, можно использовать следующие подходы: +- [[highload/Идемпотентность на базе уникального идентификатора|Идемпотентность на базе уникального идентификатора]] +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-15]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/architecture/Паттерн проектирования.md b/dev/architecture/Паттерн проектирования.md new file mode 100644 index 00000000..d72d903c --- /dev/null +++ b/dev/architecture/Паттерн проектирования.md @@ -0,0 +1,58 @@ +--- +aliases: + - паттерн + - шаблон проектирования + - шаблонов проектирования + - паттернов + - Design Pattern +tags: + - maturity/🌱 +date: 2023-11-05 +linked: +--- +- [[Dependency Injection]] +- [[Порождающий паттерн проектирования]] + - Abstract Factory: создаёт группы связанных элементов. + - [[Builder Pattern|Builder Pattern]]: строит объекты поэтапно, разделяя процесс создания и внешний вид. + - [[../other/Статическая фабрика|Статическая фабрика]] + - Prototype: создаёт копии полностью подготовленных экземпляров. + - Singleton: One and Only — особый класс, имеющий только один экземпляр. +- Структурные паттерны + - Adapter: Universal Plug — соединяет объекты с разными интерфейсами. + - Bridge: Function Connector — связывает, как объект работает, с тем, что он делает. + - Composite: Tree Builder — формирует древовидные структуры из простых и сложных частей. + - Decorator: Customizer — добавляет функции объектам, не меняя их основу. + - Facade: One-Stop-Shop — представляет всю систему через один упрощённый интерфейс. + - Flyweight: Space Saver — эффективно использует небольшие, многократно используемые элементы. + - Proxy: Stand-In Actor — представляет другой объект, управляя доступом или действиями. +- Поведенческие паттерны + - Chain of Responsibility: Request Relay — передаёт запрос по цепочке объектов до его обработки. + - Command: Task Wrapper — превращает запрос в объект, готовый к выполнению. + - Iterator: Collection Explorer — последовательно получает доступ к элементам коллекции. + - Mediator: Communication Hub — упрощает взаимодействие между различными классами. + - Memento: Time Capsule — сохраняет и восстанавливает состояние объекта. + - Observer: News Broadcaster — уведомляет классы об изменениях в других объектах. + - Visitor: Skillful Guest — добавляет новые операции классу, не изменяя его. + +- [[../../../../_inbox/Transactional Inbox|Transactional Inbox]] +- [[Transactional Outbox]] + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: [[Архитектурная концепция]] +**Источник**:: +**Автор**:: +**Создана**:: [[2023-11-05]] +### Дополнительные материалы +- +### Дочерние заметки + + +- [[MVC]] +- [[Transactional Inbox]] +- [[Dependency Injection]] +- [[Transactional Outbox]] +- [[Порождающий паттерн проектирования]] +- [[Статическая фабрика]] + diff --git a/dev/architecture/Полиморфизм.md b/dev/architecture/Полиморфизм.md new file mode 100644 index 00000000..bb444d00 --- /dev/null +++ b/dev/architecture/Полиморфизм.md @@ -0,0 +1,131 @@ +--- +aliases: + - полиморфизмом +tags: + - maturity/🌱 +date: 2024-09-27 +zero-link: + - "[[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]]" +parents: + - "[[ООП]]" +linked: +--- +Полиморфизм — это один из фундаментальных принципов [[ООП|объектно-ориентированного программирования]] (ООП), который позволяет объектам разных классов обрабатывать одно и то же сообщение (вызов метода) по-разному. Это делает код более гибким и расширяемым, упрощая добавление новых возможностей без изменения существующего кода. +## Основные виды полиморфизма +Полиморфизм времени компиляции ([[../other/Статическое связывание|статическое связывание]]): Это форма полиморфизма, которая определяется на этапе компиляции программы. Примеры включают перегрузку методов и перегрузку операторов. + +Один и тот же метод может иметь несколько версий, которые различаются по количеству или типам параметров. + +Пример перегрузки метода: + ```java + public class MathOperations { + public int add(int a, int b) { + return a + b; + } + + public double add(double a, double b) { + return a + b; + } + } + ``` + +Полиморфизм времени выполнения ([[../other/Динамическое связывание|динамическое связывание]]): Это форма полиморфизма, которая проявляется на этапе выполнения программы. Здесь используется наследование и переопределение методов. + +Полиморфизм времени выполнения позволяет классу, наследующему методы базового класса, предоставлять свою собственную реализацию этих методов. + +Пример динамического полиморфизма: + ```java + public class Animal { + public void makeSound() { + System.out.println("Animal makes sound"); + } + } + + public class Dog extends Animal { + @Override + public void makeSound() { + System.out.println("Dog barks"); + } + } + + public class Cat extends Animal { + @Override + public void makeSound() { + System.out.println("Cat meows"); + } + } + + public class Main { + public static void main(String[] args) { + Animal myAnimal = new Dog(); // Полиморфизм + myAnimal.makeSound(); // Вывод: Dog barks + + myAnimal = new Cat(); + myAnimal.makeSound(); // Вывод: Cat meows + } + } + ``` + +## Преимущества полиморфизма +- **Гибкость кода**: Полиморфизм позволяет работать с объектами через абстракции (интерфейсы или базовые классы), что делает систему гибкой для расширений и изменений. Например, новый класс может быть добавлен без изменения существующих классов или логики. +- **Упрощённое управление**: Код становится более управляемым и понятным, поскольку можно использовать общие типы данных (например, интерфейсы) для работы с разными реализациями. +- **Повторное использование кода**: Полиморфизм способствует использованию общих базовых классов, что уменьшает дублирование и увеличивает повторное использование кода. + +## Частые ошибки при использовании полиморфизма +- **Избыточное использование полиморфизма**: Когда полиморфизм используется там, где он не нужен, это может усложнить код. Например, создание слишком большого количества наследников для решения простой задачи. +- **Нарушение принципа подстановки Лисков**: Это принцип гласит, что объект подкласса должен корректно заменять объект родительского класса без изменения поведения программы. Если полиморфизм реализован неправильно, это может привести к неожиданным ошибкам. +- **Неправильное управление зависимостями**: Если базовые классы слишком зависят от подклассов или знают о специфике их реализации, это может разрушить архитектуру. Полиморфизм должен использоваться вместе с инверсией зависимостей для минимизации связности. +## Пример полиморфизма +Представьте, что у вас есть система для обработки платежей, которая поддерживает разные способы оплаты: кредитные карты, PayPal, банковские переводы. В этом случае вы можете создать абстрактный класс или интерфейс `PaymentMethod`, а затем реализовать его для каждого конкретного метода оплаты: + +```java +public interface PaymentMethod { + void pay(double amount); +} + +public class CreditCard implements PaymentMethod { + @Override + public void pay(double amount) { + System.out.println("Paid " + amount + " with Credit Card"); + } +} + +public class PayPal implements PaymentMethod { + @Override + public void pay(double amount) { + System.out.println("Paid " + amount + " with PayPal"); + } +} + +public class PaymentProcessor { + public void processPayment(PaymentMethod method, double amount) { + method.pay(amount); + } +} + +public class Main { + public static void main(String[] args) { + PaymentProcessor processor = new PaymentProcessor(); + + PaymentMethod card = new CreditCard(); + PaymentMethod paypal = new PayPal(); + + processor.processPayment(card, 100); + processor.processPayment(paypal, 200); + } +} +``` + +Этот подход делает систему легко расширяемой: если нужно добавить новый способ оплаты, можно просто реализовать новый класс, не изменяя существующий код. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: [[ООП|ООП]] +**Источник**:: +**Создана**:: [[2024-09-27]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + diff --git a/dev/architecture/Порождающий паттерн проектирования.md b/dev/architecture/Порождающий паттерн проектирования.md new file mode 100644 index 00000000..2ab4fe3f --- /dev/null +++ b/dev/architecture/Порождающий паттерн проектирования.md @@ -0,0 +1,26 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-10-04 +zero-link: +parents: +linked: +--- +- [[Builder Pattern]] +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Разработка|00 Разработка]] +**Родитель**:: [[Паттерн проектирования]] +**Источник**:: +**Создана**:: [[2024-10-04]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + +- [[Builder Pattern]] + + diff --git a/dev/architecture/Проблема горизонтального масштабирования Websocket.md b/dev/architecture/Проблема горизонтального масштабирования Websocket.md new file mode 100644 index 00000000..5961f3e5 --- /dev/null +++ b/dev/architecture/Проблема горизонтального масштабирования Websocket.md @@ -0,0 +1,33 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-11-13 +--- +WebSocket-соединение, в отличие от [[Representation State Transfer|REST]], имеет состояние, которое представлено объектом класса `Session`. Это создает трудности при горизонтальном масштабировании. + +Представим, что наш сервис чатов развернут в Kubernetes с 3 репликами. Пользователь чата открывает три вкладки браузера с нашим онлайн-чатом. [[highload/Балансировка нагрузки|Балансировщик нагрузки]], использующий алгоритм round robin, распределяет соединения между тремя репликами, и каждое соединение (каждая вкладка) попадает на свою реплику. + +Проблема заключается в том, что ==каждая реплика знает только о своих подключениях и не имеет информации о подключениях других реплик==. Если кто-то отправляет новое сообщение на первую реплику, пользователь увидит это сообщение только в той вкладке, которая подключена именно к этой реплике. + +Есть несколько способов решить проблему масштабирования для сервисов, использующих WebSocket. Основные варианты включают: + +1. **Не предпринимать никаких действий**. В некоторых приложениях строгая синхронизация между WebSocket-соединениями не требуется. Например, ==если ваше приложение только принимает сообщения или отправляет данные для всех пользователей, и вам не важно, из какой реплики они отправляются, возможно, нет необходимости решать эту проблему.== +2. **Использовать другой алгоритм балансировки**. Вы можете настроить балансировку так, чтобы все соединения одного и того же чата всегда направлялись на одну и ту же реплику. Это может вызвать менее равномерное распределение нагрузки, но решит проблему синхронизации между репликами. +3. [[Тонкий Websocket клиент]] +*** +## Мета информация +**Область**:: [[../../meta/zero/00 HighLoad|00 HighLoad]] +**Родитель**:: [[architecture/highload/Горизонтальное масштабирование|Горизонтальное масштабирование]] +**Источник**:: +**Создана**:: [[2024-11-13]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + +- [[Тонкий Websocket клиент]] + + diff --git a/dev/architecture/Протекание абстракций.md b/dev/architecture/Протекание абстракций.md new file mode 100644 index 00000000..834f3a1f --- /dev/null +++ b/dev/architecture/Протекание абстракций.md @@ -0,0 +1,24 @@ +--- +aliases: + - leaky abstractions +tags: + - maturity/🌱 +date: 2024-09-27 +zero-link: + - "[[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]]" +parents: +linked: +--- +Детали реализации или логика одного [[Архитектурный слой|архитектурного слоя]] становятся видимыми или начинают оказывать влияние на другие слои системы. Это нарушает принцип [[Инкапсуляция|инкапсуляции]] и разделения ответственности. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-09-27]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + diff --git a/dev/architecture/Протоколы коммуникаций.md b/dev/architecture/Протоколы коммуникаций.md new file mode 100644 index 00000000..afd484b4 --- /dev/null +++ b/dev/architecture/Протоколы коммуникаций.md @@ -0,0 +1,42 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-11-03 +--- +![[../../meta/files/images/Pasted image 20241103004117.png]] + +- [[../../../../_inbox/SOAP|SOAP]] + - Основан на XML +- [[Representation State Transfer]] + - Популярный, легко реализуемый, методы HTTP + - Идеален для веб-сервисов +- [[../GraphQL]] + - Язык запросов, позволяет запрашивать конкретные данные +- [[../gRPC|gRPC]] + - Современный, высокопроизводительный, использует Protocol Buffers + - Подходит для микросервисных архитектур для межсервисного общения. +- WebSocket + - В режиме реального времени, двунаправленные, постоянные соединения +- [[Webhook]] + - Событийный, HTTP-обратные вызовы, асинхронный + - Уведомляет системы при наступлении событий +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-03]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + +- [[Webhook]] +- [[Representation State Transfer]] +- [[gRPC]] +- [[GraphQL]] + + diff --git a/dev/architecture/Распределенная транзакция.md b/dev/architecture/Распределенная транзакция.md new file mode 100644 index 00000000..26db970a --- /dev/null +++ b/dev/architecture/Распределенная транзакция.md @@ -0,0 +1,20 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-12-02 +--- + +*** +## Мета информация +**Область**:: +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-12-02]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/architecture/Распределенный монолит.md b/dev/architecture/Распределенный монолит.md new file mode 100644 index 00000000..0bd61428 --- /dev/null +++ b/dev/architecture/Распределенный монолит.md @@ -0,0 +1,43 @@ +--- +aliases: + - распределённый монолит +tags: + - maturity/🌱 +date: 2024-11-24 +--- +Распределенный монолит — это архитектурный [[Паттерн проектирования|паттерн]], в котором компоненты системы, хотя и развернуты в виде отдельных [[Микросервис|сервисов]], фактически зависят друг от друга настолько, что не могут развиваться и масштабироваться независимо. + +![[../../meta/files/images/Pasted image 20241127200905.png]] + +Внешне такая архитектура выглядит как микросервисная, но из-за сильной [[Связанность|связанности]] и отсутствия независимости деплоя она теряет все преимущества микросервисного подхода и в итоге становится даже более сложной и неудобной в поддержке, чем традиционный [[Монолитная архитектура|монолит]]. + +**Признаки распределенного монолита:** +- Высокая [[Связанность|связанность]] между сервисами, требующие координации при деплое. Из-за этого невозможно обновить или развернуть один сервис без изменения других +- **Глобальные транзакции**, которые охватывают несколько сервисов, что приводит к сильной связанности и усложняет управление согласованностью данных +- **Отсутствие автономности** сервисов. Если один сервис не может работать без другого, и их логика тесно переплетается, то, вероятно, вы имеете дело с распределенным монолитом. +- **Общие схемы данных**. Использование [[Shared Database|общей базы данных]] или общей схемы между сервисами приводит к тесной связанности и усложняет внесение изменений без координации между командами. + +**Причины появления распределенного монолита** +- **Недостаточное понимание микросервисных принципов**. При переходе от монолита к микросервисам важно пересмотреть подходы к разработке и взаимодействию между компонентами. Не все команды понимают, что микросервисы требуют не только разбиения на отдельные сервисы, но и пересмотра способов их взаимодействия и управления данными. +- Излишняя [[Декомпозиция на микросервисы|гранулярность микросервисов]]. Желание сделать сервисы как можно более маленькими и специализированными иногда приводит к обратному результату — коммуникационные накладные расходы становятся слишком большими, и система превращается в распределенный монолит с большим количеством зависимостей. +- **Общие ресурсы**. Использование общих баз данных ([[Shared Database|Shared Database]]) или сервисов, которые нельзя изменить независимо, приводит к тому, что сервисы не могут быть развернуты или изменены самостоятельно. +- **Плохой дизайн API**. Сервисные интерфейсы, которые создают жесткие зависимости и требуют координации между разными сервисами, также способствуют появлению распределенного монолита. + +Как избежать создания распределенного монолита +- Слабая [[связанность]] и независимость деплоя. Стремитесь к тому, чтобы сервисы были как можно более независимыми друг от друга. Это касается не только разработки, но и данных. Каждому микросервису должна принадлежать [[Database per service|своя база данных]], чтобы минимизировать зависимость от других сервисов. +- **Декомпозиция по бизнес-доменам**. Разделение системы на сервисы должно основываться на бизнес-логике и [[Доменная область|доменных областях]]. Сервисы должны быть построены вокруг конкретных бизнес-процессов, а не технических компонентов, что поможет избежать тесной связанности. +- [[Событийно-ориентированная архитектура|Событийно-ориентированная архитектура]]. Использование событийной модели взаимодействия позволяет уменьшить тесную связанность сервисов и избавиться от необходимости прямого взаимодействия между ними. Сервисы реагируют на события, а не вызывают друг друга напрямую, что повышает автономность. +- **Асинхронные коммуникации**. Использование асинхронных методов взаимодействия, таких как [[Брокер сообщений|очереди сообщений]], снижает связанность между сервисами и позволяет им работать независимо друг от друга. +*** +## Мета информация +**Область**:: [[../../../../wiki/zero/00 Микросервисная архитектура|00 Микросервисная архитектура]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-24]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/architecture/Реактивное программирование.md b/dev/architecture/Реактивное программирование.md new file mode 100644 index 00000000..82d15efd --- /dev/null +++ b/dev/architecture/Реактивное программирование.md @@ -0,0 +1,30 @@ +--- +aliases: + - реактивном программировании +tags: + - maturity/🌱 +date: 2023-10-26 +zero-link: + - "[[../../meta/zero/00 Разработка|00 Разработка]]" +parents: + - "[[../Парадигма разработки]]" +linked: +--- +**Реактивное программирование** — это парадигма, ориентированная на потоки данных и распространение изменений. Она использует асинхронные потоки данных (например, Observables в RxJava), которые позволяют обрабатывать события по мере их поступления с автоматическим управлением параллелизмом и асинхронностью. + +**Реактивное программирование** используется для создания отзывчивых, устойчивых и масштабируемых систем, где важно быстро реагировать на поступающие данные, управляя backpressure (ситуация, когда данные поступают быстрее, чем могут быть обработаны) и обеспечивая неблокирующее взаимодействие. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Разработка|00 Разработка]] +**Родитель**:: [[../Парадигма разработки|Парадигма разработки]] +**Источник**:: +**Автор**:: +**Создана**:: [[2023-10-26]] +### Дополнительные материалы +- [Реактивное программирование на Java. Будущее, настоящее и прошлое](https://struchkov.dev/blog/ru/overview-of-reactive-programming/) +### Дочерние заметки +```dataview +LIST +FROM [[]] +WHERE contains(Родитель, this.file.link) or contains(parents, this.file.link) +``` \ No newline at end of file diff --git a/dev/architecture/Связанность.md b/dev/architecture/Связанность.md new file mode 100644 index 00000000..f5bf6692 --- /dev/null +++ b/dev/architecture/Связанность.md @@ -0,0 +1,40 @@ +--- +aliases: + - coupling + - связанности + - связанность + - связанные +tags: + - maturity/🌱 +date: 2024-11-24 +--- +Связанность (coupling) — это мера зависимости между модулями компонента. Если модули сильно связаны, изменение одного модуля требует изменения и в других модулях, что затрудняет их поддержку и развитие. Идеальной является слабая связанность (loose coupling), когда модули минимально зависят друг от друга. + +**Преимущества слабой связанности** +- **Упрощение модификации**. Система, состоящая из слабо связанных модулей, легче модифицируется, так как изменения в одном модуле минимально затрагивают другие. +- **Улучшение тестируемости**. Слабо связанные модули проще тестировать изолированно, что способствует выявлению и устранению ошибок на ранних стадиях. + +**Примеры применения** +1. [[../../../../wiki/zero/00 Микросервисная архитектура|Микросервисная архитектура]]. При проектировании микросервисной архитектуры важно, чтобы каждый сервис был слабо связан с другими, что позволяет им развиваться независимо. Сервис с высокой связанностью сосредоточен на конкретной бизнес-задаче, например, управлении пользователями или платежами. +2. **Пакеты в монолитной системе**. В монолитных системах правильное разделение на пакеты может значительно снизить связанность. Например, отдельный пакет для работы с базой данных должен иметь минимальные зависимости от бизнес-логики. +3. **Классы в объектно-ориентированном программировании**. Слабая связанность между классами позволяет изменять один класс без значительного влияния на другие. + +**Антипаттерны и частые ошибки** +- [[Циклические зависимости сервисов]]. Модули не должны иметь циклические зависимости, так как это сильно увеличивает связанность и затрудняет поддержку системы. Решением может быть введение интерфейсов или абстракций для разрыва циклов. + +**Рекомендации** +- **Применение интерфейсов и абстракций**. Использование интерфейсов помогает уменьшить связанность, так как модули взаимодействуют через абстракции, а не напрямую. +- Регулярный [[../efficiency/Рефакторинг кода|рефакторинг]]. Постоянное улучшение кода помогает устранить чрезмерные зависимости и поддерживать слабую связанность между модулями. + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-24]] +**Автор**:: +### Дополнительные материалы +- [[Связность|Связность]] +### Дочерние заметки + + diff --git a/dev/architecture/Связность.md b/dev/architecture/Связность.md new file mode 100644 index 00000000..cd2aefae --- /dev/null +++ b/dev/architecture/Связность.md @@ -0,0 +1,105 @@ +--- +aliases: + - Cohesion + - связности + - связность +tags: + - maturity/🌱 +date: 2024-11-24 +--- +Связность (cohesion) — это мера того, насколько функции внутри одного модуля связаны друг с другом и работают вместе для выполнения конкретной задачи. Высокая связность означает, что модуль фокусируется на одной задаче и все его компоненты направлены на достижение этой цели. Например, модуль обработки платежей включает только функции, связанные с платежами, что делает его логически целостным. + +Примеры применения +- [[../../../../wiki/zero/00 Микросервисная архитектура|Микросервисная архитектура]]. Сервис с высокой связностью сосредоточен на конкретной бизнес-задаче, например, управлении пользователями или платежами. Например, сервис управления пользователями может добавлять, обновлять и удалять пользователей без взаимодействия с другими сервисами, что делает его легким в поддержке. Все классы в микросервисе направлены на решение этих задач. +- **Пакеты в монолитной системе**. В монолитных системах правильное разделение на пакеты может значительно улучшить связность. Например, отдельный пакет для работы с базой данных должен иметь высокую связность внутри себя, чтобы все его компоненты были направлены на работу с данными. +- Классы в [[ООП|объектно-ориентированном программировании]]. Классы с высокой связностью содержат методы, направленные на выполнение одной конкретной задачи ([[Single Responsibility Principle]]), что упрощает их поддержку и тестирование. + +**Преимущества высокой связности** +- **Повышение переиспользуемости**. Высокая связность модулей позволяет их легче переиспользовать, так как все необходимые функции сосредоточены в одном месте. +- **Упрощение модификации**. Модуль с высокой связностью легче модифицировать, так как все его компоненты работают вместе для достижения одной цели. + +**Антипаттерны и частые ошибки** +- **Божественный объект (God Object)**. Это пример нарушения принципа высокой связности, когда один класс или модуль берет на себя слишком много обязанностей и имеет зависимости на многие другие части системы. Такой дизайн затрудняет понимание и модификацию кода. + +**Рекомендации** +- [[Single Responsibility Principle|Принцип единственной ответственности]] (SRP). Каждый модуль или класс должен иметь одну четко определенную ответственность, что повышает связность и облегчает поддержку кода. +- Регулярный [[../efficiency/Рефакторинг кода|рефакторинг]]. Постоянное улучшение кода помогает повысить связность внутри модулей, устраняя излишние обязанности и сосредоточивая функции на одной задаче. +## Антипример микросервисной архитектуры +Рассмотрим пример интернет-магазина, в котором реализовано три разных вида доставки: доставка в пункт выдачи, доставка курьером и доставка в магазин. Для каждой из этих задач были созданы отдельные микросервисы: `PickupPointService`, `CourierDeliveryService` и `StoreDeliveryService`. + +На первый взгляд, это выглядит как хороший подход, однако на практике каждое из этих решений может развиваться в разных направлениях и иметь различные бизнес-требования. В будущем может оказаться, что добавление новых функций в один из сервисов требует изменения логики и усложняет взаимодействие между сервисами, что может привести к дублированию бизнес-логики в нескольких местах. + +Кроме того, чтобы посчитать время доставки, каждый из этих сервисов должен знать и запросить время комплектации заказа. Это означает, что одно и то же время комплектации будет запрашиваться несколько раз разными сервисами, что приводит к избыточным обращениям и усложняет координацию между сервисами. + +В таких случаях объединение этой логики могло бы уменьшить сложность и избежать проблем с несогласованностью изменений в разных сервисах. Это пример того, когда дублирование и разделение по типу доставки могут изначально выглядеть оправданными, но на практике могут усложнить поддержку системы. +## Примеры кода +Высокая связность (Good Cohesion) + +```java +public class UserService { + private final UserRepository userRepository; + + public UserService(UserRepository userRepository) { + this.userRepository = userRepository; + } + + public User createUser(String name, String email) { + // Логика создания пользователя + User user = new User(name, email); + return userRepository.save(user); + } + + public User getUserById(Long id) { + // Логика получения пользователя по ID + return userRepository.findById(id); + } +} +``` + +В этом примере класс `UserService` имеет высокую связность, так как все его методы связаны с управлением пользователями и взаимодействием с `UserRepository`. Высокая связность делает класс легче поддерживаемым, поскольку все функции находятся в одном месте. + +Низкая связность (Bad Cohesion) + +```java +public class UserUtility { + private final UserRepository userRepository; + private final EmailService emailService; + + public UserUtility(UserRepository userRepository, EmailService emailService) { + this.userRepository = userRepository; + this.emailService = emailService; + } + + public User createUser(String name, String email) { + // Логика создания пользователя + User user = new User(name, email); + return userRepository.save(user); + } + + public void sendWelcomeEmail(User user) { + // Логика отправки приветственного письма + emailService.sendEmail(user.getEmail(), "Welcome!"); + } + + public void deleteUser(Long id) { + // Логика удаления пользователя + userRepository.deleteById(id); + } +} +``` + +В этом примере класс `UserUtility` имеет низкую связность, так как в нем сочетаются разные обязанности: управление пользователями, отправка email, удаление пользователей. Такой класс сложно поддерживать и тестировать, так как его методы не связаны одной конкретной задачей. + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-24]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/architecture/Событийно-ориентированная архитектура.md b/dev/architecture/Событийно-ориентированная архитектура.md new file mode 100644 index 00000000..8d70e683 --- /dev/null +++ b/dev/architecture/Событийно-ориентированная архитектура.md @@ -0,0 +1,57 @@ +--- +aliases: + - event-driven + - событийно-ориентированную архитектуру + - событийно-ориентированному подходу + - Событийно-ориентированная архитектура + - событийную архитектуру + - Событийная архитектура +tags: + - maturity/🌱 +date: + - - 2024-03-19 +--- +Событийно-ориентированная архитектура — это [[Архитектурный паттерн|архитектурный подход]], при котором взаимодействие между компонентами системы строится вокруг обмена и обработки событий. + +В этой архитектуре основной фокус направлен на поток событий и их обработку, что позволяет системам быть асинхронными и хорошо масштабируемыми. События могут представлять собой любые значимые изменения состояния или действия: от пользовательских запросов и сообщений сервисов друг другу до сигналов от внешних устройств. + +**Ключевые элементы событийно-ориентированной архитектуры:** +1. **События (Events):** Представляют собой факты или изменения состояния, которые происходят в системе. Например, поступление сообщения в [[../../../../_inbox/00 Kafka|Kafka]], нажатие кнопки в пользовательском интерфейсе или обновление данных в хранилище. +2. **Обработчики событий (Event Handlers):** Компоненты или сервисы, которые "подписываются" на определённые типы событий и выполняют определённые действия в ответ на их возникновение. Обработчиком может быть [[микросервис]], вызов функции или запуск определённой логики в реакцию на сигнал. +3. **Цикл обработки событий (Event Loop) или Механизм распределения событий:** Центральный элемент, отвечающий за получение событий, их маршрутизацию и передачу нужным обработчикам. В распределённых системах его роль часто выполняет [[брокер сообщений]] или [[../../../../_inbox/Enterprise Service Bus|шина данных]]. +4. **Очередь событий (Event Queue):** Средство для буферизации и упорядочивания событий при высокой нагрузке или одновременном возникновении большого числа сигналов. Очередь обеспечивает последовательную, контролируемую обработку и повышает надёжность системы. + +**Какие задачи хорошо решает событийно-ориентированная архитектура:** +- Ситуации, когда мгновенный ответ не критичен, но важна асинхронная и надёжная обработка. Например, асинхронная загрузка, парсинг и последующая обработка крупного XML-файла или событий из внешних систем. +- Сценарии, где требуется легко масштабировать отдельные компоненты, реагирующие на поток входящих данных или сигналов. + +**Основные компоненты архитектуры:** +- [[Брокер сообщений]], выступающий в роли центрального канала обмена событиями. +- Слабо [[Связанность|связанные]] сервисы и микросервисы, которые подписываются на события и обрабатывают их по мере поступления. + +**Преимущества:** +- Изоляция компонентов: каждый сервис может развиваться и масштабироваться независимо от других. +- Простота развёртывания и интеграции новых сервисов за счёт слабой [[Связность|связности]]. +- Высокая производительность и масштабируемость: возможность обработки большого количества асинхронных операций в параллель. +- Лёгкая адаптация под изменяющиеся потребности и нагрузки. + +**Недостатки:** +- Сложность тестирования, поскольку трудно контролировать и предсказать порядок возникновения и обработки событий. +- Повышенная сложность разработки и отладки из-за асинхронной природы взаимодействий между компонентами. + +**Способы отправки событий:** +- Отправлять в [[Брокер сообщений|брокеры сообщений]] события прямо из кода. + - [[Отправка сообщений в Kafka из транзакции БД]] +- Можно читать бинлог и отправлять в [[Брокер сообщений]] +- [[Transactional Outbox]]. Сохраняем события в БД, из которой события отправляются в [[Брокер сообщений]]. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]] +**Родитель**:: [[Архитектурный паттерн]] +**Источник**:: +**Автор**:: +**Создана**:: [[2204-03-19]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/architecture/Тонкий Websocket клиент.md b/dev/architecture/Тонкий Websocket клиент.md new file mode 100644 index 00000000..e519eda6 --- /dev/null +++ b/dev/architecture/Тонкий Websocket клиент.md @@ -0,0 +1,24 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-11-13 +--- +При таком подхода вся логика по работе с Websoket соединениями переносится в отдельный сервис. WebSocket-сервис занимается только управлением соединениями и не выполняет бизнес-логику. Вся бизнес-логика обрабатывается отдельным сервисом, который не работает с WebSocket напрямую. Когда WebSocket-сервис получает сообщение, он пересылает его в бизнес-сервис через [[брокер сообщений]], например, [[../../../../_inbox/00 Kafka|Kafka]]. + +Бизнес-сервис обрабатывает сообщение и отправляет его обратно во все реплики WebSocket-сервиса, чтобы сообщение было доставлено всем участникам чата. Для того чтобы все реплики WebSocket-сервиса получали сообщение одновременно, можно использовать [[../../../../_inbox/00 Kafka|Kafka]] [[../../../../_inbox/Consumer Group|Consumer Group]]. + +![[../../meta/files/images/Pasted image 20241113184935.png]] +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: [[Проблема горизонтального масштабирования Websocket]] +**Источник**:: +**Создана**:: [[2024-11-13]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/architecture/Трёхзвенная структура.md b/dev/architecture/Трёхзвенная структура.md new file mode 100644 index 00000000..7e75387b --- /dev/null +++ b/dev/architecture/Трёхзвенная структура.md @@ -0,0 +1,30 @@ +--- +aliases: + - трехзвенная структура +tags: + - maturity/🌱 +date: + - - 2024-05-23 +zero-link: + - "[[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]]" +parents: +linked: +--- +Мы выделяем некие звенья в обработке наших запросов, и каждое звено специализируется на обработке или выполнении определенного класса задач. + +![](Pasted%20image%2020240523133746.png) + +- [Фронтенд](Фронтенд.md). предназначен для быстрой обработки легких данных, как правило, статики. Эти запросы обрабатываются тут и не проходят на массивный, тяжелый бэкенд. Для фронтенда используются такие легковесные сервера, как [nginx](../../meta/zero/00%20Nginx.md). В разработке подобных серверов огромное внимание уделяется тому, какое количество ресурсов тратится на обработку одного запроса. +- [Бэкенд](Бэкенд.md), как правило, это тяжелые приложения, в которых происходят вычисления, зашита бизнес-логика, и обрабатывать статические запросы бэкендом попросту неэффективно. +- Следующий слой – это хранение данных, в простейшем варианте – [база данных](../../meta/zero/00%20Реляционная%20база%20данных.md). +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-05-23]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/architecture/Фронтенд.md b/dev/architecture/Фронтенд.md new file mode 100644 index 00000000..7775ca02 --- /dev/null +++ b/dev/architecture/Фронтенд.md @@ -0,0 +1,31 @@ +--- +aliases: + - фронтенд +tags: + - maturity/🌱 +date: + - - 2024-05-23 +zero-link: + - "[[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]]" +parents: +linked: +--- +Для чего нужен фронтенд +- Отдача статического контента +- Буферизация запросов +- Масштабирование бэкендов +- Обслуживание медленных клиентов. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ИС|00 Архитектура ИС]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: +### Дополнительные материалы +- +### Дочерние заметки + + +- [[Rеverse proxy]] + diff --git a/dev/architecture/Централизованный сервис.md b/dev/architecture/Централизованный сервис.md new file mode 100644 index 00000000..5d2bbe85 --- /dev/null +++ b/dev/architecture/Централизованный сервис.md @@ -0,0 +1,47 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-12-08 +--- +Централизованный сервис — это компонент [[../../../../_inbox/Информационная система|системы]], выполняющий одну или несколько ключевых функций, таких как аутентификация, управление конфигурацией, обработка данных или логирование. Все или большинство других компонентов системы зависят от работы этого сервиса, что делает его важным элементом архитектуры. + +Централизованные сервисы часто встречаются в монолитных приложениях или в [[../../../../wiki/zero/00 Микросервисная архитектура|микросервисной архитектуре]], где определённый микросервис выполняет критическую роль. + +**Примеры централизованных сервисов** +- **Auth Service** — централизованная аутентификация и авторизация пользователей. +- **Configuration Server** — единый источник конфигурационных данных для системы. +- **Message Broker** — посредник для обмена данными между микросервисами (например, Kafka, RabbitMQ). +- **Logging Service** — агрегатор логов из разных частей системы. +- **Data Store** — единый источник данных, например, основная база данных. + +**Преимущества централизованного сервиса** +- **Упрощённая логика**. Все компоненты обращаются к единому сервису, что делает логику работы системы понятной и предсказуемой. +- **Централизованное управление**. Легче внедрять изменения, поскольку обновление логики происходит в одном месте. +- **Консистентность данных**. Использование одного источника данных или логики исключает дублирование и расхождения. +- **Удобство мониторинга**. Проще отслеживать состояние системы, когда ключевые функции реализованы в одном месте. + +**Недостатки централизованного сервиса** +- [[Single point of failure|Единственная точка отказа]] (SPOF). При отказе централизованного сервиса вся система может оказаться недоступной. +- [[Bottlneck|Узкое место]]. Высокая нагрузка на сервис может привести к деградации производительности всей системы. +- Риски [[Масштабирование информационной системы|масштабируемости]]. Централизованные сервисы сложнее масштабировать, особенно если они обрабатывают большие объемы данных. +- [[Latency|Задержки]]. В распределённых системах время отклика может увеличиваться из-за необходимости обращения к централизованному компоненту. + +**Как минимизировать риски централизованных сервисов?** +- [[highload/Репликация|Репликация]] и кластеризация. Развёртывание нескольких экземпляров сервиса с балансировкой нагрузки между ними. +- **Распределение ответственности**. Разделение функциональности на несколько сервисов, чтобы уменьшить нагрузку на каждый из них. +- [[Кэширование]] +- **Децентрализация**. Внедрение распределённых механизмов, которые уменьшают зависимость от одного сервиса. Пример: использование JWT для авторизации вместо постоянных запросов к Auth Service. +*** +## Мета информация +**Область**:: [[../../../../wiki/zero/00 Микросервисная архитектура|00 Микросервисная архитектура]] +**Родитель**:: [[Single point of failure|Single point of failure]] +**Источник**:: +**Создана**:: [[2024-12-08]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/architecture/Циклические зависимости сервисов.md b/dev/architecture/Циклические зависимости сервисов.md new file mode 100644 index 00000000..b8398890 --- /dev/null +++ b/dev/architecture/Циклические зависимости сервисов.md @@ -0,0 +1,144 @@ +--- +aliases: +tags: + - maturity/🌱 +date: + - - 2023-11-20 +zero-link: + - "[[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]]" +parents: +linked: +--- +Циклические зависимости между сервисами возникают, когда сервисы взаимно внедряются друг в друга. Например, сервис А внедряет сервис Б, но в тоже время сервис Б внедряет сервис А. В этом случае [SpringBoot](../../meta/zero/00%20SpringBoot.md) и [Quarkus](../../meta/zero/00%20Quarkus.md) не знают, как создать такие бины и внедрить их друг в друга. + +> [!WARNING] +> Обычно такая ситуация сигнализирует о плохо продуманной архитектуре приложения. Модули не должны иметь циклические зависимости, так как это сильно увеличивает [[связанность]] и затрудняет поддержку системы. + +Пример циклической зависимости в Spring: + +```java +@Service +public class ServiceOne { + + private final ServiceTwo serviceTwo; + + public ServiceOne(ServiceTwo serviceTwo) { + this.serviceTwo = serviceTwo; + } + +} +``` + +```java +@Service +public class ServiceTwo { + + private final ServiceOne serviceOne; + + public ServiceTwo(ServiceOne serviceOne) { + this.serviceOne = serviceOne; + } + +} +``` + +Вот что вы можете с этим сделать: +## Пересмотреть архитектуру приложения +==Это предпочтительный вариант.== Возможно вам стоит создать сервис В, который внедрит в себя сервисы А и Б. В таком случае вы распутаете циклическую зависимость. + +```java +@Service +public class ServiceThree { + + private final ServiceOne serviceOne; + private final ServiceTwo serviceTwo; + + public ServiceThree(ServiceOne serviceOne, ServiceTwo serviceTwo) { + this.serviceOne = serviceOne; + this.serviceTwo = serviceTwo; + } + +} +``` + +```java +@Service +public class ServiceOne { + +} +``` + +```java +@Service +public class ServiceTwo { + +} +``` +## Ленивое внедрение +В Spring вы можете указать аннотацию `@Lazy` у аргумента конструктора одного их сервисов. Таким образом сначала будет создан один сервис, для второго сервиса спринг создаст прокси класс, создаст из него бин и внедрит его в ваш сервис. После чего создаст второй сервис и внедрит туда уже созданный первый. А далее заменит ссылку с прокси объекта на второй сервис. + +```java +@Service +public class ServiceTwo { + + private final ServiceOne serviceOne; + + public ServiceTwo(@Lazy ServiceOne serviceOne) { + this.serviceOne = serviceOne; + } + +} +``` + +```java +@Service +public class ServiceOne { + + private final ServiceTwo serviceTwo; + + public ServiceOne(ServiceTwo serviceTwo) { + this.serviceTwo = serviceTwo; + } + +} +``` +## Внедрение через Setter +Внедрить один из сервисов через сеттер, вместо конструктора. Таким образом, фреймворк сможет создать оба бина, а потом уже внедрит один в другой. + +```java +@Service +public class ServiceOne { + + private final ServiceTwo serviceTwo; + + public ServiceOne(ServiceTwo serviceTwo) { + this.serviceTwo = serviceTwo; + } + +} +``` + +```java +@Service +public class ServiceTwo { + + private ServiceOne serviceOne; + + @Autowired + public void setServiceOne(ServiceOne serviceOne) { + this.serviceOne = serviceOne; + } + +} +``` +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ПО|00 Архитектура ПО]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2023-11-20]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/cryptography/MD5.md b/dev/cryptography/MD5.md new file mode 100644 index 00000000..80da04b9 --- /dev/null +++ b/dev/cryptography/MD5.md @@ -0,0 +1,47 @@ +--- +aliases: + - Message Digest Algorithm 5 +tags: + - maturity/🌱 +date: 2024-09-14 +zero-link: + - "[[../../meta/zero/00 Криптография|00 Криптография]]" + - "[[../../meta/zero/00 Снипеты для Java|00 Снипеты для Java]]" +parents: + - "[[Хеш-функция]]" +linked: +--- +MD5 (Message Digest Algorithm 5) — это [[Хеш-функция]], которая преобразует входные данные в 128-битное (16-байтное) значение, называемое хешем или дайджестом сообщения. + + +> [!DANGER] +> Сегодня MD5 считается устаревшим и небезопасным для большинства криптографических приложений. В современных системах вместо MD5 рекомендуется использовать более безопасные алгоритмы, такие как [[SHA-256]] или SHA-3, которые обладают лучшей устойчивостью к коллизиям и другим атакам. + + +Широко используется для проверки целостности данных и в других криптографических задачах. + +**Основные характеристики MD5:** +- **Фиксированная длина выхода**: Независимо от размера входных данных (например, текст или файл), хеш всегда имеет длину 128 бит (16 байт). +- **Однонаправленность**: MD5 является однонаправленной функцией, что означает, что невозможно восстановить исходные данные по их хешу. +- **Быстродействие**: MD5 работает быстро и эффективно, что сделало его популярным для использования в приложениях, где требуется быстрая обработка данных. + +**Недостатки MD5:** +- **Уязвимость к коллизиям**: MD5 подвержен коллизиям, что означает, что существует возможность найти два различных входа, которые дают одинаковый хеш. Это делает MD5 небезопасным для криптографических применений, таких как цифровые подписи и сертификаты. +- **Атаки на предобраз**: Существуют методы, позволяющие найти вход, соответствующий заданному хешу, что еще больше подрывает надежность MD5. +- **Низкая устойчивость к криптографическим атакам**: Со временем были разработаны более мощные алгоритмы, такие как [[SHA-256|SHA-256]] и SHA-3, которые обеспечивают лучшую безопасность по сравнению с MD5. + +**Применения MD5:** +- **Проверка целостности данных**: Используется для проверки целостности файлов и данных, например, в контексте загрузки программного обеспечения, где MD5 хеши публикуются вместе с файлами для проверки их целостности. +- **Создание контрольных сумм**: MD5 был популярен для создания контрольных сумм файлов, чтобы быстро проверить, не были ли файлы изменены. +- **Идентификаторы и хеширование строк**: MD5 использовался для создания уникальных идентификаторов и хеширования паролей (хотя сейчас это считается небезопасной практикой). +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Криптография|00 Криптография]] +**Родитель**:: [[Хеш-функция]] +**Источник**:: +**Создана**:: [[2024-09-14]] +**Автор**:: +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/cryptography/SHA-256.md b/dev/cryptography/SHA-256.md new file mode 100644 index 00000000..9738e647 --- /dev/null +++ b/dev/cryptography/SHA-256.md @@ -0,0 +1,44 @@ +--- +aliases: + - Secure Hash Algorithm 256-bit + - SHA256 +tags: + - maturity/🌱 +date: 2024-09-14 +zero-link: + - "[[../../meta/zero/00 Криптография|00 Криптография]]" + - "[[../../meta/zero/00 Снипеты для Java|00 Снипеты для Java]]" +parents: + - "[[Хеш-функция]]" +linked: +--- +SHA-256 (Secure Hash Algorithm 256-bit) — это [[Хеш-функция]], которая преобразует входные данные в 256-битное (32-байтное) значение, называемое хешем. SHA-256 является частью семейства алгоритмов SHA-2. + +**Основные характеристики SHA-256:** +- **Фиксированная длина выхода**: Независимо от размера входных данных (например, файл, текст, строка), выход всегда имеет длину 256 бит (32 байта). +- **Однонаправленность**: Хеш-функция является однонаправленной, что означает, что по хешу невозможно восстановить исходные данные. +- **Устойчивость к коллизиям**: Вероятность нахождения двух различных входов, которые дают один и тот же хеш, чрезвычайно мала, что делает SHA-256 устойчивой к коллизиям. +- **Устойчивость к предобразу**: Трудно найти вход, который соответствует заданному хешу. +- **Быстродействие**: SHA-256 работает достаточно быстро для большинства приложений, включая цифровые подписи, контроль целостности данных и криптографические протоколы. + +**Применения SHA-256:** +- **Хранение паролей**: Хеширование паролей перед хранением для защиты от утечек данных. +- **Контроль целостности данных**: Проверка целостности файлов или сообщений с помощью хеша. +- **Криптовалюты**: SHA-256 используется в алгоритме доказательства работы (Proof-of-Work) в блокчейне Bitcoin. +- **Цифровые подписи**: Используется для создания цифровых подписей, которые подтверждают подлинность и целостность сообщений. + +**Реализации:** +- [[../snippet/Реализация SHA-256 на Java|Реализация SHA-256 на Java]] +## Мета информация +**Область**:: [[../../meta/zero/00 Криптография|00 Криптография]], [[../../meta/zero/00 Снипеты для Java|00 Снипеты для Java]] +**Родитель**:: [[Хеш-функция]] +**Источник**:: +**Создана**:: [[2024-09-14]] +**Автор**:: +### Дополнительные материалы +- +### Дочерние заметки + + +- [[Реализация SHA-256 на Java]] + diff --git a/dev/cryptography/Генерация аппаратного SSH ключа.md b/dev/cryptography/Генерация аппаратного SSH ключа.md new file mode 100644 index 00000000..f0e9dcfb --- /dev/null +++ b/dev/cryptography/Генерация аппаратного SSH ключа.md @@ -0,0 +1,46 @@ +--- +tags: + - maturity/🌾 +date: + - - 2024-01-13 +zero-link: + - "[[../../meta/zero/00 Криптография|00 Криптография]]" +parents: + - "[[SSH]]" +linked: +--- +> [!WARNING] Версия OpenSSH +> Для работы такого ключа нужен OpenSSH версии 8.2 и выше как на сервере, так и на вашем ПК + +> [!WARNING] PGP +> В интернете полно гайдов, как использовать GPG агент вместо SSH, когда у вас вместо ssh ключа будут ключи gpg. Но эти настройки выглядит как костыли. + +```bash +ssh-keygen -t ed25519-sk -O resident -O application=ssh:key_name -f ~/.ssh/key_name +``` + +Все как с обычными SSH ключами, появится 2 файла в папке ssh `key_name` и `key_name.pub`. Только вот, воспользоваться секретным ключом без подключения аппаратного ([Yubikey](Yubikey.md)) не выйдет. + +Флаги: +- `-O verify-required`. Потребует вводить пароль от аппаратного ключа для доступа к SSH ключу. +- `-O application=ssh:key_name`. Позволяет установить название ключу, которое можно будет увидеть в приложении Yubico Authentification. ![](../../meta/files/images/Pasted%20image%2020240113100105.png) + +Такой ключ подойдет и для доступа к репозиториям. Но необходимо будет прописать в `~/.ssh/config` информацию о том, какой ключ использовать: + +```yaml +Host github.com + Hostname github.com + IdentityFile ~/.ssh/github + IdentitiesOnly yes +``` +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Криптография|00 Криптография]] +**Родитель**:: [[../../../../knowledge/dev/network/SSH|SSH]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-01-13]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/cryptography/Скачать сертификат сайта.md b/dev/cryptography/Скачать сертификат сайта.md new file mode 100644 index 00000000..277cf759 --- /dev/null +++ b/dev/cryptography/Скачать сертификат сайта.md @@ -0,0 +1,26 @@ +--- +tags: + - maturity/🌱 +date: + - - 2024-01-10 +zero-link: [] +parents: +--- +```shell +openssl s_client -showcerts -connect www.example.com:443 +``` + +Эта команда выведет сертификат в консоль. Далее нужно скопировать все, что между `-----BEGIN CERTIFICATE-----` и `-----END CERTIFICATE-----` включая эти строки. + +Скопированные данные вставить в текстовый документ и сохранить с расширением `*.cer`. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Криптография|00 Криптография]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-01-10]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/cryptography/Хеш-функция.md b/dev/cryptography/Хеш-функция.md new file mode 100644 index 00000000..93bb5e82 --- /dev/null +++ b/dev/cryptography/Хеш-функция.md @@ -0,0 +1,32 @@ +--- +aliases: + - хеш-функция + - хеш функция + - хеш функции + - хеш-функции + - хеш-алгоритм +tags: + - maturity/🌱 +date: 2024-09-14 +zero-link: + - "[[../../meta/zero/00 Криптография|00 Криптография]]" +parents: +linked: +--- +- [[MD5]] +- [[SHA-256]] +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Криптография|00 Криптография]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-09-14]] +**Автор**:: +### Дополнительные материалы +- +### Дочерние заметки + + +- [[MD5]] +- [[SHA-256]] + diff --git a/dev/database/DB page.md b/dev/database/DB page.md new file mode 100644 index 00000000..25399b93 --- /dev/null +++ b/dev/database/DB page.md @@ -0,0 +1,27 @@ +--- +aliases: + - страница + - страницы + - страница БД + - Страница БД + - странице бд +tags: + - maturity/🌱 +date: 2024-11-04 +--- +В базе данных страница — это базовая единица хранения данных, используемая для организации таблиц и индексов. Она представляет собой фиксированный блок данных (обычно 8 килобайт в PostgreSQL, но размер может варьироваться) и содержит строки таблицы или фрагменты индексов. Когда база данных выполняет запрос, она обращается к страницам, чтобы получить нужные строки, и может считывать их из диска или из кэша, где часто используемые страницы уже загружены в память. + +База данных работает поверх операционной системы и поэтому использует [[../fundamental/Страница|страницы ОС]] для хранения своих страниц данных. Когда СУБД загружает страницу базы данных из диска, операционная система выделяет ей одну или несколько страниц оперативной памяти. В результате страницы базы данных хранятся в страницах памяти ОС. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Реляционная база данных|00 Реляционная база данных]] +**Родитель**:: [[../fundamental/Страница|Страница]] +**Источник**:: +**Создана**:: [[2024-11-04]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/database/Data Vault.md b/dev/database/Data Vault.md new file mode 100644 index 00000000..d1568bc0 --- /dev/null +++ b/dev/database/Data Vault.md @@ -0,0 +1,78 @@ +--- +aliases: + - Таблицы сателиты +tags: + - maturity/🌱 +date: 2024-11-25 +--- +![[../../meta/files/images/Снимок экрана 2024-11-25 в 13.57.23.png]] + +**Основные понятия:** +- **Хаб (Hub):** + Таблица, представляющая основную сущность или бизнес-объект, например, клиент, продукт или заказ. В хабе обычно содержатся стабильные и уникальные бизнес-идентификаторы. +- **Линк (Link):** + Таблица, представляющая связь между хабами. Она моделирует отношения, например, какой клиент сделал какой заказ. +- **Сателлит (Satellite):** + Таблица, привязанная к хабу или линку, которая хранит дополнительные атрибуты и временные данные. + +**Зачем нужны сателлиты?** +- **Отделение изменяемых данных от неизменяемых:** Хаб содержит уникальные данные, которые редко изменяются. Все остальные данные, которые могут меняться (например, имя клиента, его адрес или статус заказа), переносятся в сателлиты. +- **Историзация данных:** Сателлиты поддерживают версионность, т.е. они хранят не только актуальное состояние данных, но и их историю. Это достигается за счет добавления колонок: + - Дата начала действия версии (`start_date`). + - Дата окончания действия версии (`end_date`). + - Индикатор актуальной версии (например, `is_current`). +- **Разделение областей данных:** Сателлиты позволяют разделить разные типы данных для более удобного хранения и обработки. Например: + - Один сателлит может хранить адресную информацию. + - Другой — контактные данные. + - Третий — финансовую информацию +- **Облегчение загрузки данных:** При использовании ETL (Extract, Transform, Load) сателлиты упрощают инкрементальную загрузку, так как можно обрабатывать только те записи, которые изменились. +- **Масштабируемость:** За счет хранения данных в разных таблицах (сателлитах), можно легче управлять растущим объемом данных и делать хранилище более модульным. + +**Преимущества сателлитных таблиц:** +- **Поддержка аудита:** История изменений атрибутов сохраняется, что критично для аналитики и соблюдения нормативных требований. +- **Управление большими данными:** Разделение на хабы, линки и сателлиты делает модель гибкой и позволяет обрабатывать большие объемы данных с меньшими затратами. +- **Удобство для интеграции:** Модель легко расширяется за счет добавления новых сателлитов без изменения существующей структуры. + +**Недостатки:** +- Увеличение количества таблиц и сложности структуры. +- Медленные запросы из-за множества JOIN-операций. +- Увеличение объема данных из-за историзации. +- Сложные и трудоемкие ETL/ELT процессы. +- Требуется опыт и квалификация для работы с моделью. +- Ограниченная поддержка в BI-инструментах. +- Модель может быть избыточной для небольших проектов. +## Пример +Предположим, у нас есть сущность "Клиент". В Data Vault модель она будет представлена следующим образом: + +Хаб (Hub_Client): +```plaintext +client_id | business_key | load_date | record_source +``` + +Сателлит (Satellite_Client_Demographics): +```plaintext +client_id | name | birth_date | start_date | end_date | is_current | record_source +``` + +Сателлит (Satellite_Client_Address): +```plaintext +client_id | address | city | country | start_date | end_date | is_current | record_source +``` + +Здесь: +- **Hub_Client** хранит уникальный идентификатор клиента (например, ID из CRM). +- **Satellite_Client_Demographics** хранит демографические данные клиента, которые могут изменяться (например, имя при смене паспорта). +- **Satellite_Client_Address** хранит адресные данные клиента, включая исторические изменения адресов. +*** +## Мета информация +**Область**:: +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-25]] +**Автор**:: +### Дополнительные материалы +- [Введение в Data Vault / Хабр](https://habr.com/ru/articles/348188/) + +### Дочерние заметки + + diff --git a/dev/database/Online Analytical Processing.md b/dev/database/Online Analytical Processing.md new file mode 100644 index 00000000..0f2267dc --- /dev/null +++ b/dev/database/Online Analytical Processing.md @@ -0,0 +1,50 @@ +--- +aliases: + - OLAP +tags: + - maturity/🌱 +date: 2024-03-31 +--- +OLAP (Online Analytical Processing) — это тип нагрузки, который ориентирован на выполнение сложных аналитических запросов, охватывающих большие объемы данных. OLAP используется для построения отчетов, аналитики и поддержки принятия решений, где важно работать с историческими данными и выполнять сложные агрегации. + +**Особенности:** +- Источником для OLAP являются различные [[Online Transaction Processing|OLTP]] базы +- Операции `SELECT` выполняются значительно чаще, чем операции изменения данных. + - Запросы часто содержат операции агрегации (например, SUM, AVG) и группировки (GROUP BY). +- Запросы `SELECT` охватывают большие выборки данных и могут включать сложные агрегации и группировки. +- Часто используется денормализация +- Скорость обработки зависит от количества данных, но обычно медленнее чем в [[Online Transaction Processing|OLTP]] + +**Примеры задач:** +- Поиск зависимостей по товарам, которые пользователи покупают вместе. +- Получение информации о продажах за последние 3 года. +- Построение аналитики по шаблонам платежей по группам пользователей. + +**Причины выделить OLAP нагрузку:** +- Разный характер нагрузки, требующий долгосрочного хранения и анализа данных. +- Специфические стратегии [[Индекс базы данных|индексирования]] для оптимизации аналитических запросов. +- Работа с большими объемами данных и их обработка в рамках одного запроса. +- Поддержка исторических данных для анализа трендов и построения отчетов. + +Это не то же самое, что создание отдельной реплики для отчетности, так как это не решает проблему разных индексов. Однако на логической репликации это возможно. + +OLAP архитектуры: +- Звезда +- Снежинка +- [[Data Vault]] +- Lambda +- Kappa + +**Рекомендации:** +- Использовать [[Колоночная база данных|колоночную базу данных]] +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Реляционная база данных|00 Реляционная база данных]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-03-31]] +### Дополнительные материалы +- [[Online Transaction Processing]] +### Дочерние заметки + diff --git a/dev/database/Online Transaction Processing.md b/dev/database/Online Transaction Processing.md new file mode 100644 index 00000000..d6350a73 --- /dev/null +++ b/dev/database/Online Transaction Processing.md @@ -0,0 +1,37 @@ +--- +aliases: + - OLTP +tags: + - maturity/🌱 +date: 2024-03-31 +--- +OLTP (Online Transaction Processing) — это тип нагрузки, который характеризуется выполнением большого количества коротких транзакций, таких как операции вставки, обновления и удаления. OLTP-системы обычно используются для поддержки оперативной деятельности, где важна быстрая обработка данных. + +**Особенности:** +- Множество маленьких и быстрых [[Транзакция БД|транзакций]]. +- Частое выполнение операций `INSERT`, `UPDATE`, `DELETE`. +- Подавляющее большинство операций затрагивает только одну строку. +- Запросы должны выполняться максимально быстро. +- Высокая степень нормализации таблиц. + +**Примеры задач:** +- Продажа товаров пользователям. +- Прием платежей за сотовую связь. +## Лучшие практики для оптимизации производительности +- **Использование индексов**: правильно настроенные [[Индекс базы данных|индексы]] позволяют быстрее выполнять операции и уменьшить количество операций чтения. +- [[../../../../_inbox/Шардирование БД|Шардинг]] (разделение таблиц): разделение таблиц на части снижает нагрузку и улучшает производительность. +- **Избегание блокировок**: минимизация блокировок таблиц и строк особенно важна при большом количестве параллельных транзакций. +- Для OLTP-нагрузки не следует использовать параллельное выполнение запросов, так как это забирает ядро процессора у другого запроса, что может привести к задержкам в обработке транзакций и снижению общей производительности системы. В контексте OLTP важнее минимизировать время выполнения каждого отдельного запроса, а не распределять его между несколькими ядрами. ==Каждый запрос должен выполняться на одном ядре как можно быстрее.== +- Не хранить данные, которые уже не нужны для бизнес-логики, а нужны только для [[Online Analytical Processing|OLAP]]. Попробовать переносить архивные данные в отдельную базу данных. + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Реляционная база данных|00 Реляционная база данных]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-03-31]] +### Дополнительные материалы +- [[Online Analytical Processing]] +### Дочерние заметки + diff --git a/dev/database/Write-read pattern.md b/dev/database/Write-read pattern.md new file mode 100644 index 00000000..63784d1f --- /dev/null +++ b/dev/database/Write-read pattern.md @@ -0,0 +1,37 @@ +--- +aliases: + - запись-чтение +tags: + - maturity/🌱 +date: 2024-09-17 +zero-link: + - "[[../../meta/zero/00 Реляционная база данных|00 Реляционная база данных]]" +parents: +linked: +--- +Ситуация, когда после записи данных в master реплику вы пытаетесь немедленно прочитать те же данные с другой реплики. Это может привести к проблемам из-за задержек синхронизации между основным узлом и репликами. + +![](../../meta/files/images/Pasted%20image%2020240607211343.png) + +Основные причины, почему стоит избегать этого паттерна при репликации: + +- [[../architecture/highload/Отставание реплики БД|Задержки репликации]]: Данные, записанные на основном узле, не сразу реплицируются на все реплики. При чтении с реплики можно получить устаревшую информацию. +- Непоследовательность данных: Вы можете получить неконсистентные данные, так как реплика может не успеть синхронизироваться с основным узлом. +- [[../other/Race condition|Условие гонки]]: Возникает ситуация, когда операции записи и чтения конкурируют между собой. Это может привести к тому, что операция чтения прочитает данные до того, как завершится операция записи на всех узлах. + +Чтобы избежать этих проблем, рекомендуется: +- Чтение данных с основного узла, если требуется сразу после записи. +- Использование механизмов согласованности, таких как кворумное чтение и запись, где для подтверждения операции необходимо согласие нескольких узлов. +- Настройка задержек или проверок синхронизации для гарантии, что данные были реплицированы перед чтением. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Реляционная база данных|00 Реляционная база данных]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-09-17]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + diff --git a/dev/database/mysql/Mixed binlog format.md b/dev/database/mysql/Mixed binlog format.md new file mode 100644 index 00000000..4b9e3f5b --- /dev/null +++ b/dev/database/mysql/Mixed binlog format.md @@ -0,0 +1,39 @@ +--- +aliases: +tags: + - maturity/🌱 +date: + - - 2024-06-02 +zero-link: + - "[[../../../meta/zero/00 MySQL|00 MySQL]]" +parents: + - "[[Репликация в MySQL]]" +linked: + - "[[Row Based Replication (RBR)]]" + - "[[Statement Based Replication (SBR)]]" +--- +Mixed binlog format — это попытка объединить лучшие стороны [[Statement Based Replication (SBR)|SBR]] и [[Row Based Replication (RBR)|RBR]]. В зависимости от ситуации он может работать либо как SBR, либо как RBR. По умолчанию был дефолтным вариантом в MySQL 5.1. + +**Принципы работы** +- [[Statement Based Replication (SBR)|SBR]] используется для простых и детерминированных запросов, таких как UPDATE или INSERT, которые не зависят от текущего состояния данных и могут быть воспроизведены на slave без изменений. +- [[Row Based Replication (RBR)|RBR]] применяется для сложных запросов или запросов, которые могут быть недетерминированными, например, когда используются функции, такие как NOW() или RAND(), или для запросов, которые изменяют большое количество строк. + +**Плюсы**: +- **Гибкость**: Автоматический выбор между SBR и RBR в зависимости от ситуации позволяет использовать преимущества обоих форматов. +- **Оптимизация**: В теории, это позволяет оптимизировать использование ресурсов, выбирая наиболее подходящий метод для каждой транзакции. + +**Минусы** +- **Редкое использование**: Встречается редко, так как не всегда работает корректно и может приводить к неожиданным проблемам с репликацией. +- **Сложность**: Повышенная сложность настройки и диагностики, что может затруднять управление и устранение неполадок. +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 MySQL|00 MySQL]] +**Родитель**:: [[Репликация в MySQL]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-06-02]] +### Дополнительные материалы +- [[Statement Based Replication (SBR)]] +- [[Row Based Replication (RBR)]] +### Дочерние заметки + diff --git a/dev/database/mysql/Row Based Replication (RBR).md b/dev/database/mysql/Row Based Replication (RBR).md new file mode 100644 index 00000000..52cf392b --- /dev/null +++ b/dev/database/mysql/Row Based Replication (RBR).md @@ -0,0 +1,41 @@ +--- +aliases: + - RBR +tags: + - maturity/🌱 +date: + - - 2024-06-02 +zero-link: + - "[[../../../meta/zero/00 MySQL|00 MySQL]]" +parents: + - "[[Репликация в MySQL]]" +linked: + - "[[Statement Based Replication (SBR)]]" +--- +От мастера к слейву отправляются только измененные строки, сам результат изменений. Основан на журнале [Row-based Binary Log](Журналы%20в%20MySQL.md#Row-based%20Binary%20Log). + +RBR имеет три режима работы: +- full: При изменении сохраняются все колонки (до изменения и после), даже если в них не было изменений. Такой режим потребляет много памяти. +- noblob: Работает как full, но не передает изменения BLOB и TEXT колонок. +- minimal: При изменении строки сохраняются только измененные колонки и колонки Primary Keys. + +**Плюсы:** +- Детерминированность: Запрос выполняется на master, а slave получает уже результат. Это устраняет проблемы, связанные с недетерминированными функциями, как в SBR. +- Бинарный формат + +**Минусы:** +- **Бинарный формат**: Прочитать глазами уже не получится. Однако, есть утилита `mysqlbinlog -v`, которая позволяет читать журнал. +- Большое потребление памяти: Потребляет больше памяти, чем SBR, так как нужно сохранять изменения строк до и после. + - в mysql есть binlog_row_image, который решает эту проблему +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 MySQL|00 MySQL]] +**Родитель**:: [[Репликация в MySQL]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-06-02]] +### Дополнительные материалы +- [[Statement Based Replication (SBR)]] +### Дочерние заметки + + diff --git a/dev/database/mysql/Statement Based Replication (SBR).md b/dev/database/mysql/Statement Based Replication (SBR).md new file mode 100644 index 00000000..288d7529 --- /dev/null +++ b/dev/database/mysql/Statement Based Replication (SBR).md @@ -0,0 +1,40 @@ +--- +aliases: + - SBR +tags: + - maturity/🌱 +date: + - - 2024-06-02 +zero-link: + - "[[../../../meta/zero/00 MySQL|00 MySQL]]" +parents: + - "[[Репликация в MySQL]]" +linked: + - "[[Row Based Replication (RBR)]]" +--- +Первое, что приходит в голову, это сохранять в Binary Log непосредственно SQL-запросы: Statement-based Binary Log. На основе этого журнала работает Statement Based Replication (SBR). В этом случае master сохраняет в журнал SQL-запросы, а slave получает этот список запросов и выполняет их у себя. + +В основе данной репликации лежит журнал [Statement-based Binary Log](Журналы%20в%20MySQL.md#Statement-based%20Binary%20Log). + +**Плюсы:** +- Небольшое количество передаваемых данных, при однотипных изменениях. Например, если мы изменяем 5 миллионов строк одним запросом: `UPDATE users SET bonus=bonus+100`, то нужно передать только 1 строку запроса. +- В журнале все записано в понятном человеко-читаемом виде. + +**Проблемы:** +* Недетерминирован. Каждый запрос самостоятельно исполняется на слейве. + * Вызов функций, например функции `now()`. В момент попадания запроса на slave это будет уже другое время. + - [Остальные примеры](https://dev.mysql.com/doc/refman/8.0/en/replication-rbr-safe-unsafe.html): uuid(), fund_rows(), rand(), UDF, триггеры на апдейт, auto_increment +- Долгое выполнение сложных запросов. Если запрос выполнялся 10 минут на master, то на slave он тоже будет выполняться 10 минут. + +Для того чтобы SBR работала корректно, есть специальный флажок. +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 MySQL|00 MySQL]] +**Родитель**:: [[Репликация в MySQL]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-06-02]] +### Дополнительные материалы +- [[Row Based Replication (RBR)|Row Based Replication (RBR)]] +### Дочерние заметки + diff --git a/dev/database/mysql/Архитектура MySQL.md b/dev/database/mysql/Архитектура MySQL.md new file mode 100644 index 00000000..82626e87 --- /dev/null +++ b/dev/database/mysql/Архитектура MySQL.md @@ -0,0 +1,48 @@ +--- +aliases: +tags: + - maturity/🌱 +date: + - - 2024-06-16 +zero-link: + - "[[../garden/ru/meta/zero/00 MySQL|00 MySQL]]" +parents: +linked: +--- +В MysSQL есть логический слой, который занимается общими и изолированными от хранения данных операциями: кэширование, построение плана запроса и так далее. А есть конкретный физический слой, который отвечает за хранение данных. Он использует интерфейс подключения, то есть реализации хранилищ могут быть разными. ^42f122 + +Из-за этого возникают проблемы: +- [[Репликация в MySQL]]. Вынуждены писать несколько журналов, на логическом и физическом уровне +- Индексы. Реализация одного и того же индекса может отличаться в разных хранилищах +- Оптимизатор слабо связан с хранилищем, из-за этого он не может использовать какие-то особенности движка для улучшения производительности. + +![](../../../meta/files/images/Pasted%20image%2020240613195204.png) + +Клиенты, которые обращаются к серверу через функции соответствующего коннектора или C API по протоколу TCP/IP либо UNIX Socket. + +Логический слой, общий для всех движков: +- В управлении подключением происходит авторизация. Каждый клиент работает в своем независимом потоке. Каждый поток может кэшироваться сервером. +- Кэш запросов. Представлен одним общим потоком для всех клиентов. Может оказаться узким местом. +- Парсер проверяет синтаксис запроса, запрашивает у хранилищ наличие данных таблиц и полей, права доступа непосредственно к этим полям и проверяет наличие ответа в кэше запросов, после чего передает распарсенный запрос оптимизатору; +- Оптимизатор запрашивает в интерфейсе хранилищ статистику по индексам, на основании которой он строит план запроса, который передает исполнителю; +- Исполнитель. Обращается за данными в хранилище согласно плану запроса. Обновляет значения в кэше запросов. +## Оптимизатор +Выбирает самый производительный план. + +План запроса, который делает оптимизатор, это не какой-то исполняемый код, а набор инструкций, который передается исполнителю. Это некое предположение о том, как запрос будет выполняться. В отличие от PostrgreSQL, мы не можем посмотреть как фактически был выполнен запрос. Данные от 2015 года, может что-то изменилось. ^432879 + +Какие проблемы: +- Из-за архитектуры MySQL + - использует мало статистики по запросам. + - не учитывает особенности хранилищ, нагрузку, буфферы соединений и кэши + +Как влиять на оптимизатор? +- Переписать запрос. +- Использовать [[../../../../../_inbox/Индекс в MySQL|индексы]] +- user/force/ignore index. Можем явно указать когда и какие индексы использовать +- straight_join. Можем задать жесткий порядок join таблиц +- @@optimizer_switch. Позволяет включать/отключать правила, которые использует оптимизатор. +- optimizer_prune_level и optimizer_search_depth. Верхняя граница количества вариантов и времени выполнения, которые рассмотрит оптимизатор. + +## Заметки +- mariadb - форк Mysql, который пытается исправить архитектурные ошибки MySQL \ No newline at end of file diff --git a/dev/database/mysql/Журналы в MySQL.md b/dev/database/mysql/Журналы в MySQL.md new file mode 100644 index 00000000..fe0e0124 --- /dev/null +++ b/dev/database/mysql/Журналы в MySQL.md @@ -0,0 +1,65 @@ +--- +aliases: + - InnoDB +tags: + - maturity/🌱 +date: + - - 2024-05-28 +zero-link: + - "[[../../../meta/zero/00 MySQL|00 MySQL]]" +parents: + - "[[../garden/ru/dev/database/mysql/Архитектура MySQL|Архитектура MySQL]]" +linked: + - "[[Репликация в MySQL]]" +--- +Изначально в MySQL не было никаких журналов. Был движок MyISAM, а в нем журнала нет. + +![](Pasted%20image%2020240528082025.png) +На рисунке вы можете видеть штуку, которая называется Storage Engines: это такая сущность, которая занимается вопросами, как писать данные на диск и как нам их оттуда читать, как по ним искать и пр. + +Потом прикрутили репликацию. Репликация – это одна строчка в самом левом верхнем квадратике – Management Services&Utilites. Для репликации потребовался журнал. Его начали писать. Он называется Binary Log. Никто не думал про то, чтобы его использовать как-то иначе, просто сделали. + +Примерно в это же время MySQL подарили новый Storage Engine, который называется InnoDB. Это широко используемая штука, и в InnoDB свой журнал. Получилось два журнала – InnoDB и Binary Log. Этот момент стал точкой невозврата, после чего появились проблемы, которые решить очень тяжело. + +Binary Log не используется для [Point In Time Recovery](Point%20In%20Time%20Recovery%20(PITR).md), а InnoDB Undo/Redo Log не используется в репликации. Получилось, что у PostgreSQL журнал один, а у MySQL их, как бы, два. +## InnoDB Undo/Redo Log +## Binary Log +У Binary Log, который нужен для репликации, есть два или три формата (типа). +### Statement-based Binary Log +Самый первый тип, который появился, который было проще всего сделать, это Statement-based Binary Log. Что это такое? Это просто файл, в который последовательно пишутся транзакция за транзакцией. Это выглядит примерно так: + +![](Pasted%20image%2020240528082432.png) + +В транзакции указывается БД, на которой совершаются эти обновления, указывается timestamp времени начала транзакции, и дальше идет сама транзакция. +### Row-based Binary Log +Второй тип называется Row-based репликация. Это журнал, в который пишутся не сами запросы, а те строчки, которые они меняют. Он состоит из двух частей – BEFORE image и AFTER image: + +![](Pasted%20image%2020240528082516.png) +На картинке BEFORE image сверху, а AFTER image – внизу. + +В BEFORE image помещаются те строчки, которые были до выполнения транзакции. Красным цветом помечены строчки, которые удаляются: + +![](Pasted%20image%2020240528082538.png) + +Они из BEFORE image наверху, но их нет внизу – в AFTER image, значит, они удаляются. + +На следующей картинке зеленым помечены строчки, которые добавились: + +![](Pasted%20image%2020240528082552.png) + +Синие UPDATE'ы есть и в BEFORE image, и в AFTER image. Это обновления. + +Проблема такого решения связана с тем, что до недавнего времени в Row-based репликации писались в log все колонки, даже если мы обновили одну. В MySQL 5.6 это починили, и с этим должно стать полегче. +### Mixed-based +Он работает либо как Statement-based, либо как Row-based, но он широко не распространен. +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 MySQL|00 MySQL]] +**Родитель**:: [[Архитектура MySQL]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-05-28]] +### Дополнительные материалы +- [[Репликация в MySQL]] +### Дочерние заметки + diff --git a/dev/database/mysql/Репликация в MySQL.md b/dev/database/mysql/Репликация в MySQL.md new file mode 100644 index 00000000..8c41361d --- /dev/null +++ b/dev/database/mysql/Репликация в MySQL.md @@ -0,0 +1,127 @@ +--- +aliases: +tags: + - maturity/🌱 +date: + - - 2024-05-28 +zero-link: + - "[[../../../meta/zero/00 MySQL|00 MySQL]]" +parents: + - "[[../../architecture/highload/Репликация БД|Репликация БД]]" +linked: + - "[[Журналы в MySQL]]" +link: +--- +## Тезисы +- На slave можно реализовать другую схему БД, построить другие индексы. +- Можно использовать [libslave](libslave.md), чтобы "притвориться" репликой. +- Мастер многопоточен, а слейв - нет. Вроде исправлено в новых версиях SQL. + - В 5.6 версии можно реплицировать параллельно несколько БД + - В 5.7 версии можно реплицировать параллельно одни и те же таблицы +- Обязательно убедиться, что работают GUID идентификация транзакций. +- **Репликация сильно зависит от версии MySql** + - Всегда логическая репликация, модель master-slave, pull распространение + - 4.1 = асинхронная, SBR, logposs + - 5.1 = +RBR, +mixed. Дефолт mixed + - 5.6 = +semisync, +mtslave (per-db), +slavedelay, +GTID + - 5.7 = + mtslave, +master-master (plugin), +default-RBR (image=full?!), groupcommit +## Схема работы репликации +![[Архитектура MySQL#^42f122]] + +Физический слой хранилища должен писать журнал для работы транзакций (Write-Ahead Log). По идее, его можно было бы использовать для репликации, как в PostgreSQL, но логический слой ничего не знает про физический и не может использовать тот же журнал. Поэтому при включении репликации на логическом уровне master начинает вести свой журнал, называемый Binary Log. + +Механизм работы следующий: +- **Запись изменений в бинарный лог**: Все изменения данных записываются в бинарный лог (Binary Log) на мастере. Бинарный лог хранит последовательность всех транзакций, которые изменяют данные. +- **Передача бинарного лога на реплики**: Мастер передает бинарный лог на реплики. Для этого используются потоки binlog dump на мастере и I/O потоки на репликах. В отличие от PostgreSQL, используется pull модель распространения, то есть реплики сами забирают изменения с master. +- **Применение изменений на репликах**: Реплики считывают бинарный лог и применяют изменения к своим копиям данных, поддерживая синхронизацию с мастером. + +![](../../../meta/files/images/Pasted%20image%2020240712083105.png) + +Binary Log в MySQL может записывать данные в разных форматах, в зависимости от настроек журнала. Рассмотрим основные из них: +- [Statement Based Replication (SBR)](Statement%20Based%20Replication%20(SBR).md) +- [Row Based Replication (RBR)](Row%20Based%20Replication%20(RBR).md) +- [Mixed binlog format](Mixed%20binlog%20format.md) + +**Процесс записи данных операции в MySQL** +- INSERT INTO test VALUES (123, 'hello') +- Записываем в таблицу на мастере mysqld +- Записываем в binary log на мастере +- Записываем в relay log на слейве +- таблица на слейве mysqld + +Рабочие потоки ([MySQL Replication Threads](https://dev.mysql.com/doc/refman/8.0/en/replication-threads.html)): +- binlog dump thread. Сохраняет лог транзакций на master +- slave I/O thread. Спуливает изменения на slave с master +- slave SQL thread. Применяет изменения на slave + +MySQL не решает из коробки проблемы кластеризации. Из коробки нет переключений со slave на master если мастер сдох, распределения нагрузки и так далее. Можно решить дополнительным софтом: +- MHA (MySQL Master HA) +- MySQL Failover (Oracle) +- Orchestrator +## Фильтрация репликации +Можно реплицировать данные частично, но это стоит использовать осторожно. Например, это не работает с [Групповая репликация](../../architecture/highload/Групповая%20репликация.md) + +Опции: +- replicate_do_db +- replicate_ignore_db +- replicate_do_table + +[MySQL - CHANGE REPLICATION FILTER Statement](https://dev.mysql.com/doc/refman/8.0/en/change-replication-filter.html) + +![](../../../meta/files/images/Pasted%20image%2020240605091913.png) + + +*** + +- В InnoDB, заметьте, т.е. у нас архитектура разделяет репликацию выше, а storage engine ниже. Но storage engine, для того, чтобы репликация работала, должен, грубо говоря, замедлять insert'ы в таблицу. +- Другая проблема состоит в том, что мастер выполняет запросы параллельно, т.е. одновременно, а слэйв их может применять последовательно. Возникает вопрос – а почему слэйв не может применять их параллельно? На самом деле, с этим все непросто. Есть теорема о сериализации транзакций, которая рассказывает, когда мы можем выполнять запросы параллельно, а когда последовательно. Это отдельная сложная тема, разберитесь в ней, если вам интересно и нужно, например, почитав по ссылке – [http://plumqqz.livejournal.com/387380.html](http://plumqqz.livejournal.com/387380.html). +- В MySQL репликация упирается в процессор. Это прекрасная картинка – большой, мощный сервер, 12 ядер. Работает одно ядро, заодно занято репликацией. Из-за этого реплика задыхается. Это очень грустно. + +Для того чтобы выполнять запросы параллельно существует группировка запросов. В InnoDB есть специальная опция, которая управляет тем, как именно мы группируем транзакции, как именно мы их пишем на диск. Проблема в том, что мы можем их сгруппировать на уровне InnoDB, а уровнем выше – на уровне репликации – этой функциональности не было. В 2010 г. Кристиан Нельсен из MariaDB реализовал такую фичу, которая называется Group Binary Log Commit. Получается, мы журнал повторяем на двух уровнях – Storage Engine и репликация, и нам нужно таскать фичи из одного уровня на другой. Это сложный механизм. Более того, нам нужно одновременно консистентно писать сразу в два журнала – two-phase-commit. Это еще хуже. + +На следующей картинке мы видим два графика: +![](../../../meta/files/images/Pasted%20image%2020240528090119.png) +Синий график демонстрирует то, как масштабируется InnoDB, когда мы ему добавляем треды. Накидываем треды – число транзакций, которые он обрабатывает, возрастает. Красная линия показывает ситуацию, когда включена репликация. Мы включаем репликацию и теряем масштабируемость. Потому что лог в Binary Log пишется синхронно, и Group Binary Log Commit это решает. + +Грустно, что приходится так делать из-за разделения – Storage Engine внизу, репликация наверху. С этим все плохо. В MySQL 5.6 и 5.7 эта проблема решена – есть Group Binary Log Commit, и мастер теперь не отстает. Теперь это пытаются использовать для параллелизма репликации, чтобы на слэйве запросы из одной группы запустить параллельно. Тут я написал, что из этого нужно крутить: + +![](../../../meta/files/images/Pasted%20image%2020240528090205.png) + +## Параллельная репликация +Сценарий ([Estimating potential for MySQL 5.7 parallel replication](https://www.percona.com/blog/estimating-potential-for-mysql-5-7-parallel-replication/)): +- 1 мастер, 3 слейва +- первый реплицирует в 1 поток +- второй в 20 потоков +- третий в 100 потоков +- вставка в 25 различных таблиц внутри одной базы в 100 потоков + +![](../../../meta/files/images/Pasted%20image%2020240606094633.png) + +Полезные опции: +- sysvar_replica_parallel_workers - количество потоков +- sysvar_replica_parallel_type + - DATABASE - транзакции применяются параллельно, если они обновляют разные БД + - LOGICAL_CLOCK - транзакции применяются параллельно на реплике на основе timestamp +## Отставание реплики +- [Отставание реплики БД](../../architecture/highload/Отставание%20реплики%20БД.md) + +Диагностировать причину отставания реплики тяжело. Есть средство диагностики в MySQL, называется log медленных запросов. Вы можете его открыть, найти топ самых тяжелых запросов и исправить их. Но с репликацией это не работает. Нужно проводить статистический анализ – считать статистику – какие таблицы стали чаще использоваться. Вручную это сделать очень тяжело. + +В MySQL 5.6 / 5.7 появилась SLAVE PERFORMANCE SCHEMA, на базе которой такую диагностику провести проще. Мы обычно открываем лог коммитов в puppet и смотрим, что же мы выкатили в то время, когда репликация начала отставать. Иногда даже это не помогает, приходится ходить по всем разработчикам и спрашивать, что они сделали, они ли сломали репликацию. Это грустно, но с этим приходится жить. +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 MySQL|00 MySQL]] +**Родитель**:: [[../../architecture/highload/Репликация БД|Репликация БД]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-05-28]] +### Дополнительные материалы +- [Как устроена MySQL-репликация / Андрей Аксенов (Sphinx) - YouTube](https://www.youtube.com/watch?v=lHFaZkJk2O0) +- [Асинхронная репликация без цензуры / HighLoad](https://highload.guide/blog/asynchronous-replication.html) +### Дочерние заметки + + +- [[Mixed binlog format]] +- [[Row Based Replication (RBR)]] +- [[Statement Based Replication (SBR)]] + diff --git a/dev/database/postgresql/Autovacuum.md b/dev/database/postgresql/Autovacuum.md new file mode 100644 index 00000000..5e7ef726 --- /dev/null +++ b/dev/database/postgresql/Autovacuum.md @@ -0,0 +1,31 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-11-05 +--- +## Тезисы +- Autovacuum — это автоматический процесс в PostgreSQL, поддерживающий производительность базы данных. +- Основные задачи: предотвращение раздутия таблиц, освобождение неактуальных строк, обновление статистики. +*** +Autovacuum — это встроенный процесс в [[../../../meta/zero/00 PostgreSQL|PostgreSQL]], автоматически выполняющий задачи очистки и обновления данных в базе. Его цель — минимизировать проблему “раздутия” ([[Раздутие таблиц|bloat]]) таблиц, возникающую при удалении или обновлении строк. Когда строка становится неактуальной, она остается в физической структуре таблицы и занимает место, пока Autovacuum не удалит ее, освобождая ресурсы. + +Autovacuum выполняет три ключевые задачи: +1. **Удаление неактуальных строк**: после обновлений и удалений строки не удаляются физически, а остаются, что приводит к избыточному использованию памяти. Autovacuum очищает такие строки. +2. **Обновление статистики**: PostgreSQL использует статистику для оптимизации выполнения запросов. Autovacuum обновляет статистику, что помогает планировщику запросов выбирать оптимальные пути + +Проблемы: +- [[../Долгая транзакция|Долгая транзакция]] +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-05]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/database/postgresql/B-tree индекс в PostgreSQL.md b/dev/database/postgresql/B-tree индекс в PostgreSQL.md new file mode 100644 index 00000000..5db7a5a7 --- /dev/null +++ b/dev/database/postgresql/B-tree индекс в PostgreSQL.md @@ -0,0 +1,38 @@ +--- +aliases: + - B-tree индекс + - B-tree +tags: + - maturity/🌱 +date: 2024-10-23 +--- +B-tree индекс основан на [[../../fundamental/structure/B-tree|B-tree]] дереве. Только в последних узнал добавляются ссылки на строки в таблицах. + +![[../../../meta/files/draw/Структура B-tree индекса в базе данных.excalidraw.png]] +[[../../../meta/files/draw/Структура B-tree индекса.excalidraw|Структура B-tree индекса.excalidraw]] + +**Особенности:** +- Подходит для операций сравнения (`<`, `>`, `BETWEEN`), равенства (`=`) и сортировки. +- Хорошо оптимизирован для большинства операций чтения и поиска. +- Покрывает до 90% задач по индексации в типичных приложениях. +- Не рекомендуется для данных с высокой степенью повторения, так как эффективность индекса в таких случаях может снижаться. + +Пример создания: +```sql +CREATE INDEX idx_name ON table_name (column_name); +``` + +Индекс легко создать, ориентируясь на [[Таблица статистик pg_stats|pg_stats]]. +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]] +**Родитель**:: [[Индекс в PostgreSQL|Индекс в PostgreSQL]] +**Источник**:: +**Создана**:: [[2024-10-23]] +**Автор**:: +### Дополнительные материалы +- [Владимир Ситников — B-tree индексы в базах данных на примере PostgreSQL - YouTube](https://www.youtube.com/watch?v=mnEU2_cwE_s) + +### Дочерние заметки + + diff --git a/dev/database/postgresql/BRIN индекс в PostgreSQL.md b/dev/database/postgresql/BRIN индекс в PostgreSQL.md new file mode 100644 index 00000000..556387ba --- /dev/null +++ b/dev/database/postgresql/BRIN индекс в PostgreSQL.md @@ -0,0 +1,26 @@ +--- +aliases: + - BRIN индекс +tags: + - maturity/🌱 +date: 2024-10-24 +--- +BRIN индекс предназначен для больших таблиц с упорядоченными данными, таких как временные ряды. Это компактный и эффективный индекс для работы с диапазонными запросами. + +Пример создания: +```sql +CREATE INDEX idx_name ON table_name USING brin (column_name); +``` +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]] +**Родитель**:: [[Индекс в PostgreSQL|Индекс в PostgreSQL]] +**Источник**:: +**Создана**:: [[2024-10-24]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/database/postgresql/GIN индекс в PostgreSQL.md b/dev/database/postgresql/GIN индекс в PostgreSQL.md new file mode 100644 index 00000000..c6d4cb8d --- /dev/null +++ b/dev/database/postgresql/GIN индекс в PostgreSQL.md @@ -0,0 +1,34 @@ +--- +aliases: + - GIN индекс +tags: + - maturity/🌱 +date: 2024-10-24 +--- +**Особенности GIN индекса в PostgreSQL:** +- Подходит для ускорения полнотекстового поиска и работы с полями типа `tsvector` или `jsonb`. +- Полезен для поиска по документам и массивам, позволяя быстро находить совпадения по множественным значениям. +- Может ухудшить производительность операций записи, поэтому важно учитывать это при выборе индексации. + +Пример создания: +```sql +CREATE INDEX idx_name ON table_name USING gin (column_name); +``` + +**Оптимизация работы с GIN индексами:** +- При работе с `jsonb` полями доступны два типа операций индексации: + - `jsonb_ops`: Индексирует все ключи и значения, создавая объемный индекс, который подходит для универсального поиска. + - `jsonb_path_ops`: Индексирует пути в JSON, создавая более компактный индекс, подходящий для задач, где необходимо искать по конкретным путям. +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]] +**Родитель**:: [[Индекс в PostgreSQL|Индекс в PostgreSQL]] +**Источник**:: +**Создана**:: [[2024-10-24]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/database/postgresql/Gist индекс в PostgreSQL.md b/dev/database/postgresql/Gist индекс в PostgreSQL.md new file mode 100644 index 00000000..bca5e025 --- /dev/null +++ b/dev/database/postgresql/Gist индекс в PostgreSQL.md @@ -0,0 +1,33 @@ +--- +aliases: + - Gist индекс +tags: + - maturity/🌱 +date: 2024-10-23 +--- +**Особенности GiST индекса в PostgreSQL:** +- Используется для индексации сложных данных, таких как геометрия и гео-данные. +- Подходит для задач, связанных с пространственными запросами, например, для поиска ближайшей гео-точки. +- Гибкий механизм, позволяющий расширять функциональность индексации за счет различных расширений, таких как `pg_trgm` и `btree_gist`. + +**Пример создания** +```sql +CREATE INDEX idx_name ON table_name USING gist (column_name); +``` + +**Поддерживаемые расширения для GiST индекса:** +- `pg_trgm`: Поддерживает операции `LIKE`, `ILIKE`, `~`, `~*` (регулярные выражения), что делает его полезным для быстрого полнотекстового поиска. +- `btree_gist`: Добавляет поддержку B-tree в GiST и позволяет делать сложные ограничения (constraints) с интервалами, например, контроль пересечения времени для создания расписания. +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]] +**Родитель**:: [[Индекс в PostgreSQL]] +**Источник**:: +**Создана**:: [[2024-10-23]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/database/postgresql/Hash индекс в PostgreSQL.md b/dev/database/postgresql/Hash индекс в PostgreSQL.md new file mode 100644 index 00000000..e3b04bf0 --- /dev/null +++ b/dev/database/postgresql/Hash индекс в PostgreSQL.md @@ -0,0 +1,30 @@ +--- +aliases: + - Hash индекс +tags: + - maturity/🌱 +date: 2024-10-23 +--- +**Особенности:** +- Подходит для операций равенства (`=`), но **не поддерживает сортировку** и операции диапазона (`<`, `>`, `BETWEEN`). +- Занимает меньше места на диске по сравнению с [[B-tree индекс в PostgreSQL|B-tree]]. + +**Пример создания:** +```sql +CREATE INDEX idx_name ON table_name USING hash (column_name); +``` + +Хэш-индексы могут быть полезны для ускорения поиска по колонкам с бинарными значениями или другими типами данных, где часто используются точные совпадения. +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]] +**Родитель**:: [[Индекс в PostgreSQL]] +**Источник**:: +**Создана**:: [[2024-10-23]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/database/postgresql/SP-GiST индекс в PostgreSQL.md b/dev/database/postgresql/SP-GiST индекс в PostgreSQL.md new file mode 100644 index 00000000..48b60c19 --- /dev/null +++ b/dev/database/postgresql/SP-GiST индекс в PostgreSQL.md @@ -0,0 +1,24 @@ +--- +aliases: + - SP-GiST индекс +tags: + - maturity/🌱 +date: 2024-10-24 +--- +**Особенности SP-GiST индекса в PostgreSQL:** +- Подходит для специфических структур данных, таких как разреженные данные, вложенные множества или данные с неравномерным распределением. +- Обычно не используется в приложениях типа [[../Online Transaction Processing|OLTP]], так как его преимущества не очевидны для типичных транзакционных нагрузок. +- Может быть полезен в научных или аналитических приложениях, где требуется работа с разреженными или геометрическими данными. +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]] +**Родитель**:: [[Индекс в PostgreSQL]] +**Источник**:: +**Создана**:: [[2024-10-24]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/database/postgresql/Write-Ahead Log.md b/dev/database/postgresql/Write-Ahead Log.md new file mode 100644 index 00000000..6e10733e --- /dev/null +++ b/dev/database/postgresql/Write-Ahead Log.md @@ -0,0 +1,31 @@ +--- +aliases: + - WAL + - Журнал в PostgreSQL +tags: + - maturity/🌱 +date: + - - 2024-05-26 +zero-link: + - "[[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]]" +parents: + - "[[../Журнал БД|Журнал БД]]" +linked: + - "[[Репликация в PostgreSQL]]" +--- +В журнал попадают физические изменения, т.е. обновления страничек. Есть [[../DB page|страница]] в памяти, на ней лежат какие-то данные, мы с ней что-то сделали – вот эту разницу мы записываем в журнал. + +В WAL попадает всё: обновление таблиц, создание триггеров, создание хранимых процедур и так далее. + +![](Pasted%20image%2020240531083602.png) +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]] +**Родитель**:: [[../Журнал БД|Журнал БД]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-05-26]] +### Дополнительные материалы +- [[Репликация в PostgreSQL]] +### Дочерние заметки + diff --git a/dev/database/postgresql/pageinspect.md b/dev/database/postgresql/pageinspect.md new file mode 100644 index 00000000..c173ec3f --- /dev/null +++ b/dev/database/postgresql/pageinspect.md @@ -0,0 +1,54 @@ +--- +aliases: + - pageinspect +tags: + - maturity/🌱 +date: 2024-10-21 +--- +Установка расширения +```sql +create extension pageinspect +``` +## Анализ индексов +Расширение pageinspect позволяет изучить структуру индекса (размер страницы, количество страниц и так далее). + +![](../../../meta/files/images/Pasted%20image%2020240610084449.png) + +Проверить какие индексы существуют для таблицы: +```sql +select * from pg_indexes where tablename='table_name'; +``` + +Посмотреть сколько раз индекс использовался и когда был последний вызов. +```sql +select * from pg_stat_user_indexes +``` + +Посмотреть размер индекса +```sql +select pg_size_pretty(pg_indexes_size('orders')) +``` + +Можно получить мета информацию о дереве индекса: +```sql +select * from bt_metap('users_pkey'); +``` + +Можно получить мета информацию о конкретном узле: +```sql +select * from bt_page_stats('users_pkey', 3); +``` + +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]] +**Родитель**:: [[Оптимизация SQL запросов в PostgreSQL]] +**Источник**:: +**Создана**:: [[2024-10-21]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/database/postgresql/pg_stat_statements.md b/dev/database/postgresql/pg_stat_statements.md new file mode 100644 index 00000000..97b9d7fb --- /dev/null +++ b/dev/database/postgresql/pg_stat_statements.md @@ -0,0 +1,18 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-06-17 +--- +Собирает всю статистику по запросам. Позволят получить агрегированный отчет по SQL запросу: минимальное время выполнения, максимальное, среднее. Но все запросы обезличенные - не содержат значения параметров. +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]] +**Родитель**:: [[Оптимизация SQL запросов в PostgreSQL|Оптимизация SQL запросов в PostgreSQL]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-06-17]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/database/postgresql/pg_utils.md b/dev/database/postgresql/pg_utils.md new file mode 100644 index 00000000..8bf0ff77 --- /dev/null +++ b/dev/database/postgresql/pg_utils.md @@ -0,0 +1,15 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-07-24 +zero-link: [] +parents: +linked: +--- +- [GitHub - dataegret/pg-utils: Useful PostgreSQL utilities](https://github.com/dataegret/pg-utils) + +- global_reports +- `top_tables.sql` - покажет размер таблиц и размер индексов на них. Нужно обратить внимания на таблицы, размер индексов которых приближается к размеру таблицы или больше его. +- `indexes_with_nulls.sql` - позволяет найти индексы, которые содержат множество null значений. Их можно пересоздать в виде [[../Частичный индекс|частичных индексов]]. +- `low_used_indexes.sql` - показывает индексы по которым мало чтения. \ No newline at end of file diff --git a/dev/database/postgresql/Индекс в PostgreSQL.md b/dev/database/postgresql/Индекс в PostgreSQL.md new file mode 100644 index 00000000..45e6aad2 --- /dev/null +++ b/dev/database/postgresql/Индекс в PostgreSQL.md @@ -0,0 +1,53 @@ +--- +aliases: [] +tags: + - maturity/🌱 +date: 2024-03-31 +--- +[[../../../meta/zero/00 PostgreSQL|PostgreSQL]] поддерживает несколько типов [[../Индекс базы данных|индексов]], каждый из которых предназначен для определённых задач. Выбор типа индекса зависит от структуры данных и характера запросов. В этом разделе приведены основные типы индексов, их особенности и случаи, когда их использование наиболее эффективно. + +**Особенности:** +- Для **первичного ключа** индекс создается автоматически. +- Можно **отключить автоматическое обновление индекса** и настроить обновление вручную. +- **Распухание индексов** ([[Раздутие таблиц|bloat]]) — это проблема увеличения размера индексов со временем, требующая переиндексации. + +- [[Создание индекса в PostgreSQL]] +- [[../Частичный индекс|Частичный индекс]] +- [[Составной индекс в PostgreSQL]] + +**Типы индексов:** +- [[B-tree индекс в PostgreSQL|B-tree индекс]] +- [[Hash индекс в PostgreSQL|Hash индекс]] +- [[Gist индекс в PostgreSQL|Gist индекс]] +- [[SP-GiST индекс в PostgreSQL|SP-GiST индекс]] +- [[GIN индекс в PostgreSQL|GIN индекс]] +- [[BRIN индекс в PostgreSQL|BRIN индекс]] + +**Влияние обновления строки на индекс** +- **Обновление индексированной колонки.** По факту мы добавляем новую запись в индекс, а старую забываем. Старая остается мертвым грузом ([[Раздутие таблиц|bloat]]), индекс распухает, его нужно убрать - [[Autovacuum]]. +- **Обновление не индексированной колонки.** Если строка в таблице остается на той же [[../DB page|странице бд]], то есть было место на странице, то индекс не меняется. Если строка не помещается, то добавляется новая запись в индекс, а старая остается мертвым грузом ([[Раздутие таблиц|bloat]]), индекс распухает, его нужно убрать vacuum. +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]] +**Родитель**:: [[../Индекс базы данных|Индекс базы данных]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-03-31]] +### Дополнительные материалы +- [Доклад. Индексы в PostgreSQL. Как понять, что создавать](../../../source/lecture/Доклад.%20Индексы%20в%20PostgreSQL.%20Как%20понять,%20что%20создавать.md) +- [009. B-деревья. Система непересекающихся множеств - М. А. Бабенко - YouTube](https://www.youtube.com/watch?v=KFcpDTpoixo) +- [Индексы в PostgreSQL — 1 / Хабр](https://habr.com/ru/companies/postgrespro/articles/326096/) +- [Introduction of B+ Tree - GeeksforGeeks](https://www.geeksforgeeks.org/introduction-of-b-tree/) +### Дочерние заметки + + +- [[B-tree индекс в PostgreSQL]] +- [[BRIN индекс в PostgreSQL]] +- [[GIN индекс в PostgreSQL]] +- [[Gist индекс в PostgreSQL]] +- [[Hash индекс в PostgreSQL]] +- [[SP-GiST индекс в PostgreSQL]] +- [[Создание индекса в PostgreSQL]] +- [[Составной индекс в PostgreSQL]] +- [[Частичный индекс]] + diff --git a/dev/database/postgresql/Настройка репликации в PostgreSQL.md b/dev/database/postgresql/Настройка репликации в PostgreSQL.md new file mode 100644 index 00000000..ae129b68 --- /dev/null +++ b/dev/database/postgresql/Настройка репликации в PostgreSQL.md @@ -0,0 +1,386 @@ +--- +aliases: +tags: + - maturity/🌱 +date: + - - 2024-06-17 +zero-link: + - "[[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]]" +parents: + - "[[Репликация в PostgreSQL|Репликация в PostgreSQL]]" +linked: +--- +## Физическая репликация +Создаем сеть, запоминаем адрес +```shell +docker network create pgnet +docker network inspect pgnet | grep Subnet # Запомнить маску сети +``` + +Поднимаем мастер +```shell +docker run -dit -v "$PWD/volumes/pgmaster/:/var/lib/postgresql/data" -e POSTGRES_PASSWORD=pass -p "5432:5432" --restart=unless-stopped --network=pgnet --name=pgmaster postgres +``` + +Меняем postgresql.conf на мастере +```conf +ssl = off +wal_level = replica +max_wal_senders = 4 # expected slave num +``` + +Подключаемся к мастеру и создаем пользователя для репликации +```shell +docker exec -it pgmaster su - postgres -c psql +create role replicator with login replication password 'pass'; +exit +``` + +Добавляем запись в `pgmaster/pg_hba.conf` с `subnet` с первого шага +``` +host replication replicator __SUBNET__ md5 +``` + +Перезапустим мастер +```shell +docker restart pgmaster +``` + +Сделаем бэкап для реплик +```shell +docker exec -it pgmaster bash +mkdir /pgslave +pg_basebackup -h pgmaster -D /pgslave -U replicator -v -P --wal-method=stream +exit +``` + +Копируем директорию себе +```shell +docker cp pgmaster:/pgslave volumes/pgslave/ +``` + +Создадим файл, чтобы реплика узнала, что она реплика +```shell +touch volumes/pgslave/standby.signal +``` + +Меняем `postgresql.conf` на реплике `pgslave` +```conf +primary_conninfo = 'host=pgmaster port=5432 user=replicator password=pass application_name=pgslave' +``` + +Запускаем реплику `pgslave` +```shell +docker run -dit -v "$PWD/volumes/pgslave/:/var/lib/postgresql/data" -e POSTGRES_PASSWORD=pass -p "15432:5432" --network=pgnet --restart=unless-stopped --name=pgslave postgres +``` + +Запустим вторую реплику `pgasyncslave` + +Скопируем бэкап +```shell +docker cp pgmaster:/pgslave volumes/pgasyncslave/ +``` + +Изменим настройки `pgasyncslave/postgresql.conf` +```conf +primary_conninfo = 'host=pgmaster port=5432 user=replicator password=pass application_name=pgasyncslave' +``` + +Дадим знать что это реплика +```shell +touch volumes/pgasyncslave/standby.signal + ``` + +Запустим реплику `pgasyncslave` +```shell +docker run -dit -v "$PWD/volumes/pgasyncslave/:/var/lib/postgresql/data" -e POSTGRES_PASSWORD=pass -p "25432:5432" --network=pgnet --restart=unless-stopped --name=pgasyncslave postgres + ``` + +Убеждаемся что обе реплики работают в асинхронном режиме на `pgmaster` +```shell +docker exec -it pgmaster su - postgres -c psql +select application_name, sync_state from pg_stat_replication; +exit; + ``` + +Включаем синхронную репликацию на `pgmaster` + +Меняем файл `pgmaster/postgresql.conf` +```conf +synchronous_commit = on +synchronous_standby_names = 'FIRST 1 (pgslave, pgasyncslave)' +``` + +Перечитываем конфиг +```shell +docker exec -it pgmaster su - postgres -c psql +select pg_reload_conf(); +exit; +``` + +Убеждаемся, что реплика стала синхронной +```shell +docker exec -it pgmaster su - postgres -c psql +select application_name, sync_state from pg_stat_replication; +exit; +``` + +Создадим тестовую таблицу на `pgmaster` и проверим репликацию +```shell +docker exec -it pgmaster su - postgres -c psql +create table test(id bigint primary key not null); +insert into test(id) values(1); +select * from test; +exit; +``` + +Проверим наличие данных на `pgslave` +```shell +docker exec -it pgslave su - postgres -c psql +select * from test; +exit; +``` + +Проверим наличие данных на `pgasyncslave` +```shell +docker exec -it pgasyncslave su - postgres -c psql +select * from test; +exit; +``` + +Попробуем сделать `insert` на `pgslave` +```shell +docker exec -it pgslave su - postgres -c psql +insert into test(id) values(2); +exit; + ``` + +Укладываем репилку `pgasyncslave` и проверяем работу `pgmaster` и `pgslave` +```shell +docker stop pgasyncslave +docker exec -it pgmaster su - postgres -c psql +select application_name, sync_state from pg_stat_replication; +insert into test(id) values(2); +select * from test; +exit; +docker exec -it pgslave su - postgres -c psql +select * from test; +exit; + ``` + +Укладываем репилку `pgslave` и проверяем работу `pgmaster`, а потом возвращаем реплику `pgslave` + +terminal 1 +```shell +docker stop pgslave +docker exec -it pgmaster su - postgres -c psql +select application_name, sync_state from pg_stat_replication; +insert into test(id) values(3); +exit; +``` + +terminal 2 +```shell +docker start pgslave +``` + +Возвращаем вторую реплику `pgasyncslave` +```shell +docker start pgasyncslave +``` + +Убиваем мастер `pgmaster` +```shell +docker stop pgmaster +``` + +Запромоутим реплику `pgslave` +```shell +docker exec -it pgslave su - postgres -c psql +select pg_promote(); +exit; +``` + +Пробуем записать в новый мастер `pgslave` +```shell +docker exec -it pgslave su - postgres -c psql +insert into test(id) values(4); +exit; +``` + +Настраиваем репликацию на `pgslave` (`pgslave/postgresql.conf`) + +изменяем конфиг +```conf +synchronous_commit = on +synchronous_standby_names = 'ANY 1 (pgmaster, pgasyncslave)' +``` + +перечитываем конфиг +```shell +docker exec -it pgslave su - postgres -c psql +select pg_reload_conf(); +exit; +``` + +Подключим вторую реплику `pgasyncslave` к новому мастеру `pgslave` + +изменяем конфиг `pgasyncslave/postgresql.conf` +```conf +primary_conninfo = 'host=pgslave port=5432 user=replicator password=pass application_name=pgasyncslave' +``` + +перечитываем конфиг +```shell +docker exec -it pgasyncslave su - postgres -c psql +select pg_reload_conf(); +exit; +``` + +Проверяем что к новому мастеру `pgslave` подключена реплика и она работает +```shell +docker exec -it pgslave su - postgres -c psql +select application_name, sync_state from pg_stat_replication; +insert into test(id) values (5) +select * from test; +exit; +docker exec -it pgasyncslave su - postgres -c psql +select * from test; +exit; +``` + +Восстановим старый мастер `pgmaster` как реплику + +Помечаем как реплику +```shell +touch volumes/pgmaster/standby.signal +``` + +Изменяем конфиг `pgmaster/postgresql.conf` +```conf +primary_conninfo = 'host=pgslave port=5432 user=replicator password=pass application_name=pgmaster' +``` + +Запустим `pgmaster` +```shell +docker start pgmaster +``` + +Убедимся что `pgmaster` подключился как реплика к `pgslave` +```shell +docker exec -it pgslave su - postgres -c psql +select application_name, sync_state from pg_stat_replication; +exit; +``` + +## Логическая репликация +Меняем `wal_level` для текущего мастера `pgslave` + +Изменяем настройки `pgslave/postgresql.conf` +```conf +wal_level = logical +``` + +Перезапускаем `pgslave` +```shell +docker restart pgslave +``` + +Создадим публикацию в `pgslave` +```shell +docker exec -it pgslave su - postgres -c psql +GRANT CONNECT ON DATABASE postgres TO replicator; +GRANT SELECT ON ALL TABLES IN SCHEMA public TO replicator; +create publication pg_pub for table test; +exit; +``` + +Создадим новый сервер `pgstandalone` для логической репликации +```shell +docker run -dit -v "$PWD/volumes/pgstandalone/:/var/lib/postgresql/data" -e POSTGRES_PASSWORD=pass -p "35432:5432" --restart=unless-stopped --network=pgnet --name=pgstandalone postgres +``` + +Копируем файлы c `pgslave` в `pgstandalone` и восстанавливаем +```shell +docker exec -it pgslave su - postgres +pg_dumpall -U postgres -r -h pgslave -f /var/lib/postgresql/roles.dmp +pg_dump -U postgres -Fc -h pgslave -f /var/lib/postgresql/schema.dmp -s postgres +exit; + +docker cp pgslave:/var/lib/postgresql/roles.dmp . +docker cp roles.dmp pgstandalone:/var/lib/postgresql/roles.dmp +docker cp pgslave:/var/lib/postgresql/schema.dmp . +docker cp schema.dmp pgstandalone:/var/lib/postgresql/schema.dmp + +docker exec -it pgstandalone su - postgres +psql -f roles.dmp +pg_restore -d postgres -C schema.dmp +exit +``` + +Создаем подписку на `pgstandalone` +```shell +docker exec -it pgstandalone su - postgres -c psql +CREATE SUBSCRIPTION pg_sub CONNECTION 'host=pgslave port=5432 user=replicator password=pass dbname=postgres' PUBLICATION pg_pub; +exit; +``` + +Убеждаемся что репликация запущена +```shell +docker exec -it pgstandalone su - postgres -c psql +select * from test; +exit; +``` + +Сделаем конфликт в данных + +Вставляем данные в подписчике `pgstandalone` +```shell +docker exec -it pgstandalone su - postgres -c psql +insert into test values(9); +exit; +``` + +Вставляем данные в паблишере `pgslave` +```shell +docker exec -it pgslave su - postgres -c psql +insert into test values(9); +insert into test values(10); +exit; +``` + +Убеждаемся что записи с id 10 не появилось на `pgstandalone` +```shell +docker exec -it pgstandalone su - postgres -c psql +select * from test; +exit; +``` + +Посмотрим в логи `pgstandalone` и убедимся что у нас произошел разрыв репликации +```shell +docker logs pgstandalone + +2023-03-27 16:15:02.753 UTC [258] ERROR: duplicate key value violates unique constraint "test_pkey" +2023-03-27 16:15:02.753 UTC [258] DETAIL: Key (id)=(9) already exists. +2023-03-28 18:30:42.893 UTC [108] CONTEXT: processing remote data for replication origin "pg_16395" during message type "INSERT" for replication target relation "public.test" in transaction 739, finished at 0/3026450 +``` + +Исправляем конфликт +```shell +docker exec -it pgstandalone su - postgres -c psql +SELECT pg_replication_origin_advance('pg_16395', '0/3026451'::pg_lsn); # message from log + 1 +ALTER SUBSCRIPTION pg_sub ENABLE; +select * from test; +exit; +``` +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]] +**Родитель**:: [[Репликация в PostgreSQL|Репликация в PostgreSQL]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-06-17]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/database/postgresql/Оптимизация SQL запросов в PostgreSQL.md b/dev/database/postgresql/Оптимизация SQL запросов в PostgreSQL.md new file mode 100644 index 00000000..55e34436 --- /dev/null +++ b/dev/database/postgresql/Оптимизация SQL запросов в PostgreSQL.md @@ -0,0 +1,59 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-06-17 +--- +- [[../Оптимизация SQL запросов|Оптимизация SQL запросов]] + +**Алгоритм оптимизации запросов:** +- **Проверка настроек** + - **Оборудование сервера БД**: убедитесь, что сервер имеет достаточную вычислительную мощность и оперативную память для обработки текущей нагрузки. Слабое оборудование может существенно снизить производительность. + - **Проблемы с сетью**: задержка в сети или потеря пакетов могут замедлять передачу данных между клиентом и сервером. Убедитесь в стабильности соединения. + - **Настройки базы данных**: + - Если у вас много соединений, используйте [[PgBouncer]], чтобы разгрузить управление соединениями. + - Проверьте, что [[autovacuum]] включен и настроен, чтобы избежать накопления "мусорных" строк, которые могут замедлить работу БД. +- Анализ и выбор [[../Плохой SQL запрос|проблемных запросов]] + - Оптимизировать все запросы подряд неэффективно. Начните с самых проблемных, чтобы добиться наибольшего улучшения. + - **Анализ проводите только на продуктовой БД**, так как тестовые среды могут не отражать реальную нагрузку. + - **Инструменты для анализа**: + - [pg_utils](pg_utils.md): утилиты для анализа производительности PostgreSQL. + - [[pg_stat_statements]]: расширение для сбора статистики выполнения запросов, помогает находить медленные запросы. + - [[Таблица статистик pg_stats|pg_stats]]: помогает определить, какие индексы стоит добавить или изменить. + - [[pageinspect]]: дает доступ к структуре страниц таблиц и индексов для глубокого анализа. +- **Оптимизация запросов**. Используйте [[Профилирование запросов в PostgreSQL|профилирование запросов в PostgreSQL]] для определения узких мест и точек, требующих оптимизации. +- **Изучение результатов оптимизации**. Проверьте улучшение производительности с помощью инструментов анализа, чтобы убедиться, что изменения действительно дают эффект. +- **Повторение анализа**. Оптимизация — это итеративный процесс. После улучшения одного запроса снова проанализируйте производительность системы и ищите новые узкие места. + +**Конфигурационные параметры PostgreSQL** +- `work_mem`: увеличьте значение, если запросы требуют больших сортировок или операций с временными таблицами. +- `shared_buffers`: настройка этого параметра позволяет эффективно кэшировать данные в памяти и снижать количество обращений к диску. +- `maintenance_work_mem`: используйте для настройки памяти, выделяемой для операций обслуживания, таких как `VACUUM` и создание индексов. + +![Почему JOIN работает медленно?](JOIN%20SQL.md#Почему%20JOIN%20работает%20медленно?) + +![Проблемы производительности IN](IN%20SQL.md#Проблемы%20производительности%20IN) + +PostgreSQL хранит статистику по выполнениям запросов в таблице `pg_stat_user_tables`. С её помощью можно оценить какие операции PostgreSQL выполняет чаще всего. + +```sql +select relname, seq_scan, idx_scan, vacuum_count from pg_stat_user_tables +``` +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]] +**Родитель**:: [[../Оптимизация SQL запросов|Оптимизация SQL запросов]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-06-17]] +### Дополнительные материалы +- [Производительность запросов в PostgreSQL / Илья Космодемьянский (PostgreSQL Consulting) - YouTube](https://www.youtube.com/watch?v=c-ySk8COI1c) +### Дочерние заметки + + +- [[pageinspect]] +- [[pg_stat_statements]] +- [[Профилирование запросов в PostgreSQL]] +- [[Таблица статистик pg_stats]] +- [[Частичный индекс]] + diff --git a/dev/database/postgresql/Профилирование запросов в PostgreSQL.md b/dev/database/postgresql/Профилирование запросов в PostgreSQL.md new file mode 100644 index 00000000..d7fc9795 --- /dev/null +++ b/dev/database/postgresql/Профилирование запросов в PostgreSQL.md @@ -0,0 +1,56 @@ +--- +aliases: + - explain +tags: + - maturity/🌱 +date: 2024-06-10 +--- +Ключевое слово `EXPLAIN` перед SQL-запросом позволяет получить детальную информацию о том, как PostgreSQL **планирует** выполнить этот запрос "под капотом". Это полезно для диагностики производительности, поскольку помогает понять, какие шаги выполняет база данных и где могут быть узкие места. + +Пример использования `EXPLAIN` +```sql +postgres=# EXPLAIN SELECT * FROM users WHERE id = 20; + +QUERY PLAN +------------------------------------------------------- +Index Scan using users_pkey on users (cost=0.15..8.17 rows=1 width=72) + Index Cond: (id = 20) +(2 rows) +``` + +Вывод информации можно изменить. Например, чтобы получить результат в формате JSON: +```sql +EXPLAIN (FORMAT JSON) SELECT * FROM users WHERE id = 20; +``` + +> [!NOTE] Analyze +> `EXPLAIN` не выполняет сам запрос, поэтому результаты будут приблизительными. Для более точного анализа можно добавить ключевое слово `ANALYZE`, и тогда `EXPLAIN` также выполнит запрос. +## Стоимость выполнения запроса (cost) +PostgreSQL использует условные единицы для обозначения стоимости выполнения запроса — `cost`. Один `cost` примерно соответствует времени, затраченному на извлечение одной [[../DB page|страницы]] при последовательном сканировании (Seq Scan). + +Часто используются два значения `cost`: +- **Первое значение**: стоимость до начала получения первых результатов. +- **Второе значение**: полная стоимость выполнения запроса. + +Если оценочное значение `rows` слишком низкое по сравнению с фактическим количеством строк, это может означать, что статистика таблицы устарела. В таком случае необходимо выполнить `ANALYZE` для обновления статистики и улучшения качества планирования запросов. + +Также PostgreSQL умеет считать количество обращений к диску. Для этого нужно добавить опцию `buffres`: `explain (analize, buffres)`. Это не время на чтение, а количества чтений. +## Виды проходов по таблице и индексу +- **Seq Scan**: последовательный просмотр всей таблицы. Это наиболее медленный вариант и обычно нежелателен. Решение — добавить [[../Индекс базы данных|индекс]], чтобы ускорить выборку данных. +- **Index Scan**: использование [[../Индекс базы данных|индекса]] для просмотра таблицы. +- **Index Only Scan**: использование [[../Покрывающий индекс|покрывающего индекса]], когда все нужные данные находятся в индексе и не требуется дополнительного доступа к таблице. +- **Bitmap Heap Scan**: оптимизация с использованием битовых карт для поиска. Сначала строятся битовые карты с использованием нескольких индексов, затем они комбинируются. +- **Foreign Scan**: сканирование данных на удаленном сервере, используемое при [[Шардирование в PostgreSQL|шардировании]]. + +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]] +**Родитель**:: [[Оптимизация SQL запросов в PostgreSQL]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-01-29]] +### Дополнительные материалы +- +### Дочерние заметки + + diff --git a/dev/database/postgresql/Раздутие таблиц.md b/dev/database/postgresql/Раздутие таблиц.md new file mode 100644 index 00000000..66217842 --- /dev/null +++ b/dev/database/postgresql/Раздутие таблиц.md @@ -0,0 +1,44 @@ +--- +aliases: + - bloat +tags: + - maturity/🌱 +date: 2024-11-05 +--- +## Тезисы +- “Раздутие” (bloat) — это проблема неиспользуемого, но занятого пространства в таблицах базы данных. +- Основные причины: удаление и обновление строк, которые оставляют физическое пространство занятым. +- Проблема приводит к увеличению объема базы, снижению производительности и повышению требований к ресурсам. +- Для борьбы с bloat применяют Autovacuum, ручной Vacuum и вакуумирование с полной переорганизацией (VACUUM FULL). +*** +“Раздутие” (bloat) таблиц — это накопление неиспользуемого, но занятого пространства в структуре таблиц базы данных. Такая ситуация возникает, когда строки удаляются или обновляются. + +![[Таблица в PostgreSQL#^71df9c]] + + +**Основные причины раздутия**: +1. **Удаление строк**: При удалении строки данные физически остаются в таблице, занимая место. +2. **Обновление строк**: PostgreSQL создает новую версию строки для обновленных данных, сохраняя старую версию для обеспечения транзакционной целостности, что также добавляет лишние данные. + +**Последствия раздутия**: +- **Рост объема данных**: Таблицы и индексы могут существенно увеличиваться в объеме, требуя больше места на диске. +- **Снижение производительности**: Чем больше размер таблицы, тем медленнее будут выполняться запросы. Это связано с тем, что сервер вынужден обрабатывать неактуальные данные. +- **Увеличение использования ресурсов**: Дополнительные данные влияют на объем памяти и нагрузку на процессор, что может замедлить систему. + +**Методы борьбы с bloat**: +1. **Autovacuum**: В PostgreSQL есть автоматический процесс [[Autovacuum]], который регулярно удаляет неактуальные строки, чтобы уменьшить bloat. Однако его настройка требует внимания, так как высокая частота работы Autovacuum может создавать нагрузку на производительность, а слишком редкая настройка может не справляться с накоплением пустот. +2. **Ручной VACUUM**: В случае значительного bloat можно запускать команду `VACUUM` вручную, чтобы освободить неиспользуемое пространство. Такой подход полезен для интенсивных таблиц, где Autovacuum не всегда справляется. +3. **VACUUM FULL**: Для полного устранения bloat иногда требуется вакуумирование с полной переорганизацией, то есть VACUUM FULL. Эта операция пересоздает таблицу, удаляя все неиспользуемое пространство, но требует блокировки таблицы на время выполнения, что может прерывать работу пользователей. +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-05]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/database/postgresql/Репликация в PostgreSQL.md b/dev/database/postgresql/Репликация в PostgreSQL.md new file mode 100644 index 00000000..0ba46c61 --- /dev/null +++ b/dev/database/postgresql/Репликация в PostgreSQL.md @@ -0,0 +1,70 @@ +--- +aliases: +tags: + - maturity/🌱 +date: + - - 2024-05-28 +zero-link: + - "[[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]]" +parents: + - "[[../../architecture/highload/Репликация БД|Репликация БД]]" +linked: +--- +## Тезисы +- Реализуется на базе журнала [WAL](Write-Ahead%20Log.md). +- Репликация упирается в диск, а не в процессор. +- Реплика это точная бинарная копия мастера. +- Работает по push модели +- При физической репликации фильтрация не возможна +*** +Распространение изменений в PostgreSQL происходит по push модели. То есть, master отправляет [[Write-Ahead Log|WAL]] на реплики, а реплика применяет данные физически, согласно записям в WAL. Таким образом, если остановить запись в master, дождаться синхронизации реплик и сделать бинарное сравнение master и slaves, они будут идентичны. + +![](../../../meta/files/images/Pasted%20image%2020240606094952.png) + +Производительность репликации в PostgreSQL обычно ограничена производительностью дисков, а не процессора. Поэтому при использовании HDD рекомендуется выделять отдельный диск для WAL. + +Добавление реплики требует остановки работы приложения, чтобы никакие записи не менялись в БД. Хотя, если данные пишутся не так часто, то новая реплика может просто догнать отставание в мастер, которое образуется за время подключения слейва. + + +## Синхронизация +Async: +- synchronus_commit = + - off - не будет дожидаться даже локального подтверждения, нет гарантии что данные дошли до бд + - local - происходит локальный коммит и в этот же момент отправляется подтверждение + +Sync/Semi-symc: +- synchronus_commit = remote_write \/ on \/ remote_apply + - remote_write - транзакция подтверждается только если получено подтверждение со всех реплик +- synchronus_standby_names = \[FIRST \/ ANY\] N (replicas_list) + - позволяет настроить от скольких реплик ожидается ответ +## Логическая репликация +Логическая репликация позволяет более гибко управлять копированием данных. Она предоставляет возможность реплицировать отдельные таблицы или схемы, а не всю базу данных целиком. Это особенно полезно для частичного копирования данных и интеграции с другими системами. + +Logical Log Streaming Replication – это способ трансформировать Write-Ahead Log. Например, мы не хотим реплицировать все таблицы из данной базы, а хотим реплицировать только часть. Logical Log Streaming Replication позволяет мастеру объяснить, что из таблиц будет уезжать на слэйв. + +Logical Decoding – способ визуализировать то, что находится в PostgreSQL Write-Ahead Log. На самом деле, если мы можем напечатать в каком-то виде то, что у нас происходит на слэйве, точнее, что нам пришло через Write-Ahead Log, это значит, что мы можем программно реализовать все то, что делает libslave. Получили insert, update, delete, у нас “дернулся” нужный callback, мы узнали про изменения. Это и есть Logical Decoding. + +![](Pasted%20image%2020240606100439.png) + +**Конфликты:** +- Нужно идентифицировать запись для update/delete (по первичному ключу/по уникальному ненуллабельному индексу/по всем столбцам). +- В случае возникновения конфликта требуется вручную исправить данные. +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]] +**Родитель**:: [[../../architecture/highload/Репликация БД|Репликация БД]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-05-28]] +### Дополнительные материалы +- [[Настройка репликации в PostgreSQL]] +- [BDR User Guide - PostgreSQL wiki](https://wiki.postgresql.org/wiki/Logical_Log_Streaming_Replication) +- [PostgreSQL: Documentation: 16: Chapter 31. Logical Replication](https://www.postgresql.org/docs/current/logical-replication.html) +- [PostgreSQL: Documentation: 9.4: Logical Decoding](https://www.postgresql.org/docs/9.4/logicaldecoding.html). Аналог [libslave](libslave.md) в MySQL +- [Отладка и устранение проблем в PostgreSQL Streaming Replication / Хабр](https://m.habr.com/ru/company/oleg-bunin/blog/414111/) +- [An Overview of Logical Replication in PostgreSQL | Severalnines](https://severalnines.com/blog/overview-logical-replication-postgresql/) +### Дочерние заметки + + +- [[Настройка репликации в PostgreSQL]] + diff --git a/dev/database/postgresql/Создание индекса в PostgreSQL.md b/dev/database/postgresql/Создание индекса в PostgreSQL.md new file mode 100644 index 00000000..5341b4b9 --- /dev/null +++ b/dev/database/postgresql/Создание индекса в PostgreSQL.md @@ -0,0 +1,34 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-10-21 +--- +[PostgreSQL: Documentation: 16: CREATE INDEX](https://www.postgresql.org/docs/current/sql-createindex.html): рекомендуется ознакомиться с официальной документацией для более глубокого понимания команды `CREATE INDEX` и всех доступных опций. + +**Что нужно для создания индекса?** +- **Соберите статистику нагрузки на БД**. **Работайте только с продуктовым окружением**: тестовые окружения не всегда отражают реальность. + - Используйте [[pg_stat_statements|pg_stat_statements]] для анализа запросов. + - Анализируйте [[Таблица статистик pg_stats|pg_stats]]: важно понимать, как планировщик БД строит план выполнения запроса. + - Инструмент pgBadge можно применять с осторожностью, так как он собирает данные из логов, в которые попадают не все запросы. +- **Примеры запросов с параметрами**: сохраняйте примеры для проверки оптимизаций. +- **Сбор дополнительной статистики**: при необходимости вручную собирайте более полные данные, так как по умолчанию PostgreSQL использует для анализа только 30k строк, что может давать неточную картину. +- **Учитывайте блокировку таблицы**: добавление индекса блокирует таблицу, поэтому это нужно учитывать при планировании операций. +- Используйте [[Профилирование запросов в PostgreSQL|EXPLAIN]]: для анализа статистики распределения данных и проверки эффективности выполнения запросов. + +**Полезные советы:** +- [[../Селективность колонки|Селективность колонки]]: чем выше селективность, тем эффективнее работает индекс. +- **Частичные индексы**: используйте [[../Частичный индекс|частичный индекс]], чтобы уменьшить размер индекса и повысить эффективность. +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]] +**Родитель**:: [[Индекс в PostgreSQL|Индекс в PostgreSQL]] +**Источник**:: +**Создана**:: [[2024-10-21]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/database/postgresql/Составной индекс в PostgreSQL.md b/dev/database/postgresql/Составной индекс в PostgreSQL.md new file mode 100644 index 00000000..f699fdb5 --- /dev/null +++ b/dev/database/postgresql/Составной индекс в PostgreSQL.md @@ -0,0 +1,27 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-03-31 +linked: +--- +[[../Составной индекс в БД|Составные индексы]] в PostgreSQL позволяют ускорить выполнение запросов, в которых используются несколько колонок одновременно. Однако важно учитывать особенности их частичного использования. + +При выполнении запроса составной индекс может использоваться до первого неравенства включительно. Это означает, что при встрече оператора неравенства (`>`, `<`, `>=`, `<=`) индекс перестает быть эффективным для последующих колонок. + +Например, в запросе `a = 0 AND b > 3 AND c > 5` индекс будет использоваться для колонок `a` и `b`, но не для `c`, так как оператор неравенства для `b` ограничивает дальнейшее использование индекса. + +- `a > 0 AND b = 4`: Индекс будет использоваться для всех колонок, несмотря на то, что первая часть — это неравенство. +- `a = 0 AND b > 3 AND c = 3`: Индекс будет использоваться для первых двух колонок. После неравенства индекс уже не применяется. +- `a = 0 AND b > 3 AND c > 3`: Индекс будет использоваться для первой и второй колонки. +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]] +**Родитель**:: [[../Составной индекс в БД|Составной индекс в БД]], [[Индекс в PostgreSQL]] +**Источник**:: +**Автор**:: +**Создана**:: +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/database/postgresql/Таблица в PostgreSQL.md b/dev/database/postgresql/Таблица в PostgreSQL.md new file mode 100644 index 00000000..8abff18f --- /dev/null +++ b/dev/database/postgresql/Таблица в PostgreSQL.md @@ -0,0 +1,26 @@ +--- +aliases: + - таблица + - таблице +tags: + - maturity/🌱 +date: 2024-11-04 +--- +Таблица - это гомогенное множество кортежей. + +Таблица разбивается на [[../DB page|страницы]]. + +В PostgreSQL удаленные или обновленные строки не очищаются немедленно; вместо этого они остаются в таблице до следующей очистки. Это оставляет “пустоты”, которые увеличивают физический объем базы данных, хотя в них уже нет полезной информации. - [[Раздутие таблиц]] ^71df9c +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-04]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/database/postgresql/Таблица статистик pg_stats.md b/dev/database/postgresql/Таблица статистик pg_stats.md new file mode 100644 index 00000000..399577b2 --- /dev/null +++ b/dev/database/postgresql/Таблица статистик pg_stats.md @@ -0,0 +1,38 @@ +--- +aliases: + - pg_stats +tags: + - maturity/🌱 +date: 2024-03-31 +--- +Для получения статистики по определенной колонке используйте следующий запрос: +```sql +SELECT * FROM pg_stats WHERE tablename = 'your_table_name' AND attname = 'column_name'; +``` + +Пример вывода: +![400](../../../meta/files/images/Pasted%20image%2020240331093839.png) + +Самые полезные значения: +- **n_distinct**: Уникальность значений. Показывает, сколько уникальных значений содержится в колонке. Например, значение `-1` указывает, что количество уникальных значений составляет примерно 1% от общего количества строк. +- **correlation**: Упорядоченность значений. Значение близкое к 1 показывает, что значения упорядочены по возрастанию, а близкое к -1 — что по убыванию. Высокая корреляция помогает планировщику оптимизировать выполнение запросов, используя последовательное сканирование индексов. +- **most_common_vals** и **most_common_freqs**: Самые частые значения колонки и их частота. Эти данные помогают планировщику лучше оценить стоимость выполнения запросов и выбрать наиболее эффективный план. +- **null_frac**: Доля `NULL` значений. Например, значение 0.92 означает, что около 92% значений в колонке — `NULL`. Высокое значение `null_frac` может указывать на возможность создания частичного индекса для улучшения производительности. + +> [!WARNING] +> Данные в `pg_stats` основаны на выборке, и поэтому могут не всегда точно отражать реальное состояние таблицы, особенно если данные часто изменяются. Для более точной оценки можно увеличить выборку строк с помощью настройки статистики +## Советы по анализу +- При большом значении `null_frac` остальные параметры могут иметь меньшее значение. На основе этой информации можно уменьшить размер индекса, создав [[../Частичный индекс]]. +- Если `n_distinct` показывает низкую уникальность, возможно, индекс на этой колонке не принесет значительного ускорения, так как слишком много строк имеют одинаковые значения (Низкая [[../Селективность колонки|селективность]]). В таком случае стоит рассмотреть пересмотр структуры запроса или таблицы. +- Высокое значение `correlation` (близкое к 1 или -1) означает, что данные отсортированы, что может существенно ускорить диапазонные запросы. В таких случаях планировщик может использовать последовательное сканирование, что может быть быстрее, чем случайное чтение. +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 PostgreSQL|00 PostgreSQL]] +**Родитель**:: [[Оптимизация SQL запросов в PostgreSQL]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-03-31]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/database/redis/Append-Only File.md b/dev/database/redis/Append-Only File.md new file mode 100644 index 00000000..ff9ccc5b --- /dev/null +++ b/dev/database/redis/Append-Only File.md @@ -0,0 +1,44 @@ +--- +aliases: + - AOF + - appendonly +tags: + - maturity/🌱 +date: 2024-10-07 +zero-link: +parents: +linked: +--- +Включение режима appendonly позволяет Redis обеспечивать долговременное хранение данных, записывая каждую операцию изменения в файл в хронологическом порядке. Вот основные моменты, которые стоит знать. + +![[../../../meta/files/images/Pasted image 20241103222301.png]] + +**Как работает AOF:** +- **Лог изменений**: Когда appendonly включен, Redis записывает каждую команду, изменяющую состояние базы данных (например, SET, DEL, LPUSH), в файл AOF, а не только хранит данные в памяти. +- **Постоянное сохранение данных**: Эти команды добавляются в конец файла (append), что позволяет восстанавливать состояние базы данных, выполняя все записанные команды по порядку, если Redis перезапускается. +- **Конфигурация сохранения**: В файле конфигурации Redis (redis.conf) можно указать несколько режимов, как часто Redis должен сбрасывать данные в файл: + - appendfsync always — данные сбрасываются на диск после каждой команды (максимальная надежность, но высокая нагрузка на диск). + - appendfsync everysec — данные сбрасываются раз в секунду (оптимальный компромисс между производительностью и надежностью). + - appendfsync no — система операционной системы сама решает, когда записывать данные на диск (максимальная производительность, но может привести к потере данных при сбое). + +**Преимущества AOF:** +- **Надежность**: AOF предлагает более надежное сохранение данных, чем механизм RDB (Redis Database Backup), который делает дампы данных на определенные промежутки времени. +- **Гибкость восстановления**: В случае сбоя Redis можно восстановить состояние базы данных, воспроизведя команды из AOF, что минимизирует потерю данных. +- **Читаемость файла**: AOF-файл — это текстовый файл, который легко можно прочитать и проанализировать для восстановления операций вручную, если потребуется. + +**Потенциальные недостатки:** +- **Рост размера файла**: Со временем файл AOF может значительно вырасти, так как в нем сохраняются все операции. Чтобы решить эту проблему, Redis периодически выполняет операцию “переписывания” AOF-файла — это процесс, при котором он сжимает файл, удаляя избыточные команды и сохраняя только текущую версию данных. +- **Производительность**: В зависимости от настроек, частота записи в AOF может влиять на производительность системы (особенно при использовании режима appendfsync always). +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 Redis|00 Redis]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-10-07]] +**Автор**:: +### Дополнительные материалы +- [[Redis Database Backup]] + +### Дочерние заметки + + diff --git a/dev/database/redis/Redis Database Backup.md b/dev/database/redis/Redis Database Backup.md new file mode 100644 index 00000000..48b8359d --- /dev/null +++ b/dev/database/redis/Redis Database Backup.md @@ -0,0 +1,36 @@ +--- +aliases: + - RDB +tags: + - maturity/🌱 +date: 2024-10-07 +--- +Механизм RDB (Redis Database Backup) — это способ создания **снапшотов** состояния базы данных Redis и их сохранения на диск. В отличие от [[database/redis/Append-Only File|AOF]], который записывает каждую операцию в реальном времени, RDB создаёт полные резервные копии состояния базы на определенные промежутки времени. Вот как это работает и основные моменты, которые стоит учитывать: + +![[../../../meta/files/images/Pasted image 20241103222301.png]] + +**Как работает RDB:** +- **Снапшоты базы данных**: Redis периодически сохраняет полную копию всех данных в файл на диске. Это называется “снапшот”. RDB-файл содержит сжатую и двоичную версию всех ключей и их значений на момент создания. +- **Файл дампа**: По умолчанию, RDB-файл называется `dump.rdb` и сохраняется на диск. Этот файл можно использовать для восстановления данных при перезапуске Redis. + +**Преимущества RDB:** +- **Производительность**: В отличие от AOF, механизм RDB не влияет на производительность во время нормальной работы Redis. Он не записывает каждую операцию на диск, а вместо этого периодически делает полные снимки базы данных. +- **Меньший объем данных**: Файл RDB, как правило, компактный и занимает меньше места, чем файл AOF, так как он представляет собой сжатую копию текущего состояния базы, а не лог изменений. +- **Быстрое восстановление**: При перезапуске Redis восстановление данных из RDB быстрее, чем воспроизведение всех операций из AOF, так как это просто загрузка состояния базы на момент последнего снапшота. + +**Недостатки RDB:** +- **Потенциальная потеря данных**: Поскольку RDB создаёт снимки только через определённые промежутки времени, можно потерять все изменения, которые произошли с момента последнего снапшота, в случае сбоя Redis. Если снапшот создавался 15 минут назад, то при сбое вы потеряете все изменения, сделанные за эти 15 минут. +- **Тяжелые операции на большом объеме данных**: Процесс создания снапшота может потреблять значительные ресурсы, особенно в крупных базах данных, что может влиять на производительность Redis на время создания снимка. +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 Redis|00 Redis]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-10-07]] +**Автор**:: +### Дополнительные материалы +- [[database/redis/Append-Only File]] + +### Дочерние заметки + + diff --git a/dev/database/redis/Команды Redis-cli.md b/dev/database/redis/Команды Redis-cli.md new file mode 100644 index 00000000..e229381f --- /dev/null +++ b/dev/database/redis/Команды Redis-cli.md @@ -0,0 +1,39 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-11-03 +--- +[Commands | Docs](https://redis.io/docs/latest/commands/) + +Положить данные в редис: +```redis +set test hello +``` + +Прочитать +```redis +get test +``` + +Удалить ключ +```redis +del test +``` + +Keys - команда, которая ищет ключи по маске. Используется итератор для поиска, поэтому рекомендуется не использовать, так как сразу оказывает влияние на производительность. + + +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 Redis|00 Redis]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-03]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/database/redis/Конфигурация Redis.md b/dev/database/redis/Конфигурация Redis.md new file mode 100644 index 00000000..01c2a655 --- /dev/null +++ b/dev/database/redis/Конфигурация Redis.md @@ -0,0 +1,32 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-11-03 +--- +- [Redis configuration file example | Docs](https://redis.io/docs/latest/operate/oss_and_stack/management/config-file/) + +- `stop-writes-on-bg-save-error`. Если на snapshot возникает какая-то проблема, то Redis перестает работать. По умолчанию yes. Обычно рекомендуется отключать. Тогда могут возникнуть проблемы с персистентностью, но хотя бы память озу будет работать. +- `rdbcompression`. Немного влияет негативно на производительность, но уменьшает размер хранимых данных. +- `save `. **Триггеры создания снапшотов** [[Redis Database Backup|RDB]]: + - save 900 1 — сохранить снапшот, если в течение последних 900 секунд (15 минут) было выполнено хотя бы 1 изменение. + - save 300 10 — сохранить снапшот, если за последние 300 секунд (5 минут) было выполнено 10 изменений. + - save 60 10000 — сохранить снапшот, если за последние 60 секунд (1 минута) было выполнено 10 000 изменений. +- [[database/redis/Append-Only File|appendonly]] +- Можно указать [[algorithm/Алгоритм вытеснения кэша|Алгоритмы вытеснения]] ключей +- `oom-score-adj-values` +- `disable-thp`. Лучше выключить. По умолчанию выключено. + +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 Redis|00 Redis]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-03]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/database/Долгая транзакция.md b/dev/database/Долгая транзакция.md new file mode 100644 index 00000000..935fbc92 --- /dev/null +++ b/dev/database/Долгая транзакция.md @@ -0,0 +1,35 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-11-05 +--- +## Тезисы +- Долгая транзакция — это незавершенная транзакция, которая может удерживать старую точку восстановления и препятствовать работе Autovacuum. +- Проблемы, вызванные долгими транзакциями: блокировка данных, нарушение процесса очистки таблиц, увеличение объема данных. +- Причины: ошибки в приложении, не обработанные исключения, человеческий фактор. +- Рекомендации: мониторинг и внешняя автоматизация завершения долгих транзакций. +*** +**Долгая транзакция** — это транзакция, которая была начата, но не завершена, и остается открытой, даже если в данный момент не выполняет действий. Такая транзакция удерживает точку восстановления (oldest transaction ID), что приводит к тому, что PostgreSQL должен хранить данные для поддержания целостности состояния на момент её открытия. Это удерживание мешает процессу [[postgresql/Autovacuum|Autovacuum]] очищать неактуальные строки, так как они могут быть необходимы для поддержания целостности базы в случае завершения этой старой транзакции. + +**Причины появления долгих транзакций** +1. **Внешний вызов**: В рамках транзакции в базе данных выполняется вызов внешнего процесса, который завершается с ошибкой, оставляя транзакцию открытой. +2. **Отсутствие обработки ошибок**: Если приложение не обрабатывает исключения, возникшие в ходе выполнения логики внутри транзакции, это может оставить транзакцию незавершенной. +3. **Человеческий фактор**: Открыли транзакции вручную через консоль и забыли её завершить. + +**Как решать проблему долгих транзакций?** +1. **Настройка мониторинга и алертов**: Настройте мониторинг и установите порог длительности транзакции, после которого её продолжительное существование вызывает оповещение. В большинстве продакшн-систем это время обычно составляет 1 час или меньше. +2. **Автоматическое завершение долгих транзакций**. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Реляционная база данных|00 Реляционная база данных]] +**Родитель**:: [[Транзакция БД]] +**Источник**:: +**Создана**:: [[2024-11-05]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/database/Журнал БД.md b/dev/database/Журнал БД.md new file mode 100644 index 00000000..5ceec9c7 --- /dev/null +++ b/dev/database/Журнал БД.md @@ -0,0 +1,52 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-05-26 +zero-link: + - "[[../../meta/zero/00 Реляционная база данных]]" +parents: +linked: +--- +Журнал базы данных — это структура, в которой фиксируются все изменения, происходящие в базе данных, до их окончательного применения. Основная цель журнала — обеспечить надежность и консистентность данных. Это позволяет выполнять [[Транзакция БД|транзакции]] и [[../architecture/highload/Репликация БД|репликацию БД]]. + +Перед выполнением SQL-запроса база данных сначала записывает в журнал информацию о планируемых действиях, например: "Обновить значение колонки `amount` в таблице `orders` для записи с `id = 5`". После фиксации записи в журнале база данных изменяет данные в памяти, чтобы ускорить обработку операций, а затем, с некоторой задержкой, записывает их на диск в основное хранилище. Этот подход улучшает производительность за счет уменьшения количества операций записи на диск, которые являются более медленными по сравнению с изменениями в памяти. В случае сбоя системы до записи данных на диск, изменения можно восстановить из журнала. Этот алгоритм называется [[../../../../_inbox/Point In Time Recovery (PITR)|PITR]] (Point In Time Recovery). + +![](Pasted%20image%2020240528081137.png) +Этот процесс обеспечивает два важных аспекта: +- **Надежность**: В случае сбоя системы данные можно восстановить из журнала до последнего зафиксированного состояния. +- **Консистентность**: Все транзакции, записанные в журнал, будут применены в базе данных в правильном порядке, что предотвращает потерю данных и сохраняет целостность системы. + +**Недостатки**: +- Увеличение времени записи: каждая транзакция требует предварительной записи в журнал, что может замедлить выполнение операций. +- Потребление дискового пространства: журналы могут занимать значительное место, особенно в системах с высокой активностью. + +> [!INFO] +> Журналы базы данных часто имеют циклическую структуру, где новые данные записываются поверх старых, когда журнал заполняется. Это позволяет эффективно использовать дисковое пространство и упрощает управление журналом. + +Реализации в СуБД: +- [[postgresql/Write-Ahead Log|Журнал в PostgreSQL]] +- [Журналы в MySQL](mysql/Журналы%20в%20MySQL.md) + +Главные вопросы, которые встают перед разработчиком любой БД: +- Как организовать журнал? +- Как его писать? +- Как писать его меньше? +- Как сделать так, чтобы это работало быстрее? +- При чем тут репликация? + +Для повышения производительности рекомендуется выделять отдельные жесткие диски под журналы, чтобы у них был эксклюзивный доступ к ресурсам диска. Это менее актуально для SSD, так как у них значительно выше скорость чтения и записи, а также отсутствует проблема механического доступа, что делает их более эффективными для параллельной работы с данными. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Реляционная база данных|00 Реляционная база данных]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-05-26]] +### Дополнительные материалы +- +### Дочерние заметки + + +- [[Write-Ahead Log]] + diff --git a/dev/database/Индекс базы данных.md b/dev/database/Индекс базы данных.md new file mode 100644 index 00000000..02c92c74 --- /dev/null +++ b/dev/database/Индекс базы данных.md @@ -0,0 +1,75 @@ +--- +aliases: + - индексов + - индекс + - индексы + - индексирования + - индекса +tags: + - maturity/🌱 +date: 2024-10-11 +--- +**Индекс** — это служебная структура данных, которая позволяет ускорить операции поиска, сортировки и фильтрации данных в реляционных базах данных. Индексы создаются для одного или нескольких столбцов таблицы, с целью [[Оптимизация SQL запросов|ускорения выполнения запросов к базе данных]]. + +Индексы обычно реализуются на основе различных структур данных, каждая из которых подходит для определённых типов запросов. Наиболее распространённые структуры данных для индексов: +- **B-деревья** ([[../fundamental/structure/B-tree|B-tree]]). Широко применяются для ускорения операций поиска, сортировки и диапазонных запросов. +- **Хэш-индексы.** Хорошо подходят для поиска по точным значениям, но неэффективны для диапазонных запросов. +- **GiST и R-деревья.** Используются для индексации пространственных данных, таких как координаты или географические объекты. + +СУБД автоматически выбирает наиболее подходящий индекс для выполнения запроса. Важно следить за тем, чтобы индекс покрывал нужные столбцы и типы запросов, так как ==неправильный выбор индекса может замедлить выполнение запросов.== + +**Польза:** +- **Ускорение запросов.** Индексы значительно ускоряют выполнение запросов, особенно для операций равенства, сравнений и сортировки данных. + - _Пример_: `SELECT * FROM employees WHERE department = 'HR';` — индекс на столбце `department` ускорит выполнение этого запроса. +- **Покрытие запросов.** В некоторых случаях индексы могут содержать все данные, необходимые для выполнения запроса, что позволяет избежать чтения самих строк таблицы (так называемый "[[Покрывающий индекс]]"). + - _Пример_: `SELECT name, age FROM employees WHERE department = 'IT';` — если индекс покрывает столбцы `name`, `age` и `department`, то чтение строк таблицы не потребуется. +- **Поддержка ограничений.** Индексы могут использоваться для реализации ограничений на уникальность данных (UNIQUE), а также для обеспечения ссылочной целостности (FOREIGN KEY). + +**Накладные расходы:** +- **Влияние на производительность**: добавление индексов замедляет операции вставки, обновления и удаления, так как индекс должен быть обновлен при каждой модификации данных. При создании индексов необходимо учитывать характер нагрузки на таблицу, особенно если часто выполняются операции записи. Например, при [[Online Transaction Processing|OLTP]] нагрузке чтение данных значительно преобладает над записью (80% чтения и 20% записи), что оправдывает использование индексов. +- **Блокировка таблицы**: добавление индекса блокирует таблицу, что может негативно сказаться на производительности, особенно в [[../../meta/zero/00 HighLoad|высоконагруженных системах]]. +- **Дополнительное использование дискового пространства.** Индексы требуют значительного объема дискового пространства для хранения. Обычно объем индексов составляет около половины размера таблицы. Если размер индексов превышает размер таблицы, это может указывать на необходимость оптимизации. +- **Необходимость технического обслуживания.** Со временем индексы могут фрагментироваться и требовать пересоздания для поддержания эффективности. В некоторых системах управления базами данных (СУБД) это может происходить автоматически, однако в других случаях требуется ручное вмешательство. + +**Частые ошибки:** +- **Низкая селективность.**: индексы на колонках с низкой [[Селективность колонки|селективностью]] могут оказаться неэффективными и не принести ожидаемого увеличения производительности. + - Индекс на столбце `gender` с двумя возможными значениями (`M`, `F`) не даст значительного выигрыша в производительности. +- **Неиспользуемые индексы**. Индексы, которые не используются, создают дополнительные накладные расходы на хранение и обслуживание. Рекомендуется периодически проверять активность индексов и удалять те, что не используются. Найти такие индексы поможет [[postgresql/pageinspect|pageinspect]]. +- **Высокие накладные расходы.** В некоторых случаях затраты на обновление индексов могут превышать выгоды от их использования. Наличие большого количества индексов на одной таблице может вызвать накладные расходы и ухудшить производительность, особенно при частых изменениях данных. + +**Когда индексы не работают:** +- **Использование вычисляемых выражений.** Например, выражение `WHERE column + 1 = 10` не будет эффективно использовать индекс. В таких случаях могут применяться специальные методы, такие как индексы по выражению или генерация вычисляемых колонок. + - _Пример_: Для выражения `column + 1` можно создать вычисляемый столбец и индексировать его. +- **Обработка большого количества записей.** Если запрос возвращает слишком много строк, использование индекса может быть неэффективным. +- **Агрегатные функции.** Лишь некоторые агрегатные функции, такие как `MIN()` и `MAX()`, могут эффективно использовать индексы. +- **Логические операторы.** Индексы хорошо работают с условиями, использующими логический оператор И (`AND`), но менее эффективны с логическим ИЛИ (`OR`): +- **Логические операторы.** Индексы хорошо работают с условиями, использующими логический оператор И (`AND`), но менее эффективны с логическим ИЛИ (`OR`). + - _Пример запроса с ИЛИ_: `SELECT * FROM tb WHERE a = 0 OR b = 0;` — в этом случае индексы для каждого столбца могут быть использованы независимо (индексы на `a` и `b`), но составной индекс по этим столбцам не будет работать эффективно. + +**Какие бывают индексы?** +- **Уникальные и неуникальные.** Уникальные индексы обеспечивают уникальность значений в столбцах. Неуникальные индексы допускают повторяющиеся значения. +- **Простые и составные.** Простые индексы создаются для одного столбца, а [[Составной индекс в БД|составные]] — для нескольких столбцов. +- **Кластерные и некластерные.** Кластерные индексы определяют физическое расположение данных на диске, а некластерные индексы хранят указатели на строки таблицы. + +**Реализации:** +- [[postgresql/Индекс в PostgreSQL|Индекс в PostgreSQL]] +- [[../../../../_inbox/Индекс в MySQL|Индекс в MySQL]] +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Реляционная база данных|00 Реляционная база данных]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-10-11]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + +- [[Индекс в MySQL]] +- [[Индекс в PostgreSQL]] +- [[Покрывающий индекс]] +- [[Составной индекс в БД]] + + diff --git a/dev/database/Индекс в БД для мягкого удаления.md b/dev/database/Индекс в БД для мягкого удаления.md new file mode 100644 index 00000000..4cdc4ae6 --- /dev/null +++ b/dev/database/Индекс в БД для мягкого удаления.md @@ -0,0 +1,30 @@ +--- +aliases: +tags: + - maturity/🌱 + - best-practices +date: 2024-11-05 +--- +Представьте, что вам нужно поддерживать уникальность данных, например, адресов электронной почты в таблице базы данных. Однако в таблице есть строки, [[../Tombstone|помеченные как удаленные]] с помощью поля `deleted_at`, и они также остаются в базе данных. В такой ситуации создание уникального индекса на поле с электронной почтой становится невозможным из-за дублирующихся значений. [[Частичный индекс|Частичный индекс]] решает эту проблему, позволяя включать в индекс только записи, которые не помечены как удаленные. + +В PostgreSQL добавление уникального индекса для активных пользователей выглядит так: +```sql +CREATE UNIQUE INDEX users_email_uniq ON users ( + email +) WHERE deleted_at IS NULL; +``` + +В этом случае строки, у которых `deleted_at` не задан, включаются в индекс, а остальные игнорируются, что делает индекс более компактным и эффективным. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Реляционная база данных|00 Реляционная база данных]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-05]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/database/Индекс для внешнего ключа таблицы БД.md b/dev/database/Индекс для внешнего ключа таблицы БД.md new file mode 100644 index 00000000..5c9ebe30 --- /dev/null +++ b/dev/database/Индекс для внешнего ключа таблицы БД.md @@ -0,0 +1,45 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-10-11 +zero-link: +parents: +linked: +--- +При создании внешнего ключа в базе данных важно не забывать про добавление индекса на соответствующий столбец. Разберёмся, почему это важно. + +Сперва обратимся к [документации PostgreSQL](https://www.postgresql.org/docs/current/ddl-constraints.html): + +> A foreign key must reference columns that either are a primary key or form a unique constraint, or are columns from a non-partial unique index. This means that the referenced columns always have an index to allow efficient lookups on whether a referencing row has a match. Since a `DELETE` of a row from the referenced table or an `UPDATE` of a referenced column will require a scan of the referencing table for rows matching the old value, ==it is often a good idea to index the referencing columns too==. Because this is not always needed, and there are many choices available on how to index, the declaration of a foreign key constraint does not automatically create an index on the referencing columns. + +Когда выполняются операции, такие как INSERT, UPDATE или DELETE, СУБД должна проверять целостность данных. Без индекса проверка связей может занимать много времени, поскольку требуется сканирование всей таблицы для поиска необходимых записей. + +Рассмотрим пример удаления строки из таблицы, связанной с другой таблицей через внешний ключ. ==Удаление выполняется по первичному ключу, и внешний ключ в запросе напрямую не используется.== + +![600](../../meta/files/images/Pasted%20image%2020240331093028.png) + +Видно, что поиск по первичному ключу выполняется быстро, так как удаление производится по индексированному первичному ключу. Однако ==наибольшее время занимает проверка связей с другой таблицей.== + +Добавим индекс на внешний ключ и проведем повторный эксперимент. + +![600](../../meta/files/images/Pasted%20image%2020240331093524.png) + +После добавления индекса на внешний ключ и повторного выполнения запроса: +- Без индекса на внешний ключ операция удаления заняла 690 мс. +- С индексом — всего 0.101 мс. + +Таким образом, ==в большинстве случаев стоит создавать индекс для внешнего ключа, особенно если часто выполняются операции удаления или обновления==. Но когда индекс не нужен? ==Если в основном таблица используется для операций INSERT и SELECT, индекс на внешний ключ может не понадобиться==. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Реляционная база данных|00 Реляционная база данных]] +**Родитель**:: [[Оптимизация SQL запросов]] +**Источник**:: +**Создана**:: [[2024-10-11]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/database/Использование малоселективных полей для оптимизации чтения страниц.md b/dev/database/Использование малоселективных полей для оптимизации чтения страниц.md new file mode 100644 index 00000000..0b6311ad --- /dev/null +++ b/dev/database/Использование малоселективных полей для оптимизации чтения страниц.md @@ -0,0 +1,25 @@ +--- +aliases: +tags: + - maturity/🌱 + - hack +date: 2024-11-05 +--- +Если в таблице много записей с одинаковыми значениями (низкая [[Селективность колонки|селективность]]), и необходимо индексировать только записи с уникальными или более специфичными значениями, то можно использовать проблему низкой селективности для повышения эффективности запросов. + +Когда менее селективные поля находятся в начале [[Составной индекс в БД|составного индекса]], то на одной [[DB page|странице]] в памяти базы данных сгруппируются записи с одинаковыми значениями по этим полям. Это позволяет при поиске уникального значения считывать меньше [[DB page|страниц]] из памяти, что в некоторых случаях может улучшить производительность. + +![[../../meta/files/images/Pasted image 20241105002717.png]] +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Реляционная база данных|00 Реляционная база данных]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-05]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/database/Колоночная база данных.md b/dev/database/Колоночная база данных.md new file mode 100644 index 00000000..fecf5dff --- /dev/null +++ b/dev/database/Колоночная база данных.md @@ -0,0 +1,51 @@ +--- +aliases: + - Columnar Databases + - колоночную базу данных +tags: + - maturity/🌱 +date: 2024-11-26 +--- +**Колоночные базы данных** (Columnar Databases) — это системы управления базами данных, которые хранят данные столбцами, а не строками, как в традиционных реляционных базах данных. Этот подход имеет важные преимущества в задачах аналитики и обработки больших объемов данных. + +Вместо того чтобы хранить данные построчно, как это делает реляционная база данных + +![[../../meta/files/images/Pasted image 20241126185848.png]] + +колоночные базы данных хранят данные в виде отдельных столбцов. + +![[../../meta/files/images/Pasted image 20241126185910.png]] + + +Колоночные базы данных широко используются в системах, где важно быстро анализировать большие объемы данных. Примеры: +- [[../../meta/zero/00 ClickHouse|ClickHouse]] — быстрая аналитика и построение отчетов. +- **Amazon Redshift** — облачные хранилища данных. +- Apache [[Cassandra]] и **HBase** — большие распределенные хранилища. + +**Преимущества** +- **Ускорение аналитических запросов**: При агрегациях и фильтрациях задействуются только те столбцы, которые участвуют в запросе. При этом данные одного типа лежат последовательно. Это значительно сокращает объем данных, которые нужно считывать с диска. +- **Эффективное сжатие данных**: Данные в одном столбце имеют схожую природу (например, возраст — целые числа), что позволяет применять более эффективные алгоритмы сжатия, такие как RLE (Run Length Encoding) или Dictionary Encoding. +- **Снижение нагрузки на I/O**: Извлечение только нужных столбцов уменьшает объем операций ввода-вывода. + +**Недостатки** +- **Меньшая эффективность для транзакционных операций**: Записи и обновления, которые влияют на большое количество столбцов, требуют больше операций, чем в реляционных базах. +- **Усложнение работы с несжатыми или разреженными данными**: Если данные столбца не поддаются сжатию или содержат много пропусков, преимущества колоночного подхода снижаются. +- **Требования к особенностям использования**: Колоночные базы данных не подходят для [[Online Transaction Processing|OLTP]], так как их структура оптимизирована под аналитические нагрузки ([[Online Analytical Processing|OLAP]]). + +Они применяются: +- В бизнес-аналитике (BI), где важны агрегации и построение отчетов. +- В системах мониторинга, где обрабатываются метрики (логирование, мониторинг систем). +- В рекомендационных системах для анализа больших массивов пользовательских данных. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Разработка|00 Разработка]] +**Родитель**:: [[../Тип хранилища данных|Тип хранилища данных]] +**Источник**:: +**Создана**:: [[2024-11-26]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/database/Оптимизация SQL запросов.md b/dev/database/Оптимизация SQL запросов.md new file mode 100644 index 00000000..7c0dccec --- /dev/null +++ b/dev/database/Оптимизация SQL запросов.md @@ -0,0 +1,53 @@ +--- +aliases: + - ускорения SQL запросов +tags: + - maturity/🌱 +date: + - - 2024-07-13 +linked: +--- +- [[postgresql/Оптимизация SQL запросов в PostgreSQL|Оптимизация SQL запросов в PostgreSQL]] + +**Где могут быть проблемы?** +- **Передача запроса от клиента**: задержка или проблемы при передаче могут негативно сказываться на производительности. [Пример при использовании IN](IN%20SQL.md#Проблемы%20производительности%20IN) +- **Сложный запрос**: сложные запросы с большим количеством условий могут долго парситься, замедляя выполнение. +- **Долгое вычисление плана**: при сложных операциях, таких как JOIN, оптимизатору может потребоваться много времени для выбора лучшего плана выполнения. +- **Исполнение и возврат результатов**: возврат больших объемов данных (например, нескольких гигабайт) значительно замедляет запрос. + +**Как улучшить?** +- **Используйте индексы**: правильно настроенные [[Индекс базы данных|индексы]] могут существенно ускорить выполнение. +- **Переписать запрос**: упростите запрос, разделите его на несколько меньших, если это возможно. + +**Что невозможно улучшить** +- `count(*)`: Подсчет всех строк в таблице — это ресурсоемкая операция, так как требует полного сканирования таблицы. Вместо этого можно использовать приближенные значения из таблицы статистики, которые дают примерное представление и требуют меньше ресурсов. +- **JOIN на 300 таблиц**: Операции с таким количеством таблиц чрезвычайно ресурсоемки, так как оптимизатору требуется много времени для вычисления плана, а выполнение может потребовать значительных ресурсов памяти и процессора. Альтернативой может быть пересмотр структуры данных и использование денормализации для сокращения числа объединяемых таблиц. +- **Возврат 1 000 000 000 строк**: Возврат большого количества строк, таких как миллиард записей, требует огромных объемов ресурсов и времени на передачу. Лучше ограничить количество возвращаемых строк и использовать агрегированные данные, если это возможно. +## Индекс для внешнего ключа +Всегда [[Индекс для внешнего ключа таблицы БД|добавляйте индекс для внешнего ключа]]. Индексация внешних ключей позволяет ускорить операции обновления и удаления, так как база данных может быстро находить связанные записи. Это особенно важно для таблиц с большим объемом данных, где операции без индекса могут значительно замедлить производительность. +## Подзапросы и JOIN +В некоторых случаях подзапросы могут быть более производительными, чем использование `JOIN`, так как планировщик запросов может оптимизировать выполнение подзапроса отдельно. Однако это зависит от конкретного запроса и структуры данных, поэтому всегда стоит проверять план выполнения ([[postgresql/Профилирование запросов в PostgreSQL|EXPLAIN]]) и тестировать оба варианта. +## IN и BETWEEN +Использование `IN` иногда может быть быстрее, чем `BETWEEN`, так как оно позволяет базе данных более эффективно работать с множеством значений. Однако это утверждение не универсально и может зависеть от конкретной реализации СУБД и структуры данных. Рекомендуется проводить тестирование с реальными данными, чтобы определить наиболее эффективный вариант. +## Сортировка по значениям NULL +Старайтесь избегать сортировки по значениям `NULL`. Сортировка по `NULL` может добавить значительную нагрузку на базу данных, так как `NULL` требует специальной обработки, чтобы корректно определить порядок значений. +## Использование DISTINCT +Использование `DISTINCT` следует минимизировать, так как оно приводит к дополнительным вычислениям для удаления дублирующихся значений. Если возможно, попробуйте перепроектировать запрос или данные так, чтобы избежать необходимости в `DISTINCT`. + +## OFFSET и производительность +Использование `OFFSET` для постраничного отображения данных снижает производительность, особенно на больших таблицах, так как база данных должна пропустить множество строк перед тем, как выбрать нужные. Рекомендуется использовать курсоры или другие способы для постраничного вывода, чтобы уменьшить нагрузку на базу данных. +*** +## Мета информация +**Область**:: [[../../../../wiki/zero/00 SQL|00 SQL]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-07-13]] +### Дополнительные материалы +- +### Дочерние заметки + + +- [[Индекс для внешнего ключа таблицы БД]] +- [[Оптимизация SQL запросов в PostgreSQL]] + diff --git a/dev/database/Плохой SQL запрос.md b/dev/database/Плохой SQL запрос.md new file mode 100644 index 00000000..00a10cc7 --- /dev/null +++ b/dev/database/Плохой SQL запрос.md @@ -0,0 +1,29 @@ +--- +aliases: + - Сложный запрос + - плохие sql запросы + - проблемных запросов + - проблемный запрос +tags: + - maturity/🌱 +date: 2024-10-21 +--- +Понимание того, что такое плохой или медленный запрос, важно для поддержания высокой производительности системы. Плохие запросы могут существенно замедлять работу базы данных, создавая нагрузку на сервер и снижая эффективность всех операций. Их [[Оптимизация SQL запросов|оптимизация]] позволяет значительно улучшить производительность, уменьшить задержки и снизить использование ресурсов. + +**Признаки плохого запроса** +- Запрос, который выполняется медленнее, чем остальные, и значительно увеличивает время обработки. +- Запросы, которые по отдельности достаточно быстрые, но из-за частого выполнения и отсутствия оптимизации потребляют значительное количество ресурсов сервера. +- Запросы, которые создают блокировки, мешая другим операциям выполняться параллельно. +*** +## Мета информация +**Область**:: [[../../../../wiki/zero/00 SQL|00 SQL]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-10-21]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/database/Покрывающий индекс.md b/dev/database/Покрывающий индекс.md new file mode 100644 index 00000000..0ae4dada --- /dev/null +++ b/dev/database/Покрывающий индекс.md @@ -0,0 +1,49 @@ +--- +aliases: + - covering indexes + - покрывающего индекса +tags: + - maturity/🌱 +date: 2024-06-09 +--- +Покрывающий индекс — это [[Индекс базы данных|индекс]], который включает в себя все колонки, необходимые для выполнения определенного запроса, без необходимости обращения к основной таблице данных. + +Обычный индекс позволяет ускорить поиск по ключевой колонке, но при этом, чтобы получить данные из других колонок, СУБД все равно обращается к основной таблице. ==Покрывающий индекс, в отличие от обычного, содержит все необходимые для запроса колонки, что исключает необходимость обращения к таблице и, следовательно, улучшает производительность.== + +Однако это не всегда так: иногда СУБД всё же вынуждена обратиться к таблице, поскольку индекс не хранит информацию о **видимости строк** — данных, которые управляют их доступностью в текущей транзакции. В системах с многоверсионной архитектурой (например, в PostgreSQL) строки могут быть изменены, удалены или добавлены другими транзакциями, которые ещё не завершены. Это создаёт «несогласованные» версии данных, и СУБД нужно проверить, какая версия строки видима в текущем запросе. + +Пример создания покрывающего индекса в [[../../meta/zero/00 PostgreSQL|PostgreSQL]]: + +```sql +CREATE INDEX idx_example ON table_name (column1) INCLUDE (column2); +``` + +Такой индекс включает колонку `column1` для индексирования и добавляет `column2`, которая не индексируется, но хранится рядом с индексом. Это позволяет выполнять следующий запрос, не обращаясь к основной таблице: + +```sql +SELECT column1, column2 FROM table_name WHERE column1 = 'value'; +``` + +**Преимущества**: +- Значительное улучшение производительности запросов, так как нет необходимости обращаться к основной таблице. +- Уменьшение числа обращений к диску, особенно для часто используемых запросов с выборкой нескольких колонок. + +**Недостатки**: +- Покрывающие индексы могут занимать больше места в памяти, особенно если в них включены несколько дополнительных колонок. +- Увеличение времени на операции вставки, обновления и удаления, так как индекс требует обновления при изменениях данных. + +**Покрывающие индексы стоит использовать в следующих случаях:** +- Для оптимизации часто выполняемых SELECT-запросов, которые выбирают несколько колонок. +- Когда необходимо минимизировать количество обращений к диску, чтобы ускорить выполнение запросов. +- Для [[Online Analytical Processing|OLAP]], где важно быстрое чтение данных без необходимости частых обновлений. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Реляционная база данных|00 Реляционная база данных]] +**Родитель**:: [[Индекс базы данных]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-06-09]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/database/Селективность колонки.md b/dev/database/Селективность колонки.md new file mode 100644 index 00000000..33189e5b --- /dev/null +++ b/dev/database/Селективность колонки.md @@ -0,0 +1,37 @@ +--- +aliases: + - селективность + - селективные + - селективностью +tags: + - maturity/🌱 +date: 2024-03-31 +--- +Селективность колонки в базе данных — это отношение уникальных значений в столбце к общему количеству значений. ==Чем больше уникальных значений, тем выше селективность.== Селективность выражается значением от 0 до 1, где 0 означает отсутствие селективности, а 1 — идеальную селективность. + +Высокая селективность делает колонку отличным кандидатом для [[Индекс базы данных|индексирования]], так как это уменьшает количество строк для просмотра и ускоряет поиск. Например, колонка с уникальными идентификаторами пользователей позволяет значительно улучшить производительность запросов. + +Низкая селективность означает много повторяющихся значений. Например, колонка с полом пользователя ("мужской" и "женский"). Индекс на таком столбце обычно малоэффективен, но может быть полезен при использовании с другими более селективными колонками. Это помогает уменьшить объем данных для сканирования. + +Также индексы на низкоселективных колонках могут ускорить выборку редких записей, например, необработанных данных. + +```sql +SELECT * FROM records WHERE processed = false; +``` + +Если большинство записей уже обработаны, такой индекс может значительно ускорить запрос. + + + + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Реляционная база данных|00 Реляционная база данных]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-03-31]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/database/Составной индекс в БД.md b/dev/database/Составной индекс в БД.md new file mode 100644 index 00000000..5dedb339 --- /dev/null +++ b/dev/database/Составной индекс в БД.md @@ -0,0 +1,71 @@ +--- +aliases: + - Составные индексы + - многоколоночный индекс +tags: + - maturity/🌱 +date: 2024-06-16 +--- +Составной индекс — это индекс, включающий несколько полей, который используется для повышения производительности запросов, фильтрующих данные сразу по нескольким колонкам. + +Проще всего представить составной индекс не как последовательность индексов по отдельным колонкам, а как индекс по объединённым значениям этих колонок. Поэтому порядок столбцов в составном индексе имеет значение.== Он влияет на эффективность индекса, и поэтому чаще всего ==наиболее [[Селективность колонки|селективные]] поля следует располагать первыми== для максимальной производительности. ==SQL-запросы также должны учитывать этот порядок== для оптимального использования индекса. + +Однако, есть исключительные ситуации из этого правила: +- [[Использование малоселективных полей для оптимизации чтения страниц]] + +**Преимущества:** +- **Оптимизация дискового пространства**: ==Один составной индекс может заменить несколько простых индексов==, что экономит дисковое пространство. +- **Ускорение запросов**: Составной индекс позволяет ускорять запросы, которые используют несколько колонок для фильтрации и сортировки данных. + +**Недостатки:** +- **Высокие накладные расходы при обновлении**: Каждый раз при вставке, обновлении или удалении данных, которые попадают в составной индекс, СУБД должна обновлять весь индекс, что может увеличивать время выполнения таких операций. +- Старайтесь минимизировать использование неравенств в начале составных индексов, так как это может ограничить их применение для последующих колонок. + +> [!WARNING] Количество параметров +> Составной индекс из 2-3 полей обычно считается нормальным и эффективно поддерживаемым. Если количество колонок в индексе превышает три, следует тщательно анализировать его использование, чтобы избежать излишней нагрузки на производительность. + + +Создание составного индекса: +```sql +CREATE INDEX idx_example ON table_name (column_a, column_b); +``` + +Запросы, которые могут использовать этот индекс: + +Фильтрация по обоим полям: +```sql +SELECT * FROM orders WHERE customer_id = 123 AND order_date >= '2024-01-01'; +``` +Этот запрос будет максимально эффективен, так как учитывает оба поля в порядке, указанном в индексе. + +Фильтрация только по `customer_id`: + +```sql +SELECT * FROM orders WHERE customer_id = 123; +``` + +Этот запрос также будет использовать индекс, поскольку `customer_id` — первая колонка в составном индексе. + +Запрос, который не будет оптимально использовать составной индекс: + +```sql +SELECT * FROM orders WHERE order_date >= '2024-01-01'; +``` + +Такой запрос не использует весь потенциал индекса, так как `order_date` не является первой колонкой. + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Реляционная база данных|00 Реляционная база данных]] +**Родитель**:: [[Индекс базы данных]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-06-16]] +### Дополнительные материалы +- +### Дочерние заметки + + +- [[Составной индекс в PostgreSQL]] + + diff --git a/dev/database/Таблицы с колонкой статуса.md b/dev/database/Таблицы с колонкой статуса.md new file mode 100644 index 00000000..f43fc2b7 --- /dev/null +++ b/dev/database/Таблицы с колонкой статуса.md @@ -0,0 +1,44 @@ +--- +aliases: +tags: + - maturity/🌱 + - best-practices +date: 2024-11-05 +--- +Часто в приложениях есть таблицы, которые содержат колонку статуса (`state`). Обычно статус разделяет записи на "обработанные" и "необработанные". Индекс нам часто нужен именно по необработанным данным. Создавая [[Частичный индекс|частичный индекс]] только по необработанным данным, мы можем ускорить выполнение запроса и уменьшить размер индекса. + +Возьмем типичную табличку, в которой есть какие-то статусы мы хотим находить данные по этому статусу. + +![300](../../meta/files/images/Pasted%20image%2020240331095959.png) +![600](../../meta/files/images/Pasted%20image%2020240331100144.png) + +Часто появляется желание сделать индекс по полю статуса: + +![600](../../meta/files/images/Снимок%20экрана%202024-03-31%20в%2010.07.02.png) + +Но по факту мы индексируем поле, которое имеет небольшую [селективность](../../dev/database/Селективность%20колонки.md). Такой индекс не эффективный. + +Хороший вариант в данном случае: +![600](../../meta/files/images/Снимок%20экрана%202024-03-31%20в%2010.13.39.png) + +Почти идеальный: +![600](../../meta/files/images/Снимок%20экрана%202024-03-31%20в%2010.15.06.png) +![500](../../meta/files/images/Pasted%20image%2020240331101612.png) + +Идеальный. Совмещаем и [[postgresql/Составной индекс в PostgreSQL|составной индекс]] и частичный. + +![[../../meta/files/images/Pasted image 20241021225124.png]] + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Реляционная база данных|00 Реляционная база данных]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-05]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/database/Управление VIEW в Liquibase.md b/dev/database/Управление VIEW в Liquibase.md new file mode 100644 index 00000000..40bf4f59 --- /dev/null +++ b/dev/database/Управление VIEW в Liquibase.md @@ -0,0 +1,78 @@ +--- +aliases: +tags: + - maturity/🌱 + - content/problem +date: 2023-11-02 +--- +При создании VIEW в [[../../../../knowledge/dev/Liquibase|Liquibase]] возникают трудности с её поддержкой, особенно когда исходная таблица, меняется. Это становится ещё сложнее, если несколько VIEW ссылаются на одну таблицу. Когда происходят изменения, становится сложно быстро найти актуальный скрипт для создания VIEW, так как изменения могут быть разбросаны по нескольким файлам или версиям. + +Для упрощения управления все VIEW выносятся в отдельный changeLog файл. Этот файл всегда указывается в конце основного master changeLog, поскольку VIEW создаются после создания всех таблиц, чтобы обеспечить корректность их работы. + +Пример master changeLog файла: +```xml + + + + + + + + + +``` + +Пример `views/changelog.xml`: + +```xml + + + + + + + + + + + + + + + + + ...SQL FOR CREATE VIEW... + + + + +``` + +В файле changeLog для управления вьюхами необходимо соблюдать следующий порядок: +- Сначала используется changeSet, который удаляет вьюху, если она уже существует. +- Затем используется changeSet, который создаёт новую вьюху. + +Ключевыми параметрами для changeSet являются: +- `runAlways="true"` — указывает Liquibase всегда выполнять данный changeSet, даже если он уже выполнялся ранее. Это важно для поддержания актуальности данных вьюхи после каждого изменения. +- `runOnChange="true"` — указывает Liquibase игнорировать изменения контрольной суммы для данного changeSet. + +Таким образом, вы получите централизованное и актуальное место для управления структурами VIEW, что значительно упростит их поддержку и обновление. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Реляционная база данных|00 Реляционная база данных]] +**Родитель**:: [[Liquibase]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-11-02]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/database/Частичный индекс.md b/dev/database/Частичный индекс.md new file mode 100644 index 00000000..207bf33e --- /dev/null +++ b/dev/database/Частичный индекс.md @@ -0,0 +1,43 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-10-21 +--- +Можно создать частичный индекс по условию, который покрывает только записи, удовлетворяющие определенному условию `WHERE`. + +Например, можно исключить из индекса по внешнему ключу (FK) значения `NULL`: + +```sql +CREATE INDEX fk_not_null ON pgconf(fk_id) +WHERE fk_id IS NOT NULL; +``` + +Частичные индексы позволяют не только уменьшить размер индекса, но и обеспечить более эффективную работу с таблицами, содержащими данные, которые имеют различный статус (например, активные и удаленные записи). Это особенно полезно в случаях, когда необходимо поддерживать уникальность данных и при этом исключить определенные записи из индекса, такие как удаленные или обработанные. + +**Преимущества:** +- **Уменьшение размера индекса**: Индекс включает только необходимые записи, что уменьшает его общий объём. +- **Ускорение запросов**: Частичный индекс может улучшить производительность запросов, особенно если он используется для выборки узко определённых данных. +- **Снижение нагрузки на обновление**: Поскольку индекс обновляется только для строк, удовлетворяющих условию, уменьшаются накладные расходы на запись. + +**Недостатки:** +- **Ограниченная применимость**: Частичные индексы не всегда подходят, особенно для данных с высокой селективностью, где обычные индексы будут более эффективны. +- **Сложность настройки**: Необходимо тщательно выбирать условия `WHERE`, чтобы получить максимальную пользу от частичного индекса. Неправильный выбор условий может привести к ухудшению производительности. + +**Когда использовать частичные индексы:** +- Когда необходимо уменьшить размер индекса за счёт исключения ненужных записей, что позволяет сэкономить место на диске и ускорить операции поиска. +- [[Использование малоселективных полей для оптимизации чтения страниц]] +- [[Таблицы с колонкой статуса]]. В ситуациях, когда индекс нужен для работы с данными, которые соответствуют определённому условию, например, только "необработанные" записи. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 PostgreSQL|00 PostgreSQL]] +**Родитель**:: [[Индекс в PostgreSQL]], [[Оптимизация SQL запросов в PostgreSQL]] +**Источник**:: +**Создана**:: [[2024-10-21]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/devops/docker/Docker Network.md b/dev/devops/docker/Docker Network.md new file mode 100644 index 00000000..796986e0 --- /dev/null +++ b/dev/devops/docker/Docker Network.md @@ -0,0 +1,32 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-03-25 +zero-link: + - "[[../../../meta/zero/00 Docker|00 Docker]]" +parents: +linked: +--- +При запуске докера создается локальная сеть и поднимается NAT. При запуске контейнера ему выдается IP адрес из этой локальной сети. А когда мы открываем порт для контейнера в iptables добавляется новая запись переадресации с порта хостовой машины на соответсвующий контейнеру IP адрес и порт в локальной сети. Из-за этого немного проседает производительность. + +Если контейнер не запущен в какой-то сети, то он будет видеть все остальные контейнеры, которые не привязаны к какой-то конкретной сети. То есть из одного докер контейнера можно средствами терминала подключиться к другому контейнеру используя его локальный IP адрес. + +- Контейнер может быть подключен к нескольким сетям (без рестарта) +- Работает Service Discovery +- Можно задать произвольные диапазоны IP адресов + +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 Docker|00 Docker]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-03-25]] +### Дополнительные материалы +- +### Дочерние заметки + + +- [[Изменить IP-адрес подсети Docker по умолчанию]] + diff --git a/dev/devops/docker/Dockerfile.md b/dev/devops/docker/Dockerfile.md new file mode 100644 index 00000000..700bd042 --- /dev/null +++ b/dev/devops/docker/Dockerfile.md @@ -0,0 +1,31 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-03-20 +zero-link: +parents: +linked: +--- +## CMD +Данная команда позволяет задать дефолтную команду, которая будет запускаться при запуске. При этом пользователь может указать любую другую произвольную команду во время запуска. + +## ENTRYPOINT +Данная команда позволяет задать начало запроса, который будет выполняться при запуске образа. + +Например, `ENTRYPOINT ["npx", "quartz"]` означает, что при запуске контейнера будет запущена команда `npx quartz`, также пользователь может дописать продолжение команды. То есть, в отличие от CMD пользователь может писать только продолжение команды, другую команду уже не выполнить. + +## Не очевидное +- Удаление файлов не уменьшает размер образа, если удаление происходит в другом слое. Удалять файлы нужно в том же слое, в котором они добавляются. ^a070de + +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 Docker|00 Docker]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-03-20]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/devops/docker/Healthcheck в docker-compose.md b/dev/devops/docker/Healthcheck в docker-compose.md new file mode 100644 index 00000000..03ce5c58 --- /dev/null +++ b/dev/devops/docker/Healthcheck в docker-compose.md @@ -0,0 +1,43 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-10-30 +--- +Для проверки работоспособности запущенного контейнера можно задать команду `healthcheck`. Контейнер не будет считаться полностью запущенным, пока не выполнится проверка работоспособности. Это особенно полезно при запуске нескольких контейнеров, которые зависят друг от друга. Например, если один контейнер должен быть готов до того, как будет запущен другой. + +Пример конфигурации: +```yaml +services: + database: + image: postgres:latest + container_name: database + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 10s + timeout: 5s + retries: 3 + + webapp: + image: my-webapp:latest + container_name: webapp + depends_on: + database: + condition: service_healthy + ... +``` + +В этом примере контейнер с веб-приложением (`webapp`) зависит от контейнера с базой данных (`database`). Команда healthcheck для базы данных проверяет, готова ли PostgreSQL принимать подключения (`pg_isready`), и контейнер будет считаться здоровым только после успешного выполнения этой проверки. +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 Docker Compose|00 Docker Compose]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-10-30]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/devops/docker/Запуск нескольких реплик в docker-compose.md b/dev/devops/docker/Запуск нескольких реплик в docker-compose.md new file mode 100644 index 00000000..04a50542 --- /dev/null +++ b/dev/devops/docker/Запуск нескольких реплик в docker-compose.md @@ -0,0 +1,34 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-10-30 +--- +Добавив всего пару строк в конфигурацию, вы можете запустить несколько экземпляров вашего приложения ([[../../architecture/highload/Горизонтальное масштабирование|Горизонтальное масштабирование]]). + +``` +services: + my-service: + ... + ports: + - 8080-8082:8080 + deploy: + replicas: 3 +``` + +> [!Note] Балансировка нагрузки +> Docker не выполняет автоматическое распределение нагрузки между репликами, поэтому важно настроить балансировку с помощью внешних инструментов, таких как nginx ([[../nginx/Балансировка нагрузки в Nginx|Балансировка запросов на Nginx]]). Это необходимо для того, чтобы равномерно распределять запросы между репликами и обеспечить более стабильную работу приложения. + +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 Docker Compose|00 Docker Compose]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-10-30]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/devops/docker/Изменить IP-адрес подсети Docker по умолчанию.md b/dev/devops/docker/Изменить IP-адрес подсети Docker по умолчанию.md new file mode 100644 index 00000000..c7f12357 --- /dev/null +++ b/dev/devops/docker/Изменить IP-адрес подсети Docker по умолчанию.md @@ -0,0 +1,41 @@ +--- +aliases: +tags: + - maturity/🌱 +date: + - - 2024-03-25 +zero-link: + - "[[../../../meta/zero/00 Docker|00 Docker]]" +parents: + - "[[Docker Network|Docker Network]]" +linked: +--- +Недавно, при настройке нового окружения, Я столкнулся с проблемой: подсеть, которую создавал docker по умолчанию конфликтовала с подсетью нашей внутренней сети. Это приводило к тому, что я не мог авторизоваться на сервере, довольно неприятно. + +Для решения этой проблемы нужно изменить подсеть Docker по умолчанию. Таким образом, вы можете выбрать те подсети, которые не конфликтует с вашей корпоративной сетью. + +Откройте файл настроек `/etc/docker/daemon.json` и введите IP-адрес сетевой маски: + +```json +{ + ... + "default-address-pools":[ + {"base":"10.66.0.0/16","size":24}, + {"base":"10.77.0.0/16","size":24} + ] +} +``` + +Эта конфигурация позволит Docker выделить подсети в диапазоне 10.66.\[0-255\].024 и 10.77.\[0-255\].024, что позволяет использовать 256 адресов для каждой сети, а всего 512 сетей. + +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 Docker|00 Docker]] +**Родитель**:: [[Docker Network]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-03-25]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/devops/docker/Ограничение ресурсов в docker-compose.md b/dev/devops/docker/Ограничение ресурсов в docker-compose.md new file mode 100644 index 00000000..bf46a11c --- /dev/null +++ b/dev/devops/docker/Ограничение ресурсов в docker-compose.md @@ -0,0 +1,55 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-10-30 +--- +Используя ограничения на CPU и RAM, вы можете проводить локальное нагрузочное тестирование и наблюдать, как сервис будет работать в условиях, близких к реальным. + +Синтаксис ограничения ресурсов в файле docker-compose.yml может отличаться в зависимости от версии файла, указанной в первой строке. Вот пример для версии 3.7: + +```yaml +version: ‘3.7’ + +services: + my-service: + ... + deploy: + resources: + limits: + cpus: '2' + memory: '256M' +``` + +Важно помнить, что ограничение памяти контейнера не означает автоматического ограничения памяти для JVM. По умолчанию JVM использует не более 1/4 от доступной памяти системы, но не менее 128 MB. Таким образом, если контейнеру выделено 512 MB памяти, Java будет использовать только 128 MB, что приведет к неэффективному использованию оставшихся ресурсов. Чтобы этого избежать, следует явно задавать объем доступной памяти для JVM. + +Кроме того, в Docker можно использовать не только `limits` для задания максимального количества ресурсов, но и `reservations` для задания минимальных гарантированных ресурсов, которые будут выделены для контейнера. Например: + +```yaml +services: + my-service: + ... + deploy: + resources: + limits: + cpus: '2' + memory: '256M' + reservations: + cpus: '1' + memory: '128M' +``` + +Параметры `reservations` позволяют гарантировать минимально необходимое количество ресурсов для стабильной работы приложения, что особенно полезно при работе в условиях ограниченных вычислительных мощностей. +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 Docker Compose|00 Docker Compose]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-10-30]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/devops/docker/Полезные Docker образы.md b/dev/devops/docker/Полезные Docker образы.md new file mode 100644 index 00000000..774aea58 --- /dev/null +++ b/dev/devops/docker/Полезные Docker образы.md @@ -0,0 +1,25 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-09-07 +zero-link: + - "[[../../../meta/zero/00 Docker|00 Docker]]" +parents: +linked: +--- +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 Docker|00 Docker]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-09-07]] +### Дополнительные материалы +- +### Дочерние заметки + + +- [[Docker compose для запуска socks5]] +- [[Файловый сервер на Samba]] + diff --git a/dev/devops/docker/Установка Docker и Docker Compose.md b/dev/devops/docker/Установка Docker и Docker Compose.md new file mode 100644 index 00000000..eb5819c2 --- /dev/null +++ b/dev/devops/docker/Установка Docker и Docker Compose.md @@ -0,0 +1,56 @@ +--- +aliases: +tags: + - maturity/🌱 +date: + - - 2024-04-07 +zero-link: + - "[[../../../meta/zero/00 Docker|00 Docker]]" +parents: +linked: +--- +Гайдов, как устанавливать docker полно в интернете. [Официальная документации](https://docs.docker.com/engine/install/) написана доступным языком. + +Команды установки docker для CentOS 8 и RHEL 8. + +```shell +sudo yum install -y yum-utils +sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo +sudo yum install docker-ce docker-ce-cli +sudo systemctl start docker +sudo systemctl enable --now docker +``` + +Также установим docker-compose. Обращаю ваше внимание, что актуальным является Docker Compose V2, который в отличие от первой версии поставляется бинарными файлами. + +```shell +mkdir -p ~/.docker/cli-plugins/ +curl -SL https://github.com/docker/compose/releases/download/v2.14.0/docker-compose-linux-x86_64 -o ~/.docker/cli-plugins/docker-compose +chmod +x ~/.docker/cli-plugins/docker-compose +``` +[Актуальная версия docker-compose](https://github.com/docker/compose/releases/) + +> [!INFO] +> Эта команда устанавливает Compose V2 для активного пользователя в каталог `$HOME`. Чтобы установить Docker Compose для всех пользователей вашей системы, замените `~/.docker/cli-plugins` на `/usr/local/lib/docker/cli-plugins`. + +Проверяем, что установка прошла успешно. + +```shell +$ docker compose version +Docker Compose 2.2.3 +``` + +> [!WARNING] +> Также обращаю ваше внимание, что в Compose V1 для работы использовалась команда `docker-compose`, а в V2 отказались от дефиса `docker compose` + +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 Docker|00 Docker]], [[../../../meta/zero/00 Docker Compose|00 Docker Compose]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-04-07]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/devops/docker/Утилита Dive.md b/dev/devops/docker/Утилита Dive.md new file mode 100644 index 00000000..b7d9e4c1 --- /dev/null +++ b/dev/devops/docker/Утилита Dive.md @@ -0,0 +1,29 @@ +--- +aliases: + - dive +tags: + - maturity/🌱 +date: + - - 2024-03-20 +--- +Dive позволяет показать отличияслоёв друг от друга: какиефайлы добавлены, какие изменены, какие удалены. + +Полезным параметром является `Potential wasted space`, который показывает на какое количество мегабайт можно сжать образ, если поправить [Dockerfile](Dockerfile.md). + +Пример работы: +```bash +dive upagge/spring-boot-docker:dockerfile +``` + +![](../../../meta/files/images/Pasted%20image%2020240320134340.png) +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 Docker|00 Docker]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-03-20]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/devops/nginx/GZIP сжатие в Nginx.md b/dev/devops/nginx/GZIP сжатие в Nginx.md new file mode 100644 index 00000000..95c5bd69 --- /dev/null +++ b/dev/devops/nginx/GZIP сжатие в Nginx.md @@ -0,0 +1,79 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-04-07 +--- +Одним из самых эффективных способов ускорить работу веб-сервера Nginx является включение GZIP-сжатия. GZIP обеспечивает сжатие без потерь, что означает, что исходные данные можно полностью восстановить при распаковке. Сжатие основано на алгоритме [DEFLATE](https://ru.wikipedia.org/wiki/Deflate), который сочетает в себе алгоритмы [LZ77](https://ru.wikipedia.org/wiki/LZ77) и [Хаффмана](https://ru.wikipedia.org/wiki/Код_Хаффмана). + +Большинство современных клиентов и серверов поддерживают GZIP. Когда браузер или другой клиент, совместимый с GZIP, запрашивает ресурс у сервера с поддержкой GZIP, сервер сжимает ответ перед отправкой. Это позволяет значительно уменьшить объем передаваемых данных и ускорить загрузку страниц. + +Пример конфигурации для включения GZIP-сжатия в Nginx. Откройте основной файл конфигурации `/etc/nginx/nginx.conf` и добавьте следующие директивы в блок `http`: + +```nginx +http { + ... + + gzip on; + gzip_min_length 500; + gzip_vary on; + gzip_proxied expired no-cache no-store private auth; + gzip_types text/plain text/css text/javascript application/javascript application/x-javascript text/xml application/xml application/xml+rss application/json; + gzip_disable "msie6"; + gzip_comp_level 6; + gzip_buffers 16 8k; + + ... +} +``` + +`gzip` — включает сжатие GZIP на сервере. + +`gzip_min_length` — устанавливает минимальный размер ответа, для которого будет применяться сжатие. По умолчанию значение равно 20 байтам, но имеет смысл установить большее значение (например, 500 байт), так как ==сжатие слишком маленьких файлов может создать ненужную нагрузку на процессоры сервера и клиента.== + +`gzip_vary` — добавляет заголовок `Vary: Accept-Encoding` в ответ сервера. Это позволяет кэшировать как сжатые, так и несжатые версии одного ресурса в зависимости от того, поддерживает ли клиент GZIP-сжатие. + +`gzip_proxied` — определяет, нужно ли сжимать ответы для проксированных запросов в зависимости от их содержимого. Запрос считается проксированным, если в его заголовке присутствует поле Via. Можно указать несколько условий для применения сжатия: + +> [!NOTE]- Параметры `gzip_proxied` +`off` отключает сжатие для всех проксированных запросов. +> +>`expired` разрешает сжатие, если в заголовке ответа есть поле Expires, запрещающее кэширование. +> +>`no-cache` сжатие разрешено, если в заголовке ответа есть поле Cache-Control с параметром no-cache. +> +>`no-store` сжатие разрешено, если в заголовке ответа есть поле Cache-Control с параметром no-store. +> +>`private` разрешает сжатие, если в заголовке ответа есть поле Cache-Control с параметром private. +> +>`no_last_modified` разрешает сжатие, если в заголовке ответа отсутствует поле Last-Modified. +> +>`no_etag` разрешает сжатие, если в заголовке ответа нет поля ETag. +> +>`auth` сжатие разрешено, если в заголовке запроса есть поле Authorization. +> +>`any` разрешает сжатие для всех проксированных запросов без ограничений. +> +>`gzip_types` по умолчанию включено сжатие для ответов типа текст. В данном параметре можно перечислить все необходимые типы ответов. +> +>`gzip_disable` запрещает для перечисленных параметров заголовка User-Agent сжатие. В данном примере для Internet Explorer 6 сжатие применяться не будет, так как данный браузер не умеет принимать сжатые ответы. + +`gzip_types` — задает список типов MIME, для которых будет применяться сжатие. По умолчанию GZIP включен для ответов типа text/\*. В данном примере сжатие включено для текстовых файлов, CSS, JavaScript и JSON. + +`gzip_disable` — отключает сжатие для определенных клиентов. В данном примере сжатие отключено для браузера Internet Explorer 6 (определяется по значению User-Agent), так как этот браузер не поддерживает работу с GZIP-ответами. + +`gzip_comp_level` — устанавливает уровень сжатия. Рекомендуемое значение — 6, так как оно обеспечивает баланс между скоростью сжатия и эффективностью (по умолчанию уровень сжатия равен 1, а максимальный — 9). + +`gzip_buffers` — задает количество и размер буферов для хранения сжатых данных перед отправкой клиенту. В данном случае установлено 16 буферов по 8К. +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 Nginx|00 Nginx]] +**Родитель**:: [[../../algorithm/GZIP|GZIP]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-04-07]] +### Дополнительные материалы +- +### Дочерние заметки + + diff --git a/dev/devops/nginx/Балансировка нагрузки в Nginx.md b/dev/devops/nginx/Балансировка нагрузки в Nginx.md new file mode 100644 index 00000000..21ebedbe --- /dev/null +++ b/dev/devops/nginx/Балансировка нагрузки в Nginx.md @@ -0,0 +1,63 @@ +--- +aliases: + - Балансировка запросов на Nginx +tags: + - maturity/🌱 +date: 2024-10-30 +--- +Блок `upstream` используется для указания списка серверов, между которыми nginx будет распределять входящие запросы, тем самым обеспечивая [[../../architecture/highload/Балансировка нагрузки|балансировку нагрузки]]. В блоке `upstream` перечисляются серверы, между которыми будет распределяться нагрузка. + +```nginx +upstream myapp { + server server1.example.com; + server server2.example.com; + server server3.example.com; +} +``` + +Затем настройте блок `server`, чтобы перенаправлять запросы к вашему блоку `upstream`. В блоке `server` используйте директиву `proxy_pass` внутри `location`, как показано ниже: + +```nginx +server { + listen 80; + + location / { + proxy_pass http://myapp; + } +} +``` +## Метод балансировки +Nginx поддерживает несколько методов балансировки нагрузки, включая round-robin (по умолчанию), least-connected и ip-hash. Вы можете выбрать нужный метод, добавив соответствующую директиву в блок `upstream`. + +```nginx +upstream myapp { + least_conn; + server server1.example.com; + server server2.example.com; + server server3.example.com; +} +``` +## Резервные сервера +Чтобы повысить отказоустойчивость, можно добавить резервные серверы, к которым будут перенаправляться запросы, если основные серверы недоступны: + +```nginx +upstream myapp { + server server1.example.com; + server server2.example.com; + server server3.example.com; + server backup.example.com backup; +} +``` +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 Nginx|00 Nginx]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-10-30]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/devops/nginx/Кэширование на стороне Nginx.md b/dev/devops/nginx/Кэширование на стороне Nginx.md new file mode 100644 index 00000000..a2f3806c --- /dev/null +++ b/dev/devops/nginx/Кэширование на стороне Nginx.md @@ -0,0 +1,69 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-04-07 +--- +Для повышения производительности можно кэшировать ответы на запросы на стороне Nginx, которые редко изменяются. Это позволяет серверу один раз получить результат от вашего приложения и в дальнейшем возвращать его другим клиентам, снижая нагрузку на приложение. + +Для начала необходимо создать директорию, в которой будут храниться данные кэша: + +```shell +sudo mkdir -p /var/nginx/cache +``` + +После этого, в основной конфигурационный файл `nginx.conf` нужно добавить несколько директив: + +```nginx +http { + proxy_cache_path /var/nginx/cache levels=1:2 keys_zone=nginxcash:60m max_size=256m inactive=24h; + proxy_cache_key "$scheme$request_method$host$request_uri"; + proxy_cache_methods GET HEAD; + proxy_cache_min_uses 2; +} +``` + +`proxy_cache_path` — указывает путь к директории, где будут храниться кэшированные данные. + +- Параметр `levels` задает структуру папок для хранения кэша, keys_zone определяет размер зоны для хранения метаданных (в данном случае 60 мегабайт). +- `max_size=256m` задает максимальный размер кэша. +- `inactive=24h` указывает, что кэшированные данные, к которым не было обращений в течение 24 часов, будут автоматически удалены. + +`proxy_cache_key` — определяет ключ кэширования. В данном случае используется комбинация схемы запроса, метода, хоста и URI. Этот ключ позволяет разделить кэш для разных поддоменов и запросов. + +`proxy_cache_methods` — указывает, какие HTTP-методы будут кэшироваться (в данном примере — только методы GET и HEAD). + +`proxy_cache_min_uses` — задает минимальное количество обращений к ресурсу перед его кэшированием. Установка значения 2 означает, что кэширование начнется только после второго обращения, что предотвращает кэширование редко используемых данных и снижает нагрузку на запись. +## Переносим кэш Nginx в RAM +Чтобы значительно ускорить кэш, можно разместить его в оперативной памяти (RAM) вместо файловой системы. Это позволит значительно сократить время доступа к кэшированным данным. + +Для этого создаем директорию для кэша (если она уже создана, нужно очистить её от содержимого) и монтируем её в RAM с помощью [tmpfs](https://wiki.archlinux.org/index.php/Tmpfs). Выделим 256 мегабайт под кэш: + +```shell +sudo mount -t tmpfs -o size=256M tmpfs /var/nginx/cache +``` + +Если потребуется отключить RAM-кэш, выполните команду: + +```shell +sudo umount /var/nginx/cache +``` + +Чтобы автоматически пересоздавать кэш в RAM после перезагрузки системы, необходимо обновить файл `/etc/fstab`. Добавьте в него следующую строку: + +```txt +tmpfs /var/nginx/cache tmpfs defaults,size=256M 0 0 +``` +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 Nginx|00 Nginx]] +**Родитель**:: [[../../architecture/Кэширование|Кэширование]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-04-07]] +### Дополнительные материалы +- [Оптимизация NGINX](https://struchkov.dev/blog/ru/nginx-optimization/) +- [Nginx cache: всё новое — хорошо забытое старое / Хабр](https://habr.com/ru/post/428127/) +- [[../../devops/nginx/Кэширование статики в Nginx|Кэширование статики в Nginx]] +### Дочерние заметки + diff --git a/dev/devops/nginx/Кэширование статики в Nginx.md b/dev/devops/nginx/Кэширование статики в Nginx.md new file mode 100644 index 00000000..e9e22504 --- /dev/null +++ b/dev/devops/nginx/Кэширование статики в Nginx.md @@ -0,0 +1,38 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-04-07 +--- +Чтобы настроить кэширование статического контента, можно добавить следующие директивы в основной конфигурационный файл Nginx: + +```nginx +server { + ... + + # Media + location ~* \.(?:jpg|jpeg|gif|png|ico|cur|gz|svg|mp4|ogg|ogv|webm|htc)$ { + expires 30d; + } + + # CSS and Js + location ~* \.(css|js|woff2)$ { + expires 365d; + } + + ... +} +``` + +В этом примере медиа-файлы, такие как изображения и видео, будут кэшироваться на 30 дней, а файлы CSS, JS и шрифты — на 365 дней. +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 Nginx|00 Nginx]] +**Родитель**:: [[../../architecture/highload/Кэширование на стороне браузера|Кэширование на стороне браузера]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-04-07]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/devops/Очистка Nexus Sonatype.md b/dev/devops/Очистка Nexus Sonatype.md new file mode 100644 index 00000000..18a12551 --- /dev/null +++ b/dev/devops/Очистка Nexus Sonatype.md @@ -0,0 +1,39 @@ +--- +aliases: +tags: + - maturity/🌱 +date: + - - 2024-09-03 +zero-link: +parents: [] +linked: +--- +Со временем артефакты будут накапливаться в Nexus и занимать дисковое пространство. Необходимо настроить политики очистки данных, а также добавить задачи на запуск по расписанию, чтобы все происходило в автоматическом режиме. +## Cleanup Policies +В настройках администрирования есть пункт `Repository > Cleanup Policies`. Он позволяет задать правила удаления артефактов. + + +> [!WARNING] Политики не выполняются +> На этом этапе мы лишь описываем политики. Автоматически они не применяются. Чтобы они применялись необходимо зайти в пункт `Repository > Repositories` выбрать нужный репозиторий и найти пункт Cleanup Policies, в котором можно выбрать созданные политики. Именно они и будут применяться. +> +> Но и это еще не все. Необходимо зайти в раздел `System > Tasks` и убедиться в наличии или настроить автоматическое выполнение задачи по очистке: Cleanup service. Именно она запсукает процесс очистки + +## Дополнительные задачи очистки +Но и этого мало. Необходимо перейти в раздел `System > Tasks` и настроить еще несколько полезных задач. + +Выполнять их лучше в определенном порядке +- **Cleanup Policies**. Выполняет ранее настроенные политики. +- **Delete Incomplete Uploads**. Предназначена для удаления неполных загрузок, которые могли возникнуть из-за прерванных или неудачных операций загрузки артефактов в репозитории. +- **Delete unused manifests and images**. Позволяет удалять docker слои, которые потеряли связь с тегами. +- **Compact Blob Store**. Предназначена для оптимизации путем удаления удаленных или помеченных на удаление блобов, которые больше не связаны с какими-либо компонентами. То есть не все удаляется, некоторые блобы помечаются к удалению, но занимают место, эта задача окончательно их удаляет. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 DevOps|00 DevOps]] +**Родитель**:: [[../../../../_inbox/Nexus Sonatype|Nexus Sonatype]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-09-03]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/efficiency/Don't Repeat Yourself.md b/dev/efficiency/Don't Repeat Yourself.md new file mode 100644 index 00000000..a2ac2f16 --- /dev/null +++ b/dev/efficiency/Don't Repeat Yourself.md @@ -0,0 +1,36 @@ +--- +aliases: + - DRY +tags: + - maturity/🌱 +date: 2024-11-24 +--- +Принцип DRY направлен на устранение избыточности в коде и обеспечение его поддерживаемости. + +Суть принципа DRY заключается в том, чтобы избегать дублирования информации, логики или кода. Каждая часть функциональности системы должна быть реализована в одном месте, чтобы избежать дублирования. Это помогает избежать ситуаций, когда один и тот же код приходится изменять в нескольких местах, что увеличивает риск ошибок и усложняет поддержку. + +Также принцип DRY часто применяется при проектировании базы данных. Когда данные нормализованы, однотипная информация хранится в одном месте, что снижает избыточность и упрощает её изменение. + +**Преимущества принципа DRY** +- **Упрощение поддержки**. Когда логика сосредоточена в одном месте, любые изменения в ней вносятся единожды, что делает код проще в сопровождении. Например, если логика вычисления налогов вынесена в отдельный модуль, изменения в налоговых правилах потребуют правки только в этом модуле. Это снижает вероятность ошибок и помогает быстрее вносить правки. +- **Улучшение читаемости**. Код, в котором нет дублирования, проще читать и понимать. Каждый модуль или компонент [[../architecture/Single Responsibility Principle|выполняет свою конкретную задачу]], что улучшает структуру и восприятие проекта. +- **Снижение рисков ошибок**. Дублированный код часто ведет к несогласованности и ошибкам при изменениях. DRY помогает поддерживать целостность системы и снижает риск возникновения ошибок из-за некорректных правок в одном из дублирующихся мест. +- **Ускорение разработки**. Избавление от дублирования позволяет быстрее добавлять новые функции или изменять существующие, поскольку разработчики могут сосредоточиться на одной реализации, а не искать все места, где повторяется похожий код. + +**Примеры нарушения DRY** +- Дублирование одного и того же кода в разных модулях вместо вынесения его в общий компонент. +- Копирование и вставка бизнес-логики вместо использования общих методов. +- Повторное хранение одинаковой информации в разных таблицах базы данных. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Эффективная разработка|00 Эффективная разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-24]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/efficiency/Keep It Simple, Stupid.md b/dev/efficiency/Keep It Simple, Stupid.md new file mode 100644 index 00000000..9fafc6a4 --- /dev/null +++ b/dev/efficiency/Keep It Simple, Stupid.md @@ -0,0 +1,41 @@ +--- +aliases: + - KISS +tags: + - maturity/🌱 +date: 2024-11-24 +--- +Принцип KISS — это один из ключевых подходов в программировании и инженерии, подчеркивающий важность простоты в проектах и системах. Аббревиатура KISS расшифровывается как "Keep It Simple, Stupid", что можно перевести как "Делай проще, глупец". Несмотря на довольно грубую формулировку, основная цель этого принципа — подчеркивать важность простоты и избегать излишней сложности при разработке. + +Суть KISS заключается в том, что ==решения должны быть настолько простыми, насколько это возможно.== Это предполагает минимальное количество зависимостей, отсутствие лишних функций и легкость [[../Читаемый код|понимания кода]]. Вся система или её части должны быть доступны для понимания как опытным разработчикам, так и тем, кто только подключился к проекту. + +Следование принципу KISS предполагает избегание сложных архитектур и предпочтение более простых решений, когда это возможно. Например, если функциональность можно реализовать с помощью простого цикла и пары условий, лучше не добавлять сложные шаблоны проектирования без явной необходимости. + +Часто разработчики сталкиваются с искушением использовать модные технологии или сложные архитектурные решения, чтобы продемонстрировать свои навыки. Однако KISS напоминает о том, что код должен в первую очередь решать задачу, а не демонстрировать мастерство программиста. + +В конечном итоге, KISS помогает создавать устойчивые и поддерживаемые проекты, что особенно важно в условиях ограниченного времени и ресурсов. + +**Преимущества принципа KISS** +1. **Легкость поддержки**. Простые решения требуют меньше усилий на поддержку. Например, использование стандартных библиотек вместо написания собственных решений позволяет сократить количество кода и облегчить его поддержку. В случае возникновения ошибок, их гораздо проще найти и исправить. +2. **Масштабируемость**. Чем проще система, тем легче её масштабировать, добавляя новые модули или функции без риска повредить основную логику. +3. Улучшение [[../Читаемый код|читаемости кода]]. Простой код проще читать, а значит, его легче понимать новым членам команды. Это снижает порог вхождения для новых разработчиков. +4. **Снижение рисков ошибок**. Чем меньше сложностей, тем ниже вероятность возникновения ошибок, связанных с избыточной логикой или излишними зависимостями. +5. Простота также способствует более быстрой адаптации новых членов команды, так как упрощает понимание системы и сокращает время на освоение кода. + +**Примеры нарушения KISS** +- Использование излишне сложных паттернов там, где можно обойтись простым решением. +- Добавление ненужных абстракций, которые затрудняют понимание структуры кода. +- Введение избыточных зависимостей, которые усложняют настройку и поддержку системы. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Эффективная разработка|00 Эффективная разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-24]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/efficiency/TechTalk.md b/dev/efficiency/TechTalk.md new file mode 100644 index 00000000..732a961f --- /dev/null +++ b/dev/efficiency/TechTalk.md @@ -0,0 +1,42 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-11-24 +--- +TechTalk — это особенный формат общения для технических специалистов. Здесь можно не только обменяться знаниями и опытом, но и обсудить актуальные тенденции, новые технологии и подходы. + +TechTalk может быть как внутренним мероприятием в компании, так и публичным событием, доступным для широкой аудитории. + +- **Внутренние TechTalks**: Отличная возможность для команды делиться своими наработками, исследовать новые технологии и находить свежие идеи для решений задач. Это также способствует развитию корпоративной культуры и укреплению связей между сотрудниками. +- **Публичные TechTalks**: Открывают доступ к опыту ведущих экспертов отрасли, позволяя участникам узнать о лучших практиках и наработках, а также вдохновиться чужими успехами. Это также хороший способ для компаний заявить о себе на рынке. + +**Преимущества TechTalk** +1. **Обмен опытом и знаниями**: Главная ценность TechTalk заключается в обмене опытом и знаниями. ==Участники делятся не только успехами, но и неудачами==, что помогает другим избегать подобных ошибок в своих проектах. +2. **Интерактивное взаимодействие**: В отличие от стандартных докладов на конференциях, TechTalks более интерактивны и предполагают обсуждение и вопросы, что помогает углубляться в детали и находить новые точки зрения на уже знакомые темы. +3. **Профессиональное развитие**: Такие мероприятия позволяют развивать навыки публичных выступлений, улучшать коммуникативные навыки и становиться более уверенным в своих знаниях. +4. **Культура открытости**: Создание атмосферы, где каждый может свободно поделиться своими идеями и обсудить волнующие вопросы, способствует развитию культуры открытости и инноваций в компании. + +**Недостатки TechTalk** +1. **Требует времени и подготовки**: Организация и проведение TechTalk требует значительных временных и организационных затрат. Нужно подготовить материалы, организовать пространство и время для мероприятия. +2. **Не все участники готовы выступать**: Не всем специалистам комфортно выступать перед аудиторией, что может создавать препятствия для обмена знаниями. +3. **Перегруз информацией**: Иногда в рамках TechTalk может быть представлено слишком много информации, что затрудняет усвоение материала, особенно если тематика сложная или новая для участников. + +**Как организовать успешный TechTalk** +1. **Определение темы**: Тема должна быть актуальной и интересной для аудитории. Лучше всего выбирать темы, которые позволяют участникам делиться практическим опытом. +2. **Подготовка спикеров**: Спикерам нужно заранее помочь в подготовке материалов и презентации. Это может включать репетиции и предоставление обратной связи. +3. **Интерактивный формат**: Включайте вопросы и обсуждения, чтобы аудитория могла активно участвовать в процессе. Это делает мероприятие более живым и полезным для всех участников. +4. **Продолжительность**: Не затягивайте мероприятие. Оптимальная продолжительность TechTalk — 30-60 минут, чтобы участники не теряли интерес и могли усвоить представленный материал. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Эффективная разработка|00 Эффективная разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-24]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/efficiency/You Aren’t Gonna Need It.md b/dev/efficiency/You Aren’t Gonna Need It.md new file mode 100644 index 00000000..f60555f5 --- /dev/null +++ b/dev/efficiency/You Aren’t Gonna Need It.md @@ -0,0 +1,26 @@ +--- +aliases: + - YAGNI +tags: + - maturity/🌱 +date: 2024-11-27 +--- +YAGNI (You Aren’t Gonna Need It) — это принцип разработки, который гласит: “Не реализовывайте функционал или код в надежде, что он может понадобиться в будущем.” + +**Почему это важно?** +- **Код становится проще**. Самый простой код — это отсутствие кода. Любая строчка, которая добавляется, должна быть действительно необходимой. +- **Избегание чрезмерной инженерии**. Overengineering (чрезмерное проектирование) — это создание сложных решений, которые оказываются избыточными для текущих задач. Пример: разработка универсального механизма вместо простого рабочего решения. +- **Фокус на MVP**. Работайте над минимально жизнеспособным продуктом (MVP), реализуя только критически важный функционал. Лишние детали можно добавить позже, если они действительно потребуются. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Эффективная разработка|00 Эффективная разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-27]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/efficiency/Рефакторинг кода.md b/dev/efficiency/Рефакторинг кода.md new file mode 100644 index 00000000..5c033c6c --- /dev/null +++ b/dev/efficiency/Рефакторинг кода.md @@ -0,0 +1,24 @@ +--- +aliases: + - рефакторинг + - рефакторинга +tags: + - maturity/🌱 +date: 2024-11-24 +--- +Рефакторинг — это процесс улучшения существующего кода **без изменения его функциональности**. + +Регулярный рефакторинг помогает избавиться от неудачных решений ([[../../muesli/Исторически так сложилось|Исторически так сложилось]]), которые усложняют понимание системы. Устраняя технический долг, команда уменьшает количество контекста, который необходимо удерживать в голове, и делает код понятнее. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Эффективная разработка|00 Эффективная разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-24]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/efficiency/Снижение когнитивной нагрузки при разработке.md b/dev/efficiency/Снижение когнитивной нагрузки при разработке.md new file mode 100644 index 00000000..e5929be0 --- /dev/null +++ b/dev/efficiency/Снижение когнитивной нагрузки при разработке.md @@ -0,0 +1,32 @@ +--- +aliases: + - когнитивную нагрузку + - снижать когнетивную нагрузку + - Снижение когнитивной нагрузки +tags: + - maturity/🌱 +date: 2024-11-24 +--- +Когнитивная нагрузка — это объем ментальных усилий, который разработчики прикладывают для выполнения своих задач. Слишком высокая когнитивная нагрузка может приводить к ошибкам, снижению продуктивности и [[../../../../knowledge/health/болезни/Эмоциональное выгорание|выгоранию]]. Поэтому важно принимать меры по ее снижению. Рассмотрим, какие практики помогают уменьшить нагрузку и сделать процесс разработки более комфортным и эффективным. + +- [[Стандартизация подходов в разработке]] +- [[Keep It Simple, Stupid]] +- [[Рефакторинг кода]] +- Документация и [[../Комментарии в коде|комментирование кода]] +- [[Don't Repeat Yourself]] +- [[../architecture/Bounded Context|Bounded Context]] +- **Разделение задач на мелкие части**. Разделение больших задач на мелкие и четко определенные части позволяет легче управлять процессом разработки и снижает когнитивную нагрузку. Выполнение небольшой задачи проще и требует меньше усилий, чем работа с большим блоком, который трудно полностью удержать в голове. +- **Инструменты автоматизации** Инструменты, которые автоматизируют повторяющиеся действия, значительно снижают когнитивную нагрузку. Например, использование систем CI/CD для автоматической сборки и тестирования, статического анализа кода и инструментов мониторинга позволяет не отвлекаться на рутину и сосредоточиться на решении более сложных задач. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Эффективная разработка|00 Эффективная разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-24]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/efficiency/Соглашение о наименовании.md b/dev/efficiency/Соглашение о наименовании.md new file mode 100644 index 00000000..08bc010c --- /dev/null +++ b/dev/efficiency/Соглашение о наименовании.md @@ -0,0 +1,37 @@ +--- +aliases: + - осмысленные имена + - соглашений о наименовании + - правила именования +tags: + - maturity/🌱 +date: 2024-11-24 +--- +Одним из важнейших аспектов [[Чистый код|чистого кода]] является соблюдение правил именования. Понятные и согласованные имена позволяют улучшить читаемость и поддержку вашего кода. Рассмотрим несколько ключевых принципов: +## Соблюдайте соглашения стиля +Используйте общепринятые соглашения стиля для вашего языка программирования. Например, `camelCase` для переменных и методов, а `PascalCase` — для классов. Соглашения стиля могут варьироваться в зависимости от проекта или команды, и важно придерживаться общепринятых правил в данной среде. ==Важно соблюдать единообразие в стиле, чтобы упрощать навигацию по коду и снижать [[Снижение когнитивной нагрузки при разработке|когнитивную нагрузку]].== +## Выбирайте описательные имена +Чем точнее имя, тем легче понять назначение функции или переменной. Например, если функция конвертирует валюты, дайте ей имя, которое явно указывает на её назначение, а не абстрактное название вроде `convert`. + +Описательные имена облегчают понимание и поддержку кода, но важно сохранять баланс между описательностью и длиной имени, чтобы избежать чрезмерно длинных названий. Описательные имена облегчают понимание и поддержку кода. +## Избегайте двусмысленных названий +Избегайте абстрактных названий, которые могут вызвать неясности. Например, если работаете с валютами, используйте явные обозначения, такие как `usdToEur`, чтобы избежать путаницы с другими типами долларов (США, Австралии, Канады и т.д.). Также рекомендуется использовать общеизвестные аббревиатуры для валют, если это делает код короче и при этом понятным. +## Используйте произносимые имена +Не сокращайте названия переменных до непонятных сокращений, вроде `cstmrLst`, когда можно использовать `customerList`. Это снижает [[Снижение когнитивной нагрузки при разработке|когнитивную нагрузку]] и делает код более доступным для чтения. Использование полных слов также помогает при устном обсуждении кода в команде. +## Избегайте магических чисел +Если в вашем коде присутствуют числовые значения, например коэффициент `0.9` для какой-либо операции, не вставляйте его напрямую. Определите его как константу, например, `CONVERSION_RATE = 0.9`, и используйте это имя в расчетах. Такой подход делает код более понятным и облегчает его поддержку, а также помогает избежать ошибок при изменении значений в будущем. Использование констант также облегчает автоматическое документирование и улучшает понимание кода новыми разработчиками. +## Чтение кода должно быть легким +Читатели вашего кода должны сосредотачиваться на логике, а не пытаться расшифровать странные имена переменных и функций. Чем понятнее ваш код, тем проще его поддерживать и развивать. Также рекомендуется использовать [[Комментарии в коде|комментарии в коде]], если имена переменных или логика могут быть неочевидными. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Эффективная разработка|00 Эффективная разработка]] +**Родитель**:: [[Чистый код]] +**Источник**:: +**Создана**:: [[2024-11-24]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/efficiency/Стандартизация подходов в разработке.md b/dev/efficiency/Стандартизация подходов в разработке.md new file mode 100644 index 00000000..b6d1840a --- /dev/null +++ b/dev/efficiency/Стандартизация подходов в разработке.md @@ -0,0 +1,25 @@ +--- +aliases: + - стандартизация подходов +tags: + - maturity/🌱 +date: 2024-11-24 +--- +Чем больше команда придерживается общих стандартов кода и архитектуры, тем проще разработчикам работать с чужим кодом. Наличие стандартов снижает потребность каждый раз принимать решения и позволяет быстро понять, как устроены те или иные части системы. + +Практики, которые позволяют снизить когнетивную нагрузку: +- [[Соглашение о наименовании|Соглашение о наименовании]] +- [[../architecture/Паттерн проектирования|Паттерн проектирования]] +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Эффективная разработка|00 Эффективная разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-24]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/efficiency/Чистый код.md b/dev/efficiency/Чистый код.md new file mode 100644 index 00000000..9df817fd --- /dev/null +++ b/dev/efficiency/Чистый код.md @@ -0,0 +1,24 @@ +--- +aliases: + - чистого кода +tags: + - maturity/🌱 +date: 2024-11-24 +--- +- [[Соглашение о наименовании]] +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Эффективная разработка|00 Эффективная разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-24]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + +- [[Соглашение о наименовании]] + + diff --git a/dev/fundamental/Cache coherence.md b/dev/fundamental/Cache coherence.md new file mode 100644 index 00000000..5fdb7478 --- /dev/null +++ b/dev/fundamental/Cache coherence.md @@ -0,0 +1,34 @@ +--- +aliases: + - кэш-кохерентность + - кэш-кохерентности + - кэш-кохерентностью +tags: + - maturity/🌱 +date: 2024-10-12 +zero-link: +parents: +linked: +--- +Когда [[Центральный процессор|процессор]] имеет несколько [[Ядро процессора|ядер]], каждое из них может иметь собственный [[Кэш процессора|кэш процессора]], что приводит к проблеме кэш-кохерентности. Она возникает, когда одно ядро изменяет данные, находящиеся в его кэше, а другие ядра продолжают использовать устаревшую версию этих данных из своего кэша. В результате возникает рассинхронизация, что может привести к некорректной работе программ, особенно в многозадачных системах. + +Для решения этой проблемы используются протоколы кэш-кохерентности: +- [[MESI]]. Один из наиболее распространенных. +- MOESI +- MESIF +*** +## Мета информация +**Область**:: +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-10-12]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + +- [[MESI]] + + diff --git a/dev/fundamental/Concurrency.md b/dev/fundamental/Concurrency.md new file mode 100644 index 00000000..89388756 --- /dev/null +++ b/dev/fundamental/Concurrency.md @@ -0,0 +1,37 @@ +--- +aliases: + - конкурентность + - конкурентна + - конкурентности +tags: + - maturity/🌱 +date: 2024-09-10 +zero-link: [] +parents: +linked: +--- +Конкурентность — это общий термин, описывающий способность программы обрабатывать несколько задач. ==Это не обязательно означает одновременное выполнение.== + +[[Parallelism]]. Физическое одновременное выполнение нескольких задач на разных ядрах или процессорах. Параллелизм является формой конкурентности, но требует аппаратной поддержки для одновременного выполнения. + +**Механизмы реализации конкурентности** +- [[Многозадачность|Multitasking]]. +- [[Multithreading]]. Использование нескольких потоков внутри одного процесса. Потоки могут выполняться конкурентно, разделяя память и ресурсы процесса. Также требует механизма переключения контекстов, но на уровне потоков. +- [[../architecture/Асинхронное программирование]] +- [[../architecture/Реактивное программирование|Реактивное программирование]] + +![[../../meta/files/images/telegram-cloud-photo-size-2-5271536941378167546-y.jpg]] +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Разработка|00 Разработка]] +**Родитель**:: [[Многозадачность|Multitasking]] +**Источник**:: +**Создана**:: [[2024-09-10]] +**Автор**:: +### Дополнительные материалы +- [[Parallelism]] +### Дочерние заметки + + +- [[Многозадачность]] + diff --git a/dev/fundamental/Copy-on-write.md b/dev/fundamental/Copy-on-write.md new file mode 100644 index 00000000..71f6f7c7 --- /dev/null +++ b/dev/fundamental/Copy-on-write.md @@ -0,0 +1,45 @@ +--- +aliases: + - COW +tags: + - maturity/🌱 +date: 2024-09-17 +zero-link: +parents: +linked: +--- +Copy-on-Write (COW) — это техника оптимизации управления памятью, используемая в [[../../../../knowledge/dev/pc/Операционная система|операционных системах]] для эффективного копирования данных, особенно в контексте [[Многозадачность|многозадачности]] и управления виртуальной памятью. Этот метод позволяет нескольким процессам совместно использовать одну и ту же страницу памяти до тех пор, пока данные не нужно будет изменить, что экономит ресурсы и ускоряет выполнение программ. + +**Как работает Copy-on-Write:** +- **Совместное использование страниц:** Когда [[Процесс ОС|процесс]] создаёт копию себя (например, при вызове fork() в UNIX-подобных системах), операционная система не копирует все [[Страница|страницы]] памяти сразу. Вместо этого родительский и дочерний процессы продолжают совместно использовать одни и те же страницы памяти. +- **Установка флага защиты:** Страницы, используемые в режиме Copy-on-Write, помечаются как «только для чтения» для обоих процессов. Это означает, что оба процесса могут читать данные без необходимости создания отдельных копий для каждого из них. +- **Промах страницы** ([[Page Fault]]) при записи: Если один из процессов пытается изменить данные на странице, происходит Page Fault. Операционная система понимает, что требуется изменить данные, которые в данный момент используются совместно, и инициирует Copy-on-Write. +- **Создание копии страницы:** Операционная система создаёт отдельную копию страницы только для того процесса, который пытается внести изменения. В результате изменения затрагивают только копию, а остальные процессы продолжают использовать оригинальную страницу без изменений. +- **Обновление таблицы страниц:** После создания копии, таблица страниц соответствующего процесса обновляется, чтобы указывать на новую копию страницы, которая теперь доступна для записи. + +**Примеры использования:** +- **Процессы и fork():** Когда выполняется fork(), дочерний процесс получает копию адресного пространства родительского процесса. Copy-on-Write позволяет избежать полной копии всех данных сразу, экономя время и память. +- **Виртуальные машины и контейнеры:** Виртуальные машины и контейнеры часто используют Copy-on-Write для совместного использования одинаковых библиотек и данных между разными экземплярами. +- **Файловые системы (например, Btrfs, ZFS):** Некоторые файловые системы используют Copy-on-Write для создания снимков (snapshot) и клонирования данных без необходимости немедленного копирования всех данных. + +**Преимущества Copy-on-Write:** +- **Экономия памяти:** Позволяет избежать дублирования данных до тех пор, пока это действительно не нужно, что снижает расход оперативной памяти. +- **Ускорение выполнения:** Процессы могут начинать работать быстрее, поскольку нет необходимости мгновенно копировать большие объемы данных. +- **Гибкость и безопасность:** Совместное использование данных безопасно до тех пор, пока нет попыток изменить данные, что упрощает управление памятью. + +**Недостатки Copy-on-Write:** +- **Задержки при записи:** При попытке записи возникает задержка из-за необходимости создания копии страницы, что может вызывать временное снижение производительности. +- **Усложнение управления памятью:** Операционная система должна отслеживать и обрабатывать копии страниц, что усложняет управление виртуальной памятью. +- **Дополнительные Page Faults:** Copy-on-Write приводит к большему числу Page Faults, так как любое изменение данных требует создания новой копии страницы. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Разработка|00 Разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-09-17]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + diff --git a/dev/fundamental/Deadlock.md b/dev/fundamental/Deadlock.md new file mode 100644 index 00000000..f9c4ce7b --- /dev/null +++ b/dev/fundamental/Deadlock.md @@ -0,0 +1,43 @@ +--- +aliases: +tags: + - maturity/🌱 +date: + - - 2024-06-20 +zero-link: +parents: +linked: +--- +Дедлок — это ситуация, при которой два или более [[Поток процесса ОС|потока]] блокируют друг друга, ожидая освобождения ресурсов, которые удерживаются другим потоком. Чтобы понять это, нужно рассмотреть, что такое «блокировки» и «ресурсы». + +[[Блокировка]] — это способ «захвата» ресурса, чтобы предотвратить доступ других потоков к этому ресурсу до завершения текущей операции. + +Ресурс может быть любой частью программы, к которой требуется эксклюзивный доступ: файл, переменная, раздел памяти или даже объект базы данных. + +Простой пример дедлока: +- Поток A захватывает ресурс 1 (например, файл) и пытается получить доступ к ресурсу 2 (например, переменной), но этот ресурс уже захвачен потоком B. +- Поток B захватывает ресурс 2 и пытается получить доступ к ресурсу 1, который удерживается потоком A. + +В результате оба потока зависают — каждый ждёт освобождения ресурса, который удерживает другой поток. Это называется дедлоком, и программа перестаёт выполнять свои задачи, так как ни один из потоков не может продолжить работу. + +**Советы:** +- Делать транзакции короче. +- Выполнить повторно откатившуюся транзакцию + +**Что реально поможет:** +- Разделить потоки чтения и записи: [CQRS](CQRS.md) +- Использовать материализованные view. +- Изменить порядок блокировок ресурсов. Если в разных операциях блокируется определенный набор ресурсов, то блокироваться первым должен всегда один и тот же ресурс +- Пересмотреть [Уровни изоляций транзакций БД](Уровни%20изоляций%20транзакций%20БД.md) +- Сразу использовать Exclusive lock. Но это сильно может сказаться на производительности. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Разработка|00 Разработка]] +**Родитель**:: [[Multithreading|Многопоточность]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-06-20]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/fundamental/MESI.md b/dev/fundamental/MESI.md new file mode 100644 index 00000000..349c4eeb --- /dev/null +++ b/dev/fundamental/MESI.md @@ -0,0 +1,31 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-10-12 +zero-link: +parents: +linked: +--- +Название MESI происходит от четырех состояний, в которых могут находиться данные в [[Кэш процессора|кэше процессора]]: + +- **M (Modified)** — данные изменены в кэше ядра и не синхронизированы с оперативной памятью. +- **E (Exclusive)** — данные находятся только в кэше этого ядра и соответствуют содержимому памяти. +- **S (Shared)** — данные разделены между несколькими ядрами, и их копии синхронизированы с памятью. +- **I (Invalid)** — данные в кэше недействительны, потому что они были изменены другим ядром или сброшены. + +==Когда одно ядро изменяет данные в своем кэше, протокол MESI уведомляет другие ядра о том, что их копии этих данных больше не актуальны==. Это позволяет поддерживать согласованность данных между ядрами и предотвращает возможные ошибки. + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ЭВМ|00 Архитектура ЭВМ]] +**Родитель**:: [[Cache coherence]] +**Источник**:: +**Создана**:: [[2024-10-12]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/fundamental/Multithreading.md b/dev/fundamental/Multithreading.md new file mode 100644 index 00000000..0d774019 --- /dev/null +++ b/dev/fundamental/Multithreading.md @@ -0,0 +1,27 @@ +--- +aliases: + - Многопоточность + - многопоточности +tags: + - maturity/🌱 +date: 2024-10-08 +zero-link: +parents: +linked: +--- +**Многопоточность** — это одна из форм реализации [[Concurrency|конкурентности]], где задачи исполняются в виде отдельных [[Поток процесса ОС|потоков]] (threads) в рамках одного процесса. + +Потоки могут выполняться параллельно ([[Parallelism]]) (если система многопроцессорная или многоядерная) или чередоваться на одном процессорном ядре, если ядер меньше, чем потоков. Потоки в одном процессе разделяют общие ресурсы, такие как память, что делает многопоточность эффективной для задач, где требуется обмен данными между потоками. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Разработка|00 Разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-10-08]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/fundamental/Non-Uniform Memory Access.md b/dev/fundamental/Non-Uniform Memory Access.md new file mode 100644 index 00000000..52c69e9e --- /dev/null +++ b/dev/fundamental/Non-Uniform Memory Access.md @@ -0,0 +1,30 @@ +--- +aliases: + - NUMA +tags: + - maturity/🌱 +date: 2024-10-12 +zero-link: +parents: +linked: +--- +**NUMA (Non-Uniform Memory Access)** — это архитектура памяти, используемая в многопроцессорных системах, где время доступа к оперативной памяти зависит от физического расположения [[Центральный процессор|процессора]] и модулей памяти. + +В традиционной архитектуре **UMA (Uniform Memory Access)**, время доступа ко всей памяти одинаково для всех процессоров, что ограничивает масштабируемость. В NUMA же каждый процессор имеет собственную локальную память, к которой он получает доступ быстрее, чем к памяти, расположенной у другого процессора. + +NUMA может существенно влиять на работу [[Кэш процессора|кэш-памяти]]. Поскольку кэш каждого процессора хранит данные, связанные с его локальной памятью, доступ к удаленной памяти требует дополнительной синхронизации и согласования данных. В многоядерных системах это приводит к более сложным задачам по управлению [[Cache coherence|кэш-кохерентностью]], чтобы предотвратить несогласованность данных между ядрами, особенно при частом доступе к удаленным данным. + +В системах с NUMA также важно правильно распределять задачи между ядрами, чтобы минимизировать обращения к удаленной памяти и максимально использовать локальную память и кэш. Программисты могут оптимизировать производительность таких систем с помощью NUMA-aware алгоритмов, распределяя данные и задачи таким образом, чтобы кэш эффективно использовался в пределах каждого процессора и минимизировался доступ к удаленной памяти. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ЭВМ|00 Архитектура ЭВМ]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-10-12]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/fundamental/Parallelism.md b/dev/fundamental/Parallelism.md new file mode 100644 index 00000000..22b9dfa1 --- /dev/null +++ b/dev/fundamental/Parallelism.md @@ -0,0 +1,27 @@ +--- +aliases: + - параллелизм + - параллельно +tags: + - maturity/🌱 +date: 2024-09-10 +zero-link: +parents: +linked: +--- +Параллелизм это один из методов реализации [[Concurrency|конкурентности]]. Он предполагает ==выполнение нескольких задач одновременно, каждая из которых выполняется на отдельном процессорном ядре.== Это достигается на многоядерных системах, где каждое [[Ядро процессора|ядро]] может работать над своей задачей. Например, если у вас четыре ядра и четыре задачи, каждое ядро будет выполнять свою задачу параллельно, ускоряя процесс выполнения. + +[[Закон Амдала]]. Если значительная часть задачи выполняется последовательно, то добавление процессоров мало повлияет на ускорение. + +![[../../meta/files/images/telegram-cloud-photo-size-2-5271536941378167546-y.jpg]] +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Разработка|00 Разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-09-10]] +**Автор**:: +### Дополнительные материалы +- [[Concurrency]] +### Дочерние заметки + diff --git a/dev/fundamental/Slab allocator.md b/dev/fundamental/Slab allocator.md new file mode 100644 index 00000000..d96cc3a5 --- /dev/null +++ b/dev/fundamental/Slab allocator.md @@ -0,0 +1,39 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-09-19 +zero-link: + - "[[../../meta/zero/00 Разработка|00 Разработка]]" +parents: + - "[[../../../../knowledge/dev/Аллокация|Аллокация]]" +linked: +--- +Slab allocator — это метод выделения памяти, который используется для управления объектами фиксированного размера, таких как структуры данных или буферы в ядре операционной системы (например, в Linux). Он помогает оптимизировать использование памяти и уменьшить фрагментацию. + +Slab allocator делит память на несколько областей, называемых **slabs** (слабы). Каждая slab — это блок памяти, который может содержать несколько объектов одного и того же размера. Когда требуется выделить память для объекта, система аллокатора выделяет память из заранее подготовленного блока slab, что делает процесс выделения и освобождения очень быстрым. + +Вот основные концепции: +- **Slab** — это область памяти, содержащая несколько объектов одного типа и размера. +- **Cache (кэш)** — набор slabs, который управляется для определённого типа объекта. Каждый кэш предназначен для объектов одного типа (например, для структур данных). +- **Page ([[Страница|страница]])** — это базовая единица памяти, используемая системой (обычно 4 КБ), которая может содержать один или несколько slabs. + +**Почему это эффективно?** +- **Уменьшение фрагментации**: slab allocator позволяет эффективно использовать память для объектов одного типа и размера, избегая проблем с фрагментацией памяти. +- **Быстрое выделение/освобождение**: поскольку память выделяется из заранее подготовленных областей, процесс выделения и освобождения памяти выполняется быстрее. +- **Оптимизация работы кэша процессора**: объекты одного типа часто используются вместе, что улучшает работу кэша процессора. + +**Пример использования** +- Slab allocator широко используется в ядре Linux для управления памятью ядра. Он выделяет память для часто используемых структур данных, таких как дескрипторы файлов, процессы и буферы ввода-вывода. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Разработка|00 Разработка]] +**Родитель**:: [[../../../../knowledge/dev/Аллокация|Аллокация]] +**Источник**:: +**Создана**:: [[2024-09-19]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + diff --git a/dev/fundamental/Tree.md b/dev/fundamental/Tree.md new file mode 100644 index 00000000..c7c82771 --- /dev/null +++ b/dev/fundamental/Tree.md @@ -0,0 +1,38 @@ +--- +aliases: + - дерево +tags: + - maturity/🌱 +date: 2024-09-17 +--- +Дерево — это иерархическая структура данных, состоящая из узлов (вершин), которые связаны друг с другом ребрами. Главные характеристики деревьев: +- Корень: Узел, с которого начинается дерево. У него нет родительского узла. +- Листья: Узлы, которые не имеют дочерних узлов. +- Уровни: Глубина или высота узла относительно корня. +- Родители и потомки: В каждом узле, кроме корня, есть родитель, и могут быть дочерние узлы (потомки). + +Виды деревьев: +- [[structure/Бинарное дерево поиска|Бинарное дерево]]: Каждый узел имеет не более двух потомков — левый и правый. +- Двоичное дерево поиска (Binary Search Tree, BST): [[structure/Бинарное дерево поиска|Бинарное дерево]], в котором левый потомок содержит значения меньше родительского узла, а правый — больше. +- AVL-дерево: [[structure/Сбалансированное дерево|Сбалансированное]] [[structure/Бинарное дерево поиска|бинарное дерево поиска]], в котором разница высот левого и правого поддерева любого узла не превышает 1. +- Красно-черное дерево: [[structure/Бинарное дерево поиска|Бинарное дерево поиска]], которое поддерживает балансировку путём соблюдения определённых свойств цветных узлов. +- [[structure/B-tree]] (B-дерево): Обобщение бинарного дерева для случаев, когда узлы могут иметь больше двух потомков, эффективно используемое для больших данных. +- B+-дерево: Вариант B-дерева, в котором все ключи хранятся только в листьях, а внутренние узлы используются только для направления поиска. +- Trie: Префиксное дерево, используемое для хранения строк, где каждый узел представляет часть строки. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Разработка|00 Разработка]] +**Родитель**:: [[structure/Структура данных|Структура данных]] +**Источник**:: +**Создана**:: [[2024-09-17]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + +- [[B-tree]] +- [[Бинарное дерево поиска]] +- [[Сбалансированное дерево]] + diff --git a/dev/fundamental/structure/B-tree.md b/dev/fundamental/structure/B-tree.md new file mode 100644 index 00000000..a0bef8d2 --- /dev/null +++ b/dev/fundamental/structure/B-tree.md @@ -0,0 +1,84 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-01-29 +--- +[[Сбалансированное дерево|Сбалансированное]] сильно-ветвистое дерево позволяет хранить в узле множество значений, что делает его эффективным для работы с большими объемами данных. + +![[../../../meta/files/draw/Структура B-tree индекса.excalidraw.png]] +[[../../../meta/files/draw/Структура B-tree индекса.excalidraw|Структура B-tree индекса.excalidraw]] + +**Основные особенности B-tree** +- Узел содержит множество элементов, что позволяет хранить больше данных в одном месте. +- Каждый узел представляет собой [[../Страница|страничку]] на диске, что снижает издержки на чтение. +- В каждом узле есть ссылки на следующий и предыдущий узлы (характерно для B+tree). Это сильно помогает с поиском по диапазонам. +- В листьях дерева могут храниться сами данные или указатели на данные, то есть ссылаются на таблицу. +- Элементы в узле отсортированы, что делает поиск более эффективным и позволяет создавать деревья с небольшой высотой, тем самым уменьшая количество обращений к диску. +- Значения в узлах могут быть не уникальными. +- Обычно высота дерева не больше 3-4 уровней. +## Параметр t +Параметр `t` определяет количество элементов в узле дерева. +- В каждом узле должно быть не менее `t-1` и не более `2t-1` ключей. Это правило важно для поддержания сбалансированности дерева, так как позволяет равномерно распределять элементы между узлами и поддерживать эффективную высоту дерева, что, в свою очередь, обеспечивает высокую производительность операций поиска. +- Это правило не выполняется для корневого узла. + +**Как выбрать `t`**: значение `t` влияет на высоту дерева — ==большее значение уменьшает высоту, что снижает количество обращений к диску.== Обычно `t` выбирается в диапазоне от 50 до 2000 в зависимости от размера блока на диске и объема [[../../../../../knowledge/dev/pc/Оперативная память|оперативной памяти]]. Например, при `t = 1001` и 1 млрд записей требуется всего 3 операции для поиска любого ключа. +## Применение B-tree +**С чем может помочь:** +- **Поиск по равенству**: `a = 5` +- **Поиск по открытому диапазону**: `a > 5` или `a < 3` +- **Поиск по закрытому диапазону**: `3 < a < 8` +- **LIKE** работает с индексами по префиксам (`LIKE 'a%'` — эффективно) +**С чем НЕ поможет:** +- Поиск четных или нечетных чисел. +- Поиск суффиксов (`LIKE '%c'` — неэффективно). +## Поиск в B-tree +Алгоритм поиска аналогичен [[Бинарное дерево поиска|бинарному дереву]], но выбор осуществляется из нескольких вариантов, а не из двух. Поиск выполняется за `O(t logt(n))`, но количество обращений к диску — `O(logt(n))`. + +Рассмотрим пример поиска значения `5`. Начинаем с корневого узла, он всегда один. 5 больше 1, но меньше 7, поэтому идем в левую часть дерева. + +![[../../../meta/files/draw/Поиск в B-tree индексе 1.excalidraw.png]] +[[../../../meta/files/draw/Поиск в B-tree индексе 1.excalidraw|Поиск в B-tree индексе 1.excalidraw]] + +Видим, что 5 больше чем 4, поэтому идем по ссылке на 4. + +![[../../../meta/files/draw/Поиск в B-tree индексе 2.excalidraw.png]] +[[../../../meta/files/draw/Поиск в B-tree индексе 2.excalidraw|Поиск в B-tree индексе 2.excalidraw]] + +И там уже мы находим нашу 5. + +![[../../../meta/files/draw/Поиск в B-tree индексе 3.excalidraw.png]] +[[../../../meta/files/draw/Поиск в B-tree индексе 3.excalidraw|Поиск в B-tree индексе 3.excalidraw]] + +Значения в узлах могут быть не уникальными. Например, если значение `5` встречается дважды, поиск продолжается, переходя в следующий узел. Чтобы облегчить этот процесс, блоки на одном уровне связаны, создавая связный список. +## Добавление в B-tree +Представим, что нужно вставить значение `15` в уже существующее дерево. + +![](../../../meta/files/draw/Вставка%20в%20B-tree%201.excalidraw.md) + +![](../../../meta/files/images/Pasted%20image%2020240129194120.png) + +Вставка должна произойти между значениями `4` и `17`. Узел `7...16` переполнен (t = 3, максимум 5 значений), поэтому узел разбивается начиная с `t-1` элемента (в данном случае `11`). Элемент, по которому происходит разбиение, перемещается в родительский узел. Если родительский узел переполняется, он тоже разбивается, и так далее. + +После вставки мы получим следующее дерево + +![](../../../meta/files/images/Pasted%20image%2020240129194629.png) + +## Удаление из B-tree +Удаление элемента из B-tree требует поддержания минимального количества ключей в узле для сохранения сбалансированности дерева и его эффективной высоты. Например, при удалении элемента, если количество ключей в узле становится меньше `t-1`, выполняется перераспределение элементов из соседних узлов или их слияние, чтобы поддерживать сбалансированность. Существует несколько сценариев удаления: +- **Удаление из листового узла**: Если элемент находится в листовом узле и после его удаления остается не менее `t-1` элементов, узел остается без изменений. +- **Удаление из внутреннего узла**: Если удаляемый элемент находится во внутреннем узле, он заменяется на наибольший элемент в левом поддереве или наименьший элемент в правом поддереве. После этого выполняется удаление из листового узла. +- **Перераспределение и слияние узлов**: Если после удаления в узле остается меньше `t-1` элементов, выполняется перераспределение элементов из соседнего узла или слияние с соседним узлом. + +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 Разработка|00 Разработка]], [[../../../meta/zero/00 Алгоритм|00 Алгоритм]] +**Родитель**:: [[Tree]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-01-29]] +### Дополнительные материалы +- +### Дочерние заметки + + diff --git a/dev/fundamental/structure/Бинарное дерево поиска.md b/dev/fundamental/structure/Бинарное дерево поиска.md new file mode 100644 index 00000000..1670068f --- /dev/null +++ b/dev/fundamental/structure/Бинарное дерево поиска.md @@ -0,0 +1,54 @@ +--- +aliases: + - бинарное дерево + - бинарному дереву +tags: + - maturity/🌱 +date: 2024-01-29 +--- +Бинарное дерево поиска — это [[структура данных]], в которой выполняются три свойства: +- Элементы в левом поддереве должны быть меньше родительского узла. +- Элементы в правом поддереве должны быть больше родительского узла. +- У каждого узла не больше двух потомков. + +![x|400](../../../meta/files/images/Pasted%20image%2020240129190639.png) + +**Эти свойства обеспечивают:** +- Гарантированный порядок элементов. +- Детерминированный алгоритм поиска. +- В вырожденном случае придется посетить все элементы — сложность O(n). + + +> [!TIP] Сбалансированное дерево +> Чтобы улучшить поиск, можно использовать [сбалансированное](Сбалансированное%20дерево.md) бинарное дерево. + +**Сложность операций** +- **Средний случай**: поиск, вставка и удаление выполняются за O(log n), если дерево сбалансировано. +- **Худший случай**: если дерево становится несбалансированным, операции могут иметь сложность O(n). Это происходит, когда элементы добавляются в возрастающем или убывающем порядке, превращая дерево в цепочку. +## Основные операции с бинарным деревом поиска +### Вставка +При вставке нового элемента в бинарное дерево поиска он помещается в соответствующее место таким образом, чтобы сохранялся порядок элементов. Например, если вставляется значение `15`, и оно меньше текущего узла, оно вставляется в левое поддерево, иначе — в правое. + +### Удаление +Удаление элемента из бинарного дерева поиска может потребовать нескольких шагов, чтобы сохранить его свойства: +- **Удаление листа**: просто удаляется узел. +- **Удаление узла с одним потомком**: узел заменяется своим потомком. +- **Удаление узла с двумя потомками**: узел заменяется минимальным значением в правом поддереве или максимальным значением в левом поддереве. +### Поиск +Поиск элемента в бинарном дереве поиска выполняется путем рекурсивного или итеративного перехода по узлам, начиная с корня. Если искомое значение меньше текущего узла, поиск продолжается в левом поддереве, если больше — в правом. + +### Обход дерева +- **In-order обход**: обходит узлы в порядке возрастания значений. Используется для получения отсортированного списка элементов дерева. +- **Pre-order обход**: сначала посещается корень, затем левое и правое поддеревья. Полезно для копирования дерева. +- **Post-order обход**: сначала посещаются оба поддерева, затем корень. Используется для удаления дерева. +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 Разработка|00 Разработка]] +**Родитель**:: [[Tree]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-01-29]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/fundamental/structure/Сбалансированное дерево.md b/dev/fundamental/structure/Сбалансированное дерево.md new file mode 100644 index 00000000..4bf40714 --- /dev/null +++ b/dev/fundamental/structure/Сбалансированное дерево.md @@ -0,0 +1,70 @@ +--- +aliases: + - сбалансированное дерево + - сбалансированное +tags: + - maturity/🌱 +date: 2024-01-29 +--- +Сбалансированное [[../Tree|дерево]] — это [[структура данных]], в которой высота левого и правого поддеревьев каждого узла отличается не более чем на единицу. Это позволяет сохранять логарифмическую сложность поиска (O(log n)), что делает его эффективным для операций поиска, вставки и удаления. + +В несбалансированном дереве, например, при последовательном добавлении элементов в возрастающем порядке, дерево может превратиться в цепочку, что ухудшает производительность поиска до O(n). Сбалансированное дерево решает эту проблему, сохраняя высоту минимальной. + +![](../../../meta/files/images/Pasted%20image%2020240129191116.png) + +**Плюсы**: +- Быстрая операция поиска — O(высоты дерева), что близко к O(log n) для сбалансированного дерева. +- Решает проблему вырожденного случая бинарного дерева. + +**Минусы**: +- Требует дополнительных усилий и вычислительных ресурсов для поддержания балансировки, особенно при частых вставках и удалениях. +- В некоторых случаях операции вставки и удаления могут быть медленнее, чем в несбалансированных деревьях, из-за необходимости балансировки. + +**Типы сбалансированных деревьев** +- **AVL-дерево**: Обеспечивает балансировку после каждой операции добавления или удаления. Высота левого и правого поддеревьев каждого узла отличается не более чем на единицу. AVL-деревья подходят для приложений, где важна быстрая операция поиска. +- **Красно-черное дерево**: Менее строгое, чем AVL-дерево, что делает его более быстрым для операций вставки и удаления. Красно-черные деревья используются в реализациях словарей и ассоциативных массивов. + +**Алгоритмы балансировки** +- **Повороты**: Основной метод балансировки — это повороты (левое и правое). Они позволяют перераспределить элементы дерева так, чтобы сохранить его сбалансированность. +- **Перераспределение и слияние узлов**: Эти методы используются в зависимости от типа сбалансированного дерева для поддержания его свойств. +## Пример балансировки дерева +Представим, что добавляется новый элемент `30` в уже существующее AVL-дерево, и дерево становится несбалансированным: + +``` + 20 + / \ + 10 25 +``` + +После добавления `30` дерево становится несбалансированным, так как правое поддерево узла `25` становится слишком высоким: + +``` + 20 + / \ + 10 25 + \ + 30 +``` + +Чтобы восстановить баланс, выполняется левое вращение относительно узла `25`, и дерево принимает следующий вид: + +``` + 20 + / \ + 10 30 + / + 25 +``` + +Таким образом, балансировка восстанавливает равновесие дерева и сохраняет его свойства. Например, если левое поддерево стало значительно выше правого, выполняется правое вращение для восстановления равновесия. +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 Разработка|00 Разработка]] +**Родитель**:: [[Tree|Tree]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-01-29]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/fundamental/structure/Структура данных.md b/dev/fundamental/structure/Структура данных.md new file mode 100644 index 00000000..0ebcb447 --- /dev/null +++ b/dev/fundamental/structure/Структура данных.md @@ -0,0 +1,29 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-09-17 +--- +![[../../../meta/files/images/Pasted image 20241103220925.png]] + +![[../../../meta/files/images/Pasted image 20241103022447.png]] + +- [[Tree|Дерево]] +- [[structure/Хеш-таблица|Хеш-таблица]] + +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 Разработка|00 Разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-09-17]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + +- [[Tree]] +- [[Хеш-таблица]] + diff --git a/dev/fundamental/structure/Хеш-таблица.md b/dev/fundamental/structure/Хеш-таблица.md new file mode 100644 index 00000000..e6e5a87e --- /dev/null +++ b/dev/fundamental/structure/Хеш-таблица.md @@ -0,0 +1,48 @@ +--- +aliases: + - хеш таблица + - хеш таблице + - хеш-таблице + - хеш-таблицу + - хеш-таблиц + - хеш таблицу + - хеш таблиц +tags: + - maturity/🌱 +date: 2024-09-17 +zero-link: + - "[[../../../meta/zero/00 Разработка|00 Разработка]]" +parents: + - "[[Структура данных]]" +linked: +--- +Хэш-таблица — это [[Структура данных|структура данных]], которая используется для эффективного хранения и поиска данных на основе ключей. Она обеспечивает быстрый доступ к элементам, используя [[../../cryptography/Хеш-функция|хеш-функцию]] для преобразования ключа в индекс массива, где хранится значение. Это делает операции вставки, удаления и поиска очень быстрыми, обычно за время O(1). + +**Основные концепции хэш-таблицы:** +- **Ключ и значение:** Каждый элемент в хэш-таблице хранится в виде пары “ключ-значение”. Ключи должны быть уникальными, а значения могут быть любыми. Например, в хэш-таблице можно хранить данные о студентах, где ключом будет идентификационный номер, а значением — информация о студенте. +- [[../../cryptography/Хеш-функция|Хеш-функция]] Это основа работы хэш-таблицы. Хеш-функция принимает ключ и вычисляет индекс в массиве, где должно быть размещено значение. Например, для ключа “apple” хэш-функция может вернуть индекс 3, и значение будет сохранено в ячейке с индексом 3. +- **Разрешение коллизий:** Поскольку разные ключи иногда могут давать одинаковый хэш (коллизии), нужно уметь их разрешать. Существуют несколько подходов: + - **Метод цепочек (Chaining):** В каждой ячейке массива хранится связанный список значений, чьи ключи дали одинаковый хэш. При коллизии элемент добавляется в этот список. + - **Открытая адресация (Open Addressing):** При коллизии элемент помещается в следующую свободную ячейку массива по определённому алгоритму (например, линейное пробирование или двойное хэширование). +- **Коэффициент загрузки (Load Factor):** Это соотношение количества элементов к размеру массива. Если коэффициент загрузки слишком велик, производительность хэш-таблицы падает, и может понадобиться увеличение массива и перерасчёт всех хешей (рехеширование). + +**Преимущества хэш-таблиц:** +- **Быстрый доступ:** Операции вставки, удаления и поиска обычно выполняются за константное время O(1). +- **Гибкость ключей:** Могут использоваться любые неизменяемые типы данных в качестве ключей (строки, числа, кортежи и т.д.). + +**Недостатки хэш-таблиц:** +- **Память:** Хэш-таблицы могут потреблять много памяти из-за большого размера массива, особенно при низком коэффициенте загрузки. +- **Коллизии:** Если хеш-функция некачественная или слишком много элементов, это может замедлить работу из-за коллизий. +- **Нет упорядоченности:** Порядок элементов в хэш-таблице не предсказуем и не сохраняется. +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 Разработка|00 Разработка]] +**Родитель**:: [[Структура данных]] +**Источник**:: +**Создана**:: [[2024-09-17]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + diff --git a/dev/fundamental/Атомарная операция.md b/dev/fundamental/Атомарная операция.md new file mode 100644 index 00000000..3035d4ba --- /dev/null +++ b/dev/fundamental/Атомарная операция.md @@ -0,0 +1,28 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-10-12 +zero-link: +parents: +linked: +--- +Операция атомарная, если невозможно наблюдать частичный результат ее выполнения. Любой наблюдатель видит либо состояние системы до атомарной операции, либо после + +В Java: +- Запись в поле типа boolean, byte, short, char, int, Object всегда атомарна +- Запись в поле типа long/double: атомарна запись старших и младших 32 бит +- Запись в поле типа long/double, объявленное volatile, атомарна +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Разработка|00 Разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-10-12]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/fundamental/Блокировка.md b/dev/fundamental/Блокировка.md new file mode 100644 index 00000000..fa581d26 --- /dev/null +++ b/dev/fundamental/Блокировка.md @@ -0,0 +1,56 @@ +--- +aliases: + - блокировок + - блокировки +tags: + - maturity/🌱 +date: + - - 2024-05-24 +zero-link: [] +parents: +linked: +--- +Блокировки в разработке, особенно в контексте [[Multithreading|многопоточности]] и баз данных, относятся к механизмам, предотвращающим одновременный доступ к ресурсу несколькими [[Поток процесса ОС|потоками]] или [[Процесс ОС|процессами]], чтобы избежать несогласованности данных или других конфликтов. + +**Минусы блокировок:** +- Есть риск получить [Deadlock](Deadlock.md) +- Блокировок может быть много + +**Классификация:** +- По области действия. + - Строчные. Блокировка конкретной строки + - Гранулярные + - Предикативные +- По строгости + - Совместная. Shared lock. Можно читать заблокированные данные + - Исключительная. Exclusive lock. С заблокированными данными ничего делать нельзя. + +**Виды реализаций:** +- **Мьютекс (Mutex)**: + - **Назначение**: Обеспечивают эксклюзивный доступ к ресурсу. Когда поток захватывает мьютекс, другие потоки должны ждать, пока он освободится. + - **Применение**: В многопоточных приложениях для синхронизации доступа к общим данным. +- **Читательские/писательские блокировки (Reader/Writer Locks)**: + - **Назначение**: Позволяют нескольким потокам читать ресурс одновременно, но блокируют доступ на запись. Если один поток пишет, все остальные потоки (и читатели, и писатели) должны ждать. + - **Применение**: Когда ресурс чаще читается, чем пишется, для улучшения производительности. +- **Семафоры (Semaphores)**: + - **Назначение**: Управляют доступом к ресурсу, ограничивая количество потоков, которые могут одновременно им пользоваться. + - **Применение**: Для ограничения количества одновременно выполняемых операций, например, подключения к базе данных. +- **Блокировки баз данных (Database Locks)**: + - **Назначение**: Предотвращают конкурентное выполнение операций, которые могут привести к некорректному состоянию данных. + - **Применение**: В системах управления базами данных (СУБД) для управления транзакциями и поддержания целостности данных. + + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Разработка|00 Разработка]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-05-24]] +### Дополнительные материалы +- +### Дочерние заметки + + +- [[Two Phase Lock]] + diff --git a/dev/fundamental/Вытесняющая многозадачность.md b/dev/fundamental/Вытесняющая многозадачность.md new file mode 100644 index 00000000..b48fd76d --- /dev/null +++ b/dev/fundamental/Вытесняющая многозадачность.md @@ -0,0 +1,32 @@ +--- +aliases: + - вытесняющей многозадачности + - вытесняющей многозадачностью + - Preemptive Multitasking +parents: + - "[[Многозадачность]]" +date: 2024-01-28 +zero-link: + - "[[../../meta/zero/00 Архитектура ЭВМ|00 Архитектура ЭВМ]]" +linked: + - "[[Кооперативная многозадачность]]" +--- +Вытесняющая многозадачность — это подход к [[Многозадачность|многозадачности]], при котором [операционная система](Операционная%20система.md) имеет полный контроль над тем, когда и какой [процесс](Процесс%20ОС.md) или [поток](Поток%20процесса%20ОС.md) получает доступ к [[Центральный процессор|процессору]]. + +[[Квантирование времени]]. Операционная система может прервать (вытеснить) текущий процесс или поток в любой момент времени, чтобы передать управление другому процессу или потоку, обеспечивая таким образом более эффективное и справедливое распределение процессорного времени между всеми выполняющимися задачами. + +Вытеснение приводит к [переключению контекста](Переключение%20контекста.md). +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ЭВМ|00 Архитектура ЭВМ]] +**Родитель**:: [[Многозадачность]] +**Источник**:: +**Автор**:: +**Создана**:: [[2023-01-28]] +### Дополнительные материалы +- [[Кооперативная многозадачность|Кооперативная многозадачность]] +### Дочерние заметки + + +- [[Квантирование времени]] + diff --git a/dev/fundamental/Закон Амдала.md b/dev/fundamental/Закон Амдала.md new file mode 100644 index 00000000..bea0814d --- /dev/null +++ b/dev/fundamental/Закон Амдала.md @@ -0,0 +1,32 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-10-08 +zero-link: +parents: +linked: +--- +Закон Амдала описывает ограничение на ускорение выполнения задачи при добавлении дополнительных процессоров или ресурсов в многопроцессорные системы. Он был предложен [[../../meta/people/Джин Амдал|Джином Амдалом]] в [[../../meta/date/year/1967|1967]] году и формулирует, что прирост производительности зависит от доли задачи, которая может быть выполнена [[Parallelism|параллельно]]. Если значительная часть задачи выполняется последовательно, то добавление процессоров мало повлияет на ускорение. + +![[../../meta/files/images/Pasted image 20241008215741.png]] + +Закон можно выразить математически: , где: +- S — ускорение выполнения программы, +- P — доля программы, которая может быть выполнена параллельно, +- N — количество процессоров. + +При увеличении числа процессоров ускорение достигает предела, который зависит от последовательной части задачи. Если параллельная часть составляет 95%, то максимально достижимое ускорение будет ограничено в 20 раз, даже если будут доступны бесконечные вычислительные ресурсы. Это демонстрирует ключевое ограничение параллельных вычислений: ==последовательные компоненты задачи являются узким местом, которое ограничивает прирост производительности.== +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Разработка|00 Разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-10-08]] +**Автор**:: [[../../meta/people/Джин Амдал|Джин Амдал]] +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/fundamental/Закон универсальной масштабируемости.md b/dev/fundamental/Закон универсальной масштабируемости.md new file mode 100644 index 00000000..07b2f2a4 --- /dev/null +++ b/dev/fundamental/Закон универсальной масштабируемости.md @@ -0,0 +1,47 @@ +--- +aliases: + - Universal Scalability Law + - USL +tags: + - maturity/🌱 +date: 2024-10-09 +zero-link: +parents: +linked: +--- +Закон универсальной масштабируемости (Universal Scalability Law, USL), предложенный [[../../meta/people/Нил Гюнтер|Нилом Гюнтером]], расширяет [[fundamental/Закон Амдала|Закон Амдала]], добавляя более полное описание поведения системы при увеличении числа ресурсов. Он учитывает как положительные, так и отрицательные эффекты от параллелизации в распределенных системах. В то время как Закон Амдала сосредотачивается на ограничениях параллелизации, USL описывает поведение систем более реалистично, рассматривая два ключевых фактора: + +- **Увеличение конкуренции за ресурсы (Contention)** — чем больше ресурсов добавляется в систему, тем чаще они конкурируют за одни и те же ресурсы (например, память или сеть), что ограничивает прирост производительности. +- **Накладные расходы на координацию (Coherence)** — увеличение числа процессоров может требовать большего объема синхронизации между ними, что также снижает эффективность системы. + + +**Формула Закона универсальной масштабируемости** +![[../../meta/files/images/Pasted image 20241009083313.png]] +где: +- S(N) — ускорение системы при N процессорах, +- N — количество процессоров или узлов в системе, +- alpha — коэффициент конкуренции за ресурсы (contention), +- beta — коэффициент накладных расходов на координацию (coherence). + +Пояснение параметров: +- alpha представляет эффект конкуренции за ресурсы, что проявляется в снижении производительности при добавлении новых процессоров, когда те начинают бороться за доступ к общим ресурсам, например, памяти или сети. +- beta характеризует накладные расходы, возникающие при координации между процессорами, что особенно важно в системах с высокой степенью распределенности или при сложной синхронизации данных. + +Особенности Закона Гюнтера: +- Линейное ускорение: при N -> infty и низких значениях alpha и beta, производительность системы может расти линейно с увеличением числа процессоров. Это характерно для хорошо масштабируемых задач. +- Эффект насыщения: на практике чаще всего рост производительности замедляется из-за эффекта конкуренции за ресурсы (alpha), и ускорение перестает быть линейным. +- Деградация производительности: при слишком большом количестве процессоров или узлов, влияние накладных расходов (\beta) становится критическим, и система может начать замедляться, так как ресурсы тратятся на координацию, а не на полезную работу. + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Разработка|00 Разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-10-09]] +**Автор**:: [[../../meta/people/Нил Гюнтер|Нил Гюнтер]] +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/fundamental/Квантирование времени.md b/dev/fundamental/Квантирование времени.md new file mode 100644 index 00000000..151e164e --- /dev/null +++ b/dev/fundamental/Квантирование времени.md @@ -0,0 +1,27 @@ +--- +aliases: + - квантированию времени +tags: + - maturity/🌱 +date: + - - 2024-01-28 +zero-link: + - "[[../../meta/zero/00 Архитектура ЭВМ|00 Архитектура ЭВМ]]" +parents: + - "[[Вытесняющая многозадачность]]" +linked: +--- +Планировщик задач [[../../../../knowledge/dev/pc/Операционная система|ОС]] выделяет каждому потоку квант времени (~50 мкс) для выполнения на [[Центральный процессор|процессоре]]. Когда квант времени истекает или возникает событие, требующее [переключения контекста](Переключение%20контекста.md) (например, операция ввода/вывода, которая может занять некоторое время), [[../../../../knowledge/dev/pc/Операционная система|ОС]] сохраняет состояние текущего [потока](Поток%20процесса%20ОС.md) (контекст) и загружает состояние следующего [[Поток процесса ОС|потока]] для его выполнения. + +Квантирование времени является одним из механизмов, используемых в рамках [вытесняющей многозадачности](Вытесняющая%20многозадачность.md). +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ЭВМ|00 Архитектура ЭВМ]] +**Родитель**:: [[Вытесняющая многозадачность|Вытесняющая многозадачность]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-01-28]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/fundamental/Кодирование данных.md b/dev/fundamental/Кодирование данных.md new file mode 100644 index 00000000..a199157c --- /dev/null +++ b/dev/fundamental/Кодирование данных.md @@ -0,0 +1,27 @@ +--- +aliases: + - кодирования данных +tags: + - maturity/🌱 +date: 2024-09-14 +zero-link: + - "[[../../meta/zero/00 Разработка|00 Разработка]]" +parents: +linked: +--- +- [[../other/Base64|Base64]] +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Разработка|00 Разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-09-14]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + +- [[Base64]] + diff --git a/dev/fundamental/Кооперативная многозадачность.md b/dev/fundamental/Кооперативная многозадачность.md new file mode 100644 index 00000000..6e883a05 --- /dev/null +++ b/dev/fundamental/Кооперативная многозадачность.md @@ -0,0 +1,48 @@ +--- +aliases: + - non-preemptive multitasking + - cooperative multitasking + - кооперативная многозадачность + - невытесняющей многозадачности + - кооперативной многозадачности + - невытесняющая многозадачность + - кооперативную многозадачность +tags: + - maturity/🌱 +date: + - - 2024-03-19 +zero-link: + - "[[../../meta/zero/00 Архитектура ЭВМ|00 Архитектура ЭВМ]]" +parents: + - "[[Многозадачность]]" +linked: + - "[[Вытесняющая многозадачность]]" +--- +Подход к управлению выполнением задач в [операционных системах](Операционная%20система.md), при котором текущий выполняющийся [процесс](Процесс%20ОС.md) должен явно отдать управление [[../../../../knowledge/dev/pc/Операционная система|операционной системе]], чтобы другой процесс мог быть запущен. + +В этом режиме [[../../../../knowledge/dev/pc/Операционная система|операционная система]] не может прервать и вытеснить текущий процесс для переключения на другой процесс, как в [[Вытесняющая многозадачность|вытесняющей многозадачности]]. Вместо этого, каждый процесс должен "добровольно" уступить ресурсы, достигнув определённой точки в своём выполнении или завершив свою работу. + + +> [!INFO] +> В современных операционных системах преимущественно используется [вытесняющая многозадачность](Вытесняющая%20многозадачность.md). + +**Особенности кооперативной многозадачности:** +- **Кооперативность:** Процессы сами решают, когда отдать управление ОС, что требует более внимательного программирования, чтобы избежать занимания [[Центральный процессор|процессора]] одним процессом на долгое время. +- **Риски:** Если один из процессов захватывает процессор и не отдаёт управление, это может привести к "зависанию" системы или снижению отзывчивости, поскольку другие процессы не смогут выполняться до тех пор, пока не будет освобожден процессор. +- **Простота:** Механизмы кооперативной многозадачности проще в реализации по сравнению с [[Вытесняющая многозадачность|вытесняющей многозадачностью]], так как не требуют сложной логики управления приоритетами и безопасности [переключения контекста](Переключение%20контекста.md). +- **Применение:** Этот подход чаще всего используется в системах с ограниченными ресурсами, встраиваемых системах или в старых операционных системах, где аппаратная поддержка для вытесняющей многозадачности может отсутствовать. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ЭВМ|00 Архитектура ЭВМ]] +**Родитель**:: [[Многозадачность]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-03-19]] +### Дополнительные материалы +- [[Вытесняющая многозадачность]] +### Дочерние заметки + + +- [[Callback]] +- [[Green thread]] + diff --git a/dev/fundamental/Кэш процессора.md b/dev/fundamental/Кэш процессора.md new file mode 100644 index 00000000..0fd6213c --- /dev/null +++ b/dev/fundamental/Кэш процессора.md @@ -0,0 +1,47 @@ +--- +aliases: + - кэше процессора + - кэш-памяти + - кэш-память +tags: + - maturity/🌱 +date: 2024-10-12 +zero-link: +parents: +linked: +--- +Кэш — это небольшая и очень быстрая память, встроенная в [[Центральный процессор|процессор]], предназначенная для временного хранения данных, к которым процессор обращается чаще всего. Основная задача кэша — ускорение работы процессора за счет минимизации времени доступа к этим данным. + +Процессор работает значительно быстрее, чем [[../../../../knowledge/dev/pc/Оперативная память|оперативная память]] (RAM), поэтому при прямом обращении к оперативной памяти возникали бы значительные задержки. Кэш решает эту проблему, храня наиболее востребованные данные и инструкции ближе к процессору. Когда процессор выполняет операцию, он сначала проверяет кэш. ==Если нужная информация находится в кэше, она загружается практически мгновенно==. В противном случае процессору приходится обращаться к более медленной оперативной памяти, что увеличивает время ожидания. + +Кэш-память процессора делится на два типа: кэш для данных и кэш для инструкций. Такое разделение позволяет повысить производительность процессора за счет оптимизации доступа к различным видам информации. + +Кэш инструкций хранит машинный код программ, который процессор должен выполнить, а кэш данных содержит фактические данные, с которыми работают программы. Это разделение позволяет процессору одновременно загружать инструкции для выполнения и данные для обработки, минимизируя задержки. + +Когда кэш заполняется, процессор должен решить, какие данные удалить, чтобы освободить место для новых. Эта задача решается с помощью специальных алгоритмов замещения. + +Когда процессор имеет несколько ядер, каждое из них может иметь собственный кэш, что приводит к проблеме [[Cache coherence|кэш-кохерентности]]. +## Уровни кэша +Кэш процессора разделен на несколько уровней: L1, L2 и L3. Каждый уровень отличается по объему, скорости и месту в архитектуре процессора. + +**L1-кэш** — самый быстрый и ближайший к ядру процессора уровень кэша. Он имеет небольшой объем, обычно от нескольких десятков до сотни килобайт, и разделяется на две части: для инструкций и для данных. Это позволяет ускорять как выполнение команд, так и работу с информацией. + +**L2-кэш** находится на следующем уровне и имеет больший объем, чем L1, но его скорость ниже. Обычно L2-кэш выделяется для каждого ядра процессора отдельно, что позволяет ядрам работать автономно и быстро получать доступ к своим данным. + +**L3-кэш** — самый медленный, но и самый большой по объему уровень кэша. Он общий для всех ядер процессора и позволяет ядрам обмениваться данными через этот уровень. Несмотря на то что L3 медленнее, чем L1 и L2, он все равно значительно быстрее оперативной памяти. + +## Кэш-линия +Кэш-линия — это минимальная единица данных, с которой работает кэш-память. Когда процессор загружает данные из оперативной памяти в кэш, он перемещает не один байт, а целую кэш-линию, которая содержит группу смежных данных. Использование кэш-линий позволяет более эффективно задействовать кэш, так как высока вероятность того, что процессору понадобятся соседние данные, что объясняется [[Принцип локальности|принципом локальности]]. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ЭВМ|00 Архитектура ЭВМ]] +**Родитель**:: [[Центральный процессор]] +**Источник**:: +**Создана**:: [[2024-10-12]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/fundamental/Многозадачность.md b/dev/fundamental/Многозадачность.md new file mode 100644 index 00000000..e923d65b --- /dev/null +++ b/dev/fundamental/Многозадачность.md @@ -0,0 +1,37 @@ +--- +aliases: + - многозадачности + - Многозадачность ЦПУ + - Multitasking +tags: + - maturity/🌱 +date: + - - 2024-01-28 +zero-link: + - "[[../../meta/zero/00 Архитектура ЭВМ|00 Архитектура ЭВМ]]" +parents: + - "[[Центральный процессор|ЦПУ]]" +linked: +--- +Многозадачность — это способность [операционной системы](Операционная%20система.md) одновременно управлять выполнением нескольких задач ([процессов](Процесс%20ОС.md) или [потоков](Поток%20процесса%20ОС.md)). Это достигается путем распределения [[Планировщик ОС|планировщиком ОС]] доступного процессорного времени между различными задачами таким образом, чтобы создать иллюзию их параллельного выполнения. Многозадачность может быть реализована в двух основных формах: кооперативной и вытесняющей. + +- [[Переключение контекста]]. Механизм, который позволяет операционной системе сохранять и загружать состояние (контекст) процессов или потоков. Это ключевой компонент, обеспечивающий многозадачность, так как без него невозможно было бы переключаться между задачами. +- [[Кооперативная многозадачность]] требует, чтобы каждая задача явно отдавала управление операционной системе, чтобы другие задачи могли выполняться. Этот подход может привести к проблемам, если задача не отдает управление. +- [[Вытесняющая многозадачность]] позволяет операционной системе "вытеснять" текущую задачу и переключаться на другую задачу, обеспечивая более надежный и справедливый механизм планирования. Этот подход наиболее распространен в современных операционных системах. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ЭВМ|00 Архитектура ЭВМ]] +**Родитель**:: [[Центральный процессор|ЦПУ]], [[Concurrency]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-01-28]] +### Дополнительные материалы +- +### Дочерние заметки + + +- [[Concurrency]] +- [[Вытесняющая многозадачность]] +- [[Кооперативная многозадачность]] +- [[Переключение контекста]] + diff --git a/dev/fundamental/Переключение контекста.md b/dev/fundamental/Переключение контекста.md new file mode 100644 index 00000000..f696fc90 --- /dev/null +++ b/dev/fundamental/Переключение контекста.md @@ -0,0 +1,56 @@ +--- +aliases: + - context switch + - переключению контекстов + - переключение контекстов + - переключения контекста + - переключению контекста + - Контекстные переключения + - переключение между потоками + - контекстных переключений +tags: + - maturity/🌱 +date: + - - 2024-01-28 +zero-link: + - "[[../../meta/zero/00 Разработка|00 Разработка]]" +parents: + - "[[Многозадачность]]" +linked: +--- +Переключение контекстов происходит, когда [[../../../../knowledge/dev/pc/Операционная система|операционная система]] останавливает выполнение одной задачи и начинает выполнение другой ([[Concurrency|Concurrency]]). Этот процесс включает в себя сохранение текущего состояния задачи (контекста), включая значения регистров процессора, указатель инструкций и другие связанные с задачей данные, чтобы впоследствии можно было возобновить выполнение задачи с того места, где она была остановлена. + +Этот процесс происходит настолько быстро и эффективно, что пользователи и приложения воспринимают систему как способную выполнять множество операций одновременно, несмотря на то, что физически одно [[Ядро процессора|ядро]] процессора в данный момент может выполнять только один поток. + +В настоящее время все программы запускаются в так называемом "защищенном режиме", когда одна программа не имеет доступа к данным другой программы. В этом режиме указатели программы содержать не настоящий адрес на область памяти, а виртуальный, который маппится на настоящий, таким образом в двух разных программах может использоваться один и тот же адрес памяти, но на самом деле это будут разные области памяти. + +В защищенном режиме каждая программа считает, что выполняется только она, про другие программы она не знает. + +Когда программа не может дальше выполняться, то она сохраняет свое состояние и уступает ресурсы [[Центральный процессор|ЦПУ]] другой программе. +- Сохранение регистров процессора +- Сохранение общей информации: pid, tid, uid. gid, euid, egid и т.д. +- Сохранение состояния процессора/потока +- Сохранение прав доступа +- Сохранение используемых потоком ресурсов и блокировок +- Сохранение счетчиков использования ресурсов +- Сохранение регионов памяти, выделенных процессору +- Очистка конвейера команд и данных процессора +- Очистка TLB, отвечающая за страничное отображение линейных адресов на физические + +Переключение контекста занимает какое-то время (~1 мкс). Для примера выполнение одной строчки кода занимает ~0.5 нс. Переключение контекста может происходить как у процессов, так и у потоков. + +![](../../meta/files/images/Pasted%20image%2020240128143015.png) + +Чем больше [процессов](Процесс%20ОС.md), тем больше будет переключений. Время на процессы и паузы будут не измены, но пауз станет больше. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Разработка|00 Разработка]] +**Родитель**:: [[Многозадачность|Многозадачность ЦПУ]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-01-28]] +### Дополнительные материалы +- [[../../meta/zero/00 Архитектура ЭВМ|00 Архитектура ЭВМ]] +- [[Concurrency|Concurrency]] +### Дочерние заметки + diff --git a/dev/fundamental/Планировщик ОС.md b/dev/fundamental/Планировщик ОС.md new file mode 100644 index 00000000..e787bbb2 --- /dev/null +++ b/dev/fundamental/Планировщик ОС.md @@ -0,0 +1,34 @@ +--- +aliases: + - планировщика ОС + - планировщику ОС + - планировщиком ОС +tags: + - maturity/🌱 +date: + - - 2024-03-19 +zero-link: + - "[[../../meta/zero/00 Архитектура ЭВМ|00 Архитектура ЭВМ]]" +parents: + - "[[../../../../knowledge/dev/pc/Операционная система|Операционная система]]" +linked: +--- +Планировщик ОС - это ключевой компонент ядра [ОС](Операционная%20система.md), отвечающий за распределение процессорного времени между всеми запущенными процессами и потоками. Он управляет порядком, в котором [процессы](Процесс%20ОС.md) и [потоки](Поток%20процесса%20ОС.md) получают доступ к [центральному процессору](Центральный%20процессор.md) (ЦП). + +Основные функции планировщика ОС включают: +1. [Переключение контекста](Переключение%20контекста.md): Планировщик переключает контекст процессора с одного процесса или потока на другой. Это включает в себя сохранение состояния текущего процесса и восстановление состояния следующего процесса, который должен быть выполнен. +2. **Приоритеты:** Планировщик использует систему приоритетов для определения того, какие процессы должны выполняться в первую очередь. Процессы с более высоким приоритетом получают больше процессорного времени или более частый доступ к ЦП. +3. **Алгоритмы планирования:** Планировщик реализует алгоритмы планирования, которые определяют, как и когда процессы будут выполняться. Существуют различные алгоритмы, такие как круговое планирование (Round Robin), планирование с приоритетами, многоуровневые очереди и др., каждый из которых имеет свои преимущества в зависимости от сценария использования. +4. **Справедливость и эффективность:** Планировщик стремится обеспечить справедливый доступ к ЦП для всех процессов и максимизировать эффективность использования процессорных ресурсов, минимизируя простои и время ожидания. +5. **Обработка прерываний и асинхронных событий:** Планировщик также отвечает за реагирование на прерывания и асинхронные события, которые могут потребовать немедленного переключения контекста или изменения в плане выполнения процессов. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ЭВМ|00 Архитектура ЭВМ]] +**Родитель**:: [[../../../../knowledge/dev/pc/Операционная система|Операционная система]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-03-19]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/fundamental/Поток процесса ОС.md b/dev/fundamental/Поток процесса ОС.md new file mode 100644 index 00000000..80fb925d --- /dev/null +++ b/dev/fundamental/Поток процесса ОС.md @@ -0,0 +1,36 @@ +--- +aliases: + - поток + - потока + - потоки + - потоков + - нити ос + - нити операционной системы + - нить ос + - потоку + - потоком ОС + - потоку ОС + - потоками +tags: + - maturity/🌱 +date: 2024-01-28 +zero-link: + - "[[../../meta/zero/00 Архитектура ЭВМ|00 Архитектура ЭВМ]]" +parents: + - "[[Процесс ОС]]" +linked: +--- +Поток (или поток выполнения) — это легковесная единица выполнения, которая работает внутри [[Процесс ОС|процесса]]. Все потоки в пределах одного процесса делят между собой адресное пространство и ресурсы этого процесса, что позволяет им легко обмениваться данными и синхронизироваться. + +Каждый поток имеет свой собственный stack, счетчик команд и набор регистров, но разделяет с другими потоками того же [[Процесс ОС|процесса]] кучу и глобальные переменные. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ЭВМ|Архитектура ЭВМ]] +**Родитель**:: [[Процесс ОС]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-01-28]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/fundamental/Принцип локальности.md b/dev/fundamental/Принцип локальности.md new file mode 100644 index 00000000..d397ea96 --- /dev/null +++ b/dev/fundamental/Принцип локальности.md @@ -0,0 +1,30 @@ +--- +aliases: + - принципе локальности + - принципом локальности +tags: + - maturity/🌱 +date: + - - 2024-05-24 +zero-link: + - "[[../../meta/zero/00 Разработка|00 Разработка]]" +parents: +linked: +--- +Программе свойственно в определенный промежуток времени работать с некоторым небольшим подмножеством данных из всего набора. + +Наглядные примеры: +- Для чатов - последние сообщения +- Для новостей - последние новости +- Для сервиса такси - активные заказы +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Разработка|00 Разработка]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-05-24]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/fundamental/Процесс ОС.md b/dev/fundamental/Процесс ОС.md new file mode 100644 index 00000000..2339ad56 --- /dev/null +++ b/dev/fundamental/Процесс ОС.md @@ -0,0 +1,39 @@ +--- +aliases: + - процесс + - процесса + - процессы + - процессов + - процессами +tags: + - maturity/🌱 +date: + - - 2024-01-28 +zero-link: + - "[[../../meta/zero/00 Архитектура ЭВМ|00 Архитектура ЭВМ]]" +parents: + - "[[Ядро процессора]]" +--- +Процесс — это экземпляр программы, находящейся в выполнении. Каждый процесс имеет своё собственное виртуальное адресное пространство, которое изолирует его от других процессов, а также собственные коды и данные, состояние процессора и системные ресурсы, которые он использует (например, файловые дескрипторы и порты ввода/вывода). + +[Операционная система](Операционная%20система.md) управляет процессами, выделяя им процессорное время и ресурсы, необходимые для их выполнения. + +Процесс содержит в себе [потоки](Поток%20процесса%20ОС.md). + +Под любой процесс создаются свои [Namespace](../linux/Namespace.md), которые позволяют изолировать процессы, запущенные на одном ядре друг от друга. + +![[../../meta/files/images/Pasted image 20241103221422.png]] +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ЭВМ|00 Архитектура ЭВМ]]] +**Родитель**:: [[Ядро процессора|Ядро процессора]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-01-28]] +### Дополнительные материалы +- +### ### Дочерние заметки + + +- [[Поток процесса ОС]] + diff --git a/dev/fundamental/Сжатие данных.md b/dev/fundamental/Сжатие данных.md new file mode 100644 index 00000000..a02b93bf --- /dev/null +++ b/dev/fundamental/Сжатие данных.md @@ -0,0 +1,26 @@ +--- +aliases: + - Компрессия данных +tags: + - maturity/🌱 +date: 2024-09-14 +zero-link: + - "[[../../meta/zero/00 Разработка|00 Разработка]]" +parents: +linked: +--- +*** +## Мета информация +**Область**:: +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-09-14]] +**Автор**:: +### Дополнительные материалы +- +### Дочерние заметки + + +- [[GZIP]] +- [[Сжатие изображений без потери качества]] + diff --git a/dev/fundamental/Страница.md b/dev/fundamental/Страница.md new file mode 100644 index 00000000..00913d06 --- /dev/null +++ b/dev/fundamental/Страница.md @@ -0,0 +1,43 @@ +--- +aliases: + - страницы + - страниц + - страничку + - страницы ОС + - Страница ОС +tags: + - maturity/🌱 +date: 2024-09-17 +--- +Страница это непрерывный блок памяти фиксированного размера. + +**Размер страницы:** Обычно размер страницы составляет от 4 КБ до нескольких мегабайт, в зависимости от архитектуры [[Центральный процессор|процессора]] и настроек [[../../../../knowledge/dev/pc/Операционная система|операционной системы]]. Например, в большинстве современных систем страница составляет 4 КБ, но на некоторых системах могут использоваться страницы большего размера, например, 2 МБ или 4 МБ. Большие страницы (так называемые Huge Pages) могут использоваться для повышения производительности, так как они уменьшают накладные расходы на управление памятью и уменьшение количества записей в таблице страниц. + +**Страницы и виртуальная память:** Виртуальная память — это механизм, который позволяет программе использовать больше памяти, чем физически доступно на компьютере. Виртуальное адресное пространство разбивается на страницы, которые могут быть размещены в оперативной памяти (RAM) или на диске (swap file или page file). + +**Таблица страниц:** Операционная система использует таблицу страниц для отслеживания, где находятся страницы виртуальной памяти (в оперативной памяти или на диске). Каждой странице виртуальной памяти соответствует страница в физической памяти. + +**Страницы в физической памяти:** Страницы, загруженные в оперативную память, называются фреймами. Размер фрейма совпадает с размером страницы, что упрощает управление памятью. + +**Защита от записи (Read-Only):** Страницы, содержащие код программы, как правило, защищены от записи. Это делает их доступными только для чтения, предотвращая случайные или злонамеренные изменения в коде программы, что повышает безопасность и стабильность системы. + +**Зачем нужны страницы:** +- **Упрощение управления памятью:** Разбиение памяти на страницы позволяет операционной системе эффективно управлять памятью, перемещая страницы между RAM и дисковым пространством по мере необходимости. +- **Изоляция процессов:** Использование страниц помогает изолировать [[Процесс ОС|процессы]] друг от друга, так как каждый процесс видит только своё виртуальное адресное пространство. +- **Подкачка:** Страницы, которые не используются, могут быть выгружены на диск, освобождая оперативную память для других нужд. +- **Обработка ошибок:** Когда процесс пытается обратиться к странице, которой нет в памяти, операционная система обрабатывает [[../../../../_inbox/Page Fault|Page Fault]], загружая нужную страницу с диска. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Разработка|00 Разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-09-17]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + +- [[DB page]] + diff --git a/dev/fundamental/Таблица задержек. память, сеть и устройства хранения.md b/dev/fundamental/Таблица задержек. память, сеть и устройства хранения.md new file mode 100644 index 00000000..3060f53c --- /dev/null +++ b/dev/fundamental/Таблица задержек. память, сеть и устройства хранения.md @@ -0,0 +1,37 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-11-04 +--- +``` +L1 cache reference ......................... 0.5 ns +Branch mispredict ............................ 5 ns +L2 cache reference ........................... 7 ns +Mutex lock/unlock ........................... 25 ns +Main memory reference ...................... 100 ns +Compress 1K bytes with Zippy ............. 3,000 ns = 3 µs +Send 2K bytes over 1 Gbps network ....... 20,000 ns = 20 µs +SSD random read ........................ 150,000 ns = 150 µs +Read 1 MB sequentially from memory ..... 250,000 ns = 250 µs +Round trip within same datacenter ...... 500,000 ns = 0.5 ms +Read 1 MB sequentially from SSD* ..... 1,000,000 ns = 1 ms +Disk seek ........................... 10,000,000 ns = 10 ms +Read 1 MB sequentially from disk .... 20,000,000 ns = 20 ms +Send packet CA->Netherlands->CA .... 150,000,000 ns = 150 ms +``` + +![[../../meta/files/images/Pasted image 20241104204304.png]] +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Разработка|00 Разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-04]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/fundamental/Центральный процессор.md b/dev/fundamental/Центральный процессор.md new file mode 100644 index 00000000..1b9c77c6 --- /dev/null +++ b/dev/fundamental/Центральный процессор.md @@ -0,0 +1,48 @@ +--- +aliases: + - ЦПУ + - ЦП + - CPU + - центральному процессору + - процессору + - процессоре + - процессора + - процессор +tags: + - maturity/🌱 +date: + - - 2024-01-28 +zero-link: + - "[[../../meta/zero/00 Архитектура ЭВМ|00 Архитектура ЭВМ]]" +parents: +linked: +--- +Центральный процессор (ЦП или CPU, от англ. Central Processing Unit) — это основной компонент компьютера и других вычислительных устройств, который выполняет инструкции программного обеспечения. Он интерпретирует и выполняет основные арифметические, логические и ввода/вывода операции, указанные в инструкциях программ. + +ЦП состоит из нескольких ключевых компонентов: + +1. **Арифметико-логическое устройство (АЛУ)**: Выполняет арифметические и логические операции. +2. **Устройство управления (УУ)**: Извлекает инструкции из памяти компьютера, декодирует и исполняет их, контролируя при этом работу всех компонентов компьютера. +3. **Регистры**: Используются для временного хранения данных и инструкций, необходимых для выполнения текущих операций. +4. **Шина данных**: Позволяет передачу данных между различными компонентами процессора и другими частями компьютера. +5. **Шина адреса**: Используется для указания адресов памяти, откуда или куда должны быть переданы данные. +6. **Шина управления**: Управляет различными типами сигналов для координации работы компонентов компьютера. + +Работа ЦП включает в себя выполнение цикла извлечения-декодирования-исполнения (fetch-decode-execute), где ЦП извлекает инструкцию из памяти, декодирует ее, чтобы понять, какую операцию необходимо выполнить, и затем исполняет эту операцию, возможно, используя данные, хранящиеся в памяти или регистрах. + +Первые процессоры могли одновременно выполнять только одну программу. В какой-то момент появились процессоры, которые содержат несколько [процессорных ядер](Ядро%20процессора.md). Каждое процессорное ядро может работать независимо от другого, что увеличивает производительность процессора, если ПО поддерживает работу в многоядерной системе. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ЭВМ|00 Архитектура ЭВМ]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-01-28]] +### Дополнительные материалы +- +### Дочерние заметки + + +- [[Многозадачность]] +- [[Ядро процессора]] + diff --git a/dev/fundamental/Ядро процессора.md b/dev/fundamental/Ядро процессора.md new file mode 100644 index 00000000..091793a8 --- /dev/null +++ b/dev/fundamental/Ядро процессора.md @@ -0,0 +1,39 @@ +--- +aliases: + - ядро + - ядер + - многоядерный + - одноядерный + - ядра процессора +tags: + - maturity/🌱 +date: + - - 2024-01-28 +linked: +--- +Ядра в контексте [[Центральный процессор|ЦП]] относятся к отдельным вычислительным единицам внутри одного физического процессора. Каждое ядро способно независимо обрабатывать инструкции, что обеспечивает многозадачность на аппаратном уровне. + +Современные процессоры могут иметь несколько ядер, улучшая общую производительность и эффективность системы путем параллельной обработки нескольких потоков данных или задач. + +Основные аспекты ядер ЦП: +- **Многопоточность**: Многие современные ядра поддерживают технологии многопоточности, такие как Hyper-Threading от Intel, которая позволяет одному физическому ядру обрабатывать два или более независимых потока исполнения (потоков) одновременно. Это улучшает использование ресурсов ЦП и повышает производительность при выполнении множества задач. +- **Независимость**: Каждое ядро обладает собственным набором ресурсов, таких как регистры и, иногда, кэш-память, что позволяет ему обрабатывать инструкции независимо от других ядер. +- **Кэш-память**: Ядра могут иметь индивидуальные кэш-памяти (обычно L1 и иногда L2) и совместно использовать более крупные кэши (например, L3) на уровне процессора. Это уменьшает задержку доступа к часто используемым данным и инструкциям. +- **Энергопотребление и производительность**: Современные ЦП обычно включают в себя функции для оптимизации энергопотребления и производительности, такие как динамическое изменение частоты и напряжения в зависимости от нагрузки. +- **Специализированные ядра**: Некоторые процессоры включают специализированные ядра для конкретных задач, например, графические ядра в CPU с интегрированной графикой или ядра, оптимизированные для искусственного интеллекта и машинного обучения. + +==В **любой конкретный момент времени** одно ядро процессора может выполнять инструкции только одного потока.== Однако, благодаря [[Планировщик ОС|планировщику ОС]] может создаваться иллюзия того, что множество потоков выполняются параллельно, хотя на самом деле они выполняются последовательно, но с очень высокой скоростью переключения, - [[Многозадачность|Многозадачность ЦПУ]]. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Архитектура ЭВМ|00 Архитектура ЭВМ]] +**Родитель**:: [[Центральный процессор|Центральный процессор]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-01-28]] +### Дополнительные материалы +- +### Дочерние заметки + + +- [[Процесс ОС]] + diff --git a/dev/gRPC.md b/dev/gRPC.md new file mode 100644 index 00000000..53624edf --- /dev/null +++ b/dev/gRPC.md @@ -0,0 +1,30 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-04-12 +--- +- Подходит для [[../../../../wiki/zero/00 Микросервисная архитектура|микросервисных архитектур]] для межсервисного общения. + +## Как работает? +![[../meta/files/images/Pasted image 20241103005832.png]] + +- **Шаг 1**: Клиент отправляет REST-запрос. Тело запроса обычно в формате JSON. +- **Шаги 2 - 4**: Сервис заказов (gRPC-клиент) получает REST-запрос, преобразует запрос в компактный бинарный формат и передает его в транспортный слой +- **Шаг 5**: gRPC отправляет пакеты по сети через HTTP/2. Благодаря бинарному кодированию и сетевым оптимизациям, gRPC считается в 5 раз быстрее, чем JSON. +- **Шаги 6 - 8**: Сервис оплаты (gRPC-сервер) получает пакеты из сети, декодирует их и вызывает серверное приложение. +- **Шаги 9 - 11**: Результат возвращается от серверного приложения, кодируется и передаётся на транспортный уровень. +- **Шаги 12 - 14**: Сервис заказов получает пакеты, декодирует их и отправляет результат в клиентское приложение. +## Проблемы +**Балансировка нагрузки L7 vs L4**: Kubernetes обычно использует балансировку нагрузки на уровне 4 (L4), которая перенаправляет трафик на основе информации IP и порта. Однако gRPC полагается на HTTP/2, что требует балансировки на уровне 7 (L7) для эффективного распределения запросов. Это может потребовать дополнительных настроек или использования специализированных ингресс-контроллеров, поддерживающих HTTP/2. +*** +## Мета информация +**Область**:: [[../meta/zero/00 Архитектура ИС|00 Архитектура ИС]] +**Родитель**:: [[architecture/Remote Procedure Call|RPC]], [[architecture/Протоколы коммуникаций]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-04-12]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/git/Откатываем git reset hard в Idea.md b/dev/git/Откатываем git reset hard в Idea.md new file mode 100644 index 00000000..a4a4c136 --- /dev/null +++ b/dev/git/Откатываем git reset hard в Idea.md @@ -0,0 +1,34 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-09-08 +zero-link: + - "[[../../meta/zero/00 Git|00 Git]]" +parents: +linked: +--- +Сделал "Reset current branch to here" в режиме "Hard", но забыл сделать "Shelf" для не зафиксированных изменений, над которыми работал весь день. В итоге проделанная работа за день была успешно стерта. + +В такие моменты главное не поддаваться панике 😅 + +В Idea есть [замечательная функция LocalHisotry](https://www.jetbrains.com/help/idea/local-history.html), которая автоматически сохраняет все изменения над файлами. Если затертых файлов было не много, то нажмите ПКМ и в меню выберете `Local History —> Show History`. + +![](../../meta/files/images/Pasted%20image%2020240908122428.png) + +Скорее всего вы увидите состояние файла до выполнения `git reset`. + +Если же измененных файлов было много, то восстанавливать их по одному довольно муторно. Поэтому нажмите ПКМ по корневой папке проекта и также выберете `Local History —> Show History`. + +Вот и все, впредь будьте внимательнее 😊 +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Git|00 Git]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-09-08]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/git/Удаление .DS_Store из Git репозитория.md b/dev/git/Удаление .DS_Store из Git репозитория.md new file mode 100644 index 00000000..1f1a4d4d --- /dev/null +++ b/dev/git/Удаление .DS_Store из Git репозитория.md @@ -0,0 +1,41 @@ +--- +tags: + - maturity/🌳 +date: 2023-08-31 +parents: +zero-link: + - "[[../../meta/zero/00 Снипеты для Git|00 Снипеты для Git]]" +--- +Симптомы: Есть не зафиксированный файл, который мешает гиту. Файл называется `.DS_Store`. + +Чтобы удалить этот файл нужно выполнить следующие команды: + +```shell +find . -name .DS_Store -print0 | xargs -0 git rm --ignore-unmatch +``` + +```shell +git rm --cached .DS_Store +``` + +```shell +git add . +``` + +```shell +git commit -m "Remove .DS_Store from current directory" +``` + +> [!WARNING] Терминал в Idea +> Команды необходимо выполнять из обычного родного терминала. Если выполнять из терминала Idea, то они не сработают. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Снипеты для Git|00 Снипеты для Git]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2023-08-31]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/java/Class Loader Subsystem.md b/dev/java/Class Loader Subsystem.md new file mode 100644 index 00000000..cf26ae03 --- /dev/null +++ b/dev/java/Class Loader Subsystem.md @@ -0,0 +1,39 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2023-11-06 +--- +## Тезисы +- Class Loader Subsystem — часть [[Java Virtual Machine|JVM]], ответственная за загрузку, связывание и инициализацию классов. +- Хранит информацию о загруженных классах и загружает скомпилированные файлы классов (Class Files) в память. +- [[gc/Garbage Collector|Сборка мусора]] здесь не производится, что может привести к `OutOfMemoryException` при создании большого количества классов "на лету". +- Основные этапы работы: загрузка, проверка, связывание и инициализация классов. +- Включает иерархию [[ClassLoader|Classloader]], что позволяет гибко управлять загрузкой и безопасностью классов. +*** + +Class Loader Subsystem — это часть [[Java Virtual Machine|JVM]], которая отвечает за управление процессом загрузки, связывания и инициализации классов. Здесь хранится информация о классах, которые были загружены в память. Он берет скомпилированные файлы классов (Class Files) и загружает их для использования в программе. + +Важно отметить, что [[gc/Garbage Collector|сборка мусора]] в этой части JVM не производится, поэтому при создании большого количества классов "на лету" существует риск получения ошибки `OutOfMemoryException`. + +**Основные этапы работы Class Loader Subsystem** +1. **Загрузка (Loading)**: На этом этапе Class Loader Subsystem находит и загружает файлы классов в память. Используются различные типы [[ClassLoader|Classloader]] (Bootstrap, Extension, Application), которые обеспечивают доступ к необходимым классам в зависимости от их принадлежности. +2. **Проверка (Verification)**: После загрузки классов выполняется проверка их корректности. Это необходимо для предотвращения потенциально опасного кода, который может нарушить работу JVM или привести к сбоям. Проверка включает анализ структуры байт-кода, соответствие стандартам Java и другие меры безопасности. +3. **Связывание (Linking)**: Этот этап включает несколько подпроцессов: + - **Подготовка (Preparation)**: Создаются статические поля классов и выделяется память под них, но не происходит их инициализация. + - **Разрешение (Resolution)**: Разрешаются ссылки на другие классы и их методы, чтобы JVM могла корректно работать с зависимостями между классами. +4. **Инициализация (Initialization)**: На этом этапе выполняются статические инициализаторы классов и инициализируются статические переменные. Это завершающий этап, который делает класс готовым к использованию. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: [[Архитектура JVM]] +**Источник**:: +**Автор**:: +**Создана**:: [[2023-11-06]] +### Дополнительные материалы +- +### Дочерние заметки + + +- [[ClassLoader]] + diff --git a/dev/java/ClassLoader.md b/dev/java/ClassLoader.md new file mode 100644 index 00000000..6439751e --- /dev/null +++ b/dev/java/ClassLoader.md @@ -0,0 +1,97 @@ +--- +aliases: + - Class Loader + - Class Loaders +tags: + - maturity/🌱 +date: 2024-11-04 +--- +## Тезисы +- Classloader — это компонент JVM, отвечающий за динамическую загрузку классов в память во время выполнения программы. +- Classloader выполняет загрузку, проверку, связывание и инициализацию классов. +- В Java существует иерархия Classloader: Bootstrap, Extension (Platform), и Application (System). +- Классы могут загружаться из нестандартных источников с использованием кастомного Classloader, что полезно для создания модульных систем или плагинов. +*** + +Classloader — это компонент [[Java Virtual Machine|JVM]], отвечающий за динамическую загрузку классов в память во время выполнения программы. В Java каждый класс должен быть загружен в память перед его использованием, и именно Classloader выполняет эту задачу. + +**Функции Classloader** +1. **Загрузка классов**: Classloader находит и загружает файлы классов (обычно с расширением `.class`) из classpath в память. +2. **Проверка классов**: После загрузки Classloader проверяет [[Java байт-код|байт-код]] класса для обеспечения его корректности и безопасности. +3. **Связывание классов**: Classloader связывает загруженные классы, включая проверку ссылок и разрешение символов. +4. **Инициализация классов**: Classloader инициализирует загруженные классы, вызывая их статические инициализаторы и инициализаторы переменных. + +**Иерархия Classloader** +- **Bootstrap ClassLoader**: Базовый загрузчик классов, встроенный в JVM. Он загружает основные классы Java из файла rt.jar, такие как классы из `java.lang`, `java.util` и других. Реализован на нативном языке и является частью ядра JVM. +- **Extension ClassLoader (Platform ClassLoader)**: Загружает классы из стандартных расширений Java, находящихся в директории `jre/lib/ext` или другой директории, определенной системным параметром `java.ext.dirs`. Обратите внимание, что директория `jre/lib/ext` используется в старых версиях Java, а более новые версии могут использовать другой подход. Сам загружается с помощью Bootstrap ClassLoader. +- **Application ClassLoader (System ClassLoader)**: Загружает классы приложения из директории classpath. Обычно это директория, указанная в переменной окружения `CLASSPATH` или параметре командной строки `-cp`. Используется для загрузки классов приложений и библиотек. + +Пример: +```java +public class Main { + public static void main(String[] args) { + ClassLoader classLoader = Main.class.getClassLoader(); + System.out.println("ClassLoader: " + classLoader); + + try { + Class aClass = classLoader.loadClass("Example"); + System.out.println("Class loaded: " + aClass.getName()); + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } + } +} +``` + +Этот пример демонстрирует, как можно использовать Classloader для динамической загрузки классов во время выполнения программы. Он полезен в случаях, когда классы могут быть неизвестны на этапе компиляции и должны быть загружены из внешних источников, например, при создании плагинов или модулей, добавляемых на лету. +## Кастомный Classloader +Можно создавать собственные Classloader, расширяя класс `java.lang.ClassLoader`, для загрузки классов из нестандартных источников (например, из базы данных, сети или зашифрованных архивов). Это может быть полезно, когда требуется загрузить обновляемые модули или плагины, которые могут меняться без необходимости перезапуска всей системы. Например, кастомный Classloader можно использовать для реализации системы плагинов, где плагины загружаются динамически по запросу пользователя. + +```java +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Paths; + +public class CustomClassLoader extends ClassLoader { + + @Override + public Class findClass(String name) throws ClassNotFoundException { + try { + byte[] bytes = loadClassData(name); + return defineClass(name, bytes, 0, bytes.length); + } catch (IOException e) { + throw new ClassNotFoundException(name, e); + } + } + + private byte[] loadClassData(String name) throws IOException { + String path = name.replace('.', '/') + ".class"; + InputStream inputStream = Files.newInputStream(Paths.get(path)); + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + int data; + while ((data = inputStream.read()) != -1) { + byteArrayOutputStream.write(data); + } + return byteArrayOutputStream.toByteArray(); + } +} +``` + +- Мы расширяем `ClassLoader` и переопределяем метод `findClass`. +- Метод `loadClassData` загружает данные класса из файла. +- Метод `defineClass` создает класс из байтового массива. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: [[Class Loader Subsystem|Class Loader Subsystem]] +**Источник**:: +**Создана**:: [[2024-11-04]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/java/Execution Engine.md b/dev/java/Execution Engine.md new file mode 100644 index 00000000..cff8821e --- /dev/null +++ b/dev/java/Execution Engine.md @@ -0,0 +1,29 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-11-24 +--- +Execution Engine — это основная часть [[Java Virtual Machine]] (JVM), которая выполняет [[Java байт-код|байт-код]] Java. Он играет важную роль в преобразовании скомпилированного байт-кода (`.class` файлы) в машинный код, который может быть выполнен на конкретной платформе. + +Этот процесс делает Java переносимой, позволяя одной и той же программе выполняться на различных устройствах и операционных системах. Это достигается тем, что байт-код, сгенерированный компилятором Java, является платформенно-независимым, а Execution Engine адаптирует его для конкретной машины. + +**Основные компоненты Execution Engine** +- [[ClassLoader|Class Loader]] (Загрузчик классов). Class Loader отвечает за загрузку классов и интерфейсов в JVM по мере их необходимости. Например, это полезно при работе с фреймворками, такими как Spring, где классы могут загружаться динамически в зависимости от конфигурации или окружения. Это позволяет программам динамически подключать классы, снижая начальное время загрузки и делая систему более гибкой. +- **Interpreter (Интерпретатор)** Интерпретатор отвечает за выполнение байт-кода, читая его инструкции и выполняя их одну за другой. Хотя интерпретация обеспечивает гибкость, она может быть медленнее по сравнению с компилированным исполнением, так как требует постоянного преобразования байт-кода в машинный код во время выполнения. +- **Just-In-Time Compiler (JIT-компилятор)** Для повышения производительности JVM использует JIT-компилятор. JIT-компиляция преобразует часто выполняемые части байт-кода в машинный код, который может выполняться напрямую процессором. Это значительно ускоряет выполнение программы по сравнению с постоянной интерпретацией. +- [[gc/Garbage Collector|Garbage Collector]] (Сборщик мусора). Сборщик мусора управляет памятью JVM, автоматически освобождая её от объектов, которые больше не используются. Это предотвращает утечки памяти и снижает риск ошибок, связанных с ручным управлением памятью. + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: [[Java Virtual Machine|JVM]] +**Источник**:: +**Создана**:: [[2024-11-24]] +**Автор**:: +### Дополнительные материалы +- [[Процесс выполнения Java программы|Процесс выполнения Java программы]] + +### Дочерние заметки + + diff --git a/dev/java/JDK для Apple Silicon.md b/dev/java/JDK для Apple Silicon.md new file mode 100644 index 00000000..3df234a9 --- /dev/null +++ b/dev/java/JDK для Apple Silicon.md @@ -0,0 +1,40 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-09-08 +zero-link: + - "[[../../meta/zero/00 Java разработка|00 Java разработка]]" +parents: + - "[[JDK]]" +linked: +--- +Когда-то давным давно скачал [JDK](JDK.md), работает и ладно. Посмотрел доклад про [нативные сборки](Нативные%20сборки%20в%20Java.md), и там упоминалось про [JDK](JDK.md) для Apple Silicon. Решил проверить, а такой ли у меня. Оказалось не такой. + +В итоге вот сколько собирался большой [монолит](../architecture/Монолитная%20архитектура.md) (с генерацией javadoc), состоящий из 22 модуля на обычной [JDK](JDK.md). Все зависимости были закачены заранее и сборка была запущена в [многопоточном режиме](Параллельная%20сборка%20модулей%20в%20Maven.md). + +![](../../meta/files/images/Pasted%20image%2020240908115826.png) + +И вот сколько на [JDK](JDK.md) для Apple Silicon: + +![](../../meta/files/images/Pasted%20image%2020240908115909.png) + +> СБОРКА СТАЛА БЫСТРЕЕ В 4 РАЗА! + +> [!WARNING] +> Проект собирался без генерации javadoc. С генерацией JavaDoc сборка была быстрее всего в 1,6 раза. В целом нет смысла запускать локальную сборку с генерацией javadoc. + +Если вы владелец Macbook-а на базе Apple Silicon, то рекомендую проверить вашу версию Java. Возможно вы используете обычную [JDK](JDK.md), вместо сборки под Apple Silicon. Должна быть aarch64, как на скрине. + +![](../../meta/files/images/Pasted%20image%2020240908120026.png) +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: [[JDK]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-09-08]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/java/JDK.md b/dev/java/JDK.md new file mode 100644 index 00000000..6a51c6a2 --- /dev/null +++ b/dev/java/JDK.md @@ -0,0 +1,31 @@ +--- +aliases: + - jdk +tags: + - maturity/🌱 +date: 2023-09-27 +zero-link: + - "[[../../meta/zero/00 Java разработка|00 Java разработка]]" +linked: +--- +- [[JDK 8]] +- [[JDK 11]] +- [[JDK 17]] +- [JDK 21](JDK%2021.md) +## Заметки +- Идеи формируются в JEP разработка ведется в рамках JSP + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2023-09-27]] +### Дополнительные материалы +- +### Дочерние заметки + + +- [[JDK для Apple Silicon]] + diff --git a/dev/java/JDeps.md b/dev/java/JDeps.md new file mode 100644 index 00000000..e0ef96b0 --- /dev/null +++ b/dev/java/JDeps.md @@ -0,0 +1,43 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-10-15 +zero-link: +parents: +linked: +--- +JDeps — это инструмент для анализа зависимостей модулей и пакетов, который был введён в [[../../../../knowledge/dev/java/JDK 8|JDK 8]], ещё до появления модульной системы [[Java Platform Module System|JPMS]]. Основная задача JDeps — помочь разработчикам понять, как модули и пакеты связаны друг с другом внутри проекта. + +Основные возможности: +- Показывает, какие модули используются в проекте, какие зависимости между ними существуют и какие модули вызывают друг друга. +- Позволяет анализировать, какие библиотеки и классы реально используются, что помогает очищать проект от лишних зависимостей + +Пример запуска Jdeps +```bash +jdeps --multi-release 17 --ignore-missing-deps -q -recursive --print-module-deps -cp 'project-core/build/lib/boot/*':'project-core/build/lib/main/*':'project-core/build/app/*' project-core/build/app/* + +Output: +jdk.zipfs,jdk.management,jdk.crypto.cryptoki,java.security.jgss,jdk.crypto.ec +``` + +- `--multi-release 17`: указывает на использование многоверсионного JAR-файла для JDK 17, что позволяет учитывать разные версии классов для разных версий JDK. +- `--ignore-missing-deps`: игнорирует отсутствующие зависимости, чтобы избежать ошибок при их отсутствии. +- `-q`: отключает подробный вывод, что делает команду менее «шумной» и оставляет только ключевые данные. +- `-recursive`: указывает JDeps анализировать зависимости всех модулей рекурсивно. +- `--print-module-deps`: выводит список всех модулей, которые требуются для работы проекта. +- `-cp`: указывает путь к классам и библиотекам проекта. + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-10-15]] +**Автор**:: +### Дополнительные материалы +- [[JLink]] + +### Дочерние заметки + + diff --git a/dev/java/JLink.md b/dev/java/JLink.md new file mode 100644 index 00000000..6da05c75 --- /dev/null +++ b/dev/java/JLink.md @@ -0,0 +1,55 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-10-15 +zero-link: +parents: +linked: +--- +JLink — это мощный инструмент, который был введён в [[../../../../knowledge/dev/java/Java 9|Java 9]] как часть модульной системы [[Java Platform Module System|JPMS]]. Его основная задача — создание кастомизированных [[JDK]], включающих только необходимые модули для работы конкретного приложения. + +Благодаря исключению ненужных модулей, приложения, собранные с помощью JLink, становятся легче и быстрее загружаются. Это особенно важно для приложений, работающих в ограниченных средах, например, в микросервисной архитектуре или на встраиваемых устройствах. Меньший размер JRE снижает время старта и использование оперативной памяти, что критично в условиях ограниченных ресурсов. + +Например, обычный JRE содержит десятки модулей, таких как `java.sql` или `java.xml`, которые могут быть не нужны конкретному приложению. Используя JLink, разработчик может создать минимальный набор модулей, достаточный для его проекта. + +Основная команда JLink выглядит следующим образом: +```bash +jlink --module-path $JAVA_HOME/jmods --add-modules <список модулей> --output <путь_к_результирующей_JRE> +``` + +- `--module-path` указывает путь к модульной системе JDK, которая по умолчанию находится в папке `jmods` в вашем JDK. +- `--add-modules` определяет, какие модули будут включены в итоговую сборку JRE. Это могут быть как модули стандартной библиотеки (например, `java.base`), так и модули вашего приложения. +- `--output` указывает папку, в которую будет выведена готовая сборка JRE. + +**Основные опции JLink** +- `–-strip-debug`. Удаляет символы отладки из итоговой сборки JRE. Это помогает дополнительно уменьшить размер JRE, особенно когда приложение не нуждается в отладочной информации. +- `--compress`. отвечает за сжатие файлов в сборке JRE. Она поддерживает несколько уровней сжатия: + - 0 — без сжатия (по умолчанию), + - 1 — сжатие классов, но без применения дорогих методов сжатия, + - 2 — максимальное сжатие, что снижает размер сборки, но может замедлить время загрузки. +- `-–strip-native-commands`. Эта опция удаляет нативные команды (например, инструменты вроде jcmd, jmap, и другие утилиты), которые не нужны в большинстве рабочих окружений. +- `--launcher`. Позволяет создавать собственные лаунчеры для вашего приложения. Это может быть полезно для упрощения запуска приложения конечными пользователями. Лаунчеры создаются в директории bin сгенерированной JRE. Пример `--launcher myapp_launcher=myapp.module/com.example.Main` +- `--bind-services`. Полезна для автоматического связывания сервисов, если приложение использует `ServiceLoader`. Эта опция необходима, когда модульная система управляет загрузкой сервисов, и их нужно зарегистрировать для запуска приложения. +- `--target`. Позволяет создавать JRE для других платформ (например, создавать сборку для Linux с машины на Windows). Пример `--target linux-x64` + +[[JDeps]] анализирует зависимости приложения, автоматически определяя, какие модули используются, а JLink на основе этого анализа создаёт кастомную JRE + +Пример совместного использования JDeps и JLink: +```bash +jlink --add-modules $(jdeps --multi-release 17 --ignore-missing-deps -q -recursive --print-module-deps -cp 'project-core/build/lib/boot/*':'project-core/build/lib/main/*':'project-core/build/app/*' project-core/build/app/*) --strip-debug --no-man-pages --no-header-files --compress=2 --output ./build/jdk +``` + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-10-15]] +**Автор**:: +### Дополнительные материалы +- [[JDeps]] + +### Дочерние заметки + + diff --git a/dev/java/Java 21 LTS.md b/dev/java/Java 21 LTS.md new file mode 100644 index 00000000..f3bf0c9c --- /dev/null +++ b/dev/java/Java 21 LTS.md @@ -0,0 +1,25 @@ +--- +aliases: + - java 21 +tags: + - maturity/🌱 +date: 2023-11-08 +zero-link: [] +parents: +linked: +--- +- [[Java Virtual Threads|Java Virtual Threads]] +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2023-11-08]] +### Дополнительные материалы +- +### Дочерние заметки + + +- [[Java Virtual Threads]] + diff --git a/dev/java/Java Platform Module System.md b/dev/java/Java Platform Module System.md new file mode 100644 index 00000000..82568645 --- /dev/null +++ b/dev/java/Java Platform Module System.md @@ -0,0 +1,58 @@ +--- +aliases: + - модули + - модуль + - модулей + - JPMS + - модульную систему +tags: + - maturity/🌱 +date: 2024-10-15 +zero-link: +parents: +linked: +--- +Модульная система Java (JPMS), представленная в [[../../../../knowledge/dev/java/Java 9|Java 9]], позволяет разработчикам разбивать приложения на логически обособленные блоки — модули. + +> [!WARNING] Не Maven/Gradle модули +> Модули в Maven и Gradle — это структурные единицы системы сборки, которые помогают управлять зависимостями и сборкой проекта, но они не являются модулями в контексте модульной системы Java (JPMS). + +Модуль - это набор пакетов, содержащих типы (классы и интерфейсы) ресурсы и другие виды статической информации. + +**Какие проблемы решает?** +- Делает зависимости явными +- Улучшает [[../architecture/Инкапсуляция|инкапсуляцию]], предотвращая создание нежелательных зависимостей между модулями. Все привыкли к модификаторам доступов у классов, но у пакетов модификаторов доступа не было. + +Одним из ключевых преимуществ JPMS является чёткий контроль зависимостей. В старой системе через classpath все классы и пакеты были доступны друг другу без явного указания разрешений, что часто приводило к ошибкам и некорректному использованию библиотек. С JPMS разработчики могут точно указывать, какие зависимости нужны модулю и какие его части будут видимы другим модулям. +## Дескриптор +Каждый модуль имеет дескриптор - файл `module-info.java`, который содержит описание того, какие зависимости необходимы модулю и какие пакеты он экспортирует для других. Этот файл должен быть размещен в папке `src/main/java`. + +Дескриптор описывает: +- Импортируемые, экспортируемые, транзитивно-экспортируемые пакеты. + +Пример простого дескриптора: +```java title=module-info.java +module com.example.myapp { + requires java.sql; + exports com.example.myapp.service; +} +``` + +В этом примере модуль называется `com.example.myapp` и он использует (`requires`) модуль `java.sql` и экспортирует (`exports`) пакет `com.example.myapp.service`, который может быть использован другими модулями. Все остальные пакеты, не указанные в директиве `exports`, остаются приватными и недоступными для других модулей. + +> [!NOTE] Обратная совместимость +> Модульная система разработана с учётом совместимости с предыдущими версиями JDK. Проекты, которые не перешли на JPMS, могут по-прежнему использовать старую систему через classpath. + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: [[../../../../knowledge/dev/java/Устройство Java|Устройство Java]] +**Источник**:: +**Создана**:: [[2024-10-15]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/java/Java Reflection.md b/dev/java/Java Reflection.md new file mode 100644 index 00000000..ab8c653c --- /dev/null +++ b/dev/java/Java Reflection.md @@ -0,0 +1,24 @@ +--- +aliases: + - рефлексию + - рефлексия +tags: + - maturity/🌱 +date: 2024-09-11 +zero-link: + - "[[00 Java разработка]]" +parents: +linked: +--- + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-09-11]] +**Автор**:: +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/java/Java Virtual Machine.md b/dev/java/Java Virtual Machine.md new file mode 100644 index 00000000..018d60cc --- /dev/null +++ b/dev/java/Java Virtual Machine.md @@ -0,0 +1,16 @@ +--- +aliases: + - JVM +tags: + - maturity/🌱 +date: 2023-11-07 +--- +JVM (Java Virtual Machine) — это виртуальная машина, которая выполняет программы, написанные на языке Java, а также другие языки платформы Java, такие как Kotlin и Scala. Её основная задача — выполнение [[Java байт-код|байт-кода]], промежуточного представления между исходным кодом и машинным кодом конкретного устройства. JVM также управляет памятью, сборкой мусора, безопасностью и многопоточностью, создавая надёжную среду для выполнения приложений. + +**Основные функции JVM** +- **Платформонезависимость**. Java-программы компилируются в байт-код, который может выполняться на любой системе с установленной JVM, что позволяет запускать один и тот же код на различных операционных системах и аппаратных платформах без изменений. +- **Управление памятью**. JVM управляет памятью через кучу (heap), автоматически выделяя и освобождая память, что устраняет необходимость ручного управления и снижает риск утечек. +- [[gc/Garbage Collector|Сборка мусора]] (Garbage Collection). JVM использует сборщик мусора для автоматического освобождения памяти, занятой объектами, которые больше не используются. Это предотвращает утечки памяти и улучшает производительность приложения. +- **Безопасность**. JVM обеспечивает безопасное выполнение кода с помощью системы управления доступом, проверяющей разрешения для выполнения определённых операций, таких как доступ к файловой системе, что помогает предотвратить выполнение вредоносного кода. +- **Многопоточность**. JVM поддерживает [[../fundamental/Multithreading|многопоточность]], позволяя разрабатывать многопоточные приложения на уровне языка. Она управляет созданием, синхронизацией и выполнением потоков. +- **Управление исключениями**. JVM предоставляет механизм обработки исключений, который позволяет программам Java надёжно обрабатывать ошибки во время выполнения, повышая стабильность и устойчивость приложений. \ No newline at end of file diff --git a/dev/java/Java Virtual Threads.md b/dev/java/Java Virtual Threads.md new file mode 100644 index 00000000..5e977002 --- /dev/null +++ b/dev/java/Java Virtual Threads.md @@ -0,0 +1,32 @@ +--- +aliases: + - виртуальные потоки + - виртуальный поток + - виртуальных потоков +tags: + - maturity/🌱 +date: 2024-10-03 +zero-link: +parents: +linked: +--- +Виртуальный поток не привязан к конкретному [[../fundamental/Поток процесса ОС|потоку ОС]]. При вызове [[../architecture/Блокирующий вызов|блокирующей операции]] Java останавливает этот поток, до момента пока его можно будет вызвать. То есть мы освобождаем настоящий поток ОС, чтобы он не простаивал. + +![[../../../../garden/ru/meta/files/images/Pasted image 20241003081726.png]] + +В виртуальных потоках не рекомендуется использовать ThreadLocal. + +Виртуальный поток не поможет вам, если ваши операции требуют активной работы CPU. +*** +## Мета информация +**Область**:: [[../../../../garden/ru/meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: [[../../../../garden/ru/dev/java/Java 21 LTS|Java 21 LTS]] +**Источник**:: +**Создана**:: [[2024-10-03]] +**Автор**:: +### Дополнительные материалы +- [Примеры · GitHub](https://github.com/petrelevich/jvm-digging/tree/master/virtual-thread) + +### Дочерние заметки + + diff --git a/dev/java/Java байт-код.md b/dev/java/Java байт-код.md new file mode 100644 index 00000000..926341c5 --- /dev/null +++ b/dev/java/Java байт-код.md @@ -0,0 +1,22 @@ +--- +aliases: + - байт-кода + - байт-код +tags: + - maturity/🌱 +date: 2024-11-03 +--- +Байт-код является универсальным форматом, который можно запускать на любой платформе с установленной [[Java Virtual Machine|JVM]], что обеспечивает независимость от платформы +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-03]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/java/ResultSet.md b/dev/java/ResultSet.md new file mode 100644 index 00000000..44395567 --- /dev/null +++ b/dev/java/ResultSet.md @@ -0,0 +1,70 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-11-24 +--- +`ResultSet` — это интерфейс, используемый для хранения и управления результатами SQL-запроса типа SELECT к базе данных. Он позволяет Java-программе извлекать и обрабатывать данные, возвращаемые запросом. + +- **Получение данных**: при выполнении запроса SELECT база данных возвращает данные в виде таблицы. `ResultSet` предоставляет доступ к этим данным в Java-коде. +- **Обработка данных**: интерфейс включает методы для навигации по строкам и извлечения значений из текущей строки. +- **Управление данными**: `ResultSet` также позволяет перемещать курсор по строкам данных и получать доступ к столбцам по имени или индексу. + +Создание и выполнение запроса + ```java + Statement stmt = connection.createStatement(); + ResultSet rs = stmt.executeQuery("SELECT * FROM employees"); + ``` + +Обработка данных + ```java + while (rs.next()) { + int id = rs.getInt("id"); + String name = rs.getString("name"); + double salary = rs.getDouble("salary"); + System.out.println("ID: " + id + ", Name: " + name + ", Salary: " + salary); + } + ``` +## Основные методы +Эти методы являются ключевыми для работы с объектом `ResultSet`, позволяя эффективно взаимодействовать с базой данных: + +`next()` — перемещает курсор к следующей строке. + + ```java + rs.next(); + ``` + +`getInt()`, `getString()`, `getDouble()` и другие get-методы — извлекают данные из текущей строки. + + ```java + int id = rs.getInt("id"); + String name = rs.getString("name"); + double salary = rs.getDouble("salary"); + ``` + +`close()` — закрывает ResultSet и освобождает связанные с ним ресурсы. + + ```java + rs.close(); + ``` + +`getMetaData()` — возвращает объект `ResultSetMetaData`, содержащий метаданные о результирующем наборе данных, такие как количество столбцов и их типы. + + ```java + ResultSetMetaData metaData = rs.getMetaData(); + int columnCount = metaData.getColumnCount(); + ``` + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: [[../../../../knowledge/dev/java/other/Java Database Connectivity|Java Database Connectivity]] +**Источник**:: +**Создана**:: [[2024-11-24]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/java/gc/Garbage Collector.md b/dev/java/gc/Garbage Collector.md new file mode 100644 index 00000000..2cdeb881 --- /dev/null +++ b/dev/java/gc/Garbage Collector.md @@ -0,0 +1,172 @@ +--- +aliases: + - сборщик мусора + - GC + - сборка мусора + - сборки мусора + - сборщику мусора +tags: + - maturity/🌿 +zero-link: + - "[[../../../meta/zero/00 Java разработка|00 Java разработка]]" +parents: + - "[[../../../../knowledge/dev/java/Устройство Java|Устройство Java]]" +linked: +date: 2023-11-06 +--- +В некоторых языках есть механизм автоматического и безопасного освобождения оперативной памяти, ранее выделенной объектам в программе. Влияние разработчика на этот процесс опосредованное, прямого управления нет. Этот механизм принято называть Garbage collector (GC). + +> [!WARNING] Структура памяти в Java +> Перед изучением данной темы необходимо понимать, как устроена память в Java. + +Некоторые языки возлагают ответственность за управление памятью на разработчика, например C, C++, Rust. В таком случае разработчик должен сам, в коде, вызвать метод удаления объекта, чтобы освобождать память. Если этого не делать, то можно получить [[утечку памяти]]. + +Наличие GC в языке можно сравнить с коробкой автомат в автомобиле: вы получаете удобство, но в какой-то степени теряете контроль. + +Вы получаете следующие преимущества: +- Ускорение разработки. +- Защита от утечек памяти. + +B следующие недостатки: +- Потребление дополнительных вычислительных ресурсов. +- Утечки памяти :) +- [StopTheWorld](StopTheWorld.md) + +> [!NOTE]- Шуточная молитва сборщиков мусора +> Дай мне места для размещения того, что пока еще нужно. Дай мне смелости удалить то, что больше не пригодится. И дай мне мудрости, чтобы отличить одно от другого. +## Производительность GC +Вам быстро, дешево или качественно? +- [[../../architecture/Throughput|Throughput]]. Объем вычислительных ресурсов CPU, затрачиваемых на работу GC. +- **Предсказуемость.** На какое время прерывается работа приложения. +- **Footprint.** Объем используемой памяти. +## Работа GC +Глобально у GC есть всего 2 задачи: +- Найти мусор. То есть понять, что объект больше не будет использоваться. +- И собрать мусор. Уничтожить такие объекты, чтобы на их месте можно было алоцировать новые. + +> [!NOTE] +> В процессе своей работы GC не потребляет память в [[Heap]] +### Алгоритмы поиска мусора +#### Reference Counting +Этот алгоритм подсчитывает количество ссылок на каждый объект. Когда счетчик ссылок достигает нуля, объект считается недоступным. + +Есть довольно много ситуаций, когда данный способ не работает. Например, циклический граф, где объекты ссылаются друг на друга, но они все являются мусором. + +#### Tracing +Подсчет ссылок. Это наиболее распространенный алгоритм маркировки. Он начинается с изначально достижимых, "корневых" (GC Root), объектов и отслеживает все объекты, доступные от этих корней. + +> [!QUESTION] Что может быть выбрано в качестве GC Root? +> Локальные переменные и статические переменные в Main классе и main методе, поток, который выполняет main, статические переменные, ссылки из JNI. +^gcroot +### Подходы к сбору мусора +- [StopTheWorld](StopTheWorld.md) +- [Copy Collector](Copy%20Collector.md) +- [Mark and Sweep](Mark%20and%20Sweep.md) +- [Mark and Compact](Mark%20and%20Compact.md) +- [Generational Collection](Generational%20Collection.md) +- [Incremental Collection](Incremental%20Collection.md) +- [Parallel Collection](Parallel%20Collection.md) +- [Concurrent Collection](Concurrent%20Collection.md) + +### Потоки GC +#### Search thread +- Отдельный поток, который занимается поиском мусора и подает сигнал для запуска сборки. +- Как правило он один и работает параллельно с основной программой. +#### GC thread +- Отдельный поток, который занимается сборкой мусора. +- Таких потоков может быть много. +- Имеет несколько причин для старта. +- Может быть причиной StopTheWorld +### Причины старта GC +Главные: +- **Allocation Failure.** JVM попыталась выделить область памяти под новый объект, но памяти не хватило +- **GC Locker.** Кто-то подал сигнал на уборку. + +Остальные: +- **Adaptive Size Ergonomics.** +- **Allocation Profiler.** Профайлер оказывает влияние на сборку мусора искажая показатели. +- **Heap Inspection.** +- **Heap Dump.** +- **No GC.** Если сборка мусора еще не запускалась или проходила давольно давно. +- **Last Ditch Collection.** +- **Perm Generation Ful.** +- **Meradata GC Threshold.** + +### Minor Collection +^minor + +Если количество используемой Eden Space памяти превышает некоторый заданный объем, то GC может выполнить быструю (minor) сборку мусора. По сравнению с полной сборкой мусора, данный процесс занимает немного времени и затрагивает только область молодого поколения, - устаревшие объекты без ссылок удаляются, а выжившие перемещаются в Survivor Space. + +### Full Collection +В отличии от minor сборок охватывает весь Heap и занимает больше времени. +### Сборщики +- [Epsilon GC](Epsilon%20GC.md). Не собирает мусор :) +- [Serial GC](Serial%20GC.md). Морально устарел, но подойдет для консольных приложений. +- [Parallel GC](Parallel%20GC.md). Подходит для всех остальных случаев. +- [Parallel Compacting Collector](Parallel%20Compacting%20Collector.md). +- [Concurrent Mark Sweep](Concurrent%20Mark%20Sweep.md). Минимизирует время простоя в приложениях с долгоживущими данными. Подходит для web-приложений. +- [Garbage First](Garbage%20First.md). Хорошо подходит для больших объемов памяти в сочетании с небольшими объектами. +- Ultra-low latency + - [ZGC](ZGC.md) + - [Shenandoah GC](Shenandoah%20GC.md) + +По умолчанию обычно используется или [Serial](Serial%20GC.md) или [Parallel GC](Parallel%20GC.md). + +![](Pasted%20image%2020231108140632.png) +## Как повлиять на сборку? +- Писать код с учетом особенностей работы GC. Неблагодарный труд. +- Использовать флаги JVM + +Команда `System.gc()` носит рекомендательный характер. Разработчик рекомендует JVM запустить GC, но JVM может этого и не сделать. +## Мониторинг работы GC +Минимальные накладные расходы + +Параметры VM +- `-XX:+PrintGCDetails -XX:+PrintGCTimeStamps` +- `-Xlog:gc` Показывает время [StopTheWorld](StopTheWorld.md). + - Стоит помнить про [Safe Point](Safe%20Point.md). Этот параметр показывает время без учета накладных расходов. +- `-Xlog:safepoint`. Показывает время с накладными расходами. +- `-Xloggc:` +- `-XX:+PrintGcDateStamps` +- `-XX:+PrintHeapAtGC` +- `-XX:+PrintTenuringDistribution` + +Анализ диагностического вывода: +- PrintGCStats +- GChisto +- VisualVM / VisualGC + +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: [[../../../../../knowledge/dev/java/Устройство Java|Устройство Java]] +**Источник**:: +**Автор**:: +**Создана**:: [[2023-11-06]] +### Дополнительные материалы +1. [Сборка мусора в Java](https://www.youtube.com/watch?v=St6iBm4sHl8). + 1. В общих чертах о сборке мусора. +2. [Алексей Шипилёв — Shenandoah](https://www.youtube.com/watch?v=kKigibHrV5I). + 1. Подробно рассказаны алгоритмы маркировки и копирования объектов. +3. [Заметки Гусев Влад](Garbage%20Collection.docx) +4. Есть какая-то книга GC Handbook +### Дочерние заметки + + +- [[Concurrent Collection]] +- [[Concurrent Mark Sweep]] +- [[Copy Collector]] +- [[Epsilon GC]] +- [[Garbage First]] +- [[Generational Collection]] +- [[Incremental Collection]] +- [[Mark and Compact]] +- [[Mark and Sweep]] +- [[Parallel Collection]] +- [[Parallel Compacting Collector]] +- [[Parallel GC]] +- [[Serial GC]] +- [[Shenandoah GC]] +- [[StopTheWorld]] +- [[ZGC]] + diff --git a/dev/java/hibernate/Дублирование значений при использовании @ElementCollection и @OneToMany.md b/dev/java/hibernate/Дублирование значений при использовании @ElementCollection и @OneToMany.md new file mode 100644 index 00000000..8b02b6c9 --- /dev/null +++ b/dev/java/hibernate/Дублирование значений при использовании @ElementCollection и @OneToMany.md @@ -0,0 +1,59 @@ +--- +aliases: +tags: + - maturity/🌱 +date: + - - 2024-09-06 +zero-link: + - "[[../../../meta/zero/00 Hibernate|00 Hibernate]]" +parents: +linked: +--- +Столкнулся с неочевидным поведением `@ElementCollection` в связке с `@OneToMany`. Может случиться так, что в `@OneToMany` будет дублирование значений из-за `@ElementCollection`. Проще объяснить на примере. + +Допустим у нас есть три таблицы: `user`, `user_nickname`, `address`. Есть сущность `User`: + +```java +@Entity +public class User { + + // ... ... ... ... ... + + @OneToMany(mappedBy = "user", fetch = FetchType.EAGER) + private List
stages = new ArrayList<>(); + + @ElementCollection(fetch = FetchType.EAGER) + @CollectionTable( + name = "user_nickname", + joinColumns = @JoinColumn(name = "user_id") + ) + @Column(name = "nickname") + private Set nicknames = new HashSet<>(); + + // ... ... ... ... ... + +} +``` + +Допустим у нас одна запись про пользователя, у которого есть три адреса и один никнейм. В этом случае все хорошо, все придет корректно. + +==Добавим этому пользователю еще один никнейм. Теперь мы получаем шесть адресов и два никнейма. Откуда взялись еще три лишних адреса, в базе данных их все еще три.== Это дубликаты. При этом, если вы воспользуетесь пагинацией JPA, то дублей уже не будет. It is magic 💫 + +Магии в программировании, как вы понимаете, нет. Они создаются при использовании `FetchType.EAGER` у `@OneToMany` в совокупности с `@ElementCollection(fetch = FetchType.EAGER)`. Hibernate генерирует запрос с двумя-тремя полными соединениями, отсюда и берутся дубли. При этом в пагинации Hibernate не генерирует джойны, а использует кучу селектов, отсюда и отсутствие дублей при пагинации. + +Эта проблема решается несколькими способами: + +- Переделайте `List` в `Set` у `@OneToMany`. +- Уберите `FetchType.EAGER` у `@OneToMany`. +- Добавьте `@Fetch(FetchMode.SUBSELECT)` у `@OneToMany`. это аннотация Hibernate, которая вместо JOIN использует подзапрос. О [подзапросах я писал в отдельной статье](https://struchkov.dev/blog/ru/select-subquery). +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 Hibernate|00 Hibernate]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-09-06]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/java/hibernate/Логирование SQL в Hibernate.md b/dev/java/hibernate/Логирование SQL в Hibernate.md new file mode 100644 index 00000000..680e05a2 --- /dev/null +++ b/dev/java/hibernate/Логирование SQL в Hibernate.md @@ -0,0 +1,57 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2023-11-09 +zero-link: + - "[[../../../meta/zero/00 Hibernate|00 Hibernate]]" + - "[[../../../meta/zero/00 Снипеты для Java|00 Снипеты для Java]]" +parents: +linked: +--- +Чтобы каждый раз не искать эти проперти оставлю их тут. +## SpringBoot +```yml +spring: + jpa: + show-sql: true + properties: + hibernate: + format_sql: true +``` + +![](../../../meta/files/images/Pasted%20image%2020231109104008.png) + +Если требуется добавить вывод аргументов, то добавляем еще + +```yaml +logging: + level: + org: + hibernate: + type: trace +``` + +![](../../../meta/files/images/Pasted%20image%2020231109104112.png) +## Quarkus +```yml +quarkus: + hibernate-orm: + log: + sql: true + format-sql: true + bind-parameters: true +``` + +![](../../../meta/files/images/Pasted%20image%2020231109104248.png) +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 Hibernate|00 Hibernate]], [[../../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2023-11-09]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/java/quarkus/StartupEvent в Quarkus.md b/dev/java/quarkus/StartupEvent в Quarkus.md new file mode 100644 index 00000000..e8e00764 --- /dev/null +++ b/dev/java/quarkus/StartupEvent в Quarkus.md @@ -0,0 +1,75 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-09-10 +zero-link: + - "[[../../../meta/zero/00 Quarkus|00 Quarkus]]" + - "[[../../../meta/zero/00 Снипеты для Java|00 Снипеты для Java]]" +parents: +linked: +--- +`StartupEvent` позволяет выполнить операции после запуска сервиса + +```java +@ApplicationScoped +public class StartUp { + + void onStart(@Observes StartupEvent event) { + + } + +} +``` + +Но может возникнуть проблема с контекстом кваркуса. + +```log +ERROR [io.qua.mut.run.MutinyInfrastructure] - Mutiny had to drop the following exception: java.lang.IllegalStateException: No current Vertx context found +``` + +Для ее решения можно сделать следующее: + +```java +@ApplicationScoped +public class StartUp { + + void onStart(@Observes StartupEvent event) { + Unis.voidItem() + .emitOn(MutinyHelper.executor(vertx)) + .subscribe().with( + ok -> {}, + th -> {} + ) + } + +} + +@UtilityClass +public class VertxHelper { + + public static Executor getExecutor(Vertx vertx) { + final Context currentContext = Vertx.currentContext(); + if (checkNotNull(currentContext)) { + return MutinyHelper.executor(currentContext); + } else { + return MutinyHelper.executor(vertx); + } + } + +} +``` + +В самом начале пайпа мы добавляем `.emitOn(MutinyHelper.executor(vertx))`, который создает нам контекст. + +*** +## Мета информация +**Область**:: +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-09-10]] +**Автор**:: +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/java/quarkus/Сборка Quarkus приложения в исполняемый файл.md b/dev/java/quarkus/Сборка Quarkus приложения в исполняемый файл.md new file mode 100644 index 00000000..1d0b73c1 --- /dev/null +++ b/dev/java/quarkus/Сборка Quarkus приложения в исполняемый файл.md @@ -0,0 +1,71 @@ +--- +aliases: +tags: + - maturity/🌱 +date: + - - 2024-04-07 +zero-link: + - "[[../../../meta/zero/00 Quarkus|00 Quarkus]]" +parents: + - "[[../Нативные сборки в Java|Нативные сборки в Java]]" +linked: +--- +Провозился два дня, но в итоге смог собрать один из микро-сервисов в нативном режиме. Ничего сложного, но было много нюансов в настройке CICD. + +Самое полезное, это вот [эта документация Quarkus](https://quarkus.io/guides/building-native-image). А конкретно флаги: +- `-Dquarkus.native.container-build=true` +- `-Dquarkus.native.remote-container-build=true` + +Эти флаги необходимо добавить в команду сборки + +```shell +gradle build -Dquarkus.package.type=native -Dquarkus.native.remote-container-build=true +``` + +```shell +./mvnw package -Dnative -Dquarkus.native.remote-container-build=true +``` + +Во время сборки будет скачан докер образ с GraalVM и сборка будет проходить уже в этом образе. То есть можно использовать любой раннер CI без предварительной настройки базового образа. + +А вот так выглядит [Dockerfile](../../devops/docker/Dockerfile.md) сервиса: + +```Dockerfile +FROM registry.access.redhat.com/ubi8/ubi-minimal:8.6 +WORKDIR /work/ +RUN chown 1001 /work \ + && chmod "g+rwX" /work \ + && chown 1001:root /work +COPY ./build/*-runner /work/application + +EXPOSE 8080 +USER 1001 + +CMD ["./application", "-Dquarkus.http.host=0.0.0.0"] +``` + +Сервис стал собираться в 2,5 раза больше, около 5 минут, вместо 2. Но теперь он стартует моментально, наверное за доли секунды. При этом на под выделяется всего 256 mb ОЗУ на старте и 512 mb в момент работы. +## Более сложный путь +Также слепил образ для GitLab-раннера, который совмещает GraalVM и Docker, осталось добавить в него Gradle, но пока использую `./gradlew`. Оставлю это тут на всякий случай. + +```Dockerfile +FROM ghcr.io/graalvm/graalvm-ce:ol9-java17-22.3.0 +WORKDIR /opt/graalvm +RUN gu install native-image +RUN microdnf -y install dnf-plugins-core +RUN microdnf -y install yum +RUN yum install -y yum-utils +RUN yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo +RUN yum install -y docker-ce docker-ce-cli containerd.io +``` +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 Quarkus|00 Quarkus]] +**Родитель**:: [[../Нативные сборки в Java|Нативные сборки в Java]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-04-07]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/java/synchronized.md b/dev/java/synchronized.md new file mode 100644 index 00000000..1312fd66 --- /dev/null +++ b/dev/java/synchronized.md @@ -0,0 +1,142 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-10-09 +zero-link: +parents: +linked: +--- +synchronized — это один из ключевых механизмов в Java для управления [[Многопоточность в Java|многопоточностью]] и обеспечения безопасности при доступе к разделяемым ресурсам. Этот модификатор используется для того, чтобы ограничить доступ к критическим секциям кода, тем самым предотвращая состояния гонки ([[../other/Race condition|race conditions]]). + +**Как работает synchronized** +Synchronized может применяться к методам или блокам кода. Когда поток входит в метод или блок, помеченный `synchronized`, он получает [[Монитор в Java|монитор]] (lock) на объект, связанный с этим кодом. Другие потоки не могут получить доступ к этому коду до тех пор, пока монитор не будет освобожден. Это гарантирует, что только один поток может одновременно выполнять данный код. + +В этом примере, `synchronized` гарантирует, что методы `increment` и `getCount` не будут выполняться одновременно несколькими потоками, предотвращая некорректные обновления переменной `count`. + +```java +public class Counter { + private int count = 0; + + public synchronized void increment() { + count++; + } + + public synchronized int getCount() { + return count; + } +} +``` + +Иногда удобнее синхронизировать не весь метод, а только его часть. В этом случае можно использовать блок `synchronized`: + +```java +public void increment() { + synchronized (this) { + count++; + } +} +``` + +**Особенности** +- **Мониторы привязаны к объектам**, а не к методам. Если вы синхронизируете метод экземпляра (instance method), то монитором является текущий объект (this). Если метод статический, то монитором выступает сам класс (ClassName.class). +- **Блокировки могут привести к взаимной блокировке** ([[../../../../_inbox/Deadlock|deadlock]]), если два потока пытаются захватить друг у друга мониторы в неправильном порядке. + +**Ограничения** +- **Синхронизация снижает производительность**, так как потоки вынуждены ожидать освобождения блокировки. +- **Недостаточная гибкость:** при сложных задачах многопоточности использование `synchronized` может стать неэффективным, и тогда лучше рассмотреть более современные и гибкие альтернативы, такие как классы из пакета `java.util.concurrent` (например, `ReentrantLock`). + +## Частые проблемы и ошибки +### Чрезмерная синхронизация (Over-synchronization) +**Проблема:** Синхронизация всего метода или слишком большого объема кода может снизить производительность программы, так как потоки вынуждены ждать доступа к синхронизированным участкам, даже если это не требуется. + +**Решение:** Следует синхронизировать только ту часть кода, которая действительно требует защиты. + +### Синхронизация на неправильном объекте +**Проблема:** Если синхронизация происходит на локальном или временном объекте, это не защитит данные, так как каждый поток будет работать с собственной копией объекта. + +```java +public class Counter { + private int count = 0; + + public void increment() { + // Неправильная синхронизация на локальном объекте + Object lock = new Object(); + synchronized (lock) { + count++; + } + } +} +``` + +Здесь каждый поток создает собственный объект `lock`, и, следовательно, синхронизация не работает. + +**Решение:** Синхронизацию нужно выполнять на общем объекте (например, `this` или другом общем объекте). + +### Синхронизация на статических и нестатических методах +**Проблема:** Если не понимать, как работают мониторы для статических и нестатических методов, можно случайно создать ситуацию, когда доступ к объектам будет синхронизирован некорректно. + +```java +public class StaticSyncExample { + private static int staticCount = 0; + private int instanceCount = 0; + + public static synchronized void incrementStatic() { + staticCount++; + } + + public synchronized void incrementInstance() { + instanceCount++; + } +} +``` + +Здесь вызов `incrementStatic` синхронизируется на классе `StaticSyncExample.class`, а `incrementInstance` — на конкретном объекте класса. Это может привести к недоразумениям в случаях, когда ожидается один и тот же монитор для всего кода. + +Еще один пример +```java +public class Container { + private static final List list = new ArrayList<>(); + + synchronized void addEntry(String s) { + list.add(s) + } +} +``` + +Здесь у нас будет проблема, если будет 2+ объекта класса `Container`, так как каждый из них будет синхронизироваться на своем объекте, а переменная `list` у нас статическая и ее экземпляр единственный на всю программу + +**Решение:** Нужно учитывать, что статические и нестатические методы используют разные мониторы. Чтобы синхронизировать весь класс (включая как статические, так и нестатические данные), можно использовать общий объект для синхронизации. +### Пропуск синхронизации для чтения и записи +**Проблема:** Разрешение чтения переменных без синхронизации, тогда как их запись синхронизирована, может привести к непредсказуемым результатам, поскольку значения могут быть прочитаны в неконсистентном состоянии. + +```java +public class Counter { + private int count = 0; + + public synchronized void increment() { + count++; + } + + // Неправильное чтение без синхронизации + public int getCount() { + return count; + } +} +``` + +В этом случае разные потоки могут получить некорректное значение переменной count. + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: [[Многопоточность в Java]] +**Источник**:: +**Создана**:: [[2024-10-09]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/java/Автоматизация релиза с помощью Gradle.md b/dev/java/Автоматизация релиза с помощью Gradle.md new file mode 100644 index 00000000..1251102c --- /dev/null +++ b/dev/java/Автоматизация релиза с помощью Gradle.md @@ -0,0 +1,84 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2023-10-21 +zero-link: + - "[[../../meta/zero/00 Gradle|00 Gradle]]" +parents: +linked: +--- +Чтобы автоматизировать релизы можно использовать специальный Gradle Plugin: [GitHub - researchgate/gradle-release](https://github.com/researchgate/gradle-release) + +Плагин выполняет следующие действия: +- Проверяет наличие не зафиксированных изменений +- Проверяет наличие не опубликованных изменений в удаленный репозиторий +- Проверяет наличие SNAPSHOT зависимостей в файле `gradle.properties` +- Меняет версию сервиса со SNAPSHOT на релизную. В диалоговом режиме, но можно использовать флаги при работе в CI. +- Делает коммит. +- Меняет версию сервиса с релизной на новый SNAPSHOT. В диалоговом режиме. +- Автоматически публикует изменения, если удаленный репозиторий называется `origin`. Можно отключить или сконфигурировать названия веток. + +Настройка плагина в корневом файле `build.gradle`: + +```gradle +buildscript { + repositories { + gradlePluginPortal() + mavenCentral() + } + dependencies { + classpath 'org.kordamp.gradle:jandex-gradle-plugin:1.0.0' + } +} + +apply plugin: "net.researchgate.release" +release { + createReleaseTag.enabled = false + pushReleaseVersionBranch = 'rc' + preTagCommitMessage = 'Candidate release version commit: ' + newVersionCommitMessage = 'New develop version commit: ' + git { + requireBranch.set('developer') + } +} +``` + +- `createReleaseTag.enabled = false` - отключает проставление релизного тега +- `pushReleaseVersionBranch = 'rc'` - запушит релиз в ветку rc +- `preTagCommitMessage` и `newVersionCommitMessage` задает текст в релизных коммитах +- `requireBranch` позволят настроить из какой ветки можно будет выпускать релизы. + +Можно изменить конфигурацию формата версии для разработки. По умолчанию меняется патч версия. Вот эта конфигурация изменит минорную версию. + +``` +versionPatterns = [ + /(\d+)\.\d+([^\d]*$)/: { Matcher m, Project p -> m.replaceAll("${(m[0][1] as int) + 1}.0${m[0][3] ? m[0][3] : ""}") } +] +``` + +Также можно настроить передачу текста для сообщения в теге: +``` +release.tagCommitMessage = project.findProperty('release.tagCommitMessage') +``` + +Запустить выполнение плагина: +```bash +gradle relase +``` + +Пример того, как будут выглядеть коммиты в Git + +![](Pasted%20image%2020231021121612.png) +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Gradle|00 Gradle]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2023-10-21]] +### Дополнительные материалы +- [GitHub - researchgate/gradle-release](https://github.com/researchgate/gradle-release) +- [Автоматизация рутины при выпуске релизов с Maven](https://struchkov.dev/blog/ru/release-releases-with-maven/) +### Дочерние заметки + diff --git a/dev/java/Бинарный поиск на Java.md b/dev/java/Бинарный поиск на Java.md new file mode 100644 index 00000000..0e573ca4 --- /dev/null +++ b/dev/java/Бинарный поиск на Java.md @@ -0,0 +1,95 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-04-07 +zero-link: + - "[[../../meta/zero/00 Алгоритм|00 Алгоритм]]" + - "[[../../meta/zero/00 Снипеты для Java|00 Снипеты для Java]]" +parents: + - "[[../algorithm/Бинарный поиск|Бинарный поиск]]" +linked: +link: https://struchkov.dev/blog/ru/java-binary-search/ +--- +[[../algorithm/Бинарный поиск|Подробнее о самом алгоритме]] можно прочитать в отдельной заметке. Здесь только реализация на Java. +## Без рекурсии +```java +public class Binary { + + public static void main(String[] args) { + int[] values = {1, 1, 2, 3, 4, 10}; + int valueToFind = 3; + + System.out.printf("Index = %d%n", binarySearch(values, valueToFind, 0, values.length - 1)); + } + + private static int binarySearch(int[] sortedArray, int valueToFind, int low, int high) { + int index = -1; + + while (low <= high) { + int mid = low + (high - low) / 2; + if (sortedArray[mid] < valueToFind) { + low = mid + 1; + } else if (sortedArray[mid] > valueToFind) { + high = mid - 1; + } else if (sortedArray[mid] == valueToFind) { + index = mid; + break; + } + } + return index; + } + +} +``` + +## С использованием рекурсии +```java +public class Binary { + + public static void main(String[] args) { + int[] values = {1, 1, 2, 3, 4, 10}; + int valueToFind = 3; + + System.out.printf("Index = %d%n", binarySearch(values, valueToFind, 0, values.length - 1)); + } + + private static int binarySearch(int[] values, int valueToFind, int l, int r) { + if (l == r) { + return (values[l] == valueToFind) ? l : -1; + } + + int m = l + (r - l) / 2; + + if (valueToFind > values[m]) { + return binarySearch(values, valueToFind, m + 1, r); + } else if (values[m] > valueToFind) { + return binarySearch(values, valueToFind, l, m - 1); + } + return m; + } + +} +``` + +Если элемент не найден, то вернется `-1`. + +> [!WARNING] m = l + (r - l) / 2; +> Во многих примерах в интернете можно встретить запись `int m = (l + r) / 2;`, вместо `int mid = l + (r - l) / 2;`. +> +> Но использование второго варианта является лучшей практикой, так как это помогает избежать переполнения, когда размер массива велик. +> +> Например, если `l = 2147483647` и `r = 2147483647`, сумма `l` и `r` будет равна 4294967294, что превышает максимальное значение, которое может хранить `int`, вызывая переполнение. +> +> С другой стороны, если вы используете `mid = l + (r - l) / 2;` это будет работать, как и ожидалось, потому что вычитание будет сделано первым, а результат будет равен нулю, поэтому деление будет равно нулю, а сложение вернет значение `l`. + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Алгоритм|00 Алгоритм]], [[../../meta/zero/00 Снипеты для Java|00 Снипеты для Java]] +**Родитель**:: [[../algorithm/Бинарный поиск|Бинарный поиск]] +**Автор**:: +**Создана**:: [[2024-04-07]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/java/Возвращайте пустую коллекцию вместо null.md b/dev/java/Возвращайте пустую коллекцию вместо null.md new file mode 100644 index 00000000..cc63d11e --- /dev/null +++ b/dev/java/Возвращайте пустую коллекцию вместо null.md @@ -0,0 +1,31 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-09-07 +zero-link: + - "[[../../meta/zero/00 Java разработка|00 Java разработка]]" +parents: +linked: +--- +Если ваша программа может вернуть коллекцию, которая не содержит никаких значений, убедитесь, что возвращается пустая коллекция, а не `null`. Это сэкономит вам время на различные проверки и избавит от многих потенциальных ошибок. + +```java +public List getAllEventByUserId(int userId) { + if (userId == 0) { + return Collections.emptyList(); + } + return eventRepository.findAllByUserId(userId); +} +``` +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-09-07]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/java/Голосарий Java.md b/dev/java/Голосарий Java.md new file mode 100644 index 00000000..c8371b30 --- /dev/null +++ b/dev/java/Голосарий Java.md @@ -0,0 +1,76 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-10-19 +--- +#### Code block (блок кода) +Это фрагмент программы, заключенный между фигурными скобками `{}`. Он может быть частью метода, цикла, условия или других конструкций. В блоке кода содержатся операторы (statements), которые выполняются в порядке их написания. + +![[../../meta/files/images/Pasted image 20241019092032.png]] +#### Statement (оператор, предложение, инструкция) +Выполняет какое-то действие, но не возвращает значения. Оператор заканчивается точкой с запятой `;`, однако сам символ `;` не является частью выражения (expression). + +![[../../meta/files/images/Pasted image 20241019092300.png]] +#### Expression (выражение) +Выражение — это часть кода, которая вычисляет **значение**. Оно может включать переменные, константы, операторы и вызовы методов. + +Выражение может быть использовано как часть оператора или в других контекстах, например, внутри условий. +#### Значение +Это результат вычисления выражения (исключая выражения с типом `void`). Значения могут быть сохранены в переменные, переданы в методы в качестве **аргументов**, а также приняты методами в виде **параметров**. При передаче значения в метод оно копируется - [[Передача значений в метод в Java]]. + +Важно отметить, что само значение **нельзя изменить**, однако переменной, которая хранит это значение, можно присвоить новое значение. +#### Имя метода +Имя метода идентифицирует конкретную функцию или действие, которое выполняет метод. +#### Аргументы метода +В Java метод всегда имеет список аргументов, даже если они отсутствуют. В таком случае используются пустые скобки `()`. + +![[../../meta/files/images/Pasted image 20241019093016.png]] +#### Параметры метода +Параметры метода — это переменные, указанные в скобках при его объявлении. Эти параметры получают значения при вызове метода. + +Есть есть для того, кто вызывает метод передаваемые значения называются аргументами, а уже в самом методе аргументы называются параметрами. +#### Сигнатура метода +Сигнатура метода включает его имя и список аргументов, но не возвращаемый тип. Это ключевой элемент для различения методов с одинаковыми именами, но разными параметрами. +#### Квалификатор +Это часть выражения слева от точки, указывающая на объект или класс, через который вызывается метод или поле. Квалификатор может быть необязательным и иногда отсутствовать. + +![[../../meta/files/images/Pasted image 20241019092501.png]] + +Например, в выражении `System.out.println()` квалификатором для метода `println` является `out`, а для `out` — `System`. +#### Переменная +это именованная область памяти, которая используется для хранения данных. Переменная может содержать различные типы данных, такие как числа, строки или объекты. Она позволяет программам запоминать значения и использовать их в дальнейшем. +#### Declaration (объявление) +Это процесс создания переменной, метода или другой сущности в программе с указанием её типа и имени. При объявлении переменной указывается её тип (например, `int`, `String`) и имя, но ей может не присваиваться значение сразу. + +Объявление сообщает компилятору, что данная переменная или метод существует и будет использоваться в дальнейшем. Объявление может сопровождаться **инициализацией** — присвоением переменной значения при её создании. + +Пример объявления переменной: +```java +int myNumber; // Объявление переменной типа int с именем myNumber +``` + +Пример объявления метода: +```java +void myMethod() { + // тело метода +} +``` +#### Область видимости +это часть программы, в которой переменная доступна для использования. Переменные видимы и могут быть использованы только в пределах той области, где они были объявлены. +#### Локальная переменная +это переменная, объявленная внутри метода или блока кода. Она существует только в пределах этого метода или блока и недоступна за его пределами. После завершения работы метода или блока локальная переменная удаляется из памяти. + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-10-19]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/java/Границы применимости Tuple и Pair в разработке.md b/dev/java/Границы применимости Tuple и Pair в разработке.md new file mode 100644 index 00000000..7d8e9f71 --- /dev/null +++ b/dev/java/Границы применимости Tuple и Pair в разработке.md @@ -0,0 +1,143 @@ +--- +aliases: +tags: + - maturity/🌱 + - content/opinion +date: 2024-09-17 +zero-link: + - "[[../../meta/zero/00 Java разработка|00 Java разработка]]" +parents: +linked: +permalink: dev/java/tuple +--- +## Тезисы +- Публичные методы интерфейсов должны быть самодокументируемыми и понятными без дополнительных комментариев. +- `Tuple` в публичных методах снижает читаемость и может запутать других разработчиков. +- `Tuple` в аргументах метода также может снизить ясность и увеличить вероятность ошибок. +- В приватных методах `Tuple` допустим, если используется внутри класса и не нарушает ясность. +- В реактивных пайпах `Tuple` могут быть полезны для временного объединения значений. +- Извлечение данных из `Tuple` в локальные переменные улучшает читаемость реактивных пайпов. +- Если вы на проекте один и никто другой код читать не будет, можете использовать `Tuple` как угодно 😁 +*** +Некоторые языки программирования, такие как Go, позволяют возвращать из функции несколько значений сразу. В Java, однако, метод может вернуть только одно значение, и зачастую хочется вернуть сразу два — например, пару связанных данных. Конечно, правильный подход — создать объект с двумя полями, но часто на практике оказывается, что проще и быстрее использовать готовые решения вроде классов `Tuple` и `Pair`, которые служат обертками. + +Но прежде чем полагаться на эти классы, важно понять их границы применимости. Для упрощения дальнейшего объяснения я буду использовать `Tuple` как пример, но все сказанное ниже также относится и к `Pair`. +## Возвращаем Tuple в публичном методе +Публичные методы интерфейсов — это своего рода контракты между вами, разработчиком функциональности, и клиентом, то есть другим разработчиком, который будет использовать ваш код для решения своих задач. + +==Так как большую часть времени разработчик не пишет, а читает чужой код, важно, чтобы этот контракт был понятен без дополнительных пояснений и комментариев.== + +Представим, что вам нужно вернуть имя пользователя и его возраст. На первый взгляд, использование `Tuple` может показаться удобным решением: не нужно создавать новый класс, а возвращать сразу несколько значений — легко и быстро. + +И ваш контракт (интерфейс) выглядит следующим образом: + +```java +public interface UserService { + Tuple getUserData(String userId); +} +``` + +Посмотрев на контакт `getUserData(userId)` сможет ли другой разработчик сказать какие результаты он получит? Вряд ли. + +Недостатки такого использования: +- **Снижение читабельности кода:** Клиенту интерфейса будет неочевидно, что именно содержится в возвращаемом `Tuple`. В отличие от специально созданного класса с понятными именами полей, `Tuple` не говорит напрямую, что первое значение — это имя, а второе — возраст. Это усложняет понимание и использование метода. +- **Отсутствие самодокументируемости:** Хорошо продуманные классы и методы сами по себе выступают как документация, тогда как `Tuple` требует дополнительных пояснений или комментариев, чтобы разработчики понимали, что происходит. ==Вы заставляете других разработчиков тратить больше времени на понимание логики метода.== +- **Повышенная вероятность ошибок:** Использование неименованных полей увеличивает риск случайных ошибок, например, при изменении порядка полей. Разработчики могут легко перепутать значения и передать их неправильно. Особенно если тип у значений совпадает. +- **Сложности с расширяемостью:** Если в будущем потребуется расширить возвращаемые данные, интерфейс с `Tuple` станет менее гибким. +## Tuple в аргументах метода +Когда методы принимают несколько параметров, иногда может возникнуть желание объединить их в `Tuple`, чтобы упростить сигнатуру метода или передать параметры в одном объекте. На первый взгляд, это кажется удобным, особенно если типы данных уже известны, и не хочется создавать отдельный класс. + +Особенно сильно такое желание возникает, когда вы вызываете публичный метод, который возвращает `Tuple`, и вам нужны все его результаты. В таких ситуациях кажется логичным продолжать работать с `Tuple`, чтобы избежать излишней детализации и создавать меньше кода. [[../../psychology/Нисходящая спираль|Нисходящая спираль]] закручивается 😊 + +Представим, что ваш метод выглядит следующим образом. И в этот метод приходит другой разработчик, которому нужно добавить новую фичу или исправить баг и он видит вот это: + +```java +public void processUserData(Tuple userData) { + // Логика обработки данных +} +``` + +Какие проблемы могут возникнуть при таком подходе. На самом деле все те же: +- **Пониженная читаемость и ясность кода:** Как и в случае с возвращаемыми значениями, использование `Tuple` не даёт ясности о том, что именно передаётся в метод. Из сигнатуры метода непонятно, что строка представляет имя пользователя, а целое число — возраст. +- **Нарушение принципа самодокументируемого кода** +- **Увеличение вероятности ошибок** +- **Сложности с изменениями и расширением кода** +## Возвращаем Tuple в приватном методе +В отличие от публичных методов, приватные методы находятся внутри границ одного класса и, не участвуют в контрактах. Это дает больше свободы в выборе структур данных для внутренних операций. + +Возвращение `Tuple` из приватного метода может оказаться разумным решением, когда нужно быстро вернуть несколько значений без создания дополнительных классов. Например: + +```java +private Tuple fetchUserData() { + // Логика получения данных + return new Tuple<>("John Doe", 30); +} +``` + +Когда использовать `Tuple` уместно: +- Если данные возвращаются только внутри приватного метода и используются в узком контексте, где значение каждого элемента `Tuple` очевидно из контекста вызова. +- Если метод временный и планируется рефакторинг, или когда требуется быстрое прототипирование. + +Преимущества использования `Tuple` в приватных методах: +- **Удобство и скорость реализации:** Использование `Tuple` может значительно сократить время на реализацию, особенно когда речь идет о простых данных и методах, которые используются в узких контекстах. +- **Снижение избыточности кода:** Если данные нужны только внутри класса и их использование ограничено несколькими методами, создание отдельного класса может казаться избыточным. `Tuple` позволяет избежать ненужной сложности и дополнительных файлов. + +Тем не менее, стоит помнить о проблемах Tuple. Если логика метода со временем усложниться, [[../Читаемый код|читаемость кода]] может понизится. + +**Когда стоит задуматься о создании отдельного класса:** +- Если структура данных становится сложной или используется в нескольких местах внутри класса. +- Если потребуется передавать данные в другие классы в будущем. +- Если работа с данными требует дополнительной логики, такой как валидация или преобразование. +## Tuple в реактивном программировании +В [[../architecture/Реактивное программирование|реактивном программировании]], особенно с использованием [[../../meta/zero/00 Quarkus|Quarkus]] и Mutiny, часто возникает необходимость передачи нескольких значений между стадиями реактивного потока данных. `Tuple` может быть удобным решением для объединения значений, особенно когда результат остаётся внутри потока и не становится частью публичного API. + +Например, в реактивных пайпах могут использоваться такие структуры, как `Tuple2`, `Tuple3` и далее: + +```java +Uni userUni = getUser() + ... + .onItem().invoke(tuple -> { + String name = tuple.getItem1(); + int age = tuple.getItem2(); + // Дальнейшая обработка + }); +``` + +Здесь `Tuple2` используется для объединения имени и возраста пользователя, ==и значения извлекаются в локальные переменные с понятными именами.== Если нужно объединить больше значений, можно использовать `Tuple3`, `Tuple4` и так далее: + +```java +Uni orderUni = getOrder() + ... + .onItem().invoke(tuple -> { + String orderId = tuple.getItem1(); + double total = tuple.getItem2(); + LocalDate date = tuple.getItem3(); + // Дальнейшая обработка + }); +``` + +Когда использование различных Tuple оправдано: +- **Переходные стадии в пайпах:** Внутри реактивных потоков, `Tuple2`, `Tuple3` и другие позволяют временно объединять нужное количество значений для обработки, сохраняя компактность и удобство. +- **Локальные переменные для улучшения читаемости:** Извлечение значений `Tuple` в локальные переменные с осмысленными именами значительно улучшает [[../Читаемый код|читаемость кода]] и упрощает понимание логики. + +Ограничения: +- **Сложность при увеличении количества элементов:** Чем больше значений объединяется в `Tuple` (например, `Tuple4`, `Tuple5` и далее), тем сложнее становится поддерживать и понимать код. В таких случаях лучше рассмотреть создание именованных классов. +- **Не использовать в публичных методах:** Если `Tuple` выходит за границы класса, в публичные методы или интерфейсы, использование именованных структур данных предпочтительнее для улучшения читаемости и поддержки. +## Заключение +Использование `Tuple` в различных сценариях — будь то публичные методы, приватные методы или реактивные пайпы — всегда требует баланса между удобством и читаемостью кода. `Tuple` может быть полезным инструментом в определённых ситуациях, но стоит помнить, что ясность и поддерживаемость кода зачастую важнее мгновенного выигрыша в скорости разработки. Создание именованных классов или record помогает сделать код самодокументируемым, снижает вероятность ошибок и упрощает дальнейшую поддержку. + +Однако, если вы на проекте один и точно уверены, что других разработчиков там никогда не появится, то можете использовать Tuple как хотите 😁 + +Но в большинстве случаев, лучше следовать правилам и заботиться о тех, кто будет работать с вашим кодом в будущем. Ведь читаемость и ясность всегда остаются ключевыми аспектами качественного программирования. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-09-17]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + diff --git a/dev/java/Динамическое связывание в Java.md b/dev/java/Динамическое связывание в Java.md new file mode 100644 index 00000000..4c83d435 --- /dev/null +++ b/dev/java/Динамическое связывание в Java.md @@ -0,0 +1,224 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-10-05 +zero-link: +parents: +linked: +--- +Важной особенностью [[../../../../garden/ru/dev/other/Динамическое связывание|динамического связывания]] в Java является использование **виртуальных методов** — методов, которые могут быть переопределены в наследуемых классах, и выбор нужного метода происходит в зависимости от типа объекта, а не ссылки на него. + +Динамическое связывание в Java обеспечивается [[Java Virtual Machine|Java Virtual Machine]] через таблицы виртуальных методов (vtable). Когда создается объект, JVM строит таблицу, содержащую указатели на методы, которые могут быть вызваны для данного объекта. Если метод переопределён в подклассе, JVM заменяет соответствующую запись в таблице. Это позволяет JVM выбрать нужный метод во время выполнения, основываясь на фактическом типе объекта. + +Ключевые шаги, которые выполняет JVM: +1. Когда вызывается метод через ссылку, JVM проверяет vtable для конкретного типа объекта. +2. Если метод был переопределён, ссылка указывает на новый метод в vtable. +3. Это позволяет избежать необходимости решать, какой метод вызывать, на этапе компиляции. + +**Преимущества:** +- **Гибкость.** Позволяет легко реализовывать полиморфизм, давая возможность объектам разных типов обрабатывать вызовы по-разному. +- **Расширяемость.** Классы можно легко расширять или заменять, не изменяя уже существующий код. + +**Недостатки:** +- **Производительность.** Динамическое связывание требует дополнительных вычислительных ресурсов для поиска метода во время выполнения. +- **Сложность отладки.** Ошибки, связанные с динамическим связыванием, могут проявиться только во время выполнения, что усложняет их обнаружение. + +## Примеры динамического связывания в Java +**Переопределение методов (Method Overriding)** +Динамическое связывание чаще всего проявляется при переопределении методов в классах-наследниках. Когда метод базового класса переопределён в подклассе, JVM выбирает метод для вызова во время выполнения, основываясь на фактическом типе объекта. + +```java +class Animal { + void sound() { + System.out.println("Animal makes a sound"); + } +} + +class Dog extends Animal { + @Override + void sound() { + System.out.println("Dog barks"); + } +} + +public class Main { + public static void main(String[] args) { + Animal myAnimal = new Dog(); // Ссылка на Animal, объект Dog + myAnimal.sound(); // Вызывается Dog.sound() благодаря динамическому связыванию + } +} +``` + +**Работа с интерфейсами** +Когда класс реализует интерфейс, метод интерфейса может быть реализован по-разному в каждом классе. JVM динамически выбирает метод во время выполнения в зависимости от типа объекта. + +```java +interface Shape { + void draw(); +} + +class Circle implements Shape { + public void draw() { + System.out.println("Drawing a Circle"); + } +} + +class Square implements Shape { + public void draw() { + System.out.println("Drawing a Square"); + } +} + +public class Main { + public static void main(String[] args) { + Shape myShape = new Circle(); // Ссылка на Shape, объект Circle + myShape.draw(); // Вызывается Circle.draw() благодаря динамическому связыванию + + myShape = new Square(); // Ссылка теперь указывает на объект Square + myShape.draw(); // Вызывается Square.draw() + } +} +``` + +**Абстрактные классы** +Когда у нас есть абстрактные классы с абстрактными методами, конкретные реализации этих методов в подклассах также связаны динамически. Фактический метод выбирается во время выполнения программы. + +```java +abstract class Animal { + abstract void sound(); +} + +class Cat extends Animal { + @Override + void sound() { + System.out.println("Cat meows"); + } +} + +class Lion extends Animal { + @Override + void sound() { + System.out.println("Lion roars"); + } +} + +public class Main { + public static void main(String[] args) { + Animal myAnimal = new Cat(); // Ссылка на Animal, объект Cat + myAnimal.sound(); // Вызывается Cat.sound() благодаря динамическому связыванию + + myAnimal = new Lion(); // Ссылка теперь указывает на объект Lion + myAnimal.sound(); // Вызывается Lion.sound() + } +} +``` + +**Виртуальные методы** + +В Java ==все нестатические методы являются виртуальными по умолчанию, то есть они могут быть переопределены в подклассах и будут динамически связаны на этапе выполнения.== Исключение составляют методы, помеченные как `final`, `private`, или `static`, которые не могут быть переопределены и, соответственно, не требуют динамического связывания. + +```java +class Parent { + void show() { + System.out.println("Parent's show()"); + } +} + +class Child extends Parent { + @Override + void show() { + System.out.println("Child's show()"); + } +} + +public class Main { + public static void main(String[] args) { + Parent obj = new Child(); // Ссылка на Parent, объект Child + obj.show(); // Вызывается Child.show() благодаря динамическому связыванию + } +} +``` + +**Вызов методов через типы-переменные родительского класса** +Когда у нас есть переменная или ссылка на объект базового типа (например, через тип переменной `Object` или `Animal`), которая ссылается на объект производного класса, вызов методов будет зависеть от фактического типа объекта. Это типичный сценарий динамического связывания. + +```java +class Example { + @Override + public String toString() { + return "Example class"; + } +} + +public class Main { + public static void main(String[] args) { + Object obj = new Example(); // Ссылка на Object, объект Example + System.out.println(obj); // Вызывается Example.toString() благодаря динамическому связыванию + } +} +``` + +**Работа с коллекциями и их элементами (включая generics)** +При работе с коллекциями, особенно с элементами типа Object, динамическое связывание происходит при вызове методов объектов, которые содержатся в этих коллекциях. + +```java +import java.util.ArrayList; + +class Animal { + void sound() { + System.out.println("Animal makes a sound"); + } +} + +class Dog extends Animal { + @Override + void sound() { + System.out.println("Dog barks"); + } +} + +public class Main { + public static void main(String[] args) { + ArrayList animals = new ArrayList<>(); + animals.add(new Dog()); // Добавляем объект Dog в коллекцию типа Animal + + for (Animal animal : animals) { + animal.sound(); // Вызывается Dog.sound() благодаря динамическому связыванию + } + } +} +``` + +**Приведение типов** +Когда объект приводится к типу родительского класса или интерфейса, динамическое связывание всё равно продолжает работать. Тип ссылки может быть `Animal`, но если объект фактически является `Dog`, будет вызван метод `Dog`, а не `Animal`. + +```java +class Bird extends Animal { + @Override + void sound() { + System.out.println("Bird sings"); + } +} + +public class Main { + public static void main(String[] args) { + Animal myAnimal = new Bird(); // Ссылка на Animal, объект Bird + myAnimal.sound(); // Вызывается Bird.sound() благодаря динамическому связыванию + } +} +``` + +*** +## Мета информация +**Область**:: [[../../../../garden/ru/meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: [[../../../../garden/ru/dev/other/Динамическое связывание|Динамическое связывание]] +**Источник**:: +**Создана**:: [[2024-10-05]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/java/Использование wildcard imports в Java.md b/dev/java/Использование wildcard imports в Java.md new file mode 100644 index 00000000..2e16af2f --- /dev/null +++ b/dev/java/Использование wildcard imports в Java.md @@ -0,0 +1,147 @@ +--- +aliases: +tags: + - maturity/🌱 + - content/opinion +date: 2024-09-06 +zero-link: + - "[[../../meta/zero/00 Java разработка|00 Java разработка]]" +parents: +linked: +--- +Разработчики Java используют подстановочный знак (`*`) в операторах `import` для добавления всех классов из определенного пакета. Но в ходе ревью большинство из вас, возможно, просили убрать этот подстановочный знак импорта и добавить полное имя класса. Разберемся почему не стоит использовать знак подстановки? + +Но прежде, давайте вспомним, что полное имя класса, помимо названия, содержит также пакет, например: `java.util.List`. ==Такая запись позволяет нам иметь классы с одинаковыми именами, которые находятся в разных пакетах.== + +```java +package com.example; + +public class WithoutImport { + + public static void main(String[] args) { + + java.util.List myList = new java.util.ArrayList(); + + } +} +``` + +Однако, полная запись весьма непрактична, поэтому в Java существует оператор импорта – `import`. Операторы импорта объявляют компилятору источник имен классов, статических переменных и статических имен методов, используемых в коде. Один раз написали полное имя класса, а дальше используем только название класса. + +```java +package com.example; + +import java.util.ArrayList; +import java.util.List; + +public class WithImport { + + public static void main(String[] args) { + + List myList = new ArrayList(); + + } + +} +``` + +Если мы скомпилируем и запустим эти примеры, результат будет одинаковым. + +Импорт с подстановочными знаками указывает компилятору искать имена классов в данном пакете. Следовательно, при использовании импорта с wildcard производительность во время компиляции может немного снизиться. Но в большинстве случаев это не окажет заметного влияния. + +Во время выполнения проблемы с производительностью нет, потому что операторы импорта являются директивами компилятора, и мы не можем найти их в байт-коде. Чтобы пояснить это, мы напишем приведенный выше пример с импортом с подстановочными знаками. + +```java +package com.example; + +import java.util.*; + +public class WithWildCard { + public static void main(String[] args) { + + List myList = new ArrayList(); + + } +} +``` + +Если мы получим байт-код этого класса, то он будет выглядеть следующим образом + +```bytecode +Compiled from "WithWildCard.java" +public class com.example.WithWildCard { + public com.example.WithWildCard(); + Code: + 0: aload_0 + 1: invokespecial #1 // Method java/lang/Object."":()V + 4: return + + public static void main(java.lang.String[]); + Code: + 0: new #2 // class java/util/ArrayList + 3: dup + 4: invokespecial #3 // Method java/util/ArrayList."":()V + 7: astore_1 + 8: return +} +``` + +Если сравнить его с байт-кодом прошлого примера, то они оба имеют одинаковый байт-код. + +Во время выполнения Java использует байт-код, а не исходный код. ==В байт-коде нет операторов импорта.== Из этого ясно следует, что использование импорта с подстановочными знаками не влияет на производительность Java-приложения во время выполнения. + +## Недостатки +Так если использование подстановочного знака не приводит к проблемам производительности, то почему бы его не использовать? + +### Конфликты имен +Самая серьезная проблема это возможные конфликты именования. Представьте, что у нас есть два класса из разных библиотек `org.test.Parser` и `dev.lib.Parser`. В нашем коде мы используем импорт с wildcard: + +```java +import org.test.* +import dev.lib.* +``` + +Компилятор никак не отреагирует на наличие классов с одинаковыми именами в двух разных пакетах, импортируемых таким образом, если только не бу­дет предпринята попытка воспользоваться одним из этих классов. + +Также проблема может возникнуть в будущем, когда вы обновите версию какую-то из библиотек. Допустим у нас была библиотека с классом `org.test.Parser`, а потом разработчик второй библиотеки тоже добавил класс `dev.lib.Parser`, таким образом мы получили конфлик именования в будущем, хотя раньше все было нормально. +### Чистый код +Импорты с подстановочными знаками помогают нам избежать длинного списка импортов. Следовательно, это влияет на читабельность кода, так как читателю может потребоваться прокрутить много страниц в каждом файле исходного кода, прежде чем он доберется до кода, который показывает логику. Несомненно, более читабельный код - это также чистый код. + +Эта идея также поддерживается в книге "Чистый код" Роберта К. Мартина. Фактически, книга рекомендует использовать импорты с подстановочными знаками при использовании нескольких классов из одного источника. Другими словами, когда мы импортируем два или более классов, импортированных из пакета, лучше импортировать весь пакет. + +Однако, я не считаю это какой-то проблемой, так как IntelliJ IDEA автоматически скрывает все строки импортов. + +![](../../meta/files/images/Pasted%20image%2020240906164456.png) + +Также читаемость ухудшается, потому что разработчик не получает четкого представления о полном пути классов, используемых в коде. + +Однако, это тоже не является проблемой. Достаточно удерживая Ctrl (cmd) навести курсор на класс и вы увидите пакет, в котором этот класс размещается. + +![](../../meta/files/images/Pasted%20image%2020240906164524.png) + +Таким образом проблемы "чистого кода" более не актуальны. + +## Настройки в Idea +Intellij Idea автоматически сворачивает импорты, когда полные импорты из какого-то пакета достигают заданного количества. Эта опция настраивается в раделе Preferences > Editor > Code Style > Java во вкладке imports. + +![](../../meta/files/images/Pasted%20image%2020240906164551.png) + +Чтобы отключить автоматическое сворачивание импортов достаточно указать число 999. Вот и все, теперь Idea не будет автоматически сворачивать импорты. + +## Резюмирую +Использование подстановочных импортов никак не повлияет на производительность программы во время выполнения, но может немного повлиять на производительность во время компиляции. + +Также при обновлении библиотек вы можете столкнуться с проблемой конфликта имен. Шанс этой проблемы не велик, но и не нулевой. + +Что касается "чистого кода", то с использованием современных IDE эта проблема не является актуальной. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-09-06]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/java/Куча.md b/dev/java/Куча.md new file mode 100644 index 00000000..7a8e1cee --- /dev/null +++ b/dev/java/Куча.md @@ -0,0 +1,34 @@ +--- +aliases: + - куче + - кучей + - heap +tags: + - maturity/🌱 +date: 2024-10-19 +--- +Куча — это область памяти, используемая для динамического распределения во время выполнения программы. В отличие от стека, ==данные в куче могут существовать дольше, чем отдельные вызовы функций, а объёмы памяти, выделяемой в куче, обычно гораздо больше, чем в стеке.== + +Куча идеально подходит для хранения данных, которые должны существовать дольше времени выполнения функции, или для работы с большими объёмами данных. Однако работа с кучей требует тщательного управления: ==если объекты не удаляются, когда они больше не нужны, это может привести к утечке памяти==, что, в свою очередь, может вызвать исчерпание доступной памяти. + +Куча в Java — это область памяти, где создаются все объекты. Когда вы создаёте объект с помощью оператора `new`, он размещается в куче. Основное отличие стека и кучи в Java от их общего представления связано с автоматическим управлением памятью. В Java не нужно явно освобождать память в куче, так как этим занимается [[gc/Garbage Collector|сборщик мусора]]. + +Для наглядности представим стек и кучу. Серые объекты потеряли свою связь со стеком, и их нужно удалить, чтобы освободить память для новых объектов. + +![[../../meta/files/images/Pasted image 20241019192034.png]] + +> [!NOTE] +> Объекты могут содержать методы, а методы — локальные переменные. Эти локальные переменные хранятся в стеке потока, даже если сам объект, которому принадлежат методы, находится в куче. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: [[../../../../knowledge/dev/java/Устройство Java|Устройство Java]] +**Источник**:: +**Создана**:: [[2024-10-19]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/java/Лучшие и полезные плагины для IntelliJ IDEA 2024.md b/dev/java/Лучшие и полезные плагины для IntelliJ IDEA 2024.md new file mode 100644 index 00000000..8438f209 --- /dev/null +++ b/dev/java/Лучшие и полезные плагины для IntelliJ IDEA 2024.md @@ -0,0 +1,79 @@ +--- +aliases: +tags: + - maturity/🌳 +date: 2024-09-08 +zero-link: + - "[[../../meta/zero/00 Java разработка|00 Java разработка]]" +parents: +linked: +--- +Хочу поделиться небольшой подборкой полезных плагинов, которые помогают мне ускорить и улучшить процесс написания кода. + +> [!INFO] +> Все плагины актуальны для IntelliJ 2023.3.3 +## SonarLint +SonarLint работает так же, как статический анализатор кода [SonarQube](https://www.sonarsource.com/products/sonarqube/). Он изучает ваш код в проекте и предлагает улучшения. Анализ происходит в процессе написания, так что ошибки можно будет исправить до коммита. + +![](../../meta/files/images/Pasted%20image%2020240908105749.png) + +Это был мой любимый плагин, когда я только начинал работать. Со временем многие проблемы ты запоминаешь и обходишь стороной. Плагин снова становится полезным, когда вы занимаетесь со стажерами, экономит ваше время на поиск типичных ошибок. + +Если ваш проект анализируется в SonarQube или SonarCloud, SonarLint может подключиться к серверу, чтобы получить соответствующие профили качества и настройки для этого проекта. + +**Кому рекомендую:** Если вы Junior, то для вас это незаменимый инструмент, который позволит улучшить ваш код. + +**Ссылка для установки:** [SonarLint - IntelliJ IDEs Plugin | Marketplace](https://plugins.jetbrains.com/plugin/7973-sonarlint) +## Translation +Если у вас все печально с английским, то вам часто приходится перемещаться между Idea и переводчиком в браузере. Translation избавляет вас от этой проблемы. + +![](../../meta/files/images/Pasted%20image%2020240908105845.png) + +Возможности: +- Множественные движки перевода: + - Google переводчик + - Youdao переводчик + - Переводчик Baidu +- Перевод JavaDoc +- Озвучивание текста + +**Кому подойдет:** Этот плагин для тех, кто плохо знает английский язык. + +**Ссылка на установку:** [Translation - IntelliJ IDEs Plugin | Marketplace](https://plugins.jetbrains.com/plugin/8579-translation) +## .ignore +Простой плагин, который помогает генерировать файлы исключений, такие как `.gitignore` и `.dockerignore`. + +![](../../meta/files/images/plugin-ignore.gif) + +**Ссылка на установку:** [.ignore - IntelliJ IDEs Plugin | Marketplace](https://plugins.jetbrains.com/plugin/7495--ignore) +## Key Promoter X +Сам я им не пользуюсь, но многие используют. Плагин показывает вам какими сочетаниеми горячих клавиш вы могли бы выполнить действие, которое выполнили мышью. + +![](../../meta/files/images/screenshot_17105.png.gif) + +**Ссылка на установку:** [Key Promoter X - IntelliJ IDEs Plugin | Marketplace](https://plugins.jetbrains.com/plugin/9792-key-promoter-x) +## String Manipulation +Плагин для работы со строками. Может переводить все строки в верхний/нижний регистр, сортировать строки и прочие манипуляции. + +![](../../meta/files/images/plugin-string-manipulation.gif) + +**Ссылка на установку:** [String Manipulation - IntelliJ IDEs Plugin | Marketplace](https://plugins.jetbrains.com/plugin/2162-string-manipulation) +## Presentation Assistant +Этот плагин отлично дополнит ваш live coding, потому что его задача ненавязчиво выводить комбинации клавиш, которые вы нажимаете. Даже если вы не будете нажимать сочетание клавиш, а просто кликаете мышкой, но для этого есть хоткей, то он также будет выведен. + +**Кому подойдет:** Тем кто проводит вебинары. Также он мне больше нравится, чем Key Promoter X для изучения хоткеев. + +![](../../meta/files/images/Pasted%20image%2020240908110354.png) + +**Ссылка на установку:** [Presentation Assistant for 2023.2 - IntelliJ IDEs Plugin | Marketplace](https://plugins.jetbrains.com/plugin/7345-presentation-assistant) +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-09-08]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/java/Многопоточность в Java.md b/dev/java/Многопоточность в Java.md new file mode 100644 index 00000000..8b252fa5 --- /dev/null +++ b/dev/java/Многопоточность в Java.md @@ -0,0 +1,26 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-10-08 +zero-link: +parents: +linked: +--- +- [[synchronized]] +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-10-08]] +**Автор**:: +### Дополнительные материалы +- [[../../source/lecture/Доклад. Лекция 11. Многопоточность в Java|Доклад. Лекция 11. Многопоточность в Java]] + +### Дочерние заметки + + +- [[synchronized]] + + diff --git a/dev/java/Мультимодульные проекты c Jandex.md b/dev/java/Мультимодульные проекты c Jandex.md new file mode 100644 index 00000000..68c98710 --- /dev/null +++ b/dev/java/Мультимодульные проекты c Jandex.md @@ -0,0 +1,91 @@ +--- +aliases: + - jandex +tags: + - maturity/🌱 +date: 2023-10-21 +zero-link: + - "[[../../meta/zero/00 Gradle|00 Gradle]]" + - "[[../../meta/zero/00 Maven|00 Maven]]" +parents: +linked: + - "[[../../meta/zero/00 Quarkus|00 Quarkus]]" +--- +Столкнулся с такой проблемой при использовании [[../../meta/zero/00 Quarkus|Quarkus]]. [[../../meta/zero/00 Gradle|Gradle]] проект, который состоит из нескольких модулей успешно собирался, но бины из одного модуля не обнаруживались в другом. Та же проблема будет и с [[../../meta/zero/00 Maven|Maven]]. + +Проблема решилась с помощью плагина: [Jandex](https://github.com/kordamp/jandex-gradle-plugin). + +Пример настройки в корневом `build.gradle` + +```gradle +plugins { + id("org.kordamp.gradle.jandex") version "2.0.0" +} + +buildscript { + repositories { + gradlePluginPortal() + mavenCentral() + } + dependencies { + classpath 'org.kordamp.gradle:jandex-gradle-plugin:1.0.0' + } +} + +apply plugin: "org.kordamp.gradle.jandex" + +subprojects { + + apply plugin: "org.kordamp.gradle.jandex" + + tasks.withType(Javadoc).configureEach { + dependsOn('jandex') + options.encoding = 'UTF-8' + options.addStringOption("Xdoclint:none", "-quiet") + } +} + +allprojects { + tasks.matching { task -> + task.name in ['quarkusDependenciesBuild'] + }.configureEach { + dependsOn 'jandex' + } +} +``` + +Пример настройки в корневом `pom.xml` + +- [Maven Repository: io.smallrye » jandex](https://mvnrepository.com/artifact/io.smallrye/jandex) + +```xml + + + + io.smallrye + jandex-maven-plugin + 3.1.6 + + + make-index + + jandex + + + + + + +``` + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Maven|00 Maven]], [[../../meta/zero/00 Gradle|00 Gradle]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2023-10-21]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/java/Нативные сборки в Java.md b/dev/java/Нативные сборки в Java.md new file mode 100644 index 00000000..d639c455 --- /dev/null +++ b/dev/java/Нативные сборки в Java.md @@ -0,0 +1,39 @@ +--- +aliases: + - нативные сборки +tags: + - maturity/🌱 +date: 2023-11-15 +zero-link: + - "[[../../meta/zero/00 Java разработка|00 Java разработка]]" +parents: +linked: +--- +Нативные сборки в контексте Java относятся к процессу компиляции Java-приложений в нативный машинный код, специфичный для конкретной операционной системы и архитектуры процессора. Это отличается от традиционного подхода Java, где приложения компилируются в байт-код и выполняются на Java Virtual Machine ([Java Virtual Machine](Java%20Virtual%20Machine.md)). Основным инструментом для создания нативных сборок в Java является GraalVM Native Image. + +**Плюсы:** +1. **Быстрый Старт и Низкое Расходование Ресурсов**: Нативные сборки могут значительно ускорить время запуска приложения и уменьшить потребление ресурсов (например, памяти), поскольку они не требуют запуска JVM и загрузки классов ([Class Loader Subsystem](Class%20Loader%20Subsystem.md)) во время выполнения. +2. **Уменьшение Зависимости от JVM**: Нативные приложения уменьшают зависимость от конкретной версии JVM, что может быть полезно в контекстах с ограниченными ресурсами или в случаях, когда требуется минимизировать размер сборки. +3. **Лучшая Интеграция с Системой**: Нативные приложения могут лучше интегрироваться с операционной системой и использовать системные библиотеки. +4. **Безопасность и Изоляция**: Нативные сборки могут предложить улучшенную безопасность и изоляцию, так как они меньше зависят от внешних факторов, таких как настройки JVM. + +**Минусы:** +1. **Ухудшение Производительности**: Несмотря на ускорение запуска, нативные сборки могут иметь более низкую производительность выполнения по сравнению с JVM, особенно для долго работающих приложений, где JVM оптимизирует выполнение кода во время работы ([[JIT Compilation]]). +2. **Сложность Сборки**: Процесс создания нативной сборки может быть сложнее и требует дополнительных настроек по сравнению с традиционной Java-сборкой. +3. **Ограниченная Совместимость**: Не все библиотеки и фреймворки Java совместимы с нативной компиляцией, и некоторые могут требовать специальной адаптации или полностью не поддерживаться. Чаще всего проблема в генерации классов во время выполнения программы. Например, [такого очень много в SpringBoot.](Создание%20прокси-объектов%20в%20SpringBoot.md) +4. **Отсутствие Кросс-Платформенности**: Одним из ключевых преимуществ Java является ее кросс-платформенность, которая теряется при переходе к нативным сборкам, так как они специфичны для каждой платформы. + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2023-11-15]] +### Дополнительные материалы +- [Исследование сборки исполняемых файлов](Исследование%20сборки%20исполняемых%20файлов.md) +### Дочерние заметки + + +- [[Сборка Quarkus приложения в исполняемый файл]] + diff --git a/dev/java/Не используйте @Data.md b/dev/java/Не используйте @Data.md new file mode 100644 index 00000000..8bcdc72a --- /dev/null +++ b/dev/java/Не используйте @Data.md @@ -0,0 +1,35 @@ +--- +aliases: +tags: + - maturity/🌱 + - content/opinion +date: 2023-11-20 +zero-link: + - "[[00 Java разработка]]" +parents: +linked: +--- +Многие разработчики в целом против использования Lombok. Это действительно холиварная тема. Но если вы всё-таки используете Lombok в проекте, постарайтесь избегать спорных и потенциально вредных аннотаций. + +Одна из таких — это `@Data`. Во-первых, мало кто помнит, [какие методы она генерирует](https://projectlombok.org/features/Data). +- `@EqualsAndHashCode`. Это наиболее проблемная аннотация в составе `@Data`. Она генерирует методы `equals()` и `hashCode()` для всех полей класса, но зачастую этого не требуется. Например, для сущностей достаточно сравнивать только по идентификатору. +- `@ToString`. Если объект содержит чувствительную информацию, этот метод может вывести её в лог, что небезопасно. +- `@Getter` / `@Setter`. Здесь проблем нет. +- `@RequiredArgsConstructor`. Тоже допустимо. + +Основная проблема кроется в аннотации `@EqualsAndHashCode`. Конечно, можно использовать `@EqualsAndHashCode.Exclude`, чтобы исключить отдельные поля из генерации, но вам придётся добавлять это почти ко всем полям. Использовать `@EqualsAndHashCode.Include` не получится — вы не можете включить только необходимые поля, придётся исключать все лишние. + +Кроме того, избегайте аннотаций из пакета `experimental`. Эти аннотации нестабильны и могут быть удалены в следующих версиях Lombok. Единственным исключением является [@FieldNameConstants](https://projectlombok.org/features/experimental/FieldNameConstants). За несколько лет с ней не возникало проблем, а существующие альтернативы оставляют желать лучшего. + +В целом, Lombok делает код чище, но, как и с любым “магическим” инструментом, важно понимать, как он работает и в каких случаях его применение уместно. В противном случае это может привести к снижению производительности или даже некорректной работе приложения. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2023-11-20]] +### Дополнительные материалы +- [Lombok + JPA: Что может пойти не так? / Хабр](https://habr.com/ru/company/haulmont/blog/564682/) +### Дочерние заметки + diff --git a/dev/java/Не используйте var в Java.md b/dev/java/Не используйте var в Java.md new file mode 100644 index 00000000..4f4be578 --- /dev/null +++ b/dev/java/Не используйте var в Java.md @@ -0,0 +1,29 @@ +--- +aliases: +tags: + - maturity/🌱 + - content/opinion +date: 2024-10-20 +--- +Использование `var`, введенное в [[../../../../knowledge/dev/java/Java 10|Java 10]], может улучшить компактность кода, но имеет недостатки, связанные со снижением [[Читаемый код|читаемости]]. Хотя переменная остается статически типизированной и обеспечивает безопасность кода, ==скрытие типа может затруднить понимание логики, особенно при командной работе и ревью.== + +Например, следующий код не дает информации о том, что представляет `result` и что возвращает метод `process()`, что усложняет чтение, особенно в больших командах: + +```java +var result = process(); +``` + +Это может привести к путанице, особенно если метод возвращает обобщённый тип или коллекцию. Без явного указания типов ==разработчикам придётся тратить дополнительное время на выяснение, что происходит==. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-10-20]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/java/Параллельная сборка модулей в Maven.md b/dev/java/Параллельная сборка модулей в Maven.md new file mode 100644 index 00000000..6cbeafbe --- /dev/null +++ b/dev/java/Параллельная сборка модулей в Maven.md @@ -0,0 +1,51 @@ +--- +aliases: +tags: + - maturity/🌱 +date: + - - 2023-11-20 +zero-link: + - "[[../../meta/zero/00 Maven|00 Maven]]" +parents: +linked: +--- +Небольшая хитрость, которая может ускорить сборку многомодульного maven проекта. Это параллельная сборка модулей. + +```shell +mvn -T 1C clean install +``` +1C означате использовать 1 поток на 1 ядро процессора + +Но есть одно условие. Ваш проект должен содержать модули, которые не зависят друг от друга последовательно. + +Объясню на примере проекта, который состоит из 18 модулей. Оранжевыми прямоугольники я выделил модули, которые могут собираться параллельно, так как они не зависят друг от друга. + +![400](../../meta/files/images/Pasted%20image%2020231120092703.png) + +По факту эти группы модулей зависят только друг от друга. Сначала собирается группа `domain`, от нее зависит группа `context`, потом core и так далее. Без `context` не собрать `core`, думаю суть понятна. Но вот модули core не зависят друг от друга, и могут собираться параллельно. + +Для примера вот время сборки в последовательном режиме: + +![](../../meta/files/images/Pasted%20image%2020231120092720.png) + +А вот в параллельном: + +![](../../meta/files/images/Pasted%20image%2020231120092732.png) + +Выигрыш почти в два раза. + +И на последок, вот как можно настроить этот параметр в Idea, чтобы не приходилось запускать сборку из консоли каждый раз. Эту настройку нужно делать в каждом проекте, она не глобальная. + +![](../../meta/files/images/Pasted%20image%2020231120092753.png) + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Maven|00 Maven]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2023-11-20]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/java/Передача значений в метод в Java.md b/dev/java/Передача значений в метод в Java.md new file mode 100644 index 00000000..c3f8079f --- /dev/null +++ b/dev/java/Передача значений в метод в Java.md @@ -0,0 +1,48 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-10-19 +--- +Важно понимать, как происходит передача данных в методы. При передаче [[Примитивный тип|примитивных типов]] в метод, копируется **значение** переменной. Это значит, что ==любые изменения, которые вы делаете с переменной внутри метода, не влияют на оригинальную переменную.== + +Однако, при передаче [[Ссылочный тип|ссылочных типов]] копируется значение ссылки на объект, а не сам объект. Это значит, что ==если изменить содержимое объекта через эту ссылку, изменения отразятся и на оригинальном объекте==. + +Это часто становится причиной ошибок у новичков, поэтому представьте, что [[Примитивный тип|примитивные типы]] — это как копирование листа бумаги: вы даете кому-то копию, и он может писать на ней, но оригинал останется нетронутым. А [[Ссылочный тип|ссылочные типы]] — это как передача адреса на дом: если кто-то приедет по адресу и изменит что-то в доме, оригинальный дом изменится, даже если у каждого будет только этот “адрес”. + +```java +public class Example { + public static void main(String[] args) { + int primitive = 5; + modifyPrimitive(primitive); + System.out.println("После изменения примитива: " + primitive); // Выведет 5 + + int[] reference = {1, 2, 3}; + modifyReference(reference); + System.out.println("После изменения ссылочного типа: " + reference[0]); // Выведет 100 + } + + public static void modifyPrimitive(int number) { + number = 10; // Изменение копии примитива, оригинал не затронут + } + + public static void modifyReference(int[] array) { + array[0] = 100; // Изменение объекта по ссылке, оригинальный массив изменится + } +} +``` +- В примере с примитивным типом (int), значение переменной primitive не изменяется, потому что в метод передаётся копия значения. +- В примере с массивом (ссылочный тип), изменяется оригинальный объект, так как в метод передается ссылка на массив, и мы изменяем содержимое этого объекта через ссылку. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-10-19]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/java/Примитивный тип.md b/dev/java/Примитивный тип.md new file mode 100644 index 00000000..eb682ca5 --- /dev/null +++ b/dev/java/Примитивный тип.md @@ -0,0 +1,29 @@ +--- +aliases: + - примитивных типов + - примитивные типы +tags: + - maturity/🌱 +date: 2024-10-19 +--- +- Логические: boolean +- Целочисленные: byte, short, int, long +- Дробные: float, double +- Символьные (UTF-16): CHAR + +![[../../meta/files/images/Pasted image 20241030215828.png]] +![[../../meta/files/images/Pasted image 20241030223908.png]] + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-10-19]] +**Автор**:: +### Дополнительные материалы +- [[Ссылочный тип|Ссылочный тип]] + +### Дочерние заметки + + diff --git a/dev/java/Процесс выполнения Java программы.md b/dev/java/Процесс выполнения Java программы.md new file mode 100644 index 00000000..03f90cfa --- /dev/null +++ b/dev/java/Процесс выполнения Java программы.md @@ -0,0 +1,26 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-11-24 +--- +1. **Компиляция исходного кода в байт-код:** исходный код (`.java` файлы) компилируется компилятором Java (javac) в [[Java байт-код|байт-код]] (`.class` файлы). +2. **Загрузка байт-кода и классов:** класс-загрузчики [[Java Virtual Machine|JVM]] ([[ClassLoader|Class Loaders]]) загружают байт-код в память по мере необходимости. Сначала загружается основной класс, затем все остальные классы, необходимые для выполнения программы. +3. **Проверка байт-кода:** JVM проверяет байт-код для обеспечения его корректности и безопасности, чтобы предотвратить выполнение некорректного или вредоносного кода. +4. **Интерпретация:** интерпретатор начинает выполнение программы, интерпретируя байт-код в машинный код построчно. Этот этап позволяет сразу начать выполнение программы, не тратя время на полную компиляцию. Однако интерпретация может быть медленной, так как каждая инструкция должна заново преобразовываться в машинный код. +5. **JIT-компиляция:** Чтобы ускорить выполнение, JVM использует Just-In-Time (JIT) компилятор, который преобразует часто выполняемые части байт-кода в машинный код, позволяя процессору выполнять их напрямую. +6. **Сборка мусора:** Сборщик мусора (Garbage Collector) автоматически освобождает память от объектов, которые больше не используются, что предотвращает утечки памяти и снижает нагрузку на разработчика. Это улучшает управление ресурсами и обеспечивает надёжное выполнение программы. + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разр аботка]] +**Родитель**:: [[Java Virtual Machine|JVM]] +**Источник**:: +**Создана**:: [[2024-11-24]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/java/Расширяющее преобразование в Java.md b/dev/java/Расширяющее преобразование в Java.md new file mode 100644 index 00000000..7c21e9bb --- /dev/null +++ b/dev/java/Расширяющее преобразование в Java.md @@ -0,0 +1,33 @@ +--- +aliases: + - widening conversions +tags: + - maturity/🌱 +date: 2024-11-01 +--- +Расширяющие преобразования (widening conversions) позволяют в Java автоматически преобразовывать значение одного типа к другому, более широкому типу без явного приведения. + +``` +byte → short → int → long → float → double + ↑ + char +``` + +**Потеря точности**: +- int -> float +- long -> float (на больших значениях long) +- long -> double (на больших значениях long) + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-01]] +**Автор**:: +### Дополнительные материалы +- [[Сжимающее преобразование в Java]] + +### Дочерние заметки + + diff --git a/dev/java/Сжимающее преобразование в Java.md b/dev/java/Сжимающее преобразование в Java.md new file mode 100644 index 00000000..56f1a28f --- /dev/null +++ b/dev/java/Сжимающее преобразование в Java.md @@ -0,0 +1,31 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-11-01 +--- +Сужающие преобразования (narrowing conversions) позволяют в Java преобразовывать значение более широкого типа к более узкому типу, но такие преобразования **не выполняются автоматически** и требуют явного приведения. Сужающие преобразования могут привести к **потере данных** или **потере точности** и требуют внимания при их использовании. + +``` +double → float → long → int → short → byte + ↓ + char +``` + +- Преобразование int в short может привести к потере данных, если значение int выходит за пределы диапазона short (-32768, 32767). +- Преобразование double в float может привести к потере точности, так как float имеет меньше значащих разрядов, чем double. +- Преобразование float или double в int, short, byte приводит к усечению десятичной части, что также может вызвать потерю точности. + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-01]] +**Автор**:: +### Дополнительные материалы +- [[Расширяющее преобразование в Java|Расширяющее преобразование в Java]] + +### Дочерние заметки + + diff --git a/dev/java/Сохранение HeapDump.md b/dev/java/Сохранение HeapDump.md new file mode 100644 index 00000000..6ba9bbc9 --- /dev/null +++ b/dev/java/Сохранение HeapDump.md @@ -0,0 +1,32 @@ +--- +aliases: + - HeapDumpOnOutOfMemoryError + - HeapDumpPath +tags: + - maturity/🌱 +date: 2024-11-25 +--- +При запуске Java-приложения с помощью следующей команды: +```shell +/app/jdk/bin/java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/dumps/oom.bin -jar your-app.jar +``` + +параметры `-XX:+HeapDumpOnOutOfMemoryError` и `-XX:HeapDumpPath=/dumps/oom.bin` позволяют автоматически сохранить heap dump в файл `/dumps/oom.bin` при возникновении ошибки `OutOfMemoryError`. + +**Рекомендации:** +- Убедитесь, что каталог `/dumps` существует. +- Проверьте, что у процесса Java есть права на запись в этот каталог. +- Если каталог отсутствует или недостаточно прав, heap dump может не сохраниться. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-25]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/java/Сравнение enum в Java.md b/dev/java/Сравнение enum в Java.md new file mode 100644 index 00000000..10994ee3 --- /dev/null +++ b/dev/java/Сравнение enum в Java.md @@ -0,0 +1,41 @@ +--- +aliases: +tags: + - maturity/🌱 + - content/opinion +date: 2023-11-20 +zero-link: + - "[[../../meta/zero/00 Java разработка|00 Java разработка]]" +parents: +linked: +--- +Enum это объект, как и все в Java. Однако это особенный объект. Каждый из объектов enum создаётся только единожды. Давайте на примере: + +```java +enum TestEnum {ONE, TWO, THREE} +``` + +Если мы создадим 10 переменных `TestEnum.ONE`, то все они будут ссылаться на один и тот же объект. И поэтому enum можно сравнивать с помощью `==` и это корректно и будет работать. + +Сторонники такого подхода называют следующие преимущества. Давайте их разберем. + +**Вы никогда не получите `NullPointerException`.** И это правда, но если вы будете придерживаться правила ["сравнение константы слева"](Сравнение%20константы%20слева%20в%20Java.md), то и при использовании `.equals()` `NullPointerException` вам не страшен. + +**Оператор == работает быстрее.** Быстрее чего? Видимо метода `.equals()`. Давайте посмотрим реализацию метода `.equals()` у enum. + +![](../../meta/files/images/Pasted%20image%2020231120093026.png) + +**Оператор == более понятный синтаксически.** Это еще почему? Для сравнения объектов в Java используется `.equals()`. Enum это объект. Логичнее и очевиднее использовать `.equals()` для сравнения, чтобы не нарушать единообразие сравнения объектов. + +На мой взгляд, правильнее использовать `.equals()`, главное не забывать о правиле "[Сравнение константы слева](Сравнение%20константы%20слева%20в%20Java.md)". +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2023-11-20]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/java/Сравнение константы слева в Java.md b/dev/java/Сравнение константы слева в Java.md new file mode 100644 index 00000000..9d6af2e0 --- /dev/null +++ b/dev/java/Сравнение константы слева в Java.md @@ -0,0 +1,73 @@ +--- +aliases: +tags: + - maturity/🌱 + - content/opinion +date: 2024-09-06 +zero-link: + - "[[../../meta/zero/00 Java разработка|00 Java разработка]]" +parents: +linked: +--- +Представьте, что у вас есть enum, который отвечает за статус пользователя в системе: "онлайн", "офлайн" и "занят". + +```java +public enum UserStatus { + + ONLINE, OFFLINE, BUSY + +} +``` + +```java +public class User { + + ... + + @Column(name = "status") + @Enumerated(EnumType.STRING) + private UserStatus status; + + ... + +} +``` + +Скорее всего для выполнения бизнес-логики вам потребуется проверять статус пользователя + +```java +if (user.getStatus().equals(UserStatus.ONLINE)) { + // to do something +} +``` + +Вроде бы все отлично, миссия выполнена. Но есть одно НО. Что если `getStatus()` вернет вам `null`? Правильно, вы получите `NullPointerException`. + +Чтобы этого избежать следует придерживаться правила "Сравнения константы слева". Оно очень простое. В нашем примере, мы точно уверены, что `UserStatus.ONLINE` существует, поэтому `.equals()` стоит вызывать от него. + +```java +if (UserStatus.ONLINE.equals(user.getStatus())) { + // to do something +} +``` + +В остальных подобных ситуациях делайте также, например со строками: + +```java +if ("Иванов".equals(user.getLastName())) { + // to do something +} +``` + +Это простое правило защитит вас от `NullPointerException`. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-09-06]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/java/Ссылочный тип.md b/dev/java/Ссылочный тип.md new file mode 100644 index 00000000..51ae1067 --- /dev/null +++ b/dev/java/Ссылочный тип.md @@ -0,0 +1,33 @@ +--- +aliases: + - ссылочных типов + - ссылочные типы + - ссылочный тип +tags: + - maturity/🌱 +date: 2024-10-19 +zero-link: +parents: +linked: +--- +Ссылочные типы позволяют работать с пользовательскими типами данных, такими как объекты классов. Однако, важно понимать, что ==переменная ссылочного типа не хранит сами данные объекта. Вместо этого переменная хранит **ссылку** на объект==, который находится в области памяти, называемой [[Куча|кучей]] (heap). + +Когда вы объявляете переменную ссылочного типа, например: +```java +MyClass obj = new MyClass(); +``` + +Переменная `obj` ==не содержит сам объект класса `MyClass`, а лишь хранит адрес этого объекта в памяти==. То есть, в самой переменной хранится ссылка на объект, а не его данные. Все операции с такой переменной выполняются через эту ссылку. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-10-19]] +**Автор**:: +### Дополнительные материалы +- [[Примитивный тип|Примитивный тип]] + +### Дочерние заметки + + diff --git a/dev/java/Статическая фабрика в Java.md b/dev/java/Статическая фабрика в Java.md new file mode 100644 index 00000000..1a97080a --- /dev/null +++ b/dev/java/Статическая фабрика в Java.md @@ -0,0 +1,78 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-10-06 +zero-link: +parents: +linked: +--- +[[../other/Статическая фабрика|Статическая фабрика]] в Java — это метод, который возвращает экземпляры класса, но вместо создания объектов через конструктор, используется статический метод. Такой подход дает разработчику гибкость в процессе создания объектов, возможность кэширования и возвращения уже созданных экземпляров, а также улучшает [[../Читаемый код|читаемость кода]] за счет осмысленных имен методов, таких как `of()` или `valueOf()`. + +Статическая фабрика часто используется для реализации паттернов, таких как Singleton, а также для создания объектов, требующих дополнительной логики при инициализации. + +Рассмотрим простой пример создания объекта с помощью статической фабрики: + +```java +public class Foo { + private int value; + + // Приватный конструктор + private Foo(int value) { + this.value = value; + } + + // Статический фабричный метод + public static Foo of(int value) { + return new Foo(value); + } + + // Другой статический метод + public static Foo doubleCreate(int value) { + return new Foo(value * value); + } +} +``` + +Здесь конструктор класса `Foo` является приватным, и доступ к нему осуществляется через два статических метода: `of()` для простого создания объекта и `doubleCreate()`, который создает объект с модифицированным значением. + +Теперь рассмотрим пример с кэшированием, чтобы избежать создания новых объектов при одинаковых параметрах: + +```java +import java.util.HashMap; +import java.util.Map; + +public class Foo { + private static final Map cache = new HashMap<>(); + private int value; + + private Foo(int value) { + this.value = value; + } + + // Статический фабричный метод с кэшированием + public static Foo of(int value) { + if (!cache.containsKey(value)) { + cache.put(value, new Foo(value)); + } + return cache.get(value); + } +} +``` + +В этом примере используется кэширование: если объект с определенным значением уже был создан, статическая фабрика возвращает его из кэша, а если нет — создает новый и сохраняет его для дальнейшего использования. + + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: [[../other/Статическая фабрика|Статическая фабрика]] +**Источник**:: +**Создана**:: [[2024-10-06]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/java/Статическое связывание в Java.md b/dev/java/Статическое связывание в Java.md new file mode 100644 index 00000000..bf08b12c --- /dev/null +++ b/dev/java/Статическое связывание в Java.md @@ -0,0 +1,55 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-10-05 +zero-link: +parents: +linked: +--- +Примеры [[../other/Статическое связывание|статического связывания]] в Java + +**Перегрузка методов (Method Overloading).** Когда методы с одним именем имеют разные параметры (тип или количество). Решение о том, какой метод вызвать, принимается на этапе компиляции. + +```java +class Example { + void show(int x) { + System.out.println("Integer: " + x); + } + void show(String s) { + System.out.println("String: " + s); + } +} +``` + +**Методы или поля с ключевым словом** `final` +Методы и поля, помеченные как `final`, подлежат статическому связыванию, так как их реализация не может быть изменена. + +**Методы или поля внутри** `private` **классов** +Методы, объявленные с модификатором доступа `private`, также связываются статически, поскольку они недоступны для переопределения в подклассах. + +**Статические методы (Static Methods)** +Статические методы связаны с классом, а не с объектом. Поэтому их связывание происходит на этапе компиляции. + +**Простые вызовы полей** +Доступ к полям (переменным класса) также осуществляется через статическое связывание. Например, если переменная является примитивным типом или объявлена как `static`, её связывание происходит на этапе компиляции. + +**Перегрузка операторов (Operator Overloading)** +Хотя Java не поддерживает прямую перегрузку операторов, операторы, такие как + для строк, являются примерами статического связывания. Компилятор точно знает, какой оператор будет использован с каким типом данных. + +```java +String result = "Hello" + "World"; // Конкатенация строк +``` +*** +## Мета информация +**Область**:: [[../../../../garden/ru/meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: [[../../../../garden/ru/dev/other/Статическое связывание|Статическое связывание]] +**Источник**:: +**Создана**:: [[2024-10-05]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/java/Странности в Java.md b/dev/java/Странности в Java.md new file mode 100644 index 00000000..2516813e --- /dev/null +++ b/dev/java/Странности в Java.md @@ -0,0 +1,87 @@ +--- +aliases: + - polygenelubricants +tags: + - maturity/🌱 +date: 2024-10-30 +--- +## Арифметические +### Особые числа + +- +0.0, -0.0 + - Равны по equals, но различаются по toString +- Double.POSITIVE_INFINITY + - Больше всякого другого числа, положительное + - 1/Infinity = 0.0 + - Infinity+1=Infinity, Infinity+Infinity=Infinity +- Double.NEGATIVE_INFINITY + - Меньше всякого другого числа, отрицательное + - 1/-Infinity = -0.0 +- `Double.NAN` + - Не больше, не меньше и не равно никакому числу, в том числе себе + - Любая операция с NaN даст NaN +### Отсутствие переполнения +```java +System.out.println(-Integer.MIN_VALUE) // -2147483648 +``` + +Можно использовать `Math.negateExact()`, чтобы получить исключение + +```java +Math.negateExact(Integer.MIN_VALUE) +``` + +### Абсолютное значение +```java +Math.abs(-Integer.MIN_VALUE) // -2147483648 +``` + +### Character +```java +System.out.println(Character.isDigit('⑤')); // false +System.out.println(Character.getNumericValue('⑤') == 5); // true +``` +## Прочее +### Хранение массивов в памяти +``` +int[][] table = new int[2][500]; // 4056 байт, 1.4% +int[][] table = new int[500][2]; // 14016 байт, 350.4% +``` + +- [[../../../../knowledge/dev/java/Устройство объекта в памяти Java|Устройство объекта в памяти Java]] + - Мы создаём **только 2 объекта массива** (главный массив и два подмассива). На каждый массив выделяется небольшая дополнительная память для служебной информации, связанной с объектом. + - Мы создаём **500 подмассивов** (главный массив и 500 маленьких подмассивов). На каждый массив также выделяется дополнительная память для служебной информации о каждом объекте. +### polygenelubricants +```java +System.out.println("polygenelubricants".hashCode()); // Integer.MIN_VALUE +``` +### Bugaga +```java +class Hello { + public static void main(String[] args) { + // Безобидный комментарий \u000a System.out.println("Bugaga") ; + System.out.println("Hello World"); + } +} +``` + +Sout: +``` +Bugaga +Hello World +``` + + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Java разработка|00 Java разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-10-30]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/kafka/Dead Letter Queue.md b/dev/kafka/Dead Letter Queue.md new file mode 100644 index 00000000..063a58fd --- /dev/null +++ b/dev/kafka/Dead Letter Queue.md @@ -0,0 +1,33 @@ +--- +aliases: + - DLQ +tags: + - maturity/🌱 +date: 2024-11-12 +--- +**DLQ (Dead Letter Queue)** — это специальная очередь, используемая в системах обработки сообщений, таких как [[../../../../_inbox/00 Kafka|Kafka]], для хранения сообщений, которые не могут быть обработаны основным потребителем. Основное назначение DLQ — изолировать проблемные сообщения, чтобы они не блокировали остальную обработку и позволить команде разобраться с ними позже, не нарушая работы системы. + +> [!WARNING] Не лечите симптом +> Попадание событий в DLQ говорит о сбоях в работе системы, которые необходимо исправлять. Обработка DLQ делается на всякий случай и не является решением проблемы. + +Подходы по обработке DLQ сообщений: +- [[Перенос DLQ сообщений обратно в основной топик]] +- **Анализ и исправление ошибок**: Можно настроить процесс, который анализирует причины неудачной обработки и предпринимает меры по их исправлению (например, корректировка данных или обновление логики обработки). +- **Уведомления и алерты**: Настроить систему оповещений, которая уведомляет команду о наличии сообщений в DLQ, чтобы они могли вручную принять меры. +- **Отложенная повторная обработка**: Использовать механизм отложенной повторной попытки с экспоненциальной задержкой, чтобы избежать постоянного быстрого переотправления сообщений. +*** +## Мета информация +**Область**:: [[00 Kafka]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-12]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + +- [[Перенос DLQ сообщений обратно в основной топик]] + + diff --git a/dev/kafka/Перенос DLQ сообщений обратно в основной топик.md b/dev/kafka/Перенос DLQ сообщений обратно в основной топик.md new file mode 100644 index 00000000..423e9fe2 --- /dev/null +++ b/dev/kafka/Перенос DLQ сообщений обратно в основной топик.md @@ -0,0 +1,26 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-11-12 +--- +Один из распространённых подходов к обработке сообщений из [[Dead Letter Queue|DLQ]] — это перенос их обратно в основной топик с использованием специального счётчика в заголовках сообщений для контроля количества попыток. Однако такой подход может иметь несколько недостатков: + +1. **Порядок сообщений**: Возвращение сообщений в основной топик может нарушить порядок сообщений, что критично для приложений, где последовательность имеет значение. +2. **Бесконечные циклы**: Если сообщение постоянно не удаётся обработать, оно может застрять в цикле между основным топиком и DLQ. Даже с ограничением по количеству попыток остаётся риск, что проблемные сообщения будут потреблять ресурсы без достижения результата. +3. **Нагрузка на систему**: Повторная обработка сообщений увеличивает нагрузку на систему, что может повлиять на производительность и увеличить затраты на ресурсы. +4. **Усложнение отладки**: Труднее отслеживать и отлаживать проблемы, когда сообщения постоянно перемещаются между топиками. +5. **Потенциальные дублирования**: Возникает возможность появления дублирующихся сообщений, если не гарантируется [[../architecture/Идемпотентность|идемпотентность]] при обработке. +*** +## Мета информация +**Область**:: [[00 Kafka]] +**Родитель**:: [[Dead Letter Queue|Dead Letter Queue]] +**Источник**:: +**Создана**:: [[2024-11-12]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/linux/Control group.md b/dev/linux/Control group.md new file mode 100644 index 00000000..924b58d0 --- /dev/null +++ b/dev/linux/Control group.md @@ -0,0 +1,39 @@ +--- +aliases: + - cgroup +tags: + - maturity/🌱 +date: + - - 2024-03-19 +zero-link: + - "[[../../meta/zero/00 Linux|00 Linux]]" +parents: + - "[[Контейнерная виртуализация]]" +linked: +--- +Control group — это механизм в ядре Linux, предоставляющий функциональность управления и ограничения ресурсами, используемыми [процессами](../fundamental/Процесс%20ОС.md), запущенными в системе. Это позволяет системному администратору распределять ресурсы, такие как CPU, память, [пропускная способность](../architecture/Throughput.md) сети и доступ к устройствам, между наборами процессов. + +С помощью cgroup можно: +- Управлять лимитом cpu. Как процент времени, который выделяется, так и CPU-sets, то есть какие ядра мы можем задействовать. Есть как общее ограничение, так и индивидуальные для подпроцессов +- Управлять ограничением по памяти. Имеется возможность настроить как максимальный так и минимальный порог. +- Доступ к устройствам +- Ограничения сети +- Ограничения дисковых операций + +С помощью cgroup можно: +- Ограничивать количество ресурсов, которые могут использовать процессы в группе. Например, можно задать максимальное количество CPU или объем оперативной памяти, которые доступны определенной группе процессов. +- Отслеживать использование ресурсов процессами или группами процессов. Это позволяет вести мониторинг загрузки системы и определять, какие процессы или группы процессов используют больше всего ресурсов. +- Управлять приоритетами доступа к ресурсам для различных групп процессов. Это может быть полезно для обеспечения того, чтобы критически важные задачи имели доступ к необходимым ресурсам в первую очередь. + +Утилита `cgroup` позволяет организовывать процессы в иерархические группы, что упрощает управление и делает систему более гибкой и масштабируемой. `cgroup` широко используется в технологиях виртуализации и контейнеризации, таких как [[../../meta/zero/00 Docker|Docker]] и Kubernetes, поскольку они предоставляют эффективные средства для изоляции и управления ресурсами виртуальных и контейнеризированных сред. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Linux|00 Linux]] +**Родитель**:: [[Контейнерная виртуализация]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-03-19]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/linux/File Globbing.md b/dev/linux/File Globbing.md new file mode 100644 index 00000000..8acd25d8 --- /dev/null +++ b/dev/linux/File Globbing.md @@ -0,0 +1,51 @@ +--- +aliases: + - globbing +tags: + - maturity/🌱 +date: 2024-11-14 +--- +Глоббинг (globbing) — это техника, используемая в командной оболочке Linux (и других UNIX-подобных системах) для поиска файлов, используя шаблоны вместо перечисления имен файлов. Паттерны глоббинга помогают выполнять операции с несколькими файлами за один раз, что делает работу удобнее и эффективнее. + +**Базовые паттерны глоббинга:** +- `*` — Совпадает с любым количеством символов (включая ноль символов). Пример: `file*` найдет `file1.txt`, `fileA`, и любые другие файлы, начинающиеся на "file". +- `?` — Совпадает с одним любым символом. Пример: `file?.txt` найдет файлы вроде `file1.txt` или `fileA.txt`, но не `file10.txt`. +- `[abc]` — Совпадает с любым из символов, указанных в квадратных скобках. Пример: `file[abc].txt` найдет `filea.txt`, `fileb.txt`, или `filec.txt`. +- `[a-z]` — Совпадает с любым символом в указанном диапазоне. Пример: `file[a-z].txt` найдет файлы, такие как `filea.txt`, `filem.txt` и т.д. +- `[!abc]` или `[^abc]` — Совпадает с любым символом, не входящим в указанный список. Пример: `file[!a].txt` найдет все файлы, кроме `filea.txt`. + +**Комбинированные паттерны глоббинга:** +- `file*` — Найдет все файлы, начинающиеся с "file". +- `*.txt` — Найдет все файлы с расширением ".txt". +- `file[0-9].txt` — Найдет файлы, такие как `file1.txt`, `file2.txt`, но не `fileA.txt`. +- `file{1,2,3}.txt` — Найдет файлы `file1.txt`, `file2.txt`, `file3.txt`. + +**Расширенные паттерны глоббинга:** +- `**/*.txt` — Найдет все файлы с расширением ".txt" в текущей директории и всех ее поддиректориях. +- `[a-z]*` — Найдет файлы, начинающиеся с любой строчной буквы. +- `[[:digit:]]*` — Найдет файлы, начинающиеся с цифры. + +**Использование глоббинга в командах:** +- `ls *.txt` — Показать все файлы с расширением `.txt` в текущей директории. +- `cp file?.txt /backup/` — Скопировать файлы, такие как `file1.txt` или `fileA.txt` в директорию `/backup/`. +- `rm file[0-9]*` — Удалить файлы, начинающиеся с `file` и за которыми следует цифра. +- `mv data{1,2,3}.csv /data/archive/` — Переместить файлы `data1.csv`, `data2.csv`, `data3.csv` в `/data/archive/`. +- `tar -cvf archive.tar *.log` — Архивировать все `.log` файлы в `archive.tar`. + +**Экранирование специальных символов** +Чтобы указать оболочке, что определенные символы не должны интерпретироваться как метасимволы, их необходимо экранировать с помощью обратной косой черты (`\`). +- `ls \*.txt` — Найдет файл с именем `*.txt`. +- `ls file\?` — Найдет файл с именем `file?`. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Linux|00 Linux]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-14]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/linux/FirewallD.md b/dev/linux/FirewallD.md new file mode 100644 index 00000000..5d3bf20c --- /dev/null +++ b/dev/linux/FirewallD.md @@ -0,0 +1,56 @@ +--- +aliases: + - firewalld +tags: + - maturity/🌱 +date: + - - 2024-08-03 +--- +**Проверка статуса FirewallD** +- `firewall-cmd --state` – Проверить текущий статус FirewallD. +- `firewall-cmd --get-active-zones` – Показать активные зоны. +- `firewall-cmd --list-all` – Показать все правила для зоны по умолчанию. + +**Включение/Отключение FirewallD** +- `systemctl start firewalld` – Включить FirewallD. +- `systemctl stop firewalld` – Отключить FirewallD. +- `systemctl enable firewalld` – Включить автозапуск FirewallD при загрузке системы. +- `systemctl disable firewalld` – Отключить автозапуск FirewallD при загрузке системы. + +**Разрешение/Блокировка трафика** +- `firewall-cmd --add-port=/tcp` – Разрешить трафик на определенный порт (например, 22/tcp для SSH). +- `firewall-cmd --remove-port=/tcp` – Заблокировать трафик на определенный порт. +- `firewall-cmd --add-service=` – Разрешить трафик для определенного сервиса (например, 'http', 'https'). +- `firewall-cmd --remove-service=` – Заблокировать трафик для определенного сервиса. + +**Разрешение/Блокировка трафика с условиями** +- `firewall-cmd --add-rich-rule='rule family="ipv4" source address="" port port="" protocol="tcp" accept'` – Разрешить трафик от определенного IP и порта. +- `firewall-cmd --add-rich-rule='rule family="ipv4" source address="" port port="" protocol="tcp" reject'` – Заблокировать трафик от определенного IP и порта. + +**Удаление правил** +- `firewall-cmd --remove-port=/tcp` – Удалить правило разрешения для порта. +- `firewall-cmd --remove-service=` – Удалить правило разрешения для сервиса. +- `firewall-cmd --remove-rich-rule=''` – Удалить rich-rule правило. + +**Зоны и профили FirewallD** +- `firewall-cmd --get-zones` – Показать доступные зоны. +- `firewall-cmd --zone= --list-all` – Показать все правила для указанной зоны. +- `firewall-cmd --zone= --add-port=/tcp` – Добавить правило для конкретной зоны. + +**Логирование и мониторинг** +- `firewall-cmd --set-log-denied=all` – Включить логирование всех отклоненных подключений. +- `firewall-cmd --query-log-denied` – Проверить текущее состояние логирования отклоненных подключений. + +**Настройки по умолчанию** +- `firewall-cmd --set-default-zone=` – Установить зону по умолчанию для новых подключений. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Linux|00 Linux]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-08-03]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/linux/Logical Volume Management.md b/dev/linux/Logical Volume Management.md new file mode 100644 index 00000000..540c612d --- /dev/null +++ b/dev/linux/Logical Volume Management.md @@ -0,0 +1,34 @@ +--- +aliases: + - LVM +tags: + - maturity/🌱 +date: + - - 2024-01-09 +--- +- [[Основные команды для управления LVM|Основные команды для управления LVM]] + +Проверка состояния логических томов (LV) +```bash +sudo lvs -a -o +devices,lv_health_status +``` + +## Logical Volume + + +## Полезные материалы +- [Работа с LVM. Управление дисковыми носителями с помощью Logical Volume Manager](https://www.dmosk.ru/instruktions.php?object=lvm&ysclid=lr6peozovr651519872#delete) +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Linux|00 Linux]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: +### Дополнительные материалы +- +### Дочерние заметки + + +- [[Основные команды для управления LVM]] + diff --git a/dev/linux/Namespace.md b/dev/linux/Namespace.md new file mode 100644 index 00000000..084f46b6 --- /dev/null +++ b/dev/linux/Namespace.md @@ -0,0 +1,36 @@ +--- +aliases: +tags: + - maturity/🌱 +date: + - - 2024-03-20 +zero-link: + - "[[../../meta/zero/00 Linux|00 Linux]]" +parents: + - "[[Контейнерная виртуализация]]" +linked: +--- +Namespaces в Linux – это функция ядра, которая ограничивает видимость и доступность ресурсов процессам. Каждый namespace инкапсулирует определенный аспект системы, позволяя процессам работать в изолированной среде, как если бы они были единственными процессами в системе. + +Это ключевая технология для реализации контейнеров, таких как [[../../meta/zero/00 Docker|Docker]] и LXC, поскольку она позволяет каждому контейнеру иметь собственные сетевые интерфейсы, файловые системы, идентификаторы пользователей и процессов, не влияя на остальную часть системы. + +Linux поддерживает несколько типов namespaces: +1. **PID (Process ID) namespaces**: Изолируют пространство идентификаторов процессов. Это означает, что процессы в разных PID namespaces могут иметь одинаковые PID, но будут рассматриваться как разные процессы внутри их namespaces. +2. **Network namespaces**: Изолируют сетевые интерфейсы, таблицы маршрутизации, firewall правила, и прочие сетевые ресурсы. Это позволяет каждому namespace иметь собственный набор виртуальных сетевых интерфейсов и свою собственную сетевую конфигурацию. +3. **Mount namespaces**: Изолируют точки монтирования файловых систем. Это позволяет процессам в разных mount namespaces видеть разные файловые системы, что обеспечивает дополнительный уровень изоляции файлов и директорий. +4. **IPC (Inter-Process Communication) namespaces**: Изолируют IPC ресурсы, такие как очереди сообщений, разделяемые память и семафоры, позволяя процессам в разных IPC namespaces иметь раздельные IPC ресурсы. +5. **UTS (UNIX Time-sharing System) namespaces**: Позволяют иметь изолированные имена узлов и доменные имена. Это означает, что каждый UTS namespace может иметь свое собственное имя хоста и NIS доменное имя. +6. **User namespaces**: Изолируют идентификаторы пользователей и групп. В таком namespace, процесс может иметь привилегии root внутри namespace, не имея их за его пределами. + +Чтобы увидеть namespaces нужно в папке `/proc/*/ns` вызвать команду `sudo ls -la` +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Linux|00 Linux]] +**Родитель**:: [[Контейнерная виртуализация]] +**Источник**:: +**Автор**:: +**Создана**:: [[2024-03-20]] +### Дополнительные материалы +- [Разделяй и властвуй. Изоляция процессов в Linux / Хабр](https://habr.com/ru/companies/otus/articles/673960/) +### Дочерние заметки + diff --git a/dev/linux/Uncomplicated Firewall.md b/dev/linux/Uncomplicated Firewall.md new file mode 100644 index 00000000..bada9a19 --- /dev/null +++ b/dev/linux/Uncomplicated Firewall.md @@ -0,0 +1,60 @@ +--- +aliases: + - UWF +tags: + - maturity/🌱 +date: 2024-10-30 +--- +**Проверка статуса UFW** +- `ufw status` – Проверить статус UFW. +- `ufw status verbose` – Получить подробный статус с активными правилами. + +**Включение/Отключение UFW** +- `ufw enable` – Включить брандмауэр. +- `ufw disable` – Отключить брандмауэр. + +**Разрешение/Блокировка трафика** +- `ufw allow ` – Разрешить трафик на определенный порт (например, 22 для SSH). +- `ufw deny ` – Заблокировать трафик на определенный порт. +- `ufw allow from ` – Разрешить трафик от определенного IP-адреса. +- `ufw deny from ` – Заблокировать трафик от определенного IP-адреса. +- `ufw allow ` – Разрешить трафик для определенного сервиса (например, 'http', 'https'). +- `ufw deny ` – Заблокировать трафик для определенного сервиса. + +**Разрешение/Блокировка трафика с условиями** +- `ufw allow proto from to port ` – Разрешить трафик с определенным протоколом, IP-адресами и портом. +- `ufw deny proto from to port ` – Заблокировать трафик с определенным протоколом, IP-адресами и портом. + +**Удаление правил** +- `ufw delete allow ` – Удалить правило разрешения для порта. +- `ufw delete deny ` – Удалить правило блокировки для порта. +- `ufw delete allow from ` – Удалить правило разрешения для IP-адреса. +- `ufw delete deny from ` – Удалить правило блокировки для IP-адреса. + + +**Профили и приложения UFW** +- `ufw app list` – Список доступных профилей приложений. +- e`ufw app info ` – Получить подробную информацию о профиле приложения. +- `ufw app update ` – Обновить правила профиля приложения. + +**Логирование и мониторинг** +- `ufw logging on` – Включить логирование UFW. +- `ufw logging off` – Отключить логирование UFW. +- `ufw logging ` – Установить уровень логирования (например, 'low', 'medium', 'high', 'full'). + +**Настройки UFW по умолчанию** +- `ufw default deny incoming` – Заблокировать входящие подключения по умолчанию. +- `ufw default allow outgoing` – Разрешить исходящие подключения по умолчанию. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Linux|00 Linux]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-10-30]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/linux/centos/Настройка прокси на CentOS 7 и 8.md b/dev/linux/centos/Настройка прокси на CentOS 7 и 8.md new file mode 100644 index 00000000..c4c532ff --- /dev/null +++ b/dev/linux/centos/Настройка прокси на CentOS 7 и 8.md @@ -0,0 +1,117 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-09-08 +zero-link: + - "[[../../../meta/zero/00 Linux|00 Linux]]" +parents: +linked: +--- +Ремарка, которую можно пропустить: Помню свой первый день на работе, тогда мне поручили настраивать сервер на CentOS 7. Установить необходимые пакеты, уже не помню точно что, но не суть. Я тогда еще обладатель ПК на windows погуглил и нашел команду `yum install pack_name`. + +И как же я был удивлен, когда это не сработало. Корпоративные сервера чаще всего находятся в изоляции от интернета, и для доступа необходимо настраивать прокси. Но я тогда не знал об этом, и устанавливал пакеты вручную, скачивая их сначала к себе и перенося на сервер, то еще занятие, на это ушел целый день 😄 + +Потом я узнал о существовании прокси, которое открывало доступ в интернет. Сейчас расскажу, как его настроить. + +Особенность использования прокси в том, что его надо настраивать везде. Недостаточно настроить только на уровне ОС, надо также настроить на уровне каждого приложения, даже у пакетного менеджера типа `yum` и `dnf`, нужно указать прокси. +## Настройка для ОС +Первым делом настраиваем прокси на linux машине. Для этого нужно установить значения для некоторых переменных среды. + +Если прокси без пароля: + +```shell +export http_proxy="http://SERVER:PORT/" +export https_proxy="http://SERVER:PORT/" +export no_proxy="127.0.0.1,localhost" +export HTTP_PROXY="http://SERVER:PORT/" +export HTTPS_PROXY="http://SERVER:PORT/" +export NO_PROXY="127.0.0.1,localhost" +``` + +Если у вас есть логин и пароль: + +```shell +export http_proxy="http://USERNAME:PASSWORD@SERVER:PORT/" +export https_proxy="http://USERNAME:PASSWORD@SERVER:PORT/" +export no_proxy="127.0.0.1,localhost" +export HTTP_PROXY="http://USERNAME:PASSWORD@SERVER:PORT/" +export HTTPS_PROXY="http://USERNAME:PASSWORD@SERVER:PORT/" +export NO_PROXY="127.0.0.1,localhost" +``` + +> [!WARNING] +> Если в имени пользователя или пароле используется символ `@`, добавьте обратную косую черту (`\`) перед `@`. + + +Данным способом мы установили временное прокси, ==после перезагрузки подключение пропадет.== Чтобы добавить постоянное прокси, нужно изменить файл `/etc/environment`. + +Если вам повезло и редактор nano был предустановлен, то воспользуйтесь им, добавив следующие строчки: + +```shell +sudo nano /etc/environment + +export http_proxy="http://USERNAME:PASSWORD@SERVER:PORT/" +export https_proxy="http://USERNAME:PASSWORD@SERVER:PORT/" +export no_proxy="127.0.0.1,localhost" +export HTTP_PROXY="http://USERNAME:PASSWORD@SERVER:PORT/" +export HTTPS_PROXY="http://USERNAME:PASSWORD@SERVER:PORT/" +export NO_PROXY="127.0.0.1,localhost" +``` + +Если повезло чуть меньше, и установлен только редактор vi. Инструкция будет чуть сложнее, сначала открываем файл в редакторе: + +```shell +sudo vi /etc/environment +``` + +Далее необходимо нажать клавишу i, чтобы войти в режим редактирования, после вставляем наши заветные строчки: + +```shell +export http_proxy="http://USERNAME:PASSWORD@SERVER:PORT/" +export https_proxy="http://USERNAME:PASSWORD@SERVER:PORT/" +export no_proxy="127.0.0.1,localhost" +export HTTP_PROXY="http://USERNAME:PASSWORD@SERVER:PORT/" +export HTTPS_PROXY="http://USERNAME:PASSWORD@SERVER:PORT/" +export NO_PROXY="127.0.0.1,localhost" +``` + +Чтобы сохранинть изменения санчала нажмите `ESC`, а далее наберите `:wq`, чтобы выйти без сохранения нажмите `ESC` и наберите просто `:q` + +Если вам совсем не повезло, и по какой-то причине редакторов совсем не предустановлено, то воспользуйтесь следующей командой: + +```shell +sudo cat >> /etc/environment << EOFXX +export http_proxy="http://USERNAME:PASSWORD@SERVER:PORT/" +export https_proxy="http://USERNAME:PASSWORD@SERVER:PORT/" +export no_proxy="127.0.0.1,localhost" +export HTTP_PROXY="http://USERNAME:PASSWORD@SERVER:PORT/" +export HTTPS_PROXY="http://USERNAME:PASSWORD@SERVER:PORT/" +export NO_PROXY="127.0.0.1,localhost" +EOFXX +``` +## Настройка для пакетных менеджеров +Теперь настроим прокси для пакетных менеджеров `yum` и `dnf`. Для этого отредактируем файл `/etc/yum.conf`, добавив в конец следующие строки: + +```toml +proxy=http://SERVER:PORT +``` + +Для авторизации укажите также следующие строки: + +```toml +proxy_username=USERNAME +proxy_password=PASS +proxy_auth_method=basic +``` +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 Linux|00 Linux]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-09-08]] +### Дополнительные материалы +- +### Дочерние заметки + diff --git a/dev/linux/iptables.md b/dev/linux/iptables.md new file mode 100644 index 00000000..af843c3e --- /dev/null +++ b/dev/linux/iptables.md @@ -0,0 +1,64 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-11-03 +--- + +**Проверка правил** +- `iptables -L` — Показать все правила. +- `iptables -L -v -n` — Показать правила с подробной информацией и числовыми адресами. +- `iptables -S` — Показать все правила в формате, который можно использовать повторно. + +**Очистка правил** +- `iptables -F` — Очистить все правила во всех цепочках. +- `iptables -X` — Удалить все пользовательские цепочки. +- `iptables -Z` — Обнулить счетчики пакетов и байтов. + +**Установка политики по умолчанию** +- `iptables -P INPUT ACCEPT` — Установить политику по умолчанию для цепочки INPUT. +- `iptables -P FORWARD ACCEPT` — Установить политику по умолчанию для цепочки FORWARD. +- `iptables -P OUTPUT ACCEPT` — Установить политику по умолчанию для цепочки OUTPUT. + +**Разрешение и запрет трафика** +- `iptables -A INPUT -p tcp --dport <порт> -j ACCEPT` — Разрешить входящий трафик на определенный порт. +- `iptables -A INPUT -s -j ACCEPT` — Разрешить трафик с определенного IP-адреса +- `iptables -A INPUT -p tcp --dport <порт> -j DROP` — Запретить входящий трафик на определенный порт. +- `iptables -A INPUT -s -j DROP` — Запретить трафик с определенного IP-адреса. + +**Условные разрешения и запреты трафика** +- `iptables -A INPUT -p tcp -s --dport <порт> -j ACCEPT` — Разрешить трафик с IP на конкретный порт. +- `iptables -A INPUT -p tcp -s --dport <порт> -j DROP` — Запретить трафик с IP на конкретный порт. + +**Удаление правил** +- `iptables -D INPUT <номер-правила>` — Удалить правило по его номеру. +- `iptables -D INPUT -p tcp --dport <порт> -j ACCEPT` — Удалить конкретное правило. + +**Работа с цепочками** +- `iptables -N <имя-цепочки>` — Создать новую цепочку. +- `iptables -X <имя-цепочки>` — Удалить пользовательскую цепочку. +- `iptables -A INPUT -j <имя-цепочки>` — Переход к пользовательской цепочке. + +**NAT и перенаправление портов** +- `iptables -t nat -A POSTROUTING -o <интерфейс> -j MASQUERADE` — Включить NAT на интерфейсе. +- `iptables -t nat -A PREROUTING -p tcp --dport <порт> -j DNAT --to-destination :<порт>` — Перенаправление трафика с одного порта на другой. + +**Сохранение и восстановление правил** +- `iptables-save > /etc/iptables/rules.v4` — Сохранить правила IPv4 в файл. +- `iptables-restore < /etc/iptables/rules.v4` — Восстановить правила IPv4 из файла. + +**Логирование** +- `iptables -A INPUT -p tcp --dport <порт> -j LOG --log-prefix "IPTables-Dropped: " --log-level 4` — Логировать сброшенные пакеты. +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Linux|00 Linux]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-03]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + diff --git a/dev/linux/rhel/Установка утилиты mozjpeg на RHEL.md b/dev/linux/rhel/Установка утилиты mozjpeg на RHEL.md new file mode 100644 index 00000000..0df2ccf3 --- /dev/null +++ b/dev/linux/rhel/Установка утилиты mozjpeg на RHEL.md @@ -0,0 +1,126 @@ +--- +aliases: +tags: + - maturity/🌱 + - "#content/problem" +date: 2024-09-25 +zero-link: + - "[[00 Разработка]]" +parents: +linked: +--- +mozjpeg не устанавливается из обычных пакетных менеджеров для RHEL, его необходимо собирать вручную. + +**Mozjpeg** использует **CMake** для сборки. Установим необходимые утилиты +```shell +sudo yum install cmake nasm make gcc git +``` + +Склонируем репозиторий: +```shell +git clone https://github.com/mozilla/mozjpeg.git +``` + +Соберем и установим **mozjpeg** +```shell +cd mozjpeg +mkdir build && cd build +cmake -G"Unix Makefiles" .. +make +sudo make install +``` + + +> [!INFO] Путь установки +> По умолчанию **mozjpeg** устанавливается в каталог /opt/mozjpeg. + +Добавим mozjpeg в PATH +```shell +export PATH=/opt/mozjpeg/bin:$PATH +``` + +Проверим, что все установилось успешно +```shell +cjpeg -version +``` +## Проблема при установке +Во время запуска cmake я получил следующую проблему. + +```shell +$ cmake -G"Unix Makefiles" .. + +.... + +-- Found ZLIB: /usr/lib64/libz.so (found version "1.2.11") +-- Found PNG: /usr/lib64/libpng.so (found suitable version "1.6.37", minimum required is "1.6") +-- PNG reading support enabled (PNG_SUPPORTED = 1) +-- Could NOT find ZLIB (missing: ZLIB_LIBRARY) (found version "1.2.11") +CMake Error at /usr/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:230 (message): + Could NOT find PNG (missing: PNG_LIBRARY) (Required is at least version + "1.6") +Call Stack (most recent call first): + /usr/share/cmake/Modules/FindPackageHandleStandardArgs.cmake:600 (_FPHSA_FAILURE_MESSAGE) + /usr/share/cmake/Modules/FindPNG.cmake:159 (find_package_handle_standard_args) + CMakeLists.txt:778 (find_package) + + +-- Configuring incomplete, errors occurred! +``` + +Проблема связана с отсутствием необходимых библиотек разработки для **zlib** и **libpng**. Хотя из вывода **CMake** видно, что сначала он находит библиотеки **ZLIB** и **PNG**: + +```shell +-- Found ZLIB: /usr/lib64/libz.so (found version "1.2.11") +-- Found PNG: /usr/lib64/libpng.so (found suitable version "1.6.37", minimum required is "1.6") +``` + +Я попытался установить нужные пакеты, но они уже были установлены. +```shell +sudo yum install zlib-devel libpng-devel +``` + +Я проверил наличие библиотек и заголовочных файлов. Они также были на месте. +```shell +ls /usr/lib64/libz.* +ls /usr/lib64/libpng.* +ls /usr/include/zlib.h +ls /usr/include/png.h +``` + +Я попробовал установить **pkg-config**, который помогает **CMake** находить пути к библиотекам и заголовочным файлам. И проверил, что **pkg-config** возвращает пути к библиотекам. + +```shell +sudo yum install pkgconfig +pkg-config --libs zlib +pkg-config --libs libpng +``` + +Я пытался использовать cmake3 указывая пути до библиотек +```shell +cmake3 -G"Unix Makefiles" \ + -DZLIB_LIBRARIES=/usr/lib64/libz.so \ + -DZLIB_INCLUDE_DIR=/usr/include \ + -DPNG_LIBRARY=/usr/lib64/libpng.so \ + -DPNG_PNG_INCLUDE_DIR=/usr/include \ + .. +``` + +В итоге я решил просто отключить поддержку PNG для mozjpeg, раз с ней возникают проблемы, так как я планирую использовать mozjpeg только для сжатия jpeg файлов. + +```shell +cmake -G"Unix Makefiles" -DPNG_SUPPORTED=OFF .. +``` + +И это в итоге помогло. +*** +## Мета информация +**Область**:: [[../../../meta/zero/00 Разработка|00 Разработка]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-09-25]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + diff --git a/dev/linux/Виртуализация серверов.md b/dev/linux/Виртуализация серверов.md new file mode 100644 index 00000000..d9bcdc2b --- /dev/null +++ b/dev/linux/Виртуализация серверов.md @@ -0,0 +1,36 @@ +--- +aliases: + - виртуализации серверов +tags: + - maturity/🌱 +date: + - - 2024-03-20 +zero-link: + - "[[../../meta/zero/00 Linux|00 Linux]]" +parents: +linked: +--- +Виртуализация — это технология создания виртуальных (а не физических) версий серверов. Она позволяет разделять физические ресурсы компьютера на несколько виртуальных сред, каждая из которых может использовать и управлять ресурсами как независимый компьютер. + +Типы виртуализаций: +- [Контейнерная виртуализация](Контейнерная%20виртуализация.md) +- [Гипервизор](../../../../_inbox/Гипервизор.md) + +Виртуализация помогает увеличить эффективность использования ресурсов, упрощает управление ИТ-инфраструктурой, повышает гибкость и масштабируемость систем, а также улучшает безопасность и изоляцию приложений. + +![](../../meta/files/images/Pasted%20image%2020240320133203.png) +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Linux|00 Linux]] +**Родитель**:: +**Источник**:: +**Автор**:: +**Создана**:: [[2024-03-20]] +### Дополнительные материалы +- +### Дочерние заметки + + +- [[Гипервизор]] +- [[Контейнерная виртуализация]] + diff --git a/dev/linux/Диагностика Linux.md b/dev/linux/Диагностика Linux.md new file mode 100644 index 00000000..bf850298 --- /dev/null +++ b/dev/linux/Диагностика Linux.md @@ -0,0 +1,62 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-11-24 +--- +Linux предоставляет широкий спектр утилит для мониторинга системы, отладки и устранения неисправностей. Эти инструменты могут помочь в диагностике проблем с процессами, памятью, сетью и другими аспектами системы. Рассмотрим основные категории утилит, которые часто используются для отладки. + +- [[Проверка свободного места на дисках]] +## Мониторинг процессов и системы +- **top** и **htop**: отображают информацию о текущем использовании системных ресурсов в реальном времени, включая процессы, загрузку ЦП и память. +- **ps aux**: выводит список всех запущенных процессов с подробной информацией. +- **lsof**: отображает открытые файлы и процессы, которые их используют. +- **strace** и **ltrace**: позволяют отслеживать системные вызовы и сигналы для процесса. +- **vmstat**: предоставляет информацию о виртуальной памяти и процессах. +- **iostat**: выводит статистику ввода/вывода по устройствам. +## Отладка аварийных завершений и дампов памяти +- **dmesg**: выводит сообщения из буфера ядра, полезно для диагностики аппаратных проблем. +- **journalctl**: позволяет просматривать системные логи, включая сообщения ядра и системных служб. +- **gdb**: отладчик, позволяющий анализировать дампы памяти и выполнять отладку приложений. +## Сетевая отладка +- **ping** и [[../../../../knowledge/dev/network/Анализ маршрута до интернет ресурса|traceroute]]: позволяют проверять доступность хостов и отслеживать маршрут до них. +- **mtr**: комбинирует возможности ping и [[../../../../knowledge/dev/network/Анализ маршрута до интернет ресурса|traceroute]] для непрерывной диагностики сети. +- **netstat** (или **ss**): выводит информацию об открытых портах и активных соединениях. +- **tcpdump**: захватывает и отображает сетевые пакеты для анализа. +- **nmap**: инструмент для сканирования сети и оценки безопасности. +- **ip addr show**: отображает все сетевые интерфейсы и их IP-адреса. +## Отладка файлов и дисков +- **fsck**: проверяет и исправляет ошибки файловой системы. +- [[Диагностика HDD c использованием S.M.A.R.T.|smartctl]]: выводит информацию о состоянии жестких дисков, используя данные S.M.A.R.T. +- **badblocks**: ищет поврежденные блоки на диске. +- **df** и [[Проверка свободного места на дисках|du]]: отображают информацию о дисковом пространстве в системе. +- **lsblk**: выводит информацию об устройствах хранения и их разделах. +- **mount** и **umount**: позволяют подключать и отключать файловые системы. +## Мониторинг системных ресурсов +- **sar**: собирает и сохраняет информацию о системной активности. +- **free**: выводит информацию о доступной и использованной памяти. +- **iostat** и **mpstat**: показывают статистику ввода/вывода и процессорной активности. +- **pidstat**: предоставляет статистику по процессам. +## Отладка ядра и модулей +- **uname**: выводит информацию о ядре и версии операционной системы. +- **lsmod**: отображает загруженные модули ядра. +- **modinfo**: выводит подробную информацию о модулях ядра. +- **dmesg | grep \**: помогает находить сообщения ядра, связанные с определенным модулем. + + +*** +## Мета информация +**Область**:: [[../../meta/zero/00 Linux|00 Linux]] +**Родитель**:: +**Источник**:: +**Создана**:: [[2024-11-24]] +**Автор**:: +### Дополнительные материалы +- + +### Дочерние заметки + + +- [[Проверка свободного места на дисках]] + + diff --git a/dev/linux/Команды управления диском в Linux.md b/dev/linux/Команды управления диском в Linux.md new file mode 100644 index 00000000..a584248a --- /dev/null +++ b/dev/linux/Команды управления диском в Linux.md @@ -0,0 +1,63 @@ +--- +aliases: +tags: + - maturity/🌱 +date: 2024-11-24 +--- +## Просмотр информации о дисках +- `lsblk` - Список блочных устройств (диски и разделы). +- `fdisk -l` - Показать таблицу разделов и информацию о диске. +- `blkid` - Показать атрибуты блочного устройства (UUID, файловые системы). +- `df -h` - Показать использование дискового пространства в удобочитаемом формате. +- `du -sh ` - Суммировать использование пространства директорией. +## Разделение дисков +- `fdisk ` - Интерактивный инструмент для разделения диска. +- `parted ` - Создание, изменение и управление разделами на диске. +- `cfdisk ` - Инструмент с текстовым интерфейсом для манипуляции разделами. +- `gdisk ` - Редактор таблицы разделов GPT. +## Управление файловыми системами +- `mkfs.ext4 ` - Создать файловую систему ext4 на разделе. +- `mkfs.xfs ` - Создать файловую систему XFS на разделе. +- `mkfs.vfat ` - Создать файловую систему FAT32 на разделе. +- `mkfs.ntfs ` - Создать файловую систему NTFS на разделе. +- `tune2fs -L