В статье мы рассмотрим основные подходы и практики для оптимизации производительности API, применяемые в МТС Exolve, поймем, как избежать подобных последствий и обеспечить стабильную работу сервисов.

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

Например, в сфере электронной коммерции замедление работы сайта всего на одну секунду может привести к ежегодным потерям в размере 1,6 млрд долларов.

Анализ текущего состояния и прогноз нагрузки

Анализ текущего состояния и прогноз нагрузки — это основа для эффективной работы API в условиях роста и изменения потребностей. Регулярное выполнение этих процессов позволяет избежать сбоев, оптимизировать затраты и обеспечить высокое качество сервиса.

Анализ проводится в несколько этапов.

Мониторинг API

В условиях высокой нагрузки на API выявление и устранение проблем — ключевые факторы для поддержания стабильной работы сервисов. Без эффективного мониторинга компании рискуют столкнуться с серьезными последствиями: финансовые потери, ущерб репутации и юридические последствия.

Есть несколько решений, доступных в России. Все они следят за работой API, оповещают о сбоях и выдают отчет о проблемах.

  • Zabbix — открытое и бесплатное решение для мониторинга сетей и приложений, широко используемое в России.

  • Monq — российская система корпоративного ИТ-мониторинга нового поколения.

  • Prometheus — система мониторинга с открытым исходным кодом, популярная среди разработчиков. В ней можно настроить оповещения об отклонениях от нормы.

  • ELK Stack (Elasticsearch, Logstash, Kibana) — набор инструментов для сбора, хранения и отображения логов и метрик.

  • AppDynamics — коммерческое решение для мониторинга производительности приложений и API. В России недоступно, поэтому не столь известное.

Специалисты МТС Exolve при выборе приложения рекомендуют учитывать потребности и масштабы бизнеса. Zabbix или Monq подойдут для малого и среднего бизнеса, крупной компании стоит присмотреться к Prometheus или ELK Stack.

Логирование запросов

Это процесс записи информации о каждом обращении к API. Логи содержат данные о времени запроса, типе операции, адресе клиента, статусе ответа, времени обработки и других аспектах работы API. Эти данные записываются в специальные файлы или системы хранения для последующего анализа.

Как организовать логирование запросов

  1. Выберите инструмент логирования.

Вот несколько распространенных решений:

  • Fluentd — вариант для сбора, фильтрации и отправки логов в различные хранилища.

  • Logstash (часть ELK-стека) — высокопроизводительный инструмент для обработки и анализа логов.

  • Graylog — система, позволяющая удобно работать с логами в реальном времени.

Эксперты МТС Exolve составили небольшую таблицу, чтобы упростить подбор инструмента:

Инструмент

Ключевые особенности

Когда выбрать

Fluentd

Легковесность, масштабируемость, простота интеграции

Если вам нужен простой и легкий инструмент для сбора и передачи логов.

Logstash

Сложные преобразования данных, часть ELK

Если вы уже используете ELK или требуется мощный ETL для логов.

Graylog

Удобный интерфейс, поиск и визуализация

Если вам важен удобный интерфейс для анализа логов и нет необходимости в ELK.

При этом учитывайте, что Fluentd и Logstash работают в реальном времени, а Graylog обрабатывает логи после их сохранения.

  1. Настройте сбор данных.

Для простого API достаточно записывать информацию в текстовые файлы. В более сложных системах логи отправляются в централизованные системы, где их легче анализировать и визуализировать.

  1. Стандартизируйте формат логов.

Убедитесь, что все записи логов имеют одинаковую структуру. Например, каждая запись может включать:

  • Время запроса.

  • URL конечной точки API.

  • Код статуса ответа.

  • Время выполнения операции.

  • IP-адрес клиента.

  1. Анализируйте данные.

Регулярно просматривайте логи, чтобы выявлять: ошибки (например, частые HTTP-коды 4xx или 5xx); запросы с долгим временем обработки; необычные пики нагрузки.

  1. Визуализируйте результаты.

