锋盈数科-知识库 Logo
首页
软件开发
计算机基础
Hello Halo
新手必读
关于本知识库
登录 →
锋盈数科-知识库 Logo
首页 软件开发 计算机基础 Hello Halo 新手必读 关于本知识库
登录
  1. 首页
  2. 默认分类
  3. 深入浅出操作系统的零拷贝

深入浅出操作系统的零拷贝

0
  • 默认分类
  • 发布于 2024-09-23
  • 0 次阅读
黄健
黄健

在 kafka、netty 这些技术中,零拷贝都是一个重要的考点。但是零拷贝与这些具体的技术无关,关键点是数据传输。就像冰糖葫芦里的山楂:冰糖葫芦里重要的组成可以有山楂。但是山楂并不是冰糖葫芦特有的,羊羹里也可以有。

下面是一个 MQ 的基本流程。

如果采用传统方法进行数据传输,消息从存储系统到达消费者需要经过4次拷贝。如果使用零拷贝技术,情况会怎样呢?

传统模式下的数据拷贝过程

过程解释

传统模式下,上图红框中经过了从文件读数据和从 socket 进行数据发送两个过程。

内部流程如下图所示:

用户进程如 Java 程序想进行 File.read ,需要将数据进行 DMA 拷贝读取到到文件读取缓冲区。还记得《时刻掌握系统运行状态-深度理解top命令》里的 buffers/cached 空间吗?文件读取缓冲区占用的就是这个空间。

文件读取缓冲区仍然是内核空间,用户进程要使用还需要进行一次 CPU 拷贝将数据拷贝到应用进程缓冲区。这时候用户进程比如 Java 程序就可以对数据进行排序、过滤等操作了。这个过程就完成了 File.read。

如果数据想发送到网卡,也就是 Socket.send。还需要再进行一次 CPU 拷贝发送到套接字发送缓冲区进行中转,这个地方也是要占用 buffers/cached 空间的。中转这个过程很快,所以 buffers/cached 空间可以很快被释放。

数据从中转站还要进行一次 DMA 拷贝,将数据运送到网络设备缓冲区,最终发送到网络上。这个过程就完成了 Socket.send。

这个过程要进行几次上下文切换呢?File.read 这个函数需要先调用发起内核请求,进入到内核空间操作,这是一次内核切换。内核操作完成返回内核的结果,这是第二次内核切换。同理, Socket.send 也需要两次内核切换。这里的用户态到内核态的切换就是上下文切换。总共是4次。

性能测试

这种方式性能如何呢?咱们来测试一下。

写个程序从本地电脑中读取自己的一张照片,这张照片5M多大,发送到服务端。

服务端只要能接收客户端数据就可以,我随便写了一个:

    public static void server() throws Exception {        ServerSocket serverSocket = new ServerSocket(520);        int i = 1;        while (true) {            Socket socket = serverSocket.accept();            int left = 0;            while (left >= 0) {                InputStream io = socket.getInputStream();                byte[] bytes = new byte[1024];                left = io.read(bytes);            }        }    }

客户端读取数据并发送到网络:

@GetMapping(path = "hi")public String hi() throws Exception {    client();    return "end";}
public void client() throws Exception {    Socket socket = new Socket("127.0.0.1", 520);    //向服务器端第一次发送字符串    OutputStream netOut = socket.getOutputStream();    InputStream io = new FileInputStream("D:\\photo\\编程一生.JPG");    long begin = System.currentTimeMillis();    byte[] bytes = new byte[1024];    while (io.read(bytes) >= 0) {        netOut.write(bytes);    }    System.out.println("耗时为" + (System.currentTimeMillis() - begin) + "ms");    netOut.close();    io.close();    socket.close();}

服务启动后:http://localhost:8080/hi 访问5次,结果如下:

耗时为450ms

耗时为437ms

耗时为424ms

耗时为423ms

耗时为420ms

结论:使用传统方式,5M多的数据读取到发送需要400多毫秒。

零拷贝过程

过程解释

linux操作系统中有个 sendFile 方法可以不通过用户进行,直接将数据从磁盘发送到网络设备缓冲区。在 linux2.1 版本的 sendFile 过程如下图:

到了 linux2.4 ,linux 的 sendFile 进行了优化,实现了完全没有 CPU 拷贝实现数据传输。

不管是 linux2.1 还是 linux2.4 ,都是 linux 自身实现的,函数都对应的是 sendFile 。上层比如 Java 可以使用 transferTo 和 transferFrom 使用 sendFile 方法,这两个方法是 netty 实现的重要工具,一个是发送数据用,一个是接收数据用。

性能测试

这种方式性能如何呢?咱们来测试一下。

服务端不变,客户端代码如下:

@GetMapping(path = "hi")public String hi() throws Exception {    client();    return "end";}
 public void client() throws Exception {      SocketChannel socket = SocketChannel.open();      socket.connect(new InetSocketAddress("127.0.0.1", 520));      FileChannel io = new FileInputStream("D:\\photo\\编程一生.JPG").getChannel();      long begin = System.currentTimeMillis();      io.transferTo(0, io.size(), socket);      System.out.println("耗时为" + (System.currentTimeMillis() - begin) + "ms");      io.close();      socket.close();  }

服务启动后:http://localhost:8080/hi 访问5次,结果如下:

耗时为44ms

耗时为33ms

耗时为43ms

耗时为46ms

耗时为35ms

结论:使用零拷贝方式,5M多的数据读取到发送需要40多毫秒。与传统方式相比,性能提高10倍。

内存映射模式与零拷贝

linux 系统有零拷贝,windows 也希望减少拷贝和下上下切换,它依靠内存映射(MMAP)。当然,linux 也支持内存映射,并且在 RocketMQ 等的实现上发挥着巨大作用。

通过与上面传统方式比较,可看到由于内存映射发挥作用,在文件读取时减少了一次 CPU 拷贝。

在 Java 中可以通过下面方法进行内存映射:

 RandomAccessFile raf = new RandomAccessFile(file, "rw"); MappedByteBuffer mmap = raf.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, 500);   

