آیا به شناسهای نیاز دارید که با شناسهای که شخص دیگری ساخته است تداخل نداشته باشد، آن هم روی دستگاهی که هرگز نام آن را نشنیدهاید و بدون اینکه از کسی اجازه بگیرید؟ این دقیقا کاری است که یک UUID انجام میدهد. این یک عدد 128 بیتی است که به صورت 36 کاراکتر در الگوی آشنای 8-4-4-4-12 نوشته میشود، و کل طراحی آن به گونهای است که هیچ دو مورد از آنها یکسان نخواهند بود، حتی با وجود اینکه هیچ چیزی هماهنگ نمیکند که چه کسی کدام را دریافت کند. این تولیدکننده رایگان، آنها را در مرورگر شما میسازد: یک نسخه را در «نسخه» انتخاب کنید، بگویید چند عدد نیاز دارید در «تعداد»، و روی «تولید» کلیک کنید. صفحه با یک v4 تکی باز میشود، نسخهای که اکثر پروژهها به آن نیاز دارند، بنابراین اولین شناسه تنها با یک کلیک در دسترس شماست.
هر شناسه توسط مرورگر شما و از طریق Web Crypto API ساخته میشود. نسخه 4 در صورت پشتیبانی مرورگر از crypto.randomUUID() استفاده میکند و در غیر این صورت از crypto.getRandomValues() بهره میبرد — که یک منبع قوی و از نظر رمزنگاری ایمن برای اعداد تصادفی است، نه یک تابع شبهتصادفی JavaScript مانند Math.random(). نسخه 7 یک مهر زمانی 48 بیتی با دقت میلیثانیه را در ابتدا قرار میدهد، سپس یک شمارنده 12 بیتی که در همان میلیثانیه افزایش مییابد، و در نهایت 62 بیت تصادفی؛ این همان روش مرتبسازی است که در RFC 9562 توضیح داده شده است. همین شمارنده است که باعث میشود یک دسته هزارتایی به جای درهمریختگی، به ترتیب تولید شود. نسخه 1 یک مهر زمانی را با یک شناسه گره تصادفی که بیت چندپخشی فعال است ترکیب میکند، بنابراین برخلاف پیادهسازیهای اولیه در دهه 1990، هرگز آدرس کارت شبکه شما را در خود حمل نمیکند. نسخههای 3 و 5 به هیچ وجه تصادفی نیستند: آنها یک فضای نام و یک نام را با استفاده از MD5 و SHA-1 هش میکنند، و این عملیات هشینگ نیز روی دستگاه شما اتفاق میافتد. هیچ چیزی به سرور ارسال نمیشود، هیچ چیزی ثبت نمیشود و پس از بارگذاری صفحه، حتی با قطع اتصال اینترنت نیز به کار خود ادامه میدهد.
«نسخه» فیلدی است که همه چیزهای دیگر را تعیین میکند. نسخه 4 شامل 122 بیت تصادفی و بدون هیچ ساختار خاصی است — این حالت پیشفرض و پاسخ درست زمانی است که یک شناسه فقط باید یکتا باشد. نسخه 7 دارای 62 بیت تصادفی است اما با زمان ایجاد آن شروع میشود، بنابراین مجموعهای از آنها بر اساس زمان ساخته شدن مرتب میشوند؛ به همین دلیل است که وقتی قرار است شناسه به کلید پایگاه داده تبدیل شود، باید به سراغ این نسخه رفت. نسخه 1 همان طرح اولیه مبتنی بر زمان است که فقط برای سیستمهایی که هنوز به آن نیاز دارند در اینجا نگه داشته شده است. نسخههای 3 و 5 جفت عجیبی هستند: آنها قطعی هستند، به این معنی که ورودیهای یکسان همیشه شناسه یکسانی تولید میکنند، و دو فیلد اضافی میگیرند — «فضای نام» که یکی از فضاهای استاندارد DNS، URL، OID و X.500 یا یک فضای «دلخواه» متعلق به خود شماست، و «نام» که همان رشتهای است که باید شناسایی شود. اگر به v5 فضای نام URL و https://example.com/a را بدهید، امروز، فردا و روی دستگاه هر شخص دیگری دقیقاً همان UUID را دریافت خواهید کرد. به همین دلیل، وقتی v3 یا v5 انتخاب میشود فیلد «تعداد» ناپدید میشود: هزار کپی از یک مقدار قطعی، صرفا هزار کپی از همان مقدار قطعی خواهد بود. برای هر نسخه دیگری، «تعداد» از 1 تا 1000 قابل تنظیم است.
چهار کلید تغییر وضعیت، ظاهر خروجی را بدون تغییر 128 بیت زیرین آن تغییر میدهند. «حروف بزرگ» ارقام هگزادسیمال را به صورت حروف بزرگ چاپ میکند، «بدون خط تیره» فرم فشرده 32 کاراکتری را که برخی ستونها و نامهای فایل ترجیح میدهند ارائه میدهد، و «آکولادها» مقدار را داخل { } قرار میدهد — شکلی که در دنیای Windows و .NET به آن GUID میگویند. در زیر «گزینههای پیشرفته»، گزینه urn:uuid: پیشوندی را اضافه میکند که آن را به یک URN رسمی تبدیل میکند؛ فعال بودن آن، دو گزینه «آکولادها» و «بدون خط تیره» را خاموش میکند، زیرا استاندارد فقط اجازه یک شکل URN را میدهد و آن همان فرم اصلی با خطوط تیره است. «فرمت کپی» تصمیم میگیرد وقتی یک دسته را کپی میکنید چگونه به هم متصل شوند: یکی در هر خط، جدا شده با کاما، یا هر مقدار داخل کوتیشن با یک کاما در انتها، که مستقیماً داخل یک آرایه در کد پیست میشود. در زیر نتیجه، خطی وجود دارد که میزان تصادفی بودن را بر حسب بیت — 122 برای v4، 62 برای v7 — و برای v7، مهر زمانی رمزگذاری شده در اولین شناسه دسته را گزارش میدهد، بنابراین زمانِ درونِ مقدار، به جای پنهان ماندن، قابل مشاهده است. دکمههای «کپی همه» و «ذخیره در فایل» هر دو از «فرمت کپی» پیروی میکنند. «تاریخچه» 10 دسته آخر شما را در مرورگر خودتان نگه میدارد: روی یکی کلیک کنید تا آن را برگردانید، یک مورد خاص را کپی یا حذف کنید، یا همه را پاک کنید. دکمه «پاک کردن»، نتایج را خالی میکند اما تنظیمات شما را دستنخورده میگذارد، و از 50 شناسه به بعد، لیست به جای پنجاه سطر مجزا، تبدیل به یک بلوک قابل اسکرول میشود.
مهمترین نکته در این صفحه، تفاوت بین v4 و v7 به عنوان کلید اصلی است و این مسئلهای سلیقهای نیست. ایندکسهای پایگاه داده، درختهایی هستند که به ترتیب مرتب نگه داشته میشوند، و اینکه یک کلید جدید کجای آن ترتیب قرار گیرد، تعیین میکند که درج چقدر هزینه در بر خواهد داشت. یک کلید v4 تصادفی است، بنابراین درجهای متوالی در گوشههای نامرتبطی از ایندکس قرار میگیرند: صفحاتی که پر بودهاند دچار شکستگی میشوند، بخشهایی از درخت که پایگاه داده در حافظه نگه میدارد به ندرت همان بخشهایی هستند که درج بعدی به آنها نیاز دارد، و در نهایت ایندکس بسیار بزرگتر و تکهتکهتر از آن چیزی میشود که سطرهای اشاره شده توسط آن توجیه میکنند. یک کلید v7 با میلیثانیه فعلی شروع میشود، بنابراین درجهای متوالی در کنار یکدیگر در لبه سمت راست درخت قرار میگیرند، که همان الگویی است که یک عدد صحیح افزایشی خودکار ایجاد میکند و همان الگویی است که ساختارهای ایندکس برای آن ساخته شدهاند. کل مبادله همین است: v7 رفتار درج یک کلید متوالی را برای شما فراهم میکند در حالی که ویژگی اولیهای را که باعث شد UUID را انتخاب کنید، حفظ میکند؛ یعنی اینکه هر کسی میتواند بدون درخواست از یک سرور، یکی از آنها را بسازد. هزینهای که برای این کار میپردازید این است که اکنون زمان ایجاد در داخل شناسه قابل خواندن است، و اینکه آیا این موضوع اهمیت دارد یا نه، سوالی درباره دادههای شماست، نه درباره فرمت آن.
هیچ چیزی هرگز یکتا بودن یک UUID را بررسی نمیکند؛ اندازه آن، ضمانت آن است. هیچ ثبتی وجود ندارد، هیچ رفتوبرگشتی به سرور در کار نیست و هیچ جستجویی انجام نمیشود — یک تولیدکننده عددی را تولید کرده و تحویل میدهد، و دلیل اینکه دو مورد از آنها با هم تداخل پیدا نمیکنند صرفاً این است که 2^122 مقدار ممکن برای v4 وجود دارد، یعنی حدود 5.3 × 10^36. مسئله تولد راهی صادقانه برای اندازهگیری این موضوع است: شما تقریباً به 2.7 × 10^18 شناسه نیاز دارید تا احتمال مطابقت هر دو مورد از آنها به 50% برسد، که معادل تولید یک میلیارد UUID جدید در هر ثانیه به مدت 86 سال است. ارزشش را دارد که درباره آنچه این موضوع وعده میدهد و آنچه وعده نمیدهد دقیق باشیم. این یک ضمانت آماری است، نه یک ضمانت ریاضی، و تنها تا زمانی معتبر است که تصادفی بودن پایه واقعی باشد — تولیدکنندهای که بذر بدی داشته باشد، یا ماشین مجازی که همراه با استخر انتروپی خود کلون شده باشد، آن را به روشی میشکند که فرمت قادر به تشخیص آن نیست. نسخه 7 این مسئله را حتی محدودتر میکند: در داخل یک میلیثانیه واحد، یک تولیدکننده به هیچ وجه نمیتواند خود را تکرار کند، زیرا شمارنده به جای انداختن تاس، افزایش مییابد، و در میان تولیدکنندههای مستقل، 62 بیت تصادفی کار را انجام میدهند.
یک UUID یک شناسه است، نه یک رمز عبور. نسخه 4 غیرقابل پیشبینی است، و این امر افراد را وسوسه میکند که با آن به عنوان یک راز برخورد کنند — یک لینک بازیابی رمز عبور، یک URL غیرقابل حدس، یک توکن نشست، یا یک کلید API. غیرقابل پیشبینی بودن واقعی است، اما محرمانه بودن ویژگیِ نحوه مدیریت یک مقدار است، و شناسهها از روی عمد بیدقت مدیریت میشوند: آنها در URLها قرار میگیرند، که به تاریخچه مرورگر، گزارشهای سرور، هدرهای referrer و سیستمهای آمارگیر ختم میشوند، و در پیامهای چت پیست میشوند. نسخههای دیگر گزینههای به مراتب بدتری هستند. نسخههای 1 و 7 هر دو زمان ایجاد را در خود رمزگذاری میکنند، بنابراین هر کسی که یکی از آنها را در دست داشته باشد میداند که تقریباً چه زمانی ساخته شده است و میتواند محدوده هر چیز دیگری را که در همان زمان ساخته شده محدود کند. نسخههای 3 و 5 عمداً قطعی هستند: یک UUID v5 از یک آدرس ایمیل، یک راز هششده نیست، بلکه مقداری است که هر کسی که همان آدرس را بداند میتواند در یک ثانیه آن را محاسبه کند. برای نامگذاری یک چیز از UUID استفاده کنید. وقتی مقداری باید ناشناخته بماند، از یک تولیدکننده رمز عبور یا یک توکن از کتابخانهای که برای رازها ساخته شده است، استفاده کنید.
چرا این تولیدکننده UUID را انتخاب کنید؟
- تولید صرفاً در مرورگر: شناسهها روی دستگاه شما ساخته میشوند و هرگز به هیچ جایی ارسال نمیشوند
- تصادفی بودن Web Crypto API: از نظر رمزنگاری ایمن، نه استفاده از Math.random()
- پنج نسخه در یک مکان: v1، v3، v4، v5 و v7، بدون نیاز به تغییر ابزارها
- نسخه v7 واقعاً مرتبشده: یک شمارنده در داخل میلیثانیه، همانطور که RFC 9562 توصیف میکند
- نسخههای قطعی v3 و v5 با چهار فضای نام استاندارد یا فضای نام متعلق به خودتان
- تا 1000 عدد در یک بار، همراه با یک لیست فشرده و قابل اسکرول پس از پنجاه عدد
- همه شکلهای رایج: خط تیرهدار، ساده، حروف بزرگ، دارای آکولاد یا پیشوند urn:uuid: URN
- کپی به صورت خطوط، با کاما یا مقادیر داخل کوتیشن برای پیست کردن مستقیم در کد
- نامحدود و رایگان: بدون ثبت نام، بدون محدودیت استفاده، بدون هیچ دادهای روی سرورهای ما
از UUIDها در هر جایی که باید چیزی نامگذاری شود پیش از آنکه کسی بتواند آزاد بودن نام را تأیید کند، استفاده میشود. کد برنامهها آنها را برای سطرهایی که قرار است درج کنند میسازند، تا شیء قبل از رسیدن به پایگاه داده هویتی داشته باشد و کلاینت بتواند در حالی که فرآیند نوشتن هنوز در جریان است، به آن ارجاع دهد. سیستمهای توزیعشده حتی بیشتر به آنها متکی هستند: چندین سرویس که در یک جدول مینویسند، یک کلاینت موبایل آفلاین که رکوردها را در هواپیما ایجاد میکند، یا یک صف که باید پیامی را که قبلاً پردازش کرده است تشخیص دهد — هیچکدام از اینها نمیتوانند منتظر نوبت خود برای یک شمارنده مشترک بمانند. نسخه 5 نیاز متفاوتی را برطرف میکند، که همان دستیابی به یک شناسه پایدار مشتقشده از چیزی است که از قبل دارید: یک سند یکسان، یک URL یکسان یا یک حساب کاربری یکسان همیشه به یک UUID یکسان مپ میشود، بنابراین یک فرآیند import میتواند دو بار اجرا شود بدون اینکه چیزی را تکراری کند. در جاهای دیگر، آنها صرفاً فرمتی هستند که یک سیستم تقاضا میکند — یک شناسه همبستگی در میان لاگها و ردیابیها، نام فایلی که در صورت آپلود هزاران کاربر در یک مخزن تداخل پیدا نخواهد کرد، کلیدی در رجیستری Windows، یا دادههای آزمایشی که باید شبیه دادههای واقعی به نظر برسند.
دانستن چند محدودیت صادقانه ارزشش را دارد. یک دسته برابر با یک نسخه است: مقدار انتخاب شده در «نسخه» برای همه موارد داخل آن اعمال میشود، بنابراین اجرای مجموعهای از v4ها و مجموعهای از v7ها به معنای دو دسته مجزا است. این یک تولیدکننده است، نه یک بازرس — پیست کردن یک UUID برای خواندن نسخه یا مهر زمانی آن کاری نیست که این صفحه انجام دهد. گزینه «ذخیره در فایل»، به جای CSV یا JSON، یک فایل متنی ساده مینویسد. نسخه 7 به طور آشکار زمان ایجاد خود را تا حد میلیثانیه فاش میکند، که یک مبادله واقعی است نه یک نقص، و نسخه 1 نیز زمان را به همین ترتیب فاش میکند؛ اگر این موضوع برای دادههای شما مشکلساز است، نسخه 4 همان نسخهای است که چیزی به کسی نمیگوید. دو مقدار خاص در استاندارد وجود دارند که نسخه محسوب نمیشوند و در نتیجه به عنوان گزینهای در «نسخه» نیز قرار ندارند، اما میتوانید آنها را از اینجا کپی کنید: nil UUID یعنی 00000000-0000-0000-0000-000000000000، و max UUID یعنی ffffffff-ffff-ffff-ffff-ffffffffffff. همه چیز در این صفحه از RFC 9562 پیروی میکند، استانداردی که در سال 2024 جایگزین RFC 4122 شد، بنابراین خروجیِ آن توسط هر کتابخانه، پایگاه داده یا API که با UUIDها کار میکند، پذیرفته میشود. در چارچوب این محدودیتها، ضمانت ارائهشده بسیار قوی است: هر شناسه مطابق با استاندارد، با استفاده از تصادفی بودن ایمن از نظر رمزنگاری، بر روی دستگاه خود شما ساخته میشود و هیچ کس دیگری هرگز آن را نمیبیند.