Используйте инструменты вроде Kibana или Grafana, чтобы создавать удобные дашборды. Графики и таблицы помогут быстро увидеть проблемные зоны.

  1. Автоматизируйте оповещения.

Настройте систему так, чтобы она автоматически отправляла уведомления при обнаружении аномалий, например, резком увеличении количества ошибок или превышении допустимого времени обработки запросов. За основу можно взять наш прошлый гайд.

Например, если ваш API начал отвечать медленно, анализ логов может показать, что одна из функций, например, обработка платежей, выполняется дольше остальных. Это может быть связано с перегрузкой базы данных или неэффективным SQL-запросом. Логирование позволяет быстро локализовать проблему и устранить её, не затрагивая остальные функции API.

Прогнозирование роста нагрузки

Это процесс предсказания, как изменится объем запросов к API в будущем. В основе анализ данных о текущей активности, сезонных колебаниях и других факторах, которые влияют на использование сервиса.

Например, если ваш API обслуживает интернет-магазин, вы можете ожидать резкий рост запросов во время распродаж или праздничных акций. Анализируя прошлые данные, можно предсказать такие всплески и подготовить инфраструктуру к увеличению нагрузки.

Как это сделать

  1. Для начала важно собирать данные о работе API. Потребуется узнать: количество запросов в разное время суток, дни недели, месяцы; параметры запросов; моменты перегрузок и сбоев. Помогут автоматизировать сбор этих данных инструменты: Logstash, Fluentd или Prometheus.

  2. Далее проводится анализ данных с использованием базовых статистических методов: скользящие средние; сезонный анализ; коэффициенты корреляции.

  3. При большом объеме данных или сложных зависимостях, поможет машинное обучение. Его проведение включает обучение (линейная регрессия, LSTM), оценку и использование модели.

Архитектурные подходы к оптимизации

Архитектурные подходы к оптимизации — это изменения в структуре и логике построения API, повышающие его скорость работы, устойчивость к нагрузкам, помогающие масштабировать систему.

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

Масштабирование инфраструктуры

Это процесс увеличения вычислительных мощностей API для обработки растущего числа запросов. Этот подход необходим для поддержания стабильной работы и предотвращения перегрузок, особенно в периоды пиковых нагрузок.

Масштабирование может быть двух видов: вертикальное (увеличение мощности серверов) и горизонтальное (добавление новых серверов). Вертикальный проще реализовать, но он ограничен физическими возможностями серверов. Горизонтальный подобных ограничений не имеет, но управлять такой системой намного сложнее. В МТС Exolve работает горизонтальный способ.

Микросервисная архитектура

Суть микросервисной архитектуры в том, что система проектируется как совокупность небольших независимых составляющих (микросервисов). Они работают автономно и выполняют разные задачи.

Этот подход помогает справляться с высокой нагрузкой и упрощает управление сложными системами. Вместо одного большого приложения есть много маленьких и гибких, взаимодействующих через API. Такие системы намного устойчивее к высоким нагрузкам, чем монолит.

Сейчас популярно решение, которое называют оркестрацией контейнеров. Контейнер – это легковесная виртуализированная среда, включающая сам микросервис, библиотеки, настройки, среду выполнения и минимальный набор системных инструментов и файлов, необходимых для работы.

В России этот вариант реализуется с использованием локальных облачных провайдеров (Яндекс.Облако, VK Cloud).

Кэширование данных

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

Внедрение кэширования (Redis, Memcached)

Кэширование можно реализовать с помощью специализированных инструментов Redis и Memcached.

  1. Redis — это хранилище данных в оперативной памяти. Поддерживает сложные структуры данных, такие как списки, множества и хэши. Отлично подходит для хранения временных данных, таких как сессии пользователей или результаты сложных вычислений.

  2. Memcached — быстрое кэш-хранилище для строк и объектов. Идеально для кэширования результатов запросов к базе данных или небольших данных.

Подходы к кэшированию

Рассмотрим три варианта кэширования: на уровне запросов, на уровне данных и на уровне заголовков.

