架构设计之计算高性能——单体服务器高性能

架构设计之计算高性能——单体服务器高性能

高性能是每个程序员共同的追求,无论是开发系统,还是仅仅只是写一段脚本,都希望能够达到高性能的效果,而高性能又是软件系统设计中最复杂的一步。无论是开发千万级并发的电商系统,还是编写简单的数据处理脚本,开发者们都在不断追求更快的执行速度、更低的响应延迟。在网络时代,性能等同于用户体验。用户可能不会注意到精心设计的界面,但500毫秒的延迟就会显著降低满意度;开发者或许能优化复杂的算法,但I/O瓶颈却能让一切努力付诸东流。

而高性能又是软件系统设计中最复杂的一步。它要求我们平衡:

  • 资源效率:最大化利用CPU、内存、网络
  • 系统复杂度:避免过度设计带来的维护成本
  • 实时性与吞吐量:响应速度 vs 处理能力
  • 成本约束:服务器资源的经济性优化

高性能架构主要在两个维度展开:单服务器高性能集群高性能。本文主要聚焦单服务器领域,揭示如何通过网络编程模型的选择,在单台机器上压榨出极致的性能潜力。

1. 网络编程模型:

单服务器高性能的关键之一在于服务器采取的网络编程模型,网络编程模型的两个关键点:

  1. 服务器如何管理连接?
  2. 服务器如何处理请求?

这两个问题最终都指向操作系统的I/O模型进程/线程模型。不同的组合方式会产生截然不同的性能特征:

模型组合典型应用连接处理能力CPU利用率
阻塞I/O+多进程传统Apache中等较低
非阻塞I/O+线程池Tomcat NIO
异步I/O+协程Nginx极高极高
连接管理
I/O模型
阻塞I/O
非阻塞I/O
异步I/O
请求处理
进程模型
单进程
多进程
线程池
协程
PPC/prefork
Reactor
Proactor
TPC/prethread

2. PPC:

PPC是Process per Connection的缩写,其含义是指每次有新的连接就新建一个进程去专门处理这个连接的请求,这是传统的UNIX网络服务器所采用的模型。基本的流程图如下。
在这里插入图片描述
(1)父进程接受连接(图中accept)。
(2)父进程“fork”子进程(图中 fork)。
(3)子进程处理连接的读写请求(图中子进程read、业务处理、write)。
(4)子进程关闭连接(图中子进程中的 close)。

// 简化版PPC伪代码
while(1) {int conn_fd = accept(listen_fd);  // 接受新连接if(fork() == 0) {                 // 创建子进程close(listen_fd);             // 子进程关闭监听process_request(conn_fd);     // 处理请求close(conn_fd);               // 关闭连接exit(0);                      // 子进程退出}close(conn_fd);                   // 父进程关闭连接
}

PPC的优势

  • 逻辑隔离性强:进程崩溃不影响整体服务
  • 编程简单直接:无需考虑并发控制
  • 利用多核优势:操作系统自动调度进程

PPC的不足

ClientMain ProcessChild ProcessTCP SYNfork()代价1:进程创建开销传递conn_fdHTTP响应请求数据响应数据代价2:进程间通信开销loop[多次交互]TCP FIN进程终止代价3:资源回收延迟ClientMain ProcessChild Process

三大性能瓶颈

  1. 进程创建代价高昂:Linux中fork()需要复制页表、文件描述符等资源,消耗数百微秒
  2. 进程通信复杂低效:共享内存需同步、管道/消息队列引入额外拷贝
  3. 进程数量限制:Linux默认最多32768进程,消耗GB级内存

3. Prefork:

空间换时间

在PPC模式中,当连接进来时才“fork”新进程来处理连接请求,由于“fork”进程代价高,用户访问时可能感觉比较慢,prefork模式的出现就是为了解决这个问题。面对PPC的性能瓶颈,Prefork模式带来的思路是:预先创建进程池,规避实时fork()的开销。

