diff --git a/_drafts/Article/Translation/how-weve-saved-98-percent-in-cloud-costs-by-writing-our-own-database.md b/_drafts/Article/Translation/how-weve-saved-98-percent-in-cloud-costs-by-writing-our-own-database.md index acb7560f..50517cdc 100644 --- a/_drafts/Article/Translation/how-weve-saved-98-percent-in-cloud-costs-by-writing-our-own-database.md +++ b/_drafts/Article/Translation/how-weve-saved-98-percent-in-cloud-costs-by-writing-our-own-database.md @@ -1,5 +1,5 @@ --- -title: How we’ve saved 98% in cloud costs by writing our own database +title: 通过编写自己的数据库,我们节省了98%的云成本 date: 2024-06-08T09:01:47.183Z authorURL: "" originalURL: https://hivekit.io/blog/how-weve-saved-98-percent-in-cloud-costs-by-writing-our-own-database/ @@ -7,8 +7,91 @@ translator: "" reviewer: "" --- -#### Cloud +两名机械师正在维护数据库 - +编程的第一条规则是什么?可能是类似"不要重复自己"或"如果它能工作,就不要动它"?或者,"不要编写自己的数据库!"……这是一条很好的规则。 -Use Hivekit's API as a fully managed cloud service. \ No newline at end of file +编写数据库是一场噩梦,从原子性、一致性、隔离性和持久性(ACID)要求到分片,再到故障恢复和管理 - 一切都难以置信地困难。 + +幸运的是,市面上有许多经过数十年打磨且分文不取的优秀数据库。那么,我们为什么会愚蠢到从头开始编写一个呢? + +嗯,事情是这样的…… +----------------------- + +我们运行着一个云平台,同时跟踪数万人和车辆。每次位置更新都会被存储,并可以通过历史 API 检索。 + +同时连接的车辆数量和它们位置更新的频率随时间变化很大,但拥有大约 13,000 个同时连接,每个连接每秒发送大约一次更新,这是相当正常的。 + +我们的客户以非常不同的方式使用这些数据。有些用例非常粗略,例如当汽车租赁公司想要显示客户当天行驶路线的轮廓时。这种需求可以用 30-100 个位置点来处理一小时的行程,这将允许我们在存储之前对位置数据进行大量聚合和压缩。 + +但还有许多其他用例,这不是一个选项。快递公司希望能够重放事故发生前的确切几秒钟。矿山拥有非常精确的现场位置跟踪器,希望生成哪个工人踏入哪个受限区域的报告 - 即使只有半米之差。 + +所以 - 鉴于我们事先不知道每个客户需要什么级别的粒度,我们存储每一次位置更新。以 13,000 辆车计算,每月有 35 亿次更新 - 而且这个数字只会从这里增长。到目前为止,我们一直使用带有 PostGIS 扩展的 AWS Aurora 进行地理空间数据存储。但 Aurora 每月已经花费我们超过 1 万美元,仅用于数据库 - 而且未来只会变得更加昂贵。 + +但这不仅仅是关于 Aurora 的定价。虽然 Aurora 在负载下表现相当不错,但我们的许多客户正在使用我们的本地版本。在那里,他们必须运行自己的数据库集群,这些集群很容易被这种数量的更新所淹没。 + +为什么我们不直接使用专为地理空间数据构建的数据库? +----------------------------------------------------------------------- + +不幸的是,没有这样的东西。(如果有,而我们在研究中忽略了它,[请告诉我][3])。从 Mongo 和 H2 到 Redis 的许多数据库都支持空间数据类型,如点和区域。还有"空间数据库" - 但它们完全是建立在现有数据库之上的扩展。[PostGIS][4],建立在 PostgreSQL 之上,可能是最著名的一个,但还有其他如[Geomesa][5],它们在其他存储引擎之上提供了出色的地理空间查询能力。 + +不幸的是,这不是我们需要的。 + +以下是我们的需求概况: + +* **极高的写入性能** + 我们希望每个节点每秒能够处理多达 30,000 次位置更新。它们可以在写入前缓冲,从而导致 IOPS 数量大大降低。 +* **无限并行性** + 多个节点需要能够同时写入数据,没有上限 +* **磁盘上的小尺寸** + 考虑到数据量,我们需要确保它在磁盘上占用尽可能少的空间 + +这意味着,我们必须接受一些权衡。以下是我们可以接受的: + +* **从磁盘读取的中等性能** + 我们的服务器是围绕内存架构构建的。实时流的查询和过滤针对内存中的数据运行,因此非常快。 + 只有当新服务器上线,当客户使用历史 API 或(即将推出)当应用用户在我们的数字孪生界面上回溯时间时,才会从磁盘读取。这些磁盘读取需要足够快以提供良好的用户体验,但它们相对不频繁且数量较少。 + +* **低一致性保证** + 我们可以接受丢失一些数据。我们在写入磁盘之前缓冲大约一秒钟的更新。在服务器宕机而另一个接管的罕见情况下,我们可以接受丢失当前缓冲区中的那一秒钟的位置更新。 + + +我们需要存储什么样的数据? +-------------------------------------- + +我们需要持久化的主要实体类型是"对象" - 基本上是任何车辆、人员、传感器或机器。对象有一个 ID 标签、位置和任意的键/值数据,例如燃油水平或当前骑手 ID。位置由经度、纬度精度、速度、方向、高度和高度精度组成 - 尽管每次更新可能只改变这些字段的一个子集。 + +此外,我们还需要存储区域、任务("对象"必须执行的事情)和指令(hivekit 服务器基于传入数据执行的微小空间逻辑)。 + +我们构建了什么 +---------------- + +我们创建了一个专用的进程内存储引擎,它是我们核心服务器可执行文件的一部分。它写入一种最小的、基于增量的二进制格式。单个条目看起来像这样: + +![图片2:字节图][2] + +每个块代表一个字节。标记为"flags"的两个字节是一系列是/否开关,指定"有纬度"、"有经度"、"有数据"等 - 告诉我们的解析器在条目的剩余字节中寻找什么。 + +我们每 200 次写入存储一次对象的完整状态。在这些之间,我们只存储增量。这意味着,一个完整的位置更新,包括时间和 ID、纬度和经度,只需要 34 个字节。这意味着,我们可以将大约 3000 万个位置更新塞进一个千兆字节的磁盘空间。 + +我们还维护一个单独的索引文件,将每个条目的静态字符串 ID 及其类型(对象、区域等)转换为唯一的 4 字节标识符。由于我们知道这个固定大小的标识符总是每个条目的字节索引 6-9,因此检索特定对象的历史记录非常快。 + +结果:云成本减少 98%,一切都更快 +--------------------------------------------------------------- + +这个存储引擎是我们服务器二进制文件的一部分,所以运行它的成本没有变化。但变化的是,我们用每月 200 美元的弹性块存储(EBS)卷替换了每月 1 万美元的 Aurora 实例。我们使用具有 3000 IOPS 的预配置 IOPS SSD(io2),并将更新批处理为每个节点和领域每秒一次写入。 + +EBS 内置了自动备份和恢复功能,并有高可用性保证,所以我们不觉得我们错过了 Aurora 提供的任何可靠性保证。我们目前每月产生约 100GB 的数据。但是,由于客户很少查询超过 10 天的条目,我们已经开始将所有超过 30GB 的数据移至 AWS Glacier,从而进一步降低我们的 EBS 成本。 + +但这不仅仅是成本。通过文件系统写入本地 EBS 比写入 Aurora 要快得多,开销也更低。查询也变得快了很多。很难量化,因为查询并不完全类似,但例如,重新创建领域历史中的特定时间点从大约两秒减少到约 13 毫秒。 + +当然,这是一个不公平的比较,毕竟,Postgres 是一个具有表达性查询语言的通用数据库,而我们构建的只是一个游标流式传输二进制文件,功能非常有限 - 但话又说回来,这正是我们需要的功能,我们没有失去任何特性。 + +你可以在[https://hivekit.io/developers/][6]了解更多关于 Hivekit 的 API 和功能 + +[1]: https://hivekit.io/blog/how-weve-saved-98-percent-in-cloud-costs-by-writing-our-own-database/title.png +[2]: https://hivekit.io/blog/how-weve-saved-98-percent-in-cloud-costs-by-writing-our-own-database/byte-diagram.png +[3]: mailto:wolfram@hivekit.io +[4]: https://postgis.net/ +[5]: https://www.geomesa.org/ +[6]: https://hivekit.io/developers/