Кэширование на уровне запросов – это сохранение результатов запросов API. Если повторяется запрос с одинаковыми параметрами, API возвращает готовый результат из кэша. Так, если пользователь запрашивает список товаров, API возвращает сохраненный результат, не выполняя повторный запрос к базе данных.

Кэширование на уровне данных – это сохранение данных из базы в кэше, чтобы API мог быстро их извлекать. Например, информация о популярных товарах сохраняется в Redis, и API обращается к базе данных только при обновлении списка.

Кэширование на уровне заголовков – это указание клиентам (например, браузерам или CDN), как долго сохранять ответы от API. Например, если API возвращает статический список категорий товаров, заголовок Cache-Control: max-age=3600 сообщает клиенту, что данные актуальны в течение часа.

Использование очередей сообщений

Очереди сообщений — это технология для передачи задач между разными составляющими системы в асинхронном режиме.

API, вместо выполнения тяжёлой задачи, отправляет сообщение с инструкцией в очередь, а обработка задачи выполняется позже, другим компонентом.

Сервисы для организации очередей: RabbitMQ и Apache Kafka.

RabbitMQ подходит для большинства задач, обеспечивает гарантированную доставку сообщений и поддерживает несколько потребителей.

Apache Kafka — это система потоковой обработки данных, разработанная для высоконагруженных систем. Подходит для работы с большими объемами сообщений. Специалисты МТС Exolve рекомендуют этот вариант в ситуациях, когда требуется сохранять порядок сообщений или масштабировать обработку.

Оптимизация кода и баз данных

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

Что такое оптимизация кода и баз данных

Оптимизация кода — процесс улучшения логики и алгоритмов приложения для повышения их скорости и снижения использования ресурсов.

Оптимизация баз данных — работа по улучшению структуры данных, запросов и индексов для ускорения операций чтения, записи и обработки данных.

Рассмотрим основные способы оптимизации.

Ускорение обработки запросов

Позволяет снизить время отклика системы и сделать работу API стабильнее при большой нагрузке. Рассмотрим два ключевых подхода: рефакторинг и оптимизацию алгоритмов, а также использование асинхронных методов работы.

Рефакторинг и оптимизация алгоритмов

Рефакторинг — процесс улучшения структуры кода без изменения его поведения. Оптимизация алгоритмов направлена на повышение эффективности выполнения операций, заложенных в коде.

Он сокращает время выполнения операций, уменьшая задержки в API, уменьшает объем потребляемых ресурсов, таких как процессорное время и память, повышает читаемость и поддержку кода, что упрощает работу команды разработчиков.

Представим, что API подсчитывает сумму значений в массиве. Вместо многократного перебора массива при рефакторинге используется кэш или предварительные вычисления, чтобы ускорить процесс.

Использование асинхронных методов работы

Асинхронность позволяет API обрабатывать несколько запросов одновременно, не ожидая завершения длительных операций (например, чтения данных из базы или внешнего сервиса).

Такой подход повышает пропускную способность API, позволяя обслуживать больше запросов одновременно, сокращает время ожидания для пользователей, так как ресурсы используются более эффективно.

Разберемся, как это сделать.

Асинхронная обработка в Python (asyncio)

  • Python предоставляет библиотеку asyncio, которая позволяет писать асинхронный код.

  • Вместо последовательного выполнения операций API может запускать их параллельно.

Пример:
Если API отправляет несколько запросов к внешним сервисам, можно использовать asyncio.gather() для их выполнения одновременно.

import asyncio  
async def fetch_data(url): 
	# Имитация получения данных 
	await asyncio.sleep(1) 
	return f"Data from {url}"  
async def main(): 
	urls = ["http://example1.com", "http://example2.com"] 
	results = await asyncio.gather(*(fetch_data(url) for url in urls)) 
	print(results)  
asyncio.run(main()) 

Асинхронная обработка в Node.js

  • Node.js изначально построен на асинхронной модели. Использование async/await и событийного цикла позволяет эффективно обрабатывать запросы.

  • Асинхронные библиотеки (например, для работы с базами данных) упрощают работу с большими объемами данных.

