小米商城服务治理之客户端熔断器(Google SRE客户端熔断器)
目录
前言
一、什么是Google SRE熔断器
二、Google SRE 熔断器的工作流程:
三、客户端熔断器 (google SRE 熔断器) golang GRPC 实现
四、客户端熔断器 (google SRE 熔断器) golang GRPC单元测试
大家可以关注个人博客:xingxing – Web Developer from Somewhere 有关后端问题探讨
前言
当某个用户超过资源配额时,后端任务应该迅速拒绝该请求,返回一个“用户配额不足”类型的错误,该回复应该比真正处理该请求所消耗的资源少得多。然而,这种逻辑其实不适用于所有请求。例如,拒绝一个执行简单内存查询的请求可能跟实际执行该请求消耗内存差不多(因为这里主要的消耗是在应用层协议解析中,结果的产生部分很简单)。
就算在某些情况下,拒绝请求可以节省大量资源,发送这些拒绝回复仍然会消耗一定数量的资源。如果拒绝回复的数量也很多,这些资源消耗可能也十分可观。在这种情况下,有可能该后端在忙着不停地发送拒绝回复时一样会进人过载状态。
那么客户端截流机制就可以解决这个问题,也就是Google SRE
一、什么是Google SRE熔断器
是否可以做到在熔断器 Open 状态下(但是后端未 Shutdown)仍然可以放行少部分流量呢?Google SRE 熔断器提供了一种算法:客户端自适应限流(client-side throttling)。
解决的办法就是客户端自行限制请求速度,限制生成请求的数量,超过这个数量的请求直接在本地回复失败,而不会真正发送到服务端。
该算法统计的指标依赖如下两种,每个客户端记录过去两分钟内的以下信息(一般代码中以滑动窗口实现)。
-
requests:客户端请求总量
-
注:The number of requests attempted by the application layer(at the client, on top of the adaptive throttling system)
-
-
accepts:成功的请求总量 - 被 accepted 的量
-
注:The number of requests accepted by the backend
-
二、Google SRE 熔断器的工作流程:
-
在通常情况下(无错误发生时) requests == accepts ;
-
当后端出现异常情况时,accepts 的数量会逐渐小于 requests;
-
当后端持续异常时,客户端可以继续发送请求直到 requests = K∗accepts,一旦超过这个值,客户端就启动自适应限流机制,新产生的请求在本地会被概率(以下称为p)丢弃;
-
当客户端主动丢弃请求时,requests 值会一直增大,在某个时间点会超过 K∗accepts,使 p 计算出来的值大于 0,此时客户端会以此概率对请求做主动丢弃;
-
当后端逐渐恢复时,accepts 增加,(同时 requests 值也会增加,但是由于 K 的关系,K*accepts的放大倍数更快),使得 (requests − K×accepts) / (requests + 1) 变为负数,从而 p == 0,客户端自适应限流结束。
客户端请求被拒绝的概率(Client request rejection probability,以下简称为 p)
p 基于如下公式计算(其中 K 为倍率 - multiplier,常用的值为 2)。

-
当 requests − K∗accepts <= 0 时,p == 0,客户端不会主动丢弃请求;
-
反之, p 会随着 accepts 值的变小而增加,即成功接受的请求数越少,本地丢弃请求的概率就越高。
客户端可以发送请求直到 requests = K∗accepts, 一旦超过限制, 按照 p 进行截流。
对于后端而言,调整 K 值可以使得自适应限流算法适配不同的服务场景
-
降低 K 值会使自适应限流算法更加激进(允许客户端在算法启动时拒绝更多本地请求);
-
增加 K 值会使自适应限流算法变得保守一些(允许服务端在算法启动时尝试接收更多的请求,与上面相反)。

