我的应用在负载均衡器后面的3台服务器上运行。因此它是无状态的,所有数据都存储在redis和MySQL中。
如果我的机器正在运行工匠cron调度程序,我假设相同的任务将运行3次。一旦在每台机器上,因为不知道它们之间共享的是什么,也就是数据库表。
有哪些解决方案?
答案 0 :(得分:6)
编辑:在最新版本的Laravel中,this is now built-in。
$schedule->command('foo:bar')->onOneServer();
我们在Artisan命令中执行此操作,该命令应仅在每个cron执行的一个服务器上运行:
public function handle()
if(!Cache::add(get_class($this), true, 0.5)) {
return false;
}
Cache::add
是同步的,如果密钥已经存在,则返回false,因此即使所有三台服务器都以完全相同的微秒执行,也只有一台服务器将继续执行剩下的任务。
另一个常见的选择是在群集中的单个服务器上启用cron,或者为cron本身提供专用服务器。
答案 1 :(得分:2)
如果您的redis服务器在服务器之间共享,您可以创建一些逻辑,例如选择领导者应用服务器。
您的应用逻辑应该在处理之前检查领导者。示例代码段:
if(redis.get("LEADER").equals(currentappserver))
process();
else if(redis.get("LEADER")==null && selectLeader()) -> a lua script call.
process();
因为redis是单线程的,所以在lua脚本中写一个像这个片段的逻辑:
selectLeader()
if redis.get("LEADER")==null
redis.set("LEADER",current_node)
return true;
else
return false;
它将是原子的,并且始终只有一个领导者线程可用。
P.s:我提供的代码是vauge伪代码,而不是确切的代码。
答案 2 :(得分:0)
如果升级是一个选项,Laravel 5.4支持使用调度程序进行多服务器设置。
它使用与ceejayoz接受的答案类似的方法。
我们使用缓存存储来允许任何服务器锁定/检查预定事件,而不是使用文件系统来存储锁文件。