نقل الرسائل والأقفال والتسوية

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

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

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

تسوية عمليات الإرسال

باستخدام أي من العملاء المعتمدين لواجهة برمجة تطبيقات ناقل الخدمة، تتم دائمًا تسوية عمليات الإرسال إلى ناقل الخدمة بشكل صريح، مما يعني أن تشغيل واجهة برمجة التطبيقات ينتظر وصول نتيجة القبول من ناقل الخدمة، ثم يتم إكمال عملية الإرسال.

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

بروتوكول قائمة انتظار المراسلة المتقدمة (AMQP) هو البروتوكول الوحيد المدعوم لعملاء .NET Standard وJava وJavaScript وPython وGo. بالنسبة لعملاء .NET Framework، يمكنك استخدام بروتوكول مراسلة ناقل خدمة Microsoft Azure (SBMP) أو AMQP. عند استخدام بروتوكول AMQP، يتم تدفق عمليات نقل الرسائل والتسويات وغير المتزامنة. نوصي باستخدام متغيرات واجهة برمجة التطبيقات لنموذج برمجة غير متزامن.

في 30 سبتمبر 2026، سنتقاعد مكتبات SDK ناقل خدمة Azure WindowsAzure.ServiceBus وMicrosoft.Azure.ServiceBus و com.microsoft.azure.servicebus، والتي لا تتوافق مع إرشادات Azure SDK. سننهي أيضا دعم بروتوكول SBMP، لذلك لن تتمكن من استخدام هذا البروتوكول بعد 30 سبتمبر 2026. قم بالترحيل إلى أحدث مكتبات Azure SDK، والتي توفر تحديثات أمان هامة وقدرات محسنة، قبل ذلك التاريخ.

على الرغم من أنه لا يزال من الممكن استخدام المكتبات القديمة بعد 30 سبتمبر 2026، إلا أنها لن تتلقى بعد ذلك الدعم والتحديثات الرسمية من Microsoft. لمزيد من المعلومات، راجع إعلان إيقاف الدعم.

يمكن للمرسل وضع عدة رسائل على السلك في تتابع سريع دون الحاجة إلى الانتظار حتى يتم التعرف على كل رسالة، كما هو الحال مع بروتوكول SBMP أو بروتوكول HTTP 1.1. تكتمل عمليات الإرسال غير المتزامن هذه حيث يتم قبول الرسائل المعنية وتخزينها، في الكيانات المقسمة أو عند تداخل عملية الإرسال إلى كيانات مختلفة. قد تحدث عمليات الإكمال أيضا خارج أمر الإرسال الأصلي.

يمكن أن يكون لإستراتيجية معالجة نتائج عمليات الإرسال تأثير فوري وهام على أداء تطبيقك. الأمثلة في هذا القسم مكتوبة بلغة C# وتنطبق على العقود الآجلة لـ Java، وJava monos، وتعهدات JavaScript، والمفاهيم المكافئة في لغات أخرى.

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

مع مسافة انتقال مفترضة تبلغ 70 مللي ثانية لبروتوكول التحكم في الإرسال (TCP) من موقع محلي إلى ناقل خدمة Microsoft Azure وإعطاء 10 مللي ثانية فقط لناقل خدمة Microsoft Azure لقبول كل رسالة وتخزينها، تستغرق الحلقة التالية 8 ثوان على الأقل، دون احتساب وقت نقل الحمولة أو تأثيرات ازدحام المسار المحتملة:

for (int i = 0; i < 10; i++)
{
    // creating the message omitted for brevity
    await sender.SendMessageAsync(message);
}

إذا بدأ التطبيق عمليات الإرسال غير المتزامنة العشر في تتابع فوري وينتظر اكتمال كل منها بشكل منفصل، فسيحدث تداخل في زمن الذهاب والإياب لعمليات الإرسال العشر هذه. يتم نقل الرسائل العشر في تتابع فوري، ومن المحتمل أيضًا مشاركة إطارات TCP، وتعتمد مدة النقل الإجمالية إلى حد كبير على الوقت المرتبط بالشبكة الذي يستغرقه نقل الرسائل إلى الوسيط.

من خلال عمل نفس الافتراضات كما في التكرار الحلقي السابقة، قد يظل إجمالي وقت التنفيذ المتداخل للتكرار الحلقي التالي أقل من ثانية واحدة:

