الاتصال بالخدمات في Service Fabric والتواصل معها

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

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

راجع هذه الصفحة للحصول على فيديو تدريبي يناقش أيضاً اتصالات الخدمة:

أحضر بروتوكولك الخاص

تساعد Service Fabric على إدارة دورة حياة خدماتك ولكنها لا تتخذ قرارات بشأن ما تفعله خدماتك. وهذا يشمل التواصل. عندما يتم فتح خدمتك بواسطة Service Fabric، فهذه فرصة لخدمتك لإعداد نقطة نهاية للطلبات الواردة باستخدام أي بروتوكول أو مكدس اتصال تريده. ستستمع خدمتك إلى عنوان IP:port عادي باستخدام أي مخطط عنونة، مثل معرف URI. قد تشترك مثيلات الخدمة المتعددة أو النُسخ المتماثلة في عملية مضيفة، وفي هذه الحالة سيحتاجون إما إلى استخدام منافذ مختلفة أو استخدام آلية مشاركة المنافذ، مثل برنامج تشغيل http.sys kernel في Windows. في كلتا الحالتين، يجب أن يكون كل مثيل خدمة أو نسخة متماثلة في عملية مضيف قابلاً للعنونة بصفةٍ فريدةٍ.

نقاط نهاية الخدمة

اكتشاف الخدمة ودقتها

في النظام المُوزَّع، قد تنتقل الخدمات من جهاز لآخرٍ بمرور الوقت. يمكن أن يحدث هذا لأسبابٍ مختلفةٍ، بما في ذلك موازنة الموارد أو الترقيات أو تجاوز الفشل أو التوسع. وهذا يُعني أن عناوين نقاط نهاية الخدمة تتغير مع انتقال الخدمة إلى عُقد ذات عناوين IP مختلفة، وقد تفتح على منافذ مختلفة إذا كانت الخدمة تستخدم منفذاً محدداً ديناميكياً.

توزيع الخدمات

توفر Service Fabric خدمة اكتشاف ودقة تُسمى "خدمة التسمية". تحتفظ "خدمة التسمية" بجدول يعين مثيلات الخدمة المُسماة إلى عناوين نقاط النهاية التي يستمعون إليها. تحتوي جميع مثيلات الخدمة المُسماة في Service Fabric على أسماء فريدة ممثلة كمعرفات URI، على سبيل المثال، "fabric:/MyApplication/MyService". لا يتغير اسم الخدمة على مدة بقاء الخدمة وإنما فقط عناوين نقطة النهاية هي التي يمكن أن تتغير عند نقل الخدمات. هذا مشابه لمواقع الويب التي لها عناوين URL ثابتة ولكن قد يتغير فيها عنوان IP. وعلى غرار نظام DNS على الويب، الذي يحل عناوين URL الخاصة بمواقع الويب إلى عناوين IP، لدى Service Fabric مسجل يعين أسماء الخدمة إلى عنوان نقطة النهاية خاصته.

رسم تخطيطي يوضح أن Service Fabric لديه جهة تسجيل تقوم بتعيين أسماء الخدمات إلى عنوان نقطة النهاية الخاص بها.

يتضمن حل الخدمات والاتصال بها الخطوات التالية التي يتم تشغيلها في تكرار حلقي:

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

الاتصال بخدمات أخرى

يمكن للخدمات المتصلة ببعضها البعض داخل نظام مجموعة بوجهٍ عامٍ الوصول مباشرةً إلى نقاط نهاية الخدمات الأخرى لأن العُقد الموجودة في نظام المجموعة موجودة في الشبكة المحلية نفسها. لتسهيل الاتصال بين الخدمات، توفر Service Fabric خدمات إضافية تستخدم "خدمة التسمية". خدمة DNS وخدمة وكيل عكسي.

خدمة نظام DNS

نظراً لأن العديد من الخدمات، وخاصة الخدمات المُعبأة في حاويات، يمكن أن يكون لها اسم URL موجود، فإن إمكانية حلها باستخدام بروتوكول DNS القياسي (بدلاً من بروتوكول خدمة التسمية) تكون مناسبة للغاية، خاصة في سيناريوهات "الرفع والنقل" الخاصة بالتطبيق. وهذا هو بالضبط ما تفعله خدمة DNS. فإنها تمكِّنك من تعيين أسماء DNS إلى اسم خدمة؛ وبالتالي، حل عناوين IP لنقطة النهاية.

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

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

