用户定义函数 (UDF) 一直都是数据库系统中的固有功能,允许用户扩展数据库的内置功能,用来补充 SQL 语句,使其用起来更方便。尽管传统的 UDF 是一个强大的工具,但开发人员经常被迫使用自己不熟悉的编程语言(这些编程语言是数据库独有的)。然而,随着具有沙盒安全控制和广泛语言支持(WebAssembly)的可移植、低级二进制格式的诞生,行业出现了我们乐见的一种新的 UDF 实现。
例如,Singlestore 的代码引擎为用户提供了使用 Wasm 代码创建 UDF 和表值函数 (TVF) 的能力,而 InfinyOn 和 RedPanda 让开发人员能够使用 Wasm 操作数据流。我们自己的 Extism 是一个通用插件系统,在一个演示中展示了使用 Wasm UDF 扩展 SQLite3 的能力。让我们在本文中更深入地了解驱动这个趋势的因素,并谈谈对未来的一些想法和思考。
为 UDF 创建任务提供广泛的编程语言支持,可以使数据库提供商更广泛地接触到许多开发人员社区,从而扩大市场。另一方面,数据库用户希望用他们最喜欢、对他们而言更高效的编程语言编写 UDF。因此,对数据库创建者和使用者来说,更多的语言支持显然是双赢的,那么为什么过去我们对 UDF 语言的支持如此有限呢?时间和资源约束是最有可能的因素。
如果没有针对指定语言的通用的运行环境和执行模板,数据库供应商将需要构建/集成和维护各种语言运行环境,以提供 Wasm 的广泛语言支持。这是一项复杂且耗时的任务,因此需要进行取舍,显而易见,选择一种广泛使用的通用编程语言(例如 JavaScript)或创建一种特定于领域的语言(DSL)是更合适的选项。
对于前者,供应商将他们的 UDF 引擎的成功与所选择的语言联系起来,对于后者,他们也做了同样的事情,但由于强加的学习曲线和缺乏可转移的技能,也给产品采用带来了更多的阻力。
我们很高兴地说,是时候吃你的 UDF 蛋糕了。在撰写本文时,有超过 10 种语言直接针对 Wasm,由于未来有更多的语言能够这样做,数据库平台可以在几乎不需要增量工作的情况下获得这些额外的语言支持。
除了支持各种语言运行环境,数据库提供者还必须确保适当的沙盒控制能力,以便主机系统(即数据库)免受任何意外或恶意的副作用。
Wasm 特别适合这种情况,因为运行时被设计为在沙箱环境中执行代码,默认情况下对主机系统资源的访问受到限制。有了这种内置的隔离,数据库提供商可以花更少的时间来运行自己的安全运行时,而有更多的时间在 Twitter 上展示自己。
Wasm 代码最大的特性是占用空间小,因此可以很容易地对数据进行计算,并且接近原生的执行速度使其非常适合复杂的数据工作负载。
数据集日益庞大,使得在数据库和应用程序之间来回传输数据进行处理变得繁琐和昂贵。除了由这种工作流造成的额外延迟之外,每个连接到数据库的新应用程序都会增加额外的故障点,与数据驻留相关的问题都使得直接在数据旁边运行 Wasm 非常有吸引力。能够将数据保存在它所在的地方,并将(至少部分)应用程序带到它上面,对于不明确和复杂的监管环境来说,这一简化的意义重大。
此外,将计算引入数据的能力消除了系统对许多微服务的需求——取而代之的是在数据库中运行这些微服务!
就可移植性而言,为什么数据库用户要一遍又一遍地针对不同的主机数据库实现 UDF 呢?编写一次,并在任何数据库的任何地方运行!UDF 的一个传统优点是它可以跨 SQL 查询重用,但为什么要将可重用性限制在一个数据库平台上呢?通过混合使用 Wasm,UDF 重用的范围理论上可以扩展到任何支持 Wasm 运行时以及主机功能的标准化接口的数据库上。
在实践中,这需要跨数据库提供者的生态系统进行某种程度的协作,或者需要社区努力将各种接口虚拟化成一个公共标准,但这种可能性和相关的好处都是可预期的。
Wasm 显然是 UDF 的力量倍增器,但是让我们讨论一下应该考虑的一些设计和实现方面的话题。
数据库提供程序必须支持一组导入和导出,这些导入和导出将作为数据库和 Wasm UDF 之间交互的基础。如上所述,如果接口能够标准化,将有利于整个生态系统。WASI SQL Embedding 就是这样一个例子,它提出了一种将 WASM 模块作为扩展嵌入到 SQL 数据库中的标准。
设计高质量的语言支持和库对于成功至关重要,因为 UDF 创建者将需要这样的支持来实现其实现目标。例如,Python 开发人员希望 NumPy 可以用于分析工作。数据库提供者应该考虑在主机级别包含这种支持,特别是出于性能原因而需要本地扩展时。这样做使用户可以访问必要的库,而不必强制将它们直接编译到 Wasm UDF 中,因为这会增加模块本身的大小。
如果可能的话,应该围绕任何导入提供特定于语言的包装器,以提供惯用语言支持。看看像 Extism 这样的开源项目,它为创建这些类型的实用程序的团队提供了一个良好的开端。
大多数生产环境的数据库已经在事务中运行 UDF,允许在发生异常时进行无缝回滚,并且不需要在突变代码本身中实现故障补偿。也就是说,考虑事务如何适应 Wasm 口味的 UDF 及其世界观是很重要的,而且仍然是“留给读者的练习”,需要数据库实现者来解决。
数据库提供者和 UDF 创建者需要什么工具来观察和检查 UDF 的性能,并在意外发生时调试它们?在生态系统中,多租户可观察性是一个未得到充分满足的需求,应该仔细考虑。
回到主机/客户机接口标准化的主题,如果必须使用定制接口,请考虑使用 Modsurfer 等工具,这些工具为数据库提供者和 UDF 创建者提供了一种以主动方式验证相互兼容性的方法。某些导入和导出的存在性、运行时复杂性、二进制大小和函数签名都是任何验证方案中应该包含的关键组件。
除了 UDF 之外,数据库还有很多领域都已经可以用 WebAssembly 来提升扩展性了,存储过程、表值函数 (TVF) 和用户定义的聚合函数 (UDAF) 都在范围内。
领取专属 10元无门槛券
私享最新 技术干货