【微服务网关——负载均衡】

1. 四大负载均衡策略

  • 随机负载
    • 随机挑选目标服务器IP
  • 轮询负载
    • ABC三台服务器,ABCABC依次轮询
  • 加权负载
    • 给目标设置访问权重,按照权重轮询
  • 一致性hash负载
    • 请求固定URL访问指定IP

2.随机负载均衡

可以通过random函数来随机选择一个ip

2.1 代码实现

type RandomBalance struct {curIndex intrss      []string
}func (r *RandomBalance) Add(params ...string) error {if len(params) == 0 {return errors.New("param len 1 at least")}addr := params[0]r.rss = append(r.rss, addr)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
}

2.2 测试代码

package load_balanceimport ("fmt""testing"
)func TestRandomBalance(t *testing.T) {rb := &RandomBalance{}rb.Add("127.0.0.1:2003") //0rb.Add("127.0.0.1:2004") //1rb.Add("127.0.0.1:2005") //2rb.Add("127.0.0.1:2006") //3rb.Add("127.0.0.1:2007") //4fmt.Println(rb.Next())fmt.Println(rb.Next())fmt.Println(rb.Next())fmt.Println(rb.Next())fmt.Println(rb.Next())fmt.Println(rb.Next())fmt.Println(rb.Next())fmt.Println(rb.Next())fmt.Println(rb.Next())
}

2.3 测试结果

在这里插入图片描述

3.轮询负载均衡

按一定顺序进行轮询

3.1 代码实现

type RoundRobinBalance struct {curIndex intrss      []string
}func (r *RoundRobinBalance) Add(params ...string) error {if len(params) == 0 {return errors.New("param len 1 at least")}addr := params[0]r.rss = append(r.rss, addr)return nil
}func (r *RoundRobinBalance) Next() string {if len(r.rss) == 0 {return ""}lens := len(r.rss) //5if r.curIndex >= lens {r.curIndex = 0}curAddr := r.rss[r.curIndex]// 这里是轮询实现的重点r.curIndex = (r.curIndex + 1) % lensreturn curAddr
}func (r *RoundRobinBalance) Get(key string) (string, error) {return r.Next(), nil
}

3.2 测试代码

package load_balanceimport ("fmt""testing"
)func Test_main(t *testing.T) {rb := &RoundRobinBalance{}rb.Add("127.0.0.1:2003") //0rb.Add("127.0.0.1:2004") //1rb.Add("127.0.0.1:2005") //2rb.Add("127.0.0.1:2006") //3rb.Add("127.0.0.1:2007") //4fmt.Println(rb.Next())fmt.Println(rb.Next())fmt.Println(rb.Next())fmt.Println(rb.Next())fmt.Println(rb.Next())fmt.Println(rb.Next())fmt.Println(rb.Next())fmt.Println(rb.Next())fmt.Println(rb.Next())
}

3.3 测试结果

在这里插入图片描述

4.加权负载均衡

  • Weight
    • 初始化时对节点约定的权重
  • currentWeight
    • 节点的临时权重,每轮都会变化
  • effectiveWeight
    • 节点有效权重,默认与Weight相同
    • 当发生故障时,effectiveWeight会减少
  • totalWeight
    • 所有节点有效权重之和:sum(effectiveWeight)

根据不同的权重给于不同的概率,权重往往与地域、服务器的性能相关。
在这里插入图片描述

4.1 代码实现

