Golang优雅实现按比例切分流量

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

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

  • 每次都要生成新的随机数,这是有性能损耗的,尤其是并发量高的场景下更为明显;
  • 随机数的生成往往不够均匀,比如有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]落在哪个区间。

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

python 复制代码
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  
    }
}

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

python 复制代码
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

其实思路很简单:通过请求数与基数取余,确保在一定范围内总能按比例 实现流量切分;通过打乱数组确保流量分布尽可能均匀

相关推荐
XiaoYu20023 分钟前
第1章 核心竞争力和职业规划
前端·面试·程序员
excel8 分钟前
🧩 深入浅出讲解:analyzeScriptBindings —— Vue 如何分析 <script> 里的变量绑定
前端
蓝瑟11 分钟前
AI时代程序员如何高效提问与开发工作?
前端·ai编程
微露清风12 分钟前
系统性学习C++-第十讲-stack 和 quene
java·c++·学习
一蓑烟雨任平生√16 分钟前
两种上传图片的方式——91张先生
java·ossinsight
凤凰战士芭比Q30 分钟前
部署我的世界-java版服务器-frp内网穿透
java·服务器
小肖爱笑不爱笑31 分钟前
2025/11/5 IO流(字节流、字符流、字节缓冲流、字符缓冲流) 计算机存储规则(ASCII、GBK、Unicode)
java·开发语言·算法
林晓lx40 分钟前
使用Git钩子+ husky + lint语法检查提高前端项目代码质量
前端·git·gitlab·源代码管理
CodeCraft Studio42 分钟前
PPT处理控件Aspose.Slides教程:使用Java将PowerPoint笔记导出为PDF
java·笔记·pdf·powerpoint·aspose·ppt转pdf·java将ppt导出pdf
手握风云-44 分钟前
Java 数据结构第二十八期:反射、枚举以及 lambda 表达式
java·开发语言