0Pricing
Scala for Backend Engineering & Functional Programming · درس

التحكم في الضغط

تعامَل مع المنتجين السريعين بأمان

التحكم في الضغط درس مجاني في Scala for Backend Engineering & Functional Programming على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Scala for Backend Engineering & Functional Programming، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Scala for Backend Engineering & Functional Programming 4 دروس في المجموع.

ما الضغط العكسي؟

الضغط العكسي آلية للتحكم في التدفق تمنع منتجًا سريعًا من إرهاق مستهلك بطيء. فبدلًا من التخزين المؤقت بلا حدود أو إسقاط البيانات، يشير المستهلك إلى مقدار ما يستطيع معالجته.

تطبّق Akka Streams معيار Reactive Streams، حيث ينتقل الطلب إلى المنبع، وتنتقل العناصر إلى المصب.

تدفق موجّه بالطلب

لا تصدر كل مرحلة عناصر إلا عندما تشير المرحلة التالية إلى طلب. يطلب Sink عددًا قدره N من العناصر، وينتقل هذا الطلب إلى المنبع حتى ينتج Source ما طُلب بالضبط.

يعني هذا البروتوكول القائم على السحب أن المنتجين لا يدفعون أبدًا عناصر أكثر مما يستطيع المستهلكون معالجته.

أهمية ذلك في المسارات

من دون ضغط عكسي، سيؤدي مستهلك Kafka سريع يغذي قاعدة بيانات بطيئة إلى تراكم ملايين السجلات قيد المعالجة، ما يستنزف الذاكرة ويتسبب في تعطل العملية.

يحد الضغط العكسي طبيعيًا من سرعة المنبع لتتوافق مع أبطأ مرحلة، مما يحافظ على استخدام مستقر للذاكرة تحت الحمل.

// Fast source, slow sink: backpressure slows the source
val g =
  Source(1 to 1000000)
    .map(_ * 2)
    .to(slowDatabaseSink)

التخزين المؤقت الداخلي

بين الحدود غير المتزامنة، تحتفظ Akka Streams بمخزن مؤقت داخلي صغير (يبلغ حجمه الافتراضي 16 عنصرًا). ويمتص هذا المخزن الدفعات القصيرة، بحيث لا تحتاج المراحل إلى التزامن عنصرًا بعنصر.

عندما يمتلئ المخزن، يبدأ الضغط العكسي، ويتوقف المنبع عن الإنتاج حتى تتوفر مساحة.

import akka.stream.Attributes

val buffered =
  Flow[Int]
    .map(identity)
    .addAttributes(Attributes.inputBuffer(initial = 32, max = 32))

مخزن مؤقت صريح مع استراتيجية Overflow

يُدرج المعامل buffer مخزنًا مؤقتًا صريحًا بالحجم الذي تختاره، مع OverflowStrategy تحدد ما يحدث عند امتلائه.

يتيح لك ذلك الموازنة بين استهلاك الذاكرة والقدرة على فصل سرعة المنتج عن سرعة المستهلك.

import akka.stream.OverflowStrategy

val withBuffer =
  Source(1 to 1000)
    .buffer(size = 100, OverflowStrategy.backpressure)

استراتيجيات تجاوز السعة

تشمل الاستراتيجيات backpressure (إبطاء المنبع)، وdropHead/dropTail (حذف الأقدم أو الأحدث)، وdropBuffer، وdropNew، وfail (إنهاء التدفق بخطأ).

تناسب استراتيجيات الحذف البيانات الحية، مثل قراءات المستشعرات، حيث يمكن التخلص بأمان من القيم القديمة.

import akka.stream.OverflowStrategy

val latestWins =
  liveTicks.buffer(1, OverflowStrategy.dropHead)

val strict =
  liveTicks.buffer(50, OverflowStrategy.fail)

التلخيص باستخدام conflate

عندما يكون المستهلك بطيئًا، يدمج conflate العناصر المعلقة في عنصر واحد باستخدام دالة دمج، بدلًا من تخزينها جميعًا مؤقتًا.

على سبيل المثال، يمكن دمج العديد من التحديثات الرقمية في مجموعها، بحيث يرى المستهلك دائمًا تجميعًا لما فاته.

val summarized =
  fastMetrics
    .conflate((acc, next) => acc + next)

// Slow downstream receives summed batches

التوسيع لتلبية الطلب

يُعد expand النظير المقابل لـ conflate: فعندما يطلب المصب عناصر أسرع مما ينتج المنبع، ينشئ عناصر إضافية من آخر قيمة تمت رؤيتها.

يفيد ذلك في الاستمرار بإصدار أحدث قراءة بمعدل ثابت.

val repeated =
  sensor.expand(last => Iterator.continually(last))

// Downstream always gets the latest sensor value

الحدود غير المتزامنة

افتراضيًا، تعمل المراحل المدمجة على ممثل واحد من دون تخزين مؤقت بينها. ويؤدي إدراج async إلى وضع المرحلة على ممثل خاص بها، مع إضافة مخزن مؤقت وتمكين التوازي على شكل خط أنابيب.

وتوجد مخازن الضغط العكسي المؤقتة فعليًا عند الحدود غير المتزامنة.

val pipelined =
  Source(1 to 1000)
    .map(slowStep).async
    .map(anotherSlowStep).async
    .to(Sink.ignore)

Throttle للتحكم الصريح في المعدل

يفرض throttle حدًا أقصى مقصودًا للمعدل، مولدًا ضغطًا عكسيًا نحو المنبع للالتزام به. ويحمي ذلك الخدمات الخارجية المقيّدة بالمعدل حتى عندما يكون المستهلك قادرًا على العمل بسرعة أكبر.

تتيح معلمة الدفعة حدوث ارتفاعات قصيرة تتجاوز المعدل المستقر.

import scala.concurrent.duration._

val limited =
  requests
    .throttle(
      elements = 100, per = 1.second, maximumBurst = 20,
      akka.stream.ThrottleMode.Shaping)

مراقبة الضغط العكسي

يمكنك اكتشاف الضغط العكسي بمراقبة تباطؤ المنبع أو قياس إشغال المخزن المؤقت. ويساعد كل من معامل log وسمات التدفق في Akka على تتبع موضع تعثر المسار.

يشير امتلاء المخزن المؤقت باستمرار إلى أبطأ مرحلة، وهي المرحلة التي تحدد معدل المعالجة.

val traced =
  Source(1 to 100)
    .log("after-source")
    .map(_ * 2)
    .log("after-map")
    .to(Sink.ignore)

تحقق سريع

فكّر في كيفية حفاظ Akka Streams على منتج سريع من إغراق مستهلك بطيء.

مراجعة

الضغط العكسي هو الأساس الموجّه بالطلب في Akka Streams: إذ يرسل المستهلكون الطلب إلى المنبع، فلا يستطيع المنتجون إرهاقهم، وتبقى الذاكرة ضمن حدود ثابتة.

رأيت المخازن المؤقتة الداخلية، ومعامل buffer الصريح مع استراتيجيات تجاوز السعة، والتلخيص باستخدام conflate، وتلبية الطلب باستخدام expand، والحدود غير المتزامنة، والتحكم المقصود في المعدل عبر throttle. ستشغّل بعد ذلك مسارًا كاملًا.

الأسئلة الشائعة

هل درس «التحكم في الضغط» مجاني؟

نعم — نص درس «التحكم في الضغط» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Scala for Backend Engineering & Functional Programming، انتقل إلى CoddyKit PRO. تتضمن دورة Scala for Backend Engineering & Functional Programming 4 دروس في المجموع.

ماذا ستتعلم في «التحكم في الضغط»؟

تعامَل مع المنتجين السريعين بأمان تتمرن على Scala for Backend Engineering & Functional Programming مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.

هل أحتاج إلى خبرة سابقة لأبدأ Scala for Backend Engineering & Functional Programming؟

لا تُشترط خبرة سابقة. Scala for Backend Engineering & Functional Programming على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.

كم من الوقت يستغرق درس «التحكم في الضغط»؟

معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.

هل يمكنني كتابة وتشغيل أكواد في درس Scala for Backend Engineering & Functional Programming هذا؟

نعم. كل درس في Scala for Backend Engineering & Functional Programming يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.

جميع الدروس في هذه الدورة

  1. Source وFlow وSink
  2. تحويل التدفقات
  3. التحكم في الضغط
  4. تشغيل خط أنابيب
← العودة إلى Scala for Backend Engineering & Functional Programming