”工欲善其事,必先利其器。“—孔子《论语.录灵公》
首页 > 编程 > 具有Zig和Python的性能和可扩展的Web服务器

具有Zig和Python的性能和可扩展的Web服务器

发布于2025-03-22
浏览:440

前言

我对我对软件开发的兴趣充满热情,特别是人体工程学创建的软件系统的难题,可以解决最广泛的问题,同时使尽可能少的妥协。我还喜欢将自己视为系统开发人员,通过安德鲁·凯利(Andrew Kelley)的定义,这意味着有兴趣完全了解他们正在使用的系统的开发人员。在此博客中,我与您分享有关解决以下问题的想法:构建一个可靠且性能的全堆栈企业应用程序。一个挑战,不是吗?在博客中,我专注于“ Performant Web服务器”部分 - 我觉得我可以提供新的视角,因为其余的要么是好事,要么没有添加。

一个主要的警告 - 将有

没有代码示例,我实际上尚未对此进行测试。是的,这是一个主要缺陷,但实际上实施这将需要很多时间,我没有,并且在发布有缺陷的博客并且根本不发布博客之间,我坚持使用前者。您已被警告。 [2

以及我们将从哪些部分组装出我们的应用程序?

A performant and extensible Web Server with Zig and Python

的前端您很舒服,但是如果您想要最小的依赖项 - WASM表格HTMX中有Zig。

与Linux内核密切集成的ZIG Web服务器。这是表演部分,我将在此博客中重点关注。

    python后端,与Zig集成在一起。这是复杂的部分。
  • 与持久执行系统(例如时间和流动)集成。这有助于可靠性,并且不会在博客中讨论。
  • 通过我们的工具决定,让我们开始!
  • 无论如何,Coroutines是否被高估了?
Zig对Coroutines没有语言级别的支持:(和Coroutines是每个表演者Web服务器所构建的。

保持,请首先让我们的系统程序员戴上帽子。 Coroutines不是银弹,没有什么。实际的好处和缺点是什么?

他们默认情况下从较小的堆栈空间开始(2KB而不是4MB)。但这可以手动调整。

他们更好地与用户空间调度程序合作。由于内核调度程序是先发制人的,因此线程执行的任务是分配的时间切片。如果实际任务不适合切片 - 某些CPU时间会浪费。与goroutines相反,与goroutines相适应了不同的goroutines执行的许多微任务,并尽可能地融入OS-Thread的同一时间。

[2

例如,GO运行时将goroutines多重在OS线程上。线程共享页面表,以及流程拥有的其他资源。如果我们将CPU隔离和对混合物的亲和力引入 - 线程将不断在其各自的CPU内核上运行,所有的OS数据结构都将保持在内存中,而无需交换,则用户空间调度程序将使用CPU时间分配精确的CPU时间,因为它使用协作多任务模型。竞争甚至可能吗?

通过旁观线程的OS级抽象,并用Goroutine的OS级抽象来实现性能。但是翻译中没有丢失?
  • 我们可以与内核合作吗?
  • 我会争辩说,独立执行单元的“真” OS级抽象甚至不是线程 - 实际上是OS进程。实际上,这里的区别并不那么明显 - 所有区分线程和过程的都是不同的PID和TID值。至于文件描述符,虚拟内存,信号处理程序,跟踪资源 - 在“克隆” syscall的参数中指定了这些对孩子分开的。因此,我将使用“过程”一词来表示拥有自己的系统资源的执行线 - 主要是CPU时间,内存,打开文件描述符。 [2
  • 现在为什么这很重要?每个执行单位都有其对系统资源的要求。每个复杂的任务都可以分解为单位,每个任务都可以自行创建,可预测的资源请求 - 内存和CPU时间。越沿您执行的子任务的树,朝着更通用的任务 - 系统资源图形形成了带长尾巴的钟形曲线。您有责任确保尾巴不超越系统资源限制。但是,这是如何完成的,如果该限制实际上被超越了?
会发生什么?

如果我们使用单个过程的模型和许多Coroutines进行独立任务,那么当一个Coroutine超越内存限制时 - 由于在过程级别跟踪内存使用情况,因此整个过程被杀死。最好的情况是 - 如果您使用cgroup(在库伯内特的豆荚中自动是这种情况,每个豆荚都有一个cgroup) - 整个cgroup被杀死。建立可靠的系统需要考虑到这一点。那CPU时间呢?如果我们的服务同时被许多计算密集的请求遭到打击,则它将变得无反应。然后截止日期,取消,重新恢复,重新启动。A performant and extensible Web Server with Zig and Python

为大多数主流软件堆栈处理这些方案的唯一现实方法是在系统中留下“ fat” - 一些用于钟形曲线尾巴的未使用资源 - 并限制了并发请求的数量 - 这再次导致未使用的资源。即使这样,我们也会偶尔会被OOM杀死或不响应,包括恰好与离群值同一过程的“无辜”请求。这种妥协是许多人都可以接受的,并且在实践中为软件系统提供了足够的服务。但是我们可以做得更好吗?

并发模型

由于对资源的使用进行了跟踪,因此理想情况下,我们将为每个可预测的执行单元产生一个新的过程。然后,我们为CPU时间和内存设置了ULIMIT - 我们很高兴! Ulimit具有软限制,这将使该过程在击中软限制时优雅地终止,如果不发生这种情况,可能是由于错误造成的 - 在击中硬限制时会有力终止。不幸的是,在Linux上产卵的新过程很慢,对于许多Web框架以及其他系统(例如时间),每个请求都不支持每个请求产生新的过程。此外,过程切换更昂贵 - 牛和CPU固定可以减轻,但仍然不理想。不幸的是,长期运行的过程是不可避免的现实。 [2

我们距离简短的流程的清洁抽象越多,我们需要照顾好自己需要的工作级较高的工作。但是也有一些好处可以获得的好处 - 例如利用io_uring在许多执行线程之间进行批处理IO。实际上,如果由子任务组成庞大的任务 - 我们真的在乎他们的个人资源利用吗?仅用于分析。但是,如果我们可以管理(切断)资源铃曲线的尾巴(切断),那就足够了。因此,我们可以催生与我们希望同时处理的请求一样多的过程,让它们长期存在,并简单地重新调整每个新请求的ULIMIT。因此,当请求超过其资源约束时,它会产生OS信号并能够优雅地终止,从而不影响其他请求。或者,如果高资源使用是有意的,我们可以告诉客户支付更高的资源配额。对我来说听起来不错。

但是,与每次重新要求的方法相比,性能仍然会受到影响。首先,在过程内存表周围复制很昂贵。由于该表包含对内存页面的引用,因此我们可以使用大型页面,从而限制要复制的数据大小。只有低级语言(例如Zig)才能直接使用。此外,操作系统级别的多任务是先发制人的,而不是合作的,这总是效率较低。还是?

与Linux合作多任务处理

A performant and extensible Web Server with Zig and Python有SYSCALL SCANE_YIELD,它允许线程在完成其工作的一部分时放弃CPU。似乎很合作。是否有一种方法可以要求给定尺寸的时间切片?实际上,有 - 带有调度策略sched_deadline。这是一个实时策略,这意味着对于请求的CPU时间切片,该线程不间断地运行。但是,如果切片被超支 - 先发制人会启动,并且您的线程被换成并剥夺了。而且,如果切片不足 - 线程可以调用Sched_yield以提早发出信号,从而可以运行其他线程。这看起来像是两全其美的 - 合作和优势模型。 [2

一个限制是Sched_deadline线程不能分叉的事实。这给我们留下了两种并发模型 - 要么每个请求的过程,该过程为自己设定了截止日期,并运行事件循环以提高io,或者从开始时从开始为每个微任务提供了一个线程,每个任务都设置了自己的截止日期,并利用了队列与彼此进行交流。前者更加直截了当,但需要在用户空间中的事件循环,后者更多地使用了内核。

这两种策略都达到了与Coroutine模型 -

通过与内核合作,可以使应用程序任务使用最小的中断

Python作为嵌入式脚本语言

这全是用于高性能,低延迟,低级侧面的,锯齿闪闪发光的地方。但是,当涉及到应用程序的实际业务时,灵活性比延迟更有价值。如果一个过程涉及真实的人在文档上签字 - 计算机的延迟可以忽略不计。同样,尽管性能遭受了损失,但面向对象的语言为开发人员提供了更好的原语,以模拟与业务的领域建模。在最远的一端,诸如Flowable和Camunda之类的系统允许管理人员和运营人员可以更灵活地编程业务逻辑,并具有较低的入境障碍。像Zig这样的语言不会对此有所帮助,只能阻碍您的方式。

[2 另一方面,Python是最动态的语言之一。课程,对象 - 它们都是引擎盖下的词典,并且可以在运行时进行操作。这是一种绩效惩罚,但可以使企业建模,并实用许多巧妙的技巧。 Zig是相反的 - 曲折中有意巧妙的技巧,可为您提供最大的控制。我们可以通过互操作来结合他们的力量吗?

的确,我们可以,因为两者都支持C ABI。我们可以让python解释器从ZIG过程中运行,而不是作为一个单独的过程,从而减少了运行时成本和胶水代码的开销。这进一步使我们能够在Python中使用Zig的自定义分配器 - 设置用于处理单个请求的竞技场,从而减少垃圾收集器的开销,并设置内存帽。一个主要的限制是垃圾收集和IO的Cpython运行时产卵线,但我没有发现证据表明它确实如此。我们可以通过使用AbstractMemoryloop中的“上下文”字段将曲调挂在Zig的自定义事件循环中,并通过每个曲线记忆跟踪。可能性是无限的。

结论 A performant and extensible Web Server with Zig and Python

我们讨论了并发,并行性和与OS内核的各种形式集成的优点。该探索缺乏基准和代码,我希望这在提供的想法质量中弥补了这一点。您尝试过类似的事情吗?你的想法是什么?反馈欢迎:)

进一步阅读

https://man7.org/linux/man-pages/man7/sched.7.html

A performant and extensible Web Server with Zig and Python https://eli.thegreenplace.net/2018/measuring-context-switching-and-memory-overheads-for-linux-threads/

版本声明 本文转载于:https://dev.to/brogrammerjohn/a-performant-and-extensible-web-server-with-zig-and-python-4adl?1如有侵犯,请联系[email protected]删除
最新教程 更多>

免责声明: 提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发到邮箱:[email protected] 我们会第一时间内为您处理。

Copyright© 2022 湘ICP备2022001581号-3