精确掌控并发:固定时间窗口算法在分布式环境下并发流量控制的设计与实现

这篇具有很好参考价值的文章主要介绍了精确掌控并发:固定时间窗口算法在分布式环境下并发流量控制的设计与实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

这是《百图解码支付系统设计与实现》专栏系列文章中的第(14)篇。点击上方关注,深入了解支付系统的方方面面。

本篇主要介绍分布式场景下常用的并发流量控制方案,包括固定时间窗口、滑动时间窗口、漏桶、令牌桶、分布式消息中间件等,并重点讲清楚固定时间窗口应用原理和应用场景,以及使用reids实现的核心代码。

在非支付场景,也常常需要用到这些并发流量控制方案。

1. 前言

在互联网应用里面,并发流量控制无所不在。在支付系统中,流量控制同样是一个关键的技术方面,主要用于确保系统的稳定性和可靠性,尤其在高流量的情况下。以下是一些主要使用流量控制的场景:

  1. 对外API限流:对外提供的API(如支付接口)需要限流来保护后端服务不会过载。
  2. 保护外部渠道:大促时,对下流渠道的支付流量要做削峰填谷,避免突发流量把渠道打挂。
  3. 保护内部应用:大促时,内部各应用要根据流量模型配置限流值,避免形成雪崩。
  4. 满足外部退款限流要求:电商批量提交退款时,支付系统内部要在分布式集群环境下对某个渠道实现低至1TPS的退款并发,避免超过渠道退款并发导致大批量失败。

特别说明的是,流量控制通常包括限流限速

限流:就是流量达到一定程度,超过的流量会全部立即拒绝掉,也就是快速失败。比如上面的API限流。

限速:一般是指接收流量后,先保存到队列中,然后按指定的速度发出去,如果超过队列最大值,才会拒绝。比如上面的支付流量和退款流量打到外部渠道。

精确掌控并发:固定时间窗口算法在分布式环境下并发流量控制的设计与实现,百图解码支付系统设计与实现,分布式,分布式限流,redis限流,固定时间窗口,固定窗口

另外,支付和退款流量控制虽然都是流量控制,但有一些细小的区别:

  1. 支付的限流TPS通常比较高,从十几TPS到几百TPS都有,排队时效性要求很高,秒级内就要付出去。
  2. 退款的限流TPS通常比较低,在国外的基础设施建设很差,甚至部分渠道要求退款1TPS。但是排队时效性要求很低,几天内退出去就行。

2. 几种方案对比

固定窗口:算法简单,对突然流量响应不够灵活。超过流量的会直接拒绝,通常用于限流。

滑动窗口: 算法简单,对突然流量响应比固定窗口灵活。超过流量的会直接拒绝,通常用于限流。

漏桶算法:在固定窗口的基础之上,使用队列缓冲流量。提供了稳定的流量输出,适用于对流量平滑性有严格要求的场景。后面会介绍如何应用到外部渠道退款场景。

令牌桶算法:在滑动窗口的基础之上,使用队列缓冲流量。能够允许一定程度的突发性流量,但实现较为复杂。

分布式消息中间件:如Kafka和RabbitMQ等,能够有效地对消息进行缓冲和管理,增加系统复杂性,且如果需要精确控制流量还需要引入额外的机制。后面会介绍如何应用到外部渠道支付场景。

3. 固定时间窗口原理

精确掌控并发:固定时间窗口算法在分布式环境下并发流量控制的设计与实现,百图解码支付系统设计与实现,分布式,分布式限流,redis限流,固定时间窗口,固定窗口

固定窗口算法,也称为时间窗口算法,是一种流量控制和速率限制策略。此算法将时间轴分割成等长、不重叠的时间段,称为“窗口”。每个窗口都有一个独立的计数器,用于跟踪窗口期间的事件数量(如API调用、数据包传输等)。

固定窗口算法的好处是简单,缺点也很明显,就是无法应对突发流量,比如每秒30并发,如果前100ms来了30个请求,那么在10ms内就会把30个请求打出去,后面的900ms的请求全部拒绝。

工作流程:

  1. 窗口定义:首先确定窗口大小,比如1秒钟。
  2. 计数:每当发生一个事件(比如一个请求到达),就在当前窗口的计数器上加一。
  3. 限制检查:如果当前窗口的计数器达到预设阀值,则拒绝新的请求。直到下一个窗口开始。
  4. 窗口重置:当前窗口结束时,计算数器重置为零,开始下一个窗口计数。

4. 固定时间窗口在支付系统中的应用场景

主要用于简单的限流。比如在渠道网关做限流,发送渠道的请求最大不能超过测算出来的值,避免渠道侧过载,可能会导致支付请求批量失败。

是有损服务的一种实现方式。

5. 使用redis实现的核心代码

