Оптимизация серверной части веб-сервиса всегда направлена на повышение его производительности, ключевым аспектом которой является ускорение обработки данных. Этот процесс включает в себя множество важных улучшений, направленных на более эффективное использование ресурсов и минимизацию времени ответа системы на запросы. В этой статье я поделюсь несколькими проверенными методами, которые могут значительно ускорить работу вашего веб-сервиса.
Многие программисты в стремлении сделать приложение быстрее концентрируются на оптимизации кода и алгоритмов, выборе подходящих структур данных и оптимальных операций. Обычно это приводит к повышению производительности, часто повышая скорость оптимизированного кода, но незначительно.
Скромное увеличение связано с присущей скорости операций с памятью, и не следует ожидать значительных улучшений, если только исходный код не был очень неэффективен. Однако некоторые трудоемкие операции должны быть приоритетными для оптимизации, особенно операции ввода-вывода.
Независимо от того, работаете ли вы с файлами или взаимодействуете с базой данных, время выполнения этих задач всегда заметно по сравнению с операциями в памяти. Вы не можете существенно повлиять на процесс чтения данных из файла, но работа с базой данных находится под вашим непосредственным контролем. Как у разработчика у вас есть все возможности, чтобы существенно улучшить это взаимодействие.
Давайте рассмотрим следующие стратегии, которые помогут повысить эффективность работы с вашей базой данных и тем самым значительно повысить производительность вашей серверной службы.
Сегодня редко можно найти серверную веб-службу, которая не использует систему объектно-реляционного сопоставления (ORM) для взаимодействия с базой данных. Если вы стремитесь к первоклассным результатам, рассмотрите возможность настройки ORM. Хотя ORM эффективны и безошибочны, они предназначены для общего использования. Такая широкая применимость часто достигается за счет высокой производительности.
Помните, что ORM созданы для совместимости с различными базами данных, а это может означать потерю определенных преимуществ базы данных, которую вы выбрали для своего проекта. Например, как показано здесь, использование уникальных функций базы данных может значительно повысить скорость взаимодействия с базой данных (до 30 раз).
Вместо того чтобы полагаться исключительно на запросы по умолчанию, предоставляемые ORM, стоит создавать собственные оптимизированные запросы. Пользовательские запросы часто работают лучше, особенно в сценариях, включающих множественные соединения.
Ниже приведен простой пример в Spring JPA того, как можно повысить производительность с помощью запроса на соединение:
@Transactional @Lock(LockModeType.PESSIMISTIC_READ) @Query(value = """ SELECT e FROM EmployeeRecord e LEFT JOIN DepartmentRecord d ON e.departmentId = d.id WHERE e.departmentId = :departmentId; """) List<EmployeeRecord> findEmployeesByDepartmentId(Integer departmentId);
Использование сложных классов с вложенными объектами и глубокой иерархической системы может привести к существенной потере производительности системы. Часто нет необходимости запрашивать в базе данных всю вложенную структуру, особенно если не все классы в структуре используются полностью.
Хотя отложенная инициализация помогает избежать ненужных запросов к вложенным объектам, проблемы возникают, когда вложенный объект необходим, но не все его данные. Решением этой дилеммы является использование плоских классов данных.
Вам следует создать класс, предназначенный для сбора только необходимых данных полей из базы данных. Затем с помощью специального запроса к базе данных, включающего все необходимые соединения, выберите только те поля, которые действительно необходимы.
Этот подход не только повысит скорость запросов, но и сократит трафик данных из базы данных в ваш сервис.
Например, с помощью NamedParameterJdbcTemplate из Spring JPA можно создать плоский класс с необходимыми полями:
public record EmployeeDepartment(Integer employeeId, String employeeName, String departmentName) { }
Далее с помощью незамысловатого скрипта из основной и объединяемой таблиц собираются только нужные поля:
public List<EmployeeDepartment> employeeDepartments() { return template.query(""" SELECT employees.employee_id, employees.employee_name, departments.department_name FROM employees LEFT JOIN departments ON employees.department_id = departments.department_id; """, new MapSqlParameterSource(), employeeDepartmentMapper); }
Такой подход позволит существенно снизить нагрузку и сделать работу с данными гораздо более эффективной.
Следующим важным шагом в работе с данными является определение типов данных, основным из которых является Hot Data.
Горячие данные — это данные, которые сервис обрабатывает в режиме реального времени. Эти данные невозможно кэшировать, поскольку релевантность ответа веб-службы зависит от ее немедленного реагирования. Поэтому эти данные всегда должны быть актуальными. Сервис постоянно работает с Hot Data, постоянно записывая новые значения и извлекая информацию для своевременного обновления.
Чтобы работать с горячими данными максимально эффективно, крайне важно следить за тем, чтобы таблица, в которой они хранятся, оставалась максимально компактной.
Оставляйте как можно меньше столбцов
Ваша таблица должна содержать только те поля, которые активно используются, а все остальные данные хранить в отдельной таблице, сохраняя только идентификатор соответствующей строки. Такой подход позволяет получить доступ ко всем неиспользуемым полям, когда это необходимо, например, для целей отчетности, не перегружая основную таблицу этими данными.
Держите как можно меньше строк
Не сохраняйте строки, которые вам больше не нужны. Вместо этого переместите их в архивную таблицу. Такой подход позволяет вашим запросам быстрее находить нужные строки, сохраняя при этом все исторические данные в архиве. Автоматизация этого процесса с помощью простой задачи сводит к минимуму ваше участие в архивировании данных.
Постоянно обновляйте индексы
Не забудьте построить индексы. Индексы имеют решающее значение для быстрого поиска данных и часто упускаются из виду программистами. Правильная индексация может значительно сократить время поиска и потребление памяти вашей базы данных. Обязательно создайте индексы как для условий, так и для столбцов, участвующих в соединениях, включая составные индексы.
Откажитесь от использования внешних ключей
Использование внешних ключей создает дополнительную нагрузку на базу данных, чтобы гарантировать существование ключа в связанной таблице, что замедляет операции с данными, особенно при записи данных. Не поймите меня неправильно; хранить внешний ключ в такой таблице можно, а иногда даже необходимо, но лучше хранить ключ просто как простое значение.
Эти простые методы позволят вам максимизировать эффективность и полезность вашего стола.
Теплые данные — это данные, используемые для подготовки ответа, хотя их актуальность не оказывает критического влияния. Примеры включают описания продуктов или список доступных аксессуаров. При хранении таких данных уже нет необходимости внимательно следить за размером таблицы. Однако важно не упускать из виду создание индексов для этих таблиц, поскольку они часто используются для соединений.
Кэшировать теплые данные
Ключевым преимуществом Warm Data является возможность кэширования. После выполнения запроса вы можете сохранить данные в памяти, что уменьшит количество вызовов базы данных и ускорит вычисления. Однако помните, что кэш требует регулярных обновлений.
Установите разумный TTL (время жизни)
Установите правильное время жизни (TTL) для правильной работы. Обычно достаточно TTL около 90 секунд, что соответствует среднему времени, которое требуется пользователю для принятия решения и размещения заказа на веб-сайте. Всегда настраивайте TTL в соответствии с требованиями вашего сервиса.
Используйте меньшие классы для хранения «теплых» данных.
Для кэширования используйте компактные классы. Даже когда сделаны полноценные запросы и собраны все данные из таблиц, избегайте хранения всего в кеше. Храните только необходимые данные. Такой подход значительно снижает потребление памяти вашей серверной службой.
Настройка Warm Data не потребует много времени, а в конечном итоге вы добьетесь ощутимых результатов.
Холодные данные — это данные, которые редко меняются, но необходимы для реагирования. Примеры таких данных включают название или адрес магазина. Эти данные меняются очень редко и оказывают минимальное влияние на релевантность ответа.
Кэшируйте холодные данные или сохраняйте их в файле.
Этот тип данных всегда должен кэшироваться. Если размещение таких данных в памяти невозможно из-за их большого размера, рассмотрите возможность выгрузки их из базы данных и хранения в файлах в готовом к использованию формате. Разделение его на категории и выбор только наиболее часто используемых поможет сократить использование памяти. Кроме того, такой подход заметно повышает скорость по сравнению с получением данных из базы данных, поскольку исключает необходимость работы по сети.
Обновить кэш при триггере
Время жизни (TTL) для такого кэша обычно устанавливается равным 24 часам. Чтобы поддерживать обновление кеша, вам следует запланировать задачу или создать триггер, который отслеживает изменения в этих данных и инициирует обновление кеша. Например, если конечная точка вызывается для публикации или обновления холодных данных, должен быть активирован триггер для обновления кеша.
Эффективное управление холодными данными также является важной частью оптимизации эффективности реагирования, тем самым повышая общую производительность системы.
В заключение, оптимизация серверной части веб-сервиса зависит не только от оптимизации кода и алгоритмов. Улучшение взаимодействия с базой данных приведет к повышению эффективности и общей производительности службы. Реализация таких методов, как точная настройка запросов ORM (объектно-реляционное сопоставление), использование плоских классов данных, точное определение типов данных и внедрение стратегий кэширования, может значительно повысить производительность службы. Благодаря этим мерам веб-сервис в конечном итоге достигнет повышения эффективности, оперативности и улучшения общей функциональности.
Ключевые шаги :