您现在的位置是:网站首页>技术百科技术百科
并发思考:现代网络应用程序如何处理多个连接
小大寒2024-01-01[技术百科]博学多闻
并发思考:现代网络应用程序如何处理多个连接本文探讨了现代网络应用程序如何处理多个连接,介绍了进程、线程和反应器模式等多种并发处理方式的优缺点。通过比较这些模式,帮助开发人员选择适合的架构,以实现高效的并发处理和系统可扩展性。
并发思考:现代网络应用程序如何处理多个连接
文中的阿牛是一名资深软件开发工程师,如果有重名的,纯属巧合。但是,文中的技术是真的,是实战纪录。
阿牛探索了不同类型的多处理并研究了每种类型的优缺点。
当阿牛刚开始做咨询时,阿牛的客户大多数都是刚开始使用网络的小型组织,他们不可避免地会问阿牛:“需要什么样的高性能服务器?”客户们总是认为他们的网站会变得非常受欢迎,必然会有大量的访问者涌入——因此,他们需要确保服务器能够承受这种负载。
阿牛会提醒他们,每天有 86,400 秒。这意味着,如果每秒有一名新用户访问他们的网站,服务器每天将需要处理 86,400 个请求 —— 对于大多数现代计算机来说,这是微不足道的数字,尤其是如果只是提供静态文件。
然后阿牛会问他们:“真的希望每天吸引超过 86,000 名访客吗?”客户几乎都会有些羞怯地回答:“不,绝对不会。”
阿牛明白了,客户无需担心服务器的大小或速度,他的目标是以一种戏剧化的方式说服客户,他们无需为新服务器花费更多钱。但在展示这些数字时,阿牛也做了一些修正 —— 例如,假设一天的访客是均匀分布的,但实际上,午餐时间的流量将会激增,许多人会在这时进行休闲阅读或购物。
随着网页加载时包含的 CSS、JavaScript 和图像的增加,即使是 20,000 名访问者,您的服务器也可能会处理超过 200,000 个 HTTP 请求。
当一个简单的网站变成一个复杂的网络应用程序时,您还需要考虑后端数据库和第三方服务的性能,以及执行一些计算所需的时间。
在这种情况下,如果您每秒只能处理一个请求,那么多个用户同时访问时会发生什么呢?您可能会让其中一个用户等待另一个用户完成处理之后再进行下一步操作,但如果同时有 10 或 15 个请求,这种策略最终会适得其反。
大多数现代系统使用的解决方案是多处理:让计算机同时执行多项任务。如果计算机每秒能够执行两项任务,并且访客的数量在一天内均匀分布,那么您可以处理 172,800 名访客。如果可以同时执行三项任务,那么您能处理 259,200 名访客,以此类推。
那么计算机如何才能同时做多件事呢?使用单个 CPU 时,每个进程都会获得一个“时间片”,即 CPU 工作时间的一部分。如果有十个进程,每个进程将获得相等的时间片,每秒运行一次,持续 0.1 秒。随着进程数量的增加,分配给每个进程的时间会变少。
现代计算机通常配有多个 CPU(核心),这意味着它们能够并行执行任务,而不是简单地为每个进程分配一个时间片。理论上,如果您有十个进程和双核系统,每秒可以运行每个进程一次,持续 0.2 秒,任务分配到各个处理器上。
尽管缩放并非完全线性,无法精准预测,但这种方式是一个理想的思考方式。
正如前文所述,进程是计算机同时执行多项任务的常见方式。然而,许多应用程序还采用其他并发处理方法,如线程和反应器模式,特别是在 node.js 和 nginx HTTP 服务器中,线程和反应器模式尤为流行。
因此,阿牛将探讨现有的几种多处理方式,并分析每种方式的优缺点。即使您不打算更换现有架构,了解不同的多处理方法仍然是很有价值的。
流程
进程背后的概念非常简单:一个正在运行的程序不仅包含执行代码,还包括数据和上下文。由于代码、数据和上下文存储在内存中,操作系统可以非常快速地在不同进程间切换。代码 + 数据 + 上下文的组合叫做“进程”,它是 Linux 系统的工作基础。
启动 Linux 系统时,只有一个进程在运行。然后这个进程会“分叉”,生成两个相同的进程。第二个进程会读取新代码、数据和上下文(“exec”),开始运行一个新进程。整个系统运行时会不断地进行这一过程。当您在命令行中使用 & 启动新程序时,您是在分叉一个新的 shell 进程,然后在其上执行所需程序。
Apache httpd 服务器在许多 Linux 系统中非常流行,默认采用进程模型。您可能以为当有新请求时,Apache 会启动一个新的进程来处理它。但由于启动进程需要时间,这会导致延迟。因此,Apache 使用了“预分叉”的方式,预先启动一组进程,以便新请求到达时可以立即处理。当 Apache 检测到进程数不足时,会自动扩展进程池,确保总有足够的进程来处理请求。
尽管进程模型非常优秀,但也有一定的开销。如果您只是提供静态文件或进行少量处理,使用完整进程可能会显得过于繁重。
线程
具有 Windows 或 Java 背景的人常常批评 UNIX 使用进程,认为进程太重,线程更适合处理大部分任务。线程类似于进程,只是存在于进程内部。
线程共享进程中的内存,这使得它们的启动速度比进程更快,且内存消耗较少。由于线程共享内存,也带来了一些潜在的问题,如多个线程同时访问相同的数据时如何保证数据一致性。
虽然线程的优势非常明显,但线程编程也有其挑战。多线程开发人员需要确保代码编写方式充分利用线程的优势,避免常见的陷阱。
Apache 服务器也曾认识到,推行单一模型并不合适,决定推出多种多处理模块(MPM)。用户可以根据需求选择不同的 MPM,如“pre-fork” MPM 或者“worker” MPM,后者结合了进程与线程。
旧与新理念
近年来,许多网络应用程序采用了一种不再依赖多个进程或线程的编程方式,而是采用单个进程来处理所有传入的网络请求。
这种方式看似疯狂,但它的背后原理是,虽然 Linux 系统的进程切换有开销,线程切换的开销较小,但通过使用事件循环处理所有任务,可以避免上下文切换的开销。
这种模式被称为反应器模式,已经成为 nginx、node.js 等流行技术的基础。反应器模式比传统的多进程、多线程处理方式具有更好的扩展性,尽管它要求开发人员采用不同的编程思维。
结论
现代网络应用程序提供了多种选择来处理并发任务。根据不同需求,您可以选择使用进程、线程,或是反应器模式。了解这些多处理模式及其优缺点,对于设计高效、可扩展的网络架构至关重要。
总之,当你开始考虑性能优化时,选择合适的处理方式将直接影响应用程序的可扩展性和运行效率。特别是在高并发的场景中,掌握这些处理模型能帮助你更好地设计出高效、稳定的系统架构。
阅读完毕,很棒哦!
上一篇:巧用 Linux Tracer
下一篇:不同团队的困惑