在前两篇中,我们通过官网的example体验了livy的功能,留下了一个疑问,究竟livy是如何做到的呢?这一篇从源码里面找一下答案。
在直接分析源码前,先把结论通过时序图画出来,有个直观的映像:
- 客户端创建session,LivyServer收到请求后启动一个RpcServer。RpcServer会顺序选择一个从
10000~10010
之间的可用端口启动监听,假设此时是10000
。 - LivyServer随后通过SparkSubimit提交Application。Application在远端,最终会启动
RSCDrvier
。 RSCDrvier
首先也从10000~10010
之间顺序选择一个可用的端口,启动RpcServer。图中打出了关键的日志,第二篇中曾经提到过这个日志。RSCDrvier
完成bind后,反向连接到LivyServer端的RpcServer。图中打出了关键的日志,第二篇中同样提到过。RSCDrvier
主要向LivyServer所在的RpcServer上报自己bind的端口和ip。这一步其实就是最关键的步骤。- RpcServer收到请求后将
RSCDrvier
的端口和ip封装成ContextInfo
返回给LivyServer。同时关闭RpcServer
。 - LivyServer通过
RSCDrvier
的端口和ip连接到RSCDriver,从而完成tcp连接。至此session建立完成
以上就是简化的核心工作原理,可以通过netstat
证实一下网络连接关系。vm3198是livyServer,vm3196是driver所在机器
下图是driver上的相关连接:
可以看到driver启用了10000端口的监听
下图是livyServer上的相关连接:
可以看到livyServer有一条连接到driver的链路,端口是可以对应上的
读者可能注意到,这里Driver的监听端口并不是10001,而是10000。这是因为虽然livyServer会率先占用10000,但由于Driver与livyServer不在一台机器上,所以对于Driver来说,10000当时并没有被占用,所以就使用10000端口了
注意到,我们在livyServer上并没有找到10000端口的监听。这是因为,一旦driver将自己的地址回发过来(通过回发RemoteDriverAddress
消息),livyServer的Rpc监听就关闭了。
读者可能会考虑,RSCDrvier
是如何知道livyServer的Rpc监听端点的呢?答案在启动Spark任务时上送的配置文件,我们摘取其中关键的配置项:
spark.__livy__.livy.rsc.launcher.address=vm3198
spark.__livy__.livy.rsc.launcher.port=10000
launcher.address/port;就是livyServer启动的Rpc监听端点。从RSCDriver的源码可以看到,程序从配置文件中读取了信息:
...
// Address for the RSC driver to connect back with it's connection info.
LAUNCHER_ADDRESS("launcher.address", null)
LAUNCHER_PORT("launcher.port", -1)
...
String launcherAddress = livyConf.get(LAUNCHER_ADDRESS);
int launcherPort = livyConf.getInt(LAUNCHER_PORT);
...
LOG.info("Connecting to: {}:{}", launcherAddress, launcherPort);
总结
本篇我们探究了livy的核心工作机制,了解了建立session时,在livyServer和Driver之间是如何建立连接关系的。更多关于rpc通信的细节有机会还会再基于源码详细展开分析
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。