技术探索与实践:一个县城远程打工人的心路历程

霸气_导师
2025-12-15 23:54
阅读 748

去年冬天,窗外飘着小雪,我裹着我妈织的毛线毯子,在县城老房子的书桌前敲代码。桌上摆着半杯凉透的枸杞茶、一本翻烂了的《Rust 权威指南》,还有一张写满“跳槽计划”的便签纸——是的,我又在琢磨换工作的事儿了。

我在这家公司已经待了三年多,做的是后端开发,主要用 Go 写一些电商相关的微服务。公司不大,但团队氛围还不错,老板是个技术出身的中年大叔,偶尔还会和我们吐槽产品经理又提了个“三天上线双十一全场券系统”的需求。不过最近一年,我总感觉有点“卡住”了:技术栈没怎么更新,项目越来越重复,简历上能写的亮点越来越少。尤其是上周五晚上,运维兄弟突然在群里 @ 我:“线上支付回调超时,用户投诉炸了!”——我一边排查一边想:这要是换个语言或者架构,是不是早就避免了?

于是,我决定认真搞点新东西。正好刷知乎看到有人吹 Rust 的性能和内存安全,又听说不少大厂在招 Rust 工程师(虽然我们县城可能连个 Rust 岗都没有),但我心想:就算为了面试题挑战不翻车,也得学点硬核的


起因:被一道面试题逼出来的学习欲

事情的导火索其实挺尴尬的。

上个月,我偷偷投了几份简历,面了一家据说“技术驱动”的初创公司。面试官很年轻,穿着格子衫,眼神里透着一股“你行不行啊”的审视感。他问了个问题:

“如果让你设计一个高并发的限流器,你会怎么保证线程安全?Go 里怎么做?Rust 呢?”

我当时脑子一懵。Go 里我熟啊,sync.RWMutex + map[string]int64,简单粗暴。但 Rust?我只听说过 Arc<Mutex<T>>,具体咋用?完全说不清楚。最后草草糊弄过去,结果自然凉了。

回家路上我就在想:都2024年了,还只会写 CRUD 和加锁,简历上写“精通并发编程”是不是有点脸红?

更扎心的是,那天晚上我翻自己的简历,发现除了“参与XX系统开发”、“优化接口响应时间30%”这种万金油描述,根本拿不出像样的技术深度。别说 Rust 了,就连 Go 的 channel 底层实现都说不利索。

于是我下定决心:这次不为别的,就为下次面试别再被问住,也为自己简历添点真材实料


开干:从《Rust 权威指南》到手搓限流器

我选了《Rust 权威指南》(The Rust Programming Language)这本书入门。说实话,前两章还好,变量、所有权、借用这些概念虽然绕,但还能理解。可一到“生命周期”和“并发模型”,我直接裂开。

“error[E0597]: x does not live long enough”
——编译器又在嘲笑我了。

那几天我天天在 Discord 上蹲 Rust 中文社区,看别人讨论 tokio::sync::Semaphorestd::sync::Mutex 的区别。有一次凌晨两点还在调试一个死锁问题,差点把键盘砸了——结果发现是我忘了 drop(guard),Rust 编译器早就在报错里提示了,只是我没看懂。

但越是难,我越觉得有意思。Rust 的“零成本抽象”不是吹的。比如我想实现一个滑动窗口限流器,用 Go 的话大概要自己维护一个环形队列 + 时间戳 + 锁,而 Rust 里配合 tokioDashMap(一个高性能并发哈希表),居然能写出既安全又高效的代码。

下面是我最终实现的核心逻辑(简化版):

use dashmap::DashMap;
use std::time::{Duration, Instant};
use tokio::sync::Semaphore;

#[derive(Clone)]
pub struct SlidingWindowLimiter {
    windows: DashMap<String, (Instant, Arc<Semaphore>)>,
    max_requests: u32,
    window_size: Duration,
}

impl SlidingWindowLimiter {
    pub fn new(max_requests: u32, window_size_sec: u64) -> Self {
        Self {
            windows: DashMap::new(),
            max_requests,
            window_size: Duration::from_secs(window_size_sec),
        }
    }

    pub async fn allow(&self, key: &str) -> bool {
        let now = Instant::now();
        let entry = self.windows.entry(key.to_string()).or_insert_with(|| {
            (
                now,
                Arc::new(Semaphore::new(self.max_requests as usize)),
            )
        });

        let (ref mut start_time, ref sem) = *entry;

        // 如果窗口过期,重置
        if now.duration_since(*start_time) > self.window_size {
            *start_time = now;
            // 注意:这里不能直接 new Semaphore,因为已有引用
            // 所以实际生产中建议用更复杂的结构,比如带版本号的窗口
            // 但为了演示,我们简化处理
            return true; // 这里其实有 bug!后面会讲
        }

        // 尝试获取许可
        match sem.acquire().await {
            Ok(_permit) => true,
            Err(_) => false, // 不该发生,但防御性编程
        }
    }
}

这段代码看着挺美,但第一次跑压测就崩了——窗口重置时,旧的 Semaphore 还被其他协程持有,导致 permit 泄漏!也就是说,限流数会慢慢变少,最后所有请求都被拒。

