יצירת תעודות זהות
1) מדוע לשים לב לזהויות
זיהוי (ID) - המפתח הבסיסי של הישות: מסדי נתונים, הודעות, קובץ, סדר. התכונות שלו תלויות:- ייחודיות וסקלה (התנגשויות, צמיחה אופקית).
- סדר ומיון (מתאם זמן, שכפול, dedup).
- ביצועי אחסון (אינדקסים, עמודים חמים, גודל מפתח).
- בטיחות (בלתי צפויה, דליפות, ניחושים).
- שימושיות/אינטגרציה (קיצור, URL-בטוח, לא רגיש למקרה).
בחירת תעודת זהות היא פשרה בין אנטרופיה, סדר, אורך, שיעור הדור וניצול.
2) דרישות מפתח ומונחים
ייחודיות: ההסתברות להתנגשות חייבת להיות נמוכה מהסיכון המקובל.
אנטרופיה: "כמה אקראיות מכילה תעודת זהות (ביט).
זמן סביר/k-בערך-לקסיקוגרפי מיון מבוסס זמן.
מונוטוני: רצף לא יורד בתוך צומת/זרם.
מיקום הכניסה: עד כמה התוספת החדשה מרוכזת ב ”זנב” האינדקס (סכנת דפים חמים).
חיזוי: האם ניתן לנחש תעודות זהות שכנות (חשובות לביטחון/API).
ייצוג: בינארי/מחרוזת, Base16/32/36/58/64, מקפים, מקרה.
3) משפחות מזהות עיקריות
3. 1 UID
v4 (אקראי): 122 סיביות של אנטרופיה. מבולבל, טוב לבטיחות ופשטות. מינוס: מדדים ”כאוטיים” בשל הפצה אקראית - אשר, לעומת זאת, מפזרים באופן שווה עומסים ומסירים ”דפים חמים”.
V1 (זמן + MAC): לארגן, אבל נושא MAC/זמן (פרטיות); לעתים קרובות נמנע.
זמן אלפית שנייה + חלק אקראי. עיצוב למיון לקסיקוגרפי לפי זמן ודחיסה טובה בבסיס הנתונים. פשרה: מופיע ”הזנב החם” של האינדקס; מטופל על ידי גרידה/קידומת/גיבוב.
טיפים
עבור רכיבי API חיצוניים ודרישות סדר רופפות - V4.
למאורע/יומן מסדי נתונים ו ”ממוין” מפתחות - v7.
3. 2 ULID (קרוקפורד Base32)
128 סיביות: 48 סיביות זמן (ms) + 80 סיביות של אקראיות. מיון לקסיקוגרפי לפי הזמן, ידידותי לאדם (ללא ”I, L, O, U”, URL-Safe). קיימת וריאציה מונוטונית (עם אותה חותמת זמן, החלק האקראי גדל).
מקצוענים: קריאות, סדר, ניידות.
חסרונות: עם תדירות גבוהה מאוד של כניסות בנקודה אחת בזמן - ”זנב חם”.
3. 3 KSUID
160 ביט: 32 ביט של זמן (שנייה) ביחס לתקופה + 128 ביט של אקראיות. טווח זמן גדול יותר ומיון יציב, מיתרים קצרים יותר מ-ULID? (כבר לא, אבל עם קידוד משלו), טוב עבור בולי עץ מבוזרים וחפצים.
3. 4 פתית שלג דמוי (מזהים פתיתי k-סבירים)
סכימה קלאסית (מותאמת אישית):
[ timestamp bits ][ region/datacenter bits ][ worker bits ][ sequence bits ]
מאפיינים: גידול מונוטוני בצומת, ייחודיות קוואזי-גלובלית, ייצוג בינארי קצר (64 סיביות).
סיכונים: תלות בשעון (סחף זמן/רגרסיה), תשישות רצף בקרצייה אחת, קואורדינציה של סיביות אזור/פועל.
מטופלים: הגנה מפני ”שעון אחורי”, רצף מילואים, גלאי זמן, משמעת PTP/NTP.
3. 5 רצפי DB (רצף/זהות)
הדור המונוטוני הפשוט ביותר בשבר אחד של DBMS.
מקצוענים: קצר, מהיר, נוח לשולחנות מקומיים.
חסרונות: קשה גלובלית באשכול מבוזר; צפוי (חסר ביטחון כמפתח ציבורי), יוצר זנב חם של המדד.
3. 6 תעודות זהות כתובות תוכן (תוכן חשיש)
תוכן SHA-256/Blake3 מספר זיהוי יציב, שכפול, בדיקת שלמות, זימון.
מקצוענים: דטרמיניזם, הגנה מפני החלפה.
חסרונות: דור יקר (מעבד), התנגשויות הן אפסים מעשיים, אין מיון זמן, אורך.
4) התנגשויות ו ”פרדוקס יום ההולדת” (אינטואיטיבי)
הסתברות ההתנגשות לזיהוי אקראי של גודל 'b' ביטים ב 'דורות היא בקירוב:
p ≈ 1 - exp (-n (n-1 )/2/2 ^ b) ≈ n ^ 2/2 ^ (b + 1) (for small p)
דוגמאות:
- UUIDv4 (122 סיביות) ב- n = 10 בחזקת 12 (טריליון) כפול p ~ 1e-14 (זניח).
- 64 סיביות אקראיות עם n = 10 _ 9 כבר ~ 0. 027 (סיכון בולט).
- מסקנה: 64 סיביות אקראיות לרוב אינן מספיקות למערכות ענקיות; השתמש 96/128 סיביות.
5) אינדקסים, עמודים חמים ואחסון
מקשים אקראיים (v4) מפזרים באופן שווה את החדירות על פני עץ האינדקס.
זמן מיון (v7/ULID/Snowflake) מוכנס ”בזנב” = מקום טוב יותר ודחיסה, אך הסיכון של דפים חמים תחת הקלטה מקבילה גבוה.
- קידומת/כרישה על ידי דייר/אזור (להוסיף 1-2 ביטים לפני הזמן);
- השתלבות: חלק מהאקראיות בחלקים הגבוהים;
- הכנסת צרור, פילפקטור ב-B-tree, מעבר אוטומטי ל-BRIN/קיבוצים עבור בולי עץ גדולים.
- 'UUID (16B)' נגד 'BIGINT (8B) '/' INT8' זיכרון/מטמון; Base32/58/64 שורות גדלות ב-20-60%. לבסיס הנתונים, לאחסן בינארי, להתאים מחרוזת על הקצה.
6) ביטחון ופרטיות
אל תשתמש ב ־ SEQUENCE/INT כמזהה ציבורי ב ־ URL/API: ניתן לנחש את מספר המשאבים.
הוסף תעודות זהות אקראיות ובלתי צפויות (v4/v7/ULID/KSUID) עבור אזכורים חיצוניים.
אין לקודד PII לזיהוי. אם ברצונך לאפשר את התכונה, הצפן/סימן (לדוגמה, JWE/JWS) או השתמש באסימונים אטומים.
Base32 קרוקפורד, Base58 (ללא '0OIL'), Base64url.
7) עמידות מרובה, קדימות וניתוב
תבנית: ” TENANT _ PREFIX - ID ”.
מקצוענים: מסננים מהירים/דיירים, הגנה מפני סריקות N + 1.
חסרונות: עלול להחמיר את צפיפות האנטרופיה בביטים הגבוהים יותר.
Hash suffix (2-3 bytes) מפחית התנגשויות ועוזר לחתוך ניתוב: ”רסיס = חשיש (id)% N”.
8) המלצות מעשיות לבחירה
API, קישורים ציבוריים, שירותים מבוזרים ללא סדר קפדני: UUIDv4, ULID/KSUID.
רישומים/אירועים/פקודות, בהם אנו ממיינים על ידי זמן: UUIDv7 או ULID (מונוטון).
רוחב פס גבוה ביותר עם מונוטוני מקומי ומפתח קצר: פתית שלג דמוי 64 ביט (משמעת זמן נדרשת).
כספות של חפצים/בונים/בועות: תוכן-addressable (SHA-256), ועל גבי - ”Showcase” קצר ידידותי לאדם (Hashids/link).
טבלאות מקומיות במסד נתונים אחד: SEQUENCE/IDATION + ”עטיפה” חיצונית עבור קישורים ציבוריים (מיסוך).
9) יישומים ודוגמאות
9. 1 פוסט ־ GreSQL
לאחסן את UUID בינארי, אינדקסים - 'בטרי' או 'חשיש' לפי הצורך.
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);
תיקון חם רציף: עבור זיהוי ממוין בזמן, הוסף ”מלח” לחלקים העליונים או ציון על ידי הדייר:
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 רדיס (דלפקי אטום/מונוטוניה)
bash
INCR "seq: orders" # local sequence combine: epoch_ms<<20 (worker_id<<10) (seq & 1023)
9. 3 גנרטור דמוי פתית שלג (פסאודו-קוד)
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. 4 ULID/UUID ביישומים
לכי
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 import uuid, time id_v4 = uuid. uuid4()
For v7, use a library (for example, uuid6/7 third-party packages)
10) קישוטים וייצוגים
בינארי בבסיס הנתונים ("BYTEA", "UUId') * קומפקטי ומהיר. בקצה, להמיר ל:- Base32 קרוקפורד (ULID): מקרה חסר רגישות, אין דמויות דומות ויזואלית.
- Base58: בקיצור Base32/64 אסימונים ניתנים לקריאה אנושית, URL-בטוח.
- Base64url: קצר, אבל '-&ft ו' _ "בכתובת.
ייצוב מקרה ופורמט (מקפים/אף אחד) כדי למנוע שכפולים בעת השוואת מחרוזות.
11) ספרי משחק מבחנים ויכולת תצפית
התנגשויות: 'id _ collusion _ total' (חייב להיות 0), התראה ב> 0.
הפצת קידומת: היסטוגרמה של ביטים גבוהים - אנחנו מחפשים לקנות.
קצב הדור: ”ids _ per _ sec”, p99 generator latency.
שעון סקיו (עבור פתית שלג): צומתי קיזוז, ”השעון חזר” אירועים.
זנבות אינדקס: p95/p99 ”INSERT” Latency; פרופורציה של מנעולים/עמודים חמים.
- הזרקת ”סחף שעון/חזרה” = לוודא שהגנרטור ממתין/מתחלף.
- ”רצף” עולה על גדותיו באלפיות שנייה next_ms בדיקת המתנה.
- מקבילית המסה = האם ישנן סופות של מנעולים באינדקס.
12) אנטי דפוסים
AUTO_INCREMENT/SEQUENCE כזיהוי ציבורי: ניחוש, הדלפות. השתמש בתעודת זהות אטומה לציבור על אחד פנימי.
UUIDv1 (MAC/time): פרטיות.
זיהוי אקראי של 64 סיביות לטריליון כניסות: סיכון אמיתי להתנגשויות.
גלובל ”גנרטור מרכזי” ללא HA: ספופ וצוואר בקבוק.
תעודות זהות ממוינות ללא הגנת שעון אחורי: שכפול/רגרסיה של סדר.
ערבוב פורמטי זיהוי שונים ללא גירסה מפורשת/קידומת = תוהו ובוהו בדיון/הגירה.
שמירת תעודת זהות כמחרוזת עם רגיסטרים/טפסים שונים.
13) רשימת מימושים
[ ] תבנית נבחרת (v4/v7/ULID/KSUID/Snowflake/SEQ/hash) לדרישות התחום.
[ דרישות סדר ] מוגדרות (בין אם דרושה סבירות).
[ ] ההסתברות להתנגשויות (b סיביות, n דורות) מוערכת וסף הסיכון נקבע.
[ ] הקידוד מעוצב (בינארי במופע ראווה שניתן לקרוא ע "י DB + אדם).
[ ] למיון זמן - הגנה לאחור שעון, מגבלות רצף ומשמעת NTP/PTP.
[ ] לתעודות זהות ציבוריות - בלתי צפויות (אקראי/ULID/KSUID), היעדר מח "ש.
[ ] מחשבה על חשיש (id)% N, קדימות רב דייר.
[ ] תצפית: התנגשות, הפצה, איחור, מדדי ריחוף השעון.
[ ] רצף/מחלוקת/חלונות אורך עוקף מקרי בדיקה.
[ פורמט ], גרסה, תקופות, מפת סיביות ותיעוד תוכניות נדידה.
14) FAQ
Q: מה לבחור ”ברירת מחדל” במיקרו ־ רחם?
A: UUIDv7 או ULID: הזמנת זמן, הרבה אנטרופיה, עבור API חיצוני, ULID/UUIDv4 הוא גם אישור.
קיו: צריך זיהוי קצר וניתן לקריאה אנושית.
A: ULID/KSUID או Base58-128-bit קידוד זיהוי אקראי/זמני. זכור על אורך והתנגשויות.
ש: האם זה אפשרי לבצע זיהוי מספרי קצר, אבל בטוח?
א. כן: לאחסן את ה ־ SEQ הפנימי, ומחוץ לו לתת את האסימון האטום (96-128 סיביות אקראיות) או האשידים עם חתימה של מלח +.
קיו: איך אני נודד מ ־ SEQ ל ־ UUIDv7?
A: הזן טור חדש ”id _ new” (UUID), דו-רצועה, פרסם אזכורים לתעודת הזהות החדשה, לאחר מכן החלף מפתחות DC/זרים ומחק את הישן.
קיו: למה הכנסת האיי-אל-איי שלי הייתה ”חמה”?
א ': הוספת מפתחות מגדילים במדד אחד בלבד. מחיצה/דייר, לערבב ביטים בהזמנה גבוהה, להשתמש בכניסות אצווה.
15) סיכומים
זיהוי טוב הוא הסט הנכון של תכונות לבעיה: מספיק אנטרופיה, מיון צפוי (במידת הצורך), פרסום בטוח וניצול בריא של מדדים. בחר UUIDv4/ULID/UUIDv7/KSUID לפשטות והפצה, פתית שלג למונוטוניות צפופות ומפתחות קצרים (לדיסציפלינת זמן), רצפים לטבלאות מקומיות, חשיש תוכן לחפצים. להניח את יכולת התצפית ובדיקות - ומזהים יחדלו להיות מקור של הפתעות.