Go 限流与熔断:rate 令牌桶保护下游与简单熔断器实现

test12026-09-130 次阅读

问题背景

调用第三方或下游服务时,突发流量可能把对方打挂。限流(控制自身速率)和熔断(下游异常时快速失败)是两件互补的事:前者防自己发太多,后者防对方已病时还硬扛。

令牌桶限流

package main

import (
	"context"
	"fmt"
	"time"

	"golang.org/x/time/rate"
)

func main() {
	// 5 QPS,允许突发 10
	limiter := rate.NewLimiter(rate.Limit(5), 10)

	for i := 0; i < 20; i++ {
		ctx, cancel := context.WithTimeout(context.Background(), time.Second)
		if err := limiter.Wait(ctx); err != nil {
			fmt.Println("被限流:", err)
		} else {
			fmt.Println("处理请求", i, time.Now().Format("15:04:05"))
		}
		cancel()
	}
}

简单熔断器

package main

import (
	"errors"
	"sync"
	"time"
)

type Breaker struct {
	mu          sync.Mutex
	failures    int
	threshold   int
	openUntil   time.Time
	cooldown    time.Duration
}

func NewBreaker(threshold int, cooldown time.Duration) *Breaker {
	return &Breaker{threshold: threshold, cooldown: cooldown}
}

func (b *Breaker) Call(fn func() error) error {
	b.mu.Lock()
	if time.Now().Before(b.openUntil) {
		b.mu.Unlock()
		return errors.New("breaker open")
	}
	b.mu.Unlock()

	if err := fn(); err != nil {
		b.mu.Lock()
		b.failures++
		if b.failures >= b.threshold {
			b.openUntil = time.Now().Add(b.cooldown)
		}
		b.mu.Unlock()
		return err
	}

	b.mu.Lock()
	b.failures = 0
	b.mu.Unlock()
	return nil
}

要点

  • rate.Limiter 的突发额度是令牌桶容量,突发后会被限速到设定 QPS。
  • 熔断器要设置半开试探,否则冷却后直接全量恢复仍可能再次雪崩;示例为最简版。
  • 限流与熔断建议配合使用:限流保护全链路,熔断保护单点故障。
T

test1

文章作者

问题背景 调用第三方或下游服务时,突发流量可能把对方打挂。限流(控制自身速率)和熔断(下游异常时快速失败)是两件互补的...

分类
技术
发布时间
2026-09-13
字数
约 1351 字
阅读
0 次