业务背景
什么是限流?限流主要作用是限制流量,防止因系统过载而崩溃。istio限流有两大类,一个是本地限流,另一个是全局限流。
限流按生效位置分可分为virtualhost级别的限流和route级别的限流;按协议分可分为http的限流和tcp的限流;按服务位置分可分为mesh内部限流和对外部请求的限流。
本地限流是在envoy内部(针对Pod)提供一种令牌桶限速的功能,全局限流需要访问外部限流服务(官方实现:envoyproxy/ratelimit)。
技术背景
全局限流架构
ratelimit 架构包含两部分,一部分是 Envoy 中 ratelimit filter,一部分是 ratelimit gRPC 服务。每次请求前会调用外部限流服务(传递domain和descriptor)决定是否对流量进行限制。
ratelimit filter
其中,Envoy 中 ratelimit filter 又包含:配置 ratelimit service和启用 action filter。一个示例如下:
patch:
operation: INSERT_BEFORE
# Adds the Envoy Rate Limit Filter in HTTP filter chain.
value:
name: envoy.filters.http.ratelimit
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit
# domain can be anything! Match it to the ratelimter service config
domain: productpage-ratelimit
# 如果调用限速服务发生错误或限速服务返回了一个错误,并且 failure_mode_deny 设置为 true,则返回 500 状态码
failure_mode_deny: true
timeout: 10s
rate_limit_service:
# 配置grpc外部限流服务
grpc_service:
envoy_grpc:
# ratelimit.bookinfo.svc.cluster.local要对应ratelimit服务的host:
# <service>.<namespace>.svc.cluster.local
cluster_name: outbound|8081||ratelimit.bookinfo.svc.cluster.local
authority: ratelimit.bookinfo.svc.cluster.local
transport_api_version: V3
configPatches:
- applyTo: VIRTUAL_HOST
match:
context: GATEWAY
routeConfiguration:
vhost:
# 给80端口的虚拟主机配置一个rate_limits 动作
name: "*:80"
route:
action: ANY
patch:
operation: MERGE
# Applies the rate limit rules.
value:
rate_limits:
- actions: # any actions in here
- request_headers: # ("<descriptor_key>", "<header_value_queried_from_header>")
header_name: ":path"
# descriptor_key用于选择在configmap里配置的key
descriptor_key: "PATH"
action支持:
{
"source_cluster": "{...}",源集群动作
"destination_cluster": "{...}",目标集群动作
"request_headers": "{...}",请求头动作
"remote_address": "{...}",远程地址动作
"generic_key": "{...}",通用key动作
"header_value_match": "{...}",头匹配动作
"dynamic_metadata": "{...}",动态元数据动作
"metadata": "{...}",元数据动作
"extension": "{...}",扩展动作
"masked_remote_address": "{...}",ip地址mask动作
"query_parameter_value_match": "{...}",查询参数动作
}
ratelimit service
Envoy对ratelimit service的client和server的规定请见ratelimit service v3
RateLimitServiceClient 的定义如下:
// RateLimitServiceClient is the client API for RateLimitService service.
//
type RateLimitServiceClient interface {
// Determine whether rate limiting should take place.
ShouldRateLimit(ctx context.Context, in *RateLimitRequest, opts ...grpc.CallOption) (*RateLimitResponse, error)
}
ratelimit service client 定义了 ShouldRateLimit 方法,而该方法将调用 ratelimit service server 的 ShouldRateLimit 方法:
func (c *rateLimitServiceClient) ShouldRateLimit(ctx context.Context, in *RateLimitRequest, opts ...grpc.CallOption) (*RateLimitResponse, error) {
out := new(RateLimitResponse)
err := c.cc.Invoke(ctx, "/envoy.service.ratelimit.v3.RateLimitService/ShouldRateLimit", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
RateLimitServiceServer 的定义如下:
// RateLimitServiceServer is the server API for RateLimitService service.
type RateLimitServiceServer interface {
// Determine whether rate limiting should take place.
ShouldRateLimit(context.Context, *RateLimitRequest) (*RateLimitResponse, error)
}
RateLimitServiceServer 注册函数如下:
func RegisterRateLimitServiceServer(s *grpc.Server, srv RateLimitServiceServer) {
s.RegisterService(&_RateLimitService_serviceDesc, srv)
}
官方限流服务
envoyproxy/ratelimit 是一个官方提供的Go/gRPC 服务,旨在为各种应用程序提供通用速率限制方案。应用程序根据 domain 和一组 descriptor 向 ratelimit 服务请求限速决定(限速或不限速)。
ratelimit 服务读取配置内容(监听磁盘目录),根据配置文件内容组成一个 cacheKey,并且通过该 cacheKey 访问 Redis 缓存,最后返回一个限速决定到调用方,支持每秒、每分、每小时或者每天限速