Генерация глобального уникального идентификатора в Java

Вывод: я разрабатываю постоянное веб-приложение Java, и мне нужно убедиться, что все ресурсы, которые я сохраняю, имеют глобальные уникальные идентификаторы для предотвращения дублирования.

Мелкий шрифт:

  1. Я не использую СУБД, поэтому у меня нет каких-либо причудливых генераторов последовательностей (например, предоставленных Oracle).
  2. Я бы хотел, чтобы это было быстро, желательно все в памяти - я бы предпочел не открывать файл и увеличивать какое-то значение
  3. Он должен быть потокобезопасным (я ожидаю, что только одна JVM за раз должна будет генерировать идентификаторы)
  4. Необходимо обеспечить согласованность между экземплярами JVM. Если сервер выключается и запускается, генератор идентификаторов не должен повторно генерировать те же идентификаторы, которые он сгенерировал в предыдущих экземплярах (или, по крайней мере, шанс должен быть очень, очень мал - я ожидаю, что многие миллионы сохраненных ресурсов)
  5. Я видел примеры в статье о шаблонах уникальных идентификаторов EJB. Они не будут работать для меня (я бы предпочел не полагаться исключительно на System.currentTimeMillis(), потому что мы будем сохранять несколько ресурсов в миллисекунду).
  6. Я просмотрел ответы, предложенные в этом вопросе. Я беспокоюсь о них, какова вероятность того, что со временем я получу дубликат удостоверения личности? Я заинтригован предложением использовать java .util.UUID для UUID, но опять же, вероятность дублирования должны быть бесконечно малы.
  7. Я использую JDK6

person Julie    schedule 10.10.2008    source источник
comment
Вы запускаете несколько экземпляров приложения на разных машинах? Если да, то вероятно ли, что вы будете запускать машины в пакетном режиме, чтобы несколько процессов запускались в одну и ту же миллисекунду? Если злоумышленник найдет способ вызвать коллизию UUID, не поставит ли это под угрозу безопасность вашего приложения?   -  person Mike Samuel    schedule 17.03.2012
comment
(A) Какой объем идентификаторов будет создан? Как быстро? (Сколько в секунду/минуту) (B) Да, UUID были изобретены именно для вашей цели.   -  person Basil Bourque    schedule 04.02.2014


Ответы (6)


Почти уверен, что UUID «достаточно хороши». Доступно 340 282 366 920 938 463 463 374 607 431 770 000 000 UUID.

http://www.wilybeagle.com/guid_store/guid_explain.htm

«Чтобы представить эти цифры в перспективе, ежегодный риск столкновения с метеоритом оценивается как один шанс из 17 миллиардов, что означает, что вероятность составляет около 0,00000000006 (6 × 10−11), что эквивалентно шансам создания нескольких метеоритов. десятки триллионов UUID в год и иметь один дубликат. Другими словами, только после генерации 1 миллиарда UUID каждую секунду в течение следующих 100 лет вероятность создания только одного дубликата будет около 50%.Вероятность одного дубликата будет быть около 50%, если каждый человек на земле владеет 600 миллионами UUID"

http://en.wikipedia.org/wiki/Universally_Unique_Identifier

person Shawn Miller    schedule 10.10.2008
comment
Хорошая ссылка! Таким образом, можно с уверенностью сделать вывод, что если я использую UUID.randomUUID() в своем приложении, вероятность того, что он дважды сгенерирует один и тот же UUID, бесконечно мала, тогда...? - person Julie; 11.10.2008
comment
Ну, то, что существует так много возможных значений, не обязательно означает, что они написали алгоритм достаточно хорошо, чтобы получить хорошее случайное распределение. Опять же, дизайнеры класса UUID, вероятно, вложили в него гораздо больше мыслей, чем я мог бы за полдня! - person Julie; 11.10.2008
comment
да, мы много думали об этом... Стандартизирован Open Software Foundation (OSF) как часть распределенной вычислительной среды (DCE) - person Shawn Miller; 11.10.2008
comment
Пока вы не спите ночью, беспокоясь об этом дубликате UUID, обязательно следите за этим метеоритом... ;) - person Michael Burr; 11.10.2008
comment
Предпочтителен UUID Версия 1, использующий MAC-адрес + текущее время + случайное число. Класс java.util.UUID, связанный с Java, не создает Версию 1, предположительно, из соображений безопасности и конфиденциальности. На странице Википедии, посвященной UUID Implementations, перечислены две библиотеки, которые генерируют версию 1. Но полностью случайным образом. (v4), как правило, достаточно хорош, если генерируется с помощью криптографически стойкого рандомизатора (как в связанном классе). - person Basil Bourque; 04.02.2014

