في هذه الصفحة
المقدمة
في سنة 2017 فريق المهندسين في Discord نشروا مقال عن إزاي بيخزنوا مليارات الرسايل. وقتها شاركوا الرحلة بتاعتهم من حيث استخدام MongoDB لحد ما قرروا ينقلوا بياناتهم لـ Cassandra، وده لإنهم كانوا بيدوروا على قاعدة بيانات قابلة للتوسيع Scalable، بتتحمل الأخطاء Fault-Tolerant، وما تحتاجش صيانة كتير Maintenance.
ولإنهم كانوا عاوزين قاعدة البيانات تكبر معاهم، كانوا متأملين إن احتياجات الصيانة ما تكبرش بنفس معدل النمو بتاع التخزين. ولكن للأسف، ده ما كانش الحال - فمجموعة Cassandra بتاعتهم بدأت تظهر فيها مشاكل في الأداء كبيرة وكانت بتحتاج مجهود كبير عشان يحافظوا عليها، مش عشان يطوروها.
وبعد حوالي 6 سنين، اتغيرت حاجات كتير، والطريقة اللي بيخزنوا بيها الرسايل كمان اتغيرت.
Cassandra Troubles
فريق المهندسين في Discord كانوا بيخزنوا الرسايل في قاعدة بيانات اسمها cassandra-messages. وزي ما الاسم موضح، كانت شغالة بـ Cassandra وبتخزن الرسايل. في 2017، كانوا مشغلين تقريبًا حوالي 12 node لـ Cassandra، وكان عندهم مليارات الرسايل.
اما في بداية 2022، عدد الـ nodes زاد ووصل لـ 177 وعدد الرسايل بقى بالـ trillions. وللأسف، النظام ده كان بيحتاج صيانة كتير جدًا — والفريق اللي على الـ on-call كان بيتبعت له تحذيرات كتير عن مشاكل في الـ database، والـ latency كان غير متوقع إطلاقًا، وكانوا مضطرين يوقفعوا عمليات الصيانة لأنها كانت بتاخد وقت ومجهود كبير من الفرق.
إيه اللي كان مسبب المشاكل دي؟ خلينا نبص على الرسالة نفسها.
CREATE TABLE messages (
channel_id bigint,
bucket int,
message_id bigint,
author_id bigint,
content text,
PRIMARY KEY ((channel_id, bucket), message_id)
) WITH CLUSTERING ORDER BY (message_id DESC);
الـ CQL statement اللي فوق هو نسخة مبسطة من الـ schema بتاعت الرسايل. كل الـ IDs اللي بيستخدموها هي عبارة عن Snowflake، ودي Service من Twitter عشان تـ Generate IDs فبالتالي ده بيخليها sortable بشكل زمني.
وبيعملوا partition للرسايل على حسب الـ channel اللي اتبعتت فيه، بالإضافة للـ bucket، اللي هو عبارة عن Window كده زمنية ثابتة. الـ partitioning ده بيخلي كل الرسائل اللي في channel و bucket معينين تتخزن مع بعض وتكون مكررة على 3 nodes (أو حسب الـ replication factor اللي متظبط).
لكن جوه الـ partitioning ده في مشكلة محتملة في الأداء الا وهي: السيرفر اللي فيه عدد قليل من الأعضاء بيبعت رسائل أقل بكتير جدًا مقارنة بالسيرفر اللي فيه مئات الآلاف من الناس. طب ده هيعمل مشكلة في ايه ؟ خلونا نكمل ..
في Cassandra، الـ reads بتكون تقيلة شويتين وHeavier من الـ writes. وده لإن الـ writes اصلًا بتتضاف في الـ commit log وبتتكتب بعد كده في structure موجود في الـ memory اسمه memtable اللي بعد كده بيتحفظ على الـ disk ويتعمله Flushing.
أما الـ reads، فهي بتحتاج تقرا من الـ memtable وكمان ممكن تحتاج تقرا من كذا SSTable (ملفات موجودة على الـ disk)، ودي بتكون عملية تقيلة شويتين. فالـ reads الكتير اللي بتحصل في نفس الوقت مع تفاعل المستخدمين مع السيرفرات بتسبب حاجة بنسميها "hot partition" وهي دي المشكلة اللي بتنتج من الـ Partition بناء على الـ Channel. وحجم الـ dataset بتاعة Discord، مع نمط التفاعل ده، عمل مشاكل في الـ cluster ككل.
فلما كانوا بيقابلوا hot partition، ده كان بيأثر على الـ latency في الـ cluster كله. ولما الـ node بتاخد وقت أطول عشان تخدم الـ Traffic، كل الـ queries التانية اللي رايحة للـ node كانت بتعاني من نفس التأخير، وده لإنهم كانوا شغالين بالـ Quorum Consistency Level وده كان بيزود تأثير المشكلة على المستخدمين بالتأكيد.
كمان مهام الصيانة كانت بتعمل مشاكل كتير جدًا. فكانوا دايمًا متأخرين في عملية الـ compactions، اللي فيها Cassandra بتدمج الـ SSTables على الـ disk علشان تحسن أداء الـ reads. وده كان بيخلي الـ reads تقيلة، وكانوا بيشوفوا تأخير أكبر لما الـ node كانت بتحاول تعمل compact.
بالإضافة لإنهم كانوا بيعملوا عملية اسمها "gossip dance"، اللي فيها بنخرج الـ node من الـ rotation علشان نديها فرصة تعمل compact من غير أي Traffic تستقبله، وبعدين يرجعوها تاني علشان تلتقط الـ hints من hinted handoff، ويكرروا العملية لحد ما الـ backlog بتاع الـ compaction يخلص.
وكانوا بيقضوا وقت طويل برضه في تعديل إعدادات الـ JVM's garbage collector والـ heap settings، لأن الـ GC pauses كانت بتسبب ارتفاع كبير في الـ latency.
Changing Architecture
مجموعة الرسايل ما كانتش هي الـ Cassandra cluster الوحيدة اللي Discord بيشتغل عليها بالتأكيد. وكان فيه أكتر من cluster تاني، وكلهم كانوا بيعانوا من مشاكل مشابهة (ولو إن كانت مشاكل الرسايل هي الأصعب بالنسبالهم).
في المقال اللي نشروه قبل كده، اتكلموا عن إنهم كانوا مهتمين بـ ScyllaDB، وهي Database متوافقة مع Cassandra مكتوبة بلغة C++. والوعود بتاعتها كانت بتقول إنها أسرع، بتصلح المشاكل بشكل أسرع، وعندهاعزل أفضل للـ workload بسبب الـ shard-per-core architecture بتاعتها، وما فيش فيها مشكلة الـ garbage collection.
ورغم إن ScyllaDB مش خالية من المشاكل، بس هي خالية من الـ garbage collector، لأنها مكتوبة بـ C++ بدل الـ Java. وتاريخيًا، فريق مهندسين Discord كان بيعاني مع الـ garbage collector في Cassandra، من الـ pauses اللي بتأثر على الـ latency، لحد pauses طويلة جدًا كانت بتوصل لدرجة إن لازم شخص من الفريق يعيد تشغيل الـ node ويهتم بيها بشكل يدوي.
المشاكل دي كانت سبب كبير في الـ on-call، وجذور كتير من المشاكل اللي كنا بنواجهها في stability.
فبعد ما جربوا ScyllaDB وشافوا تحسينات، قرروا ينقلوا كل قواعد البيانات بتاعتهم ليها. وبالرغم إن القرار ده ممكن يكون في مقال تاني لوحده منفصل خالص، فباختصار في 2020 كانوا نقلوا تقريبًا كل قواعد البيانات ما عدا واحدة لـ ScyllaDB.
والـ database اللي كانوا لسه ما قاموش بنقلها هي: cassandra-messages.
تقدروا دلوقتي تشتركوا في النشرة الأسبوعية لاقرأ-تِك بشكل مجاني تمامًا عشان يجيلكوا كل جديد بشكل أسبوعي فيما يخص مواضيع متنوعة وبشروحات بسيطة وسهلة وبجودة عالية 🚀
النشرة هيكون ليها شكل جديد ومختلف عن شكلها القديم وهنحاول انها تكون مميزة ومختلفة وخليط بين المحتوى الأساسي اللي بينزل ومفاجآت تانية كتير 🎉
بفضل الله قمنا بإطلاق قناة اقرأ-تِك على التليجرام مجانًا للجميع 🚀
آملين بده اننا نفتح باب تاني لتحقيق رؤيتنا نحو إثراء المحتوى التقني باللغة العربية ، ومساعدة لكل متابعينا في انهم يوصلوا لجميع أخبار اقرأ-تِك من حيث المقالات ومحتوى ورقة وقلم والنشرة الأسبوعية وكل جديد بطريقة سريعة وسهلة
مستنينكوا تنورونا , وده رابط القناة 👇
Why Cassandra-Messages Not Migrated
لأن الـ cluster ده كان كبير جدًا. ومع تريليونات من الرسايل وحوالي 200 node، أي عملية نقل هتكون معقدة جدًا. وكمان، كانوا عاوزين يتأكدوا إن الـ database الجديدة هتبقى بأفضل أداء ممكن وكانوا محتاجين خبرة أكتر مع ScyllaDB في الـ production عشان يفهموا أكتر المشاكل اللي ممكن تقابلهم والتحديات اللي هتكون قدامهم.