从PHP到golang或rust,只要您使用的是原始sql调用

I was tasked not long ago to make a tiny private prototype. The old application was a monolithic w32 API software which wasn’t friendly with the Internet, and my prototype was a microservice-oriented web app. Given the current pandemic, most of work is being routed to web interfaces, and some applications are being hammered down to the point of data corruption, timeouts, or worse, virtual lines. This happens because the web interface is doing something while the other software has to poll the data and wait until something completes, and there is always somebody who just exits the old program or just sleeps the computer.

不久前,我受命制作一个小型私人原型。 旧的应用程序是单片的w32 API软件,它对Internet不友好,而我的原型是面向微服务的Web应用程序。 在当前大流行的情况下,大部分工作都被路由到Web界面,并且一些应用程序被淘汰到数据损坏,超时或更糟的虚拟线路。 发生这种情况是因为Web界面正在执行某项操作,而其他软件必须轮询数据并等待完成某件事,并且总有人退出旧程序或使计算机进入睡眠状态。

Once I did it and proved my point that this what the perfect opportunity to rewrite the old application to something more microservice-esque and elastic— clients paying at the month’s end was a timeout circus — I doubted if using the Lumen framework (PHP) with a sole SQL database was enough to keep it performanant. It’s known that PHP speed is good but not the best compared to most close-to-metal languages. Today, the top languages are C++, Golang and Rust, but that alone doesn’t mean C++, Golang and Rust have the same frameworks and tools that PHP have honed through its 25 years of existence, at least not on the microservice and web area of the software world.

一旦做完并证明了自己的观点,这是将旧应用程序重写为更具微服务风格和弹性的东西的绝佳机会-客户在月底付款是超时马戏团-我怀疑是否将Lumen框架(PHP)与一个唯一SQL数据库足以确保其性能 。 众所周知,与大多数接近金属的语言相比,PHP的速度不错,但并不是最好的 。 今天,顶级语言是C ++,Golang和Rust,但这并不意味着C ++,Golang和Rust具有与PHP在其25年的发展中磨砺过的相同的框架和工具,至少在微服务和Web领域没有软件世界。

Image for post
The initial prototype that aimed to replace part of the Contract and Client management.
旨在取代合同和客户管理部分内容的初始原型。

I went to the Rust and Golang routes to see if using these languages could offer more performance out of the box, but before fully diving in, I used TechEmpower benchmarks to check what were the top performing frameworks. You know, nobody spends two weeks trying to code just a database connection unless it’s the project itself, you will mostly use a framework for anything you want to do to avoid writing everything from line zero.

我去了Rust和Golang路线,看看使用这些语言是否可以提供更多的开箱即用的性能,但是在全面研究之前,我使用TechEmpower基准测试来检查性能最高的框架。 您知道,除非是项目本身,否则没有人会花两周的时间尝试仅对数据库连接进行编码,而您将主要使用框架来执行您想做的所有事情,从而避免从零行开始编写所有内容。

Image for post

I have to say these benchmarks are outstanding, at least for single query statements. Having Actix (Rust) handling almost 700.000 requests per second is marvelous.

我必须说这些基准非常出色,至少对于单个查询语句而言。 使Actix(Rust)每秒处理近700.000个请求非常了不起。

Let’s check multiple queries, since most microservices will vary between getting one or two records, and sometimes an INSERT operation in between.

让我们检查多个查询,因为大多数微服务会在获取一两个记录之间有所不同,有时还会在两者之间进行INSERT操作。

Image for post

Wow, again Rust and Golang frameworks perform very well. Note that using Actix with ORM objects is just as the same as using raw PHP and raw connections, something you would do… two decades ago?

哇,Rust和Golang框架再次表现出色。 请注意,将Actix与ORM对象一起使用与使用原始PHP和原始连接相同,您将在二十年前做些什么?

Let’s be honest. It’s very difficult to make 20 queries in a single request for a microservice. Unless there is a complex scenario, the one I did doesn’t go over 3 at best, including a single row insert when everything goes alright.

说实话。 在单个微服务请求中很难进行20个查询。 除非有复杂的场景,否则我最多不会超过3个场景,包括在一切正常的情况下插入一行。

Seems like Rust and Go should become my prefered choices. Rust is a more close-to-the-metal language, while Golang is aimed to microservices. I put both under my radar and started to dig what I could find. What you need to accomplish that top performance?

