Нічого собі, це просте запитання, на яке величезний масив можливих відповідей. Більш чітка частина вашого запитання запитує, чи більш масштабованим є взаємодія з вашою базою даних безпосередньо або через веб-сервіс. Ця відповідь проста: запитайте безпосередньо в базу даних. Перехід через веб-сервіс додає цілу купу затримок, які абсолютно непотрібні для коду, що працює за брандмауером (за великим рахунком). Наприклад, для веб-сервісу потрібен якийсь компонент, щоб отримати запит, десеріалізувати його, запитувати БД, серіалізувати відповідь та повернути його. Тож якщо ваш код працює за брандмауером, збережіть собі проблеми і просто запитайте БД безпосередньо.
Однак зробити веб-сайт масштабованим виходить далеко за рамки питання, яке ви поставили спочатку. Тож вибачте, якщо я піду на дотичну, але я подумав, що це може бути корисним, враховуючи, що ви згадали зокрема про Facebook.
Я рекомендую вам ознайомитися з роботою та інструментами, побудованими Бредом Фітцпатріком (засновником LiveJournal і зараз в Google). Коли я працював з ним у Six Apart, ось деякі речі, які я дізнався від нього, та про архітектуру LiveJournal, яка зробила його таким масштабним.
Використовуйте вузькі таблиці баз даних на відміну від широких . Захоплююче в цьому було вивчення того, що мотивувало цю архітектуру, яка створювала систему легко і швидкооновлено. Якщо ви використовуєте широкі таблиці або таблиці, для яких кожне поле або властивість є стовпцем таблиці, коли настає час оновити схему бази даних, наприклад, додати новий стовпець, тоді системі потрібно буде заблокувати таблицю, поки схема зміна реалізована. При роботі в масштабі це означатиме, що проста зміна схеми бази даних може призвести до великого відключення бази даних. Який смокче очевидно. З іншого боку, вузька таблиця просто зберігає кожну окрему властивість, пов'язану з об'єктом, як один рядок у базі даних. Тому, коли ви хочете додати до бази даних новий стовпець, все, що вам потрібно зробити, це записи INSERT в таблицю, що є незаблокувальною операцією. Гаразд, це невелике тло, давайте подивимося, як ця модель насправді перекладається в такій робочій системі, як LiveJournal.
Скажімо, ви хочете завантажити останні 10 записів журналу в блозі людини, і скажімо, що кожен запис журналу має десять властивостей. У класичному широкому макеті таблиці кожна властивість співвідноситься зі стовпцем таблиці. Потім користувач запитує таблицю один раз, щоб отримати всі необхідні їм дані. Запит повертає 10 рядків, і кожен рядок матиме всі необхідні їм дані (наприклад, ВИБІР * ВІД записів ЗАМОВЛЕННЯ ДЛЯ ГРОМИ 10). У вузькому макеті таблиці все дещо інакше. У цьому прикладі насправді є дві таблиці: перша таблиця (таблиця A) зберігає прості критерії, за якими хотіли б шукати, наприклад, ідентифікатор запису, ідентифікатор автора, дата введення тощо. Друга таблиця (таблиця B), тоді зберігаються всі властивості, пов'язані із записом. У цій другій таблиці є три стовпці: entry_id, ключ та значення. Для кожного рядка таблиці A буде 10 рядків у таблиці B (по одному рядку для кожної властивості). Тому для отримання та відображення останніх десяти записів вам знадобиться 11 запитів. Перший запит дає вам список ідентифікаторів запису, а потім наступні десять запитів отримають властивості, пов'язані з кожною з записів, повернутих у першому запиті.
"Святий молі!" ви кажете, "як на Землі це може бути масштабнішим ?!" Це абсолютно контр-інтуїтивно зрозуміло? У першому сценарії у нас був лише один запит до бази даних, але в другому «більш масштабованому» рішенні у нас є 11 запитів до бази даних. В цьому немає сенсу. Відповідь на це питання повністю покладається на наступну групу.
Використовуйте memcache вільно. Якщо ви не були в курсі, memcache - це розподілена кешова система, керована мережею, з низьким рівнем затримки. Його використовують у Facebook, Google, Yahoo та майже на кожному популярному та масштабованому веб-сайті планети. Він був винайдений Бредом Фітцпатріком частково, щоб допомогти компенсувати накладні витрати, притаманні дизайну баз даних вузької таблиці. Давайте подивимось на той самий приклад, про який говорилося в №1 вище, але цього разу введемо пам’ять.
Почнемо, коли користувач вперше відвідує сторінку, і нічого немає в кеші. Ви починаєте з таблиці запитів A, яка повертає ідентифікатори 10 записів, які ви хочете відобразити на сторінці. Після цього для кожного з цих запитів ви запитуєте базу даних для отримання властивостей, пов'язаних із цим записом, а потім, використовуючи ці властивості, становлять об'єкт, з яким ваш код може взаємодіяти (наприклад, об'єкт). Потім ви зберігаєте цей об’єкт (або серіалізовану форму цього об’єкта) у мемошах.
Другий раз, коли хтось завантажує ту саму сторінку, ви починаєте так само: за допомогою запиту таблиці A для списку вхідних ідентифікаторів, які ви будете відображати. Для кожного запису ви спершу переходите до пам’ятної пам’яті та говорите: „Чи є у вас кеш-запис #X?“ Якщо так, то memcache повертає вам об'єкт введення. Якщо ні, то вам потрібно ще раз запитувати базу даних, щоб отримати її властивості, скласти об'єкт і зберегти його в мемках. Більшість випадків, коли вдруге хтось відвідує ту саму сторінку, є лише один запит до бази даних, а всі інші дані потім витягуються прямо з пам'яті.
На практиці, що в більшості випадків відбувається у LiveJournal, це те, що більшість даних системи, особливо менш мінливі дані, зберігаються в пам'яті, а додаткові запити до бази даних, необхідні для підтримки схеми вузької таблиці, майже повністю компенсуються.
Ця конструкція зробила вирішення проблеми, пов’язаної зі складанням списку публікацій, пов’язаних з усіма вашими друзями, в потік або "стіну" набагато, набагато простіше.
Далі розглянемо розділення вашої бази даних. Модель, обговорена вище поверхонь, ще одна проблема, і це ваші вузькі таблиці, як правило, дуже великі / довгі. І чим більше рядків цих таблиць, тим складніше стають інші адміністративні завдання. Щоб компенсувати це, може бути доцільним керувати розміром ваших таблиць, так чи інакше розподіляючи таблиці, так що кластери користувачів обслуговуються однією базою даних, а інший кластер користувачів обслуговується окремою базою даних. Це розподіляє навантаження на базу даних і підтримує ефективність запитів.
Нарешті, вам потрібні приголомшливі індекси. Швидкість ваших запитів багато в чому буде залежати від того, наскільки добре проіндексовані таблиці вашої бази даних. Я не витрачу надто багато часу на обговорення того, що таке індекс, крім того, щоб сказати, що це дуже схоже на систему гігантських каталогів карт, щоб зробити голки в стозі сіна більш ефективним. Якщо ви використовуєте mysql, то рекомендую увімкнути журнал повільних запитів для моніторингу запитів, які потребують тривалого часу. Коли на вашому радарі з'являється запит (наприклад, тому, що він повільний), то з’ясуйте, який індекс потрібно додати до таблиці, щоб прискорити його.
"Дякую за весь цей чудовий фон, але святий суровий, це дуже багато коду, який мені доведеться написати".
Не обов'язково. Написано багато бібліотек, які роблять взаємодію з пам’яттю справді просто. Ще інші бібліотеки кодифікували весь описаний вище процес; Дані :: ObjectDriver в Perl - саме така бібліотека. Що стосується інших мов, то вам потрібно буде зробити власне дослідження.
Сподіваюся, ви знайшли цю відповідь корисною. Що найчастіше я знаходив, це те, що масштабованість системи часто зводиться все менше і менше до кодування, а все більше - до надійної стратегії зберігання та управління даними / технічного проектування.