我一直很喜欢Deno个人项目!开发人员的体验非常出色,Deno Deploy使快速,轻松地部署它变得容易。
虽然其按需设计效率高且非常适合许多用例,但由于其为每个请求创建新实例的性质,因此在某些情况下的性能很差。不幸的是,当我为我一直从事的项目构建缓存层时,我遇到了其中之一。在本文中,我将解决这些问题,并解释我避免使用的替代路线。
问题:redis超负荷ð¯
数据库读取既昂贵又慢。有一个multitude of other reasons为什么缓存至关重要,但是对于我正在处理的项目,我正在使用supabase,他们的免费层仅支持有限的带宽。为了避免任何限制限制的限制,我在其前面添加了一个Redis层,以减少直接击中数据库的查询数量。
方便地,Deno有一个deno-redis(实验)插件,我用来在项目中添加一个简单的缓存层:
import { connect } from "https://deno.land/x/redis/mod.ts";
const redis = await connect({ hostname, port });
let cachedResult = await redis.get(query);
let result = cachedResult;
if (!cachedResult) {
result = db.get(query);
await redis.set(query, result);
}
return result;
有了这个,完整的请求生命周期如下:
这很好!但是,在足够的请求开始涌入后,会抱怨有太多的连接,不允许新的连接(redis.connect
导致:ERR max number of clients reached
)。当然,我还使用他们的免费级别,一次限制了30个客户。但是,由于hosted integrations通常在连接数量上有硬上限,因此此问题也会出现。
为什么会发生这种情况?这是由于DeNo的基本方面:每次提出请求时,都会创建全新的上下文,在这种情况下,必须建立与Redis的新联系。为了形象化这一点,这是当n
用户每个人提出请求时发生的情况:
为了解决这个问题,我们需要一种方法来减少连接的数量并将其保持在极限之下,但是当我们看到这样做的性能好处。
一个持续的连接ð°°
尽管任何传统的服务器环境都可以启用此功能,但我使用了Node,因为它接近Deno且易于使用。有了几行代码,在开始时创建单个客户端的express服务器将启用任何传入的请求以重复使用相同的连接。添加一些简单的路由来检测请求参数并使用REDIS返回的内容响应,然后允许DENO中的缓存请求与GET
请求交换到此服务器。
这被称为reverse proxy,在任何网络堆栈中都是常见的。有了这个,请求生命周期现在看起来像这样:
有了这个地方,由于连接的数量,不仅没有错误,而且性能会大大改善,持续时间降低了50%以上:
基准 | 时间(AVG) | (min - 最大) | p75 | p99 |
---|---|---|---|---|
deno-> redis | 65.06 ms/iter | (792 ns - 114.68 ms) | 111.41 MS | 114.68 MS |
deno->节点 - > redis | 34.79 ms/iter | (28.4 msâ€41.7 ms) | 36.53 MS | 41.7 m |
但是有一个转折! -
我的主要目的是确定重新误差的解决方案,但我认为为什么不测试持续的postgres连接的行为是否相似。令我惊讶的是,结果相反!
令人困惑的是,当对上述相同的基准测试(deno vs deno + deNo +节点层)时,就会有一个令人惊讶的结果:deno的表现优于〜2x!因此,尽管为每个请求重新创建supabase客户端,但DENO仍然胜过节点:
基准 | 时间(AVG) | (min - 最大) | p75 | p99 |
---|---|---|---|---|
deno-> Postgres | 42.98 ms/iter | (916 NSâ€89.29 ms) | 79.8 ms | 89.29 MS |
deno->节点 - > Postgres | 88.24 ms/iter | (667 ns - 205.44 ms) | 160.8 ms | 205.44 MS |
这是由于deno's中不存在的@supabase/supabase-js
实施中的限制,还是只是DENO的表现更好,我不完全确定。据我所知,连接到单个Supabase实例的客户端数量没有限制。但是基于这些数字,我将保留节点以查询redis和deno查询邮政。
感谢您的阅读!
如果您想自己尝试这些基准,这是运行这些基准测试的源:
brycedorn / deno-node-redis-postgres-benchmarks
根据DENO与DENO和节点的组合对Redis和Postgres性能进行基准测试。
Deno vs Node Redis/Postgres benchmarking
As part of a dev.to article.
结果
在Apple M1 Max 64GB Ventura上运行的结果来自阿姆斯特丹。
使用节点? | 基准 | 时间(AVG) | (min - 最大) | p75 | p99 |
---|---|---|---|---|---|
否 | deno-> redis | 65.06 ms/iter | (792 ns - 114.68 ms) | 111.41 MS | 114.68 MS |
否 | deno-> Postgres | 42.98 ms/iter | (916 NSâ€89.29 ms) | 79.8 ms | 89.29 MS |
是 | deno->节点 - > redis | 34.79 ms/iter | (28.4 msâ€41.7 ms) | 36.53 MS | 41.7 m |
是 | deno->节点 - > Postgres | 88.24 ms/iter | (667 ns - 205.44 ms) | 160.8 ms | 205.44 MS |
在本地运行
先决条件
- deno> = v1.30.2。
- v8> = v10.9.194.5。
- ts> = v4.9.4。
- node> = v16.15.0。
- redis实例,我正在使用Redis Enterprise Cloud(有免费层)。
- Postgres实例,我正在使用supabase(有免费层)
- 此示例使用
hex
作为查找键,但这是
- 此示例使用