لمزيدٍ من التفاصيل عن كيفية استخدام خدمة DNS، راجع خدمة DNS في مقالة Azure Service Fabric.

خدمة الوكيل العكسي

يعالج الوكيل العكسي الخدمات الموجودة في نظام المجموعة والذي يعرض نقاط نهاية HTTP بما في ذلك HTTPS. يبسِّط الوكيل العكسي إلى حدٍ كبيرٍ الاتصال بالخدمات الأخرى وأساليبها من خلال وجود تنسيق معرف URI محدد ويعالج خطوات الحل والاتصال وإعادة المحاولة المطلوبة لخدمة واحدة للتواصل مع خدمة أخرى باستخدام "خدمة التسمية". بمعنى آخر، فإنه يخفي "خدمة التسمية" عنك عند الاتصال بخدمات أخرى عن طريق جعل هذا الأمر بسيطاً مثل الاتصال بعنوان URL.

رسم تخطيطي يوضح كيفية معالجة الوكيل العكسي للخدمات في نظام المجموعة الذي يعرض نقاط نهاية HTTP بما في ذلك HTTPS.

لمزيدٍ من التفاصيل عن كيفية استخدام خدمة الوكيل العكسي، راجع الوكيل العكسي في مقالة Azure Service Fabric.

اتصالات من عملاء خارجيين

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

Service Fabric في Azure

يُوضع نظام مجموعة Service Fabric في Azure خلف Azure Load Balancer. يجب أن تمر حركة المرور الخارجية كلها إلى نظام المجموعة عبر موازن التحميل. سيعيد موازن التحميل تلقائياً توجيه حركة المرور الواردة على منفذٍ معينٍ إلى عُقدة عشوائية لها نفس المنفذ المفتوح. يعرف Azure Load Balancer فقط عن المنافذ المفتوحة على العُقد، ولا يعرف عن المنافذ المفتوحة بواسطة الخدمات الفردية.

Azure Load Balancer وطوبولوجيا Service Fabric

