资源预览内容
第1页 / 共11页
第2页 / 共11页
第3页 / 共11页
第4页 / 共11页
第5页 / 共11页
第6页 / 共11页
第7页 / 共11页
第8页 / 共11页
第9页 / 共11页
第10页 / 共11页
亲,该文档总共11页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
新型计划任务:以接形式实现的计划任务1.31.1 这所说的计划任务计划任务主要负责处理些耗时的操作,或者户触发的作业。有些会称它为后台任务,或者推送作业,又或者定时任务。这时则统称为:计划任务。例如,当你发布条微信朋友圈后需要通知上百个好友时;当条后台的推荐资讯需要推送到每个户的客户端时;当需要将本地的静态资源如图同步到CDN时。显然这些动则需要分钟级别的操作,不应该在客户端调接时同步处理(但让我惊讶的是现实真的有会这么做!),又或者户触发需要后台处理(但更让我惊讶的是竟然也有系统是在户请求时附带进处理,且还是国内某个知名的会员中!)。这不仅仅是提供实现计划任务的约束和机制,更多的是引导家更好地应对此类问题。1.31.2 计划任务的关键环节(1)触发先,是何时何地由何户产条待执的计划任务,我们可以把这个场景点称为个触发点。通常的做法,我们会先纪录下此触发点的场景信息,并放到个队列,以便等待计划任务消费。(2)调度其次,是通过何种机制进计划任务的调度。这不仅有技术层的问题,还有业务的问题,如每次批量处理多少,间隔多少,是否需要失败重试等等?(3)消费最后,则是具体的计划任务执,以完成必要的操作,也称为消费。很多传统的做法,都是把这些操作和接混在起的,这,PhalApi则会以种更为明朗的式来实现,从底上,持更多的调度式和触发机制。1.31.3 传统的计划任务如果以图鳖之,上图虽然简化,但可以很好地说明传统计划任务的结构体系。即:很多项都是使内嵌的式来包含计划任务,这样明显会把接服务系统和后台计划任务混在起,增加了系统间的耦合性。虽然项可以忍受或者适合这种混合,但是出于长远考虑,进有意识地分解还是很有好处的。且这种混合潜意识下又让开发员不加判断就进调,这会严重增加接的反应时间。我曾睹个接耗时了近36秒之久,在对这个旧系统的接进番排查后,原来是这个接在发布后对上百个好友做了通知推送导致产了上百条insert语句。(1)传统的调度式我们重点关注下传统计划任务的调度式,在过去,我们通常会有两种式:种是启动死循环的进程,另种是启动个crontab之类的定时任务。当然,上述的在接请求时同步进调度也算种式,但不是正规的做法。如果采死循环的式,我们还需要考虑代码更新升级后,对脚本的重启,以便载新的代码。如果是sh循环调PHP脚本,则可以忽略。1.31.4 新型的计划任务(1)以接的形式提供计划任务服务PhalApi中最具特的做法是,将计划任务的执消费实现,以接形式来提供。这样的好处在于,我们作为接开发员,可以以熟悉的式来进计划任务的开发。但更的得益在于,将计划任务通过接的形式提供后,我们会看到更为阔的使场景:我们可以使MQ队列消费,可以同步请求也可以异步请求。(2)系统架构我们所做的,不仅仅只是把原来混合型的代码作简单分解,如下:是以种更为正统的做法,为此我们添加了些必要的节点来设计此构架。新的实现式下的体系结构如下:节点说明在上图中,应节点还是我们的接系统;MQ队列则是于存放待消费的场景信息,同其他的MQ样;计划任务则可以分为两部分,API接实现和任务调度。计划任务这两部分,物理部署上可以合在起,也可以分开,这取决于应系统是采分布式的做法,还是单的服务器。执流程由上图可以看出,个完整的计划任务流程为:1、应产条新的计划任务,并存放于MQ队列2、计划任务定时或者不停扫描新的计划任务;若有,则进调度3、计划任务API完成需要的作,并将结果返回调度器(3)单个添加,批量处理这只持单个MQ添加,处理则是批量的,且每批处理的数据可指定配置。(4)MQ共享论是分布式还是本地体化,MQ队列都应该是可以共享访问的,以便为应节点、计划任务调度节点所访问,如下图所:选redis MQ因为MQ作为频繁读写的媒介,应该优先使效缓存来提系统的吞吐率以及增加并发的能。此外,作为临时次性的数据,使效缓存也是有好处的(但我们也需要考虑到数据丢失的情况)。且,为了持 单个添加,批量处理,第三缓存应该很好地持队列的操作。所以,redis是个不错的选择。如下,是redis简单的队列操作:$redis = new Redis();$redis-connect(127.0.0.1, 6300);$redis-lpush(test_key, www);$redis-lpush(test_key, phalapi);$redis-lpush(test_key, net);echo $redis-lpop(test_key), n;echo $redis-lpop(test_key), n;echo $redis-lpop(test_key), n;数据库MQ如果考虑到redis扩展不好安装,或者应喜欢使数据库来存放MQ,也是可以的。只需要SQL的些基本的操作语句便可做到FIFO。件MQ件MQ也是种式,但很少使。(5)更丰富的调度式接同步调度虽然也是同步调度,但是我们将计划任务隔离后,便于后发现此同步的计划任务影响到接的响应时间时,可以及时轻松地切换到后台异步处理的式。回归传统的调度我们也可以沿传统的做法,即使死循环的脚本调度,或者crontab类的定时任务。MQ队列消费既然我们以接服务的形式提供计划任务的操作,那么可以把同接的调度放置到同队列中进维护和消费。接异步调度当计划任务以接服务提供后,我们可以使另种免MQ的做法,即使接的异步调度。如下:这样既可以避免死循环带来的性能负载问题,也可以避免定时任务带来的延时问题,可以说异步调度是种折中完美的做法。但这也可能是种不负责任或者不安全的做法,因为我们法跟进异步计划任务的结果。本地调度和远程调度本地调度是指在执过程中构建模拟接的调须经过络请求,远程调度则是通过远程接请求来实现。如果把本地调度和远程调度,跟同步/异步组合起来,我们可以得到以下三种有意义的组合:本地同步调度远程同步调度远程异步调度(6)计划任务的划分service即类型明显地,接服务名称service即可作为计划任务划分的依据。不同的service作为不同的队列,不同类型的计划任务;相同的service则作为相同的队列相同的计划任务。接参数即参数接参数即可计划任务执时所需要的上下信息。1.31.5 PhalApi中计划任务的核设计解读(1)桥接模式 - 数据与为独变化为了给计划任务个执的环境,我们提供了 计划任务调度器 ,即:Task_Runner。每个计划任务需要调度的接是不样的,即不同的接服务决定不同的为;每个为需要的数据也不样,即不同的接参数决定不同的数据。然的,Task_Runner按照桥接模式,其充当的如下:然后,我们就可以这样各实现:(2)适配器模式 - 对象适配器和类适配器在对MQ进实现时,我们提供的Redis MQ队列、件MQ队列和DB MQ队列,都使了适配器模式,以重框架已有的功能。其中,Redis MQ队列和件MQ队列是属于对象适配器,DB MQ队列是类适配器。对于对象适配器,我们也提供了外部注,以便客户端在使时可以轻松定制扩展,当然也可以使默认的缓存。如下:这样以后,我们可以这样根据创建不同的MQ队列:/Redis MQ队列$mq = Task_MQ_Redis();/或$mq = Task_MQ_Redis(new PhalApi_Cache_Redis(array(host = 127.0.0.1/件MQ队列$mq = new Task_MQ_File();/或$mq = new Task_MQ_File(new PhalApi_Cache_File(array(path = /tmp/cache/DB MQ队列$mq = new Task_MQ_DB();/Array MQ队列$mq = new Task_MQ_Array();(3)模板法 - 本地和远程两种调度策略在完成底层的实现后,我们可以再来关注如何调度的问题,前可以有本地调度和远程调度两种式。本地调度:是指本地模拟接的请求,以实现接的调度远程调度:是指通过计划任务充当接客户端,通过请求远程服务器的接以完成接的调度为此,我们的设计演进成了这样:上图多了两个调度器的实现类,并且远程调度器会将远程的接请求功能委托给连接器来完成。(4)设计审视好了!让我们再回头审视这样的设计。先,我们在层,也就是规约层得到了很好的约定。不必过多地深理解计划任务内部的实现细节,我们也可以轻松得到这样的概念流程:计划任务调度器(Task_Runner)从MQ队列(Task_MQ)中不断取出计划任务接服务(PhalApi_Api)进消费。再下层,则是具体的实现,即我们所说的实现层。客户可以根据的需要进选取使,他们也可以扩展他们需要的MQ。重要的是,他们需要实现计划任务的接服务。根据爱因斯坦说的,要保持简单,但不要过于简单。所以,为了更好地理解计划任务的运过程,我们提供了简单的时序图:上图主要体现了两个操作流程:加MQ和MQ消费。其中,注意这两个流程是共享同个MQ的,否则不能共享数据。同时调度是会进循环式的调度,并且穷极之。(5)没有引法的原因我们在考虑是否需要提供法来创建计划任务调度器,或者MQ。但我们发现,设计是如此明了,不必要再引法来增加使的复杂性,因为存在组合的情况。且,对于后期客户端进扩展也不利。当我们需要启动个计划任务时,可以这样写:$mq = new Task_MQ_Redis();$runner = new Task_Runner_Local($mq);$runner-go(MyTask.DoSth);上简单的组合可以有:4种MQ * 2种调度 = 8种组合。所以,我们最后决定不使法,是把这种由组合的权利交给客户端。(6)失败重试与并发问题除了对计划任务使什么模式进探讨外,我们还需要关注计划任务其他运时的问题。个考虑的是失败重试,这点会发在远程调度中,因为接请求可能会超时。这时我们采的是失败轮循重试。即,把失败的任务放到MQ的最后,等待下批次的尝试。连接器在进请求时,也会进定次数的超时重试。这主要是为了预防接服务器崩溃后的计划任务丢失。另个则是并发的问题。这并没有过多地进加锁策略。是把这种需要的实现移交给了客户端。因为加锁会使得计划任务更为复杂,且有时不定需要使,如个计划任务只有个进程时,也就是单个死循环的脚本进程的情况。(7)客户端的使最后,客户端的使就很简单了:$mq = new Task_MQ_Redis();$taskLite = new Task_Lite();$taskLite-add(MyTask.DoSth, array(id = 888);W3Cschool(www.w3cschool.cn)最的技术知识分享与学习平台此篇内容来于w3cschool.cn站户上传并发布。
收藏 下载该资源
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号