为什么选择redis?因为在分布式场景下,限流需要有一个集群共用的计算数来保存当前时间窗口的请求量,redis是一个比较优的方案。

场景示例:WPG渠道的支付每秒不能超过20TPS。

那么设计key=“WPG-PAY” + 当前时间戳(精确到S),数据过期时间为2S(这个过期时间主要是兼容各服务器的时间差)。

下面是流程图:

精确掌控并发:固定时间窗口算法在分布式环境下并发流量控制的设计与实现,百图解码支付系统设计与实现,分布式,分布式限流,redis限流,固定时间窗口,固定窗口

lua脚本:limit.lua

local key = KEYS[1]
-- 默认为2S超期,精确到S级。也可以改造成由外面传进来 --
local expireTime = 2
-- 先自增,如果不存在就自动创建 --
redis.incr(key);
local count = tonumber(redis.call("get", key))
-- 如果结果为1,说明是新增的,设置超时时间 --
if count == 1 then
    redis.call("expire", key, expireTime)
end
return count;

redis操作类:RedisLimitUtil

/**
 * redis限流操作类
 */
@Component
public class RedisLimitUtil {
    // 限流脚本
    private static final String LIMIT_SCRIPT_LUA = "limit.lua";
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    private DefaultRedisScript<Long> limitScript;

    /**
     * 缓存脚本
     */
    @PostConstruct
    public void cacheScript() {
        limitScript = new DefaultRedisScript();
        limitScript.setScriptSource(new ResourceScriptSource(new ClassPathResource(LIMIT_SCRIPT_LUA)));
        limitScript.setResultType(Long.class);

        List<Boolean> cachedScripts = redisTemplate.getConnectionFactory().getConnection().scriptExists(
            limitScript.getSha1());
        // 需要缓存
        if (CollectionUtils.isEmpty(cachedScripts) || !cachedScripts.get(0)) {
            redisTemplate.getConnectionFactory().getConnection().
            scriptLoad(redisTemplate.getStringSerializer().serialize(limitScript.getScriptAsString()));
        }
    }

    /**
     * 判断是否限流
     * 这里不考虑超过long最大值的情况,系统在达到long最大值前就奔溃了。
     */
    public boolean isLimited(String key, long countLimit) {
        Long count = redisTemplate.execute(limitScript, Lists.newArrayList(key));
        return countLimit >= count;
    }

}

使用:PayServiceImpl

/**
 * 支付服务示例
 */
public class PayServiceImpl implements PayService {
    @Autowired
    private RedisLimitUtil redisLimitUtil;

    @Override
    public PayOrder pay(PayRequest request) {
        if (isLimited(request)) {
            throw new RequestLimitedException(buildExceptionMessage(request));
        }

        // 其它业务处理
        ... ...
    }

    /*
     * 限流判断
     */
    private boolean isLimited(PayRequest request) {
        // 限流KEY,这里以[业务类型 + 渠道]举例
        String key = request.getBizType() + request.getChannel();
        // 限流值
        Long countLimit = countLimitMap.get(key);

        // 如果key对应的限流值没有配置,或配置为-1,说明不限流
        if (null == countLimit || -1 == countLimit) {
            return false;
        }

        return redisLimitUtil.isLimited(key + buildTime(), countLimit);
    }
}

注释写得比较清楚,没有什么需要补充的。

6. 结束语

分布式流控有很多实现方案,使用redis实现的固定时间窗口是最简单的方案,而且也非常实用,应付一般的场景已经足够使用。

下一篇会介绍滑动时间窗口算法及实现。

7. 传送门

支付系统设计与实现是一个专业性非常强的领域,里面涉及到的很多设计思路和理论也可以应用到其它行业的软件设计中,比如幂等性,加解密,领域设计思想,状态机设计等。

在《百图解码支付系统设计与实现》的知识宇宙,每一篇深入浅出的文章都是一颗既独立但又彼此强关联的星球,有必要提供一个传送门以便让大家即刻到达想要了解的文章。

专栏地址百图解码支付系统设计与实现
领域相关
支付行业黑话:支付系统必知术语一网打尽
跟着图走,学支付:在线支付系统设计的图解教程
支付交易的三重奏:收单、结算与拒付在支付系统中的协奏曲
在线支付系统的精英搭档:深入剖析收银核心与支付引擎的协同作战(一)
在线支付系统的精英搭档:深入剖析收银核心与支付引擎的协同作战(二)

技术专题
交易流水号的艺术:掌握支付系统的业务ID生成指南
揭密支付安全:为什么你的交易无法被篡改
金融密语:揭秘支付系统的加解密艺术
支付系统日志设计完全指南:构建高效监控和问题排查体系的关键基石
避免重复扣款:分布式支付系统的幂等性原理与实践
支付系统的心脏:简洁而精妙的状态机设计与核心代码实现
精确掌控并发:分布式环境下并发流量控制的设计与实现(一)
精确掌控并发:分布式环境下并发流量控制的设计与实现(二)
金融疆界:在线支付系统渠道网关的创新设计(一)文章来源地址https://www.toymoban.com/news/detail-804978.html

