Membina pengimbang beban mudah dalam Go

WBOY
Lepaskan: 2024-09-07 22:30:37
asal
532 orang telah melayarinya

Pengimbang beban adalah penting dalam pembangunan perisian moden. Jika anda pernah tertanya-tanya bagaimana permintaan diedarkan merentasi berbilang pelayan atau sebab tapak web tertentu berasa lebih pantas walaupun semasa trafik padat, jawapannya selalunya terletak pada pengimbangan beban yang cekap.

Building a simple load balancer in Go

Dalam siaran ini, kami akan membina pengimbang beban aplikasi mudah menggunakan algoritma Round Robin dalam Go. Matlamat siaran ini adalah untuk memahami cara pengimbang beban berfungsi di bawah hud, langkah demi langkah.

Apakah Pengimbang Beban?

Pengimbang beban ialah sistem yang mengagihkan trafik rangkaian masuk merentas berbilang pelayan. Ia memastikan bahawa tiada pelayan tunggal menanggung beban yang terlalu banyak, menghalang kesesakan dan meningkatkan keseluruhan pengalaman pengguna. Pendekatan pengimbangan beban juga memastikan bahawa jika satu pelayan gagal, maka trafik boleh dialihkan semula secara automatik ke pelayan lain yang tersedia, sekali gus mengurangkan kesan kegagalan dan meningkatkan ketersediaan.

Mengapa kita menggunakan Pengimbang Beban?

  • Ketersediaan tinggi: Dengan mengagihkan trafik, pengimbang beban memastikan walaupun satu pelayan gagal, trafik boleh dialihkan ke pelayan lain yang sihat, menjadikan aplikasi lebih berdaya tahan.
  • Skalabiliti: Pengimbang beban membolehkan anda menskalakan sistem anda secara mendatar dengan menambahkan lebih banyak pelayan apabila trafik meningkat.
  • Kecekapan: Ia memaksimumkan penggunaan sumber dengan memastikan semua pelayan berkongsi beban kerja secara sama rata.

Algoritma pengimbangan beban

Terdapat algoritma dan strategi yang berbeza untuk mengagihkan trafik:

  • Round Robin: Salah satu kaedah paling mudah yang ada. Ia mengedarkan permintaan secara berurutan di antara pelayan yang tersedia. Sebaik sahaja ia sampai ke pelayan terakhir, ia bermula semula dari awal.
  • Robin Bulat Berwajaran: Serupa dengan algoritma robin bulat kecuali setiap pelayan diberikan beberapa pemberat berangka tetap. Berat yang diberikan ini digunakan untuk menentukan pelayan untuk penghalaan trafik.
  • Sambungan Paling Kurang: Halakan trafik ke pelayan dengan sambungan paling kurang aktif.
  • IP Hashing: Pilih pelayan berdasarkan alamat IP pelanggan.

Dalam siaran ini, kami akan menumpukan pada pelaksanaan Round Robin pengimbang beban.

Apakah algoritma Round Robin?

Algoritma round robin menghantar setiap permintaan masuk ke pelayan tersedia seterusnya secara bulat. Jika pelayan A mengendalikan permintaan pertama, pelayan B akan mengendalikan permintaan kedua, dan pelayan C akan mengendalikan permintaan ketiga. Setelah semua pelayan menerima permintaan, ia bermula semula dari pelayan A.

Sekarang, mari beralih ke kod dan bina pengimbang beban kami!

Langkah 1: Tentukan Pengimbang Beban dan Pelayan

type LoadBalancer struct {
    Current int
    Mutex   sync.Mutex
}
Salin selepas log masuk

Kami mula-mula akan mentakrifkan struct LoadBalancer yang mudah dengan medan Semasa untuk menjejaki pelayan mana yang harus mengendalikan permintaan seterusnya. Mutex memastikan kod kami selamat digunakan serentak.

Setiap pelayan yang kami muatkan baki ditentukan oleh struct Pelayan:

type Server struct {
    URL       *url.URL
    IsHealthy bool
    Mutex     sync.Mutex
}
Salin selepas log masuk

Di sini, setiap pelayan mempunyai URL dan bendera IsHealthy, yang menunjukkan sama ada pelayan tersedia untuk mengendalikan permintaan.

Langkah 2: Algoritma Round Robin

Inti pengimbang beban kami ialah algoritma round robin. Begini caranya:

