Laravel 分布式应用程序的时间表

Laravel schedules on distributed app

我的应用程序 运行 位于负载平衡器后面的 3 台服务器上。因此它是无状态的,所有数据都存储在redis和MySQL.

如果我的机器 运行 正在运行 artisan cron 调度程序,我假设相同的任务将 运行 3 次。在每台机器上一次,因为不知道它们之间 运行 共享了什么,也就是数据库 table。

解决方案是什么?

edit: In recent versions of 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 是同步的,如果密钥已经存在,则 return 为 false,因此即使所有三个服务器都以完全相同的微秒执行,只有一个服务器将继续执行其余任务。

另一个常见选项是仅在集群中的单个服务器上启用 cron,或者为 cron 本身设置专用服务器。

如果您的 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: 我提供的代码是虚伪的伪代码,不是准确的代码。

Laravel 5.4 支持使用调度器 的多服务器设置(如果升级是一个选项)。

它使用与 ceejayoz 接受的答案类似的方法。

Instead of using the file system to store a lock file, we use the cache store to allow any server to lock/check scheduled events.

https://github.com/laravel/internals/issues/69