一、构建两个应用服
9091 和 9092端口
package main
import (
"encoding/base64"
"log"
"net/http"
"os"
"os/signal"
"strings"
)
type web1handler struct {}
func(web1handler) ServeHTTP (writer http.ResponseWriter,request *http.Request) {
//请求头是否有给到 Authorization 信息
auth := request.Header.Get("Authorization")
if auth == "" {
writer.Header().Set("WWW-Authenticate",`Basic realm="您必须输入用户名和密码"`)
writer.WriteHeader(http.StatusUnauthorized)
return
}
// auth中取出用户和密码信息 "Basic xxxxxx="
auth_list := strings.Split(auth," ") //将字符串分割
if len(auth_list) == 2 && auth_list[0] == "Basic" {
res,err := base64.StdEncoding.DecodeString(auth_list[1]) //base64解码
if err == nil && string(res) == "leo:123" {
writer.Write([]byte("<h1>web1</h1>"))
return
}
}
writer.Write([]byte("用户名和密码错误"))
}
type web2handler struct {}
func(web2handler) ServeHTTP(writer http.ResponseWriter,request *http.Request) {
writer.Write([]byte("web2"))
}
func main() {
c := make(chan os.Signal)
go func() {
http.ListenAndServe(":9091",web1handler{})
}()
go func() {
http.ListenAndServe(":9092",web2handler{})
}()
signal.Notify(c,os.Interrupt)
s := <-c
log.Println(s)
}
二、代理服网关代码
1.定义下游服务列表的获取,负载均衡算法 /proxy/util/util.go
注意:LB.AddServer(NewHttpServer("http://localhost:9091",5)) ,下游服的ip地址+端口根据实际的下游服务定义。实际项目中获取下游应用服信息是需要去 服务注册与发现中获取到能调用的应用服列表元数据,将元数据再从列表中根据算法来做到负载。或者就用服务注册与发现的负载算法获取到一个可调用的应用服元数据直接进行代理访问。
package util
import (
"fmt"
"hash/crc32"
"math/rand"
"time"
)
var LB *LoadBalance
var ServerIndices []int
func init() {
LB = NewLoadBalance()
LB.AddServer(NewHttpServer("http://localhost:9091",5))
LB.AddServer(NewHttpServer("http://localhost:9092",15))
for index,server := range LB.Servers {
if server.Weight > 0 {
for i:=0;i<server.Weight;i++{
ServerIndices = append(ServerIndices,index)
}
}
}
fmt.Println(ServerIndices)
}
//HttpServer 目标server类
type HttpServer struct {
Host string
Weight int
}
// NewHttpServer 生成一个目标server类
func NewHttpServer(host string,weight int) *HttpServer {
return &HttpServer{Host:host,Weight: weight}
}
//LoadBalance 负载均衡类
type LoadBalance struct {
Servers []*HttpServer //应用服列表
CurIndex int //当前访问的目标应用服
}
func NewLoadBalance() *LoadBalance {
return &LoadBalance{Servers: make([]*HttpServer,0)}
}
// AddServer 添加一个目标server类
func (this *LoadBalance) AddServer(server *HttpServer) {
this.Servers = append(this.Servers,server)
}
// SelectByRand 随机(负载分发规则)
func(this *LoadBalance)SelectByRand() *HttpServer {
rand.Seed(time.Now().UnixNano()) //随机种子
index := rand.Intn(len(this.Servers)) //servers长度
return this.Servers[index]
}
// SelectByWeightRand 随机加权(负载分发规则)
func(this *LoadBalance)SelectByWeightRand() *HttpServer {
rand.Seed(time.Now().UnixNano()) //随机种子
index := rand.Intn(len(ServerIndices)) //ServerIndices切片里随机取到一个key
return this.Servers[ServerIndices[index]]
}
// SelectByWeightRand2 升级版-随机加权(负载分发规则)
func(this *LoadBalance)SelectByWeightRand2() *HttpServer {
rand.Seed(time.Now().UnixNano()) //随机种子
sumList := make([]int,len(this.Servers))
sum := 0
for i := 0; i < len(this.Servers); i++ {
sum += this.Servers[i].Weight
sumList[i]=sum
}
rad := rand.Intn(sum)
for index,value := range sumList {
if rad < value {
return this.Servers[index]
}
}
return this.Servers[0] //不会执行到这一步
}
// SelectByIpHASH hash(负载分发规则)
func(this *LoadBalance)SelectByIpHASH(ip string) *HttpServer {
//将ip用hash算法转化为int32,转int取模 下游服务器台数,则根据客户端ip固定访问某台应用服
index := int(crc32.ChecksumIEEE([]byte(ip))) % len(this.Servers)
return this.Servers[index]
}
// RoundRobin 简单轮询算法 (负载分发规则)
func(this *LoadBalance) RoundRobin() *HttpServer{
server := this.Servers[this.CurIndex]
this.CurIndex = (this.CurIndex+1)%len(this.Servers)
CurIndex 指到下一个应用服
//this.CurIndex++
如果超出边界,则调整到开始位置
//if this.CurIndex >= len(this.Servers) {
// this.CurIndex = 0
//}
return server
}
// RoundRobinByWeight 加权轮询算法 (负载分发规则)
func(this *LoadBalance) RoundRobinByWeight() *HttpServer{
server := this.Servers[ServerIndices[this.CurIndex]]
this.CurIndex = (this.CurIndex+1)%len(this.Servers)
return server
}
2.main包中,获取下游应用服地址,根据算法选一个调用。/proxy/myproxy/main.go
package main
import (
"go_code/proxy/util"
"log"
"net/http"
"net/http/httputil"
"net/url"
)
type ProxyHandler struct {}
func (* ProxyHandler) ServeHTTP(w http.ResponseWriter,r *http.Request) {
defer func() {
if err := recover(); err != nil {
w.WriteHeader(500)
log.Println(err)
}
}()
lb := util.LB
//serveUrl,_ := url.Parse(lb.SelectByRand().Host) //随机算
serveUrl,_ := url.Parse(lb.SelectByWeightRand().Host) //加权随机算
//serveUrl,_ := url.Parse(lb.SelectByIpHASH(r.RemoteAddr).Host) //hash算法
proxy := httputil.NewSingleHostReverseProxy(serveUrl) //获得代理对象
proxy.ServeHTTP(w,r) //处理请求和返回
}
func main() {
http.ListenAndServe(":8080",&ProxyHandler{})
}