Чи дійсно значущі дзвінки бездротової бази даних за допомогою мережевого дзвінка для веб-API?


16

У одного з моїх роботодавців ми працювали над REST (але це стосується і SOAP) API. Клієнт, який є інтерфейсом програми, здійснював дзвінки через Інтернет (локальна мережа в типових виробничих розгортаннях) до API. API здійснював дзвінки до бази даних.

Однією з тем, що повторюється в наших дискусіях, є ефективність: деякі люди в команді вважають, що вам не слід мати кілька дзвінків до бази даних (як правило, читає) з одного дзвінка API через ефективність; ви повинні оптимізувати їх так, щоб кожен виклик API мав (точно) один виклик бази даних.

Але чи це насправді важливо? Подумайте, що інтерфейс повинен здійснити мережевий дзвінок в API; це досить великий (порядок мілісекунд). Бази даних оптимізовані, щоб зберігати речі в пам'яті та виконувати зчитування дуже, дуже швидко (наприклад, SQL Server завантажує і зберігає все в оперативній пам’яті і споживає майже всю вашу вільну оперативну пам’ять, якщо це можливо).

TLDR: Чи дійсно важливо турбуватися про багаторазові дзвінки до бази даних, коли ми вже здійснюємо мережевий дзвінок через локальну мережу? Якщо так, то чому?

Щоб було зрозуміло, я говорю про порядок розміру - я знаю, що це залежить від специфіки (апаратне обладнання машини, вибір API та БД тощо). Якщо у мене є дзвінок, який займає O (мілісекунди), робить оптимізацію для БД дзвінки, які приймають на порядок менше, насправді мають значення? Або в цьому є більше проблеми, ніж ця?

Редагувати: для нащадків, я вважаю, що досить смішно висловлювати претензії, що нам потрібно підвищити продуктивність, комбінуючи дзвінки до бази даних за цих обставин - особливо з відсутністю профілювання. Однак, це не моє рішення, робимо ми це чи ні; Я хочу знати, що обґрунтовує думку про те, що це правильний спосіб оптимізації викликів веб-API.


Чи немає іншого мережевого дзвінка між шаром API та базою даних?
Увійти

4
Що показали ваші тести на терміни?
Дан Пішельман

@Sign Немає мережевого дзвінка між API та БД. Вони гарантовано будуть на одній машині, наскільки я розумію.
ashes999

@DanPichelman це теж я прошу. Здається, ніхто не приймає та проводить терміни виконання; ми просто отримуємо вимоги до "фіксації продуктивності в X, об'єднуючи всі дзвінки БД в один виклик".
ashes999

Відповіді:


25

Але чи це насправді важливо? Подумайте, що інтерфейс повинен здійснити мережевий дзвінок в API; це досить великий (порядок мілісекунд). Бази даних оптимізовані, щоб зберігати речі в пам'яті та виконувати зчитування дуже, дуже швидко (наприклад, SQL Server завантажує і зберігає все в оперативній пам’яті і споживає майже всю вашу вільну оперативну пам’ять, якщо це можливо).

Логіка

Теоретично ви праві. Однак у цього обґрунтування є кілька недоліків:

  1. З того, що ви заявили, незрозуміло, чи дійсно ви тестували / профілювали додаток. Іншими словами, чи ви насправді знаєте, що мережеві передачі від програми до API є найповільнішим компонентом? Оскільки це інтуїтивно, легко припустити, що це так. Однак, обговорюючи ефективність, ніколи не слід припускати. У мого роботодавця я є керівником ефективності. Коли я вперше приєднався, люди продовжували говорити про CDN, реплікацію тощо, грунтуючись на інтуїції про те, якими повинні бути вузькі місця. Виявляється, нашими найбільшими проблемами продуктивності були погано виконані запити до бази даних.

  2. Ви говорите, що тому, що бази даних хороші для отримання даних, що база даних обов’язково працює з максимальною продуктивністю, використовується оптимально, і нічого не можна зробити для її покращення. Іншими словами, бази даних розроблені так, щоб вони були швидкими, тому мені ніколи про це не потрібно хвилюватися. Ще одна небезпечна лінія мислення. Це як сказати, що машина має на увазі швидко рухатися, тому мені не потрібно міняти масло.

  3. Такий спосіб мислення передбачає поодинокий процес, або, кажучи іншим способом, не одночасно. Він передбачає, що один запит не може впливати на виконання іншого запиту. Ресурси є спільними, наприклад, введення / виведення диска, пропускна здатність мережі, пули підключення, пам'ять, цикли процесора тощо. Отже, зменшення використання загальним ресурсом виклику однієї бази даних може запобігти сповільненню інших запитів. Коли я вперше приєднався до свого теперішнього роботодавця, керівництво вважало, що налаштування 3-секундного запиту на базу даних - це марна трата часу. 3 секунди так мало, навіщо на це витрачати час? Чи не було б нам краще з CDN або стисненням чи чимось іншим? Але якщо я можу зробити 3-секундний запуск запиту за 1 секунду, скажімо, додавши індекс, тобто на 2/3 менше блокуючи, на 2/3 менше часу, зайнятого на зайняття потоку, і що ще важливіше, менше даних, що читаються з диска,

