بنية التخزين المؤقت والمراسلة

السعة وتوسيع بنية البيانات التحتية

18 دقيقة الدرس 9 من 30

السعة وتوسيع بنية البيانات التحتية

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

Redis: تحديد سعة التخزين

Redis مخزن في الذاكرة، لذا كل بايت يُحسب. معادلة التحجيم مباشرة:

  • حجم مجموعة العمل: قدّر بصمة البايتات الإجمالية لجميع المفاتيح الحية باستخدام أمر OBJECT ENCODING وأداة redis-memory-analyzer. لا تعتمد على INFO memory وحده — فـused_memory_rss يتجاوز دائماً used_memory بسبب التشتت.
  • نسبة التشتت: استهدف mem_fragmentation_ratio بين 1.0 و1.5. النسب فوق 2.0 في Redis 6+ تُشغّل إزالة التشتت النشط تلقائياً، لكن تحتاج مع ذلك إلى مساحة احتياطية.
  • قاعدة المساحة الاحتياطية: خصّص الموارد بحيث لا يتجاوز الاستخدام في الذروة 60–70%. عقدة Redis مُحمَّلة بالكامل لا تستطيع قبول BGSAVE (تحتاج ~100% من الذاكرة المستخدمة لصفحات CoW) دون الانتقال للتبديل، مما يدمر زمن الاستجابة.
# بصمة الذاكرة لمجموعة البيانات الحية redis-cli INFO memory | grep -E 'used_memory_human|used_memory_rss_human|mem_fragmentation_ratio|maxmemory_human' # عدد صفوف كل فضاء مفاتيح ومتوسط TTL redis-cli INFO keyspace # تقدير الذاكرة لنمط مفاتيح معين rma scan -p 'session:*' --host 127.0.0.1 --port 6379

لـتحجيم الإخلاء، اضبط maxmemory على 75% من الذاكرة المتاحة واختر سياسة الإخلاء قبل أن تحتاجها. الإعداد الافتراضي لأعباء عمل التخزين المؤقت في شركات التقنية الكبرى هو allkeys-lru؛ لمخازن الجلسات استخدم volatile-lru حتى تكون فقط المفاتيح ذات TTL مؤهلة للإخلاء. لا تترك maxmemory على 0 في بيئة مشتركة — سيُنهي OOM Killer العملية دون تحذير.

Redis: أنماط التوسعة

هناك ثلاثة محاور للتوسعة في Redis:

  1. التوسعة الرأسية: الانتقال إلى مثيل أكبر. مباشرة لكن محدودة. فوق ~256 جيجابايت من الذاكرة، يصبح BGSAVE المبني على fork بطيئاً بشكل مؤلم؛ فكّر في تعطيل RDB واستخدام AOF على النسخة المتماثلة فقط.
  2. توسعة القراءة عبر النسخ المتماثلة: وجّه الأوامر للقراءة فقط إلى النسخ المتماثلة باستخدام تفضيل القراءة من جانب العميل أو وكيل (Envoy أو Twemproxy). النسخ المتماثلة تُضيف تأخيراً في التكرار؛ لا توجّه قراءات تتطلب تسلسلية إلى نسخة متماثلة أبداً.
  3. التقسيم الأفقي عبر Redis Cluster: 16,384 فتحة تجزئة موزّعة على عدد من العقد الأساسية. الحد الأدنى للكلاستر هو 3 عقد أساسية + 3 نسخ متماثلة. استهدف ≤200 جيجابايت من مجموعة العمل لكل شريحة أساسية بقاعدة 70% احتياطي. إعادة التشريح تتم أونلاين لكنها مكثفة على المعالج — جدولها في أوقات انخفاض حركة المرور.
Redis Cluster Scaling Topology Client (cluster-aware) Primary A Slots 0–5460 Primary B Slots 5461–10922 Primary C Slots 10923–16383 Replica A Replica B Replica C توجيه فتحات التجزئة · متقطع = تكرار غير متزامن
Redis Cluster: 3 شرائح أساسية تغطي جميع فتحات التجزئة الـ16,384، لكل منها نسخة متماثلة واحدة غير متزامنة.
إعادة تشريح الكلاستر عملياً: استخدم redis-cli --cluster reshard <host>:<port> بصورة تفاعلية، أو أتمتها بـ--cluster-from all --cluster-to <target-id> --cluster-slots <N> --cluster-yes. شغّلها في أوقات الذروة المنخفضة. راقب cluster_state وcluster_slots_assigned في INFO cluster طوال العملية. إعادة التشريح الفاشلة تترك الفتحات في حالة migrating — أكمل أو أجهض بـCLUSTER SETSLOT <slot> STABLE.

