spark将在1.6中替换掉akka,而采用netty实现整个集群的rpc的框架,netty的内存管理和NIO支持将有效的提高spark集群的网络传输能力,为了看懂这块代码,在网上找了两本书看《netty in action》和《netty权威指南》,结合了spark的源码既学习了netty也看完了spark netty的部分源码。该部分源码掺杂了太多netty的东西,看起来还是有点累的。

 

缓存模块

network工程里面抽闲了一个ManagerBuffer的接口,该接口用来表示二进制数据中视图(表示数据的一部分),具体的实现依赖数据的来源,目前支持file,nio bytebuffer,netty bytebuf这3中数据来源。注意该接口具体的实现可能脱离了JVM GC的管理,比如NettyManagerBuffer是引用计数的,此时当该buffer传递给其他线程是需要调用retain/release来添加或减少引用。
ManagerBuffer以ByteBuffer, InputStream和Netty对象三种方式对外显示这些数据,ByteBuffer由于消耗过大,不建议使用,添加了引用计数管理和数据大小查询。
  1. publicabstractclassManagedBuffer{
  2. /** Number of bytes of the data. */
  3. publicabstractlong size();
  4. /**
  5. * Exposes this buffer's data as an NIO ByteBuffer. Changing the position and limit of the
  6. * returned ByteBuffer should not affect the content of this buffer.
  7. */
  8. // TODO: Deprecate this, usage may require expensive memory mapping or allocation.
  9. publicabstractByteBuffer nioByteBuffer()throwsIOException;
  10. /**
  11. * Exposes this buffer's data as an InputStream. The underlying implementation does not
  12. * necessarily check for the length of bytes read, so the caller is responsible for making sure
  13. * it does not go over the limit.
  14. */
  15. publicabstractInputStream createInputStream()throwsIOException;
  16. /**
  17. * Increment the reference count by one if applicable.
  18. */
  19. publicabstractManagedBuffer retain();
  20. /**
  21. * If applicable, decrement the reference count by one and deallocates the buffer if the
  22. * reference count reaches zero.
  23. */
  24. publicabstractManagedBuffer release();
  25. /**
  26. * Convert the buffer into an Netty object, used to write the data out.
  27. */
  28. publicabstractObject convertToNetty()throwsIOException;
  29. }
ManageredBuffer每一种数据来源有一个实现类。先看下数据来源为file的。
  1. publicfinalclassFileSegmentManagedBufferextendsManagedBuffer{
  2. privatefinalTransportConf conf;
  3. privatefinalFile file;
  4. privatefinallong offset;
  5. privatefinallong length;
  6. publicFileSegmentManagedBuffer(TransportConf conf,File file,long offset,long length){
  7. this.conf = conf;
  8. this.file = file;
  9. this.offset = offset;
  10. this.length = length;
  11. }
  12. @Override
  13. publiclong size(){
  14. return length;
  15. }
  16. @Override
  17. publicByteBuffer nioByteBuffer()throwsIOException{
  18. FileChannel channel =null;
  19. try{
  20. channel =newRandomAccessFile(file,"r").getChannel();
  21. // Just copy the buffer if it's sufficiently small, as memory mapping has a high overhead.
  22. if(length < conf.memoryMapBytes()){
  23. ByteBuffer buf =ByteBuffer.allocate((int) length);
  24. channel.position(offset);
  25. while(buf.remaining()!=0){
  26. if(channel.read(buf)==-1){
  27. thrownewIOException(String.format("Reached EOF before filling buffer\n"+
  28. "offset=%s\nfile=%s\nbuf.remaining=%s",
  29. offset, file.getAbsoluteFile(), buf.remaining()));
  30. }
  31. }
  32. buf.flip();
  33. return buf;
  34. }else{
  35. return channel.map(FileChannel.MapMode.READ_ONLY, offset, length);
  36. }
  37. }catch(IOException e){
  38. try{
  39. if(channel !=null){
  40. long size = channel.size();
  41. thrownewIOException("Error in reading "+this+" (actual file length "+ size +")",
  42. e);
  43. }
  44. }catch(IOException ignored){
  45. // ignore
  46. }
  47. thrownewIOException("Error in opening "+this, e);
  48. }finally{
  49. JavaUtils.closeQuietly(channel);
  50. }
  51. }
  52. @Override
  53. publicInputStream createInputStream()throwsIOException{
  54. FileInputStream is =null;
  55. try{
  56. is =newFileInputStream(file);
  57. ByteStreams.skipFully(is, offset);
  58. returnnewLimitedInputStream(is, length);
  59. }catch(IOException e){
  60. try{
  61. if(is !=null){
  62. long size = file.length();
  63. thrownewIOException("Error in reading "+this+" (actual file length "+ size +")",
  64. e);
  65. }
  66. }catch(IOException ignored){
  67. // ignore
  68. }finally{
  69. JavaUtils.closeQuietly(is);
  70. }
  71. thrownewIOException("Error in opening "+this, e);
  72. }catch(RuntimeException e){
  73. JavaUtils.closeQuietly(is);
  74. throw e;
  75. }
  76. }
  77. @Override
  78. publicManagedBuffer retain(){
  79. returnthis;
  80. }
  81. @Override
  82. publicManagedBuffer release(){
  83. returnthis;
  84. }
  85. @Override
  86. publicObject convertToNetty()throwsIOException{
  87. if(conf.lazyFileDescriptor()){
  88. returnnewLazyFileRegion(file, offset, length);
  89. }else{
  90. FileChannel fileChannel =newFileInputStream(file).getChannel();
  91. returnnewDefaultFileRegion(fileChannel, offset, length);
  92. }
  93. }
  94. publicFile getFile(){return file;}
  95. publiclong getOffset(){return offset;}
  96. publiclong getLength(){return length;}
  97. @Override
  98. publicString toString(){
  99. returnObjects.toStringHelper(this)
  100. .add("file", file)
  101. .add("offset", offset)
  102. .add("length", length)
  103. .toString();
  104. }
  105. }
