Files
godoxy-yusing/internal/net/gphttp/loadbalancer/sticky.go
yusing d33ff2192a refactor(loadbalancer): implement sticky sessions and improve algorithm separation
- Refactor load balancer interface to separate server selection (ChooseServer) from request handling
- Add cookie-based sticky session support with configurable max-age and secure cookie handling
- Integrate idlewatcher requests with automatic sticky session assignment
- Improve algorithm implementations:
  * Replace fnv with xxhash3 for better performance in IP hash and server keys
  * Add proper bounds checking and error handling in all algorithms
  * Separate concerns between server selection and request processing
- Add Sticky and StickyMaxAge fields to LoadBalancerConfig
- Create dedicated sticky.go for session management utilities
2025-11-07 15:24:57 +08:00

51 lines
1.3 KiB
Go

package loadbalancer
import (
"encoding/hex"
"net/http"
"time"
"unsafe"
"github.com/bytedance/gopkg/util/xxhash3"
"github.com/yusing/godoxy/internal/types"
)
func hashServerKey(key string) string {
h := xxhash3.HashString(key)
as8bytes := *(*[8]byte)(unsafe.Pointer(&h))
return hex.EncodeToString(as8bytes[:])
}
// getStickyServer extracts the sticky session cookie and returns the corresponding server
func getStickyServer(r *http.Request, srvs []types.LoadBalancerServer) types.LoadBalancerServer {
cookie, err := r.Cookie("godoxy_lb_sticky")
if err != nil {
return nil
}
serverKeyHash := cookie.Value
for _, srv := range srvs {
if hashServerKey(srv.Key()) == serverKeyHash {
return srv
}
}
return nil
}
// setStickyCookie sets a cookie to maintain sticky session with a specific server
func setStickyCookie(rw http.ResponseWriter, r *http.Request, srv types.LoadBalancerServer, maxAge time.Duration) {
http.SetCookie(rw, &http.Cookie{
Name: "godoxy_lb_sticky",
Value: hashServerKey(srv.Key()),
Path: "/",
MaxAge: int(maxAge.Seconds()),
SameSite: http.SameSiteLaxMode,
HttpOnly: true,
Secure: isSecure(r),
})
}
func isSecure(r *http.Request) bool {
return r.TLS != nil || r.Header.Get("X-Forwarded-Proto") == "https"
}