Поиск по осколкам? - PullRequest
8 голосов
/ 04 ноября 2008

Короткая версия

Если я разделю своих пользователей на осколки, как мне предложить «поиск пользователей»? Очевидно, я не хочу, чтобы каждый поиск попадал в каждый осколок.

Длинная версия

Под шардом я имею в виду наличие нескольких баз данных, каждая из которых содержит часть общих данных. Для (наивного) примера базы данных UserA, UserB и т. Д. Могут содержать пользователей, имена которых начинаются с «A», «B» и т. Д. Когда новый пользователь регистрируется, я просто проверяю его имя и помещаю его в правильное база данных. Когда возвращающийся пользователь входит в систему, я снова смотрю на его имя, чтобы определить правильную базу данных, из которой он получает информацию.

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

Между тем, осколки не заботятся о записях друг друга. Если Брайан подписывается на шард UserB, ему не нужно слышать об этом. Если Брайан отправит сообщение Алексу, я могу записать этот факт как на шарды UserA, так и на UserB. Таким образом, когда в систему входит Алекс или Брайан, он может получить все свои отправленные и полученные сообщения из своего осколка, не запрашивая все осколки.

Пока все хорошо. Как насчет поисков? В этом примере, если Брайан ищет «Алекс», я могу проверить UserA. Но что, если он ищет Алекса по фамилии «Смит»? В каждом черепке есть кузнецы. Отсюда я вижу два варианта:

  1. Попросите приложение найти Смитов на каждом осколке. Это можно сделать медленно (запросить каждый осколок подряд) или быстро (запросить каждый осколок параллельно), но в любом случае каждый осколок должен быть задействован в каждом поиске. Точно так же, как репликация чтения не масштабирует записи, поиск по каждому фрагменту не масштабирует ваши поиски. Вы можете достигнуть времени, когда ваш объем поиска будет достаточно большим, чтобы разбить каждый осколок, и добавление осколков вам не поможет, поскольку все они получают одинаковый объем.
  2. Какая-то индексация, которая сама по себе терпима к шардингу. Например, скажем, у меня есть постоянное количество полей, по которым я хочу искать: имя и фамилия. В дополнение к UserA, UserB и т. Д. У меня также есть IndexA, IndexB и т. Д. Когда регистрируется новый пользователь, я прикрепляю его к каждому индексу, в котором я хочу, чтобы он был найден. Поэтому я поместил Алекса Смита в IndexA и IndexS, и его можно найти либо в «Алекс», либо в «Смит», но без подстрок. Таким образом, вам не нужно запрашивать каждый фрагмент, поэтому поиск может быть масштабируемым.

Так можно ли масштабировать поиск? Если да, то подходит ли этот подход к индексированию? Есть ли другие?

Ответы [ 5 ]

7 голосов
/ 06 ноября 2008

Волшебной пули нет.

Поиск каждого осколка подряд исключен, очевидно, из-за невероятно высокой задержки, которую вы понесете.

Так что вы хотите искать параллельно, если вам нужно.

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

Основное понимание, которое вы можете использовать, заключается в том, что при поиске вам редко требуется полный набор результатов. Вам нужна только первая (или n-я) страница результатов. Таким образом, есть достаточно места для маневра, чтобы уменьшить время отклика.

Индексация

Если вам известны атрибуты, по которым будут выполняться поиск пользователей, вы можете создать собственные, отдельные индексы для них. Вы можете создать свой собственный инвертированный индекс , который будет указывать на кортеж (shard, recordId) для каждого поискового запроса, или вы можете сохранить его в базе данных. Обновлять его лениво и асинхронно. Я не знаю требований к вашему приложению, возможно, даже можно будет перестраивать индекс каждую ночь (это означает, что у вас не будет самых последних записей в любой день - но это может подойти вам). Обязательно оптимизируйте этот индекс по размеру, чтобы он мог поместиться в памяти; обратите внимание, что вы можете осквернить этот индекс, если вам нужно.

Естественно, если люди могут искать что-то вроде "lastname='Smith' OR lastname='Jones'", вы можете прочитать индекс Смита, прочитать индекс Джоунса и вычислить объединение - вам не нужно хранить все возможные запросы, только их составные части. .

Параллельный поиск

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

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

2 голосов
/ 04 ноября 2008

Полагаю, вы говорите об осколках а-ля: http://highscalability.com/unorthodox-approach-database-design-coming-shard

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

1 голос
/ 06 ноября 2008

Возможно, вы захотите взглянуть на Sphinx (http://www.sphinxsearch.com/articles.html).. Он поддерживает распределенный поиск. GigaSpaces имеет параллельный запрос и поддержку слияния. Это также можно сделать с MySQL Proxy (http://jan.kneschke.de/2008/6/2/mysql-proxy-merging-resultsets).

Для создания неосколенных индексируемых видов поражений цель шарда в первую очередь :-) Централизованный индекс, вероятно, не сработает, если нужны осколки.

Я думаю, что все осколки нужно наносить параллельно. Результаты должны быть отфильтрованы, ранжированы, отсортированы, сгруппированы и результаты объединены из всех сегментов. Если сами осколки перегружены, вы должны сделать обычное действие (перетаскивание, увеличение и т. Д.), Чтобы снова разбить их.

1 голос
/ 04 ноября 2008

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

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

0 голосов
/ 11 февраля 2012

RDBM не являются хорошим инструментом для текстового поиска. Вам будет намного лучше смотреть на Solr . Разница в производительности между Solr и базой данных будет порядка 100X.

...