7 نصائح حول كيفية كتابة الخدمات الدقيقة عالية الأداء من Golang

هذه مقدمة لكيفية تصميم وتطوير Go microservice. ستقودك هذه المقالة مباشرة إلى أفضل الممارسات في عالم Go وستظهر لك مسكتك قبل اليد. سأترك جميع المصادر أدناه.

  1. لا تستخدم عميل HTTP الافتراضي لـ Go
  2. فكر في هذه الأطر والمكتبات الخارجية (المعايير)
  3. لا تخف من ملفات Makefiles
  4. استخدم وحدات Go Go لتوفير وقتك في إعداد البيئة
  5. تسجيل بشكل صحيح (Logrus)
  6. اكتب اختبارات الوحدة بدون ألم
  7. المستند بسرعة (Swagger)

1. لا تستخدم عميل HTTP الافتراضي لـ Go

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

لا تحدد حزمة http الخاصة بـ Go مهلات الطلب بشكل افتراضي ، مما يسمح للخدمات باختطاف goroutines الخاصة بك. حدد دومًا http.Client مخصص عند الاتصال بالخدمات الخارجية.

عند استخدام http.Get (url) ، فأنت تستخدم http.DefaultClient ، وهو متغير حزمة يحدد التكوين الافتراضي للعميل. الإعلان عن ذلك هو:

var DefaultClient = & Client {}

من بين أمور أخرى ، يقوم http.Client بتكوين مهلة تقصر الاتصالات طويلة المدى. القيمة الافتراضية لهذه القيمة هي 0 ، والتي يتم تفسيرها على أنها "بدون مهلة". قد يكون هذا افتراضًا معقولًا للحزمة ، ولكنه خطأ شرير وسبب سقوط تطبيقنا في المثال أعلاه. كما اتضح ، تسبب انقطاع واجهة برمجة تطبيقات Spacely Sprockets في حدوث محاولات اتصال للتعليق (لا يحدث هذا دائمًا ، ولكنه يحدث في مثالنا). سيستمر تعليقهم طالما قرر الخادم المعطل الانتظار. نظرًا لإجراء مكالمات API لخدمة طلبات المستخدم ، تسبب ذلك في تعليق goroutines التي تخدم طلبات المستخدم أيضًا. بمجرد وصول عدد كافٍ من المستخدمين إلى صفحة العجلة المسننة ، سقط التطبيق ، على الأرجح بسبب الوصول إلى حدود الموارد.

الحل

من الأفضل دائمًا أن يكون لديك تحكم أكثر دقة في دورة حياة الطلب ، يمكنك أيضًا تحديد شبكة مخصصة. النقل وشبكة. طلب. النقل عبارة عن بنية يستخدمها العملاء لإدارة اتصال TCP الأساسي وهو Dialer عبارة عن هيكل يدير إنشاء الاتصال. تحتوي حزمة Go's net على Transport and Dialer افتراضي أيضًا. فيما يلي مثال على استخدام تلك المخصصة:

tr: = & http.Transport {DialContext: (& net.Dialer {Timeout: n * time.Second، KeepAlive: n * time.Second،}). DialContext، TLSHandshakeTimeout: n * time.Second، ExpectContinueTimeout: n * time.Second ، ResponseHeaderTimeout: n * time.Second ،
        MaxIdleConns: n ، MaxConnsPerHost: n ،}
cli: = & http.Client {Transport: tr، Timeout: n * time.Second،}

2. النظر في هذه الأطر والمكتبات الخارجية

إذا سألت مطور Go عن أطر الويب أو المكتبات التي يمكنك استخدامها ، فإن الإجابة النموذجية هي التمسك بالمكتبات القياسية. ومن المفارقات ، أن أفضل نتيجة بحث من Google لـ "أطر عمل golang" هي سبب عدم استخدامك لها.

بناء خوادم HTTP أسهل مع إطار العمل.

لقد وجدت معايير ضد Gin و Echo و Beego و Gorilla Mux و Goji لمعلمة واحدة مسماة وأدناه هي النتائج. يحتوي Gin على أسرع جهاز توجيه ، يليه صدى ثاني قريب.

تسلسل JSON وإلغاء التسلسل

بمجرد وصول طلب API عبر جهاز التوجيه وتمريره إلى وحدة تحكم أو معالج ، فإن الخطوة التالية هي فك تشفير الطلب JSON أو Encode أثناء إعادة الاستجابة.

يحتوي Go على حزمة ترميز جيدة تدعم تنسيقات متعددة مثل json و XML و csv ، ولكن نظرة سريعة على البدائل تظهر لك الكثير من المكتبات. فيما يلي معيار المقارنة بين Jsoniter و EasyJson مقابل حزمة الترميز / json القياسية وأدناه هي النتائج.

