【Rust 日报】2021-7-15 Zenoh 性能提升的故事| 漫游在 Rust 异步仙境

2021-07-19 15:17:00 浏览数 (1)

这是 Facebook for Develpers 网站出的Rust Nibbles系列文章,介绍 facebook 开源的各种 Rust 库。

Gazebo 是 facebook 工程师 编写的基础库,Gazebo以独立模块的形式包含了一系列经过测试的Rust实用程序。这篇文章是介绍了 Gazebo 中的 Dupe trait 。

在Rust中,有两个用于 "复制 "一个值的相关特性--Copy和Clone。

在Gazebo中引入了第三个类似的trait,称之为Dupe,它可以在Gazebo Prelude中使用。(dupe 有复制物品/复制底片的意思)。

Copy 是 编译器的自动行为,复制成本也不高。而 Clone 则不然。为了降低 Clone 的成本,一般可以使用 Arc,但是 Arc 使得代码阅读成本提升。比如 let xs = ys.clone();,你可能需要查看大量上下文来弄清是 调用了 Clone 还是 Arc 。当然你可以使用 let xs = Arc::clone(ys)来提升可读性,但缺点是,它破坏了抽象。

所以,Gazebo 中引入了 Dupe trait, let xs = ys.dupe()

rust use gazebo::prelude::*; #[derive(Clone, Dupe)] struct MyArc(Arc);

看了一下实现源码:https://github.com/facebookincubator/gazebo/blob/master/gazebo/src/dupe.rs

rust pub trait Dupe: Clone { fn dupe(&self) -> Self { self.clone() } } 看上去和 Clone 很像,但它仅在 常量时或零分配下可用,比如 Arc。因为 Dupe 只给这些类型实现了。

https://developers.facebook.com/blog/post/2021/07/06/rust-nibbles-gazebo-dupe/

Forward : Rust 视界

Zenoh 性能提升的故事| 漫游在 Rust 异步仙境

在 Rust Maginze 月刊第四期中介绍过 Zenoh : 开源产品 | eclipse zenoh 助力雾计算和边缘计算

eclipse zenoh (读:/zeno/ ) ,提供了零开销的Pub/Sub、Store/Query 和 计算。

zenoh 统一了 动态/静止/使用中的数据并提供计算结果。它颇有分寸地将传统的Pub/Sub与地理分布的存储、查询和计算融合在一起,同时保留了远远超出任何主流协议栈的时间和空间效率水平。

官网是 zenoh.io 。

GitHub代码仓库 eclipse-zenoh/zenoh 。

2020 年 12 月 Eclipse Edge Native 工作组启动,并将 Zenoh 引入 Eclipse 。并用 Rust 对 zenoh 进行重写。

在本文中,Zenoh 团队剖析了他们如何改进让异步性能提升一倍。

  • 8字节payload 时超过3.5M msg/s
  • 1Mb payload 时超过 45Gb/s
  • 在 backlogged 场景下,延迟低至 35 微秒

该团队如何做到的呢?

一:准备工作

  1. 准备测试环境,以便获得可复现的结果。因为很多外部因素可能会影响代码性能,这是为了排除这些干扰。这有个非常棒的指南:https://easyperf.net/blog/2019/08/02/Perf-measurement-environment-on-Linux
  2. 彻底阅读 《Rust 性能手册》。我们发现它对Rust的性能技巧和诀窍以及剖析技术都很有见地。另外,还有一篇关于如何在Rust中编写高性能代码的博客也是不错的参考。

二:寻找性能热点(hotspots)

  1. 我们先使用 flamegraph 来生成火焰图,打算寻找 zenoh 中的异步性能热点。然而,异步使得火焰图相当难以阅读,因为异步调度器和future执行器基本上出现在火焰图中每一个地方。所以改变了性能剖析工具,开始使用 perf ,可以提供更清晰的热点图,尤其是序列化和反序列化方面。
  2. 改进了序列化/反序列化相关实现,性能直接提升 100% 。但是这种改进在吞吐量测试中没有反映出来。

三:堆分配还是栈分配?

zenoh 团队 一直避免在关键环节进行堆分配。用 valgrind 仔细检查后发现,并没有不必要的堆分配,缓存未命中率也不高。因此该团队开始检查 栈分配的问题,利用 Rust 编译器的一个 flag (仅在 Rust Nightly 可用)来验证一个数据结构多大以及它的内存对齐方式。

rust $ RUSTFLAGS=-Zprint-type-sizes cargo build --release 用这种方式来编译 zenoh 即可。输出:

rust print-type-size type: net::protocol::proto::msg::Data: 304 bytes, alignment: 8 bytes print-type-size field .key: 40 bytes print-type-size field .data_info: 168 bytes print-type-size field .payload: 96 bytes

异步数据结构也会这样打印出来。然后该团队发现了一个痛苦的事实:

  1. 异步 future,一旦被编译,就会在栈中占用几十 KB 的空间。每次有消息需要通过网络发送,就会调用这些 futures。
  2. 因为zenoh广泛使用异步,所以现在导致 栈太深太大,给内存带来很大压力。
  3. 经过思考,该团队将 异步代码隔离在特定的部分,尤其是网络交互部分,而其他部分则转为使用同步。由此来平衡 同步和异步,汲取了两个世界的优点。大幅减少了栈内存的压力,带了巨大的性能提升。

四:性能测试结果

该团队性能测试环境为:AMD Ryzen 5800x,32GB内存,通过100Gb以太网连接,根据前面所说的性能测试环境配置指南配置好。

具体的性能测试图表,可以进一步查看文章。也可以关注 zenoh 团队的博客,因为他们性能优化还会继续。

https://zenoh.io/blog/2021-07-13-zenoh-performance-async/

Forward : Rust 视界

Rust Tauri Svelte 教程

随着 Rust 越来越受欢迎,越来越多的人想要学习它,我决定创建另一个主要针对初学者的教程。使用 Rust 创建桌面应用程序的方法很少,而 Tauri 绝对是一种可以让您制作漂亮的 UI(HTML/JS/CSS)并在后台利用 Rust 功能的方法。由于 Tauri 允许您选择任何前端框架(或不选择),因此我创建了一个使用 Svelte 和 Bootstrap(通过 Sveltestrap)的简单模板,为开发人员提供了一个很好的起点。为了演示如何使用它,我们将创建简单的密码生成器。

恰好我的实习项目Local Native就是使用tauri-bundle进行多平台打包的,说实话,用起来很丝滑,很简单易用,在此再次感谢tauri团队!

Read More: https://jbarszczewski.com/rust-tauri-svelte-tutorial

使用基于 eBPF 的内存分析器将 TezEdge 节点的内存使用量减半

本文介绍了作者使用基于eBPF的内存分析器来优化Rust代码的事。

Read More: https://medium.com/tezedge/halving-the-tezedge-nodes-memory-usage-with-an-ebpf-based-memory-profiler-2bfd32f94f69

本周引语

代码语言:javascript复制
Rust 新锈:呃,为什么编译器要阻止我做这些?太可怕了!

Rust 老锈:呃,为什么编译器不阻止我做这些!太可怕了!

– qDot 发表于 twitter

Read More:https://this-week-in-rust.org/blog/2021/07/14/this-week-in-rust-399/

中文:https://blog.budshome.com/budshome/rust-guan-fang-zhou-bao-399-qi-(2021-07-14)

--

From 日报小组 Cupnfish AlexZhang

感谢张老师提供的内容

0 人点赞