【间接经验】高性能调度系统设计总结

2024-09-05 09:52

本文主要是介绍【间接经验】高性能调度系统设计总结,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原文

他人的间接经验 -> 自己的直接经验

调度模块在很多系统中都是常用的模块,比如实习生的每天签到邮件,预约银行的业务短信,学习通的上课通知,腾讯视频push中台的任务下发,调度系统在中间起到关键作用。

用户画像:圈一群人

业务场景:短信验证码、优惠券等营销活动消息通知短信、预约银行的业务短信、团课预约上课通知、推荐内容、app里的通知、消息箱、私信

端触达:短信、微信的服务通知、app的通知与消息箱、手机消息通道

用户:用户实操行为、感兴趣的那群人

什么是调度

本质就是通过一些自定义策略,定时或者周期性的去触发某些事件和下游进行一次通信

通用流程

调度行为可以抽象成以下几步:

1.任务生成。

2.任务存储。

3.任务触发。

4.路由实例。

如果能做好这几步,那么一个高性能的调度系统也就诞生了,而每一步的技术选型,都和未来系统想要达成的目标(高精度,高可用),有着密不可分的关系,下面我会针对这几步进行分析。

任务生成

1.单次任务生成

2.周期性任务生成:周期性任务生成类似于打点计时器。每当任务触发时,系统会计算出未来需要触发的任务时间列表。例如,对于每小时执行的任务,系统会在第二天生成24个整点任务。

3.推送系统任务生成:对于推送系统任务,系统会根据用户过去的行为画像预测其最有可能点击的时间区间。在第二天到来之前,系统会预先计算并生成第二天各个时间点的推送任务。

任务存储

任务存储的思考分为两个方面,第一是用什么数据结构存,第二是用什么类型的db去存。

对于高性能调度系统而言,主要看重范围查询效率查询的qps,分布式锁的表现。

小总结

对于扫表+触发的模式,其实本质是需要一个能高速范围查询的数据结构。

B+树和跳表都是高效的能范围查询数据结构,但它们各自适用于不同的场景。B+树更适合于磁盘存储和范围查询,而跳表则更适合于内存中的快速查找和分布式环境

数据库分析

我们举出基于内存的数据库的代表Redis和基于磁盘的数据库MySQL进行分析。

Redis VS MySQL

1.Redis的底层是跳表,而MySQL的底层是B+树。就范围查询而言,两者不分伯仲

2.但Redis没有事务概念,内部实现是单线程,没有锁竞争,再加上IO多路复用的特性和极其高效的数据结构实现,就注定单机qps要远超过mysql。

3.mysql在这个场景下的优势则是有持久化能力,不容易丢数据,redis可能在RDB和AOF的过程中有丢数据的可能性。

因此,mysql和redis都有可能是作为存储任务的数据库,需要区分场景。

分布式锁的分析

在集群模式下,哪一台实例去执行任务扫描这一过程依赖于分布式锁的抢占。

基于MySQL实现
基于Redis实现

总的而言,mysql的分布式锁实现简单,但性能低。redis实现稍微复杂,性能高,一般用redis的多一点。

任务触发

在构建高效、可靠的分布式任务调度系统时,我们需要考虑多个方面,触发包括定时扫描、状态更新、任务重试等关键环节。

定时扫描

触发的本质就是将数据从db加载进内存中,那么我们可以通过定时任务,按照一定时间间隔去加载。那么

1.谁来扫描?

2.扫描的时间间隔多少合理?

谁来扫描?

负责扫描的实例需将扫描到的任务进行下发,即发起RPC调用。

扫描的时间间隔多少合理?

扫描时间间隔的设定对于确保系统性能和精度至关重要。这个间隔应当基于系统所需的实时精度以及单次扫描所生成的任务数量来合理确定。盲目降低扫描时间间隔并不总是能提高精度;相反,它可能会导致效率降低,甚至增加数据延迟。

因此,在确定扫描时间间隔时,应考虑以下两点:

