improved health check

This commit is contained in:
yusing
2024-10-14 10:02:53 +08:00
parent 99207ae606
commit f38b3abdbc
20 changed files with 323 additions and 155 deletions

View File

@@ -45,10 +45,10 @@ func (impl ipHash) serveHTTP(rw http.ResponseWriter, r *http.Request) {
return
}
idx := hashIP(ip) % uint32(len(impl.pool))
if !impl.pool[idx].IsHealthy() {
if impl.pool[idx].Status().Bad() {
http.Error(rw, "Service unavailable", http.StatusServiceUnavailable)
}
impl.pool[idx].handler.ServeHTTP(rw, r)
impl.pool[idx].ServeHTTP(rw, r)
}
func hashIP(ip string) uint32 {

View File

@@ -48,6 +48,6 @@ func (impl *leastConn) ServeHTTP(srvs servers, rw http.ResponseWriter, r *http.R
}
minConn.Add(1)
srv.handler.ServeHTTP(rw, r)
srv.ServeHTTP(rw, r)
minConn.Add(-1)
}

View File

@@ -3,6 +3,7 @@ package loadbalancer
import (
"net/http"
"sync"
"time"
"github.com/go-acme/lego/v4/log"
E "github.com/yusing/go-proxy/internal/error"
@@ -25,12 +26,13 @@ type (
}
LoadBalancer struct {
impl
Config
*Config
pool servers
poolMu sync.Mutex
sumWeight weightType
startTime time.Time
}
weightType uint16
@@ -38,7 +40,7 @@ type (
const maxWeight weightType = 100
func New(cfg Config) *LoadBalancer {
func New(cfg *Config) *LoadBalancer {
lb := &LoadBalancer{Config: cfg, pool: servers{}}
mode := cfg.Mode
if !cfg.Mode.ValidateUpdate() {
@@ -167,6 +169,8 @@ func (lb *LoadBalancer) Start() {
if lb.sumWeight != 0 {
log.Warnf("weighted mode not supported yet")
}
lb.startTime = time.Now()
logger.Debugf("loadbalancer %s started", lb.Link)
}
@@ -178,15 +182,20 @@ func (lb *LoadBalancer) Stop() {
logger.Debugf("loadbalancer %s stopped", lb.Link)
}
func (lb *LoadBalancer) Uptime() time.Duration {
return time.Since(lb.startTime)
}
func (lb *LoadBalancer) availServers() servers {
lb.poolMu.Lock()
defer lb.poolMu.Unlock()
avail := make(servers, 0, len(lb.pool))
for _, s := range lb.pool {
if s.IsHealthy() {
avail = append(avail, s)
if s.Status().Bad() {
continue
}
avail = append(avail, s)
}
return avail
}

View File

@@ -9,7 +9,7 @@ import (
func TestRebalance(t *testing.T) {
t.Parallel()
t.Run("zero", func(t *testing.T) {
lb := New(Config{})
lb := New(new(Config))
for range 10 {
lb.AddServer(&Server{})
}
@@ -17,7 +17,7 @@ func TestRebalance(t *testing.T) {
ExpectEqual(t, lb.sumWeight, maxWeight)
})
t.Run("less", func(t *testing.T) {
lb := New(Config{})
lb := New(new(Config))
lb.AddServer(&Server{Weight: weightType(float64(maxWeight) * .1)})
lb.AddServer(&Server{Weight: weightType(float64(maxWeight) * .2)})
lb.AddServer(&Server{Weight: weightType(float64(maxWeight) * .3)})
@@ -28,7 +28,7 @@ func TestRebalance(t *testing.T) {
ExpectEqual(t, lb.sumWeight, maxWeight)
})
t.Run("more", func(t *testing.T) {
lb := New(Config{})
lb := New(new(Config))
lb.AddServer(&Server{Weight: weightType(float64(maxWeight) * .1)})
lb.AddServer(&Server{Weight: weightType(float64(maxWeight) * .2)})
lb.AddServer(&Server{Weight: weightType(float64(maxWeight) * .3)})

View File

@@ -15,7 +15,7 @@ func (lb *roundRobin) OnRemoveServer(srv *Server) {}
func (lb *roundRobin) ServeHTTP(srvs servers, rw http.ResponseWriter, r *http.Request) {
index := lb.index.Add(1)
srvs[index%uint32(len(srvs))].handler.ServeHTTP(rw, r)
srvs[index%uint32(len(srvs))].ServeHTTP(rw, r)
if lb.index.Load() >= 2*uint32(len(srvs)) {
lb.index.Store(0)
}

View File

@@ -2,6 +2,7 @@ package loadbalancer
import (
"net/http"
"time"
"github.com/yusing/go-proxy/internal/net/types"
U "github.com/yusing/go-proxy/internal/utils"
@@ -33,10 +34,18 @@ func NewServer(name string, url types.URL, weight weightType, handler http.Handl
return srv
}
func (srv *Server) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
srv.handler.ServeHTTP(rw, r)
}
func (srv *Server) String() string {
return srv.Name
}
func (srv *Server) IsHealthy() bool {
return srv.healthMon.IsHealthy()
func (srv *Server) Status() health.Status {
return srv.healthMon.Status()
}
func (srv *Server) Uptime() time.Duration {
return srv.healthMon.Uptime()
}