Когда использовать хранилище ключей для веб-разработки? - PullRequest
14 голосов
/ 04 августа 2011

Я немного новичок, так что я пойду ...

Когда кто-то использует хранилище значений ключей (Redis, memcache и т. Д.) Для веб-разработки?Фактический вариант использования был бы наиболее полезным.

Я путаюсь с тем, что простая база данных кажется гораздо более функциональной, потому что, насколько я понимаю, она может делать все, что может делать хранилище значений ключей, плюс она также позволяет вамсделать фильтрацию / запрос.То есть, насколько я понимаю, вы НЕ МОЖЕТЕ выполнять фильтрацию как: select * homes where price > 100000 с хранилищем значений ключей.

ОБНОВЛЕНИЕ :

Давайте сделаем этот пример более реальным.Давайте представим, что StackOverflow использует хранилище значений ключей (memcache, redis и т. Д.).

Как хранилище значений ключей поможет удовлетворить потребности хостинга Stackoverflow?

Ответы [ 6 ]

13 голосов
/ 09 апреля 2013

Я не могу ответить на вопрос, когда использовать хранилище данных ключ-значение (здесь kv), но я могу показать вам некоторые примеры и ответить на ваш пример stackoverflow.

С доступом к базе данных, большинство из того, что вам нужно, это kv store. Например, пользователь входит в систему с именем пользователя "joe". Итак, вы ищете «user: joe» в своей базе данных и получаете его пароль (конечно, хеш). Или, может быть, у вас есть его пароль в разделе «user: pass: joe», это действительно не имеет значения. Если бы это было переполнение стека, и вы рендерили страницу /5626196/kogda-ispolzovat-hranilische-klychei-dlya-veb-razrabotki, вы бы посмотрели «вопрос: 6935566» и использовали его. Просто увидеть, как kv store может решить большинство ваших проблем.

Я бы хотел сказать, что kv store - это подмножество функций, предоставляемых традиционной RDMS. Это связано с тем, что дизайн традиционной RDMS предоставляет множество проблем с масштабированием и, как правило, теряет функции при масштабировании. KV-магазины не поставляются с этими функциями, поэтому они не ограничивают вас. Однако эти функции часто могут быть созданы в любом случае, спроектированы с учетом масштабируемости ядра (потому что это сразу становится очевидным, если это не так).

Однако это не значит, что есть вещи, которые вы не можете сделать. Например, вы упоминаете запрос. Это ловушка многих магазинов кв, так как они, как правило, не имеют значения (не всегда верно, например, redis и т. Д.) И не могут найти то, что вы ищете. Хуже того, они не предназначены для такой быстрой работы, они просто очень быстро ищут ключ.

Одним из решений этой проблемы является лексикографическая сортировка ключей и разрешение запросов по диапазону. По сути, это «дай мне все между вопросом 1 и вопросом 5». Теперь этот пример довольно бесполезен, но есть много вариантов использования запросов диапазона.

Вы сказали, что хотите, чтобы все дома стоили более 100 000 долларов. Если вы хотите сделать это, вы должны создать индекс домов по цене. Скажем, у вас были следующие дома.

house:0 -> {"color":"blue","sold":false,"city":"Stackoverville","price":500000}
house:1 -> {"color":"red","sold":true,"city":"Toronto","price":150000}
house:2 -> {"color":"beige","sold":false,"city":"Toronto","price":40000}
house:3 -> {"color":"blue","sold":false,"city":"The Blogosphere","price":110000}

В SQL вы должны хранить каждое поле в столбце, а не хранить все это в одном (в данном случае JSON) документе. И мог SELECT * FROM houses WHERE price > 100000. Кажется, все хорошо, но, если индекс не построен, для этого необходимо просмотреть каждый дом в вашей таблице и проверить его цену, что, если у вас есть пара миллионов домов, может быть медленным. Так что для магазина kv вам нужен индекс. Основное отличие состоит в том, что база данных SQL будет тихо делать медленную вещь, когда хранилище kv не сможет.

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

house:index:price -> [{"price":500000,"id":"0"},{"price":150000,"id":"1"},{"price":110000,"id":"3"},{"price":40000,"id":"2"}]

Но если у вас есть запросы диапазона (часто называемые сканированием ключей), вы можете создать такой индекс:

house:index:price:040000 -> 2
house:index:price:110000 -> 3
house:index:price:150000 -> 1
house:index:price:500000 -> 0

И затем вы можете запросить ключи от house:index:price:100000 до house:index:price:: (символ ':' - это символ после '9'), и вы получите [3,1,0], что на все дома дороже, чем $ 100 000 ( они тоже в порядке в порядке). Еще одна приятная вещь в этом - это то, что они, вероятно, будут находиться в одном «разделе» вашего кластера, поэтому этот запрос займет примерно то же время, что и одиночное получение (плюс крошечные дополнительные издержки передачи), или два получения, если ваш диапазон окажется выше граница сервера (но это может быть сделано параллельно!).

Итак, это показывает, как выполнять запросы в хранилище kv. Вы можете запросить все, что можно упорядочить в виде строки (почти все), и быстро найти его. Если у вас нет запросов диапазона, вам нужно хранить весь индекс под одним ключом, который отстой, но если у вас есть запросы диапазона, это очень удобно и очень быстро. Вот более сложный пример.

Я хочу непроданные дома в Торонто стоимостью менее 100 000 долларов. Мне просто нужно спроектировать свой индекс.(Я добавил пару домов, чтобы сделать их более значимыми). Сначала вы подумали, что вы можете просто создать другой индекс для каждого свойства, но вы быстро поймете, что это означает, что вам нужно выбрать каждый непроданный дом и загрузить его из базы данных.(Это то, что я имел в виду, когда говорил, что проблемы масштабирования сразу очевидны.) Решение заключается в использовании мультииндекса.После сборки вы можете выбрать именно те значения, которые вам нужны.

