写点什么

系统服务 - 技术专题 - 并发模型粗浅分析探讨

发布于: 2021 年 04 月 29 日
系统服务-技术专题-并发模型粗浅分析探讨

基本概念


  • 并发 concurrency

  • 并行 parallelism

  • 吞吐量 throughput

并发请求



并行请求



吞吐量

  • 单位时间内服务器总的请求处理量

  • 以 request/second 来衡量,如 1200rps

  • 每个请求的处理时间 latency(延迟时间)

  • 服务器处理请求的并发 workers

  • 其他因素如 GC 也会影响吞吐量

举例: CSDN new bbs

  • 平均每个请求的 latency  = 200ms

  • 总共 40 个 workers

  • 理论吞吐量上限 (1000/200)*40 = 200rps

  • 理论每日处理动态请求上限 1700 万,目前实际每日处理动态请求 270-330 万,预估实际处理上限 600 万

IO 类型

  • 磁盘文件操作,例如读硬盘文件

  • 操作系统调用,例如 shell 命令

  • 网络操作

  • 访问数据库 MySQL, MongoDB, ...

  • 访问其他 Web 服务,发起网络连接

  • 访问缓存服务器 Memcached, Redis

典型 IO 密集请求

IO 密集型并发

并发真能提高吞吐量吗?

场景

假设每个请求执行 100ms,顺序执行 10 个请求共需要 1s,单核服务器并发处理 10 个请求,假设平均分

配时间片 10ms,请求 1 到请求 10 将在 900ms 到 1000ms 间执行完毕。吞吐量没有任何提高。

计算密集型

计算密集型的场景下,并发越多,所有请求都变得非常缓慢。(考虑到任务的场景切换开销,吞吐量还会下降,需要超过 1s 才能执行完毕)。

大多数 Web 型应用都是 IO 密集型执行请求 100ms 当中,可能有 80ms 花在 IO 上,只有 20ms 消耗 CPU 时钟周期,最好情况下,请求 1 到请求 10 将在 190ms 到 280ms 间执行完毕,吞吐量极大提高。

IO 密集型

IO 密集型应用,大部分 CPU 花在等待 IO 上了,所以并发可以有效提高系统的吞吐量




并发和并行

纯 CPU 密集型的应用

在单核上并发执行多个请求,不能提高吞吐量

由于任务来回场景切换的开销,吞吐量反而会下降

只有多核并行运算,才能有效提高吞吐量

IO 密集型的应用

由于请求过程中,很多时间都是外部 IO 操作,CPU 在 wait 状态,所以并发执行可以有效提高系统吞吐量

Web 并发模型

  • multi-process

  • multi-thread

  • multi-process + multi-thread(GIL)

  • event I/O(相应时间)

  • Coroutine(协程)

multi-process

  • 常见多进程 Web 服务端编程模型

  • PHP

  • Python

  • Ruby

多进程的管理

  • 多进程并发

  • 每个进程可以并发处理 1 个请求,并发能力等于进程数量

  • 由操作系统负责进程调度,程序无法控制

  • 可以通过操作系统命令影响进程调度优先 nice

  • 多进程调度

  • 例如在一台 4 核服务器上,运行 10 个 PHP 进程。由操作系统负责给某个 PHP 进程分配某个 CPU 内核的时间片,实现 10 个并发处理

多进程优点

  • 并发模型非常简单,由操作系统调度运行稳定强壮

  • 非常容易管理

  • 很容易通过操作系统方便的监控,例如每个进程 CPU,内存

  • 变化状况,甚至可以观测到进程处理什么 Web 请求

  • 很容易通过操作系统管理进程,例如可以通过给进程发送

  • signal,实现各种管理: unicorn

  • 隔离性非常好

  • 一个进程崩溃不会影响其他进程

  • 某进程出现问题的时候,只要杀掉它重启即可,不影响整体服务的可用性

  • 很容易实现在线热部署和无缝升级

  • 代码兼容性极好,不必考虑线程安全问题

  • 多进程可以有效利用多核 CPU,实现并行处理

多进程的监控手段

多进程缺点

  • 内存消耗大户

  • 每个独立进程都需要加载完整的应用环境,内存消耗超大。(COW 模式可以缓解这个问题)

  • 例如每个 Rails 进程物理内存占用为 150MB,20 个 workers,则需要 3GB 物理内存。

  • CPU 消耗偏高

  • 多进程并发,需要 CPU 内核在多个进程间频繁切换,而进程的场景切换(context switch)是非常昂贵的,需要大量的内存换页操作。

  • 很低的 I/O 并发处理能力

多进程的低 IO 并发问题

  • 多进程的并发能力非常有限

  • 每个进程只能并发处理 1 个请求

  • 单台服务器启动的进程数有限,并发处理能力无法有效提高

  • Rails 进程消耗内存很大,单台服务器一般启动 30 个 Rails 实例

  • PHP FastCGI 进程非常轻量级,但单台服务器一般启动 64 个

  • 只适合处理短请求,不适合处理长请求

  • 每个请求都能在很短时间内执行完毕,因而不会造成进程被长期阻塞

  • 一旦某个操作特别是 IO 操作阻塞,就会造成进程阻塞,当大面积 IO 操作阻塞发生,服务器就无法响应了

  • 对于无法预知的外部 IO 操作,应用代码必须设置 timeout 参数,以防进程阻塞

缓解多进程低 IO 并发问题

  • 用 nginx 做前端 Web Server

  • 适当增大 proxy buffer size,避免多进程 request/response buffer IO 开销

  • 使用 X-sendfile,避免多进程读取大文件 IO 开销

  • 凡 IO 操作都要设置 timeout

  • 避免无法预知的 IO 挂起造成进程阻塞

  • 编写智能防火墙代码

  • 防止劣质爬虫和其他恶意的 DOS 攻击行为

  • 长请求和短请求分离开,不要放在一起


用户头像

我们始于迷惘,终于更高水平的迷惘。 2020.03.25 加入

🏆 【酷爱计算机技术、醉心开发编程、喜爱健身运动、热衷悬疑推理的”极客狂人“】 🏅 【Java技术领域,MySQL技术领域,APM全链路追踪技术及微服务、分布式方向的技术体系等】 🤝未来我们希望可以共同进步🤝

评论

发布
暂无评论
系统服务-技术专题-并发模型粗浅分析探讨