Теорія

Існує загальна думка, що продуктивність програмного забезпечення - це просто швидкість .

З чисто швидкої точки зору ви маєте рацію. Система лише така швидка, як і її найповільніша складова. Якщо ви профайлювали свій код і виявили, що Інтернет є найповільнішим компонентом, то все інше, очевидно, не найповільніша частина.

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

Припущення

Одне останнє. Ви згадали, що дзвінок до бази даних повинен бути дешевим порівняно з мережевим дзвінком від програми до API. Але ви також згадали, що програма та сервери API знаходяться в одній локальній мережі. Отже, чи не обидва вони порівнянні з мережевими дзвінками? Іншими словами, чому ви припускаєте, що передача API на порядок повільніше, ніж передача бази даних, коли вони мають однакову доступну пропускну здатність? Звичайно, протоколи та структури даних різні, я це розумію, але я заперечую припущення, що вони на порядок різні.

Там, де дістається маскі

Все це питання стосується "декількох" проти "єдиних" дзвінків до бази даних. Але незрозуміло, скільки їх кратно. Через те, що я говорив вище, я, як правило, рекомендую робити якомога менше дзвінків до бази даних. Але це лише велике правило.

Ось чому:

  1. Бази даних чудово читають дані. Вони є двигунами зберігання. Однак ваша логіка бізнесу живе у вашій програмі. Якщо ви прийняли правило, що кожен виклик API призводить до точно одного виклику бази даних, то ваша бізнес-логіка може опинитися в базі даних. Можливо, це нормально. Дуже багато систем це роблять. Але деякі ні. Йдеться про гнучкість.
  2. Іноді для досягнення гарної розв'язки потрібно розділити 2 виклики до бази даних. Наприклад, можливо, кожен запит HTTP направляється через загальний фільтр безпеки, який підтверджує з БД, що користувач має права на доступ. Якщо вони є, перейдіть до виконання відповідної функції для цієї URL-адреси. Ця функція може взаємодіяти з базою даних.
  3. Виклик бази даних у циклі. Ось чому я запитав, скільки кратно. У наведеному вище прикладі у вас було б 2 виклики до бази даних. 2 добре. 3 може бути добре. N непогано. Якщо ви викликаєте базу даних у циклі, тепер ви зробили продуктивність лінійною, а значить, це займе більше часу, ніж більше, ніж у вході циклу. Так категорично говорять, що час мережі API є найповільнішим, повністю не виходить аномалії, як, наприклад, 1% вашого трафіку займає тривалий час через ще не виявлений цикл, який викликає базу даних 10 000 разів.
  4. Іноді є речі, в яких ваша програма краще, наприклад, деякі складні розрахунки. Можливо, вам доведеться прочитати деякі дані з бази даних, зробити деякі обчислення, потім на основі результатів передати параметр на другий виклик бази даних (можливо, щоб записати деякі результати). Якщо ви об'єднаєте їх в один виклик (як збережена процедура) лише для того, щоб лише один раз викликати базу даних, ви змусили себе використовувати базу даних для того, на чому може бути кращим сервер додатків.
  5. Балансування завантаження: у вас є 1 база даних (імовірно) і кілька серверів додатків, збалансованих навантаженням. Таким чином, чим більше робота робить додаток, і тим менше буде база даних, тим простіше його масштабувати, оскільки додавати сервер додатків, як правило, простіше, ніж реплікацію бази даних. Виходячи з попередньої точки кулі, може мати сенс запустити SQL-запит, потім виконати всі обчислення в додатку, який розподіляється на декілька серверів, а потім записати результати, коли закінчите. Це може забезпечити кращу пропускну здатність (навіть якщо загальний час транзакції однаковий).

TL; DR

TLDR: Чи дійсно важливо турбуватися про багаторазові дзвінки до бази даних, коли ми вже здійснюємо мережевий дзвінок через локальну мережу? Якщо так, то чому?

Так, але лише певною мірою. Ви повинні намагатися мінімізувати кількість дзвінків до бази даних, коли це практично, але не комбінувати дзвінки, які не мають нічого спільного між собою лише заради їх поєднання. Крім того, уникайте дзвінків до бази даних у циклі за будь-яку ціну.


3

