返回顶部
首页 > 资讯 > 服务器 >kubernetes实现分布式限流
  • 253
分享到

kubernetes实现分布式限流

2024-04-02 19:04:59 253人浏览 八月长安
摘要

目录一、概念1.1 使用场景1.2 维度1.3 分布式限流二、分布式限流常用方案三、基于kubernetes的分布式限流3.1 kubernetes中的副本数3.2 rateLimi

一、概念

限流(Ratelimiting)指对应用服务的请求进行限制,例如某一接口的请求限制为 100 个每秒,对超过限制的请求则进行快速失败或丢弃。

1.1 使用场景

限流可以应对:

  • 热点业务带来的突发请求;
  • 调用方 bug 导致的突发请求;
  • 恶意攻击请求。

1.2 维度

对于限流场景,一般需要考虑两个维度的信息:
时间限流基于某段时间范围或者某个时间点,也就是我们常说的“时间窗口”,比如对每分钟、每秒钟的时间窗口做限定
资源基于可用资源的限制,比如设定最大访问次数,或最高可用连接数。
限流就是在某个时间窗口对资源访问做限制,比如设定每秒最多100个访问请求。

1.3 分布式限流

分布式限流相比于单机限流,只是把限流频次分配到各个节点中,比如限制某个服务访问100qps,如果有10个节点,那么每个节点理论上能够平均被访问10次,如果超过了则进行频率限制。

二、分布式限流常用方案

基于Guava的客户端限流Guava是一个客户端组件,在其多线程模块下提供了以RateLimiter为首的几个限流支持类。它只能对“当前”服务进行限流,即它不属于分布式限流的解决方案。

网关层限流服务网关,作为整个分布式链路中的第一道关卡,承接了所有用户来访请求。我们在网关层进行限流,就可以达到了整体限流的目的了。目前,主流的网关层有以软件为代表的Nginx,还有spring cloud中的Gateway和Zuul这类网关层组件,也有以硬件为代表的F5。

中间件限流将限流信息存储在分布式环境中某个中间件里(比如Redis缓存),每个组件都可以从这里获取到当前时刻的流量统计,从而决定是拒绝服务还是放行流量。

限流组件目前也有一些开源组件提供了限流的功能,比如Sentinel就是一个不错的选择。Sentinel是阿里出品的开源组件,并且包含在了spring Cloud Alibaba组件库中。Hystrix也具有限流的功能。

Guava的Ratelimiter设计实现相当不错,可惜只能支持单机,网关层限流如果是单机则不太满足高可用,并且分布式网关的话还是需要依赖中间件限流,而redis之类的网络通信需要占用一小部分的网络消耗。阿里的Sentinel也是同理,底层使用的是redis或者ZooKeeper,每次访问都需要调用一次redis或者zk的接口。那么在云原生场景下,我们有没有什么更好的办法呢?

对于极致追求高性能的服务不需要考虑熔断、降级来说,是需要尽量减少网络之间的io,那么是否可以通过一个总限频然后分配到具体的单机里面去,在单机中实现平均的限流,比如限制某个ip的qps为100,服务总共有10个节点,那么平均到每个服务里就是10qps,此时就可以通过guava的ratelimiter来实现了,甚至说如果服务的节点动态调整,单个服务的qps也能动态调整。

三、基于kubernetes的分布式限流

Spring Boot应用中,定义一个filter,获取请求参数里的key(ip、userId等),然后根据key来获取rateLimiter,其中,rateLimiter的创建由数据库定义的限频数和副本数来判断,最后,再通过rateLimiter.tryAcquire来判断是否可以通过。

3.1 kubernetes中的副本数

在实际的服务中,数据上报服务一般无法确定客户端的上报时间、上报量,特别是对于这种要求高性能,服务一般都会用到HPA来实现动态扩缩容,所以,需要去间隔一段时间去获取服务的副本数。

func CountDeploymentSize(namespace string, deploymentName string) *int32 {
	deployment, err := client.AppsV1().Deployments(namespace).Get(context.TODO(), deploymentName, metav1.GetOptions{})
	if err != nil {
		return nil
	}
	return deployment.Spec.Replicas
}

用法:GET host/namespaces/test/deployments/k8s-rest-api直接即可。

3.2 rateLimiter的创建

在RateLimiterService中定义一个LoadinGCache<String, RateLimiter>,其中,key可以为ip、userId等,并且,在多线程的情况下,使用refreshAfterWrite只阻塞加载数据的线程,其他线程则返回旧数据,极致发挥缓存的作用。

private final LoadingCache<String, RateLimiter> loadingCache = Caffeine.newBuilder()
        .maximumSize(10_000)
        .refreshAfterWrite(20, TimeUnit.MINUTES)
        .build(this::createRateLimit);
//定义一个默认最小的QPS
private static final Integer minQpsLimit = 3000;

之后是创建rateLimiter,获取总限频数totalLimit和副本数replicas,之后是自己所需的逻辑判断,可以根据totalLimit和replicas的情况来进行qps的限定。

