调度程序代理管理者模式 Scheduler Agent Supervisor Pattern

未匹配的标注

描述#

在分布式系统中,服务访问远程服务或资源是需要协调一系列行为的,这些行为包括故障处理,操作撤销,失败重试,异步调用等等。
这些行为集合叫调度程序代理管理者模式。这种模式可以分布式系统中增加弹性和灵活性。

背景和问题#

服务访问远程服务或资源是可能发生故障的。 例如网络崩溃,通信终端,资源无法访问,资源约束等情况。

何时使用#

在分布式环境中运行。有下面特征
1. 调用了远程服务或资源
2. 能以透明的方式处理通讯故障
3. 各个流程都支持异步机制。

解决方案#

liaoliaophp 调度程序代理管理者模式

成员#

  1. 远程服务或资源。
  2. 代理。负责调用远程服务或资源,包含错误处理和重试机制。
  3. 调度程序。负责执行工作流,记录状态到状态存储器,请求代理。
  4. 状态存储器。负责存储整个工作流状态的生命周期以及其他一些附加信息。
  5. 管理者。负责重试超时或异常的步骤(请求调度程序或维护状态存储器重试状态实现重试机制)和监控状态存储中每一个步骤的状态并且可能更新状态。

流程#

  1. 把获取远程资源的过程分成多个步骤。
  2. 各个步骤组合成一个管道或工作流。
  3. 调度器负责这个工作流程中的步骤,以适当的顺序执行,并记录任务的进度和步骤的状态 (未开始,运行中,完成)持久化到状态存储器中。
  4. 当一个步骤需要访问远程服务或资源时,调度程序调用 (通常采用异步调用) 代理程序,通过代理访问远程资源。
  5. 管理者负责重试和监控状态。

注意事项#

  1. 所有可能发生的故障都要测试覆盖。
  2. 每一个步骤都需要幂等。
  3. 状态存储器中需要持久化补偿事物所需要的所有信息。
  4. 监控的频率需要合适,不能成为性能开销。

具体实现#

实现流程#

liaoliaophp 聊聊php

结构中包含的角色#

  1. RemoteResource 远程资源
  2. Agent 代理
  3. Scheduler 调度程序
  4. SateStore 状态存储器
  5. Supervisor 管理者
  6. Crontab 定时任务 / 执行者

可用到的设计模式思维#

代理的角色就可以使用代理模式来实现。

最小可表达代码#

class RemoteResource 
{
    public function debug()
    {
        var_dump('我是远程资源...');
    }

}

class Agent
{
    public static function debug()
    {
        (new RemoteResource())->debug();
    }
}

class SateStore
{
    public function getWaitingTasks()
    {
        return [
            ['id' => 1, 'status' => 1],
            ['id' => 2, 'status' => 2],
        ];
    } 

    public function start()
    {
        var_dump('开始状态');   
    }

    public function end()
    {
        var_dump('结束状态');   
    }

    public function reset()
    {
        var_dump('重置状态,让调度器可以重新执行');
    }
}

class Supervisor
{
    private $sateStore;

    public function __construct()
    {
        $this->sateStore = new SateStore();
    }

    public function monitor()
    {
        var_dump('监控状态');
    }

    public function retry()
    {
        $this->sateStore->reset();
    }

    public function handle()
    {
        $this->monitor();

        $hasTimeOut = rand(0, 1);

        if ($hasTimeOut) {
            var_dump('有超时的状态');

            $this->retry();

            return;
        }

        var_dump('状态正常');
    }

}

class Scheduler
{
    private $sateStore;

    public function __construct()
    {
        $this->sateStore = new SateStore();
    }

    public function firstStep()
    {
        $this->sateStore->start();
        Agent::debug();
        $this->sateStore->end();
    }

    public function secondStep()
    {
        $this->sateStore->start();
        Agent::debug();
        $this->sateStore->end();
    }

    public function handle()
    {
        $tasks = $this->sateStore->getWaitingTasks();
        foreach ($tasks as $task) {
            switch ($task['status']) {
                case 1 : 
                    var_dump("task id : {$task['status']} 执行第一步");

                    $this->firstStep();
                    break;
                case 2 : 
                    var_dump("task id : {$task['status']} 执行第二步");

                    $this->secondStep();
                    break;
            }
        }
    }

}

class Crontab
{
    public function handle()
    {
        (new Supervisor)->handle();
        (new Scheduler)->handle();
    }
}

// 定时任务执行
(new Crontab)->handle();

本文章首发在 LearnKu.com 网站上。

上一篇 下一篇
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《G01 Go 实战入门》
从零开始带你一步步开发一个 Go 博客项目,让你在最短的时间内学会使用 Go 进行编码。项目结构很大程度上参考了 Laravel。
讨论数量: 0
发起讨论 查看所有版本


暂无话题~