Если он должен быть уникальным для каждого ПК: вы, вероятно, могли бы использовать (System.currentTimeMillis() << 4) | (staticCounter++ & 15) или что-то в этом роде.

Это позволит вам генерировать 16 за мс. Если вам нужно больше, сдвиньте на 5, а затем на 31...

если он должен быть уникальным для нескольких ПК, вам также следует объединить MAC-адрес вашей основной сетевой карты.

редактировать: уточнить

private static int staticCounter=0;
private final int nBits=4;
public long getUnique() {
    return (currentTimeMillis() << nBits) | (staticCounter++ & 2^nBits-1);
}

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

В конце концов он перевернется. Вероятно, 20 лет или около того с nBits на уровне 4.

person Bill K    schedule 10.10.2008
comment
Это умный способ сделать это. Я думаю, что буду доверять классу UUID, поскольку @smiller дал мне больше уверенности в том, что он достаточно уникален. - person Julie; 11.10.2008
comment
Моя компания использует систему, очень похожую на эту, для создания наших UUID. Он работает нормально (я никогда не видел дубликатов). Это кажется действительно хакерским, а также позволяет выяснить, где и когда что-то было создано. - person rmeador; 11.10.2008
comment
Хакерство в том, что я ограничивал себя длинной. Если вы просто использовали два длинных и добавили счетчик к currentTime в синхронизированном методе, он не выйдет из строя, если ваши часы не изменятся. Если вы беспокоитесь об этом, это тоже было бы тривиально исправить. - person Bill K; 13.10.2008

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

Когда мне приходится их генерировать, я обычно использую хеш-сумму MD5 текущей даты, времени, имени пользователя и IP-адреса компьютера. В основном идея состоит в том, чтобы взять все, что вы можете узнать о компьютере/человеке, а затем сгенерировать хэш MD5 этой информации.

Он работает очень хорошо и невероятно быстро (после того, как вы впервые инициализировали MessageDigest).

person Aidos    schedule 13.10.2008

почему бы не сделать так

String id = Long.toString(System.currentTimeMillis()) + 
    (new Random()).nextInt(1000) + 
    (new Random()).nextInt(1000);
person kem    schedule 16.03.2012
comment
Почему вы создаете 2 новых случайных объекта? - person user unknown; 17.03.2012

если вы хотите использовать более короткую и быструю реализацию, взгляните на UUID java:

https://code.google.com/p/spf4j/source/browse/trunk/spf4j-core/src/main/java/org/spf4j/concurrent/UIDGenerator.java

см. варианты реализации и ограничения в javadoc.

вот модульный тест о том, как использовать:

https://code.google.com/p/spf4j/source/browse/trunk/spf4j-core/src/test/java/org/spf4j/concurrent/UIDGeneratorTest.java

person user2179737    schedule 30.09.2014

person    schedule
comment
Хорошее и простое решение, да. Бит кода UUID, вероятно, будет чаще всего вызываться в моем приложении многими потоками одновременно, поэтому накладные расходы/узкое место синхронизации могут быть слишком большими. - person Julie; 13.10.2008
comment
Не сворачивайте свой собственный код UUID. Есть много тонких способов ошибиться. Этот код будет делать плохие вещи, если несколько процессов запускаются в одну и ту же миллисекунду, например, когда вы запускаете группу машин, выполняющих одну и ту же задачу в одно и то же время. - person Mike Samuel; 17.03.2012