Индивидуальные и уникальные идентификаторы MongoDB
Я использую MongoDB, и я хотел бы генерировать уникальные и критические идентификаторы для сообщений в блоге (которые будут использоваться в спокойных URL-адресах), таких как s52ruf6wst или xR2ru286zjI.
Как вы думаете, что лучше всего и более масштабируемый способ генерации этих идентификаторов?
Я думал о следующей архитектуре:
- периодическая (ежедневная?) серия, предназначенная для генерации большого количества случайных и уникальных идентификаторов и вставки их в выделенную коллекцию MongoDB с помощью InsertIfNotPresent
- и каждый раз, когда я хочу создать новое сообщение в блоге, я беру идентификатор из этой коллекции и отмечаю его как "взятый" с атомной операцией UpdateIfCurrent.
WDYT?
Ответы
Ответ 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
И для блога я не думаю, что это большая сделка... мы используем ее во всем мире.
Ответ 2
Как насчет использования UUID?
http://www.famkruithof.net/uuid/uuidgen в качестве примера.
Ответ 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, основанного на времени, или идентификатор на основе встречных сообщений. Любой из них приведет к "угадыванию", что может быть или не быть проблемой в какой-либо конкретной ситуации. Я бы счел, что идентификатор, основанный на времени или счетчик, достаточен для сообщений в блоге, хотя я не знаю подробностей вашей ситуации и рассуждений.