nioByteBuffer,如果数据大小小于spark.storage.memoryMapThreshold。那么使用ByteBufer读取通道的数据,如果大于等于该值,那么使用文件内存映射方式读取数据。
createInputStream中返回一个控制读取长度的LimitedInputStream,这里使用guava的ByteStreams
convertToNetty返回一个FileRegion。如果spark.shuffle.io.lazyFD设置为true那么使用LazyFileRegion,如果为false使用DefaultFileRegion。LazyFileRegion会在传输的时候生成FileChannel,注解说如果netty使用了epoll协议那么不可以使用LazyFileRegion。
 
数据源为ByteBuf的实现类,该类用Bytebuf来存储数据。
  1. publicfinalclassNettyManagedBufferextendsManagedBuffer{
  2. privatefinalByteBuf buf;
  3. publicNettyManagedBuffer(ByteBuf buf){
  4. this.buf = buf;
  5. }
  6. @Override
  7. publiclong size(){
  8. return buf.readableBytes();
  9. }
  10. @Override
  11. publicByteBuffer nioByteBuffer()throwsIOException{
  12. return buf.nioBuffer();
  13. }
  14. @Override
  15. publicInputStream createInputStream()throwsIOException{
  16. returnnewByteBufInputStream(buf);
  17. }
  18. @Override
  19. publicManagedBuffer retain(){
  20. buf.retain();
  21. returnthis;
  22. }
  23. @Override
  24. publicManagedBuffer release(){
  25. buf.release();
  26. returnthis;
  27. }
  28. @Override
  29. publicObject convertToNetty()throwsIOException{
  30. return buf.duplicate();
  31. }
  32. @Override
  33. publicString toString(){
  34. returnObjects.toStringHelper(this)
  35. .add("buf", buf)
  36. .toString();
  37. }
  38. }
把一个bytebuf对象转成InputStream对象使用ByteBufInputStream对象来完成。还有bytebuf的duplicate()返回一个bytebuf映射同一份数据,任何一个修改结果都会影响另一个,注意引用计数。参见http://www.maljob.com/pages/newsDetail.html?id=394
 
还一个数据源为bytebuffer的实现
  1. publicfinalclassNioManagedBufferextendsManagedBuffer{
  2. privatefinalByteBuffer buf;
  3. publicNioManagedBuffer(ByteBuffer buf){
  4. this.buf = buf;
  5. }
  6. @Override
  7. publiclong size(){
  8. return buf.remaining();
  9. }
  10. @Override
  11. publicByteBuffer nioByteBuffer()throwsIOException{
  12. return buf.duplicate();
  13. }
  14. @Override
  15. publicInputStream createInputStream()throwsIOException{
  16. returnnewByteBufInputStream(Unpooled.wrappedBuffer(buf));
  17. }
  18. @Override
  19. publicManagedBuffer retain(){
  20. returnthis;
  21. }
  22. @Override
  23. publicManagedBuffer release(){
  24. returnthis;
  25. }
  26. @Override
  27. publicObject convertToNetty()throwsIOException{
  28. returnUnpooled.wrappedBuffer(buf);
  29. }
  30. @Override
  31. publicString toString(){
  32. returnObjects.toStringHelper(this)
  33. .add("buf", buf)
  34. .toString();
  35. }
  36. }
 这里面一个有意思的显示就是把bytebuffer转成bytebuf使用netty中Unpooled.wrappedBuffer()实现
 
 
 
 

