الطريقة السهلة للحوسبة بدون خادم

اكتسبت الحوسبة بدون خادم نفسها (حرفيا "بدون خادم") شعبية واسعة في عام 2014 بعد الإعلان عن AWS Lambda - واحدة من أولى الأنظمة الأساسية Serverless. منذ تلك اللحظة ، ازدادت شعبية نهج Serverless فقط ، لكن تطوير الأدوات ، للأسف ، لا يتماشى.



اسمي فلاديسلاف تانكوف ، في 2018-2020 درست في برنامج الماجستير في شركة JetBrains في ITMO ، ومنذ عام 2017 أعمل في JetBrains .



في صيف 2018 ، في هاكاثون JetBrains ، حاولت أنا وعدد قليل من زملائي صنع أداة للغة Kotlin تسهل إنشاء تطبيقات بدون خادم من خلال تحليل كود التطبيق.



بعد الهاكاثون ، في إطار العمل العلمي في برنامج الماجستير المؤسسي في JetBrains ، قررت مواصلة تطوير هذا المشروع. في غضون عامين ، توسعت الأداة واكتسبت وظائفها بشكل كبير ، لكنها احتفظت باسمها - Kotless أو Kotlin Serverless Framework.



ما هو Serverless



أولاً ، لنتذكر ما تتكون منه أبسط منصة حوسبة بدون خادم. تتضمن هذه المنصة ثلاثة مكونات رئيسية:



  • نظام تنفيذ الوظائف بدون خادم - تطبيقات صغيرة تعالج أحداثًا معينة ؛
  • مجموعة من الواجهات المختلفة من العالم الخارجي (أو منصة سحابية مثل AWS) لنظام أحداث المنصة ، مثل واجهة HTTP ؛
  • نظام الحدث نفسه ، والذي يوفر نقل الأحداث من الواجهات إلى الوظائف ونتائج المعالجة من الوظائف إلى الواجهات.


هذه المكونات الثلاثة كافية لبناء تطبيق معقد إلى حد ما. على سبيل المثال ، يعد تطبيق الويب مجرد واجهة HTTP خارجية (في حالة AWS ، ستكون APIGateway ) ولكل مورد تمت معالجته (مثل / route / my ) وظيفة معالج بدون خادم خاص به. يمكنك إنشاء تطبيق أكثر تعقيدًا يستخدم قواعد البيانات ويستدعي نفسه وظائف أخرى بدون خادم ، كما في الصورة.



حسنًا ، يمكنك إنشاء مثل هذه التطبيقات ، لكن لماذا؟



تتمتع التطبيقات التي لا تحتوي على خادم بالعديد من المزايا التي لا يمكن إنكارها والتي تبرر البنية الهيكلية.



  • لا تعمل الوظائف بدون خادم عندما لا تكون هناك حاجة إليها. في الواقع ، تقوم الوظيفة بمعالجة الأحداث فقط - فلماذا تستهلك موارد الحوسبة إذا لم تكن هناك أحداث؟
  • يمكن للوظائف بدون خادم معالجة الأحداث من نفس النوع بالتوازي. هذا يعني أنه إذا أصبح / route / my يتمتع بشعبية كبيرة وطلبه آلاف المستخدمين مرة واحدة ، فيمكن لمنصة Serverless ببساطة تشغيل 1000 معالج ، واحد لكل حدث.


معًا ، تضيف هذه النقاط ما يصل إلى واحدة من أهم تعويذات Serverless: يتدرج تطبيق Serverless من الصفر إلى اللانهاية. مثل هذا التطبيق لا ينفق المال عندما لا يكون مطلوبًا ، وهو قادر على معالجة آلاف الطلبات في الثانية عند الحاجة.



مشكلة



لنلقِ نظرة على مثال بسيط جدًا بلغة Kotlin:



@Get("/my/route")
fun handler() = "Hello World"


