《Java高并发程序设计》学习 --7.7 消息路由

本文介绍如何使用 Akka 的 Router 组件实现消息的负载均衡。通过 RoundRobinRoutingLogic 路由策略,消息被均匀地分发给一组 Actor。演示了创建 Router、添加 Actor 以及在 Actor 停止时移除它们的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Akka提供了非常灵活的消息发送机制。有时候,会使用一组Actor而不是一个Actor来提供一项服务。这一组Actor中所有的Actor都是对等的,也就是说可以找任何一个Actor来服务。这种情况下,如何才能快速有效地找到合适的Actor?或者说如何调度这些消息,才可以使负载更为均衡地分配在这一组Actor中。
为了解决这个问题,Akka使用一个路由器组件(Router)来封装消息的调度。系统提供了几种实用的消息路由策略,比如,轮询选择Actor进行消息发送,随机消息发送,将消息发送给最为空闲的Actor,甚至是在组内广播消息。
public class WatchActor_Router extends UntypedActor {
	private final LoggingAdapter log = Logging.getLogger(getContext().system(), this);
	List<Routee> routees = new ArrayList<Routee>();
	public Router router;
	{
		for(int i=0; i<5; i++) {
			ActorRef worker = getContext().actorOf(Props.create(MyWorker.class),"worker_" + i);
			getContext().watch(worker);
			routees.add(new ActorRefRoutee(worker));
		}
		router = new Router(new RoundRobinRoutingLogic(),routees);
	}
	
	@Override
	public void onReceive(Object msg) throws Exception {
		if(msg instanceof MyWorker.Msg) {
			router.route(msg,getSender());
		} else if(msg instanceof Terminated) {
			router = router.removeRoutee(((Terminated)msg).actor());
			System.out.println(((Terminated)msg).actor().path() + " is closed, routees = " +
			routees.size());
			if(router.routees().size() == 0) {
				System.out.println("Close system");
				RouteMain.flag.send(false);
				getContext().system().shutdown();
			}
		} else {
			unhandled(msg);
		}
	}
}
上述代码定义了WatchActor。第3行,就是路由器组件Router,在构造Router时,需要指定路由策略和一组被路由的Actor(Routee),如第11行所示。这里使用了RoundRobinRoutingLogic路由策略,也就是对所有的Routee进行轮询消息发送。在本例中,Routee由5个MyWorker Actor构成(第6~10行,MyWorker与上一节中的相同)。
当有消息需要传递给这5个MyWorker时,只需要将消息投递给这个Router。Router就会根据给定的消息路由策略进行消息投递。当一个MyWorker停止工作时,还可以简单地将其从工作组中移除。在这里,如果发现系统中没有可用的Actor就会直接关闭系统。
主函数如下:
public class RouteMain {
	public static Agent<Boolean> flag = Agent.create(true, ExecutionContexts.global());
	public static void main(String[] args) throws InterruptedException {
		ActorSystem system = ActorSystem.create("route", ConfigFactory.load("samplehello.conf"));
		ActorRef w = system.actorOf(Props.create(WatchActor_Router.class), "watcher");
		int i = 1;
		while(flag.get()) {
			w.tell(MyWorker.Msg.WORKING, ActorRef.noSender());
			if(i%10==0)w.tell(MyWorker.Msg.CLOSE, ActorRef.noSender());
			i++;
			Thread.sleep(100);
		}
	}
}
上述代码向WatchActor发送大量消息,其中夹杂着几条关闭Actor的消息。这会使得MyWorker Actor逐一被关闭,最终程序将退出。
这段代码的部分输出如下(做过适当裁剪):
[INFO] [03/12/2017 21:43:44.361] [route-akka.actor.default-dispatcher-6] [akka://route/user/watcher/worker_0] I am working
[INFO] [03/12/2017 21:43:44.426] [route-akka.actor.default-dispatcher-6] [akka://route/user/watcher/worker_1] I am working
[INFO] [03/12/2017 21:43:44.526] [route-akka.actor.default-dispatcher-6] [akka://route/user/watcher/worker_2] I am working
[INFO] [03/12/2017 21:43:44.626] [route-akka.actor.default-dispatcher-7] [akka://route/user/watcher/worker_3] I am working
[INFO] [03/12/2017 21:43:44.726] [route-akka.actor.default-dispatcher-6] [akka://route/user/watcher/worker_4] I am working
[INFO] [03/12/2017 21:43:44.826] [route-akka.actor.default-dispatcher-3] [akka://route/user/watcher/worker_0] I am working
[INFO] [03/12/2017 21:43:44.926] [route-akka.actor.default-dispatcher-7] [akka://route/user/watcher/worker_1] I am working
[INFO] [03/12/2017 21:43:45.026] [route-akka.actor.default-dispatcher-3] [akka://route/user/watcher/worker_2] I am working
[INFO] [03/12/2017 21:43:45.126] [route-akka.actor.default-dispatcher-7] [akka://route/user/watcher/worker_3] I am working
[INFO] [03/12/2017 21:43:45.226] [route-akka.actor.default-dispatcher-6] [akka://route/user/watcher/worker_4] I am working
[INFO] [03/12/2017 21:43:45.226] [route-akka.actor.default-dispatcher-7] [akka://route/user/watcher/worker_0] I will shutdown
[INFO] [03/12/2017 21:43:45.258] [route-akka.actor.default-dispatcher-6] 
MyWorker is stopping
[INFO] [03/12/2017 21:43:49.248] [route-akka.actor.default-dispatcher-3] [akka://route/user/watcher/worker_1] I will shutdown
[INFO] [03/12/2017 21:43:49.249] [route-akka.actor.default-dispatcher-3] [akka://route/deadLetters] Message [cn.guet.parallel.akka.MyWorker$Msg] from Actor[akka://route/user/watcher/worker_1#-1390948406] to Actor[akka://route/deadLetters] was not delivered. [5] dead letters encountered. This logging can be turned off or adjusted with configuration settings 'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.
akka://route/user/watcher/worker_1 is closed, routees = 5
Close system
可以看到,WORKING消息被轮流发送给这5个worker。可以修改路由策略,观测不同路由策略下的消息投递方式(除了RoundRobinRoutingLogic外,还可以尝试BroadcastBoutingLogic广播策略、RandomRoutingLogic随机投递策略、SmallestMailRoutingLogic空闲Actor优先投递策略)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值