هل توقفت ميكروخدمات Kotlin الخاصة بك عن كونها مجرد ميكروخدمات؟
\n\nإذا سبق لك تشغيل نظام إنتاجي من عشرات خدمات Kotlin، فأنت تعرف هذه اللحظة. في البداية كل شيء رائع: ktor يعمل بسلاسة، spring-webflux يطير، قاعدة البيانات تستجيب فوراً. ولكن بعد شهر، ينهار العالم المألوف. تبدأ حركة المرور في التعرج، تتضاعف عمليات إعادة المحاولة، تظهر مهلات زمنية في أماكن لا ينبغي أن تكون فيها، وتتحول السجلات إلى فوضى من ملايين الأسطر.
في هذه اللحظة، تبدأ بالبحث عن service mesh. وهذا هو الطريق الصحيح. دعنا نفهم كيف تحول هذه التقنية الفوضى إلى نظام، وكيفية تطبيقها بشكل صحيح في عالم Kotlin.
\n\nما هو service mesh ولماذا يحتاجه مطور Kotlin؟
\n\nService mesh (شبكة الخدمات) هي طبقة بنية تحتية مخصصة لإدارة التفاعل بين الخدمات. تتولى كل "العمل القذر": التوجيه، موازنة التحميل، التشفير، المراقبة (observability) وقاطع الدائرة (circuit breaking). وتقوم بذلك دون تغيير كود تطبيقات Kotlin الخاصة بك.
\n\nلماذا هذا مهم بشكل خاص لـ Kotlin؟ غالباً ما تُكتب ميكروخدمات Kotlin باستخدام أطر عمل مثل Ktor أو Spring Boot. كلاهما يتعامل بشكل ممتاز مع منطق الأعمال، ولكن عندما يصبح عددها أكثر من 20، تبدأ كل خدمة في حمل الكثير من الكود المتكرر: المقاييس، التتبع (tracing)، mTLS، آليات إعادة المحاولة. يقوم Service mesh بنقل كل هذا إلى مستوى البنية التحتية.
\n\nتخيل: أنت تكتب نقطة نهاية REST بسيطة على Ktor، ويقوم service mesh تلقائياً بإضافة التشفير والتتبع وموازنة التحميل إليها. جميل، أليس كذلك؟
\n\nالمكونات الرئيسية لـ service mesh
\n\nأي شبكة خدمات تُبنى على مكونين رئيسيين:
\n\n- \n
- Control plane (مستوى التحكم) - "عقل" النظام. يجمع التكوين، يدير قواعد التوجيه، سياسات الأمان. في Istio هذا هو
istiod، في Linkerd هذا هوlinkerd-controller. \n - Data plane (مستوى البيانات) - "العضلات". مجموعة من البروكسيات الجانبية (sidecar proxies) (عادةً Envoy) التي تقع بجانب كل خدمة Kotlin لديك وتقوم باعتراض كل حركة المرور الواردة/الصادرة. \n
عندما تريد خدمة Kotlin (أ) الاتصال بالخدمة (ب)، يذهب طلبها أولاً إلى البروكسي الجانبي. يتحقق البروكسي من القواعد، يطبق mTLS، يوازن الحمل، يضيف رؤوساً للتتبع - وعندها فقط يرسل الطلب إلى وجهته. الكود الخاص بك لا يعلم حتى بهذا الأمر.
\n\nالتطبيق العملي: إعداد service mesh لميكروخدمة Kotlin
\n\nدعنا نكتب خدمة Kotlin بسيطة على Ktor ونرى كيف يغير service mesh سلوكها.
\n\nالخطوة 1. كتابة التطبيق بلغة Kotlin
\n\n// build.gradle.kts\ndependencies {\n implementation("io.ktor:ktor-server-netty:2.3.7")\n implementation("io.ktor:ktor-server-content-negotiation:2.3.7")\n implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.7")\n implementation("ch.qos.logback:logback-classic:1.4.14")\n}\n\n// Application.kt\npackage com.example\n\nimport io.ktor.server.engine.*\nimport io.ktor.server.netty.*\nimport io.ktor.server.routing.*\nimport io.ktor.server.response.*\nimport io.ktor.serialization.kotlinx.json.*\nimport io.ktor.server.plugins.contentnegotiation.*\n\nfun main() {\n embeddedServer(Netty, port = 8080) {\n install(ContentNegotiation) {\n json()\n }\n routing {\n get("/health") {\n call.respond(mapOf("status" to "UP", "service" to "payment"))\n }\n get("/api/payments/{id}") {\n val id = call.parameters["id"] ?: "unknown"\n call.respond(mapOf("paymentId" to id, "amount" to 150.00))\n }\n }\n }.start(wait = true)\n}\n\n\nهذه الخدمة لا تعرف شيئاً عن service mesh. إنها فقط تستجيب للطلبات. ولكن بمجرد نشرها في مجموعة Kubernetes مع Istio، سيتغير كل شيء.
\n\n