惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
WordPress大学
WordPress大学
云风的 BLOG
云风的 BLOG
Stack Overflow Blog
Stack Overflow Blog
MongoDB | Blog
MongoDB | Blog
腾讯CDC
V
V2EX
Martin Fowler
Martin Fowler
A
About on SuperTechFans
大猫的无限游戏
大猫的无限游戏
Blog — PlanetScale
Blog — PlanetScale
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
酷 壳 – CoolShell
酷 壳 – CoolShell
C
Check Point Blog
博客园 - 【当耐特】
Cisco Talos Blog
Cisco Talos Blog
The Hacker News
The Hacker News
K
Kaspersky official blog
Security Latest
Security Latest
H
Help Net Security
博客园_首页
美团技术团队
Spread Privacy
Spread Privacy
博客园 - 司徒正美
Hugging Face - Blog
Hugging Face - Blog
S
SegmentFault 最新的问题
G
Google Developers Blog
NISL@THU
NISL@THU
爱范儿
爱范儿
I
Intezer
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
阮一峰的网络日志
阮一峰的网络日志
N
News and Events Feed by Topic
P
Privacy International News Feed
Application and Cybersecurity Blog
Application and Cybersecurity Blog
S
Security @ Cisco Blogs
Schneier on Security
Schneier on Security
雷峰网
雷峰网
人人都是产品经理
人人都是产品经理
V
Vulnerabilities – Threatpost
W
WeLiveSecurity
P
Palo Alto Networks Blog
G
GRAHAM CLULEY
Hacker News: Ask HN
Hacker News: Ask HN
I
InfoQ
The Cloudflare Blog
F
Full Disclosure
SecWiki News
SecWiki News
宝玉的分享
宝玉的分享
N
Netflix TechBlog - Medium

蛮荆

如何获取更多的免费服务器 Kubernetes 调度器队列 - 设计与实现 Kubernetes 调度器 - 核心流程 Kubernetes Networking Model & CNI Kubernetes 控制器管理总结 Kubernetes CronJob 设计与实现 Kubernetes Job 设计与实现 Kubernetes HPA 设计与实现 Kubernetes Deployment 滚动更新实现原理 Kubernetes GC 设计与实现 Kubernetes Pod 驱逐 - 设计与实现 Kubernetes Daemonset 设计与实现 Kubernetes ReplicaSet 设计与实现 Kubernetes EndPoint 设计与实现 Kubernetes Informer 设计与实现 降本增效之应用优化 (三) 日志存储与检索 Kubernetes Pod 设计与实现 - 创建流程 Kubernetes 探针设计与实现 Unix 编程艺术名句摘录 Kubernetes - CRI 概述 Golang 编译速度为什么这么快? Kubernetes Pod 设计与实现 - Pause 容器 Kubernetes - kube-proxy 代理模式工程优化 Kubernetes 应用最佳实践 - 优雅关闭长连接 Kubernetes Service 类型和会话亲和性 Kubernetes 为什么需要 Ingress Kubernetes 架构 - 控制平面和数据平面 降本增效之应用优化 (二) 大报表 Go 语言如何获取 CPU 利用率 降本增效之应用优化 (一) Redis 业务规则引擎演变过程简述 微服务中的熔断算法 漏桶算法和令牌桶算法 jsonparser 为什么比标准库的 encoding/json 快 10 倍 ? zap 高性能设计与实现 HTTP Router 算法演进 fastcache 高性能设计与实现 Web 常见的三个安全问题 ants Code Reading Go 线程安全 map 方案选型 布隆过滤器 死锁、活锁、饥饿、自旋锁 sync.Pool Code Reading Go 内存管理概述 Go netpoll Code Reading goroutine 泄漏与检测 time/Timer Code Reading GMP Scheduler Code Reading Go channel 的 15 条规则和底层实现 为什么 Linux “一切皆文件” context.Context Code Reading runtime/HACKING.md Goland 最佳实践 互联网开发与金庸武学 为什么 Redis 6.0 引入多线程模型? Kubernetes 应用最佳实践 - 金丝雀发布 容器中如何正确配置 GOMAXPROCS ? singleflight Code Reading sync.Map Code Reading sync.Cond Code Reading sync.WaitGroup Code Reading sync.RWMutex Code Reading sync.Mutex Code Reading sync.Once Code Reading Go 无锁编程 sync/atomic Code Reading goroutine 交替打印奇偶数 GODEBUG Go 并发模式 Go 汇编 UUID 通用技术选型 Kubernetes 应用最佳实践 - 水平自动伸缩 Go 高性能 Tips fasthttp 为什么比标准库 net/http 快 10 倍 ? 技术文章配图指南 ChatGPT 初体验 Docker 网络原理概览 iptables 的五表五链 Kubernetes 应用最佳实践 - 亲和性和污点容忍度 Go 的反射与三大定律 Docker 官方提供的最佳实践 Go 语言内置的设计模式 HTTP1 到 HTTP3 的工程优化 Kubernetes 应用最佳实践 - Sidecar 模式 Kubernetes 应用最佳实践 - init 容器和钩子函数 为什么 recover 必须在 defer 中调用? 为什么 defer 的执行顺序和注册顺序不同? Go map 设计与实现 Go 切片扩容底层实现 Go 语言中的零拷贝 Go Delve 云原生和边缘计算简介 Kubernetes Pod 服务质量等级 Kubernetes 应用最佳实践 - 探针 Kubernetes 应用最佳实践 - 资源请求和限制 CDN 原理 Kubernetes 应用最佳实践 - 开篇 缓存策略和模式 Go 内存模型 Kubernetes 核心概念
网络编程框架的作用和价值
2022-10-25 · via 蛮荆

