通过对数据流和控制流的解耦,不管哪个块服务器为 Primary,我们都能够通过基于网络拓扑来调度数据流,以此提高性能 。3.2节将进一步讨论 。
前面只是推送了数据到块服务器的缓存中,此时才正式请求执行写入
此时客户端的请求将被视为已经失败,而那些被修改的区域停留在不一致的状态上 。我们的客户端代码通过重试失败的修改操作来处理这种错误 。在从头开始重复执行之前 , 它将在第3步到第7步上做几次重做的尝试 。
3.2 数据流为了有效的利用网络,我们将数据流和控制流分开 。控制流从客户端到 Primary 上,再到所有的Secondary 上,而数据则以管道形式、线性的沿一个精心设计的块服务器链进行推送 。我们的目标是最大限度的使用每台服务器的网络带宽,避免网络瓶颈和高延迟 , 最小化推送所有数据的时间延迟 。
为了有效利用每台机器的网络带宽,数据被线性的沿一个块服务器组成的链进行推送,而不是按着其它拓扑进行分发(如,树) 。因此每台机器的出口带宽都用于以最快的速度专注地传输数据 , 而不是分配给多个接收者 。
为了尽可能的避免网络瓶颈和高延迟链路,每台机器只将数据推送给网络拓扑中最近的没有接收到数据的机器 。假设客户端将数据推送给块服务器 S1 到 S4 。它将数据发送给最近的块服务器 , 我们称之为 S1,S1 将数据推送给 S2 到 S4 中最近的块服务器,我们称之为 S2,类似的,S2 将数据推送到 S3 或 S4 中距离 S2 较近的块服务器等等 。我们的网络拓扑足够简单,可以通过IP地址来精确的估计距离 。
最后 , 我们通过在 TCP 连接上使用管道传输数据来最小化时间延迟 。一旦一个块服务器接收到数据,则马上开始进行数据推送 。管道对我们的帮助很大 , 因为我们采用了全双工的交换网络 。立刻推送数据不会降低数据的接收速率 。在没有网络拥塞的情况下,将 B 个字节传输到 R 个副本的理想时间消耗为 B/T+RL,这里 T 是网络的吞吐量,L 是两台机器间的传输延迟 。我们的网络链路通常为100Mbps(T),并且 L 远小于1ms,因此,在理想情况下,1MB 的数据能够在 80ms 内分发完成 。
3.3 原子性的记录追加GFS 提供了一种原子性的追加操作称为记录追加:
- 在传统的写操作中,客户端指定数据写入的位置在文件中的偏移量,这样对同一个文件区域的并行写操作不能进行序列化:该区域最终可能包含来自多个客户端的数据片段 。
- 然而,在一个记录追加操作中,客户端只需要指定数据,GFS 将数据至少一次原子性地追加到文件(如 , 一个连续的字节序列)的 GFS 选定的一个偏移位置,并将这个偏移位置返回给客户端 。这与在没有竞争的情况下,Uinx 下多个并发写操作向一个使用 O_APPEND 选项打开的文件中写数据相似 。
推荐阅读
- JAVA的File对象
- Codeforces 1670 E. Hemose on the Tree
- 二 沁恒CH32V003: Ubuntu20.04 MRS和Makefile开发环境配置
- 驱动开发:内核监控FileObject文件回调
- 齐博X1-栏目的调用2
- Blazor组件自做十一 : File System Access 文件系统访问 组件
- How to get the return value of the setTimeout inner function in js All In One
- System.IO.FileSystemWatcher的坑
- Docker | dockerfile构建centos镜像,以及CMD和ENTRYPOINT的区别
- prometheus监控实战