var tasks = new List<Task>();
for (int i = 0; i < 10; i++)
{
    tasks.Add(sender.SendMessageAsync(message));
}
await Task.WhenAll(tasks);

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

الإشارات، كما هو موضح في القصاصة البرمجية التالية في C#، هي عناصر مزامنة تتيح التحكم على مستوى التطبيق عند الحاجة. يسمح هذا الاستخدام للإشارة بأن تكون 10 رسائل على الأكثر في حالة إرسال في وقت واحد. يتم أخذ أحد أقفال الإشارات العشرة المتوفرة قبل الإرسال، ويتم تحريره عند اكتمال الإرسال. ينتظر المرور الحادي عشر عبر الحلقة حتى تكتمل واحدة على الأقل من عمليات الإرسال السابقة، ثم يجعل تأمينها متاحا:

var semaphore = new SemaphoreSlim(10);

var tasks = new List<Task>();
for (int i = 0; i < 10; i++)
{
    await semaphore.WaitAsync();

    tasks.Add(sender.SendMessageAsync(message).ContinueWith((t)=>semaphore.Release()));
}
await Task.WhenAll(tasks);

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

for (int i = 0; i < 10; i++)
{
    sender.SendMessageAsync(message); // DON’T DO THIS
}

مع عميل AMQP منخفض المستوى، يقبل ناقل خدمة Microsoft Azure أيضا عمليات النقل "المستقرة مسبقا". النقل الذي تم تسويته مسبقا هو عملية حريق ونسيان لا يتم الإبلاغ عن النتيجة لها، في كلتا الحالتين، إلى العميل وتعتبر الرسالة مستقرة عند إرسالها. يعني عدم وجود ملاحظات للعميل أيضًا أنه لا توجد بيانات قابلة للتنفيذ متاحة للتشخيص، مما يعني أن هذا الوضع غير مؤهل للحصول على المساعدة عبر دعم Azure.

تسوية عمليات الاستلام

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

ReceiveAndDelete

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

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

تحرير القفل بسرعة

يخبر وضع Peek-Lock الوسيط بأن العميل المتلقي يريد تسوية الرسائل المستلمة بشكل صريح. تتم إتاحة الرسالة للمستلم بغرض المعالجة، بينما يتم الاحتفاظ بها تحت قفل خاص في الخدمة حتى لا يتمكن المستلمون الآخرون المتنافسون من رؤيتها. يتم تعريف مدة التأمين في البداية على مستوى قائمة الانتظار أو الاشتراك ويمكن تمديدها بواسطة العميل الذي يمتلك التأمين، عبر عملية RenewMessageLockAsync . للحصول على تفاصيل حول تجديد الأقفال، راجع قسم تجديد الأقفال في هذه المقالة.

عندما يتم قفل رسالة، يمكن للعملاء الآخرين الذين يستلمون رسائل من نفس قائمة الانتظار أو الاشتراك أن يأخذوا الأقفال ويستردوا الرسائل المتاحة التالية التي ليست ضمن القفل النشط. عند تحرير التأمين على رسالة بشكل صريح أو عند انتهاء صلاحية التأمين، يتم وضع الرسالة في أو بالقرب من مقدمة أمر الاسترداد لإعادة الحياة.

عندما يتم تحرير الرسالة بشكل متكرر من قبل المستلمين أو عند تركهم القفل ينقضي لعدد محدد من المرات (الحد الأقصى لعدد مرات التسليم)، تتم إزالة الرسالة تلقائيًا من قائمة الانتظار أو الاشتراك ووضعها في قائمة انتظار المهملات المرتبطة.

يبدأ العميل المتلقي تسوية رسالة مستلمة مع إقرار إيجابي عند استدعاء واجهة برمجة التطبيقات Complete للرسالة. يشير إلى الوسيط أنه تمت معالجة الرسالة بنجاح، وأنه تمت إزالة الرسالة من قائمة الانتظار أو الاشتراك. يرد الوسيط على هدف التسوية لدى المستلم برد يوضح ما إذا كان يمكن تنفيذ التسوية أم لا.

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

