🧮 Индексация 🧮
Следующим пунктом в нашем списке по физическому проектированию идет индексация. Для начала разберемся с этим понятием.
Индексирование — это процесс создания специальных структур данных, называемых индексами, которые позволяют быстро находить нужные данные среди большого объема информации. Индексация широко используется в базах данных, поисковых системах, файловых менеджерах и многих других приложениях, где требуется быстрое извлечение конкретных записей.
🖍Когда нужна индексация?
Индексация необходима в случаях, когда требуется ускорить операции выборки данных. Основные ситуации, когда целесообразно применять индексацию:
📥 Частые запросы
Если часто выполняются запросы на чтение данных (например, SELECT-запросы), особенно если они фильтруют большие объемы данных.
📥 Запросы с условиями
Запросы, содержащие условия WHERE, ORDER BY, GROUP BY и JOIN, значительно ускоряются благодаря наличию соответствующих индексов.
📥 Операции чтения важнее операций записи
Индексы замедляют операции вставки, обновления и удаления данных, поскольку каждый раз нужно обновлять сами индексы. Поэтому индексация выгодна там, где преобладают операции чтения над операциями изменения данных.
🔎 Какие бывают индексы?
Существует несколько типов индексов, каждый из которых оптимизирован под разные сценарии использования
🔗 B-Tree (B-дерево)
Самый распространенный вид индекса. Используется в большинстве реляционных СУБД (PostgreSQL, MySQL, SQLite). B-Tree позволяет эффективно искать значения по диапазону, сортировать и объединять таблицы.
Преимущества
Эффективная поддержка операторов сравнения (<, >, =).
Позволяет сортировку результатов по заданному полю.
Недостатки
Больший объем памяти для хранения больших объемов данных.
🔗 Hash-индексы
Hash-индексы используются, когда важно исключительно точное совпадение значений (оператор равенства "="). Они быстрее работают с поиском конкретного значения, но не поддерживают диапазон запросов или сортировки.
Преимущества
Очень быстрый доступ по ключу (равенство).
Недостатки
Невозможность эффективного использования с операторами "<", ">", BETWEEN и подобными.
🔗 Bitmap-индексы
Используются в основном для столбцов с небольшим числом уникальных значений ("низкой селективностью"). Например, такие поля, как пол, статус заказа, страна проживания. Отличаются компактностью и скоростью обработки логических условий.
Преимущества
Компактность и высокая производительность для низкоселективных полей.
Недостатки
Медленно работает с высокоселективными данными.
🔗 Full-text-индексы
Предназначены для полнотекстового поиска, позволяют выполнять поиск по содержимому текста (частей документов, статей и т.п.). Часто применяются в информационных порталах, блогах, поисковиках.
Преимущества
Поддержка сложных операций поиска по словам и фразам.
Недостатки
Сложнее поддерживать и занимают больше места.
❓Как принимать решение о необходимости индексирования?
*️⃣ Типичные запросы
Проведите профилирование ваших приложений и проанализируйте наиболее частые типы запросов. Индексировать имеет смысл именно те поля, которые участвуют в условиях WHERE, ORDER BY, GROUP BY и JOIN.
*️⃣ Анализ производительности
Используйте инструменты анализа запросов вашей базы данных (EXPLAIN ANALYZE в PostgreSQL, EXPLAIN в MySQL и др.) для оценки эффективности существующих планов выполнения запросов. Если запрос долго выполняется, возможно, дело в отсутствии нужного индекса.
*️⃣ Объем данных
Чем больше таблица, тем сильнее ощущается эффект от добавления индекса. Для небольших таблиц индексирование может оказаться избыточным и неоптимальным решением.
*️⃣ Частота изменений
Если ваши данные часто меняются (INSERT/UPDATE/DELETE), убедитесь, что выгода от индекса превышает затраты на обновление самого индекса.
Критерии выбора типа индекса
Важно правильно выбрать тип индекса исходя из особенностей вашего приложения и структуры данных. Например, если важна скорость точного поиска, выбирайте hash-индекс, если важны диапазонные запросы — b-tree, если нужны быстрые операции по низким селективностям — bitmap.
Следующим пунктом в нашем списке по физическому проектированию идет индексация. Для начала разберемся с этим понятием.
Индексирование — это процесс создания специальных структур данных, называемых индексами, которые позволяют быстро находить нужные данные среди большого объема информации. Индексация широко используется в базах данных, поисковых системах, файловых менеджерах и многих других приложениях, где требуется быстрое извлечение конкретных записей.
🖍Когда нужна индексация?
Индексация необходима в случаях, когда требуется ускорить операции выборки данных. Основные ситуации, когда целесообразно применять индексацию:
📥 Частые запросы
Если часто выполняются запросы на чтение данных (например, SELECT-запросы), особенно если они фильтруют большие объемы данных.
📥 Запросы с условиями
Запросы, содержащие условия WHERE, ORDER BY, GROUP BY и JOIN, значительно ускоряются благодаря наличию соответствующих индексов.
📥 Операции чтения важнее операций записи
Индексы замедляют операции вставки, обновления и удаления данных, поскольку каждый раз нужно обновлять сами индексы. Поэтому индексация выгодна там, где преобладают операции чтения над операциями изменения данных.
🔎 Какие бывают индексы?
Существует несколько типов индексов, каждый из которых оптимизирован под разные сценарии использования
🔗 B-Tree (B-дерево)
Самый распространенный вид индекса. Используется в большинстве реляционных СУБД (PostgreSQL, MySQL, SQLite). B-Tree позволяет эффективно искать значения по диапазону, сортировать и объединять таблицы.
Преимущества
Эффективная поддержка операторов сравнения (<, >, =).
Позволяет сортировку результатов по заданному полю.
Недостатки
Больший объем памяти для хранения больших объемов данных.
🔗 Hash-индексы
Hash-индексы используются, когда важно исключительно точное совпадение значений (оператор равенства "="). Они быстрее работают с поиском конкретного значения, но не поддерживают диапазон запросов или сортировки.
Преимущества
Очень быстрый доступ по ключу (равенство).
Недостатки
Невозможность эффективного использования с операторами "<", ">", BETWEEN и подобными.
🔗 Bitmap-индексы
Используются в основном для столбцов с небольшим числом уникальных значений ("низкой селективностью"). Например, такие поля, как пол, статус заказа, страна проживания. Отличаются компактностью и скоростью обработки логических условий.
Преимущества
Компактность и высокая производительность для низкоселективных полей.
Недостатки
Медленно работает с высокоселективными данными.
🔗 Full-text-индексы
Предназначены для полнотекстового поиска, позволяют выполнять поиск по содержимому текста (частей документов, статей и т.п.). Часто применяются в информационных порталах, блогах, поисковиках.
Преимущества
Поддержка сложных операций поиска по словам и фразам.
Недостатки
Сложнее поддерживать и занимают больше места.
❓Как принимать решение о необходимости индексирования?
*️⃣ Типичные запросы
Проведите профилирование ваших приложений и проанализируйте наиболее частые типы запросов. Индексировать имеет смысл именно те поля, которые участвуют в условиях WHERE, ORDER BY, GROUP BY и JOIN.
*️⃣ Анализ производительности
Используйте инструменты анализа запросов вашей базы данных (EXPLAIN ANALYZE в PostgreSQL, EXPLAIN в MySQL и др.) для оценки эффективности существующих планов выполнения запросов. Если запрос долго выполняется, возможно, дело в отсутствии нужного индекса.
*️⃣ Объем данных
Чем больше таблица, тем сильнее ощущается эффект от добавления индекса. Для небольших таблиц индексирование может оказаться избыточным и неоптимальным решением.
*️⃣ Частота изменений
Если ваши данные часто меняются (INSERT/UPDATE/DELETE), убедитесь, что выгода от индекса превышает затраты на обновление самого индекса.
Критерии выбора типа индекса
Важно правильно выбрать тип индекса исходя из особенностей вашего приложения и структуры данных. Например, если важна скорость точного поиска, выбирайте hash-индекс, если важны диапазонные запросы — b-tree, если нужны быстрые операции по низким селективностям — bitmap.
❤1
🔔 Критерии оценки потребности в индексе
♦️Затраты на поддержку индекса
Оценивайте нагрузку на систему от поддержания индекса. Чрезмерное количество индексов приведет к увеличению нагрузки на сервер при операциях INSERT/UPDATE/DELETE.
♦️ Выбор подходящего типа индекса
Убедитесь, что выбран правильный тип индекса, соответствующий вашим требованиям и типу запросов.
♦️ Оценка селективности
Селективность — доля строк, удовлетворяющих условию фильтра. Низкая селективность предполагает создание специфичных индексов вроде bitmap.
♦️ Производительность системы
Анализируйте метрики производительности (время отклика, использование CPU, RAM и I/O), чтобы оценить реальную пользу от новых индексов.
♦️ Тестирование на реальных нагрузках
Всегда проверяйте эффективность индексов на реальных рабочих сценариях, используя реплики продакшн-данных.
Таким образом, правильная стратегия индексирования должна балансировать между производительностью чтения и затратами на обслуживание индексов.
♦️Затраты на поддержку индекса
Оценивайте нагрузку на систему от поддержания индекса. Чрезмерное количество индексов приведет к увеличению нагрузки на сервер при операциях INSERT/UPDATE/DELETE.
♦️ Выбор подходящего типа индекса
Убедитесь, что выбран правильный тип индекса, соответствующий вашим требованиям и типу запросов.
♦️ Оценка селективности
Селективность — доля строк, удовлетворяющих условию фильтра. Низкая селективность предполагает создание специфичных индексов вроде bitmap.
♦️ Производительность системы
Анализируйте метрики производительности (время отклика, использование CPU, RAM и I/O), чтобы оценить реальную пользу от новых индексов.
♦️ Тестирование на реальных нагрузках
Всегда проверяйте эффективность индексов на реальных рабочих сценариях, используя реплики продакшн-данных.
Таким образом, правильная стратегия индексирования должна балансировать между производительностью чтения и затратами на обслуживание индексов.
❤1
❓Много столбцов или много таблиц с отношением 1-to-1
Меня давно волнует этот вопрос. И вот в очередной раз, когда я им задалась, я решила поставить точку и докопаться до истины. К чему я пришла, сейчас расскажу.
🌀 Один большой набор столбцов в одной таблице
➕Плюсы
1. Простота модели: Всё находится в одном месте, проще понимать структуру данных и писать запросы.
2. Быстрота исполнения SELECT'ов: Поскольку вся необходимая информация хранится в одной таблице, не нужно соединять таблицы (JOIN), что повышает скорость выборок.
3. Отсутствие дополнительного уровня сложности: Меньше технических деталей вроде внешнего ключа и ограничения целостности, меньше шансов допустить ошибку.
➖ Минусы
1. Проблемы с пустыми значениями: Если большинство столбцов редко используются (они часто пусты), увеличивается размер строки и неэффективность хранения данных.
2. Ухудшение производительности UPDATE и INSERT: Операции изменения данных становятся тяжелее, поскольку затрагивается больше столбцов даже при изменении одного значения.
3. Потеря контроля над целостностью данных: Нет чёткого разделения между обязательной информацией и дополнительными деталями.
🔱 Несколько связанных таблиц с отношением one-to-one
➕ Плюсы
1. Модульность и разделение обязанностей: Структура становится чище и понятнее, легко добавлять новые сущности или удалять ненужные.
2. Эффективность хранения: Вы можете сохранить минималистичный дизайн главной таблицы, уменьшив объём памяти для хранения редко используемых данных.
3. Контроль целостности: Легче контролировать наличие обязательных данных и предотвращать ввод лишней информации.
4. Производительность при изменениях: Изменяя одну таблицу, мы не трогаем другие, что ускоряет операции обновления и вставки данных.
➖ Минусы
1. Необходимость JOIN'ов: Каждый раз, когда нужно собрать всю информацию вместе, приходится объединять таблицы, что немного усложняет запросы и может снизить производительность.
2. Дополнительная сложность модели: Больше таблиц и внешних ключей увеличивают сложность схемы и повышают вероятность ошибок при разработке.
⁉️Так что в итоге? Когда что использовать?
Один большой набор столбцов
Подход хорош, если:
- Таблица маленькая и проста в управлении.
- Все столбцы активно используются.
- Требуется максимальная простота реализации и минимальное число соединений.
🆚
Несколько связанных таблиц (отношения one-to-one)
Лучше применять, если:
- Часть данных используется редко или вовсе необязательна.
- Есть необходимость чётко разделять разные виды данных (например, персональные данные и служебные характеристики).
- Нужно обеспечить высокий уровень производительности при изменениях данных.
Меня давно волнует этот вопрос. И вот в очередной раз, когда я им задалась, я решила поставить точку и докопаться до истины. К чему я пришла, сейчас расскажу.
🌀 Один большой набор столбцов в одной таблице
➕Плюсы
1. Простота модели: Всё находится в одном месте, проще понимать структуру данных и писать запросы.
2. Быстрота исполнения SELECT'ов: Поскольку вся необходимая информация хранится в одной таблице, не нужно соединять таблицы (JOIN), что повышает скорость выборок.
3. Отсутствие дополнительного уровня сложности: Меньше технических деталей вроде внешнего ключа и ограничения целостности, меньше шансов допустить ошибку.
➖ Минусы
1. Проблемы с пустыми значениями: Если большинство столбцов редко используются (они часто пусты), увеличивается размер строки и неэффективность хранения данных.
2. Ухудшение производительности UPDATE и INSERT: Операции изменения данных становятся тяжелее, поскольку затрагивается больше столбцов даже при изменении одного значения.
3. Потеря контроля над целостностью данных: Нет чёткого разделения между обязательной информацией и дополнительными деталями.
🔱 Несколько связанных таблиц с отношением one-to-one
➕ Плюсы
1. Модульность и разделение обязанностей: Структура становится чище и понятнее, легко добавлять новые сущности или удалять ненужные.
2. Эффективность хранения: Вы можете сохранить минималистичный дизайн главной таблицы, уменьшив объём памяти для хранения редко используемых данных.
3. Контроль целостности: Легче контролировать наличие обязательных данных и предотвращать ввод лишней информации.
4. Производительность при изменениях: Изменяя одну таблицу, мы не трогаем другие, что ускоряет операции обновления и вставки данных.
➖ Минусы
1. Необходимость JOIN'ов: Каждый раз, когда нужно собрать всю информацию вместе, приходится объединять таблицы, что немного усложняет запросы и может снизить производительность.
2. Дополнительная сложность модели: Больше таблиц и внешних ключей увеличивают сложность схемы и повышают вероятность ошибок при разработке.
⁉️Так что в итоге? Когда что использовать?
Один большой набор столбцов
Подход хорош, если:
- Таблица маленькая и проста в управлении.
- Все столбцы активно используются.
- Требуется максимальная простота реализации и минимальное число соединений.
🆚
Несколько связанных таблиц (отношения one-to-one)
Лучше применять, если:
- Часть данных используется редко или вовсе необязательна.
- Есть необходимость чётко разделять разные виды данных (например, персональные данные и служебные характеристики).
- Нужно обеспечить высокий уровень производительности при изменениях данных.
❤1
После разбора индексов можно переходить к корректному обеспечению бизнес-логики. Для этого есть 2 типа методов в СУБД, шпаргалку с которыми я представила ниже.
🖍 Триггер
Триггер — это специальная программа или набор инструкций, автоматически выполняемых базой данных при наступлении определённого события. Например, такие события включают вставку новой записи (INSERT), обновление существующей записи (UPDATE) или удаление записи (DELETE).
Примеры случаев использования триггеров
1. Автоматическое создание журнала аудита: каждый раз, когда изменяется запись в таблице, триггер записывает изменения в специальную таблицу для отслеживания истории изменений.
2. Обеспечение целостности данных: автоматическая проверка условий перед изменением записей, предотвращение некорректных значений.
🖍 Хранимая процедура
Хранимая процедура — это заранее подготовленный блок SQL-кода, хранящийся внутри базы данных и доступный для многократного вызова различными приложениями. Процедуры часто используются для реализации сложных бизнес-правил, обработки транзакций или улучшения производительности путем оптимизации запросов.
Примеры случаев использования хранимых процедур
1. Выполнение сложной логики обработки данных: расчет зарплаты сотрудников с учётом премий, налогов и прочих факторов.
2. Оптимизация производительности путём объединения нескольких операций в одну процедуру: выполнение множества действий одновременно (например, массовое обновление/добавление данных).
Ниже наглядная таблица, иллюстрирующая разницу между этими понятиями
🖍 Триггер
Триггер — это специальная программа или набор инструкций, автоматически выполняемых базой данных при наступлении определённого события. Например, такие события включают вставку новой записи (INSERT), обновление существующей записи (UPDATE) или удаление записи (DELETE).
Примеры случаев использования триггеров
1. Автоматическое создание журнала аудита: каждый раз, когда изменяется запись в таблице, триггер записывает изменения в специальную таблицу для отслеживания истории изменений.
2. Обеспечение целостности данных: автоматическая проверка условий перед изменением записей, предотвращение некорректных значений.
🖍 Хранимая процедура
Хранимая процедура — это заранее подготовленный блок SQL-кода, хранящийся внутри базы данных и доступный для многократного вызова различными приложениями. Процедуры часто используются для реализации сложных бизнес-правил, обработки транзакций или улучшения производительности путем оптимизации запросов.
Примеры случаев использования хранимых процедур
1. Выполнение сложной логики обработки данных: расчет зарплаты сотрудников с учётом премий, налогов и прочих факторов.
2. Оптимизация производительности путём объединения нескольких операций в одну процедуру: выполнение множества действий одновременно (например, массовое обновление/добавление данных).
Ниже наглядная таблица, иллюстрирующая разницу между этими понятиями
❤1
❓❓Почему нужно использовать хранимые процедуры вместо обычных селектов?
Я часто слышу о необходимости оборачивания бизнес-логики, реализуемой на стороне БД, в ХП. На вопрос "почему" обычно получаю краткое "безопасно".
Разберемся, в чем заключается эта безопасность и в чем тут реально дело.
🪭 И правда, безопасность
• Минимизация SQL-инъекций: Хранимые процедуры используют параметризованные запросы, что снижает риск SQL-инъекций.
• Контроль доступа: Можно ограничить доступ к таблицам напрямую, предоставив права только на выполнение хранимок.
• Аудит действий: Легче отслеживать, кто и какие операции выполнял, если все изменения идут через процедуры.
🪭 Производительность
• Предварительная компиляция: хранимки компилируются и оптимизируются при создании, что ускоряет выполнение.
• Снижение сетевого трафика: Вместо отправки больших SQL-запросов клиент передает только имя процедуры и параметры.
• Локальная обработка: Сложные операции выполняются на сервере, а не на клиенте, что уменьшает нагрузку на приложение.
🪭 Упрощение поддержки
• Централизованная логика: Изменения в бизнес-логике вносятся в одном месте - в хранимке, а не во всех клиентских приложениях.
• Согласованность данных: Все приложения используют одни и те же процедуры, что уменьшает риск ошибок из-за разных реализаций.
🪭 Контроль за транзакциями
• Упрощение управления транзакциями: Можно объединять несколько операций в одну транзакцию внутри хранимки, гарантируя атомарность.
• Автоматический откат при ошибках: Если в процедуре возникает ошибка, можно откатить изменения без дополнительного кода на клиенте.
🪭 Масштабируемость
• Разгрузка приложения: Сервер БД берет на себя часть вычислительной нагрузки.
• Возможность кеширования планов запросов: SP могут использовать кешированные планы выполнения, что ускоряет повторные вызовы.
🗝 Когда хранимые процедуры могут быть избыточны?
• В простых CRUD-приложениях без сложной бизнес-логики.
• В системах, где важна гибкость и быстрая итерация (например, NoSQL или ORM-подход).
• В микросервисных архитектурах, где бизнес-логика вынесена в сервисы.
Я часто слышу о необходимости оборачивания бизнес-логики, реализуемой на стороне БД, в ХП. На вопрос "почему" обычно получаю краткое "безопасно".
Разберемся, в чем заключается эта безопасность и в чем тут реально дело.
🪭 И правда, безопасность
• Минимизация SQL-инъекций: Хранимые процедуры используют параметризованные запросы, что снижает риск SQL-инъекций.
• Контроль доступа: Можно ограничить доступ к таблицам напрямую, предоставив права только на выполнение хранимок.
• Аудит действий: Легче отслеживать, кто и какие операции выполнял, если все изменения идут через процедуры.
🪭 Производительность
• Предварительная компиляция: хранимки компилируются и оптимизируются при создании, что ускоряет выполнение.
• Снижение сетевого трафика: Вместо отправки больших SQL-запросов клиент передает только имя процедуры и параметры.
• Локальная обработка: Сложные операции выполняются на сервере, а не на клиенте, что уменьшает нагрузку на приложение.
🪭 Упрощение поддержки
• Централизованная логика: Изменения в бизнес-логике вносятся в одном месте - в хранимке, а не во всех клиентских приложениях.
• Согласованность данных: Все приложения используют одни и те же процедуры, что уменьшает риск ошибок из-за разных реализаций.
🪭 Контроль за транзакциями
• Упрощение управления транзакциями: Можно объединять несколько операций в одну транзакцию внутри хранимки, гарантируя атомарность.
• Автоматический откат при ошибках: Если в процедуре возникает ошибка, можно откатить изменения без дополнительного кода на клиенте.
🪭 Масштабируемость
• Разгрузка приложения: Сервер БД берет на себя часть вычислительной нагрузки.
• Возможность кеширования планов запросов: SP могут использовать кешированные планы выполнения, что ускоряет повторные вызовы.
🗝 Когда хранимые процедуры могут быть избыточны?
• В простых CRUD-приложениях без сложной бизнес-логики.
• В системах, где важна гибкость и быстрая итерация (например, NoSQL или ORM-подход).
• В микросервисных архитектурах, где бизнес-логика вынесена в сервисы.
❤1
🔝 Топ-7 мифов и заблуждений при проектировании БД на физическом уровне
Рассмотрим самые распространенные ошибки, которые совершаются на этапе физического проектирования.
Миф №1: Нормализованная база данных — это лучшая практика всегда
📛 Часто считается, что нормализацию нужно проводить всегда и обязательно стремиться к третьей нормальной форме (3NF). Однако чрезмерная нормализованность может привести к увеличению числа соединений (JOIN), замедлению выполнения запросов и усложнению структуры базы данных.
✅ Необходимо учитывать требования конкретной предметной области и балансировать между производительностью и целостностью данных. Иногда денормализация вполне оправдана, особенно в высоконагруженных системах или системах OLAP (аналитические системы).
Миф №2: Индексация решит любые проблемы производительности
📛 Добавив индексы ко всем столбцам, можно добиться повышения производительности любых запросов. Но неправильная индексация увеличивает накладные расходы на обслуживание индексов, ухудшает производительность при обновлении и удалении данных.
✅ Анализируйте нагрузки на систему и создавайте индексы осознанно, исходя из реальных сценариев использования. Используйте подходы профилирования запросов и анализа медленных запросов.
Миф №3: Физический дизайн определяется исключительно моделью данных
📛 Некоторые считают, что физический уровень зависит только от логической модели данных. Хотя логическая структура важна, физическое проектирование должно также учитывать особенности используемого оборудования, платформы и программного обеспечения.
✅ Учитывать аппаратные ресурсы (количество ядер CPU, объём оперативной памяти, ёмкость дисков), выбрать подходящие механизмы управления памятью и I/O, настроить параметры резервного копирования и восстановления.
Миф №4: Размер таблицы не имеет значения
📛 Многие полагают, что размер таблицы не влияет на производительность запросов и общие характеристики системы. Большие таблицы могут стать причиной деградации производительности и затруднений в обслуживании.
✅ Использовать методы горизонтального шардинга (разбиения больших таблиц на части), кластеризации данных и продуманного подхода к индексированию.
Миф №5: Оптимизация базы данных начинается после завершения разработки
📛 Оптимизация и настройка базы данных откладываются на финальную стадию проекта. В результате многие проблемы обнаруживаются поздно, и исправлять их становится сложнее и дороже.
✅ Регулярно тестировать и анализировать поведение системы, заниматься настройкой производительности на ранних этапах жизненного цикла проекта.
Миф №6: Отказоустойчивость достигается одним методом
📛 Существуют универсальные рецепты отказоустойчивости, такие как репликация или резервное копирование. На самом деле разные сценарии требуют разных подходов и комбинаций методов.
✅ Применяйте комплексный подход к обеспечению отказоустойчивости, включающий репликацию, зеркалирование, архивацию, регулярное тестирование аварийного восстановления и мониторинг состояния системы.
Миф №7: Высокий уровень абстракции скрывает физические ограничения
📛 Современные инструменты ORM (Object Relational Mapping) позволяют игнорировать физическую структуру базы данных и сосредоточиться только на объектной модели. Однако физическая реализация оказывает значительное влияние на производительность и эффективность запросов.
✅ Понимать основы физической архитектуры базы данных и применять лучшие практики, даже при работе с инструментами высокого уровня абстракции.
Рассмотрим самые распространенные ошибки, которые совершаются на этапе физического проектирования.
Миф №1: Нормализованная база данных — это лучшая практика всегда
📛 Часто считается, что нормализацию нужно проводить всегда и обязательно стремиться к третьей нормальной форме (3NF). Однако чрезмерная нормализованность может привести к увеличению числа соединений (JOIN), замедлению выполнения запросов и усложнению структуры базы данных.
✅ Необходимо учитывать требования конкретной предметной области и балансировать между производительностью и целостностью данных. Иногда денормализация вполне оправдана, особенно в высоконагруженных системах или системах OLAP (аналитические системы).
Миф №2: Индексация решит любые проблемы производительности
📛 Добавив индексы ко всем столбцам, можно добиться повышения производительности любых запросов. Но неправильная индексация увеличивает накладные расходы на обслуживание индексов, ухудшает производительность при обновлении и удалении данных.
✅ Анализируйте нагрузки на систему и создавайте индексы осознанно, исходя из реальных сценариев использования. Используйте подходы профилирования запросов и анализа медленных запросов.
Миф №3: Физический дизайн определяется исключительно моделью данных
📛 Некоторые считают, что физический уровень зависит только от логической модели данных. Хотя логическая структура важна, физическое проектирование должно также учитывать особенности используемого оборудования, платформы и программного обеспечения.
✅ Учитывать аппаратные ресурсы (количество ядер CPU, объём оперативной памяти, ёмкость дисков), выбрать подходящие механизмы управления памятью и I/O, настроить параметры резервного копирования и восстановления.
Миф №4: Размер таблицы не имеет значения
📛 Многие полагают, что размер таблицы не влияет на производительность запросов и общие характеристики системы. Большие таблицы могут стать причиной деградации производительности и затруднений в обслуживании.
✅ Использовать методы горизонтального шардинга (разбиения больших таблиц на части), кластеризации данных и продуманного подхода к индексированию.
Миф №5: Оптимизация базы данных начинается после завершения разработки
📛 Оптимизация и настройка базы данных откладываются на финальную стадию проекта. В результате многие проблемы обнаруживаются поздно, и исправлять их становится сложнее и дороже.
✅ Регулярно тестировать и анализировать поведение системы, заниматься настройкой производительности на ранних этапах жизненного цикла проекта.
Миф №6: Отказоустойчивость достигается одним методом
📛 Существуют универсальные рецепты отказоустойчивости, такие как репликация или резервное копирование. На самом деле разные сценарии требуют разных подходов и комбинаций методов.
✅ Применяйте комплексный подход к обеспечению отказоустойчивости, включающий репликацию, зеркалирование, архивацию, регулярное тестирование аварийного восстановления и мониторинг состояния системы.
Миф №7: Высокий уровень абстракции скрывает физические ограничения
📛 Современные инструменты ORM (Object Relational Mapping) позволяют игнорировать физическую структуру базы данных и сосредоточиться только на объектной модели. Однако физическая реализация оказывает значительное влияние на производительность и эффективность запросов.
✅ Понимать основы физической архитектуры базы данных и применять лучшие практики, даже при работе с инструментами высокого уровня абстракции.
❤2
Сегодня поговорим об ограничениях уровня базы данных, которые нужно учесть. Ограничения — это правила, которые накладываются на данные в таблицах для обеспечения их целостности, согласованности и безопасности. Большинство из них вы знаете, но будет правильным собрать их в одном месте.
🌐 Первичный ключ (PRIMARY KEY)
• Что делает: Уникально идентифицирует каждую запись в таблице.
• Зачем нужно:
– Гарантирует уникальность (не может быть дубликатов).
– Обеспечивает быстрый доступ к данным (индексируется).
– Используется для связей между таблицами (FOREIGN KEY).
🌐 Внешний ключ (FOREIGN KEY)
• Что делает: Связывает поле одной таблицы с PRIMARY KEY другой таблицы.
• Зачем нужно:
– Поддерживает ссылочную целостность (нельзя ссылаться на несуществующие записи).
– Автоматически удаляет/обновляет связанные записи (если задано ON DELETE CASCADE или ON UPDATE CASCADE).
🌐 Уникальность (UNIQUE)
• Что делает: Гарантирует, что значения в столбце (или комбинации столбцов) не повторяются.
• Зачем нужно:
– Позволяет избежать дублирования (например, email пользователя).
– Отличается от PRIMARY KEY тем, что может быть NULL (в некоторых СУБД).
🌐 Проверка (CHECK)
• Что делает: Ограничивает допустимые значения в столбце по условию.
• Зачем нужно:
– Обеспечивает бизнес-правила (например, возраст > 0, дата окончания > даты начала).
– Пример:
🌐 Непустое значение (NOT NULL)
• Что делает: Запрещает NULL в столбце.
• Зачем нужно:
– Гарантирует, что критически важные данные (например, user_id) всегда заполнены.
– Уменьшает ошибки при обработке данных.
🌐 Значение по умолчанию (DEFAULT)
• Что делает: Устанавливает значение по умолчанию, если оно не указано при вставке.
• Зачем нужно:
– Упрощает вставку данных (например, created_at DEFAULT CURRENT_TIMESTAMP).
– Позволяет избежать NULL, если значение не задано.
🌐 Условия на уровне таблицы (CONSTRAINT)
сложные CHECK на несколько столбцов.
Зачем вообще нужны ограничения?
1. Целостность данных – защита от некорректных или противоречивых данных.
2. Безопасность – предотвращение случайных или злонамеренных изменений.
3. Производительность – индексы (PRIMARY KEY, UNIQUE) ускоряют запросы.
4. Согласованность – гарантия, что связи между таблицами (FOREIGN KEY) всегда корректны.
🌐 Первичный ключ (PRIMARY KEY)
• Что делает: Уникально идентифицирует каждую запись в таблице.
• Зачем нужно:
– Гарантирует уникальность (не может быть дубликатов).
– Обеспечивает быстрый доступ к данным (индексируется).
– Используется для связей между таблицами (FOREIGN KEY).
🌐 Внешний ключ (FOREIGN KEY)
• Что делает: Связывает поле одной таблицы с PRIMARY KEY другой таблицы.
• Зачем нужно:
– Поддерживает ссылочную целостность (нельзя ссылаться на несуществующие записи).
– Автоматически удаляет/обновляет связанные записи (если задано ON DELETE CASCADE или ON UPDATE CASCADE).
🌐 Уникальность (UNIQUE)
• Что делает: Гарантирует, что значения в столбце (или комбинации столбцов) не повторяются.
• Зачем нужно:
– Позволяет избежать дублирования (например, email пользователя).
– Отличается от PRIMARY KEY тем, что может быть NULL (в некоторых СУБД).
🌐 Проверка (CHECK)
• Что делает: Ограничивает допустимые значения в столбце по условию.
• Зачем нужно:
– Обеспечивает бизнес-правила (например, возраст > 0, дата окончания > даты начала).
– Пример:
🌐 Непустое значение (NOT NULL)
• Что делает: Запрещает NULL в столбце.
• Зачем нужно:
– Гарантирует, что критически важные данные (например, user_id) всегда заполнены.
– Уменьшает ошибки при обработке данных.
🌐 Значение по умолчанию (DEFAULT)
• Что делает: Устанавливает значение по умолчанию, если оно не указано при вставке.
• Зачем нужно:
– Упрощает вставку данных (например, created_at DEFAULT CURRENT_TIMESTAMP).
– Позволяет избежать NULL, если значение не задано.
🌐 Условия на уровне таблицы (CONSTRAINT)
сложные CHECK на несколько столбцов.
Зачем вообще нужны ограничения?
1. Целостность данных – защита от некорректных или противоречивых данных.
2. Безопасность – предотвращение случайных или злонамеренных изменений.
3. Производительность – индексы (PRIMARY KEY, UNIQUE) ускоряют запросы.
4. Согласованность – гарантия, что связи между таблицами (FOREIGN KEY) всегда корректны.
❤1
Ура! Я вернулась!
И конечно, такое длительное затишье я могу оправдать только большим количеством приятных новостей и постов. Да будет так!
Но делиться буду постепенно. ☺️
Новость N1
Вы классные! Просто так. Ну и потому что дождались меня и не разбежались!
Новость N2
Давно хотела поделиться, да всё некогда было. Летом я стала амбассадором Банка ПСБ, где работаю и наслаждаюсь каждым днём своей профессиональной деятельностью. 🌟
Сразу скажу: рекомендую только то, что действительно люблю сама.
Зачем вообще рассказываю?
Хочется продемонстрировать, как здорово и вдохновенно можно провести своё рабочее время, получать ценные знания и развивать профессиональные навыки именно здесь. Ведь выяснилось, что Банк незаслуженно недооценён среди IT-сообщества, хотя, на мой взгляд, заслуживает большего внимания. Поэтому я хочу изменить ситуацию.
За прошедший год Банк стал важной частью моей жизни — и это совсем не критика, а искренняя похвала. Благодаря Банку я начала танцевать, заниматься йогой, посещать каток, ходить на местные мероприятия вроде TED-talks, готовиться к выступлениям на внутренних и внешних мероприятиях, учиться ведению переговоров и публичным выступлениям. То есть всему тому, до чего раньше никак не доходили руки, теперь можно заняться вместе с коллегами!
Хотите читать истории о жизни внутри банка? Если да, то буду иногда делиться закулисьем моей работы.
Всегда открыта вашим отзывам и мнениям. Честный диалог помогает двигаться вперёд всем вместе.
И конечно, такое длительное затишье я могу оправдать только большим количеством приятных новостей и постов. Да будет так!
Но делиться буду постепенно. ☺️
Новость N1
Вы классные! Просто так. Ну и потому что дождались меня и не разбежались!
Новость N2
Давно хотела поделиться, да всё некогда было. Летом я стала амбассадором Банка ПСБ, где работаю и наслаждаюсь каждым днём своей профессиональной деятельностью. 🌟
Сразу скажу: рекомендую только то, что действительно люблю сама.
Зачем вообще рассказываю?
Хочется продемонстрировать, как здорово и вдохновенно можно провести своё рабочее время, получать ценные знания и развивать профессиональные навыки именно здесь. Ведь выяснилось, что Банк незаслуженно недооценён среди IT-сообщества, хотя, на мой взгляд, заслуживает большего внимания. Поэтому я хочу изменить ситуацию.
За прошедший год Банк стал важной частью моей жизни — и это совсем не критика, а искренняя похвала. Благодаря Банку я начала танцевать, заниматься йогой, посещать каток, ходить на местные мероприятия вроде TED-talks, готовиться к выступлениям на внутренних и внешних мероприятиях, учиться ведению переговоров и публичным выступлениям. То есть всему тому, до чего раньше никак не доходили руки, теперь можно заняться вместе с коллегами!
Хотите читать истории о жизни внутри банка? Если да, то буду иногда делиться закулисьем моей работы.
Всегда открыта вашим отзывам и мнениям. Честный диалог помогает двигаться вперёд всем вместе.
❤2
Нефункциональные требования
Мы рассмотрели, как проектировать Базу, а теперь пора уделить время нефункциональным требованиям нашей библиотечной системы. Подумаем, что учесть и как обечпечить те характеристики, которые описываются в нефункциональных требованиях.
Рассмотрим следующие характеристики:
1. Производительность
2. Надежность и Доступность
3. Безопасность
4. Масштабируемость
5. Удобство использования и Совместимость
6. Тестируемость и Поддерживаемость
♻️ 1. Производительность ♻️
Требования
• Время отклика:
– Большинство операций (поиск книги, оформление выдачи, возврат) должны выполняться менее чем за 2 секунды.
– Операции формирования сложных отчетов (например, за год) могут занимать до 30 секунд.
• Пропускная способность:
– Система должна выдерживать пиковую нагрузку до 50 одновременных операций (например, в часы "наплыва" читателей перед закрытием или в выходной день).
• Масштабируемость:
– Система должна иметь возможность масштабирования для обслуживания большего количества филиалов или пользователей без полной переработки архитектуры.
Способы исполнения
• Паттерны:
– Кэширование (Caching): Использование кэша (например, Redis или Memcached) для часто запрашиваемых и редко изменяемых данных: список популярных книг, информация о читателях (при частом обращении), справочники (жанры, авторы).
– Пагинация (Pagination): Все списки (результаты поиска, история выдач) должны возвращаться частями (по 20-50 записей), а не целиком.
– Асинхронная обработка (Async Processing): Для длительных операций (формирование объемных отчетов, рассылка уведомлений о задолженностях) использовать асинхронные задачи (через RabbitMQ, Kafka или Celery). Пользователь получает уведомление о готовности отчета, а не ждет его генерации в основном потоке.
• Инструменты:
– База данных: Выбор производительной СУБД (PostgreSQL или MySQL), создание индексов, о которых говорили ранее.
🎲 Расчеты
– Оценка нагрузки: Предположим, в библиотеке 10 активных библиотекарей. Каждый совершает 1 операцию в минуту в спокойном режиме и до 5 операций в минуту в пиковом. Итого: 10 * 5 = 50 операций/мин (≈ 0.83 ops/sec). Это скромная нагрузка, поэтому внимание можно уделить простоте реализации и поддерживаемости системы.
Никаких особенных подходов не требуется для обеспечения такой нагрузки, но можно добавить:
- Нужно оптимизация SQL-запросов
- Рекомендуется использовать простую архитектуру
- Полезно иметь систему мониторинга основных метрик (CPU, память, запросы к базе данных). Это позволит оперативно реагировать на изменения нагрузки или появление узких мест.
Подробнее о RPS поговорим позже.
Мы рассмотрели, как проектировать Базу, а теперь пора уделить время нефункциональным требованиям нашей библиотечной системы. Подумаем, что учесть и как обечпечить те характеристики, которые описываются в нефункциональных требованиях.
Рассмотрим следующие характеристики:
1. Производительность
2. Надежность и Доступность
3. Безопасность
4. Масштабируемость
5. Удобство использования и Совместимость
6. Тестируемость и Поддерживаемость
♻️ 1. Производительность ♻️
Требования
• Время отклика:
– Большинство операций (поиск книги, оформление выдачи, возврат) должны выполняться менее чем за 2 секунды.
– Операции формирования сложных отчетов (например, за год) могут занимать до 30 секунд.
• Пропускная способность:
– Система должна выдерживать пиковую нагрузку до 50 одновременных операций (например, в часы "наплыва" читателей перед закрытием или в выходной день).
• Масштабируемость:
– Система должна иметь возможность масштабирования для обслуживания большего количества филиалов или пользователей без полной переработки архитектуры.
Способы исполнения
• Паттерны:
– Кэширование (Caching): Использование кэша (например, Redis или Memcached) для часто запрашиваемых и редко изменяемых данных: список популярных книг, информация о читателях (при частом обращении), справочники (жанры, авторы).
– Пагинация (Pagination): Все списки (результаты поиска, история выдач) должны возвращаться частями (по 20-50 записей), а не целиком.
– Асинхронная обработка (Async Processing): Для длительных операций (формирование объемных отчетов, рассылка уведомлений о задолженностях) использовать асинхронные задачи (через RabbitMQ, Kafka или Celery). Пользователь получает уведомление о готовности отчета, а не ждет его генерации в основном потоке.
• Инструменты:
– База данных: Выбор производительной СУБД (PostgreSQL или MySQL), создание индексов, о которых говорили ранее.
🎲 Расчеты
– Оценка нагрузки: Предположим, в библиотеке 10 активных библиотекарей. Каждый совершает 1 операцию в минуту в спокойном режиме и до 5 операций в минуту в пиковом. Итого: 10 * 5 = 50 операций/мин (≈ 0.83 ops/sec). Это скромная нагрузка, поэтому внимание можно уделить простоте реализации и поддерживаемости системы.
Никаких особенных подходов не требуется для обеспечения такой нагрузки, но можно добавить:
- Нужно оптимизация SQL-запросов
- Рекомендуется использовать простую архитектуру
- Полезно иметь систему мониторинга основных метрик (CPU, память, запросы к базе данных). Это позволит оперативно реагировать на изменения нагрузки или появление узких мест.
Подробнее о RPS поговорим позже.
❤1
Продолжаем разбирать нефункциональные требования.
♻️ 2. Надежность и Доступность ♻️
📜Требования
✏️ Доступность: Система должна быть доступна 99.9% времени в рабочие часы библиотеки (это чуть более 8 часов простоя в год). Критично, чтобы система не "падала" в часы пиковой нагрузки.
✏️ Целостность данных: Не допускается потеря данных о выдачах, читателях или книгах. Все финансовые операции (начисление/списание штрафов) должны быть транзакционными.
✏️ Восстановление после сбоев: В случае сбоя система должна восстанавливаться из последней резервной копии с минимальной потерей данных (целевой показатель восстановления - RTO < 1 часа, целевой показатель точки восстановления - RPO < 15 минут).
🗂 Способы исполнения
📘 Паттерны:
🔸 Репликация базы данных: Настройка Master-Slave репликации. Slave-реплика может использоваться для чтения (например, для отчетов), а также служить "горячим" резервом на случай падения Master.
🔸 Резервное копирование (бекапы): Регулярное (ежедневное) автоматическое резервное копирование базы данных и файловых Assets (например, сканы документов читателей). Хранение бэкапов не только на основном сервере, но и в удаленном хранилище (например, в облаке Яндекса).
📘 Инструменты:
🔹 Мониторинг: Использование систем мониторинга (Prometheus + Grafana, Zabbix) для отслеживания доступности, нагрузки и потребления ресурсов.
🔹 Балансировщик нагрузки: Например, nginx для распределения запросов между несколькими экземплярами приложения.
📘 Архитектура:
Для обеспечения 99.9% доступности достаточно одной ноды (сервера) приложения и одной ноды базы данных с правильно настроенной репликацией и мониторингом. Переход на отказоустойчивый кластер (например, с несколькими нодами приложения за балансировщиком) потребуется при более строгих требованиях (99.99%).
А про виды девяток и их влияние поговорим немного позже
♻️ 2. Надежность и Доступность ♻️
📜Требования
✏️ Доступность: Система должна быть доступна 99.9% времени в рабочие часы библиотеки (это чуть более 8 часов простоя в год). Критично, чтобы система не "падала" в часы пиковой нагрузки.
✏️ Целостность данных: Не допускается потеря данных о выдачах, читателях или книгах. Все финансовые операции (начисление/списание штрафов) должны быть транзакционными.
✏️ Восстановление после сбоев: В случае сбоя система должна восстанавливаться из последней резервной копии с минимальной потерей данных (целевой показатель восстановления - RTO < 1 часа, целевой показатель точки восстановления - RPO < 15 минут).
🗂 Способы исполнения
📘 Паттерны:
🔸 Репликация базы данных: Настройка Master-Slave репликации. Slave-реплика может использоваться для чтения (например, для отчетов), а также служить "горячим" резервом на случай падения Master.
🔸 Резервное копирование (бекапы): Регулярное (ежедневное) автоматическое резервное копирование базы данных и файловых Assets (например, сканы документов читателей). Хранение бэкапов не только на основном сервере, но и в удаленном хранилище (например, в облаке Яндекса).
📘 Инструменты:
🔹 Мониторинг: Использование систем мониторинга (Prometheus + Grafana, Zabbix) для отслеживания доступности, нагрузки и потребления ресурсов.
🔹 Балансировщик нагрузки: Например, nginx для распределения запросов между несколькими экземплярами приложения.
📘 Архитектура:
Для обеспечения 99.9% доступности достаточно одной ноды (сервера) приложения и одной ноды базы данных с правильно настроенной репликацией и мониторингом. Переход на отказоустойчивый кластер (например, с несколькими нодами приложения за балансировщиком) потребуется при более строгих требованиях (99.99%).
А про виды девяток и их влияние поговорим немного позже
❤2
А вот и новости №3 и №4. Банк опередил и анонсировал даже раньше меня.
Осенний сезон ожидается насыщенным и иногда даже горячим.
У кого какие конференции запланированы на осень?
Осенний сезон ожидается насыщенным и иногда даже горячим.
У кого какие конференции запланированы на осень?
Forwarded from ИТ ПСБ
В своих докладах она познакомит слушателей с согласованностью и ее видами, расскажет про понятие ACID и принципы атомарности, согласованности, изоляции и долговечности. Сравнит два подхода: Saga Pattern и двухфазный коммит. А также поделится способами объединения паттернов в одном проекте и даст практические рекомендации по выбору подходящего паттерна в зависимости от требований бизнеса и технических ограничений конкретной системы.
Приходите поддержать коллегу в Петербурге или онлайн:
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1😍1
♻️ 3. Безопасность ♻️
📜 Требования
✏️ Конфиденциальность: Данные читателей (персональные данные, история чтения) должны быть защищены от несанкционированного доступа.
✏️ Аутентификация и Авторизация: Строгое разграничение прав между библиотекарями (могут выдавать книги) и администраторами (могут управлять пользователями, настраивать систему).
✏️ Аудит: Вести лог всех действий, особенно связанных с изменением данных (изменение размера штрафа, удаление записи о книге, сброс пароля).
📉 Способы исполнения
📓 Паттерны:
RBAC (Role-Based Access Control): Система прав доступа, основанная на ролях. Создаются роли Librarian и Admin, каждой роли назначаются разрешения на конкретные endpoints API или экраны UI.
📓 Инструменты и практики:
〰️ HTTPS: Обязательное использование шифрованного соединения для всего трафика.
〰️ Хэширование паролей: Пароли пользователей (библиотекарей и админов) должны храниться в базе данных только в виде хэшей.
〰️ Валидация входных данных: Защита от SQL-инъекций и XSS-атак путем использования ORM или подготовленных выражений
〰️ JWT (JSON Web Tokens) или OAuth 2.0: Для управления сессиями пользователей после входа в систему.
📜 Требования
✏️ Конфиденциальность: Данные читателей (персональные данные, история чтения) должны быть защищены от несанкционированного доступа.
✏️ Аутентификация и Авторизация: Строгое разграничение прав между библиотекарями (могут выдавать книги) и администраторами (могут управлять пользователями, настраивать систему).
✏️ Аудит: Вести лог всех действий, особенно связанных с изменением данных (изменение размера штрафа, удаление записи о книге, сброс пароля).
📉 Способы исполнения
📓 Паттерны:
RBAC (Role-Based Access Control): Система прав доступа, основанная на ролях. Создаются роли Librarian и Admin, каждой роли назначаются разрешения на конкретные endpoints API или экраны UI.
📓 Инструменты и практики:
〰️ HTTPS: Обязательное использование шифрованного соединения для всего трафика.
〰️ Хэширование паролей: Пароли пользователей (библиотекарей и админов) должны храниться в базе данных только в виде хэшей.
〰️ Валидация входных данных: Защита от SQL-инъекций и XSS-атак путем использования ORM или подготовленных выражений
〰️ JWT (JSON Web Tokens) или OAuth 2.0: Для управления сессиями пользователей после входа в систему.
❤1
♻️ 4. Масштабируемость ♻️
📜 Требования
Система должна быть спроектирована так, чтобы можно было увеличить вычислительную мощность для обработки роста количества транзакций или данных.
📗Способы исполнения
📐 Вертикальное масштабирование: Увеличение ресурсов существующего сервера (более мощный CPU, больше RAM). Минусы: имеет физический предел.
📐 Горизонтальное масштабирование: Добавление новых серверов-клонов с приложением за балансировщиком нагрузки. Более современный и гибкий подход. Для этого приложение должно быть stateless (не хранить состояние сессии на сервере, а использовать, например, JWT или хранилище сессий в Redis).
📗 Архитектура
Выбор микросервисной архитектуры (разделение на сервис каталога, сервис выдачи, сервис отчетности) упростит независимое масштабирование отдельных частей системы в будущем. Приведу небольшой спойлер, который мы будем разбирать подробнее в секции архитектуры: для старта работы библиотечной системы монолитная архитектура является более оправданной. А почему - обсудим :)
📜 Требования
Система должна быть спроектирована так, чтобы можно было увеличить вычислительную мощность для обработки роста количества транзакций или данных.
📗Способы исполнения
📐 Вертикальное масштабирование: Увеличение ресурсов существующего сервера (более мощный CPU, больше RAM). Минусы: имеет физический предел.
📐 Горизонтальное масштабирование: Добавление новых серверов-клонов с приложением за балансировщиком нагрузки. Более современный и гибкий подход. Для этого приложение должно быть stateless (не хранить состояние сессии на сервере, а использовать, например, JWT или хранилище сессий в Redis).
📗 Архитектура
Выбор микросервисной архитектуры (разделение на сервис каталога, сервис выдачи, сервис отчетности) упростит независимое масштабирование отдельных частей системы в будущем. Приведу небольшой спойлер, который мы будем разбирать подробнее в секции архитектуры: для старта работы библиотечной системы монолитная архитектура является более оправданной. А почему - обсудим :)
♻️ 5. Удобство использования и Совместимость ♻️
📜 Требования
✏️ UI/UX: Интерфейс должен быть интуитивно понятным для библиотекарей с минимальным обучением. Критичные операции (сканирование штрих-кода книги и читательского билета) должны выполняться с минимальным количеством кликов.
✏️ Кросс-браузерность: Веб-интерфейс должен корректно работать в современных браузерах (Chrome, Firefox, Safari, Edge).
✏️ Мобильность: Адаптивный интерфейс или отдельное мобильное приложение для работы с портативными сканерами штрих-кодов.
📕 Способы исполнения
🗝 Фреймворки: Использование современных frontend-фреймворков (React, Vue.js, Angular)
🗝 User Testing: Проведение тестирования с реальными библиотекарями на ранних этапах на базе прототипов в Figma).
♻️ 6. Тестируемость и Поддерживаемость ♻️
📜 Требования
Код должен быть хорошо документирован и покрыт тестами, чтобы упростить добавление нового функционала и исправление ошибок.
📒 Способы исполнения
📁 Паттерны:
🗳 Модульная архитектура: Следование принципам SOLID и использование Dependency Injection для создания слабосвязанного кода, который легко тестировать.
📁 Инструменты и практики:
🗳 Покрытие кода тестами: Написание модульных (Unit), интеграционных (Integration) и end-to-end (E2E) тестов.
🗳 CI/CD: Настройка автоматизированных пайплайнов (например, в GitLab CI/CD, GitHub Actions) для запуска тестов и развертывания на тестовые/продуктивные среды.
📜 Требования
✏️ UI/UX: Интерфейс должен быть интуитивно понятным для библиотекарей с минимальным обучением. Критичные операции (сканирование штрих-кода книги и читательского билета) должны выполняться с минимальным количеством кликов.
✏️ Кросс-браузерность: Веб-интерфейс должен корректно работать в современных браузерах (Chrome, Firefox, Safari, Edge).
✏️ Мобильность: Адаптивный интерфейс или отдельное мобильное приложение для работы с портативными сканерами штрих-кодов.
📕 Способы исполнения
🗝 Фреймворки: Использование современных frontend-фреймворков (React, Vue.js, Angular)
🗝 User Testing: Проведение тестирования с реальными библиотекарями на ранних этапах на базе прототипов в Figma).
♻️ 6. Тестируемость и Поддерживаемость ♻️
📜 Требования
Код должен быть хорошо документирован и покрыт тестами, чтобы упростить добавление нового функционала и исправление ошибок.
📒 Способы исполнения
📁 Паттерны:
🗳 Модульная архитектура: Следование принципам SOLID и использование Dependency Injection для создания слабосвязанного кода, который легко тестировать.
📁 Инструменты и практики:
🗳 Покрытие кода тестами: Написание модульных (Unit), интеграционных (Integration) и end-to-end (E2E) тестов.
🗳 CI/CD: Настройка автоматизированных пайплайнов (например, в GitLab CI/CD, GitHub Actions) для запуска тестов и развертывания на тестовые/продуктивные среды.
❤1
Новость №5.
В сентябре вышла моя первая статья на Хабре в блоге ПСБ. Охватить хотелось как можно больше, поэтому она получилась лонг-ридом.
Описала, кажется, все подводные камни, с которыми сталкивалась при проектировании API. Может, найдете что-то для себя!
За 2 недели более 5 тыс прочтений. Для меня это знак, что я создаю актуальные материалы. Пошла работать дальше.
Хотите посмеяться? когда вышла эта статья, по стечению обстоятельств, мое имя появлялось в новостной ленте банка 4 раза по разным поводам, поэтому неделю 22-26 сентября медийка Банка назвали в мою честь (в шутку)
https://habr.com/ru/companies/psb/articles/949246/
В сентябре вышла моя первая статья на Хабре в блоге ПСБ. Охватить хотелось как можно больше, поэтому она получилась лонг-ридом.
Описала, кажется, все подводные камни, с которыми сталкивалась при проектировании API. Может, найдете что-то для себя!
За 2 недели более 5 тыс прочтений. Для меня это знак, что я создаю актуальные материалы. Пошла работать дальше.
Хотите посмеяться? когда вышла эта статья, по стечению обстоятельств, мое имя появлялось в новостной ленте банка 4 раза по разным поводам, поэтому неделю 22-26 сентября медийка Банка назвали в мою честь (в шутку)
https://habr.com/ru/companies/psb/articles/949246/
🔥2
Что делать с системой при разных значениях RPS?
При формировании нефункциональных требований ранее мы упомянули, что из-за невысокого RPS мы можем позволить себе несложную архитектуру. Очень захотелось развить эту тему и порассуждать, при каких RPS влияет на сложность и надежность системы.
Значение RPS (Requests per second) определяет количество запросов, обрабатываемых системой каждую секунду. Выбор конкретных мер и сложность архитектуры зависят от множества факторов, включая не только само значение RPS, но и типы запросов, частоту всплесков нагрузки, необходимость поддержания высокой доступности и устойчивости системы.
🌀 Основные уровни значений RPS и рекомендуемые меры
🟢 Низкая нагрузка (< 10 RPS)
Примеры ситуаций: небольшие внутренние сервисы, прототипы, проекты начального этапа разработки.
✨ Подходящие решения:
- Монолитная архитектура
- Локальная база данных
- Минимальные средства мониторинга
- Отказ от кеширования или использование простого кеша (Redis для хранения сессий).
🟠 Средняя нагрузка (~10–100 RPS)
Примеры ситуаций: средние корпоративные веб-приложения, небольшие онлайн-магазины, региональные сервисы.
⚙️ Рекомендуемые шаги:
- Разделение на отдельные модули (Service-Oriented Architecture, SOA);
- Кеширование на уровне сервера приложений (Varnish, Redis, Memcached);
- Оптимизация баз данных (индексация, репликация master-slave);
- Автоматическое масштабирование хостинга (AWS Auto Scaling, Kubernetes HPA).
🔴 Высокая нагрузка (~100–1000 RPS)
Примеры ситуаций: крупные веб-сервисы, корпоративные CRM, большие e-commerce площадки.
🚀 Необходимые меры:
- Микросервисная архитектура (каждый сервис отвечает за свою область);
- Балансировка нагрузки (Nginx, HAProxy, AWS ELB / ALB);
- Горизонтальное масштабирование (масштабирование вычислительных ресурсов в облаке);
- Использование шардирования (разбиение базы данных на части);
- Интеграция CDN (Content Delivery Network) для ускорения доставки статического контента.
🔵 Очень высокая нагрузка (> 1000 RPS)
Примеры ситуаций: глобальные социальные сети, высоконагруженные игровые платформы, финансовые транзакционные системы.
🪄 Какие технологии применять:
- Полностью асинхронная обработка запросов (event-driven architecture, очереди сообщений Kafka, RabbitMQ);
- Распределённые хранилища данных (Cassandra, MongoDB);
- Географически распределённая инфраструктура (multi-datacenter deployment);
- Расширенное кэширование (использование многоуровневых прокси-кешей, Redis Cluster);
- Высокая степень автоматизации деплоев и мониторинг (Kubernetes, Docker Swarm, CI/CD pipeline).
🔝 Общие принципы выбора подхода
- Простота против сложности: Чем ниже RPS, тем проще должно быть решение. Это очевидно, но сказать стоит: избегайте избыточной сложности там, где она не нужна.
- Масштабируемость: Подбирайте инфраструктуру, способную выдержать пиковые нагрузки (особенно сезонные всплески активности пользователей).
- Надёжность: Важнее всего гарантировать доступность сервиса при любом количестве запросов (это не всегда важнее всего. На своих докладах осеннего сезона я подробно разбираю этот аспект).
- Стоимость поддержки: Усложнение инфраструктуры повышает стоимость обслуживания и внедрения новых функций.
📍📍 Итоговая рекомендация
При достижении порога в ~100 RPS целесообразно задуматься о переходе к более сложной инфраструктуре и подготовке среды к росту нагрузки. Однако решающее значение имеет также качество самих запросов: если запросы сложные (например, требуют больших вычислений или объёмных выборок из базы данных), начать подготовку стоит заранее, ещё при меньших значениях RPS.
При формировании нефункциональных требований ранее мы упомянули, что из-за невысокого RPS мы можем позволить себе несложную архитектуру. Очень захотелось развить эту тему и порассуждать, при каких RPS влияет на сложность и надежность системы.
Значение RPS (Requests per second) определяет количество запросов, обрабатываемых системой каждую секунду. Выбор конкретных мер и сложность архитектуры зависят от множества факторов, включая не только само значение RPS, но и типы запросов, частоту всплесков нагрузки, необходимость поддержания высокой доступности и устойчивости системы.
🌀 Основные уровни значений RPS и рекомендуемые меры
🟢 Низкая нагрузка (< 10 RPS)
Примеры ситуаций: небольшие внутренние сервисы, прототипы, проекты начального этапа разработки.
✨ Подходящие решения:
- Монолитная архитектура
- Локальная база данных
- Минимальные средства мониторинга
- Отказ от кеширования или использование простого кеша (Redis для хранения сессий).
🟠 Средняя нагрузка (~10–100 RPS)
Примеры ситуаций: средние корпоративные веб-приложения, небольшие онлайн-магазины, региональные сервисы.
⚙️ Рекомендуемые шаги:
- Разделение на отдельные модули (Service-Oriented Architecture, SOA);
- Кеширование на уровне сервера приложений (Varnish, Redis, Memcached);
- Оптимизация баз данных (индексация, репликация master-slave);
- Автоматическое масштабирование хостинга (AWS Auto Scaling, Kubernetes HPA).
🔴 Высокая нагрузка (~100–1000 RPS)
Примеры ситуаций: крупные веб-сервисы, корпоративные CRM, большие e-commerce площадки.
🚀 Необходимые меры:
- Микросервисная архитектура (каждый сервис отвечает за свою область);
- Балансировка нагрузки (Nginx, HAProxy, AWS ELB / ALB);
- Горизонтальное масштабирование (масштабирование вычислительных ресурсов в облаке);
- Использование шардирования (разбиение базы данных на части);
- Интеграция CDN (Content Delivery Network) для ускорения доставки статического контента.
🔵 Очень высокая нагрузка (> 1000 RPS)
Примеры ситуаций: глобальные социальные сети, высоконагруженные игровые платформы, финансовые транзакционные системы.
🪄 Какие технологии применять:
- Полностью асинхронная обработка запросов (event-driven architecture, очереди сообщений Kafka, RabbitMQ);
- Распределённые хранилища данных (Cassandra, MongoDB);
- Географически распределённая инфраструктура (multi-datacenter deployment);
- Расширенное кэширование (использование многоуровневых прокси-кешей, Redis Cluster);
- Высокая степень автоматизации деплоев и мониторинг (Kubernetes, Docker Swarm, CI/CD pipeline).
🔝 Общие принципы выбора подхода
- Простота против сложности: Чем ниже RPS, тем проще должно быть решение. Это очевидно, но сказать стоит: избегайте избыточной сложности там, где она не нужна.
- Масштабируемость: Подбирайте инфраструктуру, способную выдержать пиковые нагрузки (особенно сезонные всплески активности пользователей).
- Надёжность: Важнее всего гарантировать доступность сервиса при любом количестве запросов (это не всегда важнее всего. На своих докладах осеннего сезона я подробно разбираю этот аспект).
- Стоимость поддержки: Усложнение инфраструктуры повышает стоимость обслуживания и внедрения новых функций.
📍📍 Итоговая рекомендация
При достижении порога в ~100 RPS целесообразно задуматься о переходе к более сложной инфраструктуре и подготовке среды к росту нагрузки. Однако решающее значение имеет также качество самих запросов: если запросы сложные (например, требуют больших вычислений или объёмных выборок из базы данных), начать подготовку стоит заранее, ещё при меньших значениях RPS.
❤1
Как использовать кеширование эффективно
Для удовлетворения нефункциональных требований по производительности, масштабированию, доступности и надежности может участвовать кеширование.
Эффективное кеширование — это не просто "включить Redis". Это стратегия. Разберем процесс по косточкам.
🧲 Что лучше кешировать
– Часто читаемые, редко меняющиеся данные (Каталог товаров, справочники, контент страниц, настройки)
– Результаты тяжелых вычислений (Агрегированная статистика, отчеты, рекомендательные выборки)
– Сессии пользователей
♨️ Что НЕ надо кешировать
– Часто меняющиеся данные (Текущий баланс счета, место водителя такси на карте)
– Чувствительные/персональные данные (если только кеш не надежно зашифрован).
– Уникальные данные, которые вряд ли будут запрошены повторно.
🔑 Стратегия инвалидации
Инвалидация - это обновление кеша. Политика ее выбора - самая сложная часть.
– Time-To-Live (TTL)
Самый простой способ. Устанавливаем время жизни записи в кеше. Подходит для данных, где не будет слишком критично, если данные ненадолго"протухнут" (например, список новостей).
– Инвалидация по событию
или "Write-Through/Write-Behind". При любом изменении данных в источнике нужно обновлять или удалять соответствующие данные в кеше. Этот подход позволяет оставлять данными в наиболее свежем состоянии, но требует сложной логики.
– Отложенная запись
или "Write-Behind". Запись данных сначала происходит в кеш, а затем асинхронно "сбрасывается" в основное хранилище. Повышает производительность записи, но есть риск потери данных при сбое.
📇 Выбор размера кеша и политики вытеснения
Что делать, когда кеш заполнен? Нужно почистить его от лишних данных. Как определить, какие данные являются лишними? Есть специальные политики
- LRU (Least Recently Used) — вытесняются давно неиспользуемые данные (фильтр по дате)
- LFU (Least Frequently Used) — вытесняются реже всего используемые данные (фильтр по частоте обращения)
🟰 Многоуровневое кеширование
– Уровень 1 (L1): Внутрипроцессный кеш (в памяти приложения). Очень быстрый, но не разделяемый между экземплярами приложения.
– Уровень 2 (L2): Внешний кеш (Redis, Memcached). Чуть медленнее из-за сетевого взаимодействия, но разделяемый между всеми экземплярами приложения.
Дальше разберем виды кеширования
Для удовлетворения нефункциональных требований по производительности, масштабированию, доступности и надежности может участвовать кеширование.
Эффективное кеширование — это не просто "включить Redis". Это стратегия. Разберем процесс по косточкам.
🧲 Что лучше кешировать
– Часто читаемые, редко меняющиеся данные (Каталог товаров, справочники, контент страниц, настройки)
– Результаты тяжелых вычислений (Агрегированная статистика, отчеты, рекомендательные выборки)
– Сессии пользователей
♨️ Что НЕ надо кешировать
– Часто меняющиеся данные (Текущий баланс счета, место водителя такси на карте)
– Чувствительные/персональные данные (если только кеш не надежно зашифрован).
– Уникальные данные, которые вряд ли будут запрошены повторно.
🔑 Стратегия инвалидации
Инвалидация - это обновление кеша. Политика ее выбора - самая сложная часть.
– Time-To-Live (TTL)
Самый простой способ. Устанавливаем время жизни записи в кеше. Подходит для данных, где не будет слишком критично, если данные ненадолго"протухнут" (например, список новостей).
– Инвалидация по событию
или "Write-Through/Write-Behind". При любом изменении данных в источнике нужно обновлять или удалять соответствующие данные в кеше. Этот подход позволяет оставлять данными в наиболее свежем состоянии, но требует сложной логики.
– Отложенная запись
или "Write-Behind". Запись данных сначала происходит в кеш, а затем асинхронно "сбрасывается" в основное хранилище. Повышает производительность записи, но есть риск потери данных при сбое.
📇 Выбор размера кеша и политики вытеснения
Что делать, когда кеш заполнен? Нужно почистить его от лишних данных. Как определить, какие данные являются лишними? Есть специальные политики
- LRU (Least Recently Used) — вытесняются давно неиспользуемые данные (фильтр по дате)
- LFU (Least Frequently Used) — вытесняются реже всего используемые данные (фильтр по частоте обращения)
🟰 Многоуровневое кеширование
– Уровень 1 (L1): Внутрипроцессный кеш (в памяти приложения). Очень быстрый, но не разделяемый между экземплярами приложения.
– Уровень 2 (L2): Внешний кеш (Redis, Memcached). Чуть медленнее из-за сетевого взаимодействия, но разделяемый между всеми экземплярами приложения.
Дальше разберем виды кеширования