تعتبر موازنات التحميل ضرورية في تطوير البرامج الحديثة. إذا سبق لك أن تساءلت عن كيفية توزيع الطلبات عبر خوادم متعددة، أو لماذا تبدو بعض مواقع الويب أسرع حتى أثناء حركة المرور الكثيفة، فغالبًا ما تكمن الإجابة في موازنة التحميل الفعالة.
في هذا المنشور، سنقوم بإنشاء موازن تحميل تطبيق بسيط باستخدام خوارزمية Round Robin في Go. الهدف من هذا المنشور هو فهم كيفية عمل موازن الأحمال تحت الغطاء، خطوة بخطوة.
موازن التحميل هو نظام يقوم بتوزيع حركة مرور الشبكة الواردة عبر خوادم متعددة. فهو يضمن عدم تحمل أي خادم واحد الكثير من التحميل، مما يمنع الاختناقات ويحسن تجربة المستخدم بشكل عام. يضمن أسلوب موازنة التحميل أيضًا أنه في حالة فشل أحد الخوادم، يمكن إعادة توجيه حركة المرور تلقائيًا إلى خادم آخر متاح، وبالتالي تقليل تأثير الفشل وزيادة التوفر.
هناك خوارزميات واستراتيجيات مختلفة لتوزيع حركة المرور:
في هذا المنشور، سنركز على تنفيذ موازن التحميل Round Robin.
تقوم خوارزمية round robin بإرسال كل طلب وارد إلى الخادم التالي المتاح بطريقة دائرية. إذا تعامل الخادم A مع الطلب الأول، فسيتعامل الخادم B مع الطلب الثاني، وسيتعامل الخادم C مع الطلب الثالث. بمجرد أن تتلقى جميع الخوادم طلبًا، يبدأ مرة أخرى من الخادم أ.
الآن، دعنا ننتقل إلى التعليمات البرمجية ونبني موازن التحميل الخاص بنا!
type LoadBalancer struct { Current int Mutex sync.Mutex }
سنقوم أولاً بتحديد بنية LoadBalancer بسيطة مع الحقل الحالي لتتبع الخادم الذي يجب أن يتعامل مع الطلب التالي. يضمن Mutex أن الكود الخاص بنا آمن للاستخدام بشكل متزامن.
يتم تحديد رصيد كل خادم نقوم بتحميله من خلال بنية الخادم:
type Server struct { URL *url.URL IsHealthy bool Mutex sync.Mutex }
هنا، كل خادم لديه عنوان URL وعلامة IsHealthy، التي تشير إلى ما إذا كان الخادم متاحًا للتعامل مع الطلبات.
قلب موازن التحميل لدينا هو خوارزمية روبن الدائرية. وإليك كيفية العمل:
func (lb *LoadBalancer) getNextServer(servers []*Server) *Server { lb.Mutex.Lock() defer lb.Mutex.Unlock() for i := 0; i
يتم تخزين التكوين الخاص بنا في ملف config.json، الذي يحتوي على عناوين URL للخادم وفترات التحقق من السلامة (المزيد حول ذلك في القسم أدناه).
type Config struct { Port string `json:"port"` HealthCheckInterval string `json:"healthCheckInterval"` Servers []string `json:"servers"` }
قد يبدو ملف التكوين بالشكل التالي:
{ "port": ":8080", "healthCheckInterval": "2s", "servers": [ "http://localhost:5001", "http://localhost:5002", "http://localhost:5003", "http://localhost:5004", "http://localhost:5005" ] }
نريد التأكد من سلامة الخوادم قبل توجيه أي حركة مرور واردة إليها. ويتم ذلك عن طريق إرسال فحوصات صحية دورية إلى كل خادم:
func healthCheck(s *Server, healthCheckInterval time.Duration) { for range time.Tick(healthCheckInterval) { res, err := http.Head(s.URL.String()) s.Mutex.Lock() if err != nil || res.StatusCode != http.StatusOK { fmt.Printf("%s is down\n", s.URL) s.IsHealthy = false } else { s.IsHealthy = true } s.Mutex.Unlock() } }
كل بضع ثوانٍ (كما هو محدد في التكوين)، يرسل موازن التحميل طلب HEAD إلى كل خادم للتحقق مما إذا كان سليمًا. إذا كان الخادم معطلاً، يتم تعيين علامة IsHealthy على خطأ، مما يمنع توجيه حركة المرور المستقبلية إليه.
عندما يتلقى موازن التحميل طلبًا، فإنه يعيد توجيه الطلب إلى الخادم التالي المتاح باستخدام الوكيل العكسي. في Golang، توفر حزمة httputil طريقة مدمجة للتعامل مع البروكسي العكسي، وسوف نستخدمها في الكود الخاص بنا من خلال وظيفة ReverseProxy:
func (s *Server) ReverseProxy() *httputil.ReverseProxy { return httputil.NewSingleHostReverseProxy(s.URL) }
الوكيل العكسي هو خادم يقع بين العميل وواحد أو أكثر من خوادم الواجهة الخلفية. يتلقى طلب العميل، ويعيد توجيهه إلى أحد خوادم الواجهة الخلفية، ثم يعيد استجابة الخادم إلى العميل. يتفاعل العميل مع الوكيل، غير مدرك للخادم الخلفي المحدد الذي يتعامل مع الطلب.
في حالتنا، يعمل موازن التحميل كوكيل عكسي، حيث يجلس أمام خوادم متعددة ويوزع طلبات HTTP الواردة عبرها.
عندما يقوم العميل بتقديم طلب إلى موازن التحميل، فإنه يحدد الخادم الصحي التالي المتاح باستخدام تطبيق خوارزمية round robin في وظيفة getNextServer ويقوم بإرسال طلب العميل إلى ذلك الخادم. في حالة عدم توفر خادم سليم، فإننا نرسل خطأ عدم توفر الخدمة إلى العميل.
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { server := lb.getNextServer(servers) if server == nil { http.Error(w, "No healthy server available", http.StatusServiceUnavailable) return } w.Header().Add("X-Forwarded-Server", server.URL.String()) server.ReverseProxy().ServeHTTP(w, r) })
تقوم طريقة ReverseProxy بإرسال الطلب إلى الخادم الفعلي، ونقوم أيضًا بإضافة رأس مخصص X-Forwarded-Server لأغراض تصحيح الأخطاء (رغم أنه في الإنتاج، يجب علينا تجنب الكشف عن تفاصيل الخادم الداخلية مثل هذا).
أخيرًا، نبدأ موازن التحميل على المنفذ المحدد:
log.Println("Starting load balancer on port", config.Port) err = http.ListenAndServe(config.Port, nil) if err != nil { log.Fatalf("Error starting load balancer: %s\n", err.Error()) }
في هذا المنشور، قمنا ببناء موازن تحميل أساسي من الصفر في Golang باستخدام خوارزمية round robin. هذه طريقة بسيطة لكنها فعالة لتوزيع حركة المرور عبر خوادم متعددة والتأكد من قدرة نظامك على التعامل مع الأحمال الأعلى بكفاءة.
هناك الكثير مما يجب استكشافه، مثل إضافة فحوصات صحية متطورة، أو تنفيذ خوارزميات مختلفة لموازنة التحميل، أو تحسين تحمل الأخطاء. ولكن هذا المثال الأساسي يمكن أن يكون أساسًا متينًا يمكن البناء عليه.
يمكنك العثور على الكود المصدري في مستودع GitHub هذا.
تنصل: جميع الموارد المقدمة هي جزئيًا من الإنترنت. إذا كان هناك أي انتهاك لحقوق الطبع والنشر الخاصة بك أو الحقوق والمصالح الأخرى، فيرجى توضيح الأسباب التفصيلية وتقديم دليل على حقوق الطبع والنشر أو الحقوق والمصالح ثم إرسالها إلى البريد الإلكتروني: [email protected]. سوف نتعامل مع الأمر لك في أقرب وقت ممكن.
Copyright© 2022 湘ICP备2022001581号-3