似乎Rust和Go应该成为我的首选。 Rust是一种更接近金属的语言,而Golang是针对微服务的。 我全神贯注,开始挖掘我能找到的东西。 您需要什么来达到最佳性能?

ORM方式或性能方式 (The ORM way, or the performance way)

After checking how the applications performed on the top of the charts, it was clear that these instances were directly connecting to the database. It’s not something you should worry about in the microservices area — if you’re using complex JOIN queries then your microservice may be not as “micro” as you want.

在检查了应用程序在图表顶部的性能后,很明显这些实例直接连接到数据库。 在微服务领域,您不必担心–如果您使用的是复杂的JOIN查询,那么您的微服务可能不会像您想要的那样“微”。

Image for post
Noting that the “ORM” column was full of raw connections to a PostgreSQL instance.
注意“ ORM”列充满了到PostgreSQL实例的原始连接。

The problem with going for raw SQL calls is that you become dependant on the database engine itself. There is no way to swap a DB engine, like going from SQLite to Microsoft SQL Server, in a transparent way. Most of ORM offer a way to add drivers for each RDBMS, so you can safely switch from one to another.

进行原始SQL调用的问题是您变得依赖于数据库引擎本身。 无法以透明方式交换数据库引擎,例如从SQLite切换到Microsoft SQL Server。 大多数ORM提供了一种为每个RDBMS添加驱动程序的方法,因此您可以安全地从一个切换到另一个。

I consider the Database Layer something apart from the Application, so these should be interchangeable anytime and keep the same behaviour. It makes our lives easier, and also allows both of them testable and easy to migrate if for some reason we need to change them. For example, you can test the application against SQLite before pushing a new revision that uses a real PostgreSQL database.

我认为数据库层应用程序有所不同,因此它们应随时可互换并保持相同的行为。 它使我们的生活更轻松,并且如果出于某种原因我们需要更改它们,则还允许它们可测试且易于迁移。 例如,您可以在推送使用真实PostgreSQL数据库的新修订之前,针对SQLite测试应用程序。

This is the part where ORM comes, and where most of the performance gains of any language are lost. ORMs are basically a layer between the framework and the database itself. One of the most easy ways to pick up are those who offer the ActiveRecord pattern: each record is an object that can be created, updated or deleted. This is one of the reasons why I choose Lumen/Laravel, since it’s brain dead easy to understand and quick to build from. When I need performance I can always instance a query builder to push a SQL statement to the database.

这是ORM出现的部分,而任何一种语言的大部分性能提升都将因此而丧失。 ORM基本上是框架和数据库本身之间的一层。 提供ActiveRecord模式的是最简单的方法之一:每个记录都是可以创建,更新或删除的对象。 这就是为什么我选择Lumen / Laravel的原因之一,因为它的大脑死了,易于理解并且可以快速构建。 当我需要性能时,我总是可以实例化查询构建器来将SQL语句推送到数据库。

Image for post
Note that adding the Diesel ORM to the mix slows the request around 40%.
请注意,将柴油ORM添加到混合物中会使请求速度降低40%左右。

Since each record must persist in memory as an object, this adds overhead, and the application suddenly starts to run logic related to the ORM checks themselves rather than the data it contains: initializing the connection, checking persistence, running callbacks, synchronizing values, parsing custom values, destroying old references, etc.

由于每条记录都必须作为对象保留在内存中,因此增加了开销,并且应用程序突然开始运行与ORM相关的逻辑,以检查自身而不是其包含的数据:初始化连接,检查持久性,运行回调,同步值,解析自定义值,销毁旧引用等。

Look it this way: the data is inside a box, so everytime you need to do something with the data, you have to deal with the whole box, which is a good trade-of instead of dealing with every piece of data and other technicalities manually (like handling null values correctly). The problem is that some people overuse the ORM capabilities when not needed. For example, it’s not necessary to hydrate an ORM object with data if you only need to update it, nor doing it 100 times with other data you don’t need like timestamps.

这样看:数据位于一个框内,因此每次需要对数据做某事时,都必须处理整个框,这是一个很好的折衷方案,而不是处理每个数据和其他技术手动(例如正确处理null值)。 问题是某些人在不需要时会过度使用ORM功能。 例如,如果您只需要更新ORM对象,则不必将其与数据混合,也可以将其与时间戳等不需要的其他数据进行100次处理。

So, checking benchmarks again, it’s not difficult to see that ORM overall make the application slower, compared to just using direct connections and raw queries. Some more, some less, but every framework slows down when an ORM is used to deal with all database objects.

