diff --git a/balance/abstract.go b/balance/abstract.go new file mode 100644 index 0000000..c8caebc --- /dev/null +++ b/balance/abstract.go @@ -0,0 +1,30 @@ +// Package balance... +// +// Description : balance... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2021-11-22 4:45 下午 +package balance + +import ( + "net/http" + + "git.zhangdeman.cn/zhangdeman/gopkg/balance/define" +) + +// IBalance 负载算法接口约束 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 4:45 下午 2021/11/22 +type IBalance interface { + // GetServerNode 获取一个服务器节点 + GetServerNode(req *http.Request) (*define.ServerNode, error) + // AddServerNode 新增一个服务器节点 + AddServerNode(node *define.ServerNode) error + // Remove 移除一个节点 + Remove(hostIP string, port int, force bool) + // GetServerNodeList 获取服务节点列表 + GetServerNodeList() []*define.ServerNode +} diff --git a/balance/base.go b/balance/base.go index b82618a..a9115d2 100644 --- a/balance/base.go +++ b/balance/base.go @@ -7,7 +7,12 @@ // Date : 2021-10-19 2:26 下午 package balance -import "sync" +import ( + "errors" + "sync" + + "git.zhangdeman.cn/zhangdeman/gopkg/balance/define" +) // base ... // @@ -15,7 +20,8 @@ import "sync" // // Date : 2:26 下午 2021/10/19 type base struct { - lock *sync.RWMutex + lock *sync.RWMutex + severList []*define.ServerNode } // Lock ... @@ -53,3 +59,53 @@ func (b *base) RLock() { func (b *base) RUnlock() { b.lock.RUnlock() } + +// AddServerNode 新添加一个服务器节点 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 10:07 下午 2021/10/20 +func (b *base) AddServerNode(node *define.ServerNode) error { + if len(node.HostIP) == 0 || node.Port <= 0 { + return errors.New("host ip or port is invalid") + } + b.Lock() + defer b.Unlock() + for _, item := range b.severList { + if item.HostIP == node.HostIP && item.Port == node.Port { + return errors.New("host config is already exist") + } + } + b.severList = append(b.severList, node) + return nil +} + +// Remove 移除一个节点, force = true , 强制删除, force = false 逻辑删除, 设置状态 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 10:19 下午 2021/10/20 +func (b *base) Remove(hostIP string, port int, force bool) { + b.Lock() + defer b.Unlock() + tmpServerNode := make([]*define.ServerNode, 0) + for _, item := range b.severList { + if item.HostIP == hostIP && item.Port == port { + if force { + continue + } + item.Status = define.ServerNodeStatusRemove + } + tmpServerNode = append(tmpServerNode, item) + } + b.severList = tmpServerNode +} + +// GetServerNodeList 获取服务器节点 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 10:33 下午 2021/10/20 +func (b *base) GetServerNodeList() []*define.ServerNode { + return b.severList +} diff --git a/balance/define/node.go b/balance/define/node.go index 9da4418..d6ff5c9 100644 --- a/balance/define/node.go +++ b/balance/define/node.go @@ -13,8 +13,9 @@ package define // // Date : 12:36 下午 2021/10/19 type ServerNode struct { - HostIP string `json:"host_ip"` // 机器IP - Port int `json:"port"` // 机器端口 - Status int `json:"status"` // 机器状态 - Weight int `json:"weight"` // 机器权重 + HostIP string `json:"host_ip"` // 机器IP + Port int `json:"port"` // 机器端口 + Status int `json:"status"` // 机器状态 + Weight float64 `json:"weight"` // 机器权重 + CurrentWeight float64 `json:"current_weight"` // 当前权重 } diff --git a/balance/ip_hash.go b/balance/ip_hash.go new file mode 100644 index 0000000..8f0284c --- /dev/null +++ b/balance/ip_hash.go @@ -0,0 +1,62 @@ +// Package balance... +// +// Description : balance... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2021-11-22 4:39 下午 +package balance + +import ( + "net/http" + "sync" + + "git.zhangdeman.cn/zhangdeman/gopkg/util" + + "github.com/pkg/errors" + + "git.zhangdeman.cn/zhangdeman/gopkg/balance/define" +) + +// NewIPHash ip hash 负载均衡 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 4:53 下午 2021/11/22 +func NewIPHash(severList []*define.ServerNode) (IBalance, error) { + if nil == severList || len(severList) == 0 { + return nil, errors.New("sever list is empty") + } + return &IPHash{ + base: base{ + lock: &sync.RWMutex{}, + severList: severList, + }, + serverList: severList, + }, nil +} + +// IPHash ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 4:57 下午 2021/11/22 +type IPHash struct { + base + serverList []*define.ServerNode +} + +// GetServerNode ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 4:53 下午 2021/11/22 +func (ih *IPHash) GetServerNode(req *http.Request) (*define.ServerNode, error) { + clintIPHashID := util.GetHashID(util.GetRemoteIp(req)) + ih.RLock() + defer ih.RUnlock() + if len(ih.serverList) == 0 { + return nil, errors.New("sever list is empty") + } + return ih.serverList[int(clintIPHashID%uint64(len(ih.serverList)))], nil +} diff --git a/balance/poll.go b/balance/poll.go index c89eac8..b4b2a51 100644 --- a/balance/poll.go +++ b/balance/poll.go @@ -8,6 +8,7 @@ package balance import ( + "net/http" "sync" "git.zhangdeman.cn/zhangdeman/gopkg/balance/define" @@ -19,15 +20,15 @@ import ( // Author : go_developer@163.com<白茶清欢> // // Date : 12:40 下午 2021/10/19 -func NewPoll(serverList []*define.ServerNode) (*Poll, error) { +func NewPoll(serverList []*define.ServerNode) (IBalance, error) { if nil == serverList || len(serverList) == 0 { return nil, errors.New("server list is empty") } return &Poll{ base: base{ - lock: &sync.RWMutex{}, + lock: &sync.RWMutex{}, + severList: serverList, }, - serverList: serverList, currentServerIndex: 0, }, nil } @@ -39,7 +40,6 @@ func NewPoll(serverList []*define.ServerNode) (*Poll, error) { // Date : 12:41 下午 2021/10/19 type Poll struct { base - serverList []*define.ServerNode currentServerIndex int } @@ -48,21 +48,18 @@ type Poll struct { // Author : go_developer@163.com<白茶清欢> // // Date : 12:43 下午 2021/10/19 -func (p *Poll) GetServerNode() (*define.ServerNode, error) { - if len(p.serverList) == 0 { - return nil, errors.New("server list is empty") - } - p.Lock() - defer p.Unlock() +func (p *Poll) GetServerNode(req *http.Request) (*define.ServerNode, error) { + p.RLock() + defer p.RUnlock() var ( serverNode *define.ServerNode ) // 循环次数 loopTimes := 0 - for loopTimes < len(p.serverList) { + for loopTimes < len(p.severList) { loopTimes++ - p.currentServerIndex = (p.currentServerIndex + 1) % len(p.serverList) - if serverNode = p.serverList[p.currentServerIndex]; serverNode.Status != define.ServerNodeStatusNormal { + p.currentServerIndex = (p.currentServerIndex + 1) % len(p.severList) + if serverNode = p.severList[p.currentServerIndex]; serverNode.Status != define.ServerNodeStatusNormal { continue } break @@ -74,57 +71,3 @@ func (p *Poll) GetServerNode() (*define.ServerNode, error) { return serverNode, nil } - -// AddServerNode 新添加一个服务器节点 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 10:07 下午 2021/10/20 -func (p *Poll) AddServerNode(hostIP string, port int) error { - if len(hostIP) == 0 || port <= 0 { - return errors.New("host ip or port is invalid") - } - p.Lock() - defer p.Unlock() - for _, item := range p.serverList { - if item.HostIP == hostIP && item.Port == port { - return errors.New("host config is already exist") - } - } - p.serverList = append(p.serverList, &define.ServerNode{ - HostIP: hostIP, - Port: port, - Status: define.ServerNodeStatusNormal, - }) - return nil -} - -// Remove 移除一个节点, force = true , 强制删除, force = false 逻辑删除, 设置状态 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 10:19 下午 2021/10/20 -func (p *Poll) Remove(hostIP string, port int, force bool) { - p.Lock() - defer p.Unlock() - tmpServerNode := make([]*define.ServerNode, 0) - for _, item := range p.serverList { - if item.HostIP == hostIP && item.Port == port { - if force { - continue - } - item.Status = define.ServerNodeStatusRemove - } - tmpServerNode = append(tmpServerNode, item) - } - p.serverList = tmpServerNode -} - -// GetServerNodeList 获取服务器节点 -// -// Author : go_developer@163.com<白茶清欢> -// -// Date : 10:33 下午 2021/10/20 -func (p *Poll) GetServerNodeList() []*define.ServerNode { - return p.serverList -} diff --git a/balance/random.go b/balance/random.go new file mode 100644 index 0000000..7f75658 --- /dev/null +++ b/balance/random.go @@ -0,0 +1,59 @@ +// Package balance... +// +// Description : balance... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2021-11-22 6:27 下午 +package balance + +import ( + "errors" + "net/http" + "sync" + + "git.zhangdeman.cn/zhangdeman/gopkg/util" + + "git.zhangdeman.cn/zhangdeman/gopkg/balance/define" +) + +// NewRandom ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 6:29 下午 2021/11/22 +func NewRandom(severList []*define.ServerNode) (IBalance, error) { + if nil == severList || len(severList) == 0 { + return nil, errors.New("sever list is empty") + } + return &Random{ + base{ + lock: &sync.RWMutex{}, + severList: make([]*define.ServerNode, 0), + }, + }, nil +} + +// Random 随机负载均衡 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 6:27 下午 2021/11/22 +type Random struct { + base +} + +// GetServerNode ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 6:31 下午 2021/11/22 +func (r *Random) GetServerNode(req *http.Request) (*define.ServerNode, error) { + r.RLock() + defer r.RUnlock() + if len(r.severList) == 0 { + return nil, errors.New("sever list is empty") + } + randomID := util.GetHashID(util.GenRandomString("", 128)) % uint64(len(r.severList)) + return r.severList[int(randomID)], nil +} diff --git a/balance/weight_serverRound_robin.go b/balance/weight_serverRound_robin.go new file mode 100644 index 0000000..0f3aa4b --- /dev/null +++ b/balance/weight_serverRound_robin.go @@ -0,0 +1,114 @@ +// Package balance... +// +// Description : balance... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 2021-11-22 6:58 下午 +package balance + +import ( + "net/http" + "sync" + + "github.com/pkg/errors" + + "git.zhangdeman.cn/zhangdeman/gopkg/balance/define" +) + +// NewWeightServerRoundRobin ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 6:58 下午 2021/11/22 +func NewWeightServerRoundRobin(severList []*define.ServerNode) (IBalance, error) { + if nil == severList || len(severList) == 0 { + return nil, errors.New("sever list is empty") + } + return &WeightServerRoundRobin{ + base: base{ + lock: &sync.RWMutex{}, + severList: severList, + }, + effectiveWeight: 0, + }, nil +} + +// WeightServerRoundRobin 加权轮询 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 6:58 下午 2021/11/22 +type WeightServerRoundRobin struct { + base + effectiveWeight float64 +} + +// GetServerNode ... +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 7:00 下午 2021/11/22 +func (w *WeightServerRoundRobin) GetServerNode(req *http.Request) (*define.ServerNode, error) { + w.RLock() + defer w.RUnlock() + if len(w.severList) == 0 { + return nil, errors.New("sever list is empty") + } + var expectBackendServer *define.ServerNode + for _, backendServer := range w.severList { + // 给每个后端服务增加自身权重 + backendServer.CurrentWeight += backendServer.Weight + if expectBackendServer == nil { + expectBackendServer = backendServer + } + if backendServer.CurrentWeight > expectBackendServer.CurrentWeight { + expectBackendServer = backendServer + } + } + // 把选择的后端服务权重减掉总权重 + expectBackendServer.CurrentWeight -= w.effectiveWeight + return expectBackendServer, nil +} + +// AddServerNode 新添加一个服务器节点 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 10:07 下午 2021/10/20 +func (w *WeightServerRoundRobin) AddServerNode(node *define.ServerNode) error { + if len(node.HostIP) == 0 || node.Port <= 0 { + return errors.New("host ip or port is invalid") + } + w.Lock() + defer w.Unlock() + for _, item := range w.severList { + if item.HostIP == node.HostIP && item.Port == node.Port { + return errors.New("host config is already exist") + } + } + w.effectiveWeight += node.Weight + w.severList = append(w.severList, node) + return nil +} + +// Remove 移除一个节点, force = true , 强制删除, force = false 逻辑删除, 设置状态 +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 10:19 下午 2021/10/20 +func (w *WeightServerRoundRobin) Remove(hostIP string, port int, force bool) { + w.Lock() + defer w.Unlock() + tmpServerNode := make([]*define.ServerNode, 0) + for _, item := range w.severList { + if item.HostIP == hostIP && item.Port == port { + if force { + continue + } + item.Status = define.ServerNodeStatusRemove + } + tmpServerNode = append(tmpServerNode, item) + } + w.severList = tmpServerNode +} diff --git a/util/ip.go b/util/ip.go index ef534be..9ae7966 100644 --- a/util/ip.go +++ b/util/ip.go @@ -7,7 +7,10 @@ // Date : 2021-03-09 5:56 下午 package util -import "net" +import ( + "net" + "net/http" +) // GetHostIP 获取本机IP地址 // @@ -27,3 +30,24 @@ func GetHostIP() string { } return hostIP } + +// GetRemoteIp 获取远端IP +// +// Author : go_developer@163.com<白茶清欢> +// +// Date : 5:35 下午 2021/11/22 +func GetRemoteIp(req *http.Request) string { + + // Try via request + + ip, _, err := net.SplitHostPort(req.RemoteAddr) + + if err != nil { + return "::1" + } + userIP := net.ParseIP(ip) + if userIP == nil { + return "::1" + } + return userIP.String() +}