在 MQ 的实现上,内存映射(MMAP)和 sendFile 零拷贝是提升性能的利器。下面做一个比较:

上面可以看到 RocketMQ 由于使用了内存映射吞吐量远高于 ActiveMQ 和 RabbitMQ ,Kafka 由于使用了零拷贝又比 RocketMQ 提高了一个数量级。

实际上 RabbitMQ 的实现大量借鉴了 Kafka ,那 RabbitMQ 为什么不直接使用 Kafka 的零拷贝提高性能呢?因为 RabbitMQ 不仅仅是将数据从磁盘发送出去,还需要在内存中做一些排序、过滤等高级操作。

最后大家再来思考一个问题:零拷贝和内存映射两种模式下,各需要几次上下文切换?

标签: #知识库 257
相关文章
最全的办公楼智能化解决方案

最全的办公楼智能化解决方案 2024-10-16 08:40

办公楼综合体智能化如何建设?有哪些系统?近几年,办公楼智能化的项目越来越多,不少项目经理都参与其它,同事办公楼综合体也是弱电系统涉及的最多的项目之一,本期我们一起来看下,最全的办公楼项目智能化设计方案。

规范标准查询、下载网站 2024-10-12 16:41

我们在工作中经常需要用到各种各样的规范标准,这里给大家介绍一些免费查询和下载规范的网站,个人亲测可用。 标准查找查新网站 工标网: http://www.csres.com/ 中国国家标准化管理委员会:http://openstd.samr.gov.cn/bzgk/gb/index 全国标准信息公共

【计算机网络】网络层协议解析 2024-10-08 11:24

网络层的两种服务 IPv4 * 分类编址 划分子网 无分类地址 IPv4地址应用 IP数据报的发送和转发过程 * 主机发送IP数据报 路由器转发IP数据报 IPv4数据报首部格式 ICMP网际控制报文协议 虚拟专用网VPN与

FFmpeg教程(超级详细版) 2024-10-08 11:24

一、参考资料 通过ffmpeg把图片转换成视频 FFmpeg命令(一)、使用filter_complex命令拼接视频 FFmpeg 视频处理入门教程给新手的 20 多个 FFmpeg 命令示例 FFmpeg命令行转码

计算机网络:物理层 —— 数据的传输方式 2024-10-08 11:24

文章目录 * 传输方式 * 串行传输 * 串行传输方式 特点 应用 并行传输 * 特点 应用 网卡的串/并转换 同步传输 * 同步时钟频率的误差问题 特点 应用<

授权码机制 V2.1 2024-10-07 10:26

大家好,我是机灵鹤。 根据读者朋友们反馈的问题和建议,对 授权码 V2.0 版本做了一些优化。 优化内容主要解决了以下几个问题: 优化了授权机制中的时间校验逻辑,避免用户通过回调本地时间来绕过授权机制的问题。 封装和简化了授权接口,开发者可以更方便地接入到自己的程序中。

目录

IT 外包服务商

  • 意见投递
  • zyf6619

软件开发应用

主菜单

  • 首页
  • 软件开发
  • 计算机基础
  • Hello Halo
  • 新手必读
  • 关于本知识库
Copyright © 2024 your company All Rights Reserved. Powered by Halo.