public RateLimiter createRateLimit(String key) {
    log.info("createRateLimit,key:{}", key);
    int totalLimit = 获取总限频数,可以在数据库中定义
    Integer replicas = kubernetesService.getDeploymentReplicas();
    RateLimiter rateLimiter;
    if (totalLimit > 0 && replicas == null) {
        rateLimiter = RateLimiter.create(totalLimit);
    } else if (totalLimit > 0) {
        int nodeQpsLimit = totalLimit / replicas;
        rateLimiter = RateLimiter.create(nodeQpsLimit > minQpsLimit ? nodeQpsLimit : minQpsLimit);
    } else {
        rateLimiter = RateLimiter.create(minQpsLimit);
    }
    log.info("create rateLimiter success,key:{},rateLimiter:{}", key, rateLimiter);
    return rateLimiter;
}

3.3 rateLimiter的获取

根据key获取RateLimiter,如果有特殊需求的话,需要判断key不存在的尝尽

public RateLimiter getRateLimiter(String key) {
  return loadingCache.get(key);
}

3.4 filter里的判断

最后一步,就是使用rateLimiter来进行限流,如果rateLimiter.tryAcquire()为true,则进行filterChain.doFilter(request, response),如果为false,则返回httpstatus.TOO_MANY_REQUESTS

public class RateLimiterFilter implements Filter {
    @Resource
    private RateLimiterService rateLimiterService;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        String key = httpServletRequest.getHeader("key");
        RateLimiter rateLimiter = rateLimiterService.getRateLimiter(key);
        if (rateLimiter != null) {
            if (rateLimiter.tryAcquire()) {
                filterChain.doFilter(request, response);
            } else {
                httpServletResponse.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
            }
        } else {
            filterChain.doFilter(request, response);
        }
    }
}

四、性能压测

为了方便对比性能之间的差距,我们在本地单机做了下列测试,其中,总限频都设置为3万。

无限流

使用redis限流

其中,ping redis大概6-7ms左右,对应的,每次请求需要访问redis,时延都有大概6-7ms,性能下降明显

自研限流

性能几乎追平无限流的场景,guava的rateLimiter确实表现卓越

五、其他问题

5.1 对于保证qps限频准确的时候,应该怎么解决呢?

在k8s中,服务是动态扩缩容的,相应的,每个节点应该都要有所变化,如果对外宣称限频100qps,而且后续业务方真的要求百分百准确,只能把LoadingCache<String, RateLimiter>的过期时间调小一点,让它能够近实时的更新单节点的qps。这里还需要考虑一下k8s的压力,因为每次都要获取副本数,这里也是需要做缓存的

5.2 服务从1个节点动态扩为4个节点,这个时候新节点识别为4,但其实有些并没有启动完,会不会造成某个节点承受了太大的压力

理论上是存在这个可能的,这个时候需要考虑一下初始的副本数的,扩缩容不能一蹴而就,一下子从1变为4变为几十个这种。一般的话,生产环境肯定是不能只有一个节点,并且要考虑扩缩容的话,至于要有多个副本预备的

5.3 如果有多个副本,怎么保证请求是均匀的

这个是依赖于k8s的service负载均衡策略的,这个我们之前做过实验,流量确实是能够均匀的落到节点上的。还有就是,我们整个限流都是基于k8s的,如果k8s出现问题,那就是整个集群所有服务都有可能出现问题了。

到此这篇关于kubernetes实现分布式限流的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持编程网。

--结束END--

本文标题: kubernetes实现分布式限流

