كتابة مدونة Microservice - الجزء الأول "الوصف العام"

في هذه المقالة ، أود أن أشارك تجربتنا مع SergeyMaslov في حل المشكلات النموذجية باستخدام بنية microservice باستخدام مثال مهمة "إنشاء مدونة" (على أمل أن يتمكن القارئ من تخيل كيف يتم ترتيب المدونة وهذا لا ينبغي أن يثير أسئلة حول الوظيفة :)

لذلك ، ستتألف مدونتنا من 5 خدمات ميكروية مكتوبة بلغة golang:

  • Gateway API (api-gw) - مسؤول عن توجيه الطلبات وتوثيقها وتسجيلها وتتبعها
  • المستخدمين (المستخدم) - تسجيل / مصادقة المستخدمين ، وقطع الأشجار ، وتتبع الطلبات
  • المقالات (المشاركة) - إنشاء / قراءة / تعديل / حذف المقالات (CRUD) وتسجيل وتتبع الطلبات وترخيصها
  • التعليقات - إنشاء / قراءة / تعديل / حذف التعليقات (CRUD) وتسجيل وتتبع وتفويض الطلبات
  • الفئات (الفئة) - إنشاء / قراءة / تغيير / حذف الفئات (CRUD) وتسجيل وتتبع وتفويض الطلبات

سيتم تنفيذ تطبيق العميل (web / frontend) على vue.js وسوف يتفاعل مع الخدمات الصغيرة عبر واجهة برمجة تطبيقات REST ، وسوف تتفاعل الخدمات الميكروية نفسها مع بعضها البعض عبر gRPC.

كما التخزين سوف نستخدم MongoDB.

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

مخطط مكون المدونة


صورة

سيتم تنفيذ كل خدمة microservice في حاوية Docker منفصلة ، وسيتم إطلاق المشروع باستخدام عامل الميناء.

إبداء تحفظ على الفور في المثال ، لتبسيط عملية التطوير ، سأستخدم افتراضين يجب عدم استخدامهما في الإنتاج.

  • يتم نشر قاعدة البيانات في حاوية عامل ميناء. هذا النهج يقلل من موثوقية التخزين (باستثناء المخطط الذي تمت مناقشته في HighLoad 2018).
  • يتم استضافة المشروع بأكمله في مستودع واحد بوابة. يتناقض هذا النهج مع أحد المبادئ الأساسية لهندسة الخدمات الميكروية - العزلة ، ويزيد من احتمال التوصيل بين المكونات.

يمكنك مشاهدة العرض التوضيحي للمشروع هنا ، والكود المصدري هنا .

هيكل المشروع




كيف سيتم بناء عملية التطوير


كما قلت سابقًا ، سيتم التفاعل بين الخدمات الصغيرة على gRPC. باختصار ، gRPC هو إطار عالي الأداء تم تطويره بواسطة Google لاستدعاء الإجراءات عن بُعد (RPC) - إنه يعمل على رأس HTTP / 2. يستند GRPC إلى ملف التعريف الأولي (انظر المثال أدناه) ، وتتمثل مهمته الرئيسية في إعلان شيئين في شكل مضغوط:

  • إعطاء قائمة كاملة بواجهات الخدمة (تناظرية واجهات API) ؛
  • وصف ما يتم تغذيته لإدخال كل واجهة وما نحصل عليه في الإخراج.

أدناه ، على سبيل المثال ، يتم إعطاء ملف تعريف خدمة الفئة.

syntax = "proto3"; package protobuf; import "google/api/annotations.proto"; //   Category service CategoryService { //  rpc Create (CreateCategoryRequest) returns (CreateCategoryResponse) { option (google.api.http) = { post: "/api/v1/category" }; } //  rpc Update (UpdateCategoryRequest) returns (UpdateCategoryResponse) { option (google.api.http) = { post: "/api/v1/category/{Slug}" }; } //  rpc Delete (DeleteCategoryRequest) returns (DeleteCategoryResponse) { option (google.api.http) = { delete: "/api/v1/category/{Slug}" }; } //   SLUG rpc Get (GetCategoryRequest) returns (GetCategoryResponse) { option (google.api.http) = { get: "/api/v1/category/{Slug}" }; } // rpc Find (FindCategoryRequest) returns (FindCategoryResponse) { option (google.api.http) = { get: "/api/v1/category" }; } } //------------------------------------------ // CREATE //------------------------------------------ message CreateCategoryRequest { string ParentId = 1; string Name = 2; string Path = 3; } message CreateCategoryResponse { Category Category = 1; } //------------------------------------------ // UPDATE //------------------------------------------ message UpdateCategoryRequest { string Slug = 1; string ParentId = 2; string Name = 4; string Path = 5; int32 Status = 6; } message UpdateCategoryResponse { int32 Status =1; } //------------------------------------------ // DELETE //------------------------------------------ message DeleteCategoryRequest { string Slug = 1; } message DeleteCategoryResponse { int32 Status =1; } //------------------------------------------ // GET //------------------------------------------ message GetCategoryRequest { string Slug = 1; } message GetCategoryResponse { Category Category = 1; } //------------------------------------------ // FIND //------------------------------------------ message FindCategoryRequest { string Slug = 1; } message FindCategoryResponse { repeated Category Categories = 1; } //------------------------------------------ // CATEGORY //------------------------------------------ message Category { string Slug = 1; string ParentId = 2; string Path = 3; string Name = 4; int32 Status = 5; } 

الآن وبعد أن اكتشفنا بشكل عام سبب الحاجة إلى ملف تعريف أولي ، دعونا نرى كيف ستبدو عملية تطوير خدماتنا الصغيرة:

  1. وصفنا هيكل الخدمة في ملف التعريف ؛
  2. نبدأ منشئ الشفرة (./bin/protogen.sh) ، وسيقوم بإنشاء الجزء الرئيسي من رمز الخادم بالنسبة لنا + سيخلق رمز العميل ، على سبيل المثال ، بالنسبة لواجهة برمجة تطبيقات API + ، ستقوم بإنشاء مستندات محدثة بتنسيق swagger ؛
  3. كل ما يتعين علينا القيام به بأيدينا هو كتابة التعليمات البرمجية لتنفيذ الواجهات في ملف خاص /protobuf/functions.go.

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

تابع في مقال "كتابة مدونة على Microservices الجزء 2 من بوابة API . "

Source: https://habr.com/ru/post/ar473514/


All Articles