我整整花了两天才意识到问题所在。后来改用“带时间戳的计数器 + 定期清理”策略,配合 tokio::time::interval 做后台回收,才算搞定。

教训:Rust 虽然帮你防住了内存安全问题,但逻辑正确性还得靠脑子


实战:把它塞进公司项目试试水

光写 demo 没意思,我决定偷偷在公司项目里试试 Rust 的威力。

我们有个内部消息推送服务,用 Go 写的,高峰期经常 OOM。老板一直想优化,但没人敢动——毕竟“能跑就行,别瞎改”。

我趁周末加班(其实是自愿的,毕竟想证明 Rust 行),用 Rust 重写了核心的消息分发模块,通过 gRPC 和现有系统对接。部署方式也很土:Docker 打包,扔到 K8s 里跑 sidecar。

结果出乎意料:内存占用从平均 800MB 降到 120MB,P99 延迟从 120ms 降到 18ms

运维大哥看到监控图都惊了:“你这 Rust 是吃内存长大的还是省内存长大的?”

当然,过程也不是一帆风顺。最大的坑是 FFI(Foreign Function Interface)。我们有些加密逻辑用了公司自研的 C++ 库,得用 bindgen 生成绑定。结果因为 ABI 不一致,debug 了整整三天,最后发现是 C++17Rust 2021 的对齐规则不同……

但这一切都值得。上周站会上,我轻描淡写地展示了性能对比图,CTO 眼睛都亮了:“这玩意儿能上生产?”

我说:“已经在跑了,两周零故障。”

那一刻,我仿佛看到了简历上即将新增的一行:“主导 Rust 微服务重构,提升系统吞吐 300%,降低资源成本 70%”。


求职视角:Rust 真的能帮我跳槽吗?

说实话,学 Rust 初衷是为了面试装 X,但深入之后才发现:它改变的不只是技术栈,更是思维方式

以前写 Go,遇到并发问题第一反应是“加锁”;现在写 Rust,第一反应是“能不能无锁?能不能用 channel?能不能用原子操作?”——这种对资源和生命周期的敏感,让我写其他语言时也更谨慎了。

最近我又投了几份简历,特意在技能栏加了“Rust(实战项目)”,并附上了 GitHub 链接。有两家给了面试机会,其中一家直接问:“你那个限流器是怎么处理窗口重置的?”

我笑着把 permit 泄漏的坑讲了一遍,对面面试官居然点头说:“嗯,踩过这个坑说明真写过。”

更意外的是,有猎头私信我,说某大厂边缘计算团队在招 Rust 工程师,base 能给到一线城市水平,支持远程办公

我坐在县城的小屋里,看着窗外晒太阳的大爷,突然觉得:小镇做题家,未必只能困在小地方。只要技术够硬,远程办公的时代,哪里都是战场。


经验总结:给想学 Rust 的“打工人”几点建议

项目 建议
入门路径 别死磕《The Book》,配合 Rustlings 边写边学
工具链 cargo, clippy, rustfmt 必装;VS Code + rust-analyzer 是神器
并发模型 先掌握 tokio,再看 async-stdArc<Mutex<T>> 是新手陷阱,优先考虑 channelatomic
生产部署 musl 静态链接,避免 glibc 兼容问题;Dockerfile 记得 multi-stage 构建减体积
求职策略 不必等“精通”,有完整项目+踩坑经验就能写进简历;重点突出“解决问题的能力”

另外,别信“Rust 学完就能年薪百万”。现实是:大多数公司还是 Go/Java 主力,Rust 岗位集中在基础设施、区块链、嵌入式等特定领域。但正因为少,竞争反而小——只要你真能干活。


最后:技术探索的意义不止于跳槽

写这篇文章的时候,已经是深夜。老婆在隔壁房间睡了,猫趴在我键盘上打呼噜。我喝了口冷掉的枸杞茶,突然想起三年前刚入职时,也是在这个书桌前,战战兢兢地提交第一个 PR。

那时候我只想着“别出 bug”,现在却开始思考“怎么设计更优雅的系统”。这种变化,不是因为换了语言,而是因为持续探索带来的底气

也许我最终不会去大厂,也许还会继续在县城远程打工。但至少下次面试官问我“Rust 和 Go 的并发模型区别”时,我能笑着回答:

“Go 分享内存,Rust 分享所有权——但本质上,我们都在和时间、资源、人性斗智斗勇。”

技术人的浪漫,大概就是明知世界复杂,仍愿一行行代码去驯服它。


P.S. 如果你也在小城市远程工作,也在焦虑技术成长和职业发展——别慌。打开你的编辑器,写点让自己 proud 的代码。简历可以包装,但能力骗不了人。共勉。

P.P.S. 限流器的完整实现和压测报告我放 GitHub 了,搜 sliding-window-limiter-rs 就能找到。欢迎 star,也欢迎 issue 吐槽——毕竟,程序员的友谊,从 PR 开始 ❤️

评论 0

最热最新
暂无评论
匿名用户Lv.1
0
影响力
0
文章
0
粉丝