فيما يلي نتيجة فك تشفير JSON.

الآن إذا قمت بفك تشفير طلبك ، فقد تكون الخطوة التالية هي تطبيق منطق عملك وقد تقوم ببعض عمليات قاعدة البيانات.

بينما تقلل sqlx من عدد الأسطر النموذجي الذي تكتبه لإنشاء CRUD ، ما زلت ينتهي بكتابة كود متكرر في كثير من الأحيان. يمكن أن يساعد استخدام ORM في تقليله والتركيز على منطق عملك.

فيما يلي مقياس لقاعدة البيانات ، قاعدة البيانات + sqlx ، gorm ، go-pg للاستعلام وفيما يلي النتائج. من المثير للدهشة أن go-pg ، أداء ORM أسرع من الحزمة القياسية أو حتى sqlx. بينما GORM مشهور جدًا في النظام البيئي بطيء نسبيًا.

الاستعلام عن 200 ألف سجل من قاعدة بيانات postgres

ستساعدك هذه المعايير على اختيار مجموعة الإطارات الخاصة بك.

3. لا تخف من Makefiles

أثناء التطوير ، اعتدت على تنفيذ "go build" و "go test" بشكل متكرر يدويًا. كانت هذه عادة سيئة أستقيل عليها. إنه ليس مؤلمًا جدًا إذا كنت تستخدم أمرًا بسيطًا بدون أي أقواس. ولكن في حالة المهام الأكثر تعقيدًا ، سيكون الأمر مؤلمًا بطبيعة الحال. هناك عدد قليل من الخيارات التي يمكنك وضعها في الاعتبار كمخرج. يمكنك استخدام برنامج bash النصي للقيام بالعمل نيابة عنك. أو أفضل ، على الأقل بالنسبة لي ، يمكنك كتابة ملف Makefile. أداة الصنع موجودة لهذا السبب وفي Makefile يمكنك الاحتفاظ بجميع مهامك المشتركة معًا.

يبدو ملفي الشخصي عادة وكأنه شيء من هذا القبيل:

build: ## Build go build -o bin / binary_name cmd / main.go
تشغيل: ## تشغيل bin server / binary_name
المساعدة:grep -E '^ [a-zA-Z _-] +:. *؟ ##. * $$' $ (MAKEFILE_LIST) | awk 'BEGIN {FS = ":. *؟ ##"} ؛ {printf "\ 033 [36m٪ -30s \ 033 [0m٪ s \ n" ، $$ 1 ، $$ 2} '
.DEFAULT_GOAL: = مساعدة

ستقوم بتنفيذها على النحو التالي:

> اجري
> اجعل البناء
> make // ستدرج جميع الأوامر مع التعليقات

مزيد من المعلومات حول إمكانيات Makefile: https://sohlich.github.io/post/go_makefile/

4. استخدم وحدات Go

المصدر: https://blog.golang.org/using-go-modules

للحصول على أفضل تفسير ، يرجى الرجوع إلى مقالة المصدر حول Go Modules.

إن أمكن ، يجب أن تجعل مشروعك قابلاً للاستيراد إلى مشاريع أخرى كوحدة نمطية.

هذا يوفر الكثير من الوقت وسوف تجد مكان إعادة استخدام التعليمات البرمجية الخاصة بك بسرعة كبيرة.

5. سجل بشكل صحيح

التوصية https://github.com/sirupsen/logrus. في حين أنها واحدة من الأكثر شعبية إلا أنها تتميز بميزات غنية.

6. كتابة اختبارات الوحدة بدون ألم

لا يجب مطاردة تغطية الرمز 100٪. مجرد تغطية الأجزاء الأكثر أهمية. تعمل مكتبة الاختبار القياسية على ما يرام.

لاختبار معالجات http الخاصة بك ، يمكنك الرجوع إلى مكتبة "net / http / httpptest".

7. قم بتوثيق خدماتك الصغيرة

للتوثيق ، من السهل جدًا استخدام Swagger.

تم استخدام https://github.com/swaggo/swag وهو قادر على توفير وثائق لائقة مع أمثلة.

آمل أن يساعدك هذا! حاول الوصول إلى ما إذا كان هناك شيء بحاجة إلى التحسين أو كنت تفكر بشكل مختلف. شكرا للقراءة ، اعتن بنفسك!

مقالات ذات صلة

https://medium.com/@nate510/don-t-use-go-s-default-http-client-4804cb19f779

https://hackernoon.com/the-myth-about-golang-frameworks-and-external-libraries-93cb4b7da50f

https://sohlich.github.io/post/go_makefile/

https://blog.golang.org/using-go-modules