likes
comments
collection
share

【译】EdgeDB 1.0

作者站长头像
站长
· 阅读数 37

原文作者是 Yury Selivanov(@1st1)和 Elvis Pranskevichus(@elprans),发布于 2022 年 2 月 10 日。

Hacker News 上查看本篇文章的讨论,以及在 YouTube 上观看上线直播的回放。也可以在 V2EX 参与中文讨论,发布会视频也发在了 B 站(生肉),中英文双语字幕正在努力制作中。

经过多年开发(以及多个预发行版),今天我们十分荣幸地宣布:世界上第一款 graph-relational 数据库 EdgeDB 1.0 正式发布!🎊

下面简单回答几个问题。

EdgeDB 的主要特性是?

  • 现代简约风格的查询语言,在表达力上超越 SQL;
  • 丰富的类型系统;
  • 声明式 schema,快速定义继承、计算属性、函数和复杂约束等(以及很快将支持权限规则);
  • 内置 migration 系统,可以比较推断 schema 变更,有自动和交互式手动两种模式;
  • 基于 PostgreSQL 打造。

什么是 graph-relational 数据库?

EdgeDB 采用了“graph-relational 模型”,该模型是关系数据模型的一个扩展,解决了对象与关系的“阻抗失配”问题,同时还保留了经典关系模型的坚实基础和优越性能,使 EdgeDB 成为一款应用开发的理想数据库。

为何另辟炉灶?

目前的数据库已经无法满足开发者对美好生活开发体验的追求了,我们不应把有限的生产力浪费在一套上个世纪的数据库 API 上。在过去 20 年里,数据库后端实现有了长足的进步,但却屈居于一种大型主机时期的 DSL 之下。我们希望改变现状,将数据库 API 和开发者体验带进现代应用开发的新时代。

EdgeDB 是怎么做到的?

EdgeDB 重新设计了整个的数据库前端:从通讯协议到查询语言,从 schema 定义到客户端工具和库。后端还是 PostgreSQL,但由 EdgeDB 托管,对用户透明无感知。

我们比 SQL 更棒

如果你对 EdgeQL 还不熟悉,简单来说:

  • EdgeQL 采用 graph-relation 模型:无需手动 JOIN,数据关系是基础概念之一;
  • 语句天生可拼接:所有东西都可以当成一个表达式来用,并且结果的形态都是一致的;
  • 可以很直观地读取和修改层层嵌套关联的数据。

一图胜过千言万语,那我们就来举个例子。

目标:获取赞达亚参演过的所有的电影,算出每部电影的平均评分,以及每部电影最重要的 5 个演员。

用 EdgeQL 来实现是这样的:

select
  Movie {
    title,
    rating := math::mean(.ratings.score)
    actors: {
      name
    } order by @credits_order
      limit 5,
  }
filter
  "Zendaya" in .actors.name

标准 SQL 建模查询是这样的:

SELECT
  title,
  Actors.name AS actor_name,
  (SELECT avg(score)
   FROM Movie_Reviews
   WHERE movie_id = Movie.id) AS rating
FROM
  Movie
  CROSS JOIN LATERAL (
    SELECT name
    FROM
      Movie_Actors
      INNER JOIN Person
        ON Movie_Actors.person_id = Person.id
      WHERE Movie_Actors.movie_id = Movie.id
      ORDER BY Movie_Actors.credits_order
      FETCH FIRST 5 ROWS ONLY
   ) AS Actors
WHERE
  'Zendaya' IN (
    SELECT Person.name
    FROM
      Movie_Actors
      INNER JOIN Person
        ON Movie_Actors.person_id = Person.id
  )

这两个查询语句不完全等价,因为 SQL 并不支持电影嵌套演员,但我们可以假装没看到。即使这样,这两段文本的长度差异仍然令人震惊,而且这只是嵌套了一层查询。

真正唯一的原始定义

如今的应用程序已不再是单台服务器上的单一程序,相反地,各种服务、API 和 serverless 函数部署在海量的网络节点上,而所有这些程序都要相互协调,并一致认同哪些数据是第一手的、什么状态是合法的——以及更重要的——谁有权限访问什么。换句话说,最理想的方案是,整个系统共享同一个能承载并发压力且保持一致性的状态数据源,而数据库其实就能很好地胜任这一工作,只要你的应用程序和数据库能在数据正确性上达成一致即可。

而这个正确性就是我想说的重点:如果你能使用数据库来统一管理数据模型和基础操作,那么数据库就能顺理成章地解决数据正确性和安全性的问题。

译注:因为原文写的比较仓促,这一段并没有说的特别详细和明白,用了许多抽象的概念和名词。具体来说,EdgeDB 解决了传统技术栈中经常出现的一些问题,比如同一个用户数据结构,在前端、后端甚至是不同编程语言写的不同服务中被反复重复定义,无法有效形成共识,以至于想改用户数据结构就得所有人跟着一起改,非常容易出错。而 EdgeDB 则直接提供了 schema 定义语言,并且支持自省,所有 EdgeDB 客户端都能使用同一份定义,在数据结构上轻松达成一致,并通过内置 migration 完成同步的更新。