func (lb *LoadBalancer) getNextServer(servers []*Server) *Server {
    lb.Mutex.Lock()
    defer lb.Mutex.Unlock()

    for i := 0; i < len(servers); i++ {
        idx := lb.Current % len(servers)
        nextServer := servers[idx]
        lb.Current++

        nextServer.Mutex.Lock()
        isHealthy := nextServer.IsHealthy
        nextServer.Mutex.Unlock()

        if isHealthy {
            return nextServer
        }
    }

    return nil
}
Salin selepas log masuk
  • Kaedah ini berputar melalui senarai pelayan secara round robin. Jika pelayan yang dipilih sihat, ia mengembalikan pelayan tersebut untuk mengendalikan permintaan masuk.
  • Kami menggunakan Mutex untuk memastikan hanya satu goroutine boleh mengakses dan mengubah suai medan Semasa pengimbang beban pada satu masa. Ini memastikan bahawa algoritma round robin beroperasi dengan betul apabila berbilang permintaan sedang diproses secara serentak.
  • Setiap Pelayan juga mempunyai Mutex sendiri. Apabila kami menyemak medan IsHealthy, kami mengunci Mutex pelayan untuk menghalang akses serentak daripada berbilang goroutine.
  • Tanpa penguncian Mutex ada kemungkinan goroutine lain boleh mengubah nilai yang boleh mengakibatkan membaca data yang salah atau tidak konsisten.
  • Kami membuka kunci Mutex sebaik sahaja kami mengemas kini medan Semasa atau membaca nilai medan IsHealthy untuk memastikan bahagian kritikal sekecil mungkin. Dengan cara ini, kami menggunakan Mutex untuk mengelakkan sebarang keadaan perlumbaan.

Langkah 3: Mengkonfigurasi Pengimbang Beban

Konfigurasi kami disimpan dalam fail config.json, yang mengandungi URL pelayan dan selang semakan kesihatan (lebih lanjut mengenainya di bahagian bawah).

type Config struct {
    Port                string   `json:"port"`
    HealthCheckInterval string   `json:"healthCheckInterval"`
    Servers             []string `json:"servers"`
}
Salin selepas log masuk

Fail konfigurasi mungkin kelihatan seperti ini:

{
  "port": ":8080",
  "healthCheckInterval": "2s",
  "servers": [
    "http://localhost:5001",
    "http://localhost:5002",
    "http://localhost:5003",
    "http://localhost:5004",
    "http://localhost:5005"
  ]
}
Salin selepas log masuk

Step 4: Health Checks

We want to make sure that the servers are healthy before routing any incoming traffic to them. This is done by sending periodic health checks to each server:

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()
    }
}
Salin selepas log masuk

Every few seconds (as specified in the config), the load balancer sends a HEAD request to each server to check if it is healthy. If a server is down, the IsHealthy flag is set to false, preventing future traffic from being routed to it.

Step 5: Reverse Proxy

When the load balancer receives a request, it forwards the request to the next available server using a reverse proxy. In Golang, the httputil package provides a built-in way to handle reverse proxying, and we will use it in our code through the ReverseProxy function:

func (s *Server) ReverseProxy() *httputil.ReverseProxy {
    return httputil.NewSingleHostReverseProxy(s.URL)
}
Salin selepas log masuk
What is a Reverse Proxy?

A reverse proxy is a server that sits between a client and one or more backend severs. It receives the client's request, forwards it to one of the backend servers, and then returns the server's response to the client. The client interacts with the proxy, unaware of which specific backend server is handling the request.

In our case, the load balancer acts as a reverse proxy, sitting in front of multiple servers and distributing incoming HTTP requests across them.

Step 6: Handling Requests

When a client makes a request to the load balancer, it selects the next available healthy server using the round robin algorithm implementation in getNextServer function and proxies the client request to that server. If no healthy server is available then we send service unavailable error to the client.

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)
    })
Salin selepas log masuk

The ReverseProxy method proxies the request to the actual server, and we also add a custom header X-Forwarded-Server for debugging purposes (though in production, we should avoid exposing internal server details like this).

Step 7: Starting the Load Balancer

Finally, we start the load balancer on the specified port:

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())
}
Salin selepas log masuk

Working Demo

TL;DR

In this post, we built a basic load balancer from scratch in Golang using a round robin algorithm. This is a simple yet effective way to distribute traffic across multiple servers and ensure that your system can handle higher loads efficiently.

There's a lot more to explore, such as adding sophisticated health checks, implementing different load balancing algorithms, or improving fault tolerance. But this basic example can be a solid foundation to build upon.

You can find the source code in this GitHub repo.

Atas ialah kandungan terperinci Membina pengimbang beban mudah dalam Go. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:dev.to
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan