محمد عطية
صمّم X4 دقايق قراية

تصميم URL shortener: الـ base62 والـ cache وقرار 301 ولا 302

تصميم URL shortener خطوة بخطوة: الكود القصير بالـ base62، والـ cache قدام الـ database، وليه اختيار 301 أو 302 بيحدد هتعدّ الضغطات ولا لأ.

الفيديو على YouTube

الـ URL shortener، يعني خدمة بتاخد لينك طويل وترجّعلك لينك قصير، شكلها أسهل system design ممكن يتسأل عنه. بس جواها قرار صغير جدًا، رقم واحد في الـ response (الرد اللي السيرفر بيرجّعه)، وهو اللي بيحدد هتعرف مين ضغط على لينكاتك ولا لأ.

المطلوب إيه بالظبط؟

حاجتين بس: تدّي الخدمة لينك طويل، ترجّعلك كود قصير. ولما حد يفتح الكود، يوصل للينك الأصلي.

والملاحظة اللي هتبني عليها كل التصميم: اللينك بيتعمل مرة واحدة، وبيتفتح كتير جدًا. مثلًا حد عمل لينك قصير وحطه في بوست على السوشيال، الكتابة حصلت مرة، والفتح ممكن يحصل آلاف المرات. ده افتراض إحنا حاطينه للتصميم، مش رقم متقاس.

الكود القصير بيتعمل إزاي؟

كل لينك جديد ياخد رقم من counter، يعني عدّاد بيزيد واحد مع كل لينك. والرقم ده بنكتبه بـ base62: بدل ما نكتب الرقم بعشر أرقام بس (0 لـ 9)، بنكتبه بـ 62 رمز: الأرقام العشرة، و26 حرف صغير، و26 حرف كبير.

مثلًا لو رتّبنا الرموز كده: الأرقام الأول، بعدها الحروف الصغيرة، بعدها الكبيرة، يبقى الرقم مليون بيتكتب 4c92:

1,000,000 = 4*62^3 + 12*62^2 + 9*62 + 2
digits    = 4, 12, 9, 2
code      = "4c92"

يعني الرقم مليون اتكتب في أربع خانات بس.

والسعة؟ ست خانات تكفي حوالي 56.8 مليار لينك. سبع خانات تكفي 62⁷، يعني حوالي 3.52 تريليون. مثلًا لو الخدمة بتعمل ألف لينك جديد كل ثانية، من غير ما تقف، السبع خانات هتكفيها أكتر من 111 سنة.

بس الـ counter ليه تمن: الأكواد ورا بعض. يعني اللي معاه 4c92 يقدر يجرّب 4c93 ويشوف لينك حد تاني. لو اللينكات عندك ممكن تبقى خاصة، ده لوحده سبب تفكر في طريقة تانية لتوليد الكود، ودي حكاية لوحدها.

بنخزّن فين، وليه الـ cache؟

جدول بسيط في الـ database: الكود قصاده الـ URL الأصلي. ولأن القراية أكتر بكتير من الكتابة، بنحط cache قدامه، يعني ذاكرة سريعة بتحفظ اللينكات اللي بتتطلب كتير، فاللينك المشهور ما يلمسش الـ database كل مرة.

Browser --GET /4c92--> Shortener --> Cache --(miss)--> Database
Browser <--302, Location: https://example.com/...-- Shortener

الـ browser بيطلب الكود، الخدمة بتدوّر في الـ cache الأول، ولو مش لاقياه بتسأل الـ database. وبعدين بترد بـ redirect، يعني رد بيقول للـ browser «روح على العنوان ده»، والعنوان بيبقى في header اسمه Location. والـ header ده سطر معلومات بيتبعت مع الرد.

قرار الـ redirect: 301 ولا 302؟

هنا القرار المهم. الـ status code هو الرقم اللي في أول الـ response وبيقول إيه اللي حصل. وعندنا اختيارين حسب RFC 9110، المواصفة الرسمية لـ HTTP:

  • 301 معناها إن العنوان اتنقل للأبد، والمواصفة بتقول صراحةً: «A 301 response is heuristically cacheable». يعني الـ browser مسموح له يحفظ الرد ده حتى لو إنت ما قلتلوش يحفظه. فالمرة الجاية ممكن يروح للينك الأصلي على طول من غير ما يعدّي عليك.
  • 302 معناها إن العنوان مؤقت، والـ client، يعني الـ browser هنا، المفروض يفضل يستخدم العنوان الأصلي، يعني الكود القصير. والـ 302 مش في قايمة الأكواد اللي الـ browser مسموح له يحفظها من نفسه. فطالما إنت ما ضفتش headers بتسمح بالحفظ، كل ضغطة بتعدّي عليك.

الـ trade-off بمثالين

الـ trade-off هنا، يعني اللي بتكسبه واللي بتدفعه، واضح:

  • 301: حمل أقل على السيرفرات، لأن جزء من الضغطات المتكررة مش هيوصلك. بس مش هتعرف تعدّ كل الضغطات.
  • 302: كل ضغطة بتوصلك وتتعدّ. بس بتدفع تمنها في الحمل: كل ضغطة request، يعني طلب جديد السيرفر لازم يرد عليه.

المثال الأول: مثلًا شركة عاملة حملة إعلانية وحاطة لينك قصير في كل منشور، وعايزة تعرف كل منشور جاب كام ضغطة. مع 301، نفس الشخص لو ضغط تاني من نفس الـ browser ممكن ما يتحسبش.

المثال التاني: إنك تغيّر وجهة اللينك بعد ما تنشره. مثلًا اللينك كان رايح لصفحة عرض وخلص، وعايز توديه لصفحة تانية. مع 302 بتغيّر الصف في الجدول وخلاص. مع 301، أي browser كان حافظ الرد ممكن يفضل يودّي صاحبه للصفحة القديمة، لأنك قلتله إن ده «للأبد».

فيه حل في النص؟

فيه. الحفظ ده بيتحكم فيه header اسمه Cache-Control. لو بعت max-age=3600 مع الرد، يعني «الرد ده صالح لمدة ساعة»، الـ browser يقدر يستخدمه ساعة وبعدها يرجعلك. ولو بعت no-store، المواصفة RFC 9111 بتقول إن أي cache «MUST NOT store» الرد، يعني ما يحفظوش خالص وكل ضغطة ترجعلك. يعني في الحالتين بقيت إنت اللي محدد المدة، مش الـ browser.

رأيي

لو الإحصائيات جزء من المنتج، 302 من غير تفكير.

ده رأيي، مش قاعدة. لو بتبيع للناس عدد الضغطات، أو هتحتاج تغيّر وجهة اللينكات، الـ 302 بيدّيك الاتنين، والحمل الزيادة ده مشكلة الـ cache يحلها. أما لو الخدمة داخلية واللينك عمره ما هيتغير ومحدش هيسألك عن أرقام، الـ 301 بيوفّر عليك requests مالهاش لازمة.

وده اللي بحبه في الـ system design: حتى الـ status code قرار بيزنس، وكل قرار ليه تمن.

المصادر