因此,再次检查基准测试,与仅使用直接连接和原始查询相比,不难看出ORM总体上使应用程序变慢。 更多一些,更少一些,但是当使用ORM处理所有数据库对象时,每个框架都会变慢。

还没有结束。 (It’s not all over, yet.)

After seeing how Rust and Golang offers massive performance improvements on some frameworks, I think it will be safe to jump to these pastures as long I find a big performance problem related to the language itself instead of the database layer. It’s not that an ORM makes the application slower, because it does in some degree, but rather prioritize the included SQL Query Builder these frameworks offer instead of the big (but handy) ORM objects if these aren’t needed.

在看到Rust和Golang如何在某些框架上提供了巨大的性能改进之后,我认为只要我发现与语言本身(而不是数据库层)相关的性能问题就可以安全地跳入这些牧场。 并不是说ORM会使应用程序变慢,因为它在某种程度上确实会降低它的速度,而是优先考虑这些框架提供的SQL Query Builder所包含的优先级,而不是在不需要这些ORM对象的情况下优先考虑的大小。

So, it’s no surprise that Lumen is 9 times slower than Actix, which is a close-to-metal executable with raw PostgreSQL connections, when you use Eloquent ORM objects. Completing 3.500 requests per second at ~150 ms is not that terrible either if we can just skip the ORM objects and just push raw statements back and forth.

因此,当您使用Eloquent ORM对象时,Lumen比Actix慢9倍也就不足为奇了,Actix是具有原始PostgreSQL连接的接近金属的可执行文件。 如果我们可以跳过ORM对象并来回推送原始语句,那么在大约150毫秒每秒完成3.500个请求也不是那么糟糕。

Image for post

Additionally, or better said for the lack of thereof, these frameworks don’t include a lot of useful tools compared to Lumen/Laravel. For example, there is no input validation, event bus, queued jobs, CLI commands, authorization, and even encryption, among other things. Most of these are things you must implement yourself. Lumen/Laravel offers these out of the box without needing to look around and pray the maintainer keeps it updated, and there is a well maintained gRPC extension for microservice-communication. When you are creating something where money is involved, and probably iterating over it for months or years, this is one bit is kinda important.

另外,或者说缺少它,与Lumen / Laravel相比,这些框架没有包含很多有用的工具。 例如,除其他外,没有输入验证,事件总线,排队的作业,CLI命令,授权甚至加密。 其中大多数是您必须实现的事情。 Lumen / Laravel提供了开箱即用的功能,而无需四处看看,并祈求维护者对其进行更新,并且有一个维护良好的gRPC扩展用于微服务通信。 当你创建一些地方涉及金钱,而且很可能遍历它几个月或几年,这是一个位是有点重要。

So, in the end, it’s not that I’m forced to go for other language, or framework. I’m forced to start with creating these services as fast as I can with production-ready tools, diagnose them along the way, and then later see what needs to be added, changed or removed. One of these solutions can be use Rust (Actix, Rocket) or Golang (Gin, Fiber, Chi, Echo) for the sake of performance, but until then, PHP can work just fine.

因此,最后并不是我被迫选择其他语言或框架。 我被迫开始使用生产就绪型工具尽快创建这些服务,并一路诊断它们,然后再查看需要添加,更改或删除的内容。 为了提高性能,可以使用Rust( ActixRocket )或Golang( GinFiberChiEcho )这些解决方案之一,但是在那之前,PHP可以正常工作。

I sincerely hope that PHP 8 with its JIT compiler closes the gap, and doesn’t require having a buffer of 128MB for saving compiled machine-code, something that would make it close to JAVA-level of hardware requirements that nobody likes — from my perspective, 16MB should be enough for a microservice, but you do you.

我衷心希望PHP 8及其JIT编译器能够缩小差距,并且不需要128MB的缓冲区来保存编译后的机器代码,这会使它接近没人喜欢的JAVA级别的硬件要求。角度来看, 对于微服务而言16MB应该足够了,但是您可以做到

It’s not that each microservice is gonna be hammered with 3.000 requests per second, at least not before PHP 8 comes.

并不是每个微服务每秒都会受到3.000个请求的冲击,至少在PHP 8出现之前。

翻译自: https://medium.com/swlh/from-php-to-golang-or-rust-as-long-you-are-using-raw-sql-calls-8482aaac692

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值