// Prefork实现框架
void init_process_pool(int num) {for(int i=0; i<num; i++) {if(fork() == 0) {// 子进程进入就绪循环while(1) {int conn_fd = accept_lock(listen_fd);process_request(conn_fd);close(conn_fd);}}}
}

优化点

  • 进程预热:服务启动时创建N个进程
  • 资源预分配:预先分配文件描述符、内存等
  • 连接竞争管理:通过文件锁控制accept()调用
进程池
accept竞争
进程1
进程2
进程N
启动服务
创建进程池
获得连接
处理请求
  • 优势:解决实时fork开销,连接响应时间平均降低40%
  • 局限:未能解决进程间通信和内存开销问题
  • 典型应用:Apache HTTP Server的prefork MPM模式

进程池大小设置公式
推荐pool_size = CPU核心数 × 2 + 预期平均并发数 × 0.2

4. TPC:轻量级线程的崛起

TPC是 Thread per Connection的缩写,其含义是指每次有新的连接就新建一个线程去专门处理这个连接的请求。与进程相比,线程更轻量级,创建线程的消耗比进程要少得多:同时多线程是共享进程内存空间的,线程通信相比进程通信更简单。因此,TPC实际上是解决或弱化了PPC的问题1(fork代价高)和问题2(父子进程通信复杂)。

TPC 的基本流程如下:
(1)父进程接受连接(图中 accept)。
(2)父进程创建子线程(图中pthread)。
(3)子线程处理连接的读写请求(图中子线程read、业务处理、write)。
(4)子线程关闭连接(图中子线程中的 close)。
在这里插入图片描述

TPC(Thread Per Connection) 的核心:为每个连接创建服务线程而非进程

// Java TPC示例
ServerSocket server = new ServerSocket(8080);
while(true) {Socket client = server.accept();new Thread(() -> {// 在线程中处理请求handleRequest(client);}).start();
}

优点

  • 创建成本下降:线程创建仅需10-30微秒,比进程快10倍
  • 通信效率提升:共享内存空间,避免数据拷贝
  • 上下文切换快:线程切换开销仅为进程的1/5

不足

  • 并发限制:Java默认每进程最多2000线程
  • 同步复杂性:共享资源需要加锁
  • 多核调度开销:线程数量超过CPU核心时效率下降

5. Prethread:线程池的力量

在TPC模式中,当连接进来时才创建新的线程来处理连接请求,虽然创建线程比创建进程要更加轻量级,但还是有一定的代价,而prethread模式就是为了解决这个问题。和 prefork 类似,prethread 模式会预先创建线程,然后才开始接受用户的请求,当有新的连接进来的时候,就可以省去创建线程的操作,让用户感觉更快、体验更好。
由于多线程之间数据共享和通信比较方便,因此实际上prethread的实现方式相比prefork要灵活一些,常见的实现方式有下面几种:
(1)主进程 accept,然后将连接交给某个线程处理。
(2)子线程都尝试去 accept,最终只有一个线程accept成功,方案的基本示意图如下
在这里插入图片描述

Prethread模式通过线程池优化TPC:

# Python线程池示例
from concurrent.futures import ThreadPoolExecutorwith ThreadPoolExecutor(max_workers=100) as executor:while True:client_sock = server_sock.accept()executor.submit(handle_connection, client_sock)

线程池

  1. 线程复用:避免频繁创建/销毁开销
  2. 流量控制:通过队列缓冲突发请求
  3. 资源隔离:重要业务使用独立线程池
请求处理
空闲
空闲
繁忙
任务队列
新连接
线程状态
线程1
线程2
等待队列

线程池配置


Tomcat线程池配置
maxThreads = 200 # 最大线程数minSpareThreads = 20 # 最小空闲线程queueSize = 100 # 等待队列大小

6. Reactor模式:I/O多路复用的革命

PPC方案最主要的问题就是每个连接都要创建进程(为了描述简洁,这里只以PPC和进程为例,实际上换成 TPC 和线程,原理是一羊的),连接结束后进程就销毁了,这样做其实是很大的浪费。为了解决这个问题,一个自然而然的想法就是资源复用,即不再单独为每个连接创建进程,而是创建一个进程池,将连接分配给进程,一个进程可以处理多个连接的业务。

Reactor 模式的核心组成部分包括 Reactor 和处理资源池(进程池或线程池),其中 Reactor负责监听和分配事件,处理资源池负责处理事件。初看Reactor的实现是比较简单的,但实际上结合不同的业务场景,Reactor模式的具体实现方案灵活多变,主要体现在如下两点Reactor的数量可以变化:可以是一个Reactor,也可以是多个Reactor。
资源池的数量可以变化:以进程为例,可以是单个进程,也可以是多个进程(线程类似)。

Reactor模式通过I/O多路复用实现质的飞跃:

  • 核心:单线程/进程监听所有连接状态,事件触发后分发处理

6.1 单Reactor单进程

监听
可读事件
可写事件
错误事件
Reactor
epoll/kqueue
Handler1
Handler2
Handler3
  • 代表应用:Redis
  • 优点:极致简单高效
  • 缺点:无法利用多核

6.2 单Reactor多进程

多进程
事件
任务
响应
进程1
进程2
进程N
Reactor
epoll
分发器
进程池
  • 代表应用:Apache MPM worker
  • 折中方案:平衡多核与复杂度

6.3 多Reactor多进程

子Reactor组
线程池
SubReactor1
线程池
SubReactor2
MainReactor
  • 代表应用:Nginx
  • 终极方案:每个CPU核心独立Reactor

Reactor的三个核心组件

  1. Initiation Dispatcher:核心调度器
  2. Synchronous Event Demultiplexer:I/O多路复用器
  3. Event Handler:事件处理回调

7. Proactor:

Reactor 是非阻塞同步网络模型,因为真的read 和send 操作都需要用户进程同步操作,这里的“同步”指用户进程在执行read 和 senc这类 I/O 操作的时候是同步的,如果把 I/O 操作网络模型 Proactor。改为异步就能够进一步提升性能,这就是异步网络模型Proactor。

Reactor 可以理解为“来了事件我通知你你来处理”,而Proactor 可以理解为“来了事件我来处理,处理完了我通知你”。这里的“我”就是操作系统内核,“事件”就是有新连接、有数据可读、有数据可写这些 IO 事件。

AppProactorOS发起异步读请求提交读操作I/O完成事件回调处理函数AppProactorOS

与Reactor的本质差异

  • Reactor:通知何时可读 → 用户执行读取
  • Proactor:直接读取完成 → 用户处理数据

Proactor的优势

  • 完全避免用户态I/O阻塞
  • 更高吞吐量,尤其适合大文件传输
  • Windows IOCP原生支持

Linux实现方案

// Linux AIO示例
struct aiocb cb = {.aio_fildes = fd,.aio_buf = buf,.aio_nbytes = size
};
aio_read(&cb); // 发起异步读
while(aio_error(&cb) == EINPROGRESS); // 等待完成

结语:

通过了解单服务器高性能架构的演进,我们见证了性能的进步其实就是探索-枷锁-破冰的历程:

  • 资源粒度:从进程到线程再到协程
  • I/O效率:从阻塞到非阻塞再到异步
  • 控制方式:从串行到分时再到事件驱动

选择架构的核心准则

  • C10K以下:线程池或prefork足够
  • C100K级别:Reactor模式必备
  • C10M级别:Proactor+多Reactor+DPDK

当今最前沿的两种架构

使用
使用
Nginx
多Reactor多进程+epoll
Netty
Reactor+线程池

最后:没有普适的最优解,只有特定场景下的最佳选择。衡量维度包括:

  • 并发量预期
  • 请求响应时间分布
  • 数据局部性特征
  • 硬件资源组合

📌 关注 是对原创的最大认可,你的每一个关注 ,都是技术生态圈的+1节点!
🔔 开启通知,下一篇《架构设计之计算高性能——集群高性能》内容更新时,你就是技术圈最前沿的「极客」!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/89111.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/89111.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity灯光面板环境设置

在Unity中&#xff0c;环境设置&#xff08;Environment Lighting&#xff09; 是灯光面板&#xff08;Lighting Window&#xff09;的核心功能之一&#xff0c;用于控制场景的全局光照效果&#xff0c;包括天空盒、环境光、反射和雾效等。这些设置直接影响场景的整体氛围和真实…

MySQL语句优化案例

1.案例in查询条件很慢其中in中共115个select id,detail_id,request,response,utime,ctime from response_detaill where detaill_id in (26371986, 26372242, 26371984, 26371990, 26400150, 26371988, 26371994, 26371992,26371998, 26371996, 26371970, 26371968, 2637197…

能行为监测算法:低成本下的高效管理

AI监控智慧公司管理&#xff1a;降本增效的实践与突破一、背景&#xff1a;经济压力下的管理转型需求在经济下行周期&#xff0c;企业面临人力成本攀升、管理效率低下、安全风险频发等多重挑战。传统监控依赖人工巡检&#xff0c;存在响应滞后、误判率高、数据孤岛等问题&#…

当前(2024-07-14)视频插帧(VFI)方向的 SOTA 基本被三篇顶会工作占据,按“精度-速度-感知质量”三条线总结如下,供你快速定位最新范式

当前&#xff08;2024-07-14&#xff09;视频插帧&#xff08;VFI&#xff09;方向的 SOTA 基本被三篇顶会工作占据&#xff0c;按“精度-速度-感知质量”三条线总结如下&#xff0c;供你快速定位最新范式。感知质量最佳&#xff1a;CVPR 2024 ‑ PerVFI • 关键词&#xff1a;…

开源 python 应用 开发(七)数据可视化

最近有个项目需要做视觉自动化处理的工具&#xff0c;最后选用的软件为python&#xff0c;刚好这个机会进行系统学习。短时间学习&#xff0c;需要快速开发&#xff0c;所以记录要点步骤&#xff0c;防止忘记。 链接&#xff1a; 开源 python 应用 开发&#xff08;一&#xf…

基于深度学习的情感分析模型:从文本数据到模型部署

前言 情感分析&#xff08;Sentiment Analysis&#xff09;是自然语言处理&#xff08;NLP&#xff09;领域中的一个重要应用&#xff0c;它通过分析文本数据来判断文本的情感倾向&#xff0c;例如正面、负面或中性。随着社交媒体的兴起&#xff0c;情感分析在市场调研、品牌管…

使用python 实现一个http server

下面是一个使用 Python 内置库 http.server 的简单 HTTP 服务器实现。不需要安装任何第三方库&#xff0c;非常适合做演示或开发测试用。 from http.server import HTTPServer, BaseHTTPRequestHandlerclass SimpleHTTPRequestHandler(BaseHTTPRequestHandler):def do_GET(self…

Redis技术笔记-主从复制、哨兵与持久化实战指南

目录 前言 一、Redis主从复制 &#xff08;一&#xff09;Redis主从复制介绍 &#xff08;二&#xff09;基本环境准备 &#xff08;三&#xff09;工作原理 &#xff08;四&#xff09;结构模式 &#xff08;五&#xff09;一主一从&#xff08;无密码&#xff09; 配置…

sundog公司的SilverLining SDK库实现3d动态云层和下雨、下雨、雨夹雪效果

OSG系列文章目录 文章目录OSG系列文章目录前言一、3d动态云与下雨、下雪效果不能同时出现二、3d动态云与下雨、下雪效果不能同时出现的原因三、解决办法&#xff1a;前言 先看下效果&#xff1a;下雨 效果&#xff1a;下雪 效果&#xff1a;雨夹雪 &#x1f324;️ Sundo…

Python:简易的 TCP 服务端与客户端示例

下面是一个完整的 TCP 服务端与客户端示例&#xff0c;适用于 Python 3&#xff0c;使用 socket 模块&#xff0c;并正确处理了中文传输与异常情况&#xff0c;支持基本的多轮通信。TCP 服务端&#xff08;server_tcp.py&#xff09;import socket HOST 127.0.0.1 # 监听本地…

文心一言 4.5 开源深度剖析:中文霸主登场,开源引擎重塑大模型生态

> 百度用一场彻底的开源风暴,宣告中文大模型进入性能与普惠并重的新纪元——这里没有技术黑箱,只有开发者手中跃动的创新火花。 2025年,当全球大模型竞赛进入深水区,百度文心一言4.5的开源如同一颗重磅炸弹,彻底打破了“闭源即领先”的固有认知。这一次,中国团队不…

解决“Windows 无法启动服务”问题指南

错误1067&#xff1a;进程意外终止一、重启计算机有时系统出现临时性的服务故障&#xff0c;重启计算机就可以有效解决问题。需要注意的是&#xff0c;在重启之前&#xff0c;需要保存好所有未保存的工作&#xff0c;以免数据丢失。重启完成后&#xff0c;再次尝试启动相关服务…

银河麒麟(Kylin) - V10 GFB高级服务器操作系统ARM64部署昇腾910b训练机以及Docker安装

银河麒麟(Kylin) - V10 GFB高级服务器操作系统ARM64部署昇腾910b训练机以及Docker安装 原因 项目需要使用Deepseek-r1-distill-qwen-32b来做训练&#xff0c;在此记录 测试环境 服务器配置 型号&#xff1a;G5680V2 CPU&#xff1a;CPU 4Kunpeng 920-5250 NPU&#xff1a;NP…

消息中间件(Kafka VS RocketMQ)

目录 一、概要介绍 二、架构与原理 三、消费模式 1、Kafka—纯拉模式 2、RocketMQ—拉模式 3、RocketMQ—推模式 4、模式对比 四、特殊消息 1、顺序消息 2、消息过滤 3、延迟消息 4、事务消息 5、广播消息 五、高吞吐 六、高可用 七、高可靠 一、概要介绍 Apa…

MyBatis级联查询深度解析:一对多关联实战指南

MyBatis级联查询深度解析&#xff1a;一对多关联实战指南在实际企业级开发中&#xff0c;单表操作仅占20%的场景&#xff0c;而80%的业务需求涉及多表关联查询。本文将以一对多关系为例&#xff0c;深入剖析MyBatis级联查询的实现原理与最佳实践&#xff0c;助你掌握高效的数据…

搜索框的显示与隐藏(展开与收起)

效果如下直接上代码v-if"showAll || 0 < 3" 的意思是&#xff1a;如果 showAll 为 true&#xff0c;或者 0 小于 3&#xff0c;这个表单项就会显示。<el-form :inline"true" class"demo-form-inline" size"default" label-width…

01 启动流程实例

前言本文基于 Activiti 7.0.0.GA 源码&#xff0c;研究 Activiti 如何启动一个流程实例。审批流程图如下图&#xff0c;在此流程图中&#xff0c;存在两个UserTask节点&#xff0c;第一个节点是主管审批&#xff0c;第二个节点是产品经理审批&#xff0c;两个节点中间有一个排他…

LeetCode--47.全排列 II

解题思路&#xff1a;1.获取信息&#xff1a;给定一个可包含重复数字的序列&#xff0c;按任意顺序返回所有不重复的全排列提示信息&#xff1a;1 < nums.length < 8-10 < nums[i] < 102.分析题目&#xff1a;相较于46题&#xff0c;它多限制了一个条件&#xff0c…

vue3 服务端渲染时请求接口没有等到数据,但是客户端渲染是请求接口又可以得到数据

原因是: 服务端请求 后端接收到 请求 ‘Content-Type’: ‘application/x-www-form-urlencoded; charsetUTF-8’ 直接返回错误的code 200000 增加 data: {} 服务端请求 后端接收到 请求 ‘Content-Type’: ‘application/json; charsetUTF-8’ 服务端请求就可以得到数据 expo…

Linux 文件操作命令大全:从入门到精通的实用指南

Linux 文件操作命令大全&#xff1a;从入门到精通的实用指南 在 Linux 系统中&#xff0c;文件操作是日常工作的核心内容之一。无论是开发者、运维工程师还是 Linux 爱好者&#xff0c;掌握常用的文件操作命令都能极大提升工作效率。本文将详细介绍 Linux 系统中最常用的文件操…