背景
随着互联网的发展,应用服务中的定时任务数量日益增加,常规的垂直应用架构已无法应对,分布式服务架构势在必行。同时,也迫切需要一个分布式任务调度系统来管理分布式服务中的定时任务。
单一应用架构
当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。此时,在该应用中的定时任务如果不多还好,但是一旦比较多,则意味着每次更改一个定时任务的执行时间,就需要重新部署一遍整个应用,导致整个应用停滞一段时间。
垂直应用架构
当访问量逐渐增大,单一应用增加机器带来的加速度越来越小,将应用拆分为互不相干的几个应用来提升效率。此时,相应的任务也会被垂直拆分,每次更改任务带来的影响相应减少。
分布式服务架构
当垂直应用越来越多,应用之间可能会出现不可避免的交互,此时,将核心业务抽取出来,形成单独的服务,各式各样的服务逐渐形成稳定的服务中心,使得前端应用能更快地响应多变的市场需求。此时,用于提高业务复用及整合的分布式服务框架是关键,同时,由于服务独立,则一般能做到定时任务独立的情况,因此,任务的更改对于整体系统的影响小之又小。
分布式任务调度
在分布式服务架构的基础上,由于独立业务的数量可能很多,此时如果定时任务单独在该服务中实现,很可能会出现难以管理的情况,且避免不了定时任务更改导致的业务重启,因此,一个独立的分布式任务调度系统是很必要的,可以用来全局统筹管理所有的定时任务,同时,将任务的配置单独抽离出来作为该分布式任务调度系统的功能,就能做到定时任务的更改不影响任何业务,也不影响整个系统。
架构设计
设计思想
以Dubbo核心,将调度单独抽象出来,成为一个调度中心,调度中心本身不承担实现任何业务逻辑,只是单纯依据调度配置来发起调度请求
将任务抽象成为ExecutorService,由任务执行者来实现具体的任务,并且负责接收调度请求并执行,这样设计可以将任务与调度中心完全解耦,提高整个系统的扩展性,方便接入
将调度中心对任务执行者的一些调用 *** 作提取出来,形成一个单独的管理控制台,可以用来查看任务执行情况,同时该管理控制台通过H5实现,并提供对外Restful API,方便扩展与接入
通过各种中间件,实现一些必须的 *** 作,例如告警,监控,日志收集统计等 *** 作,完全对整个系统安全性,稳定性的保障
调度中心集群通过Zookeeper存储每个Schedular的一致性HashCode,以此来分配Job与Schedular之间的关系:新增的Job将会通过每个Schedular的一致性HashCode获取其对应的Job数,依据Job数的大小以及Schedular的相关属性来计算每个Schedular的权重,根据权重的大小来确定当前新增的Job应该被分配到哪个Schedular上。
当新增Schedular之后,该新增的Schedular的Job正常为0,因此,正常状态下,该新增的Schedular的权重会比较大。
同时,调度中心通过Zookeeper对Schedular实现主备切换,确保系统稳定性
系统组成
Schedular
基于Quartz实现调度,提供对执行者 *** 作的接口,用于 *** 作任务调度配置,调度触发等 *** 作;自身不参与任务逻辑的实现,不会受限于任务
执行者
负责接收调度中心发起的调度请求,实现相应业务逻辑,完成任务执行,同时会对任务逻辑进行切面处理,记录相应日志并在任务结束后发送给调度中心
管理控制台
管理控制台负责展示任务状态,执行情况,任务执行日志等报表数据,同时可以通过管理控制台配置新增任务, *** 作任务的状态,暂停/恢复等;另外,提供对外Restful API与H5的接入
Dubbo Monitor
实时监控调度中心接口调用情况,统计调度频次,成功失败,QPS等,能通过这些报表数据来优化任务调度,优化系统
ELK
通过ELK(ElasticSearch+Logstash+Kibana)来收集调度中心以及各执行机的执行日志,并加以分析统计,形成报表,可以方便提供观察
Alarm
报警系统,通过Chronograf控制台配置告警规则,在出现问题时第一时间通过Kapacitor进行邮件与短信报警,可以有效提高错误提示的及时性并且降低错误发生到错误解决过程中消耗的时间,降低生产环境造成的损失,告警数据通过业务仪表盘获取。例如:可以配置线上机器的cpu当前使用率,设置阀值50%,策略为超过设置阀值时短信告警,此时当线上某台机器cpu超过50%时,即会发送短信告警
业务仪表盘
通过打点的方式,来实时收集接口监控数据,通过logstash传输到kafka,通过kafka再分发到jstorm进行处理,处理完之后再存储到influxdb,形成业务仪表盘,最后通过Grafana控制台产生监控报表
配置中心
整个系统各服务,通过配置中心统一管理相应配置,形成分布式配置管理机制,方便系统内各服务的配置一致性以及准确性
在配置完之后,就可以实现自己的任务逻辑了
接入之后,可以通过日志管理控制台线上实时查看任务执行状态
另外,由于有告警系统,在任务执行异常时,会产生告警邮件与短信,实时发送,告知任务接入者与相应研发人员
配置中心属性配置
特性
支持动态暂停/恢复任务
任务状态停止时,任务将不再被触发,若任务在执行过程中被暂停,则正在执行的任务不会被阻塞(由于任务执行结果状态中存在超时失败状态,因此如果点击暂停按钮时阻塞了当前正在执行的任务,会使当前任务的执行状态变为超时,不符合超时状态真正的意义),会延迟停止,即等到当前任务执行完再真正停止任务
调度中心基于Quartz实现,通过Zookeeper实现主备隔离,保证调度中心HA
当活跃节点宕机,冷备节点就会载入所有活跃节点中正在调度状态的任务,成为新的活跃节点,保证任务调度的准确执行
执行机支持集群部署,任务分布式执行,通过调度中心统一调度
执行机负载均衡,默认根据任务在某个执行机上的执行次数计算执行机调度权重,按照权重来选择本次任务调度分发给哪台执行机,实现负载均衡,可手动更改执行机选择策略
执行机集群方式,
failover,failfast,failsafe,failback,forking,默认为failover(故障切换),调用失败时,重试其他服务器;failfast(快速失败),只会发起一次调用,不会重试,失败立即报错;failsafe(失败安全),出现异常时,直接忽略;failback(失败恢复),调用失败时,定时重发,直到成功,重启会丢失; forking,并行调用多个执行机,只要一个成功即返回
分片任务,支持任务分片,通过参数发送给任务执行机,执行机可以通过判断参数来进行分片作业的开发,同时支持动态分片,以分片参数和执行机为纬度进行分片,支持动态扩容执行机以及分片参数
例如,某张订单表按照订单ID来进行简单纬度分片,且以取模3来进行分片,则可以设置三个分片参数,(0,1,2),执行机在通过context拿到其中的一个分片参数之后可以对该分片参数做判断,来做具体的数据 *** 作,例如当拿到的分片参数为0时,则对于0相应的分片做数据查询 *** 作,依次类推
再例如,某张订单表按照订单ID和Status来进行二维分片,ID取模以3来进行分片,状态以成功,失败两种状态来进行分片,此时就可以设置6个分片参数,({‘id’:0,’status’:0},{‘id’:1,’status’:0},{‘id’:2,’status’:0},{‘id’:0,’status’:1},{‘id’:1,’status’:1},{‘id’:2,’status’:1}),执行机在通过context拿到其中的一个分片参数之后,就可以对其json参数进行判断,来实现分片 *** 作
任务执行一致性,每次任务只会被一个执行机所执行;对于分片任务,在执行机集群部署时,一次任务调度将会广播触发对应集群中相应数量的执行器执行一次任务,同时传递分片参数,可根据分片参数开发分片任务。
当分片参数大于执行器数量时,将会按照执行器路由策略,使得当前分片任务的某个或者某几个执行机执行多个分片的任务
例如:当前分片任务分片参数为(a,b,c),当前任务执行机有3台(A,B,C)时,则会均匀随机得将分片参数发送给某一台执行机,且三台执行机一次只接收一个分片参数,做一次任务处理,即(a->A,b->B,c->C)|(a->A,b->C,c->B)|(a->B,b->A,c->C)|(a->B,b->C,c->A)|(a->C,b->A,c->B) |(a->C,b->B,c->A);
当任务执行机只有2台(A,B)时,每次任务调度时,某台执行机会收到两个分片参数,并分别处理这两个分片参数,即(a->A,b->B,c->A)|(a->A,b->B,c->B)|(a->B,b->A,c->A)|(a->B,b->A,c->B);
而当任务执行机大于分片参数个数,为4台(A,B,C,D)时,(a->A,b->B,c->C)|(a->A,b->C,c->D)|(a->A,b->D,c->B)| (a->B,b->C,c->D)|(a->B,b->D,c->A)|(a->B,b->A,c->C)|(a->C,b->A,c->B)|(a->C,b->B,c->D)| (a->C,b->D,c->A)|(a->D,b->A,c->B)|(a->D,b->B,c->C)|(a->D,b->C,c->A),而统计下来,不管是执行机数目大于或者等于或者小于分片参数数目,被分发给执行机的分片参数始终是保持一致的(每台执行机接收到的总的分片参数是均匀的)
告警系统,系统接入内部告警系统,任务失败时支持邮件,短信,钉钉,电话等告警
d性扩容缩容,调度中心将会实时探测任务执行机,因此一旦有执行机上线或者下线,都将会被探测到,而如果未被调度中心探测到,则可以进行手动探测执行机,而在探测到执行机之后,下次调度将会重新分配任务
任务依赖,支持配置任务依赖关系,当父任务在执行完成之后会自动触发子任务的执行例如:有两个任务,分别为A和B,而B的执行条件为确认A任务执行完,B才能执行,否则,B任务不执行,此时的依赖关系就是B任务依赖A任务,此时在A任务配置完之后,设置B任务为依赖任务,而依赖关系则是A;又例如有6个任务,分别是A1,A2,A3,A4,A5,B,而B任务的执行需要确保A1-5这5个任务都执行完,B任务才执行,此时,B的依赖关系就是B任务依赖于A1-5,此时在配置完A1-5这5个任务之后再设置B为依赖任务,依赖关系则是A1-5
支持运行时查看任务执行情况,任务数量,调用次数,执行器数量等统计信息异常执行恢复机制,有时会遇到不可控情况,即执行机在执行后的执行结果因为网络断开等不可控因素导致不能发送给调度中心,此时能通过异常执行恢复机制临时记录,在下次执行机正常启动时重试发送给调度中心调度手动触发手动执行,特殊需求下,可能会要求调度可以手动执行,例如调度任务失败之后可能需要手动执行一次调度来补偿
并行/串行策略,当定时时间远大于任务执行时间时,可以使用并行策略,任务异步调用执行,提高任务调度精确度;当任务执行时间可能大于定时时间,却需要任务按照某个定时规则定时调度时,可以使用串行策略,调度中心调度的当前任务的上一次触发,如果没有执行完,则当前执行机的下一次定时时间点时不会被触发,当且仅当任务执行结束,以防止某些持续性定时任务的时间不确定性导致异步触发时的数据混乱的情况发生,例如:某一任务的定时时间为10秒钟,但是任务本身可能会出现执行超过10秒的情况,而超过时,如果出现两个时间点的任务并行执行时会出现数据混乱的情况,此时就可以使用串行策略,确保当前执行机上一个任务未执行完,不会触发新的执行
支持调度接口数据监控,产生监控报表,便于观测。
总结
对于互联网公司来说,时间就是金钱,效率决定一切。本系统在接入到8月初将近3个月的时间内,表现不凡,调度了约100万次,给公司内部各服务实现任务调度提供了便利。
原文
登录到XXL-Job的管理后台,进入“调度中心”页面。
点击“新建任务”按钮,在d出的对话框中填写任务的基本信息,如任务名称、任务描述、执行器等。其中,执行器是指要执行任务的机器或服务器,需要在XXL-Job中预先配置好。
在“执行模式”中选择“BEAN模式”,在“JobHandler”中输入Python脚本的路径和文件名,例如“/usr/local/python_script/hellopy”。
在“JobHandler”中输入Python脚本的路径和文件名,例如“/usr/local/python_script/hellopy”。
在“JobParams”中输入Python脚本需要的参数,以逗号分隔。例如,如果Python脚本需要接收两个参数,则可以输入“param1,param2”。
点击“保存”按钮保存任务信息,然后点击“运行”按钮手动执行任务。
在执行任务时,XXL-Job会自动调用指定的Python脚本,并将参数传递给脚本。脚本的执行结果可以在XXL-Job的管理后台中查看。linux内核的三种主要调度策略:
1,SCHED_OTHER 分时调度策略,
2,SCHED_FIFO实时调度策略,先到先服务
3,SCHED_RR实时调度策略,时间片轮转
实时进程将得到优先调用,实时进程根据实时优先级决定调度权值。分时进程则通过nice和counter值决定权值,nice越小,counter越大,被调度的概率越大,也就是曾经使用了cpu最少的进程将会得到优先调度。
SHCED_RR和SCHED_FIFO的不同:
当采用SHCED_RR策略的进程的时间片用完,系统将重新分配时间片,并置于就绪队列尾。放在队列尾保证了所有具有相同优先级的RR任务的调度公平。
SCHED_FIFO一旦占用cpu则一直运行。一直运行直到有更高优先级任务到达或自己放弃。
如果有相同优先级的实时进程(根据优先级计算的调度权值是一样的)已经准备好,FIFO时必须等待该进程主动放弃后才可以运行这个优先级相同的任务。而RR可以让每个任务都执行一段时间。
相同点:
RR和FIFO都只用于实时任务。
创建时优先级大于0(1-99)。
按照可抢占优先级调度算法进行。
就绪态的实时任务立即抢占非实时任务。
所有任务都采用linux分时调度策略时:
1,创建任务指定采用分时调度策略,并指定优先级nice值(-20~19)。
2,将根据每个任务的nice值确定在cpu上的执行时间(counter)。
3,如果没有等待资源,则将该任务加入到就绪队列中。
4,调度程序遍历就绪队列中的任务,通过对每个任务动态优先级的计算权值(counter+20-nice)结果,选择计算结果最大的一个去运行,当这个时间片用完后(counter减至0)或者主动放弃cpu时,该任务将被放在就绪队列末尾(时间片用完)或等待队列(因等待资源而放弃cpu)中。
5,此时调度程序重复上面计算过程,转到第4步。
6,当调度程序发现所有就绪任务计算所得的权值都为不大于0时,重复第2步。
所有任务都采用FIFO时:
1,创建进程时指定采用FIFO,并设置实时优先级rt_priority(1-99)。
2,如果没有等待资源,则将该任务加入到就绪队列中。
3,调度程序遍历就绪队列,根据实时优先级计算调度权值(1000+rt_priority),选择权值最高的任务使用cpu,该FIFO任务将一直占有cpu直到有优先级更高的任务就绪(即使优先级相同也不行)或者主动放弃(等待资源)。
4,调度程序发现有优先级更高的任务到达(高优先级任务可能被中断或定时器任务唤醒,再或被当前运行的任务唤醒,等等),则调度程序立即在当前任务堆栈中保存当前cpu寄存器的所有数据,重新从高优先级任务的堆栈中加载寄存器数据到cpu,此时高优先级的任务开始运行。重复第3步。
5,如果当前任务因等待资源而主动放弃cpu使用权,则该任务将从就绪队列中删除,加入等待队列,此时重复第3步。
所有任务都采用RR调度策略时:
1,创建任务时指定调度参数为RR,并设置任务的实时优先级和nice值(nice值将会转换为该任务的时间片的长度)。
2,如果没有等待资源,则将该任务加入到就绪队列中。
3,调度程序遍历就绪队列,根据实时优先级计算调度权值(1000+rt_priority),选择权值最高的任务使用cpu。
4,如果就绪队列中的RR任务时间片为0,则会根据nice值设置该任务的时间片,同时将该任务放入就绪队列的末尾。重复步骤3。
5,当前任务由于等待资源而主动退出cpu,则其加入等待队列中。重复步骤3。
系统中既有分时调度,又有时间片轮转调度和先进先出调度:
1,RR调度和FIFO调度的进程属于实时进程,以分时调度的进程是非实时进程。
2,当实时进程准备就绪后,如果当前cpu正在运行非实时进程,则实时进程立即抢占非实时进程。
3,RR进程和FIFO进程都采用实时优先级做为调度的权值标准,RR是FIFO的一个延伸。FIFO时,如果两个进程的优先级一样,则这两个优先级一样的进程具体执行哪一个是由其在队列中的未知决定的,这样导致一些不公正性(优先级是一样的,为什么要让你一直运行),如果将两个优先级一样的任务的调度策略都设为RR,则保证了这两个任务可以循环执行,保证了公平。
Ingo Molnar-实时补丁
为了能并入主流内核,Ingo Molnar的实时补丁也采用了非常灵活的策略,它支持四种抢占模式:
1.No Forced Preemption (Server),这种模式等同于没有使能抢占选项的标准内核,主要适用于科学计算等服务器环境。
2.Voluntary Kernel Preemption (Desktop),这种模式使能了自愿抢占,但仍然失效抢占内核选项,它通过增加抢占点缩减了抢占延迟,因此适用于一些需要较好的响应性的环境,如桌面环境,当然这种好的响应性是以牺牲一些吞吐率为代价的。
3.Preemptible Kernel (Low-Latency Desktop),这种模式既包含了自愿抢占,又使能了可抢占内核选项,因此有很好的响应延迟,实际上在一定程度上已经达到了软实时性。它主要适用于桌面和一些嵌入式系统,但是吞吐率比模式2更低。
4.Complete Preemption (Real-Time),这种模式使能了所有实时功能,因此完全能够满足软实时需求,它适用于延迟要求为100微秒或稍低的实时系统。
实现实时是以牺牲系统的吞吐率为代价的,因此实时性越好,系统吞吐率就越低。
任何领域,革命性的碾压式推陈出新并不是没有,但是概率极低,人们普遍的狂妄在于,总是认为自己所置身的环境正在发生着某种碾压式的变革,但其实,最终大概率不过是一场平庸。
作者 | dog250
责编 | 刘静
出品 | CSDN博客
但凡懂Linux内核的,都知道Linux内核的CFS进程调度算法,无论是从2623将其初引入时的论文,还是各类源码分析,文章,以及Linux内核专门的图书,都给人这样一种感觉,即 CFS调度器是革命性的,它将彻底改变进程调度算法。 预期中,人们期待它会带来令人惊艳的效果。
然而这是错觉。
人们希望CFS速胜,但是分析来分析去, 却只是在某些方面比O(1)调度器稍微好一点点 。甚至在某些方面比不上古老的44BSD调度器。可是人们却依然对其趋之若鹜,特别是源码分析,汗牛塞屋!
为什么CFS对别的调度算法没有带来碾压的效果呢?
首先,在真实世界,碾压是不存在的,人与人,事与事既然被放在了同一个重量级梯队比较,其之间的差别没有想象的那么大,根本就不在谁碾压谁。不能被小说电视剧蒙蔽了,此外,徐晓冬大摆拳暴打雷雷也不算数,因为他们本就不是一个梯队。
任何领域,革命性的碾压式推陈出新并不是没有,但是概率极低,人们普遍的狂妄在于,总是认为自己所置身的环境正在发生着某种碾压式的变革,但其实,最终大概率不过是一场平庸。
最终就出现了角力,僵持。
其次,我们应该看到,CFS调度器声称它会给交互式进程带来福音,在这方面CFS确实比O(1)做得好,但是惊艳的效果来自于粉丝的认同。Linux系统交互进程本来就不多,Linux更多地被装在服务器,而在服务器看来,吞吐是要比交互响应更加重要的。
那么以交互为主的Android系统呢?我们知道,Android也是采用了CFS调度器,也有一些事BFS,为什么同样没有带来惊艳的效果呢?
我承认,2008年前后出现CFS时还没有Android,等到Android出现时,其采用的Linux内核已经默认了CFS调度器,我们看下Android版本,Linux内核版本以及发行时间的关系:
Linux内核在2623就采用了CFS调度器。所以一个原因就是没有比较。Android系统上,CFS没有机会和O(1)做比较。
另外,即便回移一个O(1)调度器到Android系统去和CFS做AB,在我看来,CFS同样不会惊艳,原因很简单,Android系统几乎都是交互进程,却前台进程永远只有一个,你几乎感受不到进程的切换卡顿,换句话说,即便CFS对待交互式进程比O(1)好太多,你也感受不到,因为对于手机,平板而言,你切换 APP 的时间远远大于进程切换的时间粒度。
那么,CFS到底好在哪里?
简单点说,CFS的意义在于, 在一个混杂着大量计算型进程和IO交互进程的系统中,CFS调度器对待IO交互进程要比O(1)调度器更加友善和公平 。理解这一点至关重要。
其实,CFS调度器的理念非常古老,就说在业界,CFS的思想早就被应用在了磁盘IO调度,数据包调度等领域,甚至最最古老的SRV3以及43BSD UNIX系统的进程调度中早就有了CFS的身影,可以说,Linux只是 使用CFS调度器 ,而不是 设计了CFS调度器 !
就以43BSD调度器为例,我们看一下其调度原理。
43BSD采用了1秒抢占制,每间隔1秒,会对整个系统进程进行优先级排序,然后找到优先级最高的投入运行,非常简单的一个思想,现在看看它是如何计算优先级的。
首先,每一个进程j均拥有一个CPU滴答的度量值Cj,每一个时钟滴答,当前在运行的进程的CPU度量值C会递增:
当一个1秒的时间区间ii过去之后,Cj被重置,该进程jj的优先级采用下面的公式计算:
可以计算,在一个足够长的时间段内,两个进程运行的总时间比例,将和它们的Base_PrioBase_Prio优先级的比例相等。
43BSD的优先级公平调度是CPU滴答驱动的。
现在看Linux的CFS,CFS采用随时抢占制。每一个进程j均携带一个 虚拟时钟VCj ,每一个时钟滴答,当前进程k的VCk会重新计算,同时调度器选择VC最小的进程运行,计算方法非常简单:
可见, Linux的CFS简直就是43BSD进程调度的自驱无级变速版本!
如果你想了解CFS的精髓,上面的就是了。换成语言描述,CFS的精髓就是 “ n个进程的系统,任意长的时间周期TT,每一个进程运行T/n的时间! ”
当然,在现实和实现中,会有80%的代码处理20%的剩余问题,比如如何奖励睡眠太久的进程等等,但是这些都不是精髓。
综上,我们总结了:
所以无论从概念还是从效果,Linux CFS调度器均没有带来令人眼前一亮的哇塞效果。但是还缺点什么。嗯,技术上的解释。
分析和解释任何一个机制之前,必然要先问,这个机制的目标是什么,它要解决什么问题,这样才有意义。而不能仅仅是明白了它是怎么工作的。
那么Linux CFS调度器被采用,它的目标是解决什么问题的呢?它肯定是针对O(1)算法的一个问题而被引入并取代O(1),该问题也许并非什么臭名昭著,但是确实是一枚钉子,必须拔除。
O(1)调度器的本质问题在于 进程的优先级和进程可运行的时间片进行了强映射!
也就是说,给定一个进程优先级,就会计算出一个时间片与之对应,我们忽略奖惩相关的动态优先级,看一下原始O(1)算法中一个进程时间片的计算:
直观点显示:
针对上述问题,26内核的O(1)O(1)引入了双斜率来解决:
直观图示如下:
貌似问题解决了,但是如果单单揪住上图的某一个优先级子区间来看,还是会有问题,这就是相对优先级的问题。我们看到,高优先级的时间片是缓慢增减的,而低优先级的时间片却是陡然增减,同样都是相差同样优先级的进程,其优先级分布影响了它们的时间片分配。
本来是治瘸子,结果腿好了,但是胳臂坏了。
本质上来讲,这都源自于下面两个原因:
固定的优先级映射到固定的时间片。
相对优先级和绝对优先级混杂。
那么这个问题如何解决?
优先级和时间片本来就是两个概念,二者中间还得有个变量沟通才可以。优先级高只是说明该进程能运行的久一些,但是到底久多少,并不是仅仅优先级就能决定的,还要综合考虑,换句话距离来说,如果只有一个进程,那么即便它优先级再低,它也可以永久运行,如果系统中有很多的进程,即便再高优先级的进程也要让出一些时间给其它进程。
所以,考虑到系统中总体的进程情况,将优先级转换为权重,将时间片转换为份额,CFS就是了。最终的坐标系应该是 权重占比/时间片 坐标系而不是 权重(或者优先级)/时间片 。应该是这个平滑的样子:
看来,Linux CFS只是为了解决O(1)O(1)中一个 “静态优先级/时间片映射” 问题的,那么可想而知,它又能带来什么惊艳效果呢?这里还有个“但是”,这个O(1)O(1)调度器的问题其实在计算密集型的守护进程看来,并不是问题,反而是好事,毕竟高优先级进程可以 无条件持续运行很久而不切换 。这对于吞吐率的提高,cache利用都是有好处的。无非也就侵扰了交互进程呗,又有何妨。
当然,使用调优CFS的时候,难免也要遇到IO睡眠奖惩等剩余的事情去设计一些trick算法,这破费精力。
对了,还要设置你的内核为HZ1000哦,这样更能体现CFS的平滑性,就像它宣称的那样。我难以想象,出了Ubuntu,Suse等花哨的桌面发行版之外,还有哪个Linux需要打开HZ1000,服务器用HZ250不挺好吗?
关于调度的话题基本就说完了,但是在进入下一步固有的喷子环节之前,还有两点要强调:
在CPU核数越来越多的时代,人们更应该关心 把进程调度到哪里CPU核上 而不是 某个CPU核要运行哪个进程 。
单核时代一路走过来的Linux,发展迅猛,这无可厚非,但是成就一个 *** 作系统内核的并不单单是技术,还有别的。这些当然程序员们很不爱听,程序员最烦非技术方面的东西了,程序员跟谁都比写代码,程序员特别喜欢喷领导不会写代码云云。
Linux在纯技术方面并不优秀,Linux总体上优秀的原因是因为有一群非代码不明志的程序员在让它变得越来越优秀,另一方面还要归功于开源和社区。Linux的学习门槛极低,如果一个公司能不费吹灰之力招聘到一个Linux程序员的话,那它干嘛还要费劲九牛二虎之力去招聘什么高端的BSD程序员呢?最终的结果就是,Linux用的人极多,想换也换不掉了。
但无论如何也没法弥补Linux内核上的一些原则性错误。
Linux内核还是以原始的主线为base,以讲Linux内核的书为例,经典的Robert Love的《Linux内核设计与实现》,以及《深入理解Linux内核》,在讲进程调度的时候,关于多核负载均衡的笔墨都是少之又少甚至没有,如此经典的著作把很多同好引向了那万劫不复的代码深渊。于是乎,铺天盖地的CFS源码分析纷至沓来。
但其实,抛开这么一个再普通不过的Linux内核,现代 *** 作系统进入了多核时代,其核心正是在cache利用上的革新,带来的转变就是进程调度和内存管理的革新。review一下Linux内核源码,这些改变早就已经表现了出来。
可悲的是,关于Linux内核的经典书籍却再也没有更新,所有的从传统学校出来的喜欢看书学习的,依然是抱着10年前的大部头在啃。
>任务调度是日常开发中非常常见的一个业务场景。目前系统采用的是Quartz框架进行任务调度,但与业务系统耦合性太高,极端情况下,耗时任务甚至会耗尽调度线程,导致大量任务堵塞与延迟。也可能拖垮业务系统。
另一方面Quartz没有后台管理界面。问题定位排查 手动触发任务,随时修改任务执行时间等较难。
1:有良好的后台管理页面。
2:任务动态分片,数据庞大的大任务处理。
3:任务阻塞,路由及报警策略。
4:开发文档和社区完善。
此次主要对xxl-job(大众),Elastic-job(当当),staturn(唯品会),lts,TBSchedule(阿里)五种调度框架进行综合对比。
e-Job和xxl-job都有广泛的用户基础和的技术文档,都能满足定时任务的基本功能需求。
e-Job已有2年左右没更新,社区也已经不维护,后续稳定性无法保证。
xxl-job 文档详细,且任务报警、阻塞及路由策略丰富,社区完善。
因此采用xxl-job调度框架。
-路由策略:- 阻塞处理策略 -子任务:-失败报警 -分片广播 & 动态分片 等
这里就不照搬官网参数,参考: >
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)