2.3 转语言和多语言并行

在很多大型项目里,都出现过转语言或多语言的现象。 本质是利用不同语言的特性,解决特定问题。

在我们的项目中,是否有必要用到多语言? 如果从一开始选定一个最终语言,能节约很多后期转语言的时间,也能减少配置多位不同语言程序员的成本,同时还能在团队规模较小的情况下,降低风险。 那么有哪些转语言或者多语言的成功案例?

  • Alibaba:阿里巴巴内部以Java为主,但是到了服务器运维方面,Python能在短时间解决大量问题,包括代码服务调度,在CI/CD方面有很好的表现。而且运维人员就能轻松操作,不需要关注业务的程序员的参与。

  • Instagram: 最初,Instagram 的后端是用 Python 的 Django 框架编写的。随着用户量的增长,为了提高性能和效率,Instagram 的团队对其代码进行了大量的优化,并继续使用 Python,但他们也引入了其他技术和语言,如 Golang。

  • Twitter: 最初,Twitter 的后端是用 Ruby on Rails 构建的。随着用户数量的增长,为了提高性能和可伸缩性,Twitter 逐渐将其核心组件迁移到了 Scala 和 JVM(Java 虚拟机)上。

  • Dropbox: 虽然 Dropbox 的主要代码是用 Python 写的,但为了性能和效率,他们的团队在某些关键部分引入了 Go 和 Rust。

  • WhatsApp: 在其早期,WhatsApp 的服务器是用 Erlang 编写的,这有助于其高并发的需求。然而,随着功能和需求的增长,他们也开始使用其他语言,如 C++。

  • Slack: Slack 的原始代码是用 PHP 写的,但为了提高性能,他们逐渐将关键部分的代码迁移到了 Java 和 Hack(由 Facebook 开发的 PHP 方言)。

  • Shopify: Shopify 的核心代码是用 Ruby on Rails 编写的。但随着其增长和性能需求的变化,他们开始在某些部分使用 Go 语言。

再来看我们的项目,GPT-Onion在后期访问请求增多的情况下,流式回复会带来一些问题。

2.3.1 流式回复场景下的考量

流式回复带来的问题包括:

  1. 连接持续时间:使用流式回复时,连接会被打开并保持活跃更长的时间,尤其是当数据流动地比较慢或数据量很大时。这意味着在给定的时间内,更多的连接可能会保持打开状态,从而占用服务器的并发连接资源。

  2. 并发限制:大多数服务器和操作系统都有并发连接数的上限。超出这个限制可能会导致新的连接请求被拒绝或系统资源被耗尽。

  3. 资源使用:除了并发连接本身,持续的连接可能会消耗其他系统资源,如内存、文件描述符或其他关联的网络资源。

  4. 其他影响:流式回复可能会影响到其他系统部分,如负载均衡器或反向代理,因为这些设备/软件可能需要跟踪和管理更多的活动连接。当然我们也可以根据URI规则跳过一些。

尽管存在上述的开销和限制,流式回复也有其优势。它可以提供更好的用户体验,尤其是在需要实时更新或大量数据传输的情况下。此外,它可能会减少服务器上的内存使用,因为不需要在内存中缓存整个响应。

抛开Golang不谈,PHP/Python/Java在流式回复的场景下,服务器资源的开销都不小。 如果要展开说的话:

  1. 内存回收机制

    • PHP:PHP 使用引用计数以及周期性垃圾回收机制来管理内存。每个请求结束后,PHP 会尝试释放与该请求相关的所有资源。长时间的流式回复可能会增加内存使用,但这主要取决于处理请求的具体代码。

    • Python:Python 使用引用计数和周期性垃圾回收来管理内存。流式回复在 Python 中可能会增加内存使用,但这同样取决于具体的代码实现和数据处理。

    • Java:Java 使用基于代的垃圾回收机制。长时间运行的流式回复可能会使老年代堆积更多对象,从而增加垃圾回收的次数和开销。

  2. 单个请求占用时间

    • PHP:传统上,PHP 是用于处理短生命周期的请求的,每个请求启动和终止都有一定的开销。长时间运行的请求可能会更有效地使用资源,因为初始化开销在整个请求生命周期中被摊销。

    • Python:Python 通常可以有效地处理长时间运行的请求,尤其是使用像 Tornado 这样的异步框架。

    • Java:Java 很适合长时间运行的请求,尤其是在使用了 Servlets、Netty 等技术的情况下。

  3. Lifetime 机制

    • PHP:PHP 的生命周期通常与请求绑定。这意味着长时间的流式回复可能会受到 PHP 的 max_execution_time 配置的限制。

    • Python:Python 进程的生命周期通常独立于单个请求,所以它不受到与 PHP 类似的限制。

    • Java:Java 应用(例如基于 Tomcat 的应用)的生命周期也独立于单个请求,因此它可以很好地处理长时间的流式回复。

总的来说,这三种语言在处理流式回复时都有其优点和局限性。Java 由于其垃圾回收机制、长时间运行的进程和多线程能力,通常被认为是处理流式和长时间连接的理想选择。Python,尤其是当使用异步框架时,也可以非常有效。而 PHP,虽然不是传统上用于流式回复的选择,但在适当的配置和环境下也能处理得很好。

那么处理流式请求时,Golang跟他们相比,又有哪些明显优势呢?

  1. 轻量级并发

    • Goroutines:Go 使用 goroutines 作为其主要的并发机制。goroutines 是非常轻量级的,这意味着你可以同时启动数十万或数百万个 goroutines 而不会耗尽系统资源。这与 Java 的线程或 Python 的线程/协程相比具有明显的优势。

  2. 原生支持并发

    • Go 从设计之初就考虑到了并发。这与 Python(后来通过 asyncio 或其他库增加并发支持)和 PHP(通常依赖外部扩展进行并发处理)形成对比。

  3. Channels

    • Go 的 channels 提供了一种内置的、类型安全的方式来进行 goroutines 之间的通信,这使得构建复杂的并发模式变得更加简单和直观。

  4. 性能和资源使用

    • Go 是编译型语言,编译为机器代码,通常比解释型语言(如 Python 和 PHP)更快。同时,Go 的静态类型系统和直接的内存管理通常会导致更有效的资源使用。

  5. 标准库

    • Go 的标准库为网络编程、HTTP 服务器和客户端以及其他与流式请求相关的任务提供了广泛的支持。这意味着我们可以使用原生工具而不是依赖外部库。

  6. 简化的错误处理

    • Go 有其特有的错误处理模式,虽然某些开发者可能觉得它有些啰嗦,但它鼓励明确和直接地处理错误,这在流式请求中尤为重要,因为这种请求可能会遇到各种网络或数据中断的问题。

  7. 跨平台一致性

    • Go 应用可以容易地在多个平台上编译和运行,不需要任何外部依赖。这提供了一种跨平台的一致性,与需要运行时或虚拟机的 Java 或特定解释器的 PHP/Python 形成对比。

显而易见,Golang 由于其并发原语、性能特性和强大的标准库,对于处理流式请求和其他高并发任务非常适合。这并不是说其他语言不能处理这些任务,但 Golang 提供了一种更简洁、高效的方式来实现这些功能。

似乎,Golang是最终解法。 那么,7天的时间,Golang真的能够开发出这样的系统吗?

Last updated