熔断本质上是一种快速失败策略。旨在通过及时中断失败或超时的操作,防止资源过度消耗和请求堆积,从而避免服务因小问题而引发的雪崩效应。
三、客户端熔断器 (google SRE 熔断器) golang GRPC 实现
我们要考虑几个问题,第一个问题用哪种算法去做统计呢,我感觉用滑动窗口去统计比较合适,因为滑动窗口是统计一个周期内的请求以及响应.用户的响应也是随着周期性的变化的,这样就可以周期性的统计。
第二个问题是此算法在什么时候执行呢,就拿GRPC 来说,当然是拦截器呢,在发送后端服务请求的时候前就要去看是否要熔断,避免错误的请求发送到后端。
type googleSlide struct {sreSlide *list.List//滑动窗口大小interval int64mutex sync.Mutex//客户端成功请求量的系数k float64
}type slideVal struct {//客户端请求时间time int64//客户端的总请求量req float64//客户端成功请求量accept float64
}type SlideValOptions func(val *slideVal)func NewSlideval(options ...SlideValOptions) *slideVal {t := &slideVal{time: time.Now().UnixNano(),}for _, option := range options {option(t)}return t
}func WithReqOption(req float64) SlideValOptions {return func(val *slideVal) {val.req = req}
}func WithAcceptReqOption(accept float64) SlideValOptions {return func(val *slideVal) {val.accept = accept}
}func NewGoogleSlide(interval time.Duration, k float64) *googleSlide {return &googleSlide{sreSlide: list.New(),interval: interval.Nanoseconds(),k: k,}
}func (g *googleSlide) Sre() grpc.UnaryClientInterceptor {return func(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {g.mutex.Lock()now := time.Now().UnixNano()front := g.sreSlide.Front()//调整滑动窗口for front != nil && front.Value.(*slideVal).time+g.interval < now {g.sreSlide.Remove(front)front = g.sreSlide.Front()}var r, accept float64front = g.sreSlide.Front()//当前滑动窗口下的请求和成功请求量的统计for front != nil {t := front.Value.(*slideVal)r += t.reqaccept += t.acceptfront = front.Next()}//客户端请求被拒绝的概率((requests − K×accepts) / (requests + 1))tail := (r - g.k*accept) / (r + 1)if tail > 0 {g.mutex.Unlock()return errors.New("request is fail")}g.sreSlide.PushBack(NewSlideval(WithReqOption(1)))err := invoker(ctx, method, req, req, cc, opts...)if err == nil {g.sreSlide.PushBack(NewSlideval(WithAcceptReqOption(1)))}g.mutex.Unlock()return err}
}
四、客户端熔断器 (google SRE 熔断器) golang GRPC单元测试
模拟客户端请求,handler 是正常的请求,handler1是返回有问题的请求,2 客户端熔断器的参数. 此值越小越激进,对服务端错误的容忍越小.
测试用例我说明下:
network is fail 是模拟服务端返回的错误,是要调用服务端,此时并不会限制,随着服务恢复,整个请求逐渐正常。
request is fail 是熔断器返回的,不会调用服务端的,直接返回错误。这就是熔断器的魅力所在。
func TestGoogleSre(t *testing.T) {slide := NewGoogleSlide(5*time.Second, 2)builder := slide.Sre()// 模拟服务端正常的请求handler := func(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, opts ...grpc.CallOption) error {return nil}//模拟服务端出问题handler1 := func(ctx context.Context, method string, req, reply any, cc *grpc.ClientConn, opts ...grpc.CallOption) error {return errors.New("network is fail")}err := builder(context.Background(), "/test/a", &gen.GetByIdReq{}, &gen.GetByIDResp{}, nil, handler)assert.NoError(t, err)err = builder(context.Background(), "/test/a", &gen.GetByIdReq{}, &gen.GetByIDResp{}, nil, handler1)assert.Equal(t, err, errors.New("network is fail"))err = builder(context.Background(), "/test/a", &gen.GetByIdReq{}, &gen.GetByIDResp{}, nil, handler1)assert.Equal(t, err, errors.New("network is fail"))err = builder(context.Background(), "/test/a", &gen.GetByIdReq{}, &gen.GetByIDResp{}, nil, handler1)assert.Equal(t, err, errors.New("request is fail"))err = builder(context.Background(), "/test/a", &gen.GetByIdReq{}, &gen.GetByIDResp{}, nil, handler1)assert.Equal(t, err, errors.New("request is fail"))time.Sleep(5 * time.Second)err = builder(context.Background(), "/test/a", &gen.GetByIdReq{}, &gen.GetByIDResp{}, nil, handler)assert.NoError(t, err)
}
首先感谢《google SRE 》以及 腾讯微服务治理相关文章为我提供了深入的思考以及总结
代码或者测试用例如果有异议,请和我留言,大家一起探讨
相关文章:
小米商城服务治理之客户端熔断器(Google SRE客户端熔断器)
目录 前言 一、什么是Google SRE熔断器 二、Google SRE 熔断器的工作流程: 三、客户端熔断器 (google SRE 熔断器) golang GRPC 实现 四、客户端熔断器 (google SRE 熔断器) golang GRPC单元测试 大家可以关注个人博客:xingxing – Web Developer …...
Springboot 校验工具类
校验工具类 这个实现逻辑很简单,就是调用string的正则表达式 我这里的代码要导入糊涂工具包 <dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.7.17</version> </dependency>import…...
编程笔记 html5cssjs 069 JavaScrip Undefined数据类型
编程笔记 html5&css&js 069 JavaScrip Undefined数据类型 一、undefined数据类型二、类型运算小结 在JavaScript中,undefined 是一种基本数据类型,它表示一个变量已经声明但未定义(即没有赋值)或者一个对象属性不存在。 一…...
MySQL 处理JSON字符串
目录 前言 JSON值的部分更新 创建JSON值 JSON 值的规范化、合并和自动包装 合并JSON值 搜索和修改JSON值 JSON路径 JSON值的比较和排序 JSON值的聚合 前言 现在很多数据会以json格式存储,如果你还在用like查询json字符串,那你就OUT了࿰…...
python爬虫-多线程-数据库——WB用户
数据库database的包: Python操作Mysql数据库-CSDN博客 效果: 控制台输出: 数据库记录: 全部代码: import json import os import threading import tracebackimport requests import urllib.request from utils im…...
有向图查询所有环,非递归
图: 有向图查询所有环,非递归: import java.util.*;public class CycleTest {private final int V; // 顶点数private final List<List<Integer>> adjList; // 邻接表public CycleTest(int vertices) {this.V vertices;this.…...
SpringBoot 使用WebSocket功能
实现步骤: 1.导入WebSocket坐标。 在pom.xml中增加依赖项: <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dependency>2.编写WebSocket配…...
HTML5的新特性
目录 一,新增语义化标签 二,新增的多媒体标签 三,新增input表单 四,新增的表单属性 一,新增语义化标签 二,新增的多媒体标签 1,音频:<audio>.。。用MP3 <audio src…...
Filter过滤器学习使用
验证token 对外API过滤器 public class APIFilter implements Filter {private static Logger logger LogManager.getLogger(APIFilter.class);private ICachedTokenService tokenService;public APIFilter(ICachedTokenService tokenService) {super();this.tokenService …...
关于修改数据库服务器时间导致达梦数据库集群裂开
故障原因: 因为每天数据库服务器时间都不一致,想要给数据库服务器配置个NTP服务器。结果导致达梦数据库裂库。后面查看了达梦系统管理员手册了解了达梦集群的机制,知道数据库服务器时间需要先关闭数据库服务之后才可以修改数据库服务器时间。…...
自定义包的设计与实现
这是一个 CPacket 类,用于解析包含固定格式的数据。该类的成员变量包括固定包头 sHead、包长度 nLength、控制命令 sCmd、包数据 strData 和和校验 sSum。 构造函数: CPacket():默认构造函数,初始化成员变量。 CPacket(const B…...
时机成熟了
时机成熟了。 有一个老乡群,一到年底就各种人找车、车找人的消息。这些消息如果能直接爬取到一个小的网页里面去,则可以极大地便利大家做检索。如何把非结构化的内容转成结构化的 json,在以前是一个难题,但是有了 ChatGPT&#x…...
Linux 驱动开发基础知识——总线设备驱动模型(八)
个人名片: 🦁作者简介:学生 🐯个人主页:妄北y 🐧个人QQ:2061314755 🐻个人邮箱:2061314755qq.com 🦉个人WeChat:Vir2021GKBS 🐼本文由…...
SpringBoot+BCrypt算法加密
BCrypt是一种密码哈希函数,BCrypt算法使用“盐”来加密密码,这是一种随机生成的字符串,可以在密码加密过程中使用,以确保每次加密结果都不同。盐的使用增强了安全性,因为攻击者需要花费更多的时间来破解密码。 下图为…...
更新至2023年,2002-2023年3月中国国债发行数据
更新至2023年,2002-2023年3月中国国债发行数据 1、时间:2002-2023年3月 2、指标:序号、代码、发行日期、发行总额(亿元)、期限(年)、发行价格、票面利率(发行参考利率)(%)、票面利率说明、息票品种、附息利率类型、付息频率、起息日期、付息…...
2024最新版TypeScript安装使用指南
2024最新版TypeScript安装使用指南 Installation and Development Guide to the Latest TypeScript in 2024 By JacksonML 1. 什么是TypeScript? TypeScript is JavaScript with syntax for types. – typescriptlang.org TypeScript 是 JavaScript 的一个超集,…...
国外知名的农业机器人公司
从高科技温室到云播种,农业机器人如何帮助农民填补劳动力短缺以及超市货架的短缺。 概要 “高科技农业”并不矛盾。当代农业经营更像是硅谷,而不是美国哥特式,拥有控制灌溉的应用程序、驾驶拖拉机的 GPS 系统和监控牲畜的带有 RFID 芯片的耳…...
【EI会议征稿中|ACM出版】#先投稿,先送审#第三届网络安全、人工智能与数字经济国际学术会议(CSAIDE 2024)
#先投稿,先送审#ACM出版#第三届网络安全、人工智能与数字经济国际学术会议(CSAIDE 2024) 2024 3rd International Conference on Cyber Security, Artificial Intelligence and Digital Economy 2024年3月8日-10日 | 中国济南 会议官网&…...
【笔试常见易错选择题01】else、表达式、二维数组、%m.ns、%m.nf、常量指针和指针常量、宏定义、传参、数组越界、位段
1. 下列main()函数执行后的结果为() int func(){ int i, j, k 0; for(i 0, j -1;j 0;i, j){ k; } return k; } int main(){cout << (func());return 0; }A. -1 B. 0 C. 1 D. 2 判断为赋值语句,j等于0 0为假不进循环 选B. 2. 下面程…...
Unity中常见的单词
前言 unity中常见的单词学习积累 一.常用的基础词。 new:新建; as:像。。一样; null:对象空值; void:函数返回空值; switch:开关; abstract:抽象的; event:事件; return:返回; class:类; …...
Unity LineRenderer不只是画线:5个实战案例教你做激光、轨迹与魔法特效
Unity LineRenderer实战进阶:从激光瞄准到魔法光束的5种创意实现 在Unity游戏开发中,LineRenderer常被简单地视为"画线工具",但它的潜力远不止于此。当我们将这个组件与物理系统、着色器技术和游戏逻辑相结合时,它能创造…...
OpenWrt旁路由进阶玩法:用iPhone USB网络共享做冗余WAN口,提升家庭网络可靠性
OpenWrt旁路由进阶玩法:用iPhone USB网络共享构建冗余WAN口 当家庭网络的核心设备——主路由器突然宕机时,智能家居离线、视频会议中断、NAS文件无法访问的连锁反应会让人措手不及。而将iPhone的USB网络共享转化为OpenWrt旁路由的备用WAN口,就…...
LabelImg图像标注工具:3分钟掌握高效目标检测数据标注技巧
LabelImg图像标注工具:3分钟掌握高效目标检测数据标注技巧 【免费下载链接】labelImg LabelImg is now part of the Label Studio community. The popular image annotation tool created by Tzutalin is no longer actively being developed, but you can check ou…...
3种方案彻底解决Windows系统APK安装难题:APK Installer技术解析
3种方案彻底解决Windows系统APK安装难题:APK Installer技术解析 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer 多场景痛点直击:传统Android应用…...
告别繁琐权限,uTools hosts插件一键切换与管理的效率革命
1. 为什么我们需要更优雅的hosts管理方案 每次修改hosts文件都要经历这样的痛苦循环:先要回忆文件藏在系统哪个角落,接着得用管理员身份打开文本编辑器,小心翼翼地修改内容,最后还要担心格式错误导致系统异常。作为经常需要切换开…...
3个步骤实现教育资源高效获取:电子教材下载工具全攻略
3个步骤实现教育资源高效获取:电子教材下载工具全攻略 【免费下载链接】tchMaterial-parser 国家中小学智慧教育平台 电子课本下载工具 项目地址: https://gitcode.com/GitHub_Trending/tc/tchMaterial-parser tchMaterial-parser是一款专为教育工作者和学习…...
别再为小Batch Size发愁了!手把手教你用Group Normalization稳定训练你的PyTorch模型
别再为小Batch Size发愁了!手把手教你用Group Normalization稳定训练你的PyTorch模型 当你在训练深度学习模型时,是否遇到过这样的困境:由于GPU显存限制,只能使用较小的batch size,结果模型训练变得极不稳定ÿ…...
从标定板到生产线:OpenCV实战工业相机畸变校正全流程
1. 工业相机畸变:产线精度杀手的前世今生 第一次在产线上看到相机拍出来的零件尺寸和实物差了0.5毫米时,我盯着屏幕愣了三分钟——这个误差足以让整个自动化装配线变成废品生产线。工业相机的畸变就像近视眼没戴眼镜,看到的物体位置和形状都…...
ScintillaNET:打造专业级代码编辑器的终极Windows Forms解决方案
ScintillaNET:打造专业级代码编辑器的终极Windows Forms解决方案 【免费下载链接】ScintillaNET A Windows Forms control, wrapper, and bindings for the Scintilla text editor. 项目地址: https://gitcode.com/gh_mirrors/sc/ScintillaNET ScintillaNET是…...
FanControl实战指南:从噪音困扰到智能散热的转型之路
FanControl实战指南:从噪音困扰到智能散热的转型之路 【免费下载链接】FanControl.Releases This is the release repository for Fan Control, a highly customizable fan controlling software for Windows. 项目地址: https://gitcode.com/GitHub_Trending/fa/…...
