网络编程框架的作用和价值
问题
既然 Linux 提供了 epoll
这样的 I/O 多路复用机制,接近内核且高性能,为什么开发者不直接使用 epoll
进行编程?而是在应用层折腾出了类似 Netty (Java)
, gnet (Golang)
这样的网络编程框架呢?
毕竟,每多一层封装,系统的整体性能就会有 (主要是数据复制带来的) 损耗。
或者换个说法: 网络编程框架的作用和价值体现在哪里?
这个问题,就类似: “有了汇编语言,为什么还要有高级语言” ?
答案其实和简单,总结出来无非是 3 点:
- 简化复杂的网络编程
- 自定义功能和扩展性
- 降低开发成本、提升代码可维护性
1. 简化复杂的网络编程
编程框架可以屏蔽细节,简化并统一 API,使应用开发者可以专注处理业务逻辑,降低心智负担,提高交付效率和质量。
上面是直接使用 epoll
提供的 API 进行编程时,(Socket) 文件描述符的相关操作的简化图,除此之外,开发者还需要其他的各种底层操作:
- Reactor 模型的实现 (为了有效管理)
- I/O 事件处理
- 各类网络协议解析
- 多线程实现 (为了高性能)
- …
但是有了编程框架之后,就完全不一样了: 框架会处理好所有底层的这些 “脏活累活”,以 TCP 协议为例,最终传递到应用开发者的就是事件名称以及对应的应用数据,应用开发者只需要重复三板斧操作就可以了:
- 读数据
- 处理业务逻辑
- 写数据
所以网络编程框架,本质上可以看作是应用层的 TCP/IP
协议栈,只不过处理的 I/O 事件没有内核层的 TCP/IP
协议栈那么多而已。
提升性能和并发处理
虽然 epoll
提供了高效的 I/O 事件通知机制,但是面对大量并发网络连接时,如何调度事件、充分利用多线程的同时避免竞争条件等问题,epoll
并不负责。这时就需要一个网络编程框架来把这些必要的基础性工作完成,例如封装 Reactor
模型。
此外,框架内部通常实现了很多性能优化,比如常见的 内存池
、零拷贝
、缓冲区
、减少上下文切换的无锁编程
等机制,这些优化细节大大提高了网络应用的性能。
解析复杂的网路协议
一个系统的通信往往由多种网络协议组成:
- 面向 C 端的 HTTP、WebSocket
- 面向 B 端的 TCP、UDP
- 系统内部众多服务之间互相调用的 RPC
- …
应用开发者不可能逐个去实现解析各种网络协议,代码质量难以得到保证,且属于重复性造轮子。
网络编程框架把解析的活儿干完,应用开发者可以专注于 “一把梭” 就可以了。
毕竟,对于大多数项目来说,最复杂的地方就是去实现一套绝对灵活的 “极品” 业务逻辑规则,而不是相对固定的网络协议解析。
错误/异常处理
网络编程不同于单机编程,除了程序外,整个通信链路中容易出现问题的地方也很多,下面的错误是不是似曾相识:
connection timed out
connection refused
no route to host
broken pipe
address already in use
network is unreachable
host unreachable
- …
如果这些错误全部交给应用开发者处理,那么在开始编写业务逻辑之前,代码可能已经变成了这个样子:
解决跨平台问题
Linux
的 epoll
仅仅是众多平台 I/O 多路复用实现机制其中的一种,如果开发者的系统需要运行在多个不同平台上,就要针对每个平台编写一套系统。
网络编程框架可以根据运行平台环境,(例如通过条件编译) 自动选择对应的 I/O 多路复用机制,真正做到代码 “一次编写,随地运行”。
2. 自定义功能和扩展性
既然是业务系统,那就说明每个模块、功能必要有优先级排序,几个重要且明显的需求就出来了:
- 优先运行系统的核心功能
- 紧急任务可以临时加塞到任务队列
- 可以根据系统运行环境,自定义不同的配置参数
- …
而这些需求,不可能直接和 epoll API
的调用代码堆叠到一起,此时,就需要借助网络编程框架来进行一个优雅且合理的代码实现分层。
技术性扩展功能
现代服务端网络程序中,一些基础组件是必备的,这时就可以直接借助框架来无缝集成,
最常见的也是最必要的就是 应用层的心跳检测机制 了,这一点无需解释太多。
此外还有:
- SSL/TLS 安全层扩展集成
- 传输数据压缩
- 自动重连/断开
- 负载均衡
- 网络连接统计、状态上报
- 针对 TCP 的粘包/拆包问题 的
编码器/解码器
- …
3. 降低开发成本和提升代码可维护性
epoll
实现在内核中,提供的 API 自然是 C/C++
语言版本。
即使现在 AI 已经可以写代码了,可以编写优秀的 C/C++
程序的程序员相对较为稀缺,且开发周期较长。相反,使用 Java/Go
直接编写业务代码的程序员有足够的市场供应,这样就可以降低招聘成本和周期,快速迭代产品,投入市场进行验证。毕竟对于一个公司/项目来说,活下去最重要,而活下去靠的是什么?赚钱的业务。
通过网络编程框架,让技术水平一般的程序员,快速写出可以投入生产环境的 “及格代码”。
小结
编程框架用于分层,而分层的核心目的就是: 使用最合适的技术完成对应的工作 (合适的就是最好的 ~🐶~)。
大佬们即使用汇编语言,也可以写出健壮的高性能程序,因为他们早就超越了代码的层次,已经和计算机软硬件融为一体,真正做到 “代码千行过,Bug 不沾身”。
但是软件开发行业,尤其是其中覆盖面最广的应用软件开发领域,不能只靠精英程序员的推动,而是需要更多普通程序员的参与,这也就是为什么软件要分为系统软件、中间件、应用软件,而每种类型的软件都使用适合的编程语言、语言框架用来开发。