Здається, що ваша команда оптимізується, перш ніж у них є причина. Ви вимірювали час для виконання цих запитів? Швидше за все, ця парадигма призведе до зниження продуктивності для кінцевого користувача, оскільки зворотні поїздки до веб-сервера матимуть набагато більшу затримку, ніж час підключення від веб-сервера до бази даних. Крім того, більшість веб-браузерів здійснюватиме лише 2 одночасних з'єднання з одним веб-сервером, тому для складних сторінок ви, швидше за все, зіткнетесь із вузьким місцем.

У будь-якому випадку рішення щодо оптимізації не повинні прийматися без даних для їх резервного копіювання. Виміряйте це і з’ясуйте, що найкраще підходить для вашої програми.


1
Це хороший коментар щодо нашої недостатньої ефективності роботи, але не відповідає на моє запитання про те, чи можуть дзвінки БД хвилюватись, коли я вже має мережевий дзвінок.
ashes999

1
Взагалі, я виявив, що здійснення декількох дзвінків до бази даних не є проблемою. Це здебільшого через об'єднання з'єднань та малу затримку між БД та веб-сервером. Є момент, коли здійснювати купу різних db-дзвінків негативно вплине на продуктивність, але у мене немає важкого числа для вас. Все залежить від середовища та застосування. Тільки вимірювання дасть вам відповідь, яку ви шукаєте.
brianfeucht

