<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Rust on Cloudside</title><link>https://cloudside.icyyan.com/tags/rust/</link><description>Recent content in Rust on Cloudside</description><generator>Hugo</generator><language>en</language><lastBuildDate>Sun, 24 May 2026 10:00:00 +0800</lastBuildDate><atom:link href="https://cloudside.icyyan.com/tags/rust/index.xml" rel="self" type="application/rss+xml"/><item><title>Rust 里的 Box 到底是什么</title><link>https://cloudside.icyyan.com/posts/rust-box-guide/</link><pubDate>Sun, 24 May 2026 10:00:00 +0800</pubDate><guid>https://cloudside.icyyan.com/posts/rust-box-guide/</guid><description>&lt;p&gt;学 Rust 时，&lt;code&gt;Box&amp;lt;T&amp;gt;&lt;/code&gt; 很容易被一句话带过：它可以把数据放到堆上。&lt;/p&gt;
&lt;p&gt;这句话没错，但如果只记住这一句，后面看到 &lt;code&gt;Box&amp;lt;dyn Trait&amp;gt;&lt;/code&gt;、&lt;code&gt;Box&amp;lt;List&amp;gt;&lt;/code&gt;、&lt;code&gt;Pin&amp;lt;Box&amp;lt;T&amp;gt;&amp;gt;&lt;/code&gt;、&lt;code&gt;Box::leak&lt;/code&gt; 时，还是会觉得它像一个突然冒出来的语法补丁。&lt;/p&gt;
&lt;p&gt;更好的理解方式是：&lt;code&gt;Box&amp;lt;T&amp;gt;&lt;/code&gt; 不是“逃离所有权系统”的工具，而是 Rust 所有权系统里最基础的一种拥有型指针。它让一个值住在堆上，同时让所有权仍然清清楚楚地归某个变量管理。&lt;/p&gt;
&lt;h2 id="先看-box-解决了什么问题"&gt;先看 Box 解决了什么问题&lt;/h2&gt;
&lt;p&gt;普通变量通常可以这样理解：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; n &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;42&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;n&lt;/code&gt; 这个值本身就放在当前栈帧里。栈很快，进入函数时分配，函数返回时回收，生命周期也很清楚。&lt;/p&gt;
&lt;p&gt;但有些场景光靠栈不够舒服：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一个类型递归地包含自己，编译器算不出它的大小。&lt;/li&gt;
&lt;li&gt;你想把不同具体类型放进同一个集合，只要求它们实现同一个 trait。&lt;/li&gt;
&lt;li&gt;一个值很大，你希望移动时只移动一个指针。&lt;/li&gt;
&lt;li&gt;某些 API 需要一个固定地址的拥有型对象，比如配合 &lt;code&gt;Pin&lt;/code&gt; 使用。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这时 &lt;code&gt;Box&amp;lt;T&amp;gt;&lt;/code&gt; 就出现了。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; n &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Box::new(&lt;span style="color:#ae81ff"&gt;42&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以把它粗略想成这样：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;栈上变量 n
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&amp;gt; 保存一个指针
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; -&amp;gt; 指向堆上的 42
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;Box&amp;lt;T&amp;gt;&lt;/code&gt; 本身在栈上，里面保存指向堆数据的指针。真正的 &lt;code&gt;T&lt;/code&gt; 在堆上。变量离开作用域时，&lt;code&gt;Box&amp;lt;T&amp;gt;&lt;/code&gt; 会自动释放堆上的 &lt;code&gt;T&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;所以 &lt;code&gt;Box&amp;lt;T&amp;gt;&lt;/code&gt; 同时有两个特点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;它是指针，可以间接访问堆上的值。&lt;/li&gt;
&lt;li&gt;它拥有这个值，离开作用域时负责释放它。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这和 C 里的裸指针很不一样。你不用手写 &lt;code&gt;free&lt;/code&gt;，也不能随便复制出多个拥有者。Rust 仍然会检查所有权、移动和借用。&lt;/p&gt;
&lt;h2 id="最基本的用法boxnew"&gt;最基本的用法：Box::new&lt;/h2&gt;
&lt;p&gt;创建一个 &lt;code&gt;Box&amp;lt;T&amp;gt;&lt;/code&gt; 最常见的方式是 &lt;code&gt;Box::new&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-rust" data-lang="rust"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fn&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;main&lt;/span&gt;() {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;let&lt;/span&gt; name &lt;span style="color:#f92672"&gt;=&lt;/span&gt; Box::new(String::from(&lt;span style="color:#e6db74"&gt;&amp;#34;cloudside&amp;#34;&lt;/span&gt;));
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#a6e22e"&gt;println!&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;{name}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里 &lt;code&gt;String&lt;/code&gt; 这个值由 &lt;code&gt;Box&lt;/code&gt; 放到堆上管理，&lt;code&gt;name&lt;/code&gt; 是一个拥有它的 &lt;code&gt;Box&amp;lt;String&amp;gt;&lt;/code&gt;。注意，&lt;code&gt;String&lt;/code&gt; 自己内部还会管理一块字符串缓冲区；这里说的是 &lt;code&gt;String&lt;/code&gt; 这个三字段结构本身的位置。&lt;/p&gt;</description></item><item><title>用 Pingora 写一个最小反向代理，并把它部署起来</title><link>https://cloudside.icyyan.com/posts/pingora-minimal-reverse-proxy-guide/</link><pubDate>Sun, 17 May 2026 16:00:00 +0800</pubDate><guid>https://cloudside.icyyan.com/posts/pingora-minimal-reverse-proxy-guide/</guid><description>&lt;p&gt;Cloudflare 开源 Pingora 之后，很多人会问：它能不能替代 Nginx？如果问题只是“能不能把请求转发到后端服务”，答案是能，而且几十行 Rust 就够了。但 Pingora 不是一个读取 &lt;code&gt;nginx.conf&lt;/code&gt; 的服务器，它更像一套用来写代理、网关和网络服务的 Rust 框架。&lt;/p&gt;
&lt;p&gt;这篇只做一件事：用 Pingora 写一个最小反向代理，让 &lt;code&gt;http://127.0.0.1:6188/&lt;/code&gt; 转发到本机的 &lt;code&gt;127.0.0.1:3000&lt;/code&gt;，然后把这个二进制按服务方式部署起来。&lt;/p&gt;
&lt;p&gt;本文示例版本核对时间：&lt;strong&gt;2026-05-17&lt;/strong&gt;。示例使用 &lt;code&gt;pingora = &amp;quot;0.8&amp;quot;&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id="先看等价的-nginx-配置"&gt;先看等价的 Nginx 配置&lt;/h2&gt;
&lt;p&gt;如果用 Nginx，最小反代大概长这样：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-nginx" data-lang="nginx"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;server&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;listen&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6188&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;location&lt;/span&gt; &lt;span style="color:#e6db74"&gt;/&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;proxy_pass&lt;/span&gt; &lt;span style="color:#e6db74"&gt;http://127.0.0.1:3000&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;proxy_set_header&lt;/span&gt; &lt;span style="color:#e6db74"&gt;Host&lt;/span&gt; $host;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;proxy_set_header&lt;/span&gt; &lt;span style="color:#e6db74"&gt;X-Real-IP&lt;/span&gt; $remote_addr;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;proxy_set_header&lt;/span&gt; &lt;span style="color:#e6db74"&gt;X-Forwarded-For&lt;/span&gt; $proxy_add_x_forwarded_for;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;proxy_set_header&lt;/span&gt; &lt;span style="color:#e6db74"&gt;X-Forwarded-Proto&lt;/span&gt; &lt;span style="color:#e6db74"&gt;http&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Pingora 的思路不一样。你不是写配置块，而是实现 &lt;code&gt;ProxyHttp&lt;/code&gt; trait：请求进来以后，代码决定它要转发到哪里，转发前要改哪些请求头，最后日志怎么记。&lt;/p&gt;
&lt;h2 id="创建项目"&gt;创建项目&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cargo new mini-pingora-proxy
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd mini-pingora-proxy
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;Cargo.toml&lt;/code&gt;：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-toml" data-lang="toml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#a6e22e"&gt;package&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;name&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;mini-pingora-proxy&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;0.1.0&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;edition&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;2021&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[&lt;span style="color:#a6e22e"&gt;dependencies&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;async-trait&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;0.1&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;env_logger&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;0.11&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;log&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;0.4&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;pingora&lt;/span&gt; = { &lt;span style="color:#a6e22e"&gt;version&lt;/span&gt; = &lt;span style="color:#e6db74"&gt;&amp;#34;0.8&amp;#34;&lt;/span&gt;, &lt;span style="color:#a6e22e"&gt;features&lt;/span&gt; = [&lt;span style="color:#e6db74"&gt;&amp;#34;proxy&amp;#34;&lt;/span&gt;] }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里用的是 &lt;code&gt;pingora&lt;/code&gt; 聚合 crate，并启用 &lt;code&gt;proxy&lt;/code&gt; feature。Pingora 没有默认打开所有能力；如果后面要做负载均衡，需要再启用 &lt;code&gt;lb&lt;/code&gt;；如果要监听 HTTPS 或连接 HTTPS upstream，还要选择对应的 TLS feature，比如 &lt;code&gt;openssl&lt;/code&gt;、&lt;code&gt;boringssl&lt;/code&gt;、&lt;code&gt;s2n&lt;/code&gt; 或实验性的 &lt;code&gt;rustls&lt;/code&gt;。&lt;/p&gt;</description></item><item><title>Pingora 深度解析：为什么 Cloudflare 用 Rust 重写了 Nginx 时代的代理架构</title><link>https://cloudside.icyyan.com/posts/pingora-source-deep-dive/</link><pubDate>Sun, 17 May 2026 00:00:00 +0800</pubDate><guid>https://cloudside.icyyan.com/posts/pingora-source-deep-dive/</guid><description>&lt;p&gt;Cloudflare 公开 Pingora 时，最抓眼球的数字是：在相同流量下，新的代理系统比旧系统少用了约 70% CPU 和 67% 内存。&lt;/p&gt;
&lt;p&gt;看到这个数字，很多人的第一反应可能是：是不是 Nginx 不行了？是不是 Rust 天生就比 C 快很多？&lt;/p&gt;
&lt;p&gt;都不是。&lt;/p&gt;
&lt;p&gt;我们真正要回答的是：&lt;strong&gt;Cloudflare 为什么会觉得原来的 NGINX/OpenResty 代理不够用了？Pingora 又改掉了哪些最贵的地方？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;后面就顺着这个问题往下走。先看 Pingora 是什么，再看 Nginx 在普通场景里为什么很好用，最后再看 Cloudflare 这种规模下，连接池、线程模型和业务逻辑会怎样把成本放大。&lt;/p&gt;
&lt;p&gt;可以先带着三句话往下读，后面会一层层展开：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cloudflare 替换的是他们内部深度改造过的 NGINX/OpenResty 代理，不是说 Nginx 在所有场景下都慢。&lt;/li&gt;
&lt;li&gt;Pingora 开源版更像“用 Rust 写代理服务的工具箱”，不是一个直接读取 &lt;code&gt;nginx.conf&lt;/code&gt; 的 Nginx 替代品。&lt;/li&gt;
&lt;li&gt;重点不是“Rust 打败 Nginx”，而是连接复用、线程共享和复杂代理逻辑这些具体问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="1-pingora-不是一个新的-nginx"&gt;1. Pingora 不是一个新的 Nginx&lt;/h2&gt;
&lt;p&gt;如果你平时用 Nginx，可能会自然地把 Pingora 想成“另一个服务器软件”。但这样理解会有点偏。&lt;/p&gt;
&lt;p&gt;Pingora 更像一套用 Rust 写代理服务的工具箱。它帮你处理连接、TLS、HTTP 协议、负载均衡、连接池、优雅升级这些通用能力；你的业务逻辑则写在 Rust 回调里。&lt;/p&gt;
&lt;p&gt;它不是单个二进制 Web 服务器，而是一组 crate：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;crate&lt;/th&gt;
&lt;th&gt;作用&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pingora-core&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;底层协议、服务运行、监听器、连接器、优雅升级&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pingora-proxy&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;HTTP 代理生命周期和 &lt;code&gt;ProxyHttp&lt;/code&gt; 回调接口&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pingora-pool&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;高并发连接池&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pingora-runtime&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Tokio runtime 封装，支持 work-stealing 与 no-steal 模式&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pingora-load-balancing&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;负载均衡、健康检查、选择算法&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;pingora-cache&lt;/code&gt; / &lt;code&gt;pingora-memory-cache&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;缓存相关能力&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这些名字不用急着都记住。先有一个印象就够了：Pingora 把“写代理服务”拆成了一组可以组合的 Rust 库。&lt;/p&gt;</description></item></channel></rss>