Go语言框架中如何快速集成限流中间件

简介: Go语言框架中如何快速集成限流中间件

前言


在我们的日常开发中, 常用的中间件有很多, 今天来讲一下怎么集成限流中间件, 它可以很好地用限制并发访问数来保护系统服务, 避免系统服务崩溃, 资源占用过大甚至服务器崩溃进而影响到其他应用!


分布式版

简介


通常我们的服务会同时存在多个进程, 也就是负载来保证服务的性能和稳定性, 那么就需要走一个统一的限流, 这个时候就需要借助我们的老朋友-redis, 来进行分布式限流;

算法


漏桶算法

即一个水桶, 进水(接受请求)的速率不限, 出水(处理请求)的速率是一定的, 如果出水的速率小于进水的速率, 就会造成水桶溢出(也就是拒绝请求);

主要是从出口限制, 以固定的速率控制访问速度, 缺点是难以应对突发请求;


依赖库


https://github.com/go-redis/redis_rate

实现

下面是一个简单的实现, 对 /v1/hello接口进行每分钟2次的速率限制


// RateLimitConf 速率配置, 允许多长时间通过多少次.
type RateLimitConf struct {
  Limit int64
  Timer time.Duration
}
// exampleLimiterMap 接口请求速率配置, 建议放入redis/数据库同步本地缓存.
var exampleLimiterMap = map[string]RateLimitConf{
  "/v1/hello": {Limit: 2, Timer: time.Minute},
}
// LimiterMiddle 分布式限流中间件.
func LimiterMiddle(ctx iris.Context) {
  var (
    uri    = ctx.Request().RequestURI
    client = redis.NewClusterClient()
    key    = uri
  )
  conf, ok := exampleLimiterMap[uri]
  if ok {
    limiter := redis_rate.NewLimiter(client)
    if _, _, b := limiter.Allow(key, conf.Limit, conf.Timer); !b {
      r, _ := httpcode.NewRequest(ctx, nil)
      r.Code(httpcode.TooManyReq, fmt.Errorf("req rate limit"), nil)
      return
    }
  }
  ctx.Next()
}

注意

  1. 接口速率配置如果需要进行实时配置, 则建议将配置写入数据库, 然后刷新到本地缓存/存到redis;
  2. 如果需要对设备/ip/用户进行接口限制访问, 则将 key加上唯一标志即可;


单机版

简介

这个就只适用于单个服务进程的限流, 比如个人搭的一些小网站之类的;

算法

令牌桶算法


即也是一个桶, 按照设定的速率往桶里放令牌, 10s二十次即1s放两个令牌(允许处理两次请求), 然后请求来之后必须从桶里取出来令牌才可以进行处理, 没有令牌则选择拒绝或等待;

主要是从入口限制, 允许一定量的突发请求(即桶内所有的令牌);


依赖库


https://golang.org/x/time/rate


实现


下面是一个简单的实现, 对 /v1/hello接口进行每分钟2次的速率限制

// exampleStandAloneLimiterMap 单机接口请求速率配置.
var exampleStandAloneLimiterMap = map[string]*rate.Limiter{
  "/v1/hello": rate.NewLimiter(rate.Every(time.Minute), 2),
}
// StandAloneLimiterMiddle 单机限流中间件.
func StandAloneLimiterMiddle(ctx iris.Context) {
  var (
    uri = ctx.Request().RequestURI
  )
  limiter, ok := exampleStandAloneLimiterMap[uri]
  if ok {
    if b := limiter.Allow(); !b {
      r, _ := httpcode.NewRequest(ctx, nil)
      r.Code(httpcode.TooManyReq, fmt.Errorf("req rate limit"), nil)
      return
    }
  }
  ctx.Next()
}

结语


上面的代码均摘自我开发的一个开源项目中, 主要是一个Go的标准项目布局, 封装了一些常用的组件, 有兴趣的朋友可以了解一下, 新手极易上手;

目录
相关文章
|
3月前
|
存储 安全 Java
【Golang】(4)Go里面的指针如何?函数与方法怎么不一样?带你了解Go不同于其他高级语言的语法
结构体可以存储一组不同类型的数据,是一种符合类型。Go抛弃了类与继承,同时也抛弃了构造方法,刻意弱化了面向对象的功能,Go并非是一个传统OOP的语言,但是Go依旧有着OOP的影子,通过结构体和方法也可以模拟出一个类。
254 1
|
5月前
|
Cloud Native 安全 Java
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
340 1
|
5月前
|
Cloud Native Go API
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
431 0
|
5月前
|
Cloud Native Java Go
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
290 0
|
5月前
|
Cloud Native Java 中间件
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
276 0
|
5月前
|
Cloud Native Java Go
Go:为云原生而生的高效语言
Go:为云原生而生的高效语言
356 0
|
5月前
|
数据采集 Go API
Go语言实战案例:多协程并发下载网页内容
本文是《Go语言100个实战案例 · 网络与并发篇》第6篇,讲解如何使用 Goroutine 和 Channel 实现多协程并发抓取网页内容,提升网络请求效率。通过实战掌握高并发编程技巧,构建爬虫、内容聚合器等工具,涵盖 WaitGroup、超时控制、错误处理等核心知识点。
|
5月前
|
数据采集 JSON Go
Go语言实战案例:实现HTTP客户端请求并解析响应
本文是 Go 网络与并发实战系列的第 2 篇,详细介绍如何使用 Go 构建 HTTP 客户端,涵盖请求发送、响应解析、错误处理、Header 与 Body 提取等流程,并通过实战代码演示如何并发请求多个 URL,适合希望掌握 Go 网络编程基础的开发者。
|
6月前
|
JSON 前端开发 Go
Go语言实战:创建一个简单的 HTTP 服务器
本篇是《Go语言101实战》系列之一,讲解如何使用Go构建基础HTTP服务器。涵盖Go语言并发优势、HTTP服务搭建、路由处理、日志记录及测试方法,助你掌握高性能Web服务开发核心技能。
|
6月前
|
Go
如何在Go语言的HTTP请求中设置使用代理服务器
当使用特定的代理时,在某些情况下可能需要认证信息,认证信息可以在代理URL中提供,格式通常是:
477 0