123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- package loadbalance
- import (
- "errors"
- "math/rand"
- "net/http"
- )
- func (m *RouteManager) GetRequestUpstreamTarget(w http.ResponseWriter, r *http.Request, origins []*Upstream, useStickySession bool) (*Upstream, error) {
- if len(origins) == 0 {
- return nil, errors.New("no upstream is defined for this host")
- }
- var targetOrigin = origins[0]
- if useStickySession {
-
- targetOriginId, err := m.getSessionHandler(r, origins)
- if err != nil {
-
- targetOrigin, index, err := getRandomUpstreamByWeight(origins)
- if err != nil {
- m.println("Unable to get random upstream", err)
- targetOrigin = origins[0]
- index = 0
- }
- m.setSessionHandler(w, r, targetOrigin.OriginIpOrDomain, index)
- return targetOrigin, nil
- }
-
- return origins[targetOriginId], nil
- } else {
-
- var err error
- targetOrigin, _, err = getRandomUpstreamByWeight(origins)
- if err != nil {
- m.println("Failed to get next origin", err)
- targetOrigin = origins[0]
- }
- }
-
- return targetOrigin, nil
- }
- func (m *RouteManager) setSessionHandler(w http.ResponseWriter, r *http.Request, originIpOrDomain string, index int) error {
- session, err := m.SessionStore.Get(r, "STICKYSESSION")
- if err != nil {
- return err
- }
- session.Values["zr_sid_origin"] = originIpOrDomain
- session.Values["zr_sid_index"] = index
- session.Options.MaxAge = 86400
- session.Options.Path = "/"
- err = session.Save(r, w)
- if err != nil {
- return err
- }
- return nil
- }
- func (m *RouteManager) getSessionHandler(r *http.Request, upstreams []*Upstream) (int, error) {
-
- session, err := m.SessionStore.Get(r, "STICKYSESSION")
- if err != nil {
- return -1, err
- }
-
- originDomainRaw := session.Values["zr_sid_origin"]
- originIDRaw := session.Values["zr_sid_index"]
- if originDomainRaw == nil || originIDRaw == nil {
- return -1, errors.New("no session has been set")
- }
- originDomain := originDomainRaw.(string)
- originID := originIDRaw.(int)
-
- if len(upstreams) < originID || upstreams[originID].OriginIpOrDomain != originDomain {
-
- return -1, errors.New("upstreams has been changed")
- }
- return originID, nil
- }
- func getRandomUpstreamByWeight(upstreams []*Upstream) (*Upstream, int, error) {
-
- if len(upstreams) == 1 {
- return upstreams[0], 0, nil
- }
-
- type upstreamWithIndex struct {
- Upstream *Upstream
- Index int
- }
-
- totalWeight := 0
- fallbackUpstreams := make([]upstreamWithIndex, 0, len(upstreams))
- for index, upstream := range upstreams {
- if upstream.Weight > 0 {
- totalWeight += upstream.Weight
- } else {
-
- fallbackUpstreams = append(fallbackUpstreams, upstreamWithIndex{upstream, index})
- }
- }
-
- if totalWeight == 0 {
- if len(fallbackUpstreams) > 0 {
-
- randIndex := rand.Intn(len(fallbackUpstreams))
- return fallbackUpstreams[randIndex].Upstream, fallbackUpstreams[randIndex].Index, nil
- }
-
- return nil, -1, errors.New("no valid upstream servers available")
- }
-
- randomWeight := rand.Intn(totalWeight)
-
- for index, upstream := range upstreams {
- if upstream.Weight > 0 {
- if randomWeight < upstream.Weight {
-
- return upstream, index, nil
- }
- randomWeight -= upstream.Weight
- }
- }
-
- if len(fallbackUpstreams) > 0 {
- randIndex := rand.Intn(len(fallbackUpstreams))
- return fallbackUpstreams[randIndex].Upstream, fallbackUpstreams[randIndex].Index, nil
- }
- return nil, -1, errors.New("failed to pick an upstream origin server")
- }
|