إذا فشل العميل المتلقي في معالجة رسالة ويعرف أن إعادة تسليم الرسالة وإعادة محاولة العملية لن يساعد، فيمكنه رفض الرسالة، ما ينقلها إلى قائمة انتظار الرسائل المهملة عن طريق استدعاء واجهة برمجة تطبيقات DeadLetter على الرسالة، والتي تسمح أيضا بتعيين خاصية مخصصة بما في ذلك رمز سبب يمكن استرداده مع الرسالة من قائمة انتظار الرسائل المهملة.

إشعار

يوجد قائمة انتظار فرعية غير مستخدمة لقائمة انتظار أو اشتراك موضوع فقط عندما يكون لديك ميزة الرسائل المهملة ممكنة لقائمة الانتظار أو الاشتراك.

تتمثل الحالة الخاصة للتسوية في التأجيل، والتي تمت مناقشتها في مقالة منفصلة.

CompleteDeadLetterقد تفشل العمليات أو أو RenewLock بسبب مشكلات في الشبكة، إذا انتهت صلاحية التأمين المحتفظ به، أو كانت هناك شروط أخرى من جانب الخدمة تمنع التسوية. في إحدى الحالات الأخيرة، ترسل الخدمة إقرارًا سلبيًا يظهر كاستثناء في عملاء واجهة برمجة التطبيقات. إذا كان السبب هو اتصال شبكة معطل، فسيتم إسقاط القفل لأن ناقل الخدمة لا يدعم استعادة ارتباطات AMQP الحالية على اتصال مختلف.

إذا Complete فشل، والذي يحدث عادة في نهاية معالجة الرسائل وفي بعض الحالات بعد دقائق من معالجة العمل، يمكن للتطبيق المتلقي أن يقرر ما إذا كان سيحافظ على حالة العمل ويتجاهل نفس الرسالة عند تسليمها مرة ثانية، أو ما إذا كان سيتم حذف نتيجة العمل وإعادة المحاولة عند إعادة تسليم الرسالة.

تتمثل الآلية النموذجية لتحديد عمليات تسليم الرسائل المكررة عن طريق التحقق من معرّف الرسالة، والذي يمكن ويجب أن يضبطه المرسل على قيمة فريدة، وربما تتماشى مع معرف من عملية الإنشاء. من المحتمل أن يقوم مجدول الوظائف بتعيين معرف الرسالة لمعرف الوظيفة التي يحاول تعيينها لعامل مع العامل المحدد، ويتجاهل العامل التكرار الثاني لتعيين الوظيفة إذا تم تنفيذ هذه المهمة بالفعل.

هام

من المهم ملاحظة أن التأمين الذي يحصل عليه PeekLock أو SessionLock على الرسالة متقلب وقد يتم فقدانه في الظروف التالية

  • تحديث الخدمة
  • تحديث نظام التشغيل
  • تغيير الخصائص في الكيان (قائمة الانتظار، الموضوع، الاشتراك) أثناء الضغط على القفل.

عند فقدان التأمين، سيقوم ناقل خدمة Azure بإنشاء MessageLockLostException أو SessionLockLostException، والذي سيظهر في تطبيق العميل. في هذه الحالة، يجب أن يبدأ منطق إعادة المحاولة الافتراضي للعميل تلقائيًا ويعيد محاولة العملية.

تجديد الأقفال

القيمة الافتراضية لمدة التأمين هي دقيقة واحدة. يمكنك تحديد قيمة مختلفة لمدة القفل على مستوى قائمة الانتظار أو الاشتراك. يمكن للعميل الذي يمتلك القفل تجديد قفل الرسالة باستخدام أساليب على عنصر المستلم. بدلاً من ذلك، يمكنك استخدام ميزة تجديد القفل التلقائي حيث يمكنك تحديد المدة الزمنية التي تريد الاحتفاظ بتجديد القفل لها.

من الأفضل تعيين مدة التأمين إلى شيء أعلى من وقت المعالجة العادي، لذلك لا يتعين عليك تجديد التأمين. الحد الأقصى للقيمة هو 5 دقائق، لذلك تحتاج إلى تجديد التأمين إذا كنت تريد أن يكون أطول. وجود مدة تأمين أطول مما هو مطلوب له بعض الآثار أيضا. على سبيل المثال، عندما يتوقف العميل عن العمل، ستتوفر الرسالة مرة أخرى فقط بعد مرور مدة التأمين.

الخطوات التالية