为什么要用熔断

前面我们讲过限流保证服务的可用性,不被突如其来的流量打爆。但是两种情况是限流解决不了的。

  1. 如果我们服务只能处理1000QPS,但是有10wQPS打过来,服务还是会炸。因为拒绝请求也需要成本。
  2. 服务但是io型的,会把mysql,redis,mq等中间件打挂。

所以,我们遵循一个思路,可不可以client端在失败的多的时候就不调用了,直接返回错误呢?

什么是熔断

熔断器是为了当依赖的服务已经出现故障时,主动阻止对依赖服务的请求。保证自身服务的正常运行不受依赖服务影响,防止雪崩效应。

源码分析

源码地址

CircuitBreaker 接口

type CircuitBreaker interface {
Allow() error
MarkSuccess()
MarkFailed()
}
  1. Allow()

    • 判断熔断器是否允许通过
  2. MarkSuccess()
    • 熔断器成功的回调
  3. MarkFailed()
    • 熔断器失败的回调

Group 结构体

type Group struct {
mutex sync.Mutex
val atomic.Value New func() CircuitBreaker
}
  1. mutex

    • 互斥锁,使val这个map不产生数据竞争
  2. val
    • map,存储name -> CircuitBreaker
  3. New
    • 生成一个CircuitBreaker

Get方法

// Get .
func (g *Group) Get(name string) CircuitBreaker {
m, ok := g.val.Load().(map[string]CircuitBreaker)
if ok {
breaker, ok := m[name]
if ok {
return breaker // 很具name从val拿出 breaker 如果存在返回
}
}
// slowpath for group don`t have specified name breaker.
g.mutex.Lock()
nm := make(map[string]CircuitBreaker, len(m)+1)
for k, v := range m {
nm[k] = v
}
breaker := g.New()
nm[name] = breaker // 如果不存在 生成一个 并放入map 并返回
g.val.Store(nm)
g.mutex.Unlock()
return breaker
}

Breaker 结构体

// Breaker is a sre CircuitBreaker pattern.
type Breaker struct {
stat window.RollingCounter
r *rand.Rand
// rand.New(...) returns a non thread safe object
randLock sync.Mutex // Reducing the k will make adaptive throttling behave more aggressively,
// Increasing the k will make adaptive throttling behave less aggressively.
k float64
request int64 state int32
}
  1. stat

    • 滑动窗口,记录成功失败
  2. r
    • 随机数
  3. randLock
    • 读写锁
  4. k 成功系数
    • total(总数) = success * k
  5. request 请求数
    • 当总数 < request时,不判断是否熔断
  6. state
    • 熔断器状态 打开或者关闭

Allow()方法

// Allow request if error returns nil.
func (b *Breaker) Allow() error {
success, total := b.summary() // 从活动窗口获取成功数和总数
k := b.k * float64(success) // 根据k成功系数 获取 // check overflow requests = K * success
if total < b.request || float64(total) < k { // 如果总数<request 或者 总数 < k
if atomic.LoadInt32(&b.state) == StateOpen {
atomic.CompareAndSwapInt32(&b.state, StateOpen, StateClosed) // 如果state是打开 关闭
}
return nil
}
if atomic.LoadInt32(&b.state) == StateClosed {
atomic.CompareAndSwapInt32(&b.state, StateClosed, StateOpen) // 如果state是关闭 打开
}
dr := math.Max(0, (float64(total)-k)/float64(total+1)) // 获取系数,当k越大 dr越小
drop := b.trueOnProba(dr)
// trueOnProba 获取水机数
// 返回是否<dr if drop { // 如果是 拒绝请求
return circuitbreaker.ErrNotAllowed
}
return nil
} func (b *Breaker) trueOnProba(proba float64) (truth bool) {
b.randLock.Lock()
truth = b.r.Float64() < proba
b.randLock.Unlock()
return
}

使用trueOnProba的原因是,当熔断器关闭时,随机让一部分请求通过,当success越大,请求的通过的数量就越多。用这些数据成功与否,放入窗口统计,当成功数达到要求时,就可以关闭熔断器了。

MarkSuccess()以及MarkFailed()方法

// MarkSuccess mark requeest is success.
func (b *Breaker) MarkSuccess() {
b.stat.Add(1) // 成功数+1
} // MarkFailed mark request is failed.
func (b *Breaker) MarkFailed() {
// NOTE: when client reject requets locally, continue add counter let the
// drop ratio higher.
b.stat.Add(0) // 失败数+1
}

流程图