spark源码阅读之network(1)的更多相关文章

  1. spark源码阅读之network(2)

    在上节的解读中发现spark的源码中大量使用netty的buffer部分的api,该节将看到netty核心的一些api,比如channel: 在Netty里,Channel是通讯的载体(网络套接字或组 ...

  2. spark源码阅读之network(3)

    TransportContext用来创建TransportServer和TransportclientFactory,同时使用TransportChannelHandler用来配置channel的pi ...

  3. Spark源码阅读之存储体系--存储体系概述与shuffle服务

    一.概述 根据<深入理解Spark:核心思想与源码分析>一书,结合最新的spark源代码master分支进行源码阅读,对新版本的代码加上自己的一些理解,如有错误,希望指出. 1.块管理器B ...

  4. win7+idea+maven搭建spark源码阅读环境

    1.参考. 利用IDEA工具编译Spark源码(1.60~2.20) https://blog.csdn.net/He11o_Liu/article/details/78739699 Maven编译打 ...

  5. spark源码阅读

    根据spark2.2的编译顺序来确定源码阅读顺序,只阅读核心的基本部分. 1.common目录 ①Tags②Sketch③Networking④Shuffle Streaming Service⑤Un ...

  6. emacs+ensime+sbt打造spark源码阅读环境

    欢迎转载,转载请注明出处,徽沪一郎. 概述 Scala越来越流行, Spark也愈来愈红火, 对spark的代码进行走读也成了一个很普遍的行为.不巧的是,当前java社区中很流行的ide如eclips ...

  7. spark源码阅读---Utils.getCallSite

    1 作用 当该方法在spark内部代码中调用时,会返回当前调用spark代码的用户类的名称,以及其所调用的spark方法.所谓用户类,就是我们这些用户使用spark api的类. 2 内部实现 2.1 ...

  8. spark源码阅读--SparkContext启动过程

    ##SparkContext启动过程 基于spark 2.1.0  scala 2.11.8 spark源码的体系结构实在是很庞大,从使用spark-submit脚本提交任务,到向yarn申请容器,启 ...

  9. Spark源码阅读(1): Stage划分

    Spark中job由action动作生成,那么stage是如何划分的呢?一般的解答是根据宽窄依赖划分.那么我们深入源码看看吧 一个action 例如count,会在多次runJob中传递,最终会到一个 ...

随机推荐

  1. 十三、python沉淀之路--文件操作

    一.文件的读操作 例1 f = open('学习',encoding='utf-8') #首先要打开文件,不然直接读,是读不出来的 data = f.read() #read后的括号里不添加任何东西 ...

  2. tornado日志管理

    默认数据格式 默认情况下,采用tornado的web框架运行起来之后,任何访问都会直接在控制台输出日志信息,格式如下: [I 160807 09:27:17 web:1971] 200 GET / ( ...

  3. 用hexo搭建自己的blog

    一.工具准备: 1.1 安装node 作用:用来生成静态页面的 到Node.js官网下载相应平台的最新版本,一路安装即可. 1.2 安装Git 作用:把本地的hexo内容提交到github上去. 安装 ...

  4. hive字段原理--有删除一列想到的

    hive删除一张表的字段不会动数据文件,只是修改了一下metadata表里面的表定义:所以会出现一种情况:就是这张表如果之前数据是满的(个格列都有数据),那么被删除的那列后数据都往前窜了一个,最后一个 ...

  5. MySQL删除数据库

    drop命令用于删除数据库. drop命令格式:drop database <数据库名>; 例如,删除名为 xhkdb的数据库: mysql> drop database xhkdb ...

  6. 基于ThinkPHP的开发笔记3-登录功能(转)

    1.前台登录用的form ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <for ...

  7. python使用wxPython创建一个简单的文本编辑器。

    ubuntu下通过'sudo apt-get install python-wxtools'下载wxPython.load和save函数用于加载和保存文件内容,button通过Bind函数绑定这两个函 ...

  8. Internet上的网络层

    TCP/IP协议栈第三层是网络层,网络层的目的是实现两个系统之间的数据透明传送,具体功能包括寻址和路由选择.连接和建立.保持和终止等. TCP/IP协议给internet上的每台主机和路由分配一个地址 ...

  9. linux启动自动挂载分区和/etc/fstab简单修复

    让后加的分区能够启动时自动挂载,需要把配置写入文件 /etc/fstab vi /etc/fstab UUID=3f5859e0-592f-42cd-b533-570422fb85be   / ext ...

  10. python学习(十八) 程序打包

    18.1  Distutils基础 18.2 打包 18.2.1 建立存档文件 18.2.2 创建Windows安装程序或RPM包 18.3 编译扩展 18.4 使用py2exe创建可执行程序