Це не повинно (обов'язково) залежати від конкретних особливостей, тому що я говорю про порядок.
ashes999

Просто грубі здогадки (потрібно виміряти): Середній час підключення до БД з веб-сервера: 2 мс Середній час підключення до веб-сервера від клієнта: 20 мс. Отже, якщо припустити, що ці цифри, які я випадковим чином витягнув з повітря, є правильними, ви можете зробити 10 дзвінки до бази даних протягом часу, необхідного для здійснення одного дзвінка веб-служби. Якщо припустити, що запити до бази даних займають однакову кількість часу. Ці цифри залежать від навколишнього середовища. Якщо клієнт, який здійснює виклик веб-служби, локальний, він може знизити це на кілька порядків.
Brianfeucht

2

Ми не можемо вам сказати.

Ми не так, як виглядають ваші запити. Ми не знаємо, скільки часу потрібно для їх завершення. Ми не знаємо, скільки накладних витрат бере участь у кожному запиті на ваш сервер API. Ми не знаємо, наскільки географічно розповсюджені ваші клієнти. І т.д.

Якщо це сценарій, який вимагає оптимізації, і це той варіант, коли ви можете вирішити, чи розділити або приєднатись до дзвінків разом, вам потрібно орієнтувати його обома способами : Вирішіть, для чого оптимізуєтесь (затримка інтерфейсу, завантаження центрального процесора, суперечка, і т. д.) і виберіть ту, яка краще досягне вашої мети оптимізації.


Крім того, тільки одна річ , яку я можу додати з відносною впевненістю, це:

У межах одного запиту слід виконати всі запити, які потрібно виконати, щоб скласти відповідь.

Іншими словами, якщо відповідь не може бути сформована, поки не виконано всі N запитів, розділяти їх, як правило, безглуздо. Якщо ви можете створити значущі результати, будь то проміжні чи повні, після кожного запиту починайте тестування.


1

Дві думки:

По-перше, споживачеві, що використовує API, він здійснює один дзвінок для виконання завдання. Що станеться після того, як ваш сервер отримає дзвінок для заповнення запиту, не повинен бути таким жорстким. Якщо для одного дзвінка від споживача потрібні 10 предметів підробітку, щоб зібрати дані та повернути їх, то це має бути прийнятним.

По-друге: Чи бачите ви справжню проблему продуктивності бази даних щодо розглянутого процесу? Мій досвід показав, що часто спроба ввести всі аспекти запиту бази даних в один виклик може призвести до менш ефективного виклику, ніж просто здійснення трьох-чотирьох викликів даних. Сучасні бази даних дуже ефективні в кешуванні та виконанні планів. Часто, коли ви намагаєтеся зробити занадто багато, ви побачите процедури з курсорами (дуже погано для продуктивності, оскільки дані діють по рядках за рядком, а не як набір одразу) та код, що призводить до менш ефективного плану, ніж якщо ви зламали виклик в кілька невеликих простих кроків.

З простої організації коду я погоджуюся, що кожен виклик API, можливо, повинен викликати єдину збережену процедуру (або функцію db), яка в свою чергу відповідає за заповнення запиту. У процедурі може бути більше одного кроку.


Я згоден з вами щодо вимірювання продуктивності, якого, схоже, ніхто не робить. Немає доказів, що це швидше, але це просто продовжує з'являтися. Продуктивність виникає як проблема, коли у нас є деякі дзвінки, які можуть зробити, скажімо, 1000 БД SELECT.
ashes999

@ ashes999, хоча ви можете отримати швидкість, дивлячись на кількість db-дзвінків, це швидше за все, в стратегії індексації тощо, а не в кількості викликів. Як усі вказали, подивіться дані про ефективність.
Річард

Річард, я згоден, і я це фактично знаю. Моє запитання, чому різні люди продовжують доводити цю думку, що "кілька дзвінків у БД повільно", коли є мережевий дзвінок. Я дійсно не бачу, як це може бути суттєвим.
ashes999

@ ashes999 Вибачте, можливо, ви повинні детальніше розглянути питання про мережевий дзвінок, оскільки це здається очевидним, я вважаю, що у вашому питанні є ще трохи. Я відчуваю, що ми щось бракуємо у ваших запитаннях. Ви завжди зазнаєте певної затримки в мережі, і кожен виклик потенційно збільшуватиметься на "х" разів для кожного дзвінка (простими словами). Заява про номінал відповідає дійсності, кілька мережевих дзвінків будуть повільнішими, ніж один мережевий дзвінок на db. Ось чому я пропоную один виклик до збереженої процедури, що дозволяє зробити кілька дзвінків на db без кількох мережевих дзвінків.
Річард

1

Якщо база даних знаходиться на іншому сервері, ніж ваша послуга REST, кожен виклик бази даних призведе до обертання в мережі, що може значно погіршити продуктивність:

Я колись спостерігав, як один виклик веб-сервісу перекладається на близько 500 запитів до бази даних - це навряд чи було проблемою, коли і веб-сервіс, і база даних розташовані на одній машині, але перетворилися на час відповіді 6-7 секунд, коли вони були на різних машини.

Очевидно, що 500 переходів до бази даних є досить екстремальними. Я не впевнений, які ваші вимоги до продуктивності, але, як правило, я б сказав, що якщо ви залишаєтесь приблизно за 10 запитів до бази даних за REST-дзвінок, ви не повинні зазнати значного досягнення ефективності.


1

У нас є кілька додатків, які дуже і дуже балакать. Існує дзвінок у базу даних для кожного. Неодружений Маленький. Річ. Обслуговування довідкових даних знову і знову і знову є основною частиною навантаження в системі. Все, що планує робочі потоки, придбання та випадання замків, перевірка кеш-плану і т. Д., Додає, навіть якщо фактичного дискового вводу немає. Конфліктність вища, тому що транзакції мають утримувати блокування для декількох викликів БД, і тому пропускна здатність значно нижча, ніж могла бути. Ці команди зараз розглядають необхідність купувати нові, дуже дорогі сервери БД через це.

Отже, хоча більша частина минулого часу в поточній конфігурації вашої системи займає дзвінки API REST, ігнорування продуктивності на рівні БД зберігає проблеми на майбутнє.


0

Представлений шлях оптимізації - це просто неправильний спосіб дивитися на речі.

Дзвінки API повинні бути атомними. Іншими словами, я повинен мати можливість зробити 1 виклик веб-API, щоб виконати потрібну дію. Будь то для отримання даних, оновлення запису чи іншого. Ніколи не слід приймати більше 1 дзвінка, щоб викликати дію. І намагання використовувати транзакції через кілька дзвінків слід уникати, як чума.

Іноді одна дія є досить складною. Наприклад, отримання даних, які поєднуються з кількох джерел: знову ж таки, це повинен бути один виклик. Або вся справа працює, або вся справа не вдається.

Тепер, кажучи, що один виклик API повинен виконувати лише один запит БД, є дещо диковим. Як ви вже зазначали, накладні витрати на обробку виклику по мережі часто на порядок дорожчі за загальний час.

Я можу дещо зрозуміти їх твердження про те, що один запит може працювати швидше, ніж кілька; але це створює помилкове враження, оскільки воно ігнорує загальне завантаження БД та мережі. Лише за допомогою профілювання різних способів витягання даних із БД можна зрозуміти, у чому полягає насправді проблема. Я впевнений, що у кожного є історія, коли конкретний запит, виконаний в 100 разів частіше, ніж очікувалося, вбив системи, поки не був встановлений належний індекс ...

Зрештою, ви не зможете переконати їх просто розмовою. Створіть тестовий випадок для обох підходів та профілюйте їх. Зверніть увагу на загальний час для отримання необхідних даних, кількість генерованого мережевого трафіку, кількість та терміни викликів із бази даних тощо. Приміріть цілісний підхід - це означає, що ви переглядаєте всю систему - і вам слід отримати багато дані або їсти ворон, або показати їм золотий шлях.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.