从kratos分析breaker熔断器源码实现的更多相关文章

  1. Android5.1.1 - APK签名校验分析和修改源码绕过签名校验

    Android5.1.1 - APK签名校验分析和修改源码绕过签名校验 作者:寻禹@阿里聚安全 APK签名校验分析 找到PackageParser类,该类在文件“frameworks/base/cor ...

  2. JPEG概述和头分析(C源码)

    原创文章,转载请注明:JPEG概述和头分析(C源码)  By Lucio.Yang 部分内容来自:w285868925,JPEG压缩标准 1.JPEG概述 JPEG是一个压缩标准,又可分为标准 JPE ...

  3. Cesium专栏-填挖方分析(附源码下载)

    Cesium 是一款面向三维地球和地图的,世界级的JavaScript开源产品.它提供了基于JavaScript语言的开发包,方便用户快速搭建一款零插件的虚拟地球Web应用,并在性能,精度,渲染质量以 ...

  4. Proxy Server源码及分析(TCP Proxy源码 Socket实现端口映射)

    版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/u014530704/article/de ...

  5. 智能指针分析及auto_ptr源码

    简介 C++没有内存自动回收机制,对堆内存的管理就是简单的new和delete,每次new出来的内存都需要手动delete释放.但由于忘记.流程复杂或者异常退出等,都有可能导致没有执行delete释放 ...

  6. NIO 源码分析(05) Channel 源码分析

    目录 一.Channel 类图 二.begin 和 close 是什么 2.1 AbstractInterruptibleChannel 中的 begin 和 close 2.2 Selector 中 ...

  7. NIO 源码分析(02-2) BIO 源码分析 Socket

    目录 一.BIO 最简使用姿势 二.connect 方法 2.1 Socket.connect 方法 2.2 AbstractPlainSocketImpl.connect 方法 2.3 DualSt ...

  8. NIO 源码分析(02-1) BIO 源码分析

    目录 一.BIO 最简使用姿势 二.ServerSocket 源码分析 2.1 相关类图 2.2 主要属性 2.3 构造函数 2.4 bind 方法 2.5 accept 方法 2.6 总结 NIO ...

  9. 总结HashSet以及分析部分底层源码

    总结HashSet以及分析部分底层源码 1. HashSet继承的抽象类和实现的接口 继承的抽象类:AbstractSet 实现了Set接口 实现了Cloneable接口 实现了Serializabl ...

随机推荐

  1. 防止因提供的sql脚本有问题导致版本bvt失败技巧

    发版本时,可能会由于测试库和开发库表结构不一样而导致数据库脚本在测试那边执行时出错,导致版本BVT失败,以下技巧可解决此问题. 步骤:备份目标库,在备份库中执行将要提供的sql脚本看有无问题,若没问题 ...

  2. 谈谈 C++ STL 中的迭代器

    C++中的迭代器和指针 在前面的内容中我们简单讲过,STL主要是由三部分组成 容器(container),包括vector,list,set,map等 泛型算法(generic algorithm), ...

  3. SaaS技术栈有多复杂?

    [特别声明:本文基于Tools and Services I Use to Run My SaaS进行修改.] 软件SaaS化由于需要考量架构的各个方面,所以需要的技术栈非常全面. 以一个客户管理Sa ...

  4. [源码解析]机器学习参数服务器ps-lite(4) ----- 应用节点实现

    [源码解析]机器学习参数服务器ps-lite(4) ----- 应用节点实现 目录 [源码解析]机器学习参数服务器ps-lite(4) ----- 应用节点实现 0x00 摘要 0x01 基础类 1. ...

  5. Windows内核开发-5-(2)-内核模式调试

    Windows内核开发-5-(2)-内核模式调试 普通用户模式的调试,采取的是给进程添加一个线程来挂起断点,作为一个调试器的线程在进程中使用.照这样来类推,对操作系统调试相当于添加一个进程来限制操作系 ...

  6. 从Python到Go:初学笔记

    本文记录了我在学习Go的过程时的一些笔记,主要是比较Python和Go之间的差异并作简单描述,以此使Python程序员对Go语言的特性有简略的了解.初学难免有纰漏,欢迎各位批评指正补充交流,谢谢. 数 ...

  7. 华为eNSP基础入门-配置SSH远程登录

    eNSP 华为模拟器ensp (Enterprise Network Simulation Platform) 是华为官方推出的一款强大的图形化网络仿真工具平台,主要对企业网路由器.交换机.WLAN等 ...

  8. 超详细Java基础-多态

    茫茫人海千千万万,感谢这一秒你看到这里.希望我的能对你的有所帮助!共勉! 愿你在未来的日子,保持热爱,奔赴山海! Java基础知识(多态) 多态 多态就是指程序中定义的引用变量所指向的具体类型和通过该 ...

  9. system V信号量和Posix信号量

    一.函数上的区别 信号量有两种实现:传统的System V信号量和新的POSIX信号量.它们所提供的函数很容易被区分:对于所有System V信号量函数,在它们的名字里面没有下划线.例如,应该是sem ...

  10. 终极蛇皮上帝视角之铁头娃之鲁迅之暑假闲的慌之bilibili看尚学堂网课的非洲酋长java小复习

    转自https://www.sxt.cn/Java_jQuery_in_action/eight-cache-problem.html 第一个点 自动装箱与拆箱的功能是所谓的"编译器蜜糖(C ...