之前也提过,客户端需要写数据的时候,就会跟NameNode说他准备把文件上传到某个目录,NameNode就会开始进行元数据的更新。由于元数据的更新是非常重要的,所以客户端会在一定条件内重试,直至成功。
元数据更新成功后,Client就会创建两个队列,一个是dataQueue,一个是ackQueue。这两个队列的作用下文会讲。
客户端写入的时候,是一个个chunk写的,每一个chunk的大小是512byte,chunk的校验和chunksum是4byte,这个校验和是对块的内容进行校验用的,所以每写入一个chunk的大小就是516byte。
这些chunk写满后,就会存放在一个叫做packet的东东里面,这个packet有64k的大小,所以就是65535byte,相当于127个chunk。每次写满一个packet或者写满128M(就是block的大小),就会创建一个新的packet给chunk写入。
已经写满的packet,就是放在上面提到的dataQueue。
客户端有其他线程,会监控dataQueue,此时他发现了dataQueue有数据了,他就开始向NameNode申请block信息。
NameNode会根据负载均衡以及机架感知,把计算后的DataNode的信息给到客户端。
得到DataNode信息后的客户端,就开始与其中一个DataNode建立数据管道,这个DataNode又会与其他DataNode建立数据管道。
建立数据管道的作用,就是把通过socket把数据传过去,客户端这里并没有直接和三个DataNode建立数据管道,这是因为DataNode一般是同一个机房的,所以他们内部通讯的速度会比较快。
管道建立成功后,客户端就会把dataQueue队列的头部packet拿出来,通过socket传给DataNode,另外也会把packet放入到ackQueue。
放入ackQueue的原因是为了防止packet传输给DataNode失败,如果失败了,就会把packet队列的packet放回到dataQueue,这样监听dataQueue队列的线程就会重新把她拿出来进行传输。如果传输成功了,会把ackQueue的packet移除。
DataNode接收到数据后,会把数据写入ackQueue队列,然后再把packet传输给下游,最后才写入磁盘。
这个ackQueue队列的作用跟上面一样,是为了防止传输失败,如果传输成功,就会把ackQueue队列中的packet移除,如果失败,就会继续传输。
如果DataNode不是最后一个节点,那就会重复上面的操作。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。