Предлагаемое решение: создание уникальных идентификаторов в распределенной среде

Я просматриваю сеть, пытаясь найти решение, которое позволит нам генерировать уникальные идентификаторы в региональной среде.

Я рассмотрел следующие варианты (среди прочего):

SNOWFLAKE (по щебетать)

  • Похоже, что это отличные решения, но мне просто не нравится добавленная сложность управления другим программным обеспечением только для создания идентификаторов;
  • На данном этапе у него нет документации, поэтому я не думаю, что это будет хорошая инвестиция;
  • Узлы должны иметь возможность связываться друг с другом с помощью Zookeeper (как насчет задержки или сбоя связи?)

UUID

  • Просто посмотрите на это: 550e8400-e29b-41d4-a716-446655440000;
  • Его 128-битный идентификатор;
  • Были некоторые известные столкновения (в зависимости от версии, я думаю) см. этот пост.

АВТОМАТИЧЕСКОЕ ОБЕСПЕЧЕНИЕ В ОТНОШЕНИИ ДАННЫХ, КАК МОЙКАЛ

  • Это кажется безопасным, но, к сожалению, мы не используем реляционные базы данных (настройки масштабируемости);
  • Мы могли бы развернуть сервер MySQL для этого, как то, что делает Flickr, но опять же это представляет собой еще один пункт отказа/узкого места. Также добавлена ​​сложность.

АВТОИНКРИМЕНТ В НЕЗАВИСИМОЙ БАЗЕ ДАННЫХ, КАК СОТРУДНИЧЕСТВО

  • Это может работать, поскольку мы используем Couchbase в качестве нашего сервера базы данных, но
  • Это не сработает, если у нас есть несколько кластеров в разных регионах, проблемы с задержкой, сбои сети: в какой-то момент идентификаторы будут сталкиваться в зависимости от объема трафика;

МОЕ ПРЕДЛОЖЕННОЕ РЕШЕНИЕ (мне нужна помощь)

Давайте скажем, что у нас есть кластеры, состоящие из 10 узлов Couchbase и 10 узлов приложения в 5 разных регионах (Африка, Европа, Азия, Америка и Океания). Это делается для обеспечения того, чтобы контент обслуживался из ближайшего к пользователю местоположения (для повышения скорости) и обеспечения избыточности в случае бедствий и т.д.

Теперь задача состоит в том, чтобы генерировать идентификаторы, которые не сталкиваются, когда происходит репликация (и балансировка), и я думаю, что это может быть достигнуто в 3 этапа:

Шаг 1

Всем регионам будут назначены целые идентификаторы (уникальные идентификаторы):

  • 1 - Африка;
  • 2 - Америка;
  • 3 - Азия;
  • 4 - Европа;
  • 5 - Ociania.

Шаг 2

Назначьте идентификатор для каждого приложения node, которое добавляется в кластер, имея в виду, что в одном кластере может быть до 99 999 серверов (хотя я сомневаюсь: так же, как безопасная мера предосторожности). Это будет выглядеть примерно так (поддельные IP-адреса):

  • 00001 - 192.187.22.14
  • 00002 - 164.254.58.22
  • 00003 - 142.77.22.45
  • и т.д.

Обратите внимание, что все они находятся в одном кластере, поэтому вы можете иметь node 00001 для каждого региона.

Шаг 3

Для каждой записи, вставленной в базу данных, для ее идентификации будет использоваться инкрементированный идентификатор, и вот как это будет работать:

Couchbase предлагает функцию увеличения, которую мы можем использовать для создания идентификаторов внутри кластера. Чтобы обеспечить избыточность, в кластере будут созданы 3 реплики. Поскольку они находятся в одном и том же месте, я думаю, что должно быть безопасно предположить, что если весь кластер не будет работать, один из узлов, ответственных за это, будет доступен, в противном случае количество реплик может быть увеличено.

Объединяя все это

Скажите, что пользователь подписывается из Европы: Приложение node, обслуживающее запрос, в этом случае получит код региона (4), получите свой собственный идентификатор (скажем 00005), а затем получите увеличенный идентификатор ( 1) из Couchbase (из одного кластера).

В итоге мы получим 3 компонента: 4, 00005,1. Теперь, чтобы создать идентификатор из этого, мы можем просто присоединить эти компоненты к 4.00005.1. Чтобы сделать это еще лучше (я не слишком уверен в этом), мы можем конкатенировать (не добавлять их), чтобы в итоге получилось: 4000051.

В коде это будет выглядеть примерно так:

$id = '4'.'00005'.'1';

NB: Не $id = 4+00005+1;.

Pros

  • Идентификаторы выглядят лучше, чем UUID;
  • Они кажутся достаточно уникальными. Даже если node в другой области сгенерировал один и тот же инкрементный идентификатор и имеет тот же самый идентификатор node, что и выше, мы всегда располагаем региональным кодом для их разделения;
  • Они все равно могут быть сохранены как целые числа (возможно, большие целые числа без знака);
  • Все это часть архитектуры, никаких дополнительных сложностей.

