Пользовательские и уникальные идентификаторы MongoDB - PullRequest
12 голосов
/ 10 января 2011

Я использую MongoDB и хотел бы создать уникальные и загадочные идентификаторы для сообщений в блоге (которые будут использоваться в релакс-URL), например s52ruf6wst или xR2ru286zjI .

Какой способ создания этих идентификаторов вы считаете лучшим и более масштабируемым?

Я думал о следующей архитектуре:

  • периодический (ежедневный?) Пакетный запуск для генерации большого количества случайных и уникальных идентификаторов и вставки их в выделенную коллекцию MongoDB с помощью InsertIfNotPresent
  • и каждый раз, когда я хочу создать новую запись в блоге, я беру идентификатор из этой коллекции и помечаю его как «принятый» с помощью атомарной операции UpdateIfCurrent

WDYT?

Ответы [ 5 ]

32 голосов
/ 11 января 2011

Именно поэтому разработчики MongoDB сконструировали свои ObjectID (_id) так, как они делали ... для масштабирования по узлам и т. Д.

BSON ObjectIDявляется 12-байтовым значением, состоящим из 4-байтовой метки времени (секунды с начала эпохи), 3-байтового идентификатора компьютера, 2-байтового идентификатора процесса и 3-байтового счетчика.Обратите внимание, что поля timestamp и counter должны храниться с прямым порядком байтов в отличие от остальной части BSON.Это потому, что они сравниваются побайтово, и мы хотим обеспечить в основном увеличивающийся порядок.Вот схема:

0123   456      78    91011
time   machine  pid   inc

Традиционные базы данных часто используют монотонно увеличивающиеся порядковые номера для первичных ключей.В MongoDB предпочтительным подходом является использование идентификаторов объектов.Идентификаторы объектов более синергетичны с шардингом и распределением.

http://www.mongodb.org/display/DOCS/Object+IDs

Так что я бы сказал, просто используйте ObjectID's

Онине так уж плохо при преобразовании в строку (они были вставлены сразу после друг друга) ...

Например:

4d128b6ea794fc13a8000001
4d128e88a794fc13a8000002

Они выглядят на первый взгляд быть "угадываемым", но на самом деле их не так просто угадать ...

4d128 b6e a794fc13a8000001
4d128 e88 a794fc13a8000002

И для блога, я не думаю, что это так уж важно ... мы используем его для производстваповсюду.

3 голосов
/ 28 сентября 2012

А как насчет использования UUID?

http://www.famkruithof.net/uuid/uuidgen в качестве примера.

1 голос
/ 10 января 2011

Сделать веб-сервис, который возвращает глобально уникальный идентификатор, чтобы вы могли участвовать во многих веб-серверах и знать, что вы не попадете ни в какие дубликаты?

Если в вашей ежедневной партии не было выделено достаточно элементов?Вы запускаете его в полдень?

Я бы реализовал клиент веб-службы как очередь, которая может просматриваться локальным процессом и, при необходимости, пополняться (когда сервер работает медленнее), и в нем может храниться не достаточно элементов.нужно бежать во время пикового использования.Имеет смысл?

0 голосов
/ 19 ноября 2015

«Правильный» ответ, который на самом деле не является хорошим решением IMHO, состоит в том, чтобы сгенерировать случайный идентификатор, а затем проверить БД на предмет столкновения. Если это столкновение, сделайте это снова. Повторяйте, пока не найдете неиспользованный матч. В большинстве случаев первое будет работать (при условии, что процесс генерации достаточно случайный).

Следует отметить, что этот процесс необходим, только если вы обеспокоены последствиями безопасности для UUID на основе времени или ID на основе счетчика. Любой из них приведет к «угадыванию», что может или не может быть проблемой в любой конкретной ситуации. Я бы посчитал, что для сообщений в блоге достаточно идентификатора на основе времени или счетчика, хотя я не знаю деталей вашей ситуации и рассуждений.

0 голосов
/ 02 марта 2013

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

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

class Array
  def shuffle_with_seed!(seed)
    prng = (seed.nil?) ? Random.new() : Random.new(seed)
    size = self.size

    while size > 1
      # random index
      a = prng.rand(size)

      # last index
      b = size - 1

      # switch last element with random element
      self[a], self[b] = self[b], self[a]

      # reduce size and do it again
      size = b;
    end

    self
  end

  def shuffle_with_seed(seed)
    self.dup.shuffle_with_seed!(seed)  
  end
end

class SubstitutionCipher

  def initialize(seed)
    normal = ('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a + [' ']
    shuffled = normal.shuffle_with_seed(seed)
    @map = normal.zip(shuffled).inject(:encrypt => {} , :decrypt => {}) do |hash,(a,b)|
      hash[:encrypt][a] = b
      hash[:decrypt][b] = a
      hash
    end
  end

  def encrypt(str)
    str.split(//).map { |char| @map[:encrypt][char] || char }.join
  end

  def decrypt(str)
    str.split(//).map { |char| @map[:decrypt][char] || char }.join
  end

end

Вы используете его так:

MY_SECRET_SEED = 3429824

cipher = SubstitutionCipher.new(MY_SECRET_SEED)

id = hash["_id"].to_s
encrypted_id = cipher.encrypt(id)
decrypted_id = cipher.decrypt(encrypted_id)

Обратите внимание, что он будет шифровать только az, AZ, 0-9 и пробел, оставляя другие символы без изменений.Для идентификаторов BSON этого достаточно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...