php容错机制,Actor监控与容错机制

在如今的IT行业中,如果一个系统不具备高可用以及稳定性,那么它迟早会被淘汰的。也许有时出现故障并不是代码本身的问题,网络(连接超时、读超时等)、服务器故障、用户操作有误等原因,也不能影响用户的体验。程序发生故障时,我们要尽可能保证用户体验不受影响,这就需要我们的系统具有良好的容错机制,能保证服务在不可用时自我修复。

监督策略

Actor作为Akka中最基本的执行单元,是所有业务的核心,如若发生故障,可能产生不可估量的后果,这就需要拥有一套容错机制。前面我们已经提到,Actor系统具有监控机制,父级对子级进行管理,子级如果出现异常情况,父级可以通过处理逻辑来确定子级是重启、恢复、还是停止。

Akka提供了两种监督策略,分别是One-For-One Strategy和All-For-One Strategy。关于这两种策略的区别如下:

在程序中,当我们没有为Actor指定管理策略,Akka提供了一套默认的策略:抛出ActorInitializationException、ActorKilledException 、DeathPactException 时,停止子Actor运行。

抛出Exception时,重启子Actor。

其它类型的Throwable异常时,会上溯到父级。

实际项目中,我们可能自定义了许多异常,以此来区分不同的情况。针对这些不同的异常,我们处理Actor方式或许不一样,这就需要我们自定义监督策略。SupervisorStrategy是自定义监督策略核心类,构造函数如下:public OneForOneStrategy(int maxNrOfRetries, java.time.Duration withinTimeRange, PartialFunction decider)

我们可以看到它有三个参数,分别是maxNrOfRetries、withinTimeRange、decider。其中maxNrOfRetries和withinTimeRange表明在一段时间的重启次数,超过次数则stop。第三个参数是一个Function对象,我们可以在里面定义监督指令,使用DeciderBuilder构建工厂可以快速编写,监督指令有:

下面,我们写一个示例来观察这几个指令,示例如下:

监控者SupervisorActor类:public class SupervisorActor extends AbstractActor {

/**

* 自定义OneForOneStrategy监督策略

*/

private static SupervisorStrategy strategy = new OneForOneStrategy(3, Duration.ofMinutes(1),

DeciderBuilder.match(IOException.class, e -> SupervisorStrategy.resume())

.match(NullPointerException.class, e -> SupervisorStrategy.restart())

.match(IllegalArgumentException.class, e -> SupervisorStrategy.stop())

.matchAny(o -> SupervisorStrategy.escalate())

.build());

private final LoggingAdapter logger = Logging.getLogger(getContext().getSystem(), this);

public static void main(String[] args) throws InterruptedException {

ActorSystem system = ActorSystem.create("system");

ActorRef supervisor = system.actorOf(Props.create(SupervisorActor.class), "supervisor");

supervisor.tell("IOException", ActorRef.noSender());

//supervisor.tell("NullPointerException", ActorRef.noSender());

//supervisor.tell("IllegalArgumentException", ActorRef.noSender());

supervisor.tell("get", ActorRef.noSender());

}

@Override

public SupervisorStrategy supervisorStrategy() {

return strategy;

}

@Override

public void preStart() throws Exception {

ActorRef childActor = getContext().actorOf(Props.create(ChildActor.class), "childActor");

//监控

getContext().watch(childActor);

}

@Override

public Receive createReceive() {

return receiveBuilder().match(String.class, s -> {

Option childActor = getContext().child("childActor");

ActorRef child = childActor.get();

if ("IOException".equals(s)) {

child.tell(new IOException(), getSelf());

} else if ("NullPointerException".equals(s)) {

child.tell(new NullPointerException("空指针异常"), getSelf());

} else if ("IllegalArgumentException".equals(s)) {

child.tell(new IllegalArgumentException(), getSelf());

}else if("get".equals(s)){

child.tell("get", getSelf());

}

}).match(Terminated.class, t -> {

logger.info("监控到" + t.getActor() + "停止了");

}).matchAny(other -> {

logger.info("state= " + other);

}).build();

}

}

子类ChildActor ,我们重写preStart、postStop、preRestart、postRestart四个方法,方便我们观察不同指令下的流程:public class ChildActor extends AbstractActor {

/**

* 用来观察不同处理后的结果

*/

private int state = 1;

@Override

public Receive createReceive() {

return receiveBuilder()

.match(Exception.class, e -> {

this.state++;

throw e;

})

.matchEquals("get", s -> {

this.state++;

getSender().tell(state, getSelf());

})

.matchAny(o -> {

this.state++;

unhandled(o);

})

.build();

}

@Override

public void preStart() throws Exception {

super.preStart();

System.out.println("child preStart");

}

@Override

public void postStop() throws Exception {

super.postStop();

System.out.println("child postStop");

}

@Override

public void preRestart(Throwable reason, Optional message) throws Exception {

System.out.println("child preRestart start: " + this.state);

super.preRestart(reason, message);

System.out.println("child preRestart end: " + this.state);

}

@Override

public void postRestart(Throwable reason) throws Exception {

System.out.println("child postRestart start: " + this.state);

super.postRestart(reason);

System.out.println("child postRestart end: " + this.state);

}

}

这里特别提醒一下,ChildActor的createReceive方法中的this.state++必须写在每个匹配项里,如若写在createReceive方法里,只会执行一次。

运行SupervisorActor 的main方法,测试三种异常带来的不同状态结果(运行结果不贴出来了,大家可以运行一下示例),  结果说明如下:

正确的使用监控和容错机制,可以在程序出现异常或故障时,保证系统不崩溃,对于系统的高可用和稳定性提供极大的保障。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值