Netty 和 AKKA 的分工
Akka主要关注于actor模型和并发编程,而Netty专注于网络通信和事件驱动的编程模型。
Akka 的核心价值
1、消息驱动的业务处理*
Netty中的 I/O 事件(如 channelRead
、write
)和非IO事件会由 EventLoop
线程 按顺序依次处理,不会并发执行。所以所有耗时操作(无论是否 I/O)都应异步化,保持 EventLoop
仅处理轻量级任务。使用AKKA将每个客户端请求被封装为消息,由 Akka Actor 异步处理,避免阻塞 Netty 的 EventLoop导致其他channel长时间等待。
2、并发与状态管理
Actor 模型天然支持线程安全的状态共享(每个 Actor 串行处理消息,无需锁)
3、分布式扩展
通过 Akka Cluster 可以轻松实现横向扩展,将业务逻辑分布到多台机器。
客户端 -> Netty -> AKKA 交互流程
步骤 1:客户端建立连接
-
客户端 发起 TCP 连接请求(如 WebSocket、HTTP)。
-
Netty 的
bossEventLoop
(单线程)接受连接,创建Channel
并注册到workerEventLoopGroup
中的一个EventLoop
。 - 每个
Channel
绑定到一个固定的EventLoop
(线程)。
步骤 2:Netty 接收请求
-
Netty 的
workerEventLoop
从Channel
读取数据,触发channelRead
事件。 -
Netty Handler 进行协议解码(如 HTTP 解析、Protobuf 反序列化),生成业务请求对象。
步骤 3:Netty → Akka 消息转发
-
Akka Router Actor 接收请求,根据业务规则(如请求类型、用户 ID)路由到具体的业务 Actor。
步骤 4:Akka 处理业务逻辑
-
业务 Actor 执行核心逻辑(如订单处理、用户认证),可能调用外部服务(数据库、第三方 API)。
步骤 5:Akka → Netty 返回响应
-
业务 Actor 将处理结果封装为响应消息,发送回原始请求的
ChannelHandlerContext
(通过消息传递)。 -
Netty Handler 收到 Akka 响应后,通过
EventLoop
线程写回客户端:
步骤 6:Netty 发送响应
-
Netty 的
workerEventLoop
执行writeAndFlush
,将数据编码后通过Channel
发送给客户端。
示例代码
创建用于桥接Akka的Handler
维护一个成员变量routerActor,用于向routerActor转发消息(在启动类启动时赋值)
//继承SimpleChannelInboundHandler类指定泛型为Protobuf请求的生成类
public class NettyAkkaBridgeHandler extends SimpleChannelInboundHandler<MyRequest> {
private final ActorRef routerActor;
public NettyAkkaBridgeHandler(ActorRef routerActor) {
this.routerActor = routerActor;
}
@Override
protected void channelRead(ChannelHandlerContext ctx, MyRequest request) {
// 1. 将 Netty 请求转为 Akka 消息
AkkaRequest akkaRequest = new AkkaRequest(ctx, request);
// 2. 发送给 Akka Router Actor
routerActor.tell(akkaRequest, ActorRef.noSender());
// 注意:这里不需要手动释放 request,Netty 会自动处理
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// 异常处理(如日志、关闭连接)
ctx.close();
}
}
创建akka的路由Actor
netty将消息发给路由actor之后根据不同的AkkaRequest转发给对应的actor,其中receiveBuilder().match()
方法中,两个参数分别表示 消息类型匹配规则 和 消息处理逻辑。
下面的代码收到一条消息时,Akka 会检查该消息是否是 AkkaRequest的实例,如果是则执行第二个参数里的逻辑
public class RouterActor extends AbstractActor {
@Override
public Receive createReceive() {
return receiveBuilder()
.match(AkkaRequest.class, req -> {
//获取到对应actor的actorSelection
ActorSelection targetActorSelection = selectTargetActor(req);
if(targetActorSelection != null){
//转发
targetActorSelection .tell(req, getSender());
}else{
log.info("#$%^&^RE@!");
}
})
.build();
}
//根据req请求返回需要处理这个请求的actor的ActorSelection
private ActorSelection selectTargetActor(AkkaRequestMessage req){
int cmdId = req.getMsgBody().getCmdId();
switch (cmdId ) {
case 1:
return context().actorSelection("/user/" + "actor的名字1");
case 2:
return context().actorSelection("/user/" + "actor的名字2");
default:
return null;
}
}
}
创建处理业务逻辑的Actor
public class MyWorkerActor extends AbstractActor {
//处理db操作的线程池
private final ExecutorService dbExecutor = Executors.newFixedThreadPool(4);
@Override
public Receive createReceive() {
return receiveBuilder()
.match(AkkaRequestMessage.class, req -> {
// 处理耗时操作(如数据库查询)
CompletableFuture.supplyAsync(() -> {
return queryDatabase(req); // 阻塞操作,在独立线程池执行
}, dbExecutor).thenAccept(result -> {
// 将结果封装为响应,回到 Netty 的 EventLoop 线程写回
req.getChannelContext().executor().execute(() -> {
req.getChannelContext().writeAndFlush(req);
});
});
}).build();
}
private String queryDatabase(AkkaRequestMessage request) {
// 模拟数据库查询
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return "Order-" + request.getId() + ": processed";
}
}
启动类中初始化Netty和AKKA
// 初始化 Akka
//创建akka系统
ActorSystem system = ActorSystem.create("BusinessSystem");
//往系统中添加已经创建好的actor
ActorRef router = system.actorOf(Props.create(RouterActor.class), "routerActor");
system.actorOf(Props.create(WorkerActor1.class), "workerActorr1");
//其中WorkerActor2安排3个实例,使用轮询的策略负载均衡
system.actorOf(Props.create(WorkerActor2.class).withRouter(new RoundRobinPool(3)), "workerActorr2");
// 初始化 Netty
//bossGroup配置1个线程,workerGroup默认cpu核心数*2
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
ServerBootstrap bootstrap = new ServerBootstrap()
.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
ch.pipeline()
//解码为 MyRequest
.addLast(new ProtobufDecoder(MyRequest.getDefaultInstance()))
//添加已经创建好的Handler
//并将router(用于路由的actor)设置为这个Handler的成员变量用于tell其他actor操作
.addLast(new NettyAkkaBridgeHandler(router));
}
});