توسيع التخزين المتصل سريعًا لخدمة أكثر من مليار مستخدم لـ ChatGPT (الجزء الثاني)
كيف حسّنّا Azure Cosmos DB في منصة تخزين تطبيقاتنا، Habitat، لمواكبة نمو غير مسبوق.
تتطلب جميع منتجات OpenAI وصولًا سريعًا وموثوقًا إلى البيانات، وهو ما توفره منصة التخزين لدينا، Habitat. ويجب أن تستجيب المنصة في غضون مللي ثوانٍ لأكثر من مليار مستخدم في 40 منطقة جغرافية. واجهت بنيتنا التحتية تحديًا استثنائيًا: دعم النمو الهائل وحالات الاستخدام الجديدة، مع مواصلة تحسين الموثوقية والأداء وسرعة عمل مطوري المنتجات. وتطلّب حل هذا التحدي إعادة التفكير في تصميم منصة التخزين المتصل وتشغيلها. كنا نقيّم المفاضلات باستمرار وفق ترتيب واضح: أولًا بلوغ موثوقية كافية لطلبات المنتجات الحرجة، ثم سرعة كافية للمستخدمين حول العالم، وأخيرًا التشغيل بكفاءة على نطاق هائل.
تشرح هذه السلسلة المكوّنة من جزأين كيف طوّرنا Habitat من مكتبة عميل وقاعدة بيانات بسيطتين إلى منصة تخزين موزعة عالميًا تتيح الوصول إلى أكثر من 500 بيتابايت من البيانات. ركّز الجزء الأول على تطور Habitat من عميل بلغة Python إلى خدمة. وتناول أيضًا التقنيات التي مكّنتنا من دفع خدمة مبنية على Python إلى ما يتجاوز بكثير ما قد يعدّه كثيرون عمليًا.
في هذا المقال، وهو الجزء الثاني، نستعرض كيف وسّعنا مكوّن التخزين الأساسي: Azure Cosmos DB. ومن خلال شراكة عمل وثيقة مع فريق Azure، توصلنا إلى نهج عملي لتعدد المستأجرين باستخدام حاويات مُدارة بصورة مشتركة، مع أداء قراءة ممتاز على نطاق عالمي هائل.
الشكل 01 · ما هي Habitat؟
منصة التخزين المتصل
Habitat هي منصة التخزين المتصل التي بنيناها لتمكين منتجات OpenAI من الوصول بسرعة وموثوقية إلى المعلومات المطلوبة.
- طلب
- استجابة
- التغييرات (CDC)
مع توسع الشركات، غالبًا ما تنتقل فرق البنية التحتية من تشغيل أنظمة أحادية المستأجر إلى أنظمة متعددة المستأجرين. في الأنظمة أحادية المستأجر، يدير كل فريق مسؤول عن جانب من المنتج نظامه الخاص، مما يحدّ من نطاق تأثير الأعطال ويوفر حدود مسؤولية واضحة وعزلًا لأحمال العمل. ومع نمو الفرق وجوانب المنتجات، يصبح تشغيل هذا النهج مكلفًا. فأحادية المستأجر تجعل كل فريق منتجات مسؤولًا عن تخطيط السعة، وغالبًا ما تؤدي إلى حجز موارد تفوق الحاجة بكثير.
في المقابل، يُسند تعدد المستأجرين التحكم إلى فريق مركزي لقواعد البيانات، يتمتع بمعرفة وخبرة أفضل في تخصيص الموارد. لكن تعدد المستأجرين يخلق مشكلاته الخاصة، مثل مشكلة الجار المزعج، حيث يستهلك أحد المستأجرين حصة كبيرة على نحو غير معتاد من الموارد على حساب الآخرين.
في Habitat، كان علينا موازنة كل هذه المفاضلات لتصميم نظام تخزين موثوق وكفء على نطاق واسع. أصبحت Habitat اليوم طبقة قواعد بيانات متعددة المستأجرين لمنتجات OpenAI كثيرة، لكن رحلتنا دارت دورة كاملة: من استخدام حاوية Azure Cosmos DB واحدة متعددة المستأجرين، إلى تخصيص حاويات تخزين أحادية المستأجر، ثم العودة إلى حاوية متعددة المستأجرين بوصفها الخيار الافتراضي. ما زلنا في بداية رحلتنا مع تعدد المستأجرين في Habitat. فنحن ندعم مجموعة كبيرة من حالات الاستخدام، لكننا تمكّنا من تأجيل الاستثمار في هذا المجال بالاستفادة من الإمكانات الأساسية المدمجة في Azure Cosmos DB حيثما أمكن.
قبل استعراض رحلتنا مع Azure Cosmos DB، إليكم بعض الأساسيات:
يحدّد حساب Azure Cosmos DB مجموعة من الحاويات وسياسة للنسخ المتماثل
تُحجز لكل حاوية إنتاجية محددة بوحدات الطلب في الثانية (RU/s)
تُخزَّن البيانات داخل كل حاوية بالطريقة المعتادة للتجزئة وفق مفتاح قسم منطقي محدد، مع حدود موثّقة للتخزين والإنتاجية لكل مفتاح قسم منطقي
تتولى Azure Cosmos DB توزيع مفاتيح الأقسام المنطقية على عدد أقل من الأقسام الفعلية الأساسية، وتقسيمها إلى أقسام فعلية متعددة عندما يتجاوز التخزين عتبة معينة أو تحتاج الحاوية إلى أقسام فعلية إضافية لدعم الإنتاجية المحجوزة
في البداية، كنا نسمح بمرور أي حمل من العملاء، معتمدين على الحد المعلن البالغ 10 آلاف RU/s لكل مفتاح قسم منطقي لإحداث ضغط عكسي. وعند انطلاقتنا، كنا نستخدم أيضًا حاوية Azure Cosmos DB افتراضية واحدة فقط في كل حساب. نجح ذلك بدرجة مقبولة، لكنه كشف عن مشكلات لعدة أسباب:
بسبب قرارات مبكرة في تصميم واجهة API، أتحنا للعملاء اختيار مفاتيح الأقسام المنطقية مباشرة. ونتيجة لذلك، تتكرر لدينا التصادمات في مفاتيح الأقسام الشائعة، مثل user_id أو workspace_id، بين حالات استخدام مختلفة للمنتجات. ولأن حالات الاستخدام هذه تتشارك حدود Azure Cosmos DB على مفاتيح الأقسام المنطقية نفسها، فقد قيّد هذا التصميم الإنتاجية الإجمالية المتاحة لكل مستخدم.
من المشكلات الشائعة التي واجهناها عند توسيع Postgres قبل الانتقال إلى Habitat وAzure Cosmos DB، أن كثرة الطلبات من مؤسسة أو مفتاح شديد النشاط، أي مستأجر واحد يولّد حملًا مرتفعًا على نحو غير متناسب، كانت قادرة على تعطيل قاعدة البيانات بأكملها. وقد بُذل جهد جماعي كبير لتخزين بيانات تلك المفاتيح مؤقتًا، وإضافة آلية حجز مؤقت عند غيابها من الذاكرة المؤقتة، حتى لا يُغرق الحمل الناتج قاعدة البيانات الأساسية.
Figure 02a · Logical partition key limits
Different clients, the same partition key
رغم أن الحدود الموثّقة لحجم البيانات والإنتاجية تنطبق على مفاتيح الأقسام المنطقية، فإن القسم الفعلي هو الموضع الذي تُفرض فيه الحدود حقًا. عمليًا، يعني ذلك أن الأقسام المنطقية لا تستطيع بلوغ 10,000 RU/s. بل تتشارك حدود القسم الفعلي مع جميع مفاتيح الأقسام المنطقية الأخرى الموجودة فيه.
وقد أتاح ذلك للجيران المزعجين التأثير في كثير من مفاتيح الأقسام المنطقية غير المرتبطة بهم، إذ كانت أحمال العمل التي تعالج بيانات ميزات محدودة الاستخدام تعطّل مسارات تسجيل الدخول وإنشاء الحسابات الأساسية.
Figure 02b · Noisy neighbors
Different users, the same physical partition
كما أن حد الإنتاجية لأي قسم فعلي متغير، ويتوقف على إجمالي الإنتاجية المخصصة لحاوية Azure Cosmos DB. تتوزع الإنتاجية المحجوزة للحاوية بالتساوي تقريبًا على أقسامها الفعلية.
ومع نمو حجم البيانات، تنقسم الأقسام الفعلية، فيزداد عددها الإجمالي بينما يظل إجمالي الإنتاجية المحجوزة ثابتًا. والنتيجة أن حد الإنتاجية المتاح لكل قسم يتقلص كلما زاد حجم البيانات.
وفي حالات الاستخدام الأشد استهلاكًا للتخزين، التي تشبه تخزين الكائنات الثنائية الكبيرة، يؤدي ذلك إلى نمط من الأعطال يكفي فيه نمو التخزين وحده لتقليل سعة الإنتاجية لأحمال العمل النشطة، حتى مع ثبات معدلات الطلبات والاستخدام.
Figure 02C · Weak partitions
The limit falls below demand
A partition splits when it reaches its storage limit. Each child receives half the throughput capacity.
تساعد الحاويات المنفصلة على معالجة حدود مفاتيح الأقسام ومشكلة الجيران المزعجين جزئيًا. فباستخدام حاويات منفصلة، يمكن تخصيص أقسام فعلية مستقلة لكل حاوية، ولا يمكن أن تنشأ مشكلة الجيران المزعجين أو التداخل في نطاق مفاتيح الأقسام إلا بين أحمال العمل المختلفة داخل الحاوية نفسها. في المقابل، يتطلب إنشاء حاويات جديدة جهدًا إضافيًا، إذ تحتاج كل حاوية إلى تخطيط سعة خاص بها. لذا نفضّل إنشاء الحاويات فقط عند حدود منطقية تفصل بين الخدمات أو حالات الاستخدام.
بدأنا باستخدام حاويات Azure Cosmos DB منفصلة لأهم حالات الاستخدام الجديدة التي تتطلب عزلًا قويًا. وبالجمع بين ذلك وبرنامج نصي لإدارة الأقسام الضعيفة عبر مواءمة إجمالي الإنتاجية المحجوزة لكل حاوية مع عدد أقسامها الفعلية، تجنّبنا إلى حد كبير جميع المشكلات التي كنا نواجهها.
لكننا، لأننا بدأنا بحاوية افتراضية، وجدنا أن كثيرًا من حالات الاستخدام الحرجة القديمة بقيت عالقة فيها للأسف ما لم تُرحّل بياناتها. ولحماية الخدمات الحرجة التي ظلت تعتمد على بيانات الحاوية الافتراضية المشتركة، كنا ننصح الفرق غالبًا بإنشاء حاويات منفصلة للخدمات الجديدة أو ميزات المنتجات الرئيسية. ومع توسعنا، ازداد الضغط على الحاوية الافتراضية، وازدادت معه حوادث بيئة الإنتاج. فبدأنا بتخصيص حاويات لأي خدمة جديدة أو ميزة كبيرة، لمجرد حماية الحاوية الافتراضية من مزيد من الحمل.
وجنّبنا ذلك انقطاعات كثيرة على مستوى الموقع كله، وحصر نطاق التأثير في تدهور أداء ميزة أو خدمة أو تعطلها. لكن أعباء تخصيص الحاويات الجديدة بدأت تثقل كاهلنا في النهاية:
في الحاوية الافتراضية المشتركة القديمة، كان من غير المرجح أن يؤدي نمو أي حالة استخدام جديدة من صفر إلى مليون استعلام في الثانية (QPS) إلى تغيير كبير في إجمالي الاستخدام. أما في حاوية معزولة، فقد يمثل نمو حالة استخدام جديدة من صفر إلى مليون استعلام في الثانية حملًا يعادل 1,000 ضعف خط الأساس الناتج عن التجربة الداخلية وحدها.
ومع الحاويات المخصصة، أصبح على الفرق أن تتذكر حجز سعة الحاويات مسبقًا بما يتناسب مع الإنتاجية المتوقعة عند الإطلاق. وكثيرًا ما كانت فرق المنتجات تطلق ميزاتها في بيئة الإنتاج وتنسى زيادة السعة مسبقًا، فنقضي يوم الإطلاق في غرف إدارة الحوادث الحرجة نحاول زيادة سعة الحاويات في اللحظة الأخيرة.
وهكذا نفقد، مقابل عزل أفضل بهذه الاستراتيجية، إحدى الفوائد الأساسية لدمج أحمال العمل في الأنظمة متعددة المستأجرين.
Figure 03 · Lack of stable aggregate growth
The same workload, different headroom
1K RU/s during load testing → 1M RU/s at launch
بمرور الوقت، تطلبت مراقبة استخدام الحاويات المخصصة أيضًا معرفة دقيقة بالمنتج وبمواعيد تغير حركة الطلبات أو نموها.
يمكننا توفير برنامج نصي بسيط في طبقة التحكم لزيادة الإنتاجية المحجوزة لكل حاوية وفق اتجاهات النمو. لكن في غياب نمو إجمالي مستقر، أصبح ضبط السعة على نحو صحيح يُشرك فعليًا كل فريق منتجات في OpenAI في تخطيط السعة.
ولم يكن هذا النهج قابلًا للتوسع تنظيميًا، مع التفاوت الكبير في مدى اهتمام الفريق المسؤول عن كل خدمة بتخصيص موارد Azure Cosmos DB لها.
مع نمو المؤسسة، أصبح من الصعب التعامل مع تلك المشكلات التشغيلية على نطاق متزايد. وأدى غياب فريق مركزي واحد يتولى التخطيط إلى سوء التخطيط لدى فرق كثيرة. لذلك، عدنا في النهاية إلى حل متعدد المستأجرين، وعملنا عن كثب مع فريق Azure لمعالجة مشكلاتنا الأصلية في تعدد المستأجرين هندسيًا، من خلال تصميم يتيح تقاسم الموارد بين المستأجرين:
يمنع تقييد معدل الطلبات على المفاتيح الأشد نشاطًا أولًا الجيران المزعجين من استهلاك كامل الإنتاجية المتاحة لقسم فعلي معين. ويقلّل ذلك أثر الجار المزعج، حيث قد يمتد تأثير مفتاح واحد شديد النشاط إلى الموقع كله.
وبالمثل، تمنع جودة الخدمة القائمة على تصنيف الطلبات أحمال العمل غير التفاعلية، مثل الإدراج الجماعي أو استخراج البيانات، من استهلاك كامل إنتاجية قسم فعلي معين. فعند إسناد أولوية أقل لطلبات هذه الأحمال، تُقيَّد معدلاتها أولًا، مما يحمي الطلبات التفاعلية الأعلى أولوية التي تخدم المستخدمين النهائيين من تقييد معدلاتها.
كانت Azure Cosmos DB توفر بالفعل وضعًا بلا خوادم كان من شأنه حل مشكلة الأقسام الضعيفة التي واجهناها في وضع السعة المحجوزة. لكنه انطوى على عيب كبير: كان يتوسع وفق استخدام التخزين فقط، ويحدّ استخدام وحدات الطلب عند 5 آلاف RU/s لكل قسم فعلي. كان ذلك سيحل مشكلة الأقسام الضعيفة، لكنه سيمنعنا من توسيع حالات الاستخدام الكثيفة الاستهلاك لوحدات الطلب.
طوّر لنا فريق Azure Cosmos DB وضعًا جديدًا ومحسّنًا بلا خوادم، يتيح لكل قسم فعلي التوسع حتى 10 آلاف RU/s، ويضيف التقسيم وفق استخدام وحدات الطلب إلى جانب التقسيم وفق استخدام التخزين. وأتاح لنا ذلك التوقف عن مراقبة الحاويات وزيادة سعتها يدويًا.
بفضل هذه التغييرات، تمكّنا من العودة إلى استخدام حاوية مشتركة واحدة، مما بسّط كثيرًا متطلبات تخطيط السعة المسبق والمستمر لفرق المنتجات، مع الحفاظ على عزل أحمال العمل. ولم نشهد أي حوادث تتعلق بتخصيص الموارد أو الجيران المزعجين خلال الأشهر التالية، رغم تسارع تطوير المنتجات.
عندما تنمو الشركات إلى حجم OpenAI، تصبح الخدمات المُدارة أقل «إدارةً» من جانب مزودها، إذ تتحول أحمال عمل كثيرة إلى حالات استثنائية في البنية التحتية للمزود السحابي. ومع تحوّل OpenAI إلى أحد أكبر مستخدمي Azure Cosmos DB، تطلّب تشغيلها بنجاح نهجًا مختلفًا: اختبارات مشتركة، ولوحات متابعة مشتركة، وقنوات تواصل هندسية مباشرة، ومسؤولية مشتركة عن أنماط الأعطال التي لا تظهر إلا على نطاق عملنا. يخزّن أكبر حساب Azure Cosmos DB لدينا اليوم عشرات البيتابايت من البيانات، ويعالج أكثر من 20 مليون استعلام في الثانية. وعلى حد علمنا، نحن الشركة الوحيدة التي نشرت Azure Cosmos DB بهذا الحجم.
في أواخر عام 2024، أوضح انقطاع إقليمي سبب ضرورة هذا التعاون. ففي ذلك الوقت، أصاب انقطاع كهربائي منطقة Azure الأساسية لأحد أكبر حسابات Azure Cosmos DB لدينا. وخلال عملية تجاوز الفشل الناتجة، أدركنا أن أكبر حساباتنا ستستغرق عدة ساعات للانتقال إلى منطقة ثانوية، وهو أمر لم يختبره فريقنا ولا فريق Azure Cosmos DB على نطاقنا من قبل.
وبعد نحو شهر، تسببنا في انقطاع خطير آخر أثناء إعادة تلك الحسابات إلى المنطقة الأصلية. إذ أغرق تدفق هائل ومفاجئ للاتصالات بوابة Azure Cosmos DB في المنطقة الأصلية. وتسببت خصوصية في طريقة تعامل عميل Azure Cosmos DB بوضع البوابة مع تجاوز الفشل في أن ينشئ جميع العملاء اتصالات فورًا ويرسلوا طلبات إلى المنطقة الأصلية، رغم أن جزءًا فقط من الأقسام الفعلية كان قد عاد إليها.
في كل انقطاع، طبّقت كل من OpenAI وAzure إجراءات إدارة الحوادث لديها، وحددنا عددًا من الأسباب الجذرية ونشرنا إصلاحات لها. لكن هذه الانقطاعات كانت أعراضًا لمشكلة منهجية أكبر في التنسيق بين أساليب التشغيل والاختبار لدى فريقنا وفريق Azure Cosmos DB. في البداية، أتاح لنا الاعتماد على الخدمات المُدارة التحرك بسرعة والتركيز على أهداف العمل. لكن مع اتساع النطاق، تقلّ قدرة المزود على تولّي إدارة هذه الخدمات وحده، وتصبح بحاجة إلى تكامل عميق معه على جميع المستويات، من التصميم إلى التشغيل.
اليوم، يراقب فريقا الهندسة في Habitat وAzure معًا كل طبقات Habitat، من طبقات خدماتنا وصولًا إلى طبقات التخزين الفعلية في Azure Cosmos DB. نشغّل التغييرات ونختبرها على حساب Azure Cosmos DB يماثل بيئة الإنتاج حجمًا، لكنه ليس حساب إنتاج. ونختبر حزم SDK ونحسّنها معًا، ونحدّد أفضل الممارسات لتوسيع حسابات Azure Cosmos DB لدينا وتحديد أحجامها. ولدينا تواصل هندسي مباشر عبر Teams، بل أتحنا وسائل لاستدعاء المناوبين لدى بعضنا مباشرة دون المرور بمستويات الدعم.
بُذلت جهود مشتركة كبيرة خلال العام الماضي لتحسين قابلية توسع طبقة التحكم والبوابة في Azure Cosmos DB. وشملت إضافة حماية من الحمل الزائد وتخزين مختلف البيانات الوصفية لـ Azure Cosmos DB مؤقتًا في البوابة لحماية قسم البيانات الوصفية، وتخفيف الضغط الناجم عن مجموعة عمليات habitat-service المكتوبة بلغة Python عبر تجميع الاتصالات وزيادة إعادة استخدامها، ووضع أحمال العمل في مواقع مشتركة حيثما أمكن، وعزل الأحمال الحرجة عن أحمال العمل غير التفاعلية باستخدام شبكات سحابية خاصة افتراضية (VPC) منفصلة.
كان هذا المستوى من التعاون الهندسي أساسيًا لاستقرار Azure Cosmos DB لدينا خلال العام الماضي. فأي نظام يبلغ حجمًا أو أهميةً كافيين يستلزم هذا النوع من العمل الجماعي: إزالة الحواجز بين نطاقات المسؤولية والعمل عبر الحدود التنظيمية.
كما ذكرنا في الجزء الأول، تتمثل فلسفتنا الأساسية في: اجعله يعمل، ثم اجعله سريعًا، ثم اجعله منخفض التكلفة. الموثوقية أولًا، ثم الأداء، ثم الكفاءة. أصبحت Habitat بنية تحتية حيوية لـ OpenAI، لذا كانت الأولوية الأولى ضمان موثوقيتها. ومع استقرار النظام في عام 2025 وتوسع OpenAI عالميًا، أصبح زمن الاستجابة العائق التالي أمام المستخدمين وفرق المنتجات.
كانت موارد الحوسبة والتخزين تقع غالبًا في مناطق مختلفة، مما جعل الطلبات العابرة للمناطق أمرًا لا مفر منه.
Figure 04 · Improving performance at a global scale
Global traffic
Compute and storage capacity were often located in different regions, making cross-region requests unavoidable.
المواقع الجغرافية لموارد الحوسبة والتخزين لأغراض توضيحية فقط.
وكان زمن الاستجابة يتفاوت بشدة بحسب موقع تخزين البيانات وموقع معالجة الطلب. لتحسين أداء طلبات Habitat، اعتمد مطورو المنتجات على تخزين مؤقت إضافي لدى العميل، وتجميع الطلبات في دفعات، وتقليل عمليات القراءة والكتابة في قاعدة البيانات، وإخراج العمل من المسار الحرج حيثما أمكن. ورغم أن ذلك أفضى إلى بعض التصاميم المبتكرة لمنتجات أكثر قدرة على تحمل مشكلات قواعد البيانات، فإنه زاد تعقيد المنتجات وأبطأ دورات تطويرها. وهذا خالف هدف Habitat المتمثل في تسريع تطوير المنتجات دون الحاجة إلى فهم قاعدة البيانات.
شكّل ذلك محورًا رئيسيًا لعملنا في عام 2026، وطوّرنا استراتيجية متعددة الطبقات لتحسين أداء عمليات القراءة، التي تمثل أكثر من 90% من طلبات Habitat:
لدينا عدد من حسابات Azure Cosmos DB في مناطق Azure مختلفة حول العالم لخدمة المستخدمين الذين لديهم متطلبات لإقامة البيانات. وحتى لدى المستخدمين الذين لا يخضعون لمتطلبات صارمة لإقامة البيانات، فإن وضع البيانات بالقرب منهم يحسّن تجربتهم أيضًا عبر خفض زمن الاستجابة.
عمليًا، لا نستطيع تحقيق ذلك على نطاق واسع خارج حالات استخدام إقامة البيانات، لأن اختيار المواقع تقيّده السعة المادية للبنية السحابية. فنظرًا إلى حجم مجموعات بياناتنا، لا تستطيع مناطق كثيرة استيعاب مساحة التخزين الهائلة اللازمة لحصتها النسبية من حركة طلبات المستخدمين.
وفي المناطق التي تحدّها سعة مراكز البيانات أو الطاقة أو التبريد، نواجه أحيانًا مفاضلة مباشرة: إما حجز سعة للتخزين في الموقع نفسه وخفض زمن استجابة Habitat، أو استخدام تلك السعة لتوفير مزيد من موارد الحوسبة لمعالجة الطلبات وتوجيه طلبات التخزين إلى مواقع أبعد.
لذلك، غالبًا ما تنطوي قرارات اختيار المواقع على مفاضلة تخص المنتجات بين: أ) تحسين زمن الاستجابة لمنتجات وشرائح مستخدمين مختلفة، وب) السعة الخام للتخزين والحوسبة.
في أحمال العمل الأشد حساسية لزمن الاستجابة، مثل بيانات المصادقة الوصفية اللازمة لكل طلب، نقلّل زمن الذهاب والإياب (RTT) بين موارد الحوسبة وHabitat باستخدام حسابات Azure Cosmos DB ذات نسخ متماثلة موزعة على مناطق ثانوية كثيرة. تُنسخ بعض الحسابات نسخًا متماثلًا إلى مناطق Azure الأربعين التي نعالج فيها الطلبات، فيما تُنسخ حسابات أخرى إلى منطقة واحدة على الأقل في كل قارة.
واضطررنا إلى بناء طبقة في Habitat لنقل البيانات وتوجيهها دون أن يشعر بها العميل، في وقت أبكر مما أردنا، كي نتمكن من نقل مجموعات البيانات بين حسابات ذات ترتيبات مختلفة للنسخ المتماثل.
لكن هذا النهج يظل بدوره مقيّدًا بالسعة، ولذلك يقتصر على مجموعات بيانات قليلة منتقاة بعناية.
تغلب عمليات القراءة بكثافة على أحمال عمل Habitat، إذ تجلب التطبيقات باستمرار الإعدادات والحالة وغيرها من الخصائص. وتستأثر مجموعة عمل صغيرة نسبيًا من أنواع البيانات كثيرة الوصول بحصة كبيرة من حركة الطلبات. وهذا يجعل النظام ملائمًا جدًا للتخزين المؤقت الموزع. يحسّن التخزين المؤقت الأداء في البنية التحتية أحادية المنطقة، وتتضاعف فوائده عند العمل عبر مناطق متعددة، إذ يمكن استخدامه «لإخفاء» زمن الاستجابة بين المناطق.
دمجنا في Habitat طبقة تخزين مؤقت موزعة بنمط البحث الجانبي (lookaside). تخزّن هذه الطبقة نسخة من الكائنات والروابط التي جرى الوصول إليها مؤخرًا في خوادم Valkey ضمن بنيتنا التحتية، بالقرب من مواقع معالجة طلبات المستخدمين. عادةً ما تستخدم هذه الأنواع من الذاكرة المؤقتة مدة صلاحية (TTL) توازن بين معدل العثور على البيانات ومدى تقادمها. تقلّل مدد الصلاحية القصيرة تقادم البيانات، لكنها تحدّ من فائدة التخزين المؤقت، لأن العناصر تنتهي صلاحيتها سريعًا ويجب جلبها بوتيرة أعلى. أما مدد الصلاحية الأطول فتحسّن معدلات العثور على البيانات، لكنها تقدم بيانات قديمة لفترات ممتدة، مما يضعف تجربة المستخدم ويجعل سلوك المنتج غير متوقع.
وثمة نهج آخر يتمثل في تنفيذ عمليات إبطال صريحة للنسخ المؤقتة عندما يكتب التطبيق في البيانات الأساسية نفسها. يحسّن ذلك حداثة البيانات المخزنة مؤقتًا بدرجة كبيرة، لكن تنفيذه على نحو صحيح قد يكون صعبًا. كما يظل عرضة لعدد من الحالات الاستثنائية، مثل الأعطال الجزئية، التي تُبقي بيانات الذاكرة المؤقتة قديمة. وتفاقم عمليات النشر متعددة المناطق هذه المشكلات، بسبب انخفاض موثوقية الشبكات بين المناطق وتسابق تحديث الذاكرة المؤقتة مع النسخ المتماثل للتخزين الأساسي. وإضافة مدد صلاحية إلى هذا النهج تضع حدًا أقصى لتقادم البيانات، لكنها لا تلغي المفاضلة الأساسية نفسها التي ناقشناها أعلاه.
اعتمدنا نهجًا أكثر تطورًا للإبطال، مستلهمين أنظمة مثل TAO من Meta. يعتمد التخزين المؤقت المتكامل في Habitat على التقاط تغييرات البيانات (CDC) عبر موجز تغييرات Azure Cosmos DB، لنشر عمليات الإبطال عالميًا خلال ثوانٍ، محققًا معدلات مرتفعة للعثور على البيانات مع إبقاء تقادمها منخفضًا. تستهلك خدمة في بنيتنا التحتية موجز التغييرات هذا، وتُبطل النسخ في الذاكرات المؤقتة المحلية عند تحديث البيانات الأساسية. وبذلك لا تجد عملية القراءة التالية البيانات في الذاكرة المؤقتة، فتُملأ بأحدث نسخة منها.
خفضنا زمن الاستجابة بدرجة كبيرة أيضًا عبر إزالة أعباء إضافية من خدمة Habitat نفسها، بإعادة كتابة الشيفرة بلغة Rust الأعلى أداءً من Python المستخدمة أصلًا.
خفضت هذه التغييرات مجتمعةً زمن القراءة الإجمالي عالميًا عند المئين الخمسين (p50) من نحو 120 مللي ثانية إلى نحو 10 مللي ثوانٍ، أي تحسن بمقدار 12 ضعفًا منذ بدأنا التركيز على الأداء في وقت سابق من هذا العام.
Figure 05 · Improving performance at a global scale
p50 latency for reads
Three major design changes improved read latency
ورغم أن التخزين المؤقت خفّض وسيط زمن الاستجابة كثيرًا، فإن أبطأ الطلبات ما زالت تتطلب جلب بيانات غير مخزنة مؤقتًا من التخزين الأساسي، وغالبًا من مناطق بعيدة. ومع إتاحة مزيد من السعة وتحسين كفاءة التخزين، نخطط لمعالجة تحدٍ أكثر جوهرية: وضع البيانات منذ البداية بالقرب من المواقع التي تنطلق منها طلبات الوصول إلى هذه البيانات.
يشكّل التقاط تغييرات البيانات (CDC) الموثوق والقابل للتوسع، أي نشر تغييرات قاعدة البيانات إلى الأنظمة اللاحقة، مكوّنًا حيويًا يتجاوز دوره استراتيجية التخزين المؤقت في Habitat. تُلتقط ملايين التغييرات في الثانية عبر آلاف الحاويات وملايين أقسامها، وتتدفق عبر أكثر من مئة موضوع Kafka. وتدعم هذه التغييرات أيضًا فهارس ثانوية ذات اتساق نهائي، ومسارات نقل البيانات، والتحليلات غير الآنية، وميزات منتجات أخرى تعمل في الوقت الفعلي. ومع نمو بنيتنا التحتية الأساسية عالميًا، ازدادت مراقبة تغييرات الصفوف تعقيدًا. إذا أراد عميل تسجيل دالة استدعاء تعمل كلما تغيّرت صفوف من نوع بياناته، فعليه أولًا، ضمن أمور أخرى، تحديد حسابات Cosmos وحاوياته التي تضم بياناته، ونسخة خدمة CDC المنشورة في كل منطقة لمراقبة تلك الحاويات، وضبط سعة مجموعة عمليات خدمة CDC العاملة وKafka والمستهلك الخاص به. تهدف منصتنا لـ CDC إلى حجب هذا التعقيد عن مطوري المنتجات، وتوفير واجهة بسيطة يسجّل العملاء عبرها دالة يريدون استدعاءها عند تغيّر صفوفهم، فيما نتولى نحن جميع تفاصيل الربط والتوسع.
تضمن طبقة تحكم داخلية باستمرار التقاط تغييرات جميع الحاويات المطلوبة، وتختار مناطق Cosmos التي تُقرأ منها البيانات، وتوزّع العمل بكفاءة بين آلاف العمليات العاملة عبر مناطق جغرافية متعددة. ويحمي استخدام مناطق النسخ المتماثلة وقراءات الموجز ذات الأولوية المنخفضة طلبات Habitat الحساسة لزمن الاستجابة من أحمال التقاط التغييرات في الخلفية. في مجموعة عمليات بهذا الحجم، تتكرر باستمرار أعطال العمليات العاملة، ومشكلات الحاويات، وأخطاء مخزن الحجوزات المؤقتة، والإعدادات غير الصالحة، وأعطال الوجهات. عزّزنا متانة دورة حياة عمليات CDC العاملة ومعالجة الحجوزات المؤقتة، وعزلنا الأعطال بين التدفقات، وأضفنا وسائل حماية لتغييرات الإعدادات وعمليات الطرح. ونستخدم قوائم انتظار الرسائل المتعذّر تسليمها لمنع حالات فشل التسليم الدائم من تعطيل بقية الرسائل في الطابور. ونتحمل الانقطاعات الإقليمية بتحويل عمليات القراءة إلى مناطق Cosmos بديلة. وعلى نطاق عملنا، اضطررنا حتى إلى تعديل حزمة SDK الخاصة بـ CDC في Azure لتحسين كفاءة تنفيذ نقاط التحقق، عبر تجميعها في الذاكرة وعدم كتابة الدفعات إلا دوريًا.
رغم تعقيد استخدام Habitat الداخلي لـ Azure Cosmos DB، ظلت قيمتها الأساسية هي حجب تفاصيل البنية التحتية عن مطوري المنتجات لتسريع التطوير، ولا تختلف منصتنا لـ CDC في ذلك.
استطاع فريق صغير دعم منصة تخزين سريعة النمو، عبر إبقاء واجهة API للتخزين محدودة النطاق عمدًا، ومواصلة توسيع خدمة Python، وإعطاء الأولوية للتحديات الهندسية الأكثر إلحاحًا. ركّزنا أولًا على موثوقية معالجة طلبات المنتجات الحرجة، ثم على أداء القراءة للمستخدمين حول العالم، وأخيرًا على الكفاءة التشغيلية على نطاق واسع. أتاح هذا النهج نموًا سريعًا وحالات استخدام جديدة، مع تحسين الموثوقية والأداء وسرعة تطوير المنتجات.
ولتوسيع Habitat وتخزين المحادثات لخدمة المليار التالي من المستخدمين، نحتاج إلى معالجة صعوبة النسخ المتماثل لبياناتنا عبر بنيتنا التحتية على نطاق أكبر من أي وقت مضى. واستباقًا لذلك، نبني داخليًا نظام تخزين متصل مخصصًا على مستوى الإكسابايت، ومحسّنًا لأنواع البيانات كبيرة الحجم في Habitat. يجمع هذا النظام، الذي لا يزال قيد التطوير، بين نواة RocksDB Cloud من Rockset والنسخ المتماثل المستند إلى Raft. ويطبّق نموذج المستندات نفسه المستخدم في Azure Cosmos DB، لكنه يعتمد على تخزين منفصل عن الحوسبة ونسخ متماثل على المستوى الفعلي لتقليل سعة ذاكرة الفلاش المطلوبة، مقابل حد أقصى أقل للاستعلامات في الثانية.
إذا كنت مهتمًا بالعمل على هذه الأنواع من مشاريع البنية التحتية للبيانات بأحجام تدفع حدود التقنية، فاطّلع على وظائفنا المتاحة.