Пример:
В Node.js можно асинхронно запрашивать данные из базы:

const fetchData = async (db, query) => { 
	const data = await db.query(query); 
	return data; 
}; 
const processRequests = async () => { 
	const results = await Promise.all([ 
    	fetchData(db, "SELECT * FROM users"), 
    	fetchData(db, "SELECT * FROM orders") 
	]); 
    console.log(results); 
}; 
processRequests();

Работа с базами данных

Базы данных — это ключевой компонент API, который отвечает за хранение, обработку и предоставление данных. При высокой нагрузке именно взаимодействие с БД становится «узким местом», замедляя API. Оптимизация позволяет существенно улучшить производительность API и обеспечить стабильность системы.

Оптимизация запросов к БД

Это процесс улучшения их структуры и выполнения. Ключевые инструменты для этого — индексация и денормализация.

Индексы позволяют базе данных быстро находить нужные данные. Например, если вы часто фильтруете таблицу по полю email, создайте индекс для этого столбца.

Денормализация — это преднамеренное добавление избыточности в данные для ускорения чтения. Например, вместо выполнения сложного запроса с несколькими таблицами (JOIN) можно хранить результаты этих операций в одной таблице.

Пример:
В интернет-магазине данные о товарах и их категориях можно хранить в одной таблице, чтобы сократить количество соединений.

Было:

SELECT products.name, categories.name 
FROM products 
JOIN categories ON products.category_id = categories.id; 

Стало:

SELECT product_name, category_name FROM products_with_categories; 

Разделение чтения и записи через репликацию

Репликация — процесс копирования данных с основного (мастер) сервера базы данных на вторичные (слейв) серверы. Это позволяет разделить нагрузку: мастер обрабатывает запросы на запись, а слейвы — запросы на чтение.

При использовании репликации важно учесть задержку между мастером и слейвами, чтобы избежать ситуаций, когда новые данные еще не успели реплицироваться.

Применение NoSQL баз для высоконагруженных операций

NoSQL базы данных — это системы, которые не используют традиционные реляционные модели (таблицы и SQL). Они оптимизированы для обработки больших объемов данных с высокой скоростью. Вот две основных, что используются чаще других:

  1. ClickHouse подходит для аналитики и обработки больших объемов данных. Например, сбор статистики о посещениях сайта или работе API. Отличается высокой скоростью обработки агрегированных запросов, поддерживает сжатие данных для экономии места.

  2. Tarantool — in-memory база данных, которая подходит для хранения часто используемых данных. Обеспечивает быстрое чтение и запись благодаря хранению данных в оперативной памяти, поддерживает Lua-скриптов для обработки данных.

Обеспечение устойчивости API

Это создание системы, которая продолжает работать, даже если сталкивается с ошибками, неожиданными нагрузками или сбоями в инфраструктуре. Можно считать ключевым аспектом разработки, поскольку отказ API может повлиять на репутацию компании, пользовательский опыт и финансовые показатели.

Устойчивость означает, что API остаётся доступным и функциональным, даже если часть системы выходит из строя. Это достигается за счёт использования надёжных архитектурных решений, инструментов мониторинга и механизмов автоматического восстановления.

Политики ограничения запросов (Rate Limiting)

Rate Limiting — это механизм, который ограничивает количество запросов, которые клиент (например, пользователь или приложение) может отправить за заданный период времени.

Разберемся, как внедрить Rate Limiting.

  • Ограничение количества запросов с одного IP позволяет регулировать нагрузку от отдельных пользователей.

Каждому IP-адресу назначается квота запросов. Например, 100 запросов в минуту. После достижения лимита запросы блокируются или клиенту возвращается сообщение об ошибке (например, статус 429 Too Many Requests).

Пример инструмента.

NGINX. В NGINX можно настроить Rate Limiting через директиву limit_req.