على سبيل المثال، من أجل قبول حركة المرور الخارجية على المنفذ 80، يجب تكوين الأشياء التالية:

  1. اكتب خدمة تستمع على المنفذ 80. بادر بتكوين المنفذ 80 في ServiceManifest.xml الخدمة وافتح مستمعاً في الخدمة، على سبيل المثال، خادم ويب مستضاف ذاتياً.

    <Resources>
        <Endpoints>
            <Endpoint Name="WebEndpoint" Protocol="http" Port="80" />
        </Endpoints>
    </Resources>
    
        class HttpCommunicationListener : ICommunicationListener
        {
            ...
    
            public Task<string> OpenAsync(CancellationToken cancellationToken)
            {
                EndpointResourceDescription endpoint =
                    serviceContext.CodePackageActivationContext.GetEndpoint("WebEndpoint");
    
                string uriPrefix = $"{endpoint.Protocol}://+:{endpoint.Port}/myapp/";
    
                this.httpListener = new HttpListener();
                this.httpListener.Prefixes.Add(uriPrefix);
                this.httpListener.Start();
    
                string publishUri = uriPrefix.Replace("+", FabricRuntime.GetNodeContext().IPAddressOrFQDN);
                return Task.FromResult(publishUri);
            }
    
            ...
        }
    
        class WebService : StatelessService
        {
            ...
    
            protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
            {
                return new[] { new ServiceInstanceListener(context => new HttpCommunicationListener(context))};
            }
    
            ...
        }
    
        class HttpCommunicationlistener implements CommunicationListener {
            ...
    
            @Override
            public CompletableFuture<String> openAsync(CancellationToken arg0) {
                EndpointResourceDescription endpoint =
                    this.serviceContext.getCodePackageActivationContext().getEndpoint("WebEndpoint");
                try {
                    HttpServer server = com.sun.net.httpserver.HttpServer.create(new InetSocketAddress(endpoint.getPort()), 0);
                    server.start();
    
                    String publishUri = String.format("http://%s:%d/",
                        this.serviceContext.getNodeContext().getIpAddressOrFQDN(), endpoint.getPort());
                    return CompletableFuture.completedFuture(publishUri);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
    
            ...
        }
    
        class WebService extends StatelessService {
            ...
    
            @Override
            protected List<ServiceInstanceListener> createServiceInstanceListeners() {
                <ServiceInstanceListener> listeners = new ArrayList<ServiceInstanceListener>();
                listeners.add(new ServiceInstanceListener((context) -> new HttpCommunicationlistener(context)));
                return listeners;		
            }
    
            ...
        }
    
  2. بادر بإنشاء نظام مجموعة Service Fabric في Azure وحدد المنفذ 80 كمنفذ نقطة نهاية مخصص لنوع العُقدة الذي سيستضيف الخدمة. إذا كان لديك أكثر من نوع عُقدة واحد، فيمكنك إعداد قيد موضع على الخدمة للتأكد من أنه يعمل فقط على نوع العُقدة الذي تم فتح منفذ نقطة النهاية المخصص له.

    فتح منفذ على نوع عقدة

  3. بمجرد إنشاء نظام المجموعة، بادر بتكوين Azure Load Balancer في مجموعة موارد نظام المجموعة لإعادة توجيه حركة المرور إلى المنفذ 80. عند إنشاء نظام مجموعة من خلال مدخل Azure، يُعد هذا تلقائياً لكل منفذ نقطة نهاية مخصص تم تكوينه.

    لقطة شاشة تبرز حقل منفذ الواجهة الخلفية ضمن قواعد موازنة التحميل.

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

    إعادة توجيه نسبة استخدام الشبكة في Azure Load Balancer

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

خدمات موثوقة: خيارات واجهة برمجة تطبيقات الاتصالات المضمنة

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

  • لا يوجد بروتوكول محدد: إذا لم يكن لديك خيار معين من إطار الاتصال، ولكنك ترغب في الحصول على شيء ما وتشغيله بسرعة، فإن الخيار المثالي لك هو الاتصال عن بُعد بالخدمة، والذي يسمح بإجراء استدعاءات عن بُعد مكتوبة بقوة للحصول على خدمات وجهات فاعلة موثوقة. هذه هي الطريقة الأسهل والأسرع للبدء في اتصال الخدمة. تعالج خدمة الاتصال عن بُعد حل عناوين الخدمة والاتصال وإعادة المحاولة ومعالجة الأخطاء. هذا متاح لكلٍ من تطبيقات C# وJava.
  • HTTP: بالنسبة للتواصل حيادي اللغة، يوفر HTTP خياراً قياسياً حسب معايير الصناعة مع أدوات وخوادم HTTP المتوفرة بالعديد من اللغات المختلفة وكلها مدعومة بواسطة Service Fabric. يمكن للخدمات استخدام أي مكدس HTTP متاح، بما في ذلك واجهة برمجة تطبيقات الويب ASP.NET لتطبيقات C#. يمكن للعملاء المكتوبين بلغة C# الاستفادة من فئتي ICommunicationClient و ServicePartitionClient بينما بالنسبة لـ Java، استخدم فئتي CommunicationClient و FabricServicePartitionClient وذلك لحل الخدمات واتصالات HTTP وتكرارات إعادة المحاولة.
  • WCF: إذا كان لديك تعليمة برمجية موجودة تستخدم WCF كإطار عمل للاتصال لديك، فيمكنك استخدام WcfCommunicationListener لجانب الخادم وفئتي WcfCommunicationClient و ServicePartitionClient الخاصتين بالعميل. ومع ذلك، يتوفر هذا فقط لتطبيقات C# على نُظم المجموعات المستندة إلى Windows. لمزيدٍ من التفاصيل، راجع هذه المقالة عن التنفيذ المستند إلى WCF لمكدس الاتصال.

استخدام بروتوكولات مخصصة وأطر عمل الاتصال الأخرى

يمكن للخدمات استخدام أي بروتوكول أو إطار عمل للاتصال، سواء كان بروتوكولاً ثنائياً مخصصاً عبر مآخذ TCP، أو دفق الأحداث من خلال مراكز أحداث Azure أو مراكز إنترنت الأشياء Azure. توفر Service Fabric واجهات برمجة تطبيقات للاتصال والتي يمكنك توصيل مكدس الاتصالات خاصتك بها، بينما يتم استخراج جميع الأعمال لاكتشافها والاتصال منك. راجع هذه المقالة عن نموذج اتصال الخدمة الموثوقة لمزيد من التفاصيل.

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

اكتشف المزيد عن المفاهيم وواجهات برمجة التطبيقات المتوفرة في نموذج اتصال الخدمات الموثوقة، ثم ابدأ بسرعة في الاتصال عن بُعد بالخدمة أو تعمق لمعرفة كيفية كتابة مستمع اتصال باستخدام واجهة برمجة تطبيقات الويب مع المضيف الذاتي لـ OWIN.