服务治理【2】HTTP流量转发及负载均衡

一、启动后端服务器

代码在这篇《文章》中第一节

二、反向代理模块

utils/httputil.go( 拼接url输出正确的url )

func SingleJoiningSlash(a, b string) string {
	aslash := strings.HasSuffix(a, "/")
	bslash := strings.HasPrefix(b, "/")
	switch {
	case aslash && bslash:
		return a + b[1:]
	case !aslash && !bslash:
		return a + "/" + b
	}
	return a + b
}

proxy/lbalance/factory.go( 加载负载策略 )

type LbType int
const (
	LbRandom = iota
	LbRoundRobin
)
type LoadBalance interface {
	Add(params ...string) error
	Next() string
	Get(key string) (string, error)
}
func LoadBalanceFactory(lbtype LbType) LoadBalance {
	switch lbtype {
	case LbRandom:
		return &RandomBalance{}
	case LbRoundRobin:
		return &RoundRobinBalance{}
	default:
		return &RandomBalance{}
	}
}

proxy/lbalance/random.go( 随机负载模块 )

type RandomBalance struct {
	curIndex int
	rss      []string
}
func (r *RandomBalance) Add(params ...string) error {
	if len(params) == 0 {
		return errors.New("param len 1 at least")
	}
	r.rss = append(r.rss, params[0])
	return nil
}
func (r *RandomBalance) Next() string {
	if len(r.rss) == 0 {
		return ""
	}
	r.curIndex = rand.Intn(len(r.rss))
	return r.rss[r.curIndex]
}
func (r *RandomBalance) Get(key string) (string, error) {
	return r.Next(), nil
}

proxy/lbalance/round_robin.go( 轮询负载模块 )

type RoundRobinBalance struct {
	curIndex int
	rss      []string
}
func (r *RoundRobinBalance) Add(params ...string) error {
	if len(params) == 0 {
		return errors.New("param len 1 at least")
	}
	r.rss = append(r.rss, params[0])
	return nil
}
func (r *RoundRobinBalance) Next() string {
	if len(r.rss) == 0 {
		return ""
	}
	length := len(r.rss)
	if r.curIndex >= length {
		r.curIndex = 0
	}
	curAddr := r.rss[r.curIndex]
	r.curIndex = r.curIndex + 1
	return curAddr
}
func (r *RoundRobinBalance) Get(key string) (string, error) {
	return r.Next(), nil
}

proxy/server/server.go( 代理服务器,处理上下游请求和返回体 )

type Proxy struct {
	lb lbalance.LoadBalance
}
func (p *Proxy) director(req *http.Request) {
	hitUrl, err := p.lb.Get(req.URL.Path)
	log.Println("nextAddr: ", hitUrl)
	if err != nil {
		log.Fatal(err)
	}
	target, err := url.Parse(hitUrl)
	if err != nil {
		log.Fatal(err)
	}
	targetQuery := target.RawQuery
	req.URL.Scheme = target.Scheme
	req.URL.Host = target.Host
	req.URL.Path = utils.SingleJoiningSlash(target.Path, req.URL.Path)
	if targetQuery == "" || req.URL.RawQuery == "" {
		req.URL.RawQuery = targetQuery + req.URL.RawQuery
	} else {
		req.URL.RawQuery = targetQuery + "&" + req.URL.RawQuery
	}
	if _, ok := req.Header["User-Agent"]; !ok {
		// explicitly disable User-Agent so it's not set to default value
		req.Header.Set("User-Agent", "")
	}
}
func (p *Proxy) modifyResponse(res *http.Response) error {
	if res.StatusCode == 500 {
		data, _ := ioutil.ReadAll(res.Body)
		data = []byte("jstang " + string(data))
		res.ContentLength = int64(len(data))
		res.Header.Set("Content-Length", fmt.Sprint(len(data)))
		res.Body = ioutil.NopCloser(bytes.NewBuffer(data))
	}
	return nil
}
func (p *Proxy) NewMultiHostReverseProxy(lb lbalance.LoadBalance) (*httputil.ReverseProxy, error) {
	p.lb = lb
	reverse := &httputil.ReverseProxy{
		Director:       p.director,
		ModifyResponse: p.modifyResponse,
	}
	return reverse, nil
}

三、构建并使用流量转发中间件**

middleware/proxy_pass.go

package main
import (
	"demo/middleware"
	"demo/proxy/lbalance"
	"demo/proxy/server"
	"log"
	"net/http"
)
var (
	gateway string = "172.*.*.249:10000"
	real1   string = "http://172.*.*.249:8888"
	real2   string = "http://172.*.*.249:6666/append"
)
func main() {
	// 构建反向代理
	lb := lbalance.LoadBalanceFactory(lbalance.LbRoundRobin)
	if err := lb.Add(real1, "10"); err != nil {
		log.Fatal(err)
	}
	if err := lb.Add(real2, "20"); err != nil {
		log.Fatal(err)
	}
	proxy := &server.Proxy{}
	reverse, err := proxy.NewMultiHostReverseProxy(lb)
	if err != nil {
		log.Fatal(err)
	}

	// 构建路由
	router := middleware.NewSliceRouter()
	router.Group("/gateway").Use(middleware.TraceLogSliceMW(), func(c *middleware.SliceRouterContext) {
		c.Rw.WriteHeader(http.StatusForbidden)
		c.Rw.Write([]byte(http.StatusText(http.StatusForbidden)))
	})
	router.Group("/").Use(middleware.TraceLogSliceMW(), func(c *middleware.SliceRouterContext) {
		log.Println("Transport Forward To Backend...")
		reverse.ServeHTTP(c.Rw, c.Req)
	})
	handler := middleware.NewSliceRouterHandler(nil, router)
	log.Println("Gateway start at: ", gateway)
	log.Fatal(http.ListenAndServe(gateway, handler))
}

四、代码结构和运行结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值