Swift في عالم الخدمات المصغرة: عندما لا يكفي خادم واحد
\n\nهل سبق لك أن شغّلت تطبيق Swift وفكرت: "ليته يعمل مثل الساعة السويسرية — كل وحدة على حدة، ولكن معًا بشكل متناغم تمامًا"؟ لهذا بالضبط تُستخدم الخدمات المصغرة. ولكن بمجرد تقسيم التطبيق المتجانس إلى عشرات الخدمات الصغيرة، تبدأ الفوضى الحقيقية: تفقد الخدمات بعضها البعض، وتسقط الطلبات، وتتحول السجلات إلى فوضى.
\n\nهنا يظهر Service Mesh — طبقة ذكية تتولى كل السحر الاتصالي. ونعم، Swift يتعامل معها بشكل ممتاز. في هذه المقالة، سنفهم كيفية ترويض Service Mesh في نظام Swift البيئي باستخدام Vapor وKitura والممارسات الحديثة. لا ماء — فقط كود وحالات حقيقية.
\n\nما هو Service Mesh ولماذا يحتاجه مطور Swift؟
\n\nتخيل أن كل خدمة مصغرة لديك هي جزيرة منفصلة. عادةً، تتصل الجزر بالعبارات (طلبات HTTP). لكن العبارات تغرق، وتتأخر، وأحيانًا ينهب القراصنة (أخطاء الشبكة) البضائع. Service Mesh هي شبكة ذكية من الجسور ومرسلي الحركة، والتي:
\n\n- \n
- تدير حركة المرور — تقرر إلى أين تُوجه الطلب إذا كانت الخدمة محملة بشكل زائد \n
- تُشفّر كل شيء — mTLS بين الخدمات دون سطر واحد في الكود \n
- تجمع المقاييس — ترى كم من الوقت استغرق كل استدعاء \n
- تعالج الأخطاء — إعادة المحاولة، المهلة، قاطع الدائرة بشكل مدمج \n
هذا مهم بشكل خاص لـ Swift: نظام Swift الخادم البيئي لا يزال حديثًا، والآليات المدمجة للتوجيه المعقد لا تزال قليلة نسبيًا. Service Mesh يسد هذه الفجوات دون إجبارك على كتابة أطنان من كود boilerplate.
\n\nكيف تتواصل خدمات Swift المصغرة بدون Service Mesh؟
\n\nلنلقِ نظرة على مثال نموذجي. لنفترض أن لديك خدمة طلبات على Vapor وخدمة دفع. بدون Service Mesh، تكتب شيئًا مثل:
\n\nimport Vapor\n\nfunc processOrder(req: Request) async throws -> Order {\n // نجمع URL يدويًا — هذا سيء بالفعل\n let paymentServiceURL = "http://payment-service:8080/charge"\n \n // نعالج المهلات بأنفسنا — هذا ممل\n let client = req.client\n let response = try await client.post(URI(paymentServiceURL)) { req in\n try req.content.encode(PaymentRequest(amount: 100))\n }\n \n // نتحقق من الحالة بأنفسنا — هذا مرهق\n guard response.status == .ok else {\n throw Abort(.badGateway, reason: "Payment failed")\n }\n \n return try response.content.decode(Order.self)\n}\n\nيبدو مألوفًا؟ تخيل الآن أن لديك 20 خدمة، وفي كل مرة تحتاج إلى تكرار منطق إعادة المحاولة، التوازن، والتشفير. Service Mesh يخلصك من هذا الجحيم.
\n\nIstio + Swift: الثنائي المثالي للإنتاج
\n\nIstio هو أشهر Service Mesh لـ Kubernetes. يعمل على مستوى proxy جانبي (Envoy) يعترض كل حركة المرور. خدمة Swift لا تحتاج حتى إلى معرفة وجود Istio — فهي فقط تستمع إلى المنفذ، والـ proxy يفعل كل شيء آخر.
\n\nلكن هناك فارق بسيط: تطبيقات Swift غالبًا ما تستخدم أطر عمل بمحرك HTTP خاص بها (Vapor, Hummingbird). يجب أن يفهم Istio الرؤوس والبروتوكولات بشكل صحيح. الخبر السار: Vapor 4+ يدعم HTTP/1.1 وHTTP/2 القياسيين، لذا لا توجد مشاكل.
\n\nنشر خدمة Swift مع Istio
\n\nلنفترض أن لديك خدمة بسيطة على Vapor:
\n\n// Sources/App/routes.swift\nimport Vapor\n\nfunc routes(_ app: Application) throws {\n app.get("health") { req -> HTTPStatus in\n return .ok\n }\n \n app.get("api", "v1", "users") { req -> [User] in\n // منطق جلب المستخدمين\n return [User(id: 1, name: "Alice")]\n }\n}\n\nسيكون Dockerfile الخاص به عاديًا:
\n\nFROM swift:5.9 AS build\nWORKDIR /app\nCOPY . .\nRUN swift build -c release\n\nFROM ubuntu:22.04\nWORKDIR /app\nCOPY