Генерировать уникальный идентификатор в Java, маркировать группы связанных записей в журнале

В этой теме есть несколько сообщений по SO. Каждый из них говорит о конкретном подходе, поэтому хотел просто получить сравнение в одном вопросе.

Использование новой даты() как уникального идентификатора

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

Я пытаюсь реализовать функцию, в которой мы можем идентифицировать определенные события в файле журнала. Эти события должны быть связаны с уникальным идентификатором. Я пытаюсь разработать стратегию для этого уникального поколения. Идентификатор должен иметь 2 части: некоторая статическая информация + некоторая динамическая информация Журналы можно искать для шаблона, когда требуется отладка событий. У меня есть три способа:

  • статическая информация + Joda Дата времени ( "abc" + 2014-01-30T12: 36: 12.703)
  • статическая информация + атомное целое
  • статическая информация + UUID

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

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

  • Если не один из вышеперечисленных, любая другая стратегия?
  • Является ли стратегия времени, основанная на Йоде надежной? JVM является одиночным, но будут одновременные пользователи, поэтому могут быть параллельные события.
  • В сочетании с одной из вышеперечисленных/других стратегий, мне нужно сделать мой метод потокобезопасным/синхронизированным?

Ответ 1

У меня была такая же потребность, как и вы, различая поток связанных записей, чередующихся с другими несвязанными записями в журнале. Я пробовал все три предложенных вами подхода. Мой опыт был в 4D, а не Java, но аналогичен.

Date-Time

В моем случае я использовал значение даты и времени, определенное на целые секунды. Это просто слишком большая зернистость. Я легко столкнулся с конфликтами, когда в течение одной секунды началось несколько событий. Проклятье этих быстрых компьютеров!

В вашем случае с комплектом java.util.Date или Joda-Time (рекомендуется для других целей), оба разрешают миллисекунды. Миллисекунда долгое время находится в современных компьютерах, поэтому я не рекомендую это.

В Java 8 новый java.time. * package (вдохновленный Joda-Time, определяемый JSR 310) разрешает наносекунды. Это может показаться лучшим идентификатором, но нет. Во-первых, ваши физические часы физического времени вашего компьютера могут не поддерживать такое прекрасное разрешение. Другое дело, что компьютеры продолжают расти. Наконец, компьютерные часы могут быть reset, действительно, это reset часто, поскольку компьютерные часы дрейфуют совсем немного. Современные ОС reset их часы часто проверяются с помощью сервера времени локально или через Интернет.

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

Серийный номер

Под "Atomic Integer", я предполагаю, что вы имеете в виду серийный номер, увеличивающийся до увеличения числа.

Это кажется излишним для вашей цели.

  • Вы не заботитесь о последовательности, это не имеет значения для этой цели группировки записей журнала. Вам все равно, если одна группа заняла n-е число до или после другой группы.
  • Поддержание последовательности - это боль, точка потенциального отказа. Я всегда сталкивался с административными проблемами, поддерживая последовательность.

Таким образом, этот подход добавляет риск, не добавляя особых преимуществ.

UUID

Бинго! Только то, что вам нужно.

A UUID легко сгенерирован с использованием либо возможности класса java.util.UUID для генерации Версии 3, либо 4 UUID, или используя стороннюю библиотеку или доступ к инструменту командной строки uuidgen.

Для очень большого объема лучше всего использовать UUID [Version 1] (MAC + дата-время + случайное число). Для ведения журнала, Версия 4 UUID (полностью случайный) абсолютно приемлем.

Наличие столкновения не представляет собой реалистичную проблему. Специально для ограниченного числа значений, которые вы будете генерировать для журналов. Меня поражают люди, которые, не понимая числа, говорят, что они никогда не заменит последовательность UUID. Но при нажатии каждый программист и системный администратор, которых я знаю, испытывали сбои хотя бы с одной последовательностью.

Отсутствует проблема безопасности потоков. Никаких опасений по поводу споров (см. Мои результаты теста на еще один мой ответ).

Другим преимуществом UUID является его обычный hexadecimal, например:

6536ca53-BCAD-4552-977f-16945fee13e2

... легко узнаваем. Когда распознано, читатель сразу знает, что строка должна быть уникальным идентификатором. Таким образом, присутствие в вашем журнале самодокументируется.

Я обнаружил, что UUID являются канальной машиной. Я продолжаю искать для них новые возможности.

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

В то время как представление шестнадцатеричной строки UUID трудно читать и писать, на практике вам нужно лишь отсканировать несколько цифр в начале или конце. Или используйте copy-paste с функциями поиска и фильтрации в наших современных консольных инструментах.

Несколько фактоидов

  • UUID известен в мире Microsoft как GUID.
  • UUID - это не строка, а 128-битное значение. Биты, только бит в памяти, "on"/ "off" значения. Некоторые базы данных, такие как Postgres, умеют обрабатывать и хранить UUID как таковые 128-битные значения. Если мы хотим показать эти биты людям, мы можем использовать серию из 128 цифр "1" и "0". Но люди не очень хорошо читают или пишут 128 цифр единиц и нулей. Поэтому мы используем шестнадцатеричное представление. Но даже 32 шестнадцатеричных цифры слишком много для людей, поэтому мы разбиваем строку на группы, разделенные дефисом, как показано выше, всего 36 символов.
  • Спецификация для UUID совершенно ясно, что шестнадцатеричное представление должно быть строчным. Спектр говорит, что при создании UUID из строкового ввода верхний регистр должен допускаться. Но при генерации шестнадцатеричной строки она должна быть строчной. Многие реализации UUID игнорируют это требование. Я предлагаю придерживаться спецификации и преобразовывать шестнадцатеричные строки UUID в нижний регистр.

MDC - отображаемый контекст диагностики

Я еще не использовал MDC, но хочу указать на это...

Некоторые фреймворки регистрации добавляют поддержку этой идеи помечания связанных записей журнала. Такая поддержка называется Mapped Diagnostic Context (MDC). MDC управляет контекстной информацией по каждому потоку.

Быстрая вводная статья Log4j MDC (контекстный диагностический контекст): что и почему.

Лучший каротажный фасад, SLF4J, предлагает функция MDC. Лучшая реализация этого фасада Logback имеет глава документируя его функцию MDC.

Ответ 2

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

Вместо этого используйте UUID. На странице JSE 6.0 UUID API "[UUID is] Класс, который представляет неизменный универсально уникальный идентификатор (UUID).

Вот какой код:

import java.util.UUID;

private String id;

id = UUID.randomUUID().toString();

Ответ 3

Я написал простую службу, которая может генерировать полу-уникальные несекретные 64-битные номера. Он может быть развернут на нескольких машинах для резервирования и масштабируемости. Он использует ZeroMQ для обмена сообщениями. Для получения дополнительной информации о том, как это работает, посмотрите страницу github: zUID