VOL53: How YouTube Supports Billions of Users With MySQL
أهلًا وسهلا بكم في العدد الثالث والخمسين من النشرة الأسبوعية لاقرأ-تِك 🚀
لا تنسوا أهلنا من صالح الدعاء,اللهم إنّا استودعناك اياهم، اللهم كُن عوناً لهم، اللهم انصرهم واحفظهم. 🇵🇸
أهلًا وسهلا بكم في العدد الثالث والخمسين من النشرة الأسبوعية لاقرأ-تِك 🚀
سواء كنت مهندس برمجيات مبتدئ أو محترف، فنشرتنا هدفها انها تثري المحتوى التقني العربي سعيا للتطوير من جودة المحتوى باللغة العربية، من خلال تقديم أحدث المستجدات والتطورات في عالم البرمجيات، بالإضافة إلى أفضل الممارسات والنصائح القيمة، ونشر أحدث المقالات وترشيحات الكتب ومحتوى ورقة وقلم اللي بينزلوا بشكل مستمر في موقع اقرأ-تِك.
في الإصدار ده الفهرس هيكون كالآتي:
How YouTube Supports Billions of Users With MySQL
Layered Architecture
Deep Dive into Code Quality - Beyond Bugs
Concurrency vs Parallelism
React Props Best Practices for Handling Large Objects
How YouTube Supports Billions of Users With MySQL
منصة YouTube دلوقتي بتخدم أكتر من 2 مليار مستخدم، وعدد المستخدمين الضخم ده بيتعامل مع مئات الساعات من الفيديوهات اللي بتترفع كل دقيقة. واللي ممكن يكون مفاجئ للبعض إنهم معتمدين بشكل أساسي على MySQL، قاعدة البيانات اللي أغلبنا بنستخدمها في مشاريع كتيرة. لكن السر مش في MySQL نفسها، بل في الطريقة اللي قدروا يستخدموها بيها لتوسيعها وتحسينها.
How YouTube Used MySQL
في البداية، YouTube كانت بتستخدم MySQL كقاعدة بيانات واحدة بتخزن فيها كل حاجة زيها زي أي Application ، فكانت بتخزن فيها بيانات المستخدمين، والفيديوهات، والتعليقات، وكل حاجة تانية. لكن مع الزيادة المستمرة والضخمة لعدد المستخدمين، النظام بدأ ينهار.
وده غالبًا الحال مع أغلب الـ Use Cases اللي هنشوفها مع أي Application ، إننا بنبدأ بقاعدة بيانات واحدة وبعدين بنضطر إننا نـ Scale مع الوقت فبتبدأ المشاكل هنا تبان ونبدأ نفكر ازاي نحلها.
طب ايه هي المشاكل اللي ممكن تنتج من وجود حمل عالي على قاعدة البيانات ؟
الـ Queries هتكون بطيئة: مع ازدياد حجم البيانات اللي بتتخزن مع الوقت هيكون من الصعب جدًا إننا نـ Retrieve البيانات دي بسهولة وبسرعة زي الأول لإن البيانات بقت ضخمة وكبيرة ومهما عملنا من Optimization هنوصل للـ Limitation مع الحمل الكبير.
صعوبة الـ Backups: وده لإننا محتاجين يكون عندنا Downtime أثناء عملية الـ Backups والـ Updates اللي عاوزينها على قاعدة البيانات دي كذلك هتوقفلنا التعامل مع قاعدة البيانات لمدة من الزمن.
الـ Data Loss: لو حصل أي مشكلة في MySQL فاحنا عرضة لخسارة بعض البيانات وده لإننا مش قادرين نضمن الـ Durability للبيانات دي بـ Single Instance.
الـ Latency هتكون عالية: خصوصًا لو كان المستعملين متوزعين جغرافيًا بعيد عن بعض ، فلو كان التطبيق بيستهدف كل الناس في العالم ، فمع قاعدة بيانات واحدة هيكون من الصعب جدًا خدمة العدد ده من الناس والموضوع كان هيكون فيه Limitations كبيرة.
المشاكل اللي تناولناها دي أهم المشاكل اللي بتواجه أي قاعدة بيانات واحدة مع زيادة حمل كبير عليها.
فالنهاية YouTube كان لازم يلاقوا حل يوسعوا بيه النظام بدون ما يغيروا MySQL نفسها.
Replication is The Secret
أول خطوة YouTube خدتها هي كانت استخدام MySQL Replication، يعني يعملوا نسخ من قاعدة البيانات الرئيسية (Primary) لنسخ تانية (Replicas) للقراءة فقط.
الـ Read Queries بتروح للـ Replicas.
الـ Write Queries بتروح للـ Primary.
بالشكل ده احنا نقدر يبقى عندنا MySQL Cluster بيتكون من Primary Node وأكتر من Replica Node ونقدر نـ Handle الحمل الكبير بدلًا ماكان على قاعدة بيانات واحدة إنه يتم توزيعه على باقي الـ Replica Nodes.
الـ Replication عادة بيتم بأكتر من طريقة ولكن أشهرهم هو الـ Asynchronous Replication واللي فيه الـ Replicas بتكون متزامنة أو Synchronized مع الـ Primary Database فبيتم نسخ أي تغييرات بتطرأ على الـ Primary Database مع الـ Replica بشكل Asynchronous ومع الوقت بنضمن إن الـ Replica Nodes كلهم هيكون عندهم البيانات نفسها اللي عند الـ Primary.
لكن المشكلة إن الـ Replication في MySQL بيشتغل (Single-threaded)، فالـ Replicas كانت بتتأخر في تحديث البيانات، وده سبب مشاكل في التزامن.
وهي دي ضريبة الـ Asynchronous Replication إن على مالـ Replica يوصلها التغييرات اللي طرأت على الـ Primary Database هيكون عندي Stale Data والبيانات مش هتكون متزامنة أو Consistent مع بعض.
Consistency and Availability Trade-Offs
من فهمنا للـ CAP Theorem إن لازم يتوفر معايا ضمانين 2 بس ونضحي بالتالت ، فـ YouTube كانت شايفة إنها محتاجة في حالة الـ Network Partition إنها تضحي بالـ Strict Consistency في سبيل تحقيق الـ Availability ، ومش مشكلة إن يكون فيه Eventual Consistency والبيانات مع الوقت تبقى Consistent.
ولكن في نفس الوقت هم كان عندهم Use-Cases إن عمليات القراءة اللي هتتم مش محتاجة يكون فيها Stale ولازم تكون Fresh. فعشان يعالجوا المشكلة دي قرروا يوازنوا ويمسكوا العصاية من النص. طب ازاي ؟
عمليات القراءة من الـ Replica: فيه بعض الـ Use-Cases اللي مكنوش محتاجين فيها البيانات تكون Fresh والموضوع ده مش مهم أوي زي مثلًا إنهم يظهروا الـ View Counts الرقم ده مش محتاجين انه يكون Accurate و Consistent في كل ثانية. فلو فيه تأخير بسيط ده مش هيضر من الـ User Experience في إن الـ Count يكون دقيق جدًا لحظة بلحظة.
عمليات القراءة من الـ Primary: على النقيض فيه بعض الـ Use-Cases التانية اللي قراءة Fresh Data هو موضوع حتمي ومهم زي مثلًا لما المستخدم يغير الاعدادات بتاعته أو بياناته ويجي يعمل Refresh عشان يشوفها ، فمش منطقي ان بعد مالمستخدم يغير بياناته ويعمل Refresh يلاقي بياناته القديمة لسه موجودة. وعشان كده في الحالات دي ، عمليات القراءة بتتم على الـ Primary Database عشان هي اللي بيكون فيها الـ Fresh Data.
In-Memory Bound Replication - Introducing Cache
زي ما شوفنا مشكلة MySQL فالـ Replication إنه عملية Single Threaded ، ومع تزايد عمليات الكتابة اللي بتتم على الـ Primary Database أصبح من الصعب جدًا إن الـ Replication يتم بشكل سريع وأصبح فيه Lag كبير بين الـ Replicas والـ Primary.
Layered Architecture
الـ Layered Architecture طريقة شائعة جدًا بنستخدمها علشان نرتب بيها الكود في أي software system. الفكرة ببساطة إننا بنقسم المشروع بتاعنا لكذا layer، وكل layer بيكون ليه وظيفة محددة، ومش بيكلم غير layer اللي تحته.
الـ layers دي ممكن تكون 1 أو 2 أو 3 ، فعدد الـ Layers مش بيفرق ولكن كلهم بيتبعوا نفس الـ Rule الا وهو ان كل Layer بتعتمد على الـ Layer اللي تحتها.
يعني بكل بساطة بنفصل المسئوليات بحيث كل layer طبقة مسئولة عن حاجة واحدة، وده بيسهّل علينا نشتغل على كل جزء من السيستم بأريحية ومن غير مانكون خايفين إننا نأثر بالسلب على باقي الأجزاء.
مميزات الـ Layered Architecture
في كذا ميزة للـ Layered Architecture:
الـ Code هيبقى أسهل في الفهم: لما كل حاجة تبقى في مكانها، تقدر بسهولة تعرف فين الـ business logic، فين الـ database access، وفين الـ UI.
الـ Testability: تقدر تختبر كل layer لوحده. يعني مثلًا تقدر تعمل unit testing للـ service layer اللي هيكون فيها الـ Business Logic بتاعك من غير ما تكون مرتبط بالـ Database.
الـ Maintainability وقابلية التعديل والتوسع: لو عايز تغيّر طريقة حفظ الداتا، ممكن تشتغل بس في الـ data access layer من غير ما تلمس باقي السيستم وده هيديق ثقة وأنت شغال.
الإنتاجية كـ Team: كل حد ممكن يشتغل على layer معينة في الـ Project من غير ما يأثر على باقي شغل الناس التانية خصوصًا لو بيشتغلوا على Features مختلفة.
أشهر Layers في أي Layered Architecture
الترتيب بيختلف من مشروع للتاني، بس غالبًا هنلاقي أغلب الحاجات دي:
ليه الناس بتقول إن Layered Architecture “قديم” أو “مش أفضل اختيار”؟
Deep Dive into Code Quality - Beyond Bugs
احيانا ممكن يقابلنا مشاكل او bugs و احنا بنعدل او بنضيف Feature جديدة للكود علي عكس المتوقع و دا لأن معظمنا ك software engineers بنركز دايما اننا عايزين نطلع منتج كويس و شغال عند العميل ، بس هل فكرنا قبل كدا في quality بتاعته ك code ؟
تخيل انك بتبني عمارة علي اساس ضعيف و حبيت تضيف دور جديد للمبني هتلاقي ان المبني كله بدأ ينهار و دا بسبب الاساس الضعيف من الاول ، ف زي ما بنقول الاهم من الشغل تظبيط الشغل ، هنتعرف النهاردة عن ازاي نخلي السوفتوير بتاعنا الكواليتي بتاعته كويسة و ايه هو Code Quality و ازاي بنقيسه.
ايه هو الـ Code Quality؟
في قاعدة Lehaman’s بتقول:
Any system that’s used will need to change
يعني ايه الكلام دا بقي؟
معناه ان اي سيستم او برودكت بنعمله هنحتاج نعدل فيه سواء اننا نضيف Feature جديدة او نعدل عليها. تخيل كدا لو انت مهتمتش بجودة الكود بتاعك مش هتعرف تغير اي حاجة في السيستم من غير ما تقابل مشاكل فيه و bugs جديدة هتزود من وقت تحسينك ليه.
يبقي الCode Quality ببساطة هو انك تعمل كود يكون سهل القراءة و الفهم لما ترجعله في اي وقت.
نقدر نقول انها طريقة علشان تقيس كفاءة و مدي سهولة فهم و التعديل علي كود موجود. ونقدر نقيسه عن طريق قد ايه هو قابل للقراءة و ممكن نعيد استخدامه في اي بروجكت تاني و مدي سهولته لاي developer تاني انه يقدر يقرأه و يعدل عليه في وقت قصير.
أهمية الـ Code Quality
طيب بعد ما عرفنا يعني ايه ، ليه هو ممكن يكون مهم او ايه مدي تأثيره ؟ خلينا نشوف ..
خليك عارف ان فيه حاجتين مينفعش تثق فيهم :
انك تكون متاح في المستقبل
الذاكرة المستقبلية بتاعتك.
خلينا نفهم اكتر عن طريق السيناريو دا: انت بدات بروجكت كان الكود مش احسن حاجة و قلت انك هتعدله بعدين جالك Offer شغل تاني او انشغلت في بروجكت تاني معرفتش ترجع تعدل عليه و كان في تيم تاني هيشتغل فيه ممكن تسأل نفسك وقتها ، هل التيم هيكون قادر انه يعدل عليه او يفهمه بسهولة ؟
ايه اللي هيحصل اما يضيفوا تعديل جديد ؟ و ازاي هيأثر علي ال performance and bugs ؟ من هنا نقدر نستنج اهمية الـ Code Quality.
خصم 50% على جميع خطط الاشتراك السنوية لفترة محدودة، تقدروا دلوقتي تشتركوا في اقرأ-تِك وتستمتعوا بكافة المقالات في كل ما يخص هندسة البرمجيات باللغة العربية والمحتوى المميز من ورقة وقلم ومدونات فطين اللي بيتميزوا بتصاميم ذات جودة عالية وكل ده بحرية كاملة وكمان مفاجآت اقرأ-تِك الجاية 🚀
وبرضو متاح الاشتراك من خلال InstaPay و VodafoneCash 🎁
بفضل الله أصبح متاح حاليا دعمنا من خلال الرعاة والشراكات وفعلنا الـ Sponsorship واحنا بنرحب بجميع الشراكات مع المؤسسات والشركات وأصحاب الأعمال لبناء مجتمع عربي يشجع على القراءة والتعلم ومشاركة التجارب والخبرات العملية في هندسة البرمجيات.
دورك كشريك أو راعي هيكون محوري في دعم المحتوى وتوسيع نطاق تأثيره. فانضم لرحلتنا وكن جزءًا من صناعة مستقبل التكنولوجيا في المنطقة 🚀
تقدروا تشوفوا التفاصيل كاملة من هنا والـ Analytics بتاعتنا من خلال اقرأ-تِك والنشرة الأسبوعية 👇
Concurrency vs Parallelism
الـ Concurrency والـ Parallelism اتنين من المصطلحات المهمة جدًا واللي أغلبنا حصله لبس وماقدرش انه يستوعبهم من أول مرة بشكل كويس. ولكن هم من أهم المصطلحات اللي تهمنا في الـ Software.
إيه هي الـ Concurrency؟
الـ Concurrency هي لما يكون عندك أكتر من عملية (task) شغالة في نفس الوقت، بس مش شرط كل العمليات دي تشتغل في نفس اللحظة. بمعنى تاني، الجهاز بتاعك بيتعامل مع كذا عملية في نفس الوقت بس مش شرط يشتغل عليهم كلهم في نفس الثانية.
تخيل إنك طباخ في مطبخ وعندك أكتر من طلبية، بتبدأ شوية في الطلبية الأولى، وبعدها بتسيبها مثلا لحد ما تجهز على النار وتروح للطلبية التانية وتبدأ فيها، وبعدين ترجع للأولى وهكذا. كده إنت بتتعامل مع كل الطلبات في نفس الوقت، بس مش بتخلصهم كلهم مرة واحدة.
مثال تاني على الـ Concurrency في Microsoft Word
تخيل إنك بتكتب مستند في الـ Word، وفي نفس الوقت بتعمل تدقيق إملائي (spell check) وتنفيذ بعض الصيغ (formulas) في نفس المستند.
البرنامج بيقسم وقته بين كتابة النص والتدقيق الإملائي وتنفيذ الصيغ. بمعنى إنه شوية يتأكد من الكلمات المكتوبة وشوية ينفذ الصيغ وشوية يسمح لك بالكتابة.
البرنامج هنا بيدير كل العمليات دي بشكل متزامن، بس مش شرط يكون شغال عليهم كلهم في نفس اللحظة بالظبط.
استخدامات الـ Concurrency
تصفح الويب: لما تفتح أكتر من (tab) في المتصفح وكل (tab) بيحمل صفحة مختلفة، المتصفح بيقسم وقته بين التبويبات دي.
التطبيقات اللي بتتعامل مع المدخلات الخارجية: تطبيق بيستقبل بيانات من المستخدم وفي نفس الوقت بيحدث قاعدة البيانات وبيعمل عملية حسابية، البرنامج بيعمل كل المهام دي بشكل Concurrent، بيستغل الوقت اللي بياخده في انتظار المدخلات عشان ينفذ عمليات تانية بدل ما يفضل مستني وما يعملش حاجة.
السيرفرات والتعامل مع الطلبات المتعددة: سيرفر ويب بيتعامل مع أكتر من طلب (request) من مستخدمين مختلفين، بيوزع وقت البروسيسور بين الطلبات دي عشان يقدر يرد عليهم بشكل متزامن.
React Props Best Practices for Handling Large Objects
عند استخدام React ، تعد إدارة البيانات بين الـ Components أمرًا أساسيًا. واحدة من التحديات الشائعة التي يواجهها المطورون هي كيفية التعامل مع الـ props عند الحاجة إلى تمرير objects كبيرة تحتوي على بيانات متعددة.
في هذا المقال، نستعرض أفضل الممارسات للتعامل مع هذا السيناريو مع تسليط الضوء على مزايا وعيوب كل أسلوب.
تمرير الـ object بالكامل
في هذه الطريقة، يتم تمرير الـ object
بالكامل كـ prop
. داخل الـ UserProfile Component
، يمكن الوصول إلى الحقول المطلوبة (مثل user.name
أو user.avatar
) حسب الحاجة.
<UserProfile user={user}/>;
المزايا
سهولة وسرعة التنفيذ: تمرير الـ object بالكامل بسيط ولا يتطلب تعديلات إضافية على الكود.
مرونة مستقبلية: إذا احتاج الـ component إلى المزيد من الحقول لاحقًا، فإنها تكون متاحة بالفعل.
العيوب
أداء أقل: تمرير object كبير قد يؤدي إلى حدوث (re-rendering) بشكل غير ضروري إذا تغير أي جزء من الـ object، حتى وإن لم يكن مرتبطًا بالـ component.
زيادة البيانات المرسلة: قد يتم تمرير بيانات غير ضرورية للـ component، مما يستهلك ذاكرة إضافية.
ترابط قوي بين ال components: يصبح الـ Component معتمدًا بشكل مباشر على بنية الـ object، مما يجعل إعادة الهيكلة أكثر تعقيدًا.
تمرير الحقول المطلوبة فقط
في هذه الطريقة، يتم استخلاص الحقول المطلوبة فقط من الـ object وتمريرها كـ props منفصلة.
<UserProfile name={user.name} avatar={user.avatar} />;
الإصدار الأول - ورقة وقلم 🚀
في الإصدار ده جمعنا أكتر من 50 موضوع في مختلف مجالات هندسة البرمجيات بأكتر من 170 صفحة + تصاميم بجودة عالية وكل ده بالعربي وبشكل مميز ومتقسم لفصول سهل تنتقلوا من فصل وموضع للتاني بدون مشاكل 💎
تقدروا تشوفوا النسخة كاملة من هنا كـ E-Book ، وحاولنا نخليها بسعر رمزي يناسب الجميع 👇
ولو عندكوا أي مشكلة في الدفع ، تقدروا تتواصلوا معانا وهنكون مبسوطين باننا نوفر بدايل زي InstaPay و VodafoneCash 🎁
ولو عاوزين تعاينوا جودة الـ E-Book قبل ما تشتروه ، تقدروا تحملوا النسخة المجانية واللي بتضم حوالي 30 موضوع فيما لايزيد عن 100 صفحة من هنا 😉
رؤيتنا هي إثراء المحتوى التقني العربي وجعل التعلم من خلال القراءة أمتع، وذلك من خلال إثراء المحتوى التقني باللغة العربية وتشجيع المبرمجين على القراءة بلغتهم الأم والتفكير أيضًا بها.
لذلك اتحنا الفرصة أمام الجميع للمساهمة ومساعدتنا في نشر واثراء المحتوى التقني باللغة العربية, من خلال كتابة المقالات التقنية في مختلف مجالات هندسة البرمجيات.
وجب التنويه أنه لن يتم نشر كافة الأعمال التي تصل إلينا، وإنما سيتم الانتقاء منها ما يحقق هدفنا بإثراء المحتوى التقني العربي، ولذلك قد تُطلب بعض التعديلات من الكاتب قبل النشر.
لمعرفة المزيد بخصوص :
💬 المعايير العامة لكتابة ونشر المقالات
⚡️ كيفية الإرسال
🔥 التزامات اقرأ-تِك تجاه الكتاب
يمكنكم قراءة كافة التفاصيل من هنا 👇