Подтвердить что ты не робот

Индивидуальные и уникальные идентификаторы MongoDB

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

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

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

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

WDYT?

4b9b3361

Ответ 1

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

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

0123   456      78    91011
time   machine  pid   inc

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

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

Итак, я бы сказал, просто используйте

ObjectID <

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

Например:

4d128b6ea794fc13a8000001
4d128e88a794fc13a8000002

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

4d128 b6e a794fc13a8000001
4d128 e88 a794fc13a8000002

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

Ответ 3

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

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

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

Ответ 4

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

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

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)

Обратите внимание, что он будет только шифровать a-z, A-Z, 0-9 и пробел, оставив другие символы неповрежденными. Это достаточно для идентификаторов BSON.

Ответ 5

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

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