house:index:sold:city:price:f~Fooville~000010:5        -> ""
house:index:sold:city:price:f~Toronto~040000:2         -> ""
house:index:sold:city:price:f~Toronto~140000:4         -> ""
house:index:sold:city:price:t~Stackoverville~500000:0  -> ""
house:index:sold:city:price:t~The Blogosphere~110000:3 -> ""
house:index:sold:city:price:t~Toronto~150000:1         -> ""

Теперь, в отличие от последнего примера, я вставил идентификатор в ключ.Это позволяет двум домам иметь одинаковые свойства.Я мог бы объединить их в значение, но тогда добавление удаления индексов становится более сложным.Я также решил разделить мои данные с ~.Это потому, что это лексикографически после всех букв, гарантируя, что полное имя будет отсортировано, и мне не нужно дополнять каждый город одинаковой длины.В производственной системе я бы, вероятно, использовал байт 255 или 0.

Теперь диапазон house:index:sold:city:price:f~Toronto~100000 - house:index:sold:city:price:f~Toronto~~ выберет все дома, которые соответствуют запросу.И важно отметить, что запрос масштабируется линейно с количеством результатов.Это означает, что вам нужно создать индекс для каждого набора свойств, которые вы хотите индексировать (хотя индекс в нашем примере также работает для запросов на продажу и проданный город).Это может показаться большой работой, но, в конце концов, вы понимаете, что вы делаете это, а не ваша база данных.Я уверен, что скоро мы увидим библиотеки для подобных вещей: D

Немного расширив тему, я показал:

  • Некоторые варианты использованияkv store.
  • Как выполнять запросы в kv store.

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

5 голосов
/ 04 августа 2011

Не путайте базу данных типа NoSQL с чем-то вроде memcached (который не предназначен для постоянного хранения данных).

Типичным использованием memcached является хранение некоторых результатов запроса, к которым может обращаться кластер сети.серверы - т.е.общий кеш.Например.На этой странице находится список связанных постов, и, скорее всего, база данных проделает небольшую работу для создания этого списка.Если вы будете делать это каждый раз, когда кто-то загружает страницу, вы создадите много работы для базы данных.Вместо этого результаты, извлеченные в первый раз, могут быть сохранены на сервере memcached, ключом которого является идентификатор страницы.Любой из веб-серверов в кластере может очень быстро получить эту информацию без необходимости постоянно обращаться к базе данных.Через некоторое время запись в кеше будет очищена memcached, чтобы результаты для старых статей не занимали место.[Отказ от ответственности: я понятия не имею, если StackOverflow делает это в реальности].

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

4 голосов
/ 06 августа 2011

Существует два основных жизнеспособных варианта использования для noSQL:

  1. Быстрая разработка приложений
  2. Масштабируемые системы

Тот факт, что большинство решений noSQL эффективно не требуют схем; требуют гораздо меньше церемоний для работы; легкие (с точки зрения API); и обеспечивают значительный выигрыш в производительности в отличие от более канонических реляционных систем персистентности, которые сообщают об их пригодности для вышеуказанных двух вариантов использования (в общем смысле).

Будучи циничным - или, возможно, практичным в деловом смысле - можно предложить третий общий вариант использования для систем noSQL (все еще основанный на вышеуказанном наборе характеристик / возможностей):

Легче вздрогнуть, и любой неопытный (но не мертвый мозг) подонок может поднять его в одно мгновение. Это очень мощная функция. (Попробуйте это с Oracle ..)

Таким образом, сценарии использования систем noSQL, которые в целом можно охарактеризовать как расслабленные постоянные системы , - все оптимально информированы практическими соображениями .

Абсолютно без сомнения - вне масштабно масштабируемых систем - что системы RDBMS являются формально совершенными системами, разработанными для обеспечения целостности данных.

3 голосов
/ 04 августа 2011

Хранилища ключей-значений обычно бывают очень быстрыми, поэтому хорошо иметь их в качестве кэша для данных, к которым имеется большой доступ и которые редко обновляются, чтобы снизить нагрузку на ваши БД.

Как вы сказали, вы обычно ограниченыс запросами (хотя MongoDB обрабатывает их довольно хорошо), но хранилища значений ключей в основном предназначены для доступа к точным данным: профилю пользователя X, информации сеанса X и т. д.

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

РЕДАКТИРОВАТЬ: И под "высокими нагрузками" я имею в виду на самом деле высокие нагрузки.Хранилища значений ключей редко необходимы.

См. Это сравнение хранилищ значений ключей.

1 голос
/ 04 августа 2011

Просто добавив к ответу bstrawson, "mem- cache -d" - это механизм кэширования, тогда как Redis - это постоянное хранилище, но оба хранят данные в виде пары ключ-значение.

Поиск в хранилище значений ключей (что-то вроде Redis или Membase) больше похоже на поиск всех значений в реляционной базе данных, слишком медленный.Если вы хотите выполнить некоторые запросы, вам может потребоваться перейти к документно-ориентированной базе данных типа NoSQL, такой как MongoDB или CouchDB, в которой вы можете выполнить некоторую часть запроса.

В ближайшем будущем вы сможете работать с couchbase sever 2.0, который решит все ваши проблемы с записью данных в NoSQL с помощью недавно представленного UnQL и кэшированием (напрямую полученным из исходного кода memcached)

0 голосов
/ 10 августа 2011

Переполнение стека действительно использует Redis и широко.Подробный ответ на ваш вопрос, на примере Stack Overflow, в пару хороших сообщений в блоге от @Mark Gravell.Марк является автором превосходной Книжной оболочки полностью асинхронной библиотеки привязки .NET Redis.

...