Вау, это простой вопрос, на который огромное множество возможных ответов. Более четкая часть вашего вопроса спрашивает, является ли более масштабируемым интерфейс с вашей базой данных напрямую или через веб-сервис. Этот ответ прост: запросить базу данных напрямую. Работа с веб-службой добавляет целую кучу задержек, которые совершенно не нужны для кода, работающего за брандмауэром (по большому счету). Например, веб-сервис требует, чтобы какой-либо компонент принимал запрос, десериализовывал его, запрашивал в БД, сериализовал ответ и возвращал его. Поэтому, если весь ваш код работает за брандмауэром, избавьте себя от проблем и просто запросите БД напрямую.
Однако создание масштабируемого веб-сайта выходит далеко за рамки изначально поставленного вопроса. Так что прости меня, если я уйду по касательной здесь, но я подумал, что это может быть полезно, учитывая, что ты упомянул Facebook в частности.
Я бы порекомендовал вам прочитать о работе и инструментах, созданных Брэдом Фитцпатриком (основателем LiveJournal, а теперь и в Google). Когда я работал с ним в Six Apart, вот несколько вещей, которые я узнал от него, и об архитектуре LiveJournal, которая сделала его настолько масштабируемым.
Используйте узкие таблицы базы данных, а не широкие . Что было удивительно в этом, так это изучение того, что мотивировало эту архитектуру, которая создавала систему, которая была бы простой и быстрой.модернизированы. Если вы используете широкие таблицы или таблицы, для которых каждое поле или свойство является столбцом в таблице, когда придет время обновить схему базы данных, например, добавив новый столбец, тогда система должна будет заблокировать таблицу, пока схема изменение осуществлено. При работе в масштабе это будет означать, что простое изменение схемы базы данных может привести к значительному сбою базы данных. Который отстой, очевидно. С другой стороны, узкая таблица просто хранит каждое отдельное свойство, связанное с объектом, как одну строку в базе данных. Поэтому, когда вы хотите добавить новый столбец в базу данных, все, что вам нужно сделать, это вставить записи в таблицу, что является неблокирующей операцией. Хорошо, это небольшой фон, давайте посмотрим, как эта модель на самом деле транслируется в рабочей системе, такой как LiveJournal.
Допустим, вы хотите загрузить последние 10 записей журнала в блог человека, и, скажем, каждая запись журнала имеет десять свойств. В классической широкой компоновке таблицы каждое свойство будет соответствовать столбцу таблицы. Затем пользователь будет запрашивать таблицу один раз, чтобы получить все необходимые ему данные. Запрос будет возвращать 10 строк, и каждая строка будет содержать все необходимые данные (например, SELECT * FROM записей ORDER BY date LIMIT 10). Однако в узкой таблице все немного по-другому. В этом примере фактически есть две таблицы: первая таблица (таблица A) хранит простые критерии, по которым можно было бы искать, например, идентификатор записи, идентификатор автора, дату записи и т. Д. Вторая таблица (таблица B) затем сохраняет все свойства, связанные с записью. Эта вторая таблица имеет три столбца: entry_id, ключ и значение. Для каждой строки в таблице A будет 10 строк в таблице B (одна строка для каждого свойства). Поэтому, чтобы получить и отобразить последние десять записей, вам потребуется 11 запросов. Первый запрос выдает список идентификаторов записей, а затем следующие десять запросов извлекают свойства, связанные с каждой из записей, возвращаемых в первом запросе.
"Святой моли!" Вы говорите: «Как, черт возьми, это может быть более масштабируемым ?!» Это совершенно нелогичное право? В первом сценарии у нас был только один запрос к базе данных, но во втором «более масштабируемом» решении мы имеем 11 запросов к базе данных. Это бессмысленно. Ответ на этот вопрос полностью зависит от следующего пункта.
Используйте memcache свободно. В случае, если вы не знали, memcache - это распределенная система кэширования с низкой задержкой и сетевой задержкой. Он используется Facebook, Google, Yahoo и практически всеми популярными и масштабируемыми веб-сайтами на планете. Он был изобретен Брэдом Фитцпатриком частично, чтобы помочь компенсировать издержки базы данных, присущие дизайну базы данных с узкими таблицами. Давайте посмотрим на тот же пример, который обсуждался в # 1 выше, но на этот раз давайте представим memcache.
Давайте начнем, когда пользователь впервые заходит на страницу, а в кеше ничего нет. Вы начинаете с запроса таблицы A, которая возвращает идентификаторы 10 записей, которые вы хотите отобразить на странице. Для каждой из этих записей вы затем запрашиваете базу данных, чтобы получить свойства, связанные с этой записью, и затем используете эти свойства, образуя объект, с которым ваш код может взаимодействовать (например, объект). Затем вы прячете этот объект (или сериализованную форму этого объекта) в memcache.
Во второй раз, когда кто-то загружает ту же страницу, вы начинаете так же: запрашивая у таблицы A список идентификаторов записей, которые вы будете отображать. Для каждой записи вы сначала заходите в memcache и говорите: «У вас есть запись #X в кэше?» Если да, то memcache возвращает вам объект ввода. Если нет, то вам нужно снова запросить базу данных, чтобы получить ее свойства, создать объект и спрятать его в memcache. В большинстве случаев, когда кто-то посещает одну и ту же страницу, только один запрос к базе данных, все остальные данные извлекаются прямо из memcache.
На практике в большинстве случаев LiveJournal происходило то, что большая часть данных системы, особенно менее изменчивые данные, кэшировалась в memcache, а дополнительные запросы к базе данных, необходимые для поддержки схемы узких таблиц, были почти полностью смещены.
Этот дизайн значительно облегчил решение проблемы, связанной со сборкой списка сообщений, связанных со всеми вашими друзьями, в поток или «стену» .
Затем рассмотрите возможность разделения вашей базы данных. Модель, рассмотренная выше, обнаруживает еще одну проблему, а именно ваши узкие таблицы будут иметь тенденцию быть очень большими / длинными. И чем больше строк в этих таблицах, тем сложнее становятся другие административные задачи. Чтобы компенсировать это, может иметь смысл управлять размером ваших таблиц путем некоторого разбиения таблиц таким образом, чтобы кластеры пользователей обслуживались одной базой данных, а другой кластер пользователей обслуживался отдельной базой данных. Это распределяет нагрузку на базу данных и поддерживает эффективность запросов.
Наконец, вам нужны потрясающие индексы. Скорость ваших запросов будет во многом зависеть от того, насколько хорошо проиндексированы таблицы вашей базы данных. Я не буду тратить слишком много времени на обсуждение того, что такое индекс, за исключением того, что скажу, что это похоже на гигантскую систему карточных каталогов, которая делает поиск игл в стоге сена более эффективным. Если вы используете mysql, то я рекомендую включить медленный журнал запросов, чтобы отслеживать запросы, выполнение которых занимает много времени. Когда на вашем радаре появляется запрос (например, из-за того, что он медленный), выясните, какой индекс нужно добавить в таблицу, чтобы ускорить его.
«Спасибо вам за все эти замечательные знания, но, черт возьми, это большой код, который мне придется написать».
Не обязательно. Было написано много библиотек, которые действительно облегчают взаимодействие с memcache. Еще другие библиотеки кодифицировали весь процесс, описанный выше; Data :: ObjectDriver в Perl как раз такая библиотека. Что касается других языков, вам нужно будет провести собственное исследование.
Я надеюсь, что вы нашли этот ответ полезным. Чаще всего я обнаруживал, что масштабируемость системы все чаще сводится к коду, а все больше - к разумной стратегии хранения и управления данными / технического проектирования.