من الواضح جدًا أن مثل هذا التطبيق يمكن تنفيذه باستخدام نهج Serverless. للوهلة الأولى ، يكفي إنشاء واجهة HTTP مع بعض عناوين DNS وتعيين / طريقي / طريقي إلى معالج المرح () .



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



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


لا توجد خطوات قليلة لمثل هذا التطبيق البسيط ، أليس كذلك؟



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



هل من الممكن القيام بشيء أسهل؟ في بعض الحالات (وبالتحديد في هذا) - نعم!



البنية التحتية في الكود



دعنا ننظر إلى الجانب الآخر: بدلاً من إجبار المستخدم على وصف البنية التحتية ، سنحاول اشتقاقها من كود المستخدم المكتوب بالفعل.



فكر في نفس المثال مرة أخرى:



@Get("/my/route")
fun handler() = "Hello World"


نعلم أن المستخدم يريد أن يتم التعامل مع الطلبات إلى / طريقي / طريقي من خلال هذه الوظيفة - لذلك دعونا نقوم بتوليف بنية أساسية من شأنها إنشاء واجهة برمجة تطبيقات HTTP مع / my / route ، وإنشاء وظيفة Serverless المطلوبة ، والقيام بكل السحر اللازم لتوصيلهم!



في مقالتي في Automated Software Engineering 2019 ، أطلقت على هذا الأسلوب Infrastructure in Code. في الواقع ، نحن نستخرج وصف البنية التحتية من كود التطبيق الذي يعرفها ضمنيًا ، أي أنها موجودة بالفعل "داخل" الكود.



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



التنفيذ



نأمل في هذه المرحلة أن تكون الفكرة واضحة وهناك ثلاثة أسئلة رئيسية متبقية:



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


تحليل



سيساعدنا برنامج Kotlin Compiler Embeddable في ذلك.



على الرغم من أن المثال يدور حول التعليقات التوضيحية ، في الواقع ، يمكن تعريف واجهة برمجة تطبيقات HTTP للتطبيق ، اعتمادًا على المكتبة المستخدمة ، بطرق مختلفة تمامًا ، على سبيل المثال:



//ktor-like style
get("my-route") {
    "Hello World"
}


لتحليل الكود التعسفي ، تبين أن Kotlin Compiler Embeddable أكثر دراية وأكثر ملاءمة (نظرًا للعدد الكبير من الأمثلة).



في الوقت الحالي ، يمكن لـ Kotless تحليل ثلاثة أطر رئيسية:



  • Kotless DSL - إطار عمل التعليقات التوضيحية الخاص بـ Kotless
  • Spring Boot هو إطار عمل ويب شائع ، يتم تحليل التعليقات التوضيحية ؛
  • Ktor هو إطار عمل Kotlin Web شائع ، ويتم تحليل وظائف الامتداد.


في عملية تحليل الكود ، يتم جمع مخطط Kotless - وهذا يمثل بعض التمثيل المستقل للنظام الأساسي لتطبيق Serverless. يتم استخدامه لتوليف البنية التحتية وجعل عملية التحليل مستقلة عن منصة سحابية معينة.



نتيجة الجمع بين الطريحة والنقيضة



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



تم التوليف من مخطط Kotless ، والذي يحتوي على وصف لواجهة برمجة تطبيقات HTTP للتطبيق ووظائفه ، بالإضافة إلى بعض البيانات الإضافية (على سبيل المثال ، اسم DNS المطلوب).



بالنسبة للتوليف نفسه ، يتم استخدام مكتبة Terraform DSL المنشأة خصيصًا. يبدو رمز التوليف كما يلي:



val resource = api_gateway_rest_api("tf_name") {
    name = "aws_name"
    binary_media_types = arrayOf(MimeType.PNG)
}


يضمن DSL التنسيق والتكامل المرجعي بين موارد Terraform المختلفة ، مما يجعل توسيع مجموعة الموارد المركبة أسهل بكثير.



يتم نشر الكود المركب في النظام الأساسي السحابي باستخدام تطبيق Terraform البسيط.



