异曲同工的租约

简介:

问题描述

有这样一个需求:WordPress中有一个叫做wp-cron.php的文件,它负责做一些定时任务,例如定时发送博文,定时清理垃圾回复等。因为WordPress是运行在Web PHP环境下,不借助第三方工具,实现定时任务有一定的困难。它的思路是,每当博客有点击时,就总触发一次cron,为了不阻塞客户的正常访问,用到了fopensocket 发起一个异步cron请求,当cron页面收到这个请求的时候,就开始检查各种执行条件,如果条件满足,则从数据库中获取cron任务并执行。

这里的问题是,如果有两个用户同时点击了页面,同时触发了cron任务,如何保证只起一个cron?如何保证起了一个cron后,它不会退出,常驻后台?如何保证万一cron退出了,会有后备的cron能起来?

基本流程


对于每一个cron请求,按照下面的顺序执行: 
SELECT获取一个任务 
把这个任务从数据表中删除 
检查删除是否成功 
-如果删除成功,则开始执行SELECT到的任务 
-否则直接退出(有另外一个cron请求也在执行这个任务)

存在的问题


这种方法简单粗暴,很能解决问题,但是它有这样几个问题:

-顺序问题:SELECT取任务的顺序必须都一致。cron1取A、B;cron2取B、A,则可能两个cron都会先后主动退出,导致后台没有cron了。 
-开销问题:每次都会尝试起cron,意味着每次都会发起一次内部的http连接

如何解决


  1. 顺序问题:这个保证每次SELECT都是按照主键顺序取即可,或者按照某个行值唯一的列顺序执行即可。
  2. 开销问题:引入lease(租约)机制,每个cron job一旦启动,就会持有一个lease(3秒),每次执行完一个任务,就续一下自己的lease。任何cron希望启动的时候,必须先看一下lease是否过期,如果lease过期,则立即获取lease,并启动自己。
  3. 由于没有加锁,可能两个cron都抢到了lease,没关系,当他们处理任务的时候,会有一个主动放弃(见上面的流程说明)。这种情况比较罕见,不会影响性能。

缺陷


上面的方案,在特殊情况下还是有一些小缺陷: 
1. cron job中途异常退出后的3秒内,新的任务无法被执行。如果cron job异常退出3秒后,不再有新的请求到来,那么任务队列中堆积的任务将无人处理。

如果cron job异常退出的可能性比较低,则这不是一个很大的问题。如果需要确保任务总能被及时执行,可以考虑使用Linux系统自带的crontab,来定时触发PHP的Cron Job。

关于LEASE


分布式系统中,Lease的概念被广泛采用。当我们无法确切了解到彼此的行为时,我们可以依赖一套约定,来规范和预测彼此的行为,以保障系统处于一个一致的状态。所谓“一致的状态”,就是我们觉得正确、可以理解的状态。上文中,两个cron请求无法知道彼此的存在,通过Lease的方式,很好地达成了一致,不会出现两个cron job同时运行的窘境。

补记


PHP脚本的执行时间,是有限制的,即使在脚本执行之初调用了 ignore_user_abort 方法。该方法的语义是设置客户端断开连接时是否中断脚本的执行,并不能改变PHP脚本最长。控制PHP最大执行时长的,需要修改php-fpm、nginx等的配置,详细参考 这里这里 。不过,在脚本中,也是可以改变PHP的最大执行时间的,相关函数请参考set_time_limit()ini_set(“max_execution_time”, “45”),这里还有一篇小结。根据PHP官方文档,希望在脚本中设定最大执行时间的时候,必须保证php.ini配置中safe_mode=Off。一般默认改选项都是Off,所以你可以在脚本中设置一个无限长的脚本运行时间。不过,安全起见,不建议运行无限长的时间,而是应该在ini_get(“max_execution_time”)的基础上减去若干秒来运行,然后主动释放lease。

raywill
+关注
目录
打赏
0
2
2
1
5
分享
相关文章
查看Socket断开原因及加入心跳机制防止自动断开连接
一般情况下,前端页面连接WebSocket服务的时候都是通过Nginx等负载均衡,然后由Nginx去代理连接后端的socket服务。如果建立连接之后不做一些措施,那么可能会有各种各样的原因会导致socket断开。
2600 0
TCP重传与超时机制:解锁网络性能之秘
TCP重传与超时机制:解锁网络性能之秘
2018 0
TTL传输中过期原因,ttl传输中过期的解决办法(ttl传输中过期怎么解决)
A3: 实际上,TTL值需依据实际网络环境设定。过小的TTL值可能导致数据包过早丢弃,影响通信;反之,过大的TTL值则可能占用不必要的网络资源。因此,科学合理的TTL值设定是平衡通信效率与资源利用的关键。
1269 0
超时时间已到。超时时间已到,但是尚未从池中获取连接。出现这种情况可能是因为所有池连接均在使用,并且达到了最大池大小。
超时时间已到。超时时间已到,但是尚未从池中获取连接。出现这种情况可能是因为所有池连接均在使用,并且达到了最大池大小。
819 0
关于k8s 集群中证书期限及续约的一些笔记
嗯,k8s 集群CA 证书突然过期了,所有这里整理相关笔记 博文内容涉及: 如何确认证书是否过期 通过 kubeadm 批量续约证书 Demo 理解不足小伙伴帮忙指正
439 0
3.10.0-693.5.2内核nfs客户端租约过期挂死问题分析
## 现象 1. 边缘存储两个节点fileserver,glance挂载物理机上的挂载点均出现挂住无法访问 2. 从客户端抓包看,客户端内核间隔5s向服务端发送renew租约请求,服务端返回NFS4ERR_EXPIRED,即租约过期错误,从抓包现象看客户端一直向服务端发送相同的clientid renew请求,服务端一直返回租约过期错误,导致挂载点无法恢复 ![](https://ata2-img
1782 1
3.10.0-693.5.2内核nfs客户端租约过期挂死问题分析
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等