Identifikatorların generasiyası
1) Niyə identifikatorlara diqqət yetirmək lazımdır
ID (ID) - mahiyyətin əsas açarı: DB sətirləri, mesajlar, fayl, sifariş. Onun xüsusiyyətləri asılıdır:- Unikallıq və miqyas (toqquşmalar, üfüqi böyümə).
- Sifariş və çeşidləmə (müvəqqəti korrelyasiya, replikasiya, dedup).
- Saxlama performansı (indekslər, qaynar səhifələr, açar ölçüsü).
- Təhlükəsizlik (gözlənilməzlik, sızma, təxmin).
- İstifadəsi/inteqrasiyası (qısa, URL-safe, registrə həssas deyil).
ID seçimi - entropiya, nizamlanma, uzunluq, istehsal sürəti və istismar arasında kompromis.
2) Əsas tələblər və şərtlər
Unikallıq: toqquşma ehtimalı məqbul riskdən aşağı olmalıdır.
Entropiya: «Nə qədər təsadüflər» ID (bit) ehtiva edir.
Nizamlanma (time-sortable/k-sortable): leksikoqrafik çeşidləmə ≈ zamanla çeşidləmə.
Monotoniya: düyün/axın daxilində azalmayan ardıcıllıq.
Qeydin lokalizmi: Yeni insert indeksin «quyruğunda» nə qədər cəmləşir (isti səhifələrin təhlükəsi).
Proqnozlaşdırıla bilər: qonşu şəxsiyyəti təxmin etmək mümkündürmü (təhlükəsizlik/API üçün vacibdir).
Performans: ikili/string, Base16/32/36/58/64, defis, registr.
3) Əsas identifikator ailələri
3. 1 UUID
v4 (random): 122 entropiya bit. Nizamsız, təhlükəsizlik və sadəlik üçün yaxşıdır. Mənfi: təsadüfi paylanmaya görə indekslər «xaotit» - bununla belə, yükləri bərabər şəkildə dağıtır və «qaynar səhifələri» silir.
v1 (time + MAC): nizamlayın, lakin MAS/vaxt (gizlilik) daşıyır; çox vaxt qaçmaq.
v7 (time-ordered): millisaniyə + random hissə. Leksikoqrafik zaman sıralaması və DB-də yaxşı sıxılma üçün dizayn. Kompromis: indeksin «isti quyruğu» görünür; charding/prefiks/inklement ilə müalicə olunur.
Məsləhətlər
Xarici API və qeyri-sabit sifariş tələbləri üçün - v4.
Hadisə/DB və «çeşidlənən» açarlar üçün - v7.
3. 2 ULID (Crockford Base32)
128 bit: 48 bit vaxt (ms) + 80 bit təsadüfi. Leksikoqrafik olaraq vaxtına görə sıralanır, insan dostu (I, L, O, U olmadan), URL-safe. Monoton variasiya var (eyni vaxt işarəsi ilə təsadüfi hissə artır).
Üstünlüklər: oxunma, nizamlanma, dözümlülük.
Mənfi cəhətləri: bir anda çox yüksək tezlikdə - «isti quyruq».
3. 3 KSUID
160 bit: 32 bit vaxt (san) dövrünə nisbətən + 128 bit təsadüfi. Daha böyük zaman diapazonu və sabit çeşidlənmə, ULID-dən daha qısa sətirlər? (yox - daha uzun, lakin kodlama ilə), paylanmış log və obyektlər üçün yaxşıdır.
3. 4 Snowflake bənzər (k-sortable flake ID)
Klassik sxem (xüsusi):
[ timestamp bits ][ region/datacenter bits ][ worker bits ][ sequence bits ]
Xüsusiyyətləri: qovşaqda monoton böyümə, kvazi-qlobal unikallıq, qısa (64 bit) ikili performans.
Risklər: saat asılılığı (sürüklənmə/reqress vaxt), bir tikdə sequence tükənməsi, region/worker bitlərinin koordinasiyası.
Müalicə olunur: «clock back» qorunması, sequence ehtiyat, vaxt detektoru, PTP/NTP intizamı.
3. 5 DB ardıcıllığı (SEQUENCE/IDENTITY)
Bir DBB-də ən sadə monoton nəsil.
Üstünlüklər: qısa, sürətli, yerli cədvəllər üçün əlverişlidir.
Mənfi cəhətləri: qlobal paylanmış klasterdə çətin; proqnozlaşdırıla bilən (ictimai açar kimi təhlükəli), indeksin isti quyruğunu yaradır.
3. 6 Məzmun ünvanı ID (hash content)
SHA-256/Blake3 → sabit ID, deduplikasiya, bütövlük yoxlaması, caching.
Üstünlüklər: determinizm, saxtakarlıqdan qorunma.
Mənfi cəhətləri: bahalı nəsil (CPU), praktik sıfır toqquşmaları, heç bir müvəqqəti çeşidləmə, uzunluğu.
4) Münaqişələr və «ad günləri paradoksu» (intuitiv)
Təsadüfi ölçü ID 'b' bit üçün 'n' generasiyalarında toqquşma ehtimalı təxminən:
p ≈ 1 - exp (-n (n-1 )/2/2 ^ b) ≈ n ^ 2/2 ^ (b + 1) (for small p)
Nümunələr:
- UUIDv4 (122 bit) n = 10 ^ 12 (trilyon) → p ~ 1e-14 (laqeyd).
- 64-bit random → n = 10 ^ 9 artıq p ~ 0. 027 (nəzərəçarpacaq risk).
- Nəticə: 64-bit təsadüfi çox vaxt böyük sistemlər üçün azdır; 96/128 bit istifadə edin.
5) Indekslər, qaynar səhifələr və saxlama
Təsadüfi açarlar (v4) enjeksiyonları indeksin ağacına bərabər paylayır → heç bir «quyruq» yoxdur, lakin daha pis cache lokalizmi.
Zaman sıralanır (v7/ULID/Snowflake) «quyruğa» daxil edilir → ən yaxşı lokallıq və sıxılma, lakin yüksək paralel yazının altında isti səhifələr riski.
- tenant/region üzrə prefikslər/şardinq (vaxtından əvvəl 1-2 bayt əlavə edin);
- interleaving: yüksək bit qəza hissəsi;
- batch insert, B-ağac fillfactor, BRIN avtomobil keçid/böyük yuvaları üçün klaster.
- 'UUID (16B)' vs 'BIGINT (8B) '/' INT8' yaddaş/cache qənaət edir; Base32/58/64 sətirləri ölçünü 20-60% artırır. DB üçün ikiqat saxlayın, kənarda bir sətir seriyalayın.
6) Təhlükəsizlik və məxfilik
URL/API-də ictimai ID kimi SEQUENCE/INT istifadə etməyin: proqnozlaşdırıla bilər → resursların siyahısı.
Xarici linklər üçün random, gözlənilməz ID (v4/v7/ULID/KSUID) əlavə edin.
PII-ni ID-yə kodlamayın. Atributu aktivləşdirmək lazımdırsa, şifrələyin/imzalayın (məsələn, JWE/JWS) və ya qeyri-şəffaf tokenlərdən istifadə edin.
URL təhlükəsiz kodlaşdırma: Base32 Crockford, Base58 ('0OIl' olmadan), Base64url.
7) Multi-tenant, prefiks və marşrut
Format: '[TENANT _ PREFIX] - [ID]' və ya binar: 'tenant _ id | | id'.
Üstünlüklər: kirayəçi üçün sürətli filtrlər/partiyalar, N + 1 skanerdən qorunma.
Mənfi cəhətləri: yuxarı bit entropi sıxlığını pisləşdirə bilər → paylanması düşünün (hash prefiks).
Hash şəkilçisi (2-3 bayt) toqquşmaları azaldır və şard marşrutlamasına kömək edir: 'shard = hash (id)% N'.
8) Praktik seçim tövsiyələri
API, ictimai linklər, ciddi sifariş olmadan paylanmış xidmətlər: UUIDv4, ULID/KSUID.
Tez-tez vaxtına görə sıraladığımız qeydlər/hadisələr/sifarişlər: UUIDv7 və ya ULID (monoton).
Lokal monotonluq və qısa açar ilə ultra yüksək keçid: Snowflake kimi 64-bit (vaxt intizamı tələb olunur).
Artefaktların/binaların/blobların anbarları: məzmun ünvanları (SHA-256), üstdə isə insan dostu qısa «vitrin» (Hashids/link).
Bir DB-də lokal cədvəllər: SEQUENCE/IDENTITY + ictimai linklər üçün xarici «sarğı» (masking).
9) Tətbiqlər və nümunələr
9. 1 PostgreSQL
UUID binar, indeksləri - 'btree' və ya 'hash' ehtiyacına görə saxlayın.
sql
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE TABLE orders (
id uuid PRIMARY KEY DEFAULT gen_random_uuid(), -- или uuid_generate_v4()
created_at timestamptz NOT NULL DEFAULT now(),
tenant smallint NOT NULL
);
-- For time-sortable (UUIDv7) store binary (uuid), generation in the application.
-- If you want a cluster by time:
CREATE INDEX ON orders (created_at DESC);
Sequential hot fix: time-sorted ID üçün yaşlı bitlərə «duz» əlavə edin və ya tenant ilə partizan edin:
sql
CREATE TABLE orders_t1 PARTITION OF orders FOR VALUES IN (1);
CREATE TABLE orders_t2 PARTITION OF orders FOR VALUES IN (2);
9. 2 Redis (atom sayğacları/monutonium)
bash
INCR "seq: orders" # local sequence combine: epoch_ms<<20 (worker_id<<10) (seq & 1023)
9. 3 Snowflake oxşar generator (psevdokod)
pseudo const EPOCH = 1704067200000 # custom epoch (ms)
state: last_ms=0, seq=0, worker=7, region=3
next():
now = epoch_ms()
if now < last_ms: wait_until(last_ms) # защита от clock back if now == last_ms:
seq = (seq + 1) & ((1<<12)-1) # 12 бит if seq == 0: wait_next_ms()
else:
seq = 0 last_ms = now return (now-EPOCH)<<22 region<<17 worker<<12 seq
9. Tətbiqlərdə 4 ULID/UUID
Go
go
// ULID t:= time. Now(). UTC()
entropy:= ulid. Monotonic(rand. New(rand. NewSource(t. UnixNano())), 0)
id:= ulid. MustNew(ulid. Timestamp(t), entropy)
//UUID v7 (if there is a library)
id:= uuid. Must(uuid. NewV7())
Node. js
js import { ulid } from 'ulid';
import { v4 as uuidv4 } from 'uuid';
const id1 = ulid();
const id2 = uuidv4(); // v4
Python
python import uuid, time id_v4 = uuid. uuid4()
For v7, use a library (for example, uuid6/7 third-party packages)
10) Kodlaşdırma və təqdimatlar
BD-də ikili ('BYTEA', 'UUID') → yığcam və sürətli. Kənarda çevirmək:- Base32 Crockford (ULID): registrə həssas deyil, vizual olaraq oxşar simvollar yoxdur.
- Base58: qısa Base32/64 insan oxunan tokenlər üçün, URL-safe.
- Base64url: qısa, lakin '-' və '_' URL-də.
Sətirləri müqayisə edərkən təkrarlanmamaq üçün registr və formatı sabitləşdirin.
11) Test playbook və müşahidə
Toqquşmalar: 'id _ collision _ total' metrikası (0 olmalıdır),> 0-da alert.
Prefikslərin paylanması: böyük baytların histoqramı - alıcılıq axtarırıq.
Generasiya sürəti: 'ids _ per _ sec', p99 generator gecikmə.
Clock skew (Snowflake üçün): qovşaqların ofseti, «clock went back» hadisələri.
İndeks quyruqları: p95/p99 'INSERT' latency; blokların/qaynar səhifələrin payı.
- Enject «clock drift/back» → generator gözləyir/keçid əmin olun.
- Milisaniyədə 'sequence' aşması → gözləmə yoxlaması next_ms.
- Kütləvi paralellik → indeksdə fırtına kilidləri var.
12) Anti-nümunələr
AUTO_INCREMENT/SEQUENCE kimi ictimai ID: təxmin, sızma. Daxili üzərində ictimai qeyri-şəffaf ID istifadə edin.
UUIDv1 (MAS/vaxt): gizlilik.
trilyonlarla qeydlər üçün 64-bit təsadüfi ID: real toqquşma riski.
HA olmadan qlobal «mərkəzi generator»: SPOF və dar yer.
clock back qorunmadan Time-sorted IDs: dublikatlar/regress sifariş.
Açıq versiya/prefiks olmadan müxtəlif ID formatlarını qarışdırın → debag/miqrasiyalarda xaos.
ID-ni müxtəlif qeydlər/formalar olan sətirlər kimi saxlayın → gizli dublikatlar.
13) Giriş çek siyahısı
- Domain tələblərinə uyğun bir format (v4/v7/ULID/KSUID/Snowflake/SEQ/hash) seçilmişdir.
- Sifariş tələbləri müəyyən edilmişdir (çeşidlənmə tələb olunur).
- Toqquşma ehtimalı qiymətləndirilir (b bit, n nəsil) və risk həddi verilir.
- Kodlaşdırma (BD + insan tərəfindən oxunan vitrində binar).
- time-sorted üçün - clock back qorunması, sequence limitləri və NTP/PTP intizam.
- İctimai ID üçün - gözlənilməzlik (random/ULID/KSUID), PII olmaması.
- Şard-routing (hash (id)% N), multi-tenant prefikslər düşünülmüşdür.
- Müşahidə: toqquşma, paylanma, gecikmə, saat skew metrikası.
- Sınaq sequence/yüksək rəqabət/pəncərə uzunluğu.
- Formatın, versiyanın, dövrün, bitli işarələrin sənədləşdirilməsi və miqrasiya planı.
14) FAQ
Q: mikroservislər üçün «default» seçmək üçün nə?
A: UUIDv7 və ya ULID: zamanlama, çox entropi, kənarda sadə nəsil. Xarici API üçün - ULID/UUIDv4 də oxu.
Q: Qısa və insan oxuma ID lazımdır.
A: ULID/KSUID və ya Base58-kodlama 128-bit təsadüfi/müvəqqəti ID. Uzunluğu və toqquşmaları xatırlayın.
Q: «Qısa ədədi» ID etmək mümkündürmü, amma təhlükəsiz?
A: Bəli: daxili SEQ saxlayın və opaque tokenini (96-128 bit rand) və ya duz + imza ilə Hashids verin.
Q: SEQ-dən UUIDv7-ə necə köçmək olar?
A: Yeni 'id _ new' sütununu daxil edin (UUID), ikiqat, yeni bir ID-yə link dərc edin, sonra RC/xarici açarları dəyişdirin və köhnəni silin.
Q: Mənim ULID əlavələrim niyə «isti» oldu?
A: Ciddi artan açarları bir indeksə daxil edin. Partiyalar/tenant parçalayın, yaşlı bitləri qarışdırın, batch əlavələrini istifadə edin.
15) Nəticələr
Yaxşı bir ID bir vəzifə üçün düzgün xüsusiyyətlər toplusudur: kifayət qədər entropiya, proqnozlaşdırıla bilən çeşidləmə (lazım olduqda), təhlükəsiz ictimaiyyət və indekslərin sağlam istismarı. Sadəlik və paylanma üçün UUIDv4/ULID/UUIDv7/KSUID seçin, Snowflake - sıx monotoniya və qısa açarlar üçün (zaman nizamı ilə), ardıcıllıq - yerli cədvəllər üçün, məzmun hash - artefaktlar üçün. Müşahidə və testləri təyin edin - və identifikatorlar sürprizlərin mənbəyi olmağı dayandıracaq.