Golang实现按比例切分流量的示例详解

 更新时间:2023年09月04日 10:29:43   作者:阿拉懒神灯  
我们在进行灰度发布时,往往需要转发一部分流量到新上线的服务上,进行小规模的验证,随着功能的不断完善,我们也会逐渐增加转发的流量,这就需要按比例去切分流量,那么如何实现流量切分呢,接下来小编就给大家详细的介绍一下实现方法,需要的朋友可以参考下

我们在进行灰度发布时,往往需要转发一部分流量到新上线的服务上,进行小规模的验证,随着功能的不断完善,我们也会逐渐增加转发的流量,这就需要按比例去切分流量,那么如何实现流量切分呢?

我们很容易想到通过生成随机数方式进行实现,通过判断生成随机数是否落在指定区间内,从而决定是否进行流量的转发,这种方式虽然实现很简单,但是它有两点弊端:

  • 每次都要生成新的随机数,这是有性能损耗的,尤其是并发量高的场景下更为明显;
  • 随机数的生成往往不够均匀,比如有A、B两个服务,流量比例3:7,如果使用随机数方式,如果运气不好的话有可能请求100次全落在B服务上。

那有没有性能开销又小,又能精准切分流量的方式呢?当然是有的。实现思路如下:

  • 确定比例,并根据比例得到一个基数base,例如比例是3:7,那么基数就是10;
  • 生成长度为基数base的数组source,并填充数据0、1、2、3、4、5...;
  • 打乱数组source中元素顺序;
  • 创建全局计数器queryCount,每次有请求时加1(确保原子性);
  • 计算计数器queryCount与base取余后的值rate,并得到数组中对应位置的值source[rate];
  • 判断source[rate]落在哪个区间。

看文字可能觉得理解起来有些别扭,这里贴上完整代码:

import (  "fmt"  "math/rand"  "sync/atomic")
type TrafficControl struct {  
    source     []int  
    queryCount uint32  
    base       int  
    ratio      int
}
func NewTrafficControl(base int, ratio int) *TrafficControl {  
    source := make([]int, base)  
    for i := 0; i < base; i++ {    
        source[i] = i  
    }
    rand.Shuffle(base, func(i, j int) {    
        source[i], source[j] = source[j], source[i]  
    })
    return &TrafficControl{    
        source: source,    
        base:   base,    
        ratio:  ratio,  
    }
}
func (t *TrafficControl) Allow() bool {  
    rate := t.source[int(atomic.AddUint32(&t.queryCount, 1))%t.base]  
    if rate < t.ratio {    
        return true  
    } else {    
        return false  
    }
}

接下来我们检测下这段代码是否真的能精准切分流量:

func main() {  
    trafficCtl := NewTrafficControl(10, 6)  
    cnt := 100  
    serviceAQueryCnt := 0  
    serviceBQueryCnt := 0  
    for cnt > 0 {    
        if trafficCtl.Allow() {      
            serviceAQueryCnt++    
        } else {      
            serviceBQueryCnt++    
        }    
        cnt--  
    }
    fmt.Printf("service A query count: %v, service B query count %v", serviceAQueryCnt, serviceBQueryCnt)
}

执行结果如下:

service A query count: 60, service B query count 40

其实思路很简单:通过请求数与基数取余,确保在一定范围内总能按比例 实现流量切分;通过打乱数组确保流量分布尽可能均匀。当然流量切分还有其他实现方式,如果大家有更精妙的实现,欢迎评论区留言哈。

到此这篇关于Golang实现按比例切分流量的示例详解的文章就介绍到这了,更多相关Golang按比例切分流量内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Go语言中函数可变参数(Variadic Parameter)详解

    Go语言中函数可变参数(Variadic Parameter)详解

    在Python中,在函数参数不确定数量的情况下,可以动态在函数内获取参数。在Go语言中,也有类似的实现方式,本文就来为大家详细讲解一下
    2022-07-07
  • Golang利用Template模板动态生成文本

    Golang利用Template模板动态生成文本

    Go语言中的Go Template是一种用于生成文本输出的简单而强大的模板引擎,它提供了一种灵活的方式来生成各种格式的文本,下面我们就来看看具体如何使用Template实现动态文本生成吧
    2023-09-09
  • Go 语言结构体链表的基本操作

    Go 语言结构体链表的基本操作

    链表是一种物理存储单元上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的,这篇文章主要介绍了Go 语言结构体链表,需要的朋友可以参考下
    2022-04-04
  • GoLang channel使用介绍

    GoLang channel使用介绍

    Channel 和 goroutine 的结合是 Go 并发编程的大杀器。而 Channel 的实际应用也经常让人眼前一亮,通过与 select,cancel,timer 等结合,它能实现各种各样的功能。接下来,我们就要梳理一下 channel 的应用
    2022-10-10
  • Go利用ffmpeg进行视频和音频处理

    Go利用ffmpeg进行视频和音频处理

    ffmpeg 是一款功能强大的多媒体处理工具,支持视频和音频的编码、解码、转码,以及帧提取和流处理等功能,下面我们就来看看Go如何利用ffmpeg进行视频和音频处理吧
    2024-12-12
  • Golang中interface的基本用法详解

    Golang中interface的基本用法详解

    Go 中接口也是一个使用得非常频繁的特性,好的软件设计往往离不开接口的使用,比如依赖倒置原则(通过抽象出接口,分离了具体实现与实际使用的耦合)。 今天,就让我们来了解一下 Go 中接口的一些基本用法
    2023-01-01
  • Go 在 MongoDB 中常用查询与修改的操作

    Go 在 MongoDB 中常用查询与修改的操作

    这篇文章主要介绍了Go 在 MongoDB 中常用查询与修改的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-05-05
  • 利用go语言实现Git 重命名远程分支  

    利用go语言实现Git 重命名远程分支  

    这篇文章主要介绍了go语言实现Git 重命名远程分支,文章基于go语言的基础展开Git 重命名远程分支的实现过程,需要的小伙伴可以参考一下,希望对你的学习有所帮助
    2022-06-06
  • Go语言数据结构之二叉树必会知识点总结

    Go语言数据结构之二叉树必会知识点总结

    如果你是一个开发人员,或多或少对树型结构都有一定的认识。二叉树作为树的一种,是一种重要的数据结构,也是面试官经常考的东西。本文为大家总结了一些二叉树必会知识点,需要的可以参考一下
    2022-08-08
  • go语言学习之包和变量详解

    go语言学习之包和变量详解

    这篇文章主要给大家爱介绍了关于go语言学习之包和变量的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用go语言具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-06-06

最新评论