Kafka: تحديد سعة التخزين

تحجيم Kafka له ثلاثة أبعاد مستقلة: الإنتاجية، التخزين، والأقسام.

  • الإنتاجية: وسيط Kafka واحد على عتاد حديث يتعامل مع 200–600 ميجابايت/ثانية من الإنتاجية الإجمالية للكتابة. قِس معدل البايتات الفعلي للمنتجين بـkafka.server:type=BrokerTopicMetrics,name=BytesInPerSec. الاختناق دائماً في بطاقة الشبكة أو معدل كتابة القرص، ليس المعالج.
  • التخزين: إجمالي البايتات = معدل_الرسائل × متوسط_حجم_الرسالة × ساعات_الاحتفاظ × عامل_التكرار. أضف 20% لملفات الفهرس. استخدم kafka-log-dirs.sh لقياس استخدام القرص الفعلي لكل موضوع/قسم.
  • عدد الأقسام: ابدأ بـmax(الإنتاجية_المستهدفة / إنتاجية_القسم_الواحد، توازي_المستهلكين). الإفراط في التقسيم له تكاليف حقيقية: مزيد من واصفات الملفات المفتوحة، انتخاب قائد أطول، وضغط أكبر على بيانات ZooKeeper/KRaft. تحدّ LinkedIn وGoogle تاريخياً عدد الأقسام لكل وسيط بـ4,000.
# قياس الإنتاجية ومتأخر المستهلك kafka-consumer-groups.sh --bootstrap-server kafka:9092 \ --describe --group my-consumer-group # تفصيل استخدام القرص لكل وسيط kafka-log-dirs.sh --bootstrap-server kafka:9092 \ --topic-list orders,payments --describe \ | grep -E 'size|offsetLag' # تقدير التخزين لموضوع (مقتطف bash) MSG_RATE=50000 # رسائل/ثانية AVG_SIZE=512 # بايت RETENTION=604800 # 7 أيام بالثواني REP_FACTOR=3 echo $(( MSG_RATE * AVG_SIZE * RETENTION * REP_FACTOR / 1073741824 )) GB

Kafka: أنماط التوسعة

يتوسع Kafka أفقياً بإضافة وسطاء وإعادة توزيع قيادة الأقسام. العملية:

  1. أضف وسطاء جدداً إلى الكلاستر (يلتحقون بسجلات فارغة).
  2. شغّل أداة إعادة التخصيص (kafka-reassign-partitions.sh) لتوليد وتنفيذ خطة إعادة توزيع تنشر النسخ عبر مجموعة الوسطاء الموسّعة.
  3. راقب تقدم التكرار بـkafka-reassign-partitions.sh --verify. قيّد معدل التكرار بالشبكة لتجنب تجويع المنتجين: اضبط leader.replication.throttled.rate وfollower.replication.throttled.rate على المواضيع المتأثرة قبل البدء.
# الخطوة 1: توليد خطة إعادة التخصيص cat topics-to-move.json # {"version":1,"topics":[{"topic":"orders"},{"topic":"payments"}]} kafka-reassign-partitions.sh --bootstrap-server kafka:9092 \ --broker-list "1,2,3,4,5" \ --topics-to-move-json-file topics-to-move.json \ --generate > reassignment-plan.json # الخطوة 2: تقييد السرعة والتنفيذ kafka-configs.sh --bootstrap-server kafka:9092 \ --alter --entity-type brokers --entity-default \ --add-config 'leader.replication.throttled.rate=104857600,follower.replication.throttled.rate=104857600' kafka-reassign-partitions.sh --bootstrap-server kafka:9092 \ --reassignment-json-file reassignment-plan.json \ --execute # الخطوة 3: التحقق وإزالة التقييد عند الانتهاء kafka-reassign-partitions.sh --bootstrap-server kafka:9092 \ --reassignment-json-file reassignment-plan.json \ --verify kafka-configs.sh --bootstrap-server kafka:9092 \ --alter --entity-type brokers --entity-default \ --delete-config 'leader.replication.throttled.rate,follower.replication.throttled.rate'
Kafka Broker Expansion - Before and After Before (3 brokers) Broker 1 P0 P3 P6 Broker 2 P1 P4 P7 Broker 3 P2 P5 P8 9 partitions across 3 brokers add broker After (4 brokers) Broker 1 P0 P6 Broker 2 P1 P7 Broker 3 P2 P5 Broker 4 P3 P4 P8 balanced across 4 brokers
توسعة وسيط Kafka: إضافة وسيط رابع وإعادة توزيع قيادة الأقسام لإعادة التوازن.
عدد الأقسام في Kafka لا يمكن تقليله — يمكنك فقط الزيادة. إضافة أقسام إلى موضوع يكسر ضمانات ترتيب الرسائل للمنتجين ذوي المفاتيح — المستهلكون الذين افترضوا أن جميع رسائل مفتاح معين تهبط على نفس القسم سيرون اختلاطاً بعد التغيير. خطّط لأعداد أقسام تكفي إنتاجية 2–3× في المستقبل قبل الإطلاق، أو استخدم نمط موضوع سجل مضغوط لإعادة ترتيب الأساس.