网络编程框架的作用和价值

2022-10-25 计算机网络 网络编程

  • 问题
  • 1. 简化复杂的网络编程
    • 提升性能和并发处理
    • 解析复杂的网路协议
    • 错误/异常处理
    • 解决跨平台问题
  • 2. 自定义功能和扩展性
    • 技术性扩展功能
  • 3. 降低开发成本和提升代码可维护性
  • 小结

问题

既然 Linux 提供了 epoll 这样的 I/O 多路复用机制,接近内核且高性能,为什么开发者不直接使用 epoll 进行编程?而是在应用层折腾出了类似 Netty (Java), gnet (Golang) 这样的网络编程框架呢?

毕竟,每多一层封装,系统的整体性能就会有 (主要是数据复制带来的) 损耗。

或者换个说法: 网络编程框架的作用和价值体现在哪里?

这个问题,就类似: “有了汇编语言,为什么还要有高级语言” ?

答案其实和简单,总结出来无非是 3 点:

  1. 简化复杂的网络编程
  2. 自定义功能和扩展性
  3. 降低开发成本、提升代码可维护性

1. 简化复杂的网络编程

编程框架可以屏蔽细节,简化并统一 API,使应用开发者可以专注处理业务逻辑,降低心智负担,提高交付效率和质量。

上面是直接使用 epoll 提供的 API 进行编程时,(Socket) 文件描述符的相关操作的简化图,除此之外,开发者还需要其他的各种底层操作:

  • Reactor 模型的实现 (为了有效管理)
  • I/O 事件处理
  • 各类网络协议解析
  • 多线程实现 (为了高性能)

但是有了编程框架之后,就完全不一样了: 框架会处理好所有底层的这些 “脏活累活”,以 TCP 协议为例,最终传递到应用开发者的就是事件名称以及对应的应用数据,应用开发者只需要重复三板斧操作就可以了:

  1. 读数据
  2. 处理业务逻辑
  3. 写数据

所以网络编程框架,本质上可以看作是应用层的 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

如果这些错误全部交给应用开发者处理,那么在开始编写业务逻辑之前,代码可能已经变成了这个样子:

解决跨平台问题

Linuxepoll 仅仅是众多平台 I/O 多路复用实现机制其中的一种,如果开发者的系统需要运行在多个不同平台上,就要针对每个平台编写一套系统。

网络编程框架可以根据运行平台环境,(例如通过条件编译) 自动选择对应的 I/O 多路复用机制,真正做到代码 “一次编写,随地运行”。


2. 自定义功能和扩展性

既然是业务系统,那就说明每个模块、功能必要有优先级排序,几个重要且明显的需求就出来了:

  • 优先运行系统的核心功能
  • 紧急任务可以临时加塞到任务队列
  • 可以根据系统运行环境,自定义不同的配置参数

而这些需求,不可能直接和 epoll API 的调用代码堆叠到一起,此时,就需要借助网络编程框架来进行一个优雅且合理的代码实现分层。

技术性扩展功能

现代服务端网络程序中,一些基础组件是必备的,这时就可以直接借助框架来无缝集成,

最常见的也是最必要的就是 应用层的心跳检测机制 了,这一点无需解释太多。

此外还有:

  • SSL/TLS 安全层扩展集成
  • 传输数据压缩
  • 自动重连/断开
  • 负载均衡
  • 网络连接统计、状态上报
  • 针对 TCP 的粘包/拆包问题编码器/解码器

图片来源: https://netty.io/


3. 降低开发成本和提升代码可维护性

epoll 实现在内核中,提供的 API 自然是 C/C++ 语言版本。

图片来源: BOSS 直聘

即使现在 AI 已经可以写代码了,可以编写优秀的 C/C++ 程序的程序员相对较为稀缺,且开发周期较长。相反,使用 Java/Go 直接编写业务代码的程序员有足够的市场供应,这样就可以降低招聘成本和周期,快速迭代产品,投入市场进行验证。毕竟对于一个公司/项目来说,活下去最重要,而活下去靠的是什么?赚钱的业务。

通过网络编程框架,让技术水平一般的程序员,快速写出可以投入生产环境的 “及格代码”。

图片来源: https://www.oracle.com/


小结

编程框架用于分层,而分层的核心目的就是: 使用最合适的技术完成对应的工作 (合适的就是最好的 ~🐶~)。

大佬们即使用汇编语言,也可以写出健壮的高性能程序,因为他们早就超越了代码的层次,已经和计算机软硬件融为一体,真正做到 “代码千行过,Bug 不沾身”。

但是软件开发行业,尤其是其中覆盖面最广的应用软件开发领域,不能只靠精英程序员的推动,而是需要更多普通程序员的参与,这也就是为什么软件要分为系统软件、中间件、应用软件,而每种类型的软件都使用适合的编程语言、语言框架用来开发。