limit_req_zone $binary_remote_addr zone=api_limit:10m rate=100r/m; 
server { 
	location /api/ { 
        limit_req zone=api_limit burst=10 nodelay; 
	} 
} 
  • Внедрение механизма очередей запросов временно сохраняет избыточные запросы, чтобы обрабатывать их последовательно, а не отклонять.

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

Пример кода на Python с использованием Redis и очередей:

r = redis.Redis() 
def rate_limiter(ip, max_requests, time_window): 
	key = f"rate_limit:{ip}" 
	requests = r.incr(key) 
	if requests == 1: 
        r.expire(key, time_window) 
	if requests > max_requests: 
    	return False  # Запрос отклонен 
	return True  # Запрос разрешен 
# Пример обработки запросов 
def handle_request(ip): 
	if rate_limiter(ip, max_requests=10, time_window=60): 
    	print("Запрос обработан") 
	else: 
    	print("Превышен лимит запросов") 
handle_request("192.168.1.1")

Механизмы повторных попыток (Retry Policies)

Это стратегии обработки временных сбоев в API, которые позволяют клиенту повторно отправить запрос, если предыдущая попытка завершилась ошибкой.

Как реализовать Retry Policies

Первый вариант — через реализацию стратегии повторных запросов при сбоях. Здесь возможны несколько вариантов. Первый (фиксированные интервалы) — когда повторные запросы отправляются через равные промежутки времени. Например, каждые 2 секунды. Второй (экспоненциальная задержка) — когда интервалы между запросами увеличиваются в геометрической прогрессии (например, 1 секунда, 2 секунды, 4 секунды и так далее). Третий (случайная задержка), при котором в интервалы вносится случайный элемент, чтобы уменьшить риск перегрузки системы.

Пример кода на Python с использованием экспоненциальной задержки

def make_request_with_retry(url, max_retries=5): 
	retries = 0 
	while retries < max_retries: 
        try: 
            response = requests.get(url) 
        	if response.status_code == 200: 
                return response 
    	except requests.exceptions.RequestException: 
            pass  # Игнорируем временные ошибки 
    	retries += 1 
    	delay = 2 ** retries  # Экспоненциальная задержка 
        time.sleep(delay) 
	raise Exception("Не удалось выполнить запрос после нескольких попыток") 
 
response = make_request_with_retry("https://example.com/api")  

Через контроль за переизбытком повторных запросов 

В этом варианте устанавливается максимальное количество повторных запросов (например, не более 5 попыток). Если запрос успешен, все предыдущие попытки игнорируются, и лимиты обновляются. При этом система отслеживает время, прошедшее между попытками, и блокирует повторные запросы, если они слишком частые.

Для отслеживания количества попыток каждого клиента можно использовать Redis, а контролировать частоту запросов помогут NGINX или AWS API Gateway.

Пример внедрения с использованием Redis

r = redis.Redis() 
def is_retry_allowed(client_id, max_retries, retry_window): 
	key = f"retry:{client_id}" 
	retries = r.incr(key) 
	if retries == 1: 
        r.expire(key, retry_window) 
	return retries <= max_retries 
client_id = "user123" 
if is_retry_allowed(client_id, max_retries=5, retry_window=60): 
	print("Повторный запрос разрешен") 
else: 
	print("Превышено количество попыток")  

Обработка пиковых нагрузок

Пиковые нагрузки — это моменты, когда на API поступает значительно больше запросов, чем обычно. Такие всплески могут возникать из-за маркетинговых акций, неожиданных событий или вирусного роста пользователей. Чтобы справиться с такими нагрузками, необходимо заранее подготовить стратегию, которая обеспечит устойчивую работу системы.

Circuit Breaker

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

Пример реализации в библиотеке Resilience4j (Java)

CircuitBreakerConfig config = CircuitBreakerConfig.custom() 
	.failureRateThreshold(50)  // Лимит ошибок, например 50% 
	.waitDurationInOpenState(Duration.ofSeconds(10))  // Время блокировки 
	.build();  
