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

Резюме: Разработвам устойчиво Java уеб приложение и трябва да се уверя, че всички ресурси, които поддържам, имат глобални уникални идентификатори, за да предотвратя дублиране.

Дребният шрифт:

  1. Не използвам RDBMS, така че нямам фантастични генератори на последователности (като този, предоставен от 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) Какъв обем ID ще бъде генериран? Колко бързо? (Колко в секунда/минута) (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) като част от Distributed Computing Environment (DCE) - person Shawn Miller; 11.10.2008
comment
Докато сте будни през нощта и се тревожите за този дублиран UUID, не забравяйте да държите очите си отворени за този метеорит... ;) - person Michael Burr; 11.10.2008
comment
За предпочитане е Версия 1 UUID, като се използва MAC адрес + текущо време + произволно число. Класът java.util.UUID, включен в Java, не генерира Версия 1 вероятно поради опасения за сигурността и поверителността. Страницата на Wikipedia за UUID Имплементации изброява 2 библиотеки, които генерират версия 1. Но напълно произволни (v4) обикновено е достатъчно добър, ако се генерира с криптографски силен рандомайзер (както в пакетния клас). - person Basil Bourque; 04.02.2014

Ако трябва да бъде уникален за компютър: вероятно бихте могли да използвате (System.currentTimeMillis() << 4) | (staticCounter++ & 15) или нещо подобно.

Това ще ви позволи да генерирате 16 на ms. Ако имате нужда от повече, преместете с 5 и го с 31...

ако трябва да бъде уникален за множество компютри, трябва също така да комбинирате MAC адреса на вашата основна мрежова карта.

редактиране: за изясняване

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

и променете nBits на корен квадратен от най-голямото число, което трябва да генерирате за ms.

В крайна сметка ще се преобърне. Вероятно 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

ако искате да използвате по-кратко и по-бързо внедряване на този Java UUID, погледнете:

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