到了这里,关于精确掌控并发:固定时间窗口算法在分布式环境下并发流量控制的设计与实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 分布式调用与高并发处理 Zookeeper分布式协调服务

    单机架构 一个系统业务量很小的时候所有的代码都放在一个项目中就好了,然后这个项目部署在一台服务器上,整个项目所有的服务都由这台服务器提供。 缺点: 服务性能存在瓶颈,用户增长的时候性能下降等。 不可伸缩性 代码量庞大,系统臃肿,牵一发动全身 单点故障

    2024年02月12日
    浏览(61)
  • 第七章-分布式搜索引擎-ES:全文查询、分词查询、精确查询、地理坐标查询、组合查询(bool、funtion_score)以及RestApi

    DSL查询分类 全文查询、分词查询、非分词查询、地理坐标查询、组合查询 match_all 查询所有,不需要查询条件,固定写法_search 第一个hits就是命中的数据 ,total就是条数,第二个hits是source嘞   全文检索查询 我们不要整多个字段查询,参与的字段越多,查询速度越慢,如果有

    2024年01月16日
    浏览(79)
  • Redis高并发分布式锁

    针对单机环境下的并发访问,可以通过锁机制(Syschronized或独占锁等)来进行控制,使得一个资源在一段时间内只能被一个线程访问;但在多服务器的分布式环境下,并发访问同一个资源,可能会导致被同时修改或更新,原因在于juc包下的并发控制机制,都是基于JVM层面的,而

    2024年02月02日
    浏览(80)
  • 服务端⾼并发分布式结构演进之路

    应⽤(Application)/系统(System) 为了完成一整套服务的一个程序或相互配合的程序群 模块(Module)/组件(Component) 当应⽤较复杂时,为了分离职责,将其中具有清晰职责的、内聚性强的部分,抽象出概念,便于理解 分布式(Distributed) 分布式(Distributed)是指将计算、任务

    2024年02月13日
    浏览(94)
  • 4、Redis高并发分布式锁实战

    在分布式系统中,保证数据的一致性和避免竞争条件是至关重要的。分布式锁是一种常用的机制,而Redis作为一款高性能的内存数据库,提供了简单而强大的分布式锁方案。本文将深入探讨如何利用Redis高并发分布式锁来解决分布式系统中的并发控制问题,并提供实战案例。

    2024年01月18日
    浏览(54)
  • 分布式和高并发的详细介绍

    分布式系统和高并发性能是现代计算领域中的两个关键概念。随着互联网和计算技术的迅速发展,越来越多的应用需要能够处理大规模的数据和用户并发。在本文中,我们将深入介绍分布式系统和高并发性能的概念、特点、挑战和应对方法。 分布式系统是由多个独立的计算机

    2024年02月14日
    浏览(47)
  • 简述JMeter实现分布式并发及操作

    为什么要分布式并发? JMeter性能实践过程中,一旦进行高并发操作时就会出现以下尴尬场景,JMeter客户端卡死、请求错误或是超时等,导致很难得出准确的性能测试结论。 目前知道的有两个方法可以解决JMeter支撑高并发: 一是将JMeter部署在Linux服务器上,可以支撑的并发量

    2024年02月16日
    浏览(41)
  • 分布式集群与多线程高并发

      后台数据的处理语言有很多,Java 是对前端采集的数据的一种比较常见的开发语言。互联网移动客户端的用户量特别大,大量的数据处理需求应运而生。可移动嵌入式设备的表现形式   很多,如 PC 端,手机移动端,智能手表,Google  眼镜等。Server2client 的互联网开发模式比

    2024年02月08日
    浏览(45)
  • 设计高并发分布式锁架构的实用指南

    在面对Java超大并发需求时,设计一个高效的分布式锁架构是至关重要的。本文将为您提供一套清晰明了、实践方便的设计指南,以确保系统在高并发场景下能够稳定可靠地运行。 首先,了解业务需求对分布式锁的具体要求至关重要。考虑到系统的高并发性质,通常需要满足

    2024年01月24日
    浏览(52)
  • 分布式系统概念和设计——(事务与并发控制)

    事务与并发控制 简介 事务的目标是在多个事务访问对象以及服务器面临崩溃的情况下,保证所有由服务器管理的对象始终维持在一个一致的状态上 事务是由客户定义的针对服务器对象的一组操作,组成为一个不可分割的单元,由服务器执行 服务器必须保证整个事务被执行,

    2024年02月07日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包