CircuitBreakerRegistry registry = CircuitBreakerRegistry.of(config); 
CircuitBreaker circuitBreaker = registry.circuitBreaker("myAPI");  
Supplier<String> decoratedSupplier = CircuitBreaker 
    .decorateSupplier(circuitBreaker, () -> callApi());  
String result = Try.ofSupplier(decoratedSupplier).getOrElse("Service unavailable");  

Динамическое масштабирование

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

Локальные особенности и импортозамещение

В последние годы использование зарубежных технологий для разработки и поддержки API сталкивается с растущими ограничениями. Разрыв связей с глобальными провайдерами вынуждает переходить на отечественные решения.

VK Cloud и Яндекс.Облако

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

  • VK Cloud подходит для размещения серверов API, автоматического масштабирования ресурсов и создания надежной инфраструктуры.

  • Яндекс.Облако обеспечивает инструменты для работы с базами данных, серверless-вычислений и сетей.

Tarantool

Это высокопроизводительная in-memory база данных и сервер приложений. Tarantool идеально подходит для работы с API, которым требуется обработка данных с низкими задержками.

  • Используется для кэширования, транзакционной обработки и гибкого масштабирования.

  • Удобно интегрируется с микросервисной архитектурой.

ClickHouse

Аналитическая база данных, разработанная в Яндексе.

  • Прекрасно подходит для обработки больших объемов аналитических данных, таких как логи запросов API.

  • Обеспечивает высокую скорость запросов благодаря колонночному хранению.

Высоконагруженные API требуют постоянного внимания и гибкости. Регулярный мониторинг, улучшение архитектуры и использование подходящих инструментов позволяют справляться с нагрузками, сохраняя качество сервиса. Успех заключается в умении комбинировать решения и подстраивать их под реальные потребности вашего бизнеса.

Автор: Роман Андреев


Подписывайтесь на наш Хаб, следите за новыми гайдами и получайте приз

Каждый понедельник мы случайным образом выбираем победителей среди новых подписчиков нашего Хабр-канала и дарим крутые призы от МТС Exolve: стильные рюкзаки, лонгсливы и мощные беспроводные зарядки. Победители прошлых розыгрышей и правила.

Комментарии (6)


  1. RealLazyCat
    05.02.2025 07:12

    AppDynamics в России недоступен, поправьте.
    В целом как обзорная, "каркасная" статья для джунов - нормально, спасибо, положил в раздел "для новых сотрудников-джунов"


    1. michabramov Автор
      05.02.2025 07:12

      Благодарю, поправили


  1. Nn111
    05.02.2025 07:12

    Хех, буквально пару дней назад клиент обратился за помощью - сервис перестал работать. Он работает через другой побольше через апи.

    Так вот оказалось, что те, у кого они брали по апи в целях снижения нагрузки подключили cloudflare на точку входа. Думаю уровень программистов вам понятен)

    И ещё вспомнилось. Тоже относительно недавно было. Тоже перестало работать подключение к стороннему сервису по апи. Оказалось, они тоже там нагрузку снизили и отсеяли мои запросы по юзер агенту. Там в нем было написано 'bot'.

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


  1. savostin
    05.02.2025 07:12

    Хорошая шпаргалка для собеседования. Только бы ошибки поправить, типа NoSQL быстрее SQL, Clickhouse - noSQL и пр.


    1. michabramov Автор
      05.02.2025 07:12

      В статье на 100% не дали такого ответа :) потому что скорость зависит от задачи. Например, если нужна скорость записи и горизонтальное масштабирование, лучше сработает NoSQL.
      Если важны сложные аналитические запросы и транзакционная целостность, то лучше SQL. Если нужны аналитика и быстрые агрегатные операции, то лучше ClickHouse, а если важны частые обновления, ключевой доступ - NoSQL.


  1. cmyser
    05.02.2025 07:12

    Прям после прочтения цитата напрашивается

    "Если в вашем приложении нужно для скорости оптимизировать код и алгоритмы значит ваше приложение в очень хорошем состоянии"

    Обычно проблемы далеко не в коде и алгоритмах а гораздо сложнее и запутаннее