关于滑动窗口算法的应用场景
算法原理
滑动窗口算法是一种基于双指针(又称滑动窗口)的算法,是一种常用的数据处理算法,通常用于解决数组或字符串中的子数组或子串问题。
滑动窗口算法的基本思想是使用两个指针left和right来定义一个窗口,窗口内包含满足特定条件的元素子序列,然后不断移动指针left和right来滑动窗口,以找到相应的子序列。
滑动窗口算法的具体步骤如下:
- 初始化左指针left和右指针right,使它们都指向序列的起始位置。
- 将窗口中的元素作为子序列进行处理,满足特定条件的子序列就是算法需要解决的问题。
- 调整指针left和right,使得窗口向右移动:一般来说,先right边界先扩张,到达指定的位置(根据情况来定),然后left开始扩张,直到指定的位置。
- 获得窗口内元素集合,执行业务逻辑,如记录最大值、最小值、求和等。
- 重复上述步骤,直到滑动窗口遍历完整个序列。
由此可见,滑动窗口算法通过定义一个窗口并随着特定条件单向移动,使能够快速找到所需的子序列。
该算法也可以分类如下:
- 固定窗口大小 —— 窗口大小是固定的,左右边界指针的扩张步长是固定的。
- 可变窗口大小 —— 允许窗口大小随问题而变化,并且可以针对不同的问题选择最优的窗口大小。
常见应用场景
算法的优点在于时间复杂度为O(n),其中n为数组或字符串的长度。同时,由于只需要维护一个滑动窗口,算法的空间复杂度也比较低,通常为O(1)。因此滑动窗口算法可以将嵌套循环的问题,转换为单层循环问题,降低时间复杂度,提高效率。其可解决的问题,一般有如下特点:
- 目标数据连续的、有序的、前后关联的数据集合。
- 窗口可以通过单向递增(如由左向右滑动)实现移动
编程中常见的应用场景如下:
- 业务接口限流模块,如电商秒杀限流、开放接口请求限流。
- 离线统计业务场景:根据时间、账号等维度排序,以固定滑窗方式渐进执行直到跑完。
- 算法题目如求解“无重复字符的最长子串”、“子数组的最大和”、“最长连续子数组”、“正数组中和为k的最长子数组”等,常见于针对字符串、数组、队列的运算。
离线任务
实际工作中会有很多非实时性的、可异步的计算场景,如数据对账、账号风险打分、账号打标签等等,下面拿数据对账作为例子。
按天做数据条数校对
该场景的校对算法主要依赖select conut(*),注意考虑数据量、数据库压力,评估时间窗口的大小(滚动步长),设计流程如下:
按天做数据对账
关于数据对账,一个对账执行周期包含以下几个步骤节点:
- 拉取原生数据
- 清洗
- 保存
- 对账
- 差异处理
当对账的数据非常大(亿级),那么在执行周期里,需要合理切分子任务,控制批次数据的量,避免过程中出现OOM(Out of memory) 。设计流程如下(注意图中的case2):
备注1:上图简单举例limit 50000,实际上并不建议如此的查询操作,因为limit数过大会产生明显数据库查询耗时,严重时会拖垮数据库。此处可考虑分段、多此执行以累计获得这50000条。
备注2:需要根据服务占用的内存、服务器性能来确定对账条数(上图示例50000条)。当服务分配4G以上内存时,可考虑区间为2560051200,建议采用多线程并发对账,线程数约服务器cpu数的12倍(需综合判断偏向于cpu密集型、IO密集型)。
限流场景
通常我们说的限流指代的是 限制到达系统的并发请求数,使得系统能够正常的处理 部分 用户的请求,来保证系统的稳定性,同时限流不可避免的会造成用户的请求变慢或者被拒的情况,从而会影响用户体验。这就要求有灵活的限流算法(可配置阈值),在用户体验和系统稳定性之间做平衡。
常见的限流算法有:
- 计数器
- 滑动窗口
- 漏斗算法
- 令牌桶算法
实际上,滑动窗口在限流方面并不是最理想的。