تخطَّ إلى المحتوى الرئيسي
Tooletto

لماذا لا تتصادم معرّفات UUID عمليًا أبدًا (حتى دون تحقق)

تولّد الأنظمة معرّفات UUID عشوائية باستمرار دون أي تنسيق مركزي ودون أي تحقق من التكرار، والأمر ينجح. وتفسر مفارقة أعياد الميلاد لماذا يُعد هذا فعلًا رهانًا معقولًا.

· وقت القراءة: 3 دقائق

ثقة مفاجئة في مقدارها تُمنح لرقم عشوائي

يُولَّد معرّف UUID عشوائي قياسي بشكل مستقل، من قِبل أي عدد من الأنظمة غير المنسقة تمامًا فيما بينها، دون أي سلطة مركزية توزّع المعرّف التالي المتاح، ودون أي تحقق مقابل أي قائمة من المعرّفات المستخدَمة بالفعل — ورغم ذلك، فإن التصادمات، من الناحية العملية، أمر لا يحدث تقريبًا أبدًا. وهذا ادعاء جريء فعلًا يستند بالكامل إلى الاحتمالية لا إلى التنسيق، وفهم سبب صموده يتطلب الجزء نفسه من الرياضيات غير البديهية التي تفسر لغزًا أشهر بكثير: كم عدد الأشخاص القليل نسبيًا اللازم وجودهم في غرفة واحدة قبل أن يصبح من المرجح أن يشترك اثنان منهم في تاريخ ميلاد واحد.

مفارقة أعياد الميلاد، باختصار

تطرح مفارقة أعياد الميلاد الكلاسيكية سؤالًا: كم عدد الأشخاص الذين يجب أن يجتمعوا في غرفة واحدة قبل أن يصبح احتمال اشتراك اثنين منهم في تاريخ ميلاد واحد أكبر من 50%؟ والجواب — 23 شخصًا فقط، مقابل 365 تاريخ ميلاد ممكن — يفاجئ معظم الناس، الذين يتوقعون حدسيًا أن يكون الرقم أقرب بكثير إلى 365 نفسه. وسبب أن الجواب الحقيقي أصغر بكثير هو أن المقارنة ذات الصلة ليست "هل يشترك أي شخص معين معي في تاريخ ميلادي" بل "هل يشترك أي زوج، من بين كل الأزواج الممكنة في الغرفة، في تاريخ ميلاد واحد" — وعدد الأزواج الممكنة ينمو أسرع بكثير من نمو عدد الأشخاص، إذ يوجد بالفعل مع 23 شخصًا 253 زوجًا متمايزًا، كل واحد منها فرصة مستقلة للتطابق. وهذا النمط الرياضي بعينه — نمو عدد فرص المقارنة بشكل تربيعي بينما ينمو عدد العناصر خطيًا فقط — يُسمى مسألة أعياد الميلاد، وينطبق مباشرة على أي موقف يتضمن قيمًا عشوائية مسحوبة من مساحة ثابتة ويُتحقق من تكرارها، وتندرج معرّفات UUID ضمن ذلك تمامًا.

تطبيق الرياضيات نفسها على معرّف عشوائي من 128 بتة

يُسحَب معرّف UUID عشوائي قياسي (الإصدار 4) من مساحة قوامها 122 بتة عشوائية فعلًا — إذ تُحدَّد حفنة من إجمالي 128 بتة عبر مواصفة الصيغة نفسها لتعريف الإصدار — ما يعني أن إجمالي عدد القيم الممكنة هو 2 مرفوعة للأس 122، وهو رقم ضخم يكاد يستعصي على الفهم. وتطبيق منطق مفارقة أعياد الميلاد نفسه المستخدَم في مثال الـ365 يومًا، لكن بعد تكبيره ليلائم تلك المساحة الأضخم بكثير، يعطي النقطة التي يصبح عندها التصادم مرجحًا: إذ يلزم توليد نحو 2.7 كوينتليون معرّف UUID (أي 2.7 يليها 18 صفرًا) قبل أن يرتفع احتمال تصادم أي اثنين منها إلى نحو 50%؛ وللمقارنة، هذا عدد من معرّفات UUID أكبر من عدد حبات الرمل المقدَّر على كل شواطئ الأرض. وحتى نظام واحد، أو عدد كبير من الأنظمة مجتمعة، يولّد معرّفات UUID بأي معدل واقعي في العالم الحقيقي، سيحتاج إلى فترة زمنية تفوق عمر الكون بكثير للاقتراب من تلك العتبة، وهذا هو الأساس الرياضي الفعلي لمعاملة تصادمات UUID كأمر لا يحتاج إلى التحقق منه عمليًا.

لماذا يغيّر الإصدار v7 خاصية الترتيب دون أن يمسّ هذه الرياضيات إطلاقًا

الإصدار السابع من UUID، الذي وُضع معياره مؤخرًا تحديدًا لإنتاج معرّفات تُرتَّب بترتيب زمني تقريبي، يحقق ذلك بوضع طابع زمني بدقة الميلي ثانية في البتات الأولى من المعرّف بدلًا من ملء القيمة كلها ببيانات عشوائية كما يفعل الإصدار الرابع. وقد يبدو هذا وكأنه يُضعف ضمان مقاومة التصادم، لأن جزءًا من القيمة أصبح الآن قابلًا للتنبؤ به بدلًا من كونه عشوائيًا — لكن البتات المتبقية لا تزال تُملأ بالكمية نفسها من البيانات العشوائية فعلًا كما كانت من قبل، ولأن معرّفَي UUID المولَّدَين في الميلي ثانية نفسها بالضبط لا يزالان يحتاجان إلى تطابق باقيهما العشوائي تمامًا حتى يتصادما، تبقى مقاومة التصادم العملية مماثلة لتلك الخاصة بالإصدار الرابع عند أي معدل توليد واقعي. وما يغيّره الإصدار السابع فعليًا هو خاصية مختلفة لا علاقة لها بالأمر — ترتيب الفرز — لا رياضيات التصادم المطروحة هنا إطلاقًا، ويستحق الأمر إبقاء المفهومين منفصلين: فالتفرد ينبع من الحجم الهائل للمساحة العشوائية، بينما قابلية الفرز تنبع من موضع الطابع الزمني داخل القيمة.

ما الذي تشتريه هذه الثقة في الاحتمالية الخام فعليًا

ولأن احتمال التصادم ضئيل فعلًا لا شكليًا فقط، تستطيع الأنظمة توليد معرّفات فريدة بشكل مستقل تمامًا — تطبيق جوال يعمل دون اتصال بالشبكة، أو دالة بلا خادم (serverless) تنشأ وتختفي خلال أجزاء من الثانية، أو ألف نسخة من خدمات مصغرة متوازية تعمل في آن واحد — دون أي تنسيق بينها ودون أي سجل مركزي يتتبع ما صدر بالفعل، مع استمرار توقع سليم رياضيًا بأن أيًّا من تلك المعرّفات لن يتصادم مع آخر أبدًا. وهذه بالضبط الخاصية التي لا يمكن أن يوفرها معرّف تسلسلي يصدر مركزيًا دون سلطة تنسيق مشتركة تُبطئ كل شيء، وهي السبب الكامل وراء تحوّل معرّفات UUID العشوائية إلى الخيار الافتراضي للأنظمة الموزعة التي تحتاج إلى معرّفات لا تستطيع أي خطوة تنسيق مواكبة معدل توليدها.

أدوات ذات صلة

المزيد من المدونة