本文链接: https://lsjlt.com/news/145499.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • kubernetes实现分布式限流
    目录一、概念1.1 使用场景1.2 维度1.3 分布式限流二、分布式限流常用方案三、基于kubernetes的分布式限流3.1 kubernetes中的副本数3.2 rateLimi...
    99+
    2024-04-02
  • kubernetes怎么实现分布式限流
    本篇内容主要讲解“kubernetes怎么实现分布式限流”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“kubernetes怎么实现分布式限流”吧!一、概念限流(Ratelimiting)指对应用...
    99+
    2023-06-29
  • redis如何实现分布式限流
    Redis可以使用令牌桶算法来实现分布式限流。令牌桶算法是一种常用的限流算法,它通过维护一个固定容量的令牌桶,每秒钟往桶里放入一定数...
    99+
    2023-09-09
    redis
  • 利用Redis实现分布式限流
    标题:利用Redis实现分布式限流正文:随着互联网的快速发展,网站和服务的并发访问量不断增加,为了保护后端系统的稳定性,限制并发访问量成为了一项重要的任务。在分布式系统中,为了保证多个服务实例之间的共享状态,我们可以使用Redis作为分布式...
    99+
    2023-11-07
    分布式 redis 限流
  • Redis和Lua实现分布式限流器
    本篇文章为大家展示了Redis和Lua实现分布式限流器,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。原理计数器算法是指在一段窗口时间内允许通过的固定数量的请求, 比...
    99+
    2024-04-02
  • SpringBoot+Redis+Lua分布式限流的实现
    Redis支持LUA脚本的主要优势 LUA脚本的融合将使Redis数据库产生更多的使用场景,迸发更多新的优势: 高效性:减少网络开销及时延,多次redis服务器网络请求的操作,使用L...
    99+
    2022-11-13
    SpringBoot Redis Lua分布式限流 SpringBoot 分布式限流
  • 如何在Redis中实现分布式限流
    在Redis中实现分布式限流可以通过使用Redis的计数器和过期时间来实现。以下是一种基于计数器和过期时间的简单实现方式: 使用R...
    99+
    2024-04-09
    Redis
  • Redisson分布式限流的实现原理解析
    目录正文RRateLimiter使用RRateLimiter的实现RRateLimiter使用时注意事项RRateLimiter是非公平限流器Rate不要设置太大限流的上限取决于Redis单实例的性能分布式限流的本质正文...
    99+
    2023-02-12
    Redisson分布式限流 Redisson 分布式
  • 四种分布式限流算法和代码实现
    带着问题走近限流为什么要限流呢?就像我上面说的,流量多,的确是一件好事,但是如果过载,把系统打挂了,那大家都要吃席了。没逝吧所以,在各种大促活动之前,要对系统进行压测,评估整个系统的峰值QPS,要做一些限流的设置,超过一定阈值,就拒绝处理或...
    99+
    2023-08-15
  • 如何使用Redis实现分布式限流功能
    如何使用Redis实现分布式限流功能引言:随着互联网的快速发展,业务系统的访问量也日益增加。当流量集中到某一业务系统时,会给系统的稳定性和性能带来一定的威胁。为了保护业务系统,限流成为一种必不可少的手段。在分布式系统中,使用Redis可以方...
    99+
    2023-11-07
    分布式 redis 限流
  • Go实现分布式系统高可用限流器实战
    目录前言1. 问题描述2. 信号量限流2.1 阻塞方式2.2 非阻塞方式3. 限流算法3.1 漏桶算法3.2 令牌桶算法3.3 漏桶算法的实现改进4. Uber 开源实现 RateL...
    99+
    2024-04-02
  • 基于Redis实现分布式应用限流的方法
    限流的目的是通过对并发访问/请求进行限速或者一个时间窗口内的的请求进行限速来保护系统,一旦达到限制速率则可以拒绝服务。前几天在DD的公众号,看了一篇关于使用 瓜娃 实现单应用限流的方案 --》原文,参考《redis in action》 实...
    99+
    2023-05-30
    redis 限流 流的
  • go实现一个分布式限流器的方法步骤
    目录1. 接口定义2. LocalCounterLimiter3. LocalTokenBucketLimiter4. RedisCounterLimiter5. RedisToke...
    99+
    2024-04-02
  • springboot+redis 实现分布式限流令牌桶的示例代码
    1、前言 网上找了很多redis分布式限流方案,要不就是太大,需要引入第三方jar,而且还无法正常运行,要不就是定时任务定时往key中放入数据,使用的时候调用,严重影响性能,所以着手...
    99+
    2024-04-02
  • kubernetes中如何实现分布式负载测试Locust
    这篇文章主要介绍了kubernetes中如何实现分布式负载测试Locust,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。一: 前言  本文介绍如何在Kubernet...
    99+
    2023-06-04
  • java分布式面试系统限流最佳实践
    目录引言1、面试官:哪些场景系统使用了限流?为什么要使用限流?2、面试官:那你了解哪些常用限流算法?1.计数器方法:2.漏斗算法:3.令牌桶算法:3、面试官:那具体这值该如何评估,说...
    99+
    2024-04-02
  • redisson分布式限流RRateLimiter源码解析
    目录分布式限流-单位时间多实例多线程访问次数限制1.简单使用2. 实现限流redisson使用了哪些redis数据结构3. 超过10s,我再次获取一个令牌,数据结构发生的变化4. 源...
    99+
    2022-11-13
    redisson分布式限流RRateLimiter redisson RRateLimiter
  • redisson分布式限流RRateLimiter怎么使用
    今天小编给大家分享一下redisson分布式限流RRateLimiter怎么使用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧...
    99+
    2023-07-04
  • Redis分布式限流组件设计与使用实例
    目录1.背景2.Redis计数器限流设计2.1Lua脚本2.2自定义注解2.3限流组件2.4限流切面实现3.测试一下3.1方法限流示例3.2动态入参限流示例4.其它扩展5.源码地址本...
    99+
    2024-04-02
  • js实现瀑布流布局(无限加载)
    本文实例为大家分享了js实现瀑布流布局的具体代码,供大家参考,具体内容如下 1.实现瀑布流布局思路 准备好数据之后 . 绑定滚动事件 . 判断页面是否到底(滚动的距离+可是区域的高度...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作