译者继续注:另一个例子就是基础操作。使用传统数据库时,一些基础的数据库操作组合实现可能会分散在整个系统的各个地方:数据库触发器、数据库存储过程、驱动程序、ORM 库、不同编程语言中开发者自己的封装等等。对于应用程序,执行数据操作时就会因为逻辑的分散和不一致,造成最终结果上的错误和冲突,并且难以调试。而 EdgeDB 的一些特性,比如计算属性和通用函数,能很好地封装基础操作,不同客户端都能简单一致地操作数据,充分利用好数据库的中心特点和处理能力。

不止是数据库服务器

我们的使命是让开发者用上数据库超能力,所以我们不会止步于数据库服务器本身。

我们知道,即使是最好的数据库,也会因为一个糟糕的客户端,出现一粒老鼠屎坏了一锅粥的尴尬情况。这就是为什么我们一直坚持自己为常见语言编写官方客户端,目前涵盖了 Python、JavaScript/TypeScript/Deno 和 Go。然而,同时完成所有语言的客户端显然并不现实,所以我们还提供了详尽的客户端实现文档,以及通用的一致性测试套件。

尽管 EdgeQL 已经远比 SQL 舒服了,但在代码中直接写 EdgeQL 语句字符串还是不够完美。幸运的是,EdgeQL 在设计之初就考虑到了其作为一种编译结果而存在,也就是可以用代码生成 EdgeQL 语句,这样就能利用不同编程语言中的特色语法和用法来构造 EdgeQL 查询,这种不妥协也是我们的目标之一。今天与 EdgeDB 1.0 同时发布的,还有我们的 JavaScript/TypeScript 原生查询构造器。

之前的电影查询语句,用纯 TypeScript 来构造就是这样的:

e.select(
  e.Movie, (movie) => ({
    title: true,
    rating: e.math.mean(movie.reviews.score),
    actors: (actor) => ({
      name: true,
      order_by: actor["@credits_order"],
      limit: 5,
    }),
    filter: e.op("Zendaya", "in", movie.actors.name)
  })
)

这种写法与最初的 EdgeQL 查询有着出人意料的一致的结构,并且代码行数也几乎一样。而这样写的好处是,藉由 schema 自动生成的类型定义为基础,查询结果的所有字段都有完整的类型提示(译者加:你的 VSCode 将能自动提示和补全所有查询结果!)。我们对这个结果非常满意,这也证明了 EdgeQL 可以很好地融入到现代编程语言中,进一步降低了开发者的认知消耗。

最后还有我们全能的 CLI(edgedb 命令),不仅提供了交互式即时查询终端和传统数据库客户端命令,还包括了安装和管理本地数据库实例(很快会支持云端实例)的便捷指令、交互式创建和执行数据库 migration 的功能等等。

适配云计算的 API

现代应用程序通常能够海量伸缩,这就要求对一些非弹性的计算资源必须十分小心的管理。在云原生数据库能够达到传统数据库的性能和功能之前,我们必须承认数据库仍然是一种云计算的稀缺资源。不幸的是,传统的 RDBMS 在云计算中表现差强人意,主要有两点原因:

  • 从历史上传承下来的客户端-服务器通讯协议要么太闹要么太傻,增加了许多毫无意义的网络往复开销;
  • SQL 对于获取和更新级联数据特别糟糕,经常能看到为了一个结果而使用一连串的查询语句,而 ORM 更是雪上加霜。

而这就意味着,即使是简单的操作,都很有可能导致多次缓慢的网络收发,而这是会占用本就就十分珍贵的数据库连接和数据锁资源的,因此整个系统的可用性会受到影响。

知道了背景知识,让我们再看看 EdgeDB 是怎么解决这些问题的。EdgeQL 可以将几乎任意数量的查询和修改操作拼装到一条查询语句中,为了减少网络收发次数,我们的客户端-服务器通讯协议做了专门的设计优化,通常只需要一次请求-响应即可完成操作。

EdgeDB 仅支持 SERIALIZABLE 一种事务隔离级别,因为这是并发数据库交互唯一正确的姿势。SERIALIZABLE 意味着,服务器会时不时地拒绝接受一些事务,要求你来重试;另一种(不太常见)的情况是,在事务执行了一半的时候,因为故障转移或者网络不稳定突然断线了。对于一个分布式环境来说,以上这些情况十分常见,并且都是完全可以处理的错误(译注:而不需要让用户看大白页,让用户成为重试流程的一环)。因此,所有的 EdgeDB 客户端库都原生支持事务自动重试。

展望未来

EdgeDB 1.0 的发布对我们来说是一个重要的里程碑,现在我们有了一个坚实的基础,可以继续我们打造真正下一代数据库的使命了!换言之,好戏还在后头。

我们计划采用更快的发布周期,EdgeDB 2.0 将在几个月之后发布。我们正在打造一个云服务,许多大胆的设计远远超出了“服务启起来了,自己连这个 IP 去吧”的使用场景。

“系好安全带,老司机要猛踩油门了!”

最后,我们要感谢我们社区中的早期使用者,他们帮助我们反馈意见、测试早期版本,并且提供了珍贵的鼓励。我想再次恳请大家在 GitHub 上给我们点亮星星,也别忘了继续关注 EdgeDB!

欢迎分享你使用 EdgeDB 的经历!❤️

我们在 Gitee 开设了中文沟通交流讨论区,欢迎前来开新帖(Issue)。

转载自:https://juejin.cn/post/7065732342152691726
评论
请登录