200 लाइनों में गो पर बैलेन्सर

मैंने उल्लेख किया है कि मैंने गो पर एक बैलेंसर विकसित किया है, हालांकि एक राय है कि दृश्यपटल को नग्नेक्स होना चाहिए।

मुझे लगता है कि टिप्पणियों में लोग किसी भी चीज़ के बारे में कल्पना कर सकते हैं। शायद किसी को लगता है कि मैं एक ब्रीच हूं और गो पर कोई बैलेंसर नहीं है। इसलिए, मैंने अभी से बैलेंसर कोड बिछाने का फैसला किया। यह कोड 4 घंटे में "विशेष स्थिति" में लिखा गया था, और फिर ओवरलोडिंग के बिना 2 सप्ताह तक लगभग उसी रूप में काम किया, जैसा कि "हर कोई" ग्रीस में था। कोड सुंदर नहीं है और यहां तक ​​कि त्रुटियां भी हैं, लेकिन चूंकि यह काम किया और संतुलित था, इसलिए यह पहले से ही कुछ के लायक था।

कटौती के तहत लगभग एक मूल सरस बालिंकर है। मैंने मूल स्थिरांक और कुकी डिकोडिंग कोड को हटा दिया।


package main // (c) http://habrahabr.ru/users/pyra/ BSD license import ( // "encoding/json" "fmt" // "io" "io/ioutil" "log" "time" "net/http" "net/url" // "os" // "sort" "strconv" "strings" // "time" "errors" ) func main() { //http.HandleFunc("/r", handle_redir) //http.Handle("/extrahtml/", http.FileServer(http.Dir("./extrahtml/"))) http.HandleFunc("/googleXXXXXXXXXXXX.html", handle_google) http.HandleFunc("/", handle_def) https1 := &http.Server{ Addr: ":8443", Handler: nil, ReadTimeout: 20 * time.Second, WriteTimeout: 20 * time.Second, MaxHeaderBytes: 1 << 15, } go func() { log.Fatal(https1.ListenAndServeTLS("device.crt", "device.key")) }() http1 := &http.Server{ Addr: ":8080", Handler: nil, ReadTimeout: 20 * time.Second, WriteTimeout: 20 * time.Second, MaxHeaderBytes: 1 << 15, } http1.ListenAndServe() } var reqcntr int var opencntr int func redirectPolicyFunc(req *http.Request, via []*http.Request) error { e := errors.New("redirect") return e } func handle_google(w http.ResponseWriter, r *http.Request) { fmt.Println("google") b, _ := ioutil.ReadFile("googleXXXXXXXXXXXXXXXX.html") fmt.Println(len(b)) w.Write(b) } func handle_def(w http.ResponseWriter, r *http.Request) { //      opencntr++ defer func() { opencntr-- }() client := &http.Client{ CheckRedirect: redirectPolicyFunc, } ip := strings.Split(r.RemoteAddr, ":")[0] //    ( ) reqcntr++ q := r.URL.RawQuery //fmt.Println("def ", r.Method, reqcntr, q) //r.Form, _ = url.ParseQuery(r.URL.RawQuery) //io.WriteString(w, r.URL.Path) path := r.URL.Path // ID     var cid int64 //       breporting := false //      if strings.HasSuffix(path, ".php") { // fmt.Println("breporting = true") breporting = true } //        if path == "/ajax/main.php" { path = "/ajax/main_hide1777.php" } cid = -2 if strings.HasPrefix(path, "/ajax/") || strings.HasPrefix(path, "/im/") { //      ID  m, err := url.ParseQuery(q) if err == nil { id := m.Get("xid") if id == "" { id = m.Get("aid") if id == "" { id = m.Get("cid") if id == "" { id = m.Get("bid") } } } cid, err = strconv.ParseInt(id, 10, 64) if err != nil { cid = -1 } } } else if strings.HasPrefix(path, "/avatar/") { //     /avatar/1234.gif // ID - 1234 cid = -1 pos1 := strings.Index(path[8:], ".") if pos1 != -1 { id := path[6 : pos1+6] var err error cid, err = strconv.ParseInt(id, 10, 64) if err != nil { cid = -1 } } } //     else         //  ID        //host := "test000.cloud" host := "login.yahoo.com" //           if cid > 1000 && cid < 5000 { host = "prod002.cloud" } else if cid >= 5000 && cid < 7000 { host = "prod003.cloud" } else if cid >= 7000 && cid < 15000 { host = "prod005.cloud" } else if cid >= 15000 && cid < 16000 { host = "prod006.cloud" } else if cid >= 25000 && cid < 34000 { host = "prod011.cloud" } url := "" //   IP     PHP 5.3 FastCGI     if breporting { url = "https://" + host + path + "?" + q + "&HEHE_IP="+ip+"&HEHE_SECRET=B87BVf5" }else{ url = "https://" + host + path + "?" + q } fmt.Println(url) //   GET  if r.Method == "GET" { req1, err := http.NewRequest("GET", url, nil) if err != nil { fmt.Println("Error1: ", err) //      } req1.Header = r.Header req1.Header.Add("XHEHE_REMOTE_IP", ip) resp, _ := client.Do(req1) StatusCode := resp.StatusCode defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { fmt.Println("Error2: ", err) //   )))) //      } fmt.Println("def ", r.Method, reqcntr, opencntr, url, len(body), StatusCode) for k1, v1 := range resp.Header { for _, v2 := range v1 { w.Header().Add(k1, v2) } } w.WriteHeader(StatusCode) w.Write(body) } } // 190    