استراتيجيات الترقية

لكل من Redis وKafka مسارات ترقية متجددة موثّقة. القاعدة الأساسية: لا تقفز فوق الإصدارات الرئيسية أبداً.

ترقية Redis المتجددة: رقّ النسخ المتماثلة أولاً، ثم أجرِ إخفاقاً اختيارياً نحو نسخة متماثلة (باستخدام أمر FAILOVER في Redis 6.2+ أو CLUSTER FAILOVER)، ثم رقّ العقدة الأساسية السابقة. لإعدادات Sentinel، أطلق إخفاقاً يدوياً بـSENTINEL FAILOVER <master-name> بعد ترقية جميع النسخ المتماثلة.

ترقية Kafka المتجددة: رقّ وسيطاً واحداً في كل مرة. اضبط inter.broker.protocol.version وlog.message.format.version على الإصدار الحالي قبل البدء حتى يبقى الكلاستر متوافقاً مع البروتوكول خلال الانتقال. ارفع هذه القيم فقط بعد أن تنتهي جميع الوسطاء من الانتقال للإصدار الجديد.

# Kafka: تسلسل ترقية متجردة آمنة (وسيط تلو وسيط) # 1. على كل عقدة وسيط، قبل الترقية: kafka-configs.sh --bootstrap-server kafka:9092 \ --entity-type brokers --entity-name 3 \ --describe | grep protocol.version # 2. أعد تشغيل الوسيط 3 بثنائي جديد؛ راقب الأقسام ناقصة التكرار kafka-topics.sh --bootstrap-server kafka:9092 \ --describe --under-replicated-partitions # 3. انتظر حتى يصل عداد URP إلى 0 قبل الانتقال للوسيط 4 # 4. بعد ترقية جميع الوسطاء، ارفع إصدارات البروتوكول: kafka-configs.sh --bootstrap-server kafka:9092 \ --entity-type brokers --entity-default \ --alter --add-config 'inter.broker.protocol.version=3.7,log.message.format.version=3.7'

التخطيط للسعة عملياً

تعامل مع سعة بنية بياناتك تماماً كما تتعامل مع سعة عقد Kubernetes: نمذجها، وأنذر عليها، وخطّط للترقيات قبل بلوغ 70% من الاستخدام. المقاييس الرئيسية لتتبعها في منظومتك الرقابية (لديك بالفعل Prometheus/Grafana من دروس سابقة):

  • Redis: redis_memory_used_bytes / redis_memory_max_bytes، redis_evicted_keys_total، redis_connected_clients
  • Kafka: kafka_server_brokertopicmetrics_bytesinpersec، kafka_log_log_size، kafka_controller_kafkacontroller_activecontrollercount، متأخر مجموعة المستهلكين عبر kafka_consumer_group_lag
أكثر مفاجآت سعة الإنتاج شيوعاً هي نمو سجل موضوع Kafka خلال انقطاع المستهلك. إذا توقفت مجموعة مستهلكين، يستمر الاحتفاظ في التراكم. اضبط retention.bytes على مستوى الموضوع (ليس فقط retention.ms) كسقف صارم حتى لا يملأ موضوع جامح أقراصك بينما مهندس المناوبة يتلقى تنبيهاً.