如下是一个完美的高性能全双工隧道构件:
手贱心痒了就想优化一下,就 2 对线程怎么能行,多隧道并发如何解决,tun 读写会不会成为瓶颈,用线程池呢,协程是不是更好,tun 多队列用起来…
十多年前,这些优化就是我安身立命的饭碗,屡试不爽。但现在我否定了自己曾经的做法,我如今的方法论非常简单直白:能搭建出来的,绝不做出来。
这意味着我需要构建最内聚,最精简,最高效的核心预制构件,然后用该构件搭建整个系统,剩下的交给操作系统,这能让我省去很多 bugfix 的调试时间,损失的只是那一丁点牙缝里抠出来的性能。
我简单举些例子,看看能节省哪些时间:
- 捆绑多组单通道全双工构件,无需直面 epoll,无需设计调度器,交给系统调度器;
- 多组构建的多个独立 tun 网卡之间配置 ECMP,无需操心多队列对应分发;
- 无需管理多线程之间共享数据的互斥访问,极大简化了代码逻辑;
依照这个观点,我此前针对 OpenVPN,Wireguard 等做的所有 “多线程”,“多处理” 等优化都是弄巧成拙的内卷行为,毫无意义,简单创建多个实例即可达到更好的效果。
拼接高内聚低耦合的小构件秉承了 UNIX “只做好一件事” 以及 kiss 的哲学,受益于低耦合,编程者将少操心很多东西,比如一个专门的服务器进程只需要监听客户端的连接,然后仅将客户端连接元组信息传递给 worker 进程,而 worker 进程就是上述小构件。
构件之间只需要简单接口进行交互,构件只操作独享数据,而大进程多线程,协程则是反面,编程者不得不设计或重用复杂的机制处理共享数据间的同步,引入的潜在问题甚至比解决的还要多。
循着高内聚,低耦合,不优化的方法论,势必会朝着仅通过 IPC 交互的微核心设计更进一步。然而众所周知,IPC 肯定没有线程间交互更快,多一次调度都是时间,可这背后还是时间尺度的问题,相比手贱心痒持续优化而成的庞大程序节省的那一点指令时间,微核心结构节省的是你的生命,因为它更简单。
人生苦短,吃点好的,干点正事。
浙江温州皮鞋湿,下雨进水不会胖。