इस कोड को फिर से लिखा गया है। इसने मेरे पिछले पैक से विचारों को लागू किया। व्यवस्थापक पैनल के लिए एक अलग पोर्ट, जो हमेशा काम करता है, सर्वर, सांख्यिकी और रिपोर्टों के कितने कनेक्शन के नियंत्रण के लिए धन्यवाद, राउटिंग टेबल को अपडेट करने के लिए एपीआई (यह उपयोगकर्ताओं को माइग्रेट करने की अनुमति देता है)। और अब हम इंस्टेंसेस को अपडेट करने या उपयोगकर्ताओं को माइग्रेट करने के अनुरोधों में देरी का विकास कर रहे हैं, बीटा में भी स्टैटिक कैशिंग, रीडायरेक्ट कैशिंग है।

उपयोगकर्ता माइग्रेशन क्या है चित्रों के बिना मुख्य उपयोगकर्ता प्रोफ़ाइल ~ 10KB है। सर्वर ए उपयोगकर्ता को एक फ़ाइल में अनुक्रमित करता है, फ़ाइल को संकुचित किया जाता है, फ़ाइल को सर्वर बी में कॉपी किया जाता है, बैलेंसर या बैलेंसर्स को बताया जाता है कि अब इस उपयोगकर्ता से अनुरोधों को सर्वर बी में भेजा जाना चाहिए।

मुझे गो और नग्नेक्स की तुलना करने में दिलचस्पी होगी। स्पष्ट रूप से, nginx तेज है, लेकिन अगर nginx एक कोर पर 300 या 500 एमबी संतुलित करता है, और केवल 50 Mb चला जाता है, तो उसी DigitalOcean पर 5 रुपये के लिए क्लाउड सर्वर पर एक विशिष्ट वर्चुअल पोर्ट की गति को देखते हुए, मुझे आश्चर्य है कि यह पैसे में कैसे अनुवाद करता है? क्या होगा यदि गो केवल 1mb को संतुलित कर सकता है? तुलना और लिखने का समय नहीं है।

यदि कोई बेंचमार्क बनाने का फैसला करता है, तो न केवल यह विचार करना महत्वपूर्ण है कि प्रतिक्रिया का आकार अलग है, बल्कि यह भी कि अनुरोध को देरी से संसाधित किया जा सकता है। इसलिए, उदाहरणों के अनुकरण के लिए गो महान है। Http.NewRequest के बजाय, time.Sleep लगाएं। बेलेंसर्स की तुलना में अधिक परिमाण का एक आदेश होना चाहिए।

PS उन लोगों के लिए जो गो से परिचित नहीं हैं। गो इस प्रतीत होता है सिंक्रोनस कोड को एसिंक्रोनस में बदल देता है, जो एसिंक्रोनस कॉल का उपयोग करके एक ही धागे या कई थ्रेड्स पर चल सकता है। जैसे नग्नेक्स करता है। एक निष्पादन योग्य फ़ाइल में संकलन परिणाम गो से स्वतंत्र है और गो के बिना मशीन पर निष्पादित किया जा सकता है।

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


All Articles