1.对于精度要求不高且任务量较大的场景:可以适当延长扫描时间间隔,以确保在单次扫描周期内能够完成所有任务的处理下发。这样可以减轻系统负担,提高整体效率。

2.对于精度要求高同时任务量也很大的场景:除了优化RPC处理流程外,还可以考虑改进数据存储结构,将数据分片分桶处理。通过为每个数据分片分配独立的扫描实例,可以实现并行处理,从而在保证高精度的同时提升系统响应速度。

综上所述,合理的扫描时间间隔应当根据具体应用场景和系统需求进行细致调整,以达到最佳的性能和精度平衡点。

状态更新

为了让我们的系统展现出卓越的性能和高精度,我们采用了异步方式来下发任务。异步处理的明显优势在于它能够使任务并发执行,无需等待响应,从而显著提升了系统的信息处理能力。然而,这也带来了一个问题:我们无法确切知道下游系统是否真正收到了任务。即便上游系统竭尽全力发送任务,如果下游系统接收不到,这些努力也将化为泡影。

因此,我们需要下游系统在成功接收到信息后,主动发送一个确认信号(ACK)。一旦系统接收到这个ACK,我们就能记录下触发时间和执行时间等相关信息,以便后续的任务重试模块进行相应的处理。

考虑到任务是并发下发的,返回的信息量可能会非常庞大,每条返回信息都可能触发一次远程过程调用(RPC),这无疑会大量消耗连接资源。为了解决这个问题,我们引入了队列机制

image.png

通过这种方式,我们成功地实现了连接复用和即时响应的双重效果这也是一个写聚合的思想。

这种思想源于Kafka提供的Micro-Batch的概念,他会将相同Topic和Partition的消息聚合成一个批次,然后一次性发送到Kafka集群。

任务重试

上文我们分析了如何让海量任务下发,但仍然做不到能让调度系统拥有可靠性。在分布式环境下,服务器可能因为网络延迟,服务器故障,资源竞争等原因,任务执行可能会失败。那么如何处理这些失败的任务呢?

其实这个问题可以拆解成几个小任务:

1. 如何检测到失败的任务?
2. 如何定义一个失败的任务?
3. 检测到失败任务以后的重试策略?

重试策略分为重试次数和重试间隔

每次重试完成,我们需要去更新这个已经重试次数,并检测他是否等于最大重试次数,之所有有这个最大重试次数,是为了防止他无限重试,造成重试风暴,而超过这个最大重试次数的,我们可以把它塞入死信队列中,让负责这个任务的人手动的去处理。

路由实例

优秀系统的设计

xxl-job的实现

内存中的时间轮算法+MySQL

XXL-JOB是一款知名的分布式任务调度框架,它采用内存中的时间轮算法结合MySQL作为持久化存储来管理调度任务,其调度粒度精准至秒级

时间轮分为单级时间轮多级时间轮。xxl-job并没有像kafka那样采用多级时间轮,主要是因为设计理念的不同,他为了简化设计,并且单级时间轮已经满足大部分任务调度的需求。

总体而言,XXL-JOB采用内存结合MySQL的部署方式简单易行,无需额外引入中间件。这种设计在追求调度精度的同时牺牲了一定的水平扩展性。对于任务量适中的场景而言,它仍然是一个值得考虑的优秀调度框架选项。

腾讯视频push中台的实现

腾讯视频push中台为了应对海量的并发,牺牲了调度的精度,以redis作为db,ZSet(跳表)作为底层数据结构来支持任务的范围查询。

Redis的高精度版本实现

分治思想:分片分桶,与多级时间轮类似拆分思想,分而治之,HashMap、LongAddr也使用类似思想。

调度的精度:若使用MQ的延时消息和并发消费,是否也是一种可行的方案?如Kafka、RocketMQ、Pulsar

分片

为了实现更高精度的Redis调度,我们需要确保跳表中的数据量保持在合理范围内。过多的数据可能导致内存占用过高、成本不足以及读写响应时间变长等问题(大Key问题)。因此,为了降低Redis访问的响应时间(即提高精度),我们对数据进行分片处理,使调度器每次只需扫描一个分片的数据。

