Akka remote源码走读与逻辑梳理
Akka remote源码走读与逻辑梳理
最近事情比较少,就抽了一天时间把akka remote模块的代码粗略走读了下,梳理了以下类结构和数据流。akka remote模块里大量使用了future\ promise,以下为我梳理出的简单类结构图(不清楚的话可以单独打开图片链接):
当前akka数据传输默认使用netty来实现,之后会被Artery模块取代。
在actor层级上,akka使用了两个独立的部分transports
和endpointManager
来分别管理底层连接和上层发送接收,两者均为system
actor的子actor。
transports
actor负责管理底层连接、断开,它会为每个远程地址创建一个子actor,并交由子actor去管理该地址的所有连接。我们深入它的其中一种子actor AkkaProtocolManager
来看,AkkaProtocolManager
会为每个远程连接创建两个子actor,一个用于Inbound一个用于OutBound,这样实现了输入输出的双工操作,互不影响。这两个子actor其实是同一个类ProtocolStateActor
,它实现了akka中的FSM有限状态机,其Inbound和OutBound功能是由其构建时的初始状态决定的。
endpointManager
actor负责管理发送接收,是基于transports
所建立起来的链路进行的,因此它可以专注于发送接收而不用过多关注链路相关问题。endpointManager
会为每个连接创建一个EndpointWriter
actor用来向远程发送消息,并且EndpointWriter
也会创建EndpointReader
actor用来接收该链路上收到的消息。EndpointWriter
和EndpointReader
也保证了上层传输中的全双工消息传递。
remote模块中传输的核心是被AkkaProtocolTransport
包裹在内的NettyTransport
。它的发送接收依赖inboundBootstrap
变量和outboundBootstrap
方法,inboundBootstrap
定义如下:
private val inboundBootstrap: Bootstrap = settings.TransportMode match {
case Tcp ⇒ setupBootstrap(new ServerBootstrap(serverChannelFactory), serverPipelineFactory)
case Udp ⇒ setupBootstrap(new ConnectionlessBootstrap(serverChannelFactory), serverPipelineFactory)
}
inboundBootstrap
是一个不可变成员变量,def listen: Future[(Address, Promise[AssociationEventListener])]
方法会将其初始化,它作为server监听所有发送到该host:port下的信息,该方法会在endpointManager
初始化时被调用。
outboundBootstrap
是一个方法def outboundBootstrap(remoteAddress: Address): ClientBootstrap
,它接受一个地址,并创建一个链接到这个地址的Channel,它会被方法def associate(remoteAddress: Address): Future[AssociationHandle]
调用,即其他模块向该模块请求链接到一个远程地址remoteAddress: Address
时,它会返回一个Future[AssociationHandle]
。