У одного из моих работодателей мы работали над API REST (но это также относится и к SOAP). Клиент, который является пользовательским интерфейсом приложения, будет выполнять вызовы через Интернет (локальная сеть в типичных производственных развертываниях) в API. API будет делать вызовы в базу данных.
Одной из тем, которая повторяется в наших обсуждениях, является производительность: некоторые члены команды считают, что вам не нужно иметь несколько вызовов базы данных (обычно чтения) из одного вызова API из-за производительности; Вы должны оптимизировать их так, чтобы у каждого вызова API был (только) один вызов базы данных.
Но так ли это важно? Учтите, что пользовательский интерфейс должен выполнить сетевой вызов API; это довольно большой (порядка миллисекунд). Базы данных оптимизированы для того, чтобы хранить вещи в памяти и выполнять чтение очень и очень быстро (например, SQL Server загружает и сохраняет все в оперативной памяти и потребляет почти всю свободную оперативную память, если это возможно).
TLDR: действительно ли важно беспокоиться о множественных вызовах базы данных, когда мы уже совершаем сетевой вызов по локальной сети? Если так, то почему?
Чтобы было ясно, я говорю о порядке величины - я знаю, что это зависит от специфики (аппаратное обеспечение, выбор API и БД и т. Д.) Если у меня есть вызов, который занимает O (миллисекунды), выполняет оптимизацию для БД звонки, которые принимают на порядок меньше, на самом деле имеют значение? Или проблема не в этом?
Редактировать: для потомков, я думаю, довольно глупо заявлять, что нам нужно повысить производительность, комбинируя вызовы базы данных в этих условиях - особенно с отсутствием профилирования. Однако это не мое решение, будем ли мы это делать или нет; Я хочу знать, что стоит за мыслью, что это правильный способ оптимизации вызовов веб-API.
источник
Ответы:
Логика
В теории вы правы. Однако есть несколько недостатков с этим обоснованием:
Из того, что вы заявили, неясно, действительно ли вы тестировали / профилировали свое приложение. Другими словами, знаете ли вы , что передача по сети из приложения в API - самый медленный компонент? Поскольку это интуитивно понятно, легко предположить, что это так. Тем не менее, при обсуждении производительности, вы никогда не должны предполагать. У моего работодателя я лидер по производительности. Когда я впервые присоединился, люди продолжали говорить о CDN, репликации и т. Д., Основываясь на интуиции о том, какими должны быть узкие места. Оказывается, самыми большими проблемами с производительностью были плохо выполняемые запросы к базе данных.
Вы говорите, что поскольку базы данных хороши для извлечения данных, база данных обязательно работает с максимальной производительностью, используется оптимально, и ничего нельзя сделать, чтобы улучшить ее. Другими словами, базы данных спроектированы так, чтобы быть быстрыми, поэтому мне никогда не придется беспокоиться об этом. Еще одна опасная линия мышления. Это все равно, что сказать, что машина должна двигаться быстро, поэтому мне не нужно менять масло.
Такое мышление предполагает один процесс за раз, или, другими словами, без параллелизма. Предполагается, что один запрос не может влиять на выполнение другого запроса. Совместно используемые ресурсы, такие как дисковый ввод-вывод, пропускная способность сети, пулы соединений, память, циклы ЦП и т. Д. Следовательно, сокращение использования общего ресурса одним вызовом базы данных может предотвратить замедление других запросов. Когда я впервые присоединился к своему нынешнему работодателю, руководство полагало, что настройка 3-секундного запроса к базе данных была пустой тратой времени. 3 секунды это так мало, зачем тратить на это время? Разве нам не лучше с CDN или компрессией или чем-то еще? Но если я смогу выполнить 3-секундный запрос за 1 секунду, скажем, с помощью добавления индекса, это на 2/3 меньше блокирования, на 2/3 меньше времени, занимаемого потоком, и, что более важно, меньше данных, считываемых с диска,
Теория
Существует распространенное мнение, что производительность программного обеспечения зависит только от скорости .
С точки зрения скорости, вы правы. Система работает так же быстро, как ее самый медленный компонент. Если вы профилировали свой код и обнаружили, что Интернет - самый медленный компонент, то все остальное, очевидно, не самая медленная часть.
Однако, учитывая вышесказанное, я надеюсь, вы увидите, как конфликт ресурсов, отсутствие индексации, плохо написанный код и т. Д. Могут привести к неожиданным различиям в производительности.
Предположения
Последняя вещь. Вы упомянули, что вызов базы данных должен быть дешевым по сравнению с сетевым вызовом из приложения в API. Но вы также упомянули, что приложение и серверы API находятся в одной локальной сети. Таким образом, они не сопоставимы как сетевые вызовы? Другими словами, почему вы предполагаете, что передача API на несколько порядков медленнее, чем передача базы данных, когда они имеют одинаковую доступную пропускную способность? Конечно, протоколы и структуры данных разные, я понимаю, но я оспариваю предположение, что они различаются на несколько порядков.
Откуда это чертовски
Весь этот вопрос о «множественных» или «единичных» вызовах базы данных. Но неясно, сколько их несколько. Из-за того, что я сказал выше, как общее практическое правило, я рекомендую делать как можно меньше вызовов базы данных. Но это только эмпирическое правило.
Вот почему:
TL; DR
Да, но только в определенной степени. Вы должны стараться свести к минимуму количество обращений к базе данных, когда это целесообразно, но не объединяйте вызовы, которые не имеют ничего общего друг с другом только ради их объединения. Кроме того, избегайте вызова базы данных в цикле любой ценой.
источник
Похоже, ваша команда оптимизирует, прежде чем у них есть причина. Вы измерили время для выполнения этих запросов? Скорее всего, применение этой парадигмы приведет к ухудшению производительности для конечного пользователя, поскольку обратные вызовы к веб-серверу будут иметь гораздо большую задержку, чем время соединения между веб-сервером и базой данных. Кроме того, большинство веб-браузеров будут устанавливать только 2 одновременных подключения к одному веб-серверу, поэтому для сложных страниц вы, скорее всего, столкнетесь с узким местом.
В любом случае решения по оптимизации не должны приниматься без данных для их поддержки. Измерьте это и выясните, что лучше для вашего приложения.
источник
Мы не можем вам сказать.
Мы не знаем, как выглядят ваши запросы. Мы не знаем, сколько времени они занимают. Мы не знаем, сколько накладных расходов связано с каждым запросом к вашему API-серверу. Мы не знаем, как географически рассредоточены ваши клиенты. И т.п.
Если это сценарий, который требует оптимизации, и в котором вы можете решить, следует ли разделить или объединить вызовы вместе, вам нужно сравнить его двумя способами : решить, для чего вы оптимизируете (задержка пользовательского интерфейса, загрузка ЦП сервера, конкуренция, и т. д.) и выберите тот, который лучше достигает цели оптимизации.
Кроме того, я могу добавить с относительной уверенностью только одно :
В рамках одного запроса вы должны выполнить все запросы, необходимые для построения ответа.
Другими словами, если ответ не может быть сгенерирован до тех пор, пока не будут выполнены все N запросов, разделять их обычно бессмысленно. Если вы можете генерировать значимые результаты, промежуточные или полные, после каждого запроса начните тестирование.
источник
Две мысли:
Во-первых, потребителю, использующему API, он делает один вызов для выполнения задачи. То, что происходит после того, как ваш сервер получил запрос на выполнение запроса, не должно быть таким жестким. Если этот один звонок от потребителя требует 10 вспомогательных элементов, чтобы собрать данные и вернуть их, то это должно быть приемлемым.
Второе: видите ли вы реальную проблему с производительностью базы данных для рассматриваемого процесса? Мой опыт показал, что частая попытка объединить все аспекты запроса к базе данных в один вызов может привести к менее эффективному вызову, чем просто три или четыре запроса данных. Современные базы данных очень эффективны в планах кэширования и выполнения. Часто, когда вы пытаетесь сделать слишком много, вы увидите процедуры с курсорами (очень плохо для производительности, потому что данные обрабатываются построчно, а не как набор сразу) и код, который приводит к менее эффективному плану, чем если бы вы нарушали вызов в несколько небольших простых шагов.
Из простой организации кода я согласен, что каждый вызов API должен вызывать одну хранимую процедуру (или функцию db), которая, в свою очередь, отвечает за заполнение запроса. Там может быть более одного шага в процедуре.
источник
SELECT
с.Если база данных находится на сервере, отличном от вашей службы REST, каждый вызов базы данных будет приводить к передаче данных в обе стороны, что может значительно снизить производительность:
Однажды я наблюдал, как один вызов веб-сервиса транслировался примерно в 500 запросов к базе данных - вряд ли это было проблемой, когда и веб-сервис, и база данных расположены на одном компьютере, но время отклика составляло 6-7 секунд, когда они находились на разных машины.
Очевидно, что 500 обращений к базе данных довольно экстремально. Я не уверен, каковы ваши требования к производительности, но, как правило, я бы сказал, что если вы выполняете менее 10 запросов к базе данных на один вызов REST, вы не должны испытывать значительного снижения производительности.
источник
У нас есть пара приложений, которые очень, очень болтливы. Существует база данных для каждого. Не замужем. Маленький. Вещь. Обслуживание справочных данных снова и снова и снова является основной частью рабочей нагрузки в системе. Все это планирование рабочих потоков, получение и удаление блокировок, проверка кэша плана и т. Д. Суммируются, даже если нет фактического дискового ввода-вывода. Конфликт выше, потому что транзакции должны удерживать блокировки между несколькими вызовами БД, поэтому пропускная способность намного ниже, чем могла бы быть. Этим командам сейчас приходится покупать новые, очень дорогие серверы БД из-за этого.
Таким образом, хотя большая часть прошедшего времени в текущей конфигурации вашей системы занята вызовами API REST, игнорирование производительности на уровне БД сохраняет проблемы на будущее.
источник
Представленный путь оптимизации - просто неправильный взгляд на вещи.
Вызовы API должны быть атомарными. Другими словами, я должен быть в состоянии сделать 1 вызов веб-API для выполнения нужного мне действия. Будь то выборка данных, обновление записи или что-то еще. НИКОГДА не следует предпринимать более одного звонка, чтобы вызвать действие. И попытки использовать транзакции между несколькими вызовами следует избегать, как чума.
Иногда одно действие довольно сложно. Например, выборка данных, которые объединяются из нескольких источников: опять же, это должен быть один вызов. Либо все работает, либо все не работает.
Теперь сказать, что один вызов API должен выполнять только один запрос к БД, немного глупо. Как вы указали, накладные расходы на распределение вызовов по сети часто на порядок дороже с точки зрения общего времени.
Я могу несколько понять их утверждение, что один запрос может выполняться быстрее, чем несколько; но это создает ложное впечатление, поскольку игнорирует общую БД и нагрузку на сеть. Только путем профилирования различных способов извлечения данных из БД вы можете понять, в чем на самом деле проблема. Я уверен, что у каждого есть история, когда определенный запрос, выполненный в 100 раз чаще, чем ожидалось, убивал систему, пока не был установлен правильный индекс ...
В конце концов, вы не сможете убедить их просто поговорить. Установите контрольный пример для обоих подходов и профилируйте их. Обратите внимание на общее время получения необходимых данных, объем генерируемого сетевого трафика, количество и время вызовов базы данных и т. Д. Используйте целостный подход - это означает, что вы смотрите на всю систему - и у вас должно получиться много Данные, чтобы съесть ворону или показать им золотой путь.
источник