如下图:

image.png

我们可以把一天的数据分为多个分钟级别的数据,虽然搜索的时间复杂度仍为O(logN),但由于N大大减小,搜索效率得到提高,响应速度更快。

然而,这仍然无法解决一个问题:如果某个实例通过抢锁方式获得某一分钟分片的扫描权限,但该分钟内的数据量仍然很大,可能会导致实例的线程数不足,无法实现并发处理。

分桶

为了解决这个问题,我们可以采用分桶策略,将这一分钟的数据划分为多个bucket。

在集群模式的调度器下,每个实例竞争的是各个bucket的锁,获得锁后,只需扫描相应分桶的数据。这种方法可以实现每分钟级别的tasklist调度,多台机器可以同时扫描和下发,避免了单个实例线程不足的问题。

如下图:

image.png

若即使分成三个桶,数据量仍然过大,我们可以引入一个决策服务来监控任务的延时情况。如果任务的延时率持续较高,可以根据实际情况动态调整分桶数量,从而更好地满足实际需求。

总结

本文详细探讨了调度模块在多种系统中的应用及其重要性,并深入分析了调度系统的通用流程,包括任务生成、任务存储、定时扫描和路由实例等关键步骤

文章针对每个步骤的技术选型进行了探讨,并结合实际系统(如XXL-JOB和腾讯视频push中台)进行了案例分析。此外,还讨论了各种路由算法的实现及其适用场景。

总的来说,一个高性能的调度系统需要综合考虑任务生成策略、存储数据结构的选择、数据库选型、分布式锁的实现以及定时扫描的机制等多个方面。通过合理的技术选型和系统设计,可以实现高精度和高可用的调度目标。同时,根据具体的应用场景和需求,灵活调整调度策略和路由算法,以达到最佳的性能和效率平衡点。

这篇关于【间接经验】高性能调度系统设计总结的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1138630

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

基于人工智能的图像分类系统

目录 引言项目背景环境准备 硬件要求软件安装与配置系统设计 系统架构关键技术代码示例 数据预处理模型训练模型预测应用场景结论 1. 引言 图像分类是计算机视觉中的一个重要任务,目标是自动识别图像中的对象类别。通过卷积神经网络(CNN)等深度学习技术,我们可以构建高效的图像分类系统,广泛应用于自动驾驶、医疗影像诊断、监控分析等领域。本文将介绍如何构建一个基于人工智能的图像分类系统,包括环境

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟 开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚 第一站:海量资源,应有尽有 走进“智听

MySQL高性能优化规范

前言:      笔者最近上班途中突然想丰富下自己的数据库优化技能。于是在查阅了多篇文章后,总结出了这篇! 数据库命令规范 所有数据库对象名称必须使用小写字母并用下划线分割 所有数据库对象名称禁止使用mysql保留关键字(如果表名中包含关键字查询时,需要将其用单引号括起来) 数据库对象的命名要能做到见名识意,并且最后不要超过32个字符 临时库表必须以tmp_为前缀并以日期为后缀,备份

【区块链 + 人才服务】可信教育区块链治理系统 | FISCO BCOS应用案例

伴随着区块链技术的不断完善,其在教育信息化中的应用也在持续发展。利用区块链数据共识、不可篡改的特性, 将与教育相关的数据要素在区块链上进行存证确权,在确保数据可信的前提下,促进教育的公平、透明、开放,为教育教学质量提升赋能,实现教育数据的安全共享、高等教育体系的智慧治理。 可信教育区块链治理系统的顶层治理架构由教育部、高校、企业、学生等多方角色共同参与建设、维护,支撑教育资源共享、教学质量评估、

搭建Kafka+zookeeper集群调度

前言 硬件环境 172.18.0.5        kafkazk1        Kafka+zookeeper                Kafka Broker集群 172.18.0.6        kafkazk2        Kafka+zookeeper                Kafka Broker集群 172.18.0.7        kafkazk3