Какие типы ID используются: UUID v4 или Snowflake?
Что проверяют
Понимаете ли вы, как выбор идентификатора бьёт по базе, по распределённой генерации и по безопасности. Следом почти всегда спрашивают про UUID v7 и про то, что происходит с индексом при случайных ключах.
Как отвечать
Сравните по устройству, а потом по последствиям:
- UUID v4: 128 бит, из них 122 случайных. Генерируется где угодно без координации, коллизии на практике исключены, ID не раскрывает ни время, ни объём данных. В PostgreSQL тип
uuidзанимает 16 байт; - Snowflake: 64 бита, помещается в
int64иbigint. Классическая раскладка: 41 бит миллисекунд от своей эпохи (примерно 69 лет), 10 бит номера узла (до 1024 генераторов) и 12 бит счётчика (до 4096 ID в миллисекунду на узел). ID растут со временем, но выдают время создания; - UUID v7 (RFC 9562, 2024): компромисс. 48 бит Unix-времени в миллисекундах плюс случайная часть, те же 128 бит, но с порядком по времени. В PostgreSQL 18 появилась встроенная функция
uuidv7().
Главное последствие для базы: случайный v4 в первичном ключе вставляется в произвольные страницы B-tree индекса. Отсюда разбиения страниц, раздутый индекс и промахи кэша на больших таблицах. Монотонные Snowflake и v7 пишутся в правый край индекса.
В Go для UUID обычно берут github.com/google/uuid (в нём есть и uuid.NewV7()), для Snowflake github.com/bwmarrin/snowflake или sonyflake. Узкое место Snowflake это раздача номеров узлов: при автомасштабировании подов номер берут из конфига, базы или координатора, иначе два пода получат одинаковый номер и начнут выдавать одинаковые ID.
Где спотыкаются
Говорят, что UUID «просто больше». Главная цена не 16 байт против 8, а случайный порядок вставки в индекс.
Забывают про часы. Snowflake зависит от времени узла: если NTP перевёл часы назад, генератор должен ждать или падать, иначе появятся дубли.
Отдают 64-битный ID в JSON числом. В JavaScript точность Number заканчивается на 2^53, фронтенд молча испортит последние цифры. Такие ID сериализуют строкой, в Go для этого есть тег json:",string".