磁盘数据发送到网络的拷贝过程

磁盘数据发送到网络的拷贝过程

  1. 传统方式的4次拷贝

    1
    2
    3
    4
    ┌─────────┐    ┌──────────┐    ┌─────────┐    ┌──────────┐    ┌─────────┐
    │ 磁盘 │ -> │ 内核缓冲区│ -> │ 用户缓冲区│ -> │socket缓冲区│ -> │ 网卡 │
    └─────────┘ └──────────┘ └─────────┘ └──────────┘ └─────────┘
    拷贝1 拷贝2 拷贝3 拷贝4
  2. 详细解释每次拷贝

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    // 示例代码
    File.read(fileDesc, buf, len); // 读取文件
    Socket.send(buf, len); // 发送数据

    过程解析:
    1次拷贝:DMA拷贝
    - 由DMA控制器完成
    - 将磁盘数据拷贝到内核缓冲区
    - 不需要CPU参与

    2次拷贝:CPU拷贝
    - 由CPU完成
    - 将数据从内核缓冲区拷贝到用户缓冲区(如JVM堆)
    - read()系统调用的结果

    3次拷贝:CPU拷贝
    - 由CPU完成
    - 将数据从用户缓冲区拷贝到socket缓冲区
    - write()系统调用的过程

    4次拷贝:DMA拷贝
    - 由DMA控制器完成
    - 将socket缓冲区的数据拷贝到网卡
    - 准备通过网络发送
  3. 上下文切换

    1
    2
    3
    4
    5
    6
    7
    涉及的上下文切换:
    1. read()调用:用户态 -> 内核态
    2. read()返回:内核态 -> 用户态
    3. write()调用:用户态 -> 内核态
    4. write()返回:内核态 -> 用户态

    总计:4次上下文切换
  4. 性能影响

    1
    2
    3
    4
    5
    6
    7
    8
    9
    资源消耗:
    - CPU时间:用于数据拷贝和上下文切换
    - 内存带宽:多次数据拷贝
    - 延迟增加:每次上下文切换大约需要1-10微秒

    示例计算(发送1MB数据):
    - 数据拷贝:~10ms
    - 上下文切换:~4-40微秒
    - 总耗时:>10ms
  5. 对比零拷贝

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    零拷贝方式:
    ┌─────────┐ ┌──────────┐ ┌─────────┐
    │ 磁盘 │ -> │ 内核缓冲区│ -> │ 网卡 │
    └─────────┘ └──────────┘ └─────────┘
    DMA拷贝 DMA拷贝

    优势:
    - 只有2次DMA拷贝
    - 不需要CPU拷贝
    - 减少上下文切换
    - 降低延迟和CPU使用率