ادارة



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



من الضروري توصيل إطار العمل الذي تم إنشاء التطبيق به (على سبيل المثال ، Spring Boot) والنظام الأساسي Serverless. للقيام بذلك ، في وقت إنشاء التطبيق ، يضيف Kotless "مرسلًا" خاصًا إلى كود التطبيق - معالج أحداث خاص بالمنصة يعمل كمحول بين الإطار المستخدم في التطبيق والنظام الأساسي السحابي.



أداة



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



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



التخصيص من جانب المستخدم واضح جدًا أيضًا. يتم تطبيق المكون الإضافي نفسه أولاً:



plugins {
  io("io.kotless") version "0.1.5" apply true
}


بعد ذلك ، يضيف المستخدم الإطار الذي يحتاجه:



dependencies {
  //Kotless DSL 
  implementation("io.kotless", "lang", "0.1.5")
}


أخيرًا ، يقوم بإعداد الوصول إلى AWS بحيث يمكن لـ Kotless نشر:



kotless {
  config {
    bucket = "kotless.s3.example.com"

    terraform {
      profile = "example"
      region = "us-east-1"
    }
  }
}


إطلاق محلي



من السهل أن ترى أن النقطة الأخيرة تتطلب أن يكون المستخدم على دراية بـ AWS وأن يكون لديه حساب AWS على الأقل. أخافت هذه المتطلبات المستخدمين الذين أرادوا المحاولة أولاً محليًا إذا كانت الأداة مناسبة لهم.



هذا هو السبب في أن Kotless يدعم وضع التشغيل المحلي. باستخدام الميزات القياسية للإطار المختار (يمكن لكل من Ktor و Spring Boot و Kotless DSL ، بالطبع ، تشغيل التطبيقات محليًا) ، ينشر Kotless التطبيق على جهاز المستخدم.



علاوة على ذلك ، يمكن لـ Kotless تشغيل محاكاة AWS (المستخدمة بواسطة LocalStack ) بحيث يمكن للمستخدم التحقق محليًا من أن التطبيق يتصرف كما هو متوقع.



مزيد من التطوير



أثناء كتابة Kotless (ومعها أطروحة الماجستير الخاصة بي) ، تمكنت من تقديمها في ASE 2019 و KotlinConf 2019 وفي بودكاست Talking Kotlin. بشكل عام ، تم قبول الأداة بشكل إيجابي ، على الرغم من أنها لم تعد تبدو جديدة بحلول نهاية عام 2019 (بحلول ذلك الوقت ، أصبحت Zappa و Claudia.js و AWS Chalice شائعة).



ومع ذلك ، في الوقت الحالي ، ربما تكون Kotless هي الأداة الأكثر شهرة في فئتها في عالم Kotlin ، وأنا أخطط بالتأكيد لتطويرها.



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



على سبيل المثال ، نخطط لإعداد مجموعة من البرامج التعليمية حول كيفية إنشاء روبوتات دردشة باستخدام Kotless. يبدو أن تقنيات Serverless رائعة لحالة الاستخدام هذه (ويقوم مستخدمو Kotless بالفعل بكتابة روبوتات Telegram) ، لكن الافتقار إلى الأدوات المناسبة يعيق الاستخدام على نطاق واسع.



أخيرًا ، أحد أهم جوانب بنية الأداة بالكامل هو استقلالية النظام الأساسي الخاص بها. في المستقبل غير البعيد ، آمل أن أدعم Google Cloud Platform و Microsoft Azure ، مما سيسمح للتطبيقات بالانتقال من السحابة إلى السحابة باستخدام زر واحد حرفيًا.



أود أن آمل أن تساعد أدوات Kotless والأدوات المماثلة حقًا في إدخال تقنيات Serverless للجماهير وأن المزيد والمزيد من التطبيقات ستستهلك الموارد فقط عند تشغيلها ، مما يقلل بشكل طفيف من الكون :)



All Articles