против

  • Нет сортировки (или есть)?
  • Здесь мне нужны ваши данные (большинство)

Я знаю, что каждое решение имеет недостатки и, возможно, больше того, что мы видим на поверхности. Можете ли вы выявить любые проблемы с этим целым подходом?

Заранее благодарю вас за помощь: -)

ИЗМЕНИТЬ

Как показано в @DaveRandom, мы можем добавить 4-й шаг:

Шаг 4

Мы можем просто сгенерировать случайное число и добавить его к идентификатору, чтобы предотвратить предсказуемость. Эффективно, вы получите что-то вроде этого:

4000051357 вместо 4000051.

Ответ 1

Я думаю, что это выглядит довольно солидно. Каждый регион поддерживает согласованность, и если вы используете XDCR, конфликтов не возникает. INCR является атомарным внутри кластера, поэтому у вас не будет проблем. На самом деле вам не требуется часть машинного кода. Если все серверы приложений в регионе подключены к одному и тому же кластеру, это не имеет значения для инфиниции части 00001. Если это полезно для вас по другим причинам (какая-то аналитика), то непременно, но это необязательно.

Таким образом, это может быть просто "4". 1 '(используя ваш пример)

Можете ли вы привести мне пример того, какая "сортировка" вам нужна?

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

Например: если идентификатор из 1-100, который вы узнаете из простого запроса GET на клавише счетчика, вы можете назначать задачи по группам, эта задача занимает 1-10, следующие 11-20 и т.д., и работники могут выполнять параллельно. Если вы добавите энтропию, вам нужно будет использовать Map/Reduce View, чтобы вытащить коллекции, поэтому вы теряете выгоду от шаблона значения ключа.

Второй. Поскольку вы заинтересованы в удобочитаемости, полезно добавить идентификатор типа документа/объекта, и это можно использовать в Map/Reduce Views (или вы можете использовать json, чтобы определить это).

Ex: 'u:'. '4'. '1'

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

@scalabl3

Ответ 2

Вы обеспокоены идентификаторами по двум причинам:

  • Потенциал для коллизий в сложной сетевой инфраструктуре
  • Внешний вид

Начиная со второй проблемы, Внешний вид. Хотя UUID, конечно же, не очень красив, когда дело доходит до идентификатора, уменьшаются отдачи, поскольку вы вводите поистине уникальный номер в сложном центре обработки данных (или центрах обработки данных), как вы упомянули. Я не уверен, что в восприятии приложения происходит резкое изменение, когда длинный номер по сравнению с UUID используется, например, в URL-адресе веб-приложения. В идеале ни один из них не будет показан, а ID будет отправляться только через запросы Ajax и т.д. Хотя предпочтительный чистый запоминающийся URL-адрес предпочтительнее, он никогда не останавливал меня от покупок на Amazon (где у них абсолютно отвратительные URL-адреса).:)

Даже с вашим предложением идентификаторы, в то время как они будут короче в количестве символов, чем UUID, они не более запоминаются, чем UUID. Таким образом, появление, вероятно, останется спорным.

Говоря о первом пункте..., да, есть несколько случаев, когда известно, что UUID генерируют конфликты. Хотя это не должно происходить в правильно сконфигурированной и постоянно полученной архитектуре, я могу видеть, как это может произойти (но я лично гораздо меньше обеспокоен этим).

Итак, если вы говорите об альтернативах, я стал поклонником простоты MongoDB ObjectId и его методов избежания дублирования при создании идентификатора. Полная документация здесь. Быстрые релевантные элементы похожи на ваш потенциальный дизайн несколькими способами:

ObjectId - это 12-байтовый тип BSON, построенный с использованием:

  • 4-байтовое значение, представляющее секунды с эпохи Unix,
  • 3-байтовый идентификатор машины,
  • двухбайтовый идентификатор процесса и
  • 3-байтовый счетчик, начиная со случайного значения.

Временная метка часто может быть полезна для сортировки. Идентификатор машины похож на ваш сервер приложений, имеющий уникальный идентификатор. Идентификатор процесса - это просто дополнительная энтропия и, наконец, чтобы предотвратить конфликты, есть счетчик, который автоматически увеличивается, когда временная метка такая же, как и в последний раз, когда создается ObjectId (так что ObjectIds могут быть созданы быстро). ObjectId может быть сгенерирован на клиенте или в базе данных. Кроме того, ObjectIds занимают меньше байтов, чем UUID (но только 4). Конечно, вы не могли использовать временную метку и сбросить 4 байта.

Для пояснения я не предлагаю использовать MongoDB, но должен быть вдохновлен техникой, которую они используют для генерации идентификатора.

Итак, я думаю, что ваше решение является достойным (и, возможно, вы хотите вдохновиться внедрением MongoDB уникального идентификатора) и выполнимым. Что касается того, нужно ли вам это делать, я думаю, что на вопрос вы можете ответить только.