type WeightRoundRobinBalance struct {curIndex intrss      []*WeightNodersw      []int
}type WeightNode struct {addr            stringweight          int //权重值currentWeight   int //节点当前权重effectiveWeight int //有效权重
}func (r *WeightRoundRobinBalance) Add(params ...string) error {if len(params) != 2 {return errors.New("param len need 2")}parInt, err := strconv.ParseInt(params[1], 10, 64)if err != nil {return err}node := &WeightNode{addr: params[0], weight: int(parInt)}node.effectiveWeight = node.weightr.rss = append(r.rss, node)return nil
}func (r *WeightRoundRobinBalance) Next() string {total := 0var best *WeightNodefor i := 0; i < len(r.rss); i++ {w := r.rss[i]//step 1 统计所有有效权重之和total += w.effectiveWeight//step 2 变更节点临时权重为的节点临时权重+节点有效权重w.currentWeight += w.effectiveWeight//step 3 有效权重默认与权重相同,通讯异常时-1, 通讯成功+1,直到恢复到weight大小if w.effectiveWeight < w.weight {w.effectiveWeight++}//step 4 选择最大临时权重点节点if best == nil || w.currentWeight > best.currentWeight {best = w}}if best == nil {return ""}//step 5 变更临时权重为 临时权重-有效权重之和best.currentWeight -= totalreturn best.addr
}func (r *WeightRoundRobinBalance) Get(key string) (string, error) {return r.Next(), nil
}

4.2 测试代码

func TestLB(t *testing.T) {rb := &WeightRoundRobinBalance{}rb.Add("127.0.0.1:2003", "4") //0rb.Add("127.0.0.1:2004", "3") //1rb.Add("127.0.0.1:2005", "2") //2fmt.Println(rb.Next())fmt.Println(rb.Next())fmt.Println(rb.Next())fmt.Println(rb.Next())fmt.Println(rb.Next())fmt.Println(rb.Next())fmt.Println(rb.Next())fmt.Println(rb.Next())fmt.Println(rb.Next())fmt.Println(rb.Next())fmt.Println(rb.Next())fmt.Println(rb.Next())fmt.Println(rb.Next())fmt.Println(rb.Next())
}

4.3 测试结果

在这里插入图片描述

5.一致性负载均衡

  • 一致性Hash指标
    • 单调性
    • 平衡性
    • 分散性

链接: 一致性负载均衡理论介绍

5.1 代码实现

package load_balanceimport ("errors""fmt""hash/crc32""sort""strconv""strings""sync"
)type Hash func(data []byte) uint32type UInt32Slice []uint32func (s UInt32Slice) Len() int {return len(s)
}func (s UInt32Slice) Less(i, j int) bool {return s[i] < s[j]
}func (s UInt32Slice) Swap(i, j int) {s[i], s[j] = s[j], s[i]
}type ConsistentHashBanlance struct {mux      sync.RWMutexhash     Hashreplicas int               //复制因子keys     UInt32Slice       //已排序的节点hash切片hashMap  map[uint32]string //节点哈希和Key的map,键是hash值,值是节点key
}func NewConsistentHashBanlance(replicas int, fn Hash) *ConsistentHashBanlance {m := &ConsistentHashBanlance{replicas: replicas,hash:     fn,hashMap:  make(map[uint32]string),}if m.hash == nil {//最多32位,保证是一个2^32-1环m.hash = crc32.ChecksumIEEE}return m
}// 验证是否为空
func (c *ConsistentHashBanlance) IsEmpty() bool {return len(c.keys) == 0
}// Add 方法用来添加缓存节点,参数为节点key,比如使用IP
func (c *ConsistentHashBanlance) Add(params ...string) error {if len(params) == 0 {return errors.New("param len 1 at least")}addr := params[0]c.mux.Lock()defer c.mux.Unlock()// 结合复制因子计算所有虚拟节点的hash值,并存入m.keys中,同时在m.hashMap中保存哈希值和key的映射for i := 0; i < c.replicas; i++ {hash := c.hash([]byte(strconv.Itoa(i) + addr))c.keys = append(c.keys, hash)c.hashMap[hash] = addr}// 对所有虚拟节点的哈希值进行排序,方便之后进行二分查找sort.Sort(c.keys)return nil
}// Get 方法根据给定的对象获取最靠近它的那个节点
func (c *ConsistentHashBanlance) Get(key string) (string, error) {if c.IsEmpty() {return "", errors.New("node is empty")}hash := c.hash([]byte(key))// 通过二分查找获取最优节点,第一个"服务器hash"值大于"数据hash"值的就是最优"服务器节点"idx := sort.Search(len(c.keys), func(i int) bool { return c.keys[i] >= hash })// 如果查找结果 大于 服务器节点哈希数组的最大索引,表示此时该对象哈希值位于最后一个节点之后,那么放入第一个节点中if idx == len(c.keys) {idx = 0}c.mux.RLock()defer c.mux.RUnlock()return c.hashMap[c.keys[idx]], nil
}

5.2 测试代码

package load_balanceimport ("fmt""testing"
)func TestNewConsistentHashBanlance(t *testing.T) {rb := NewConsistentHashBanlance(10, nil)rb.Add("127.0.0.1:2003") //0rb.Add("127.0.0.1:2004") //1rb.Add("127.0.0.1:2005") //2rb.Add("127.0.0.1:2006") //3rb.Add("127.0.0.1:2007") //4//url hashfmt.Println(rb.Get("http://127.0.0.1:2002/base/getinfo"))fmt.Println(rb.Get("http://127.0.0.1:2002/base/error"))fmt.Println(rb.Get("http://127.0.0.1:2002/base/getinfo"))fmt.Println(rb.Get("http://127.0.0.1:2002/base/changepwd"))//ip hashfmt.Println(rb.Get("127.0.0.1"))fmt.Println(rb.Get("192.168.0.1"))fmt.Println(rb.Get("127.0.0.1"))
}

5.3 测试结果

在这里插入图片描述

6.为代理添加负载均衡

package mainimport ("bytes""github.com/e421083458/gateway_demo/proxy/load_balance""io/ioutil""log""net""net/http""net/http/httputil""net/url""strconv""strings""time"
)var (addr      = "127.0.0.1:2002"transport = &http.Transport{DialContext: (&net.Dialer{Timeout:   30 * time.Second, //连接超时KeepAlive: 30 * time.Second, //长连接超时时间}).DialContext,MaxIdleConns:          100,              //最大空闲连接IdleConnTimeout:       90 * time.Second, //空闲超时时间TLSHandshakeTimeout:   10 * time.Second, //tls握手超时时间ExpectContinueTimeout: 1 * time.Second,  //100-continue状态码超时时间}
)func NewMultipleHostsReverseProxy(lb load_balance.LoadBalance) *httputil.ReverseProxy {// 请求协调者director := func(req *http.Request) {// 获取请求者的req.RemoteAddr,根据这个获得下游ipnextAddr, err := lb.Get(req.RemoteAddr)if err != nil {log.Fatal("get next addr fail")}target, err := url.Parse(nextAddr)if err != nil {log.Fatal(err)}targetQuery := target.RawQueryreq.URL.Scheme = target.Schemereq.URL.Host = target.Hostreq.URL.Path = 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 {req.Header.Set("User-Agent", "user-agent")}}//更改内容modifyFunc := func(resp *http.Response) error {//请求以下命令:curl 'http://127.0.0.1:2002/error'if resp.StatusCode != 200 {//获取内容oldPayload, err := ioutil.ReadAll(resp.Body)if err != nil {return err}//追加内容newPayload := []byte("StatusCode error:" + string(oldPayload))resp.Body = ioutil.NopCloser(bytes.NewBuffer(newPayload))resp.ContentLength = int64(len(newPayload))resp.Header.Set("Content-Length", strconv.FormatInt(int64(len(newPayload)), 10))}return nil}//错误回调 :关闭real_server时测试,错误回调//范围:transport.RoundTrip发生的错误、以及ModifyResponse发生的错误errFunc := func(w http.ResponseWriter, r *http.Request, err error) {//todo 如果是权重的负载则调整临时权重http.Error(w, "ErrorHandler error:"+err.Error(), 500)}return &httputil.ReverseProxy{Director: director, Transport: transport, ModifyResponse: modifyFunc, ErrorHandler: errFunc}
}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
}func main() {rb := load_balance.LoadBanlanceFactory(load_balance.LbWeightRoundRobin)if err := rb.Add("http://127.0.0.1:2003/base", "10"); err != nil {log.Println(err)}if err := rb.Add("http://127.0.0.1:2004/base", "20"); err != nil {log.Println(err)}proxy := NewMultipleHostsReverseProxy(rb)log.Println("Starting httpserver at " + addr)log.Fatal(http.ListenAndServe(addr, proxy))
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/29912.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

陶建辉入选 2023 年度“中国物联网行业卓越人物榜”

在这个技术飞速发展的时代&#xff0c;物联网行业作为推动社会进步的重要力量&#xff0c;正在不断地演化和革新。近日&#xff0c;中国智联网生态大会暨“2023 物联之星”年度榜单颁奖典礼在上海浦东举行。现场公布了拥有物联网行业奥斯卡奖之称的 ——“物联之星 2023 中国物…

「51媒体」上海电视台媒体邀约专访怎么做?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 电视台专访通常会对一些热门话题&#xff0c;行业热点&#xff0c;或者新闻焦点&#xff0c;邀请嘉宾进行访谈。企业如果想要在电视台进行专访&#xff0c;通常要有合适的时机和选题。 下…

【面试干货】Java方法重写的规则

【面试干货】Java方法重写的规则 1、Java方法重写的规则2、示例代码3、总结 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在Java中&#xff0c;方法重写&#xff08;Overriding&#xff09;是面向对象编程中的一个核心概念&#xff0c;它…

结硬寨:联想服务器的向前之路

曾国藩曾经将自己的战略思想&#xff0c;总结为“结硬寨&#xff0c;打呆仗”。 这种稳健的策略&#xff0c;往往在真实的产业发展中能收获奇效。我们喜欢听颠覆性的产业创新&#xff0c;却往往忽视稳扎稳打&#xff0c;把每一个优势聚集起来形成整体优势&#xff0c;可能才是市…

在Python项目中自定义日志工具

在Python项目中自定义日志工具 日志记录是软件开发中的一个关键部分&#xff0c;它可以帮助开发人员调试代码、监控运行状况以及记录重要事件。在Python中&#xff0c;logging 模块提供了强大的日志记录功能。本文将介绍如何创建一个日志工具&#xff0c;使其能够同时将日志输…

【ajax基础02】URL详解

目录 一&#xff1a;什么是URL 二&#xff1a;URL组成 协议 ​编辑 域名&#xff08;在url中必须写&#xff09; 资源路径 三&#xff1a;URL查询参数 定义&#xff1a; 语法格式&#xff1a; 如何利用axios实现特定数据查询&#xff1a; 语法格式: 案例&#xff1a…

【耐水好】强耐水UV胶水它的粘接强度和普通UV胶水比如何呢

【耐水好】强耐水UV胶水它的粘接强度和普通UV胶水比如何呢 强耐水UV胶水的粘接强度与普通UV胶水相比&#xff0c;具有显著的优势。以下是详细的比较和归纳&#xff1a; 固化方式&#xff1a; 两者都是通过紫外线&#xff08;UV&#xff09;照射进行固化&#xff0c;但强耐水UV…

2024年全球架构师峰会(ArchSummit深圳站)

前言 ArchSummit全球架构师峰会是极客邦科技旗下InfoQ中国团队推出的重点面向高端技术管理者、架构师的技术会议&#xff0c;54%参会者拥有8年以上工作经验。 ArchSummit聚焦业界强大的技术成果&#xff0c;秉承“实践第一、案例为主”的原则&#xff0c;展示先进技术在行业中的…

程序员学CFA——经济学(三)

经济学&#xff08;三&#xff09; 总产出、价格水平和经济增长总产出、总收入和总支出总产出、总收入和总支出的概念及联系国内生产总值国内生产总值&#xff08;GDP&#xff09;的定义GDP的衡量方法GDP的相关概念GDP的核算方法 总需求、总供给和市场均衡总需求总需求及其假设…

Netty中Reactor线程的运行逻辑

Netty中的Reactor线程主要干三件事情&#xff1a; 轮询注册在Reactor上的所有Channel感兴趣的IO就绪事件。 处理Channel上的IO就绪事件。 执行Netty中的异步任务。 正是这三个部分组成了Reactor的运行框架&#xff0c;那么我们现在来看下这个运行框架具体是怎么运转的~~ 这…

设计模式-结构型-06-桥接模式

1、传统方式解决手机操作问题 现在对不同手机类型的不同品牌实现操作编程&#xff08;比如&#xff1a;开机、关机、上网&#xff0c;打电话等&#xff09;&#xff0c;如图&#xff1a; UML 类图 问题分析 扩展性问题&#xff08;类爆炸&#xff09;&#xff1a;如果我们再…

Zygote进程的理解

Zygote进程是安卓系统的一个重要进程&#xff0c;由init进程创建而来&#xff1b;另外系统里的重要进程&#xff08;system_server等&#xff09;都是由zygote进程fork的&#xff0c;所有的app进程也是由zygote进程fork的。 一、C 里的fork函数 fork是Linux里面创建子进程的函…

电池荷电状态估计SOC?电池管理系统

一、背景 电池荷电状态&#xff08;SOC, State of Charge&#xff09;估计是电池管理系统&#xff08;BMS, Battery Management System&#xff09;的关键功能之一&#xff0c;对于确保电池的安全高效运行至关重要&#xff0c;特别是在电动车、储能系统以及便携式电子设备等领…

LCL滤波器并网逆变器双闭环控制系统仿真

并网逆变器通常采用L滤波器&#xff0c;虽然结构和控制简单&#xff0c;但是随着功率级别的增加&#xff0c;体积重量增大等问题也日益突出。为了解决这个问题&#xff0c;人们开始使用LCL滤波器&#xff0c;这种滤波器在功率较大的场合表现出色。 无源滤波器&#xff0c;又称…

神经网络模型---ResNet

一、ResNet 1.导入包 import tensorflow as tf from tensorflow.keras import layers, models, datasets, optimizersoptimizers是用于更新模型参数以最小化损失函数的算法 2.加载数据集、归一化、转为独热编码的内容一致 3.增加颜色通道 train_images train_images[...,…

Linux 系统图像化编程GTK入门

环境前期准备 演示环境&#xff1a;Windows 11 Ubuntu 22.04.4 VS Code 前提条件&#xff1a;1、Windows 11 子系统Ubuntu 22.04.4 已经安装图形化界面&#xff0c;如果没有安装请参考文章&#xff1a; windows11子系统Ubuntu 22.04.4子安装图形化界面 2、Ubuntu 22.04.4…

C语言笔记第16篇:编译和链接

1、翻译环境和运行环境 在ANSI C的任何一种实现中&#xff0c;存在两个不同的环境。 第1种是翻译环境&#xff0c;在这个环境中源代码被转换为可执行机器指令&#xff08;二进制指令&#xff09; 第2种是执行环境&#xff0c;它用于实际执行代码 2、翻译环境 那翻译环境是怎…

数据资产管理的未来趋势:洞察技术前沿,探讨数据资产管理在云计算、大数据、区块链等新技术下的发展趋势

一、引言 随着信息技术的飞速发展&#xff0c;数据已成为企业最重要的资产之一。数据资产管理作为企业核心竞争力的关键组成部分&#xff0c;其发展趋势和技术创新受到了广泛关注。特别是在云计算、大数据、区块链等新技术不断涌现的背景下&#xff0c;数据资产管理面临着前所…

【凤凰房产-注册安全分析报告-缺少轨迹的滑动条】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 1. 暴力破解密码&#xff0c;造成用户信息泄露 2. 短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉 3. 带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造…

2024 端午节巽寮湾游玩记录

2024 端午节巽寮湾游玩记录 文章目录 2024 端午节巽寮湾游玩记录一、前言二、巽寮湾游玩行程1、三天衣食住行2、主要图片&#xff1a; 三、其他1、小结2、巽寮湾游玩建议3、感慨 一、前言 时间总是过得很快&#xff0c;只要你活着时间就会不停往前走。 所以你以后的路其实都是…