以下是 Igor Baliuk 的客座博客文章。Igor 在莫斯科高等经济学院攻读计算机科学学士学位,并计划于 2023 年毕业。他是一名 Golang 软件工程师,对服务网格和遥测技术特别感兴趣。
简介
有时我们想在线运行 SQL 查询来验证它们,与他人分享它们,或者仅仅因为我们懒得在本地安装数据库。在线 SQL 游乐场可以帮助我们解决这个问题。
游乐场允许从浏览器运行 SQL 查询,而无需用户端拥有数据库实例。在本文中,我们将讨论一个专门为 ClickHouse 创建的新的开源 SQL 游乐场 — ClickHouse Fiddle。我们将介绍该平台的动机和内部架构。
动机
如果您从未使用过在线游乐场,那么您可能会想到一个合理的问题:此类平台的使用案例是什么?
想象一下,您需要执行几个查询并查看执行结果。例如,您想知道您最喜欢的数据库如何看待表达式 0.1 + 0.2 == 0.3
的真假。如果您已经有一个正在运行的数据库实例,您可以连接到它并在那里执行一个简单的查询。完成。但是,如果您没有正在运行的实例怎么办?或者,也许您拥有的实例版本不是您想要的...
那么,您需要下载所需版本的二进制文件,使用正确的选项运行它,最后执行 SELECT (0.1 + 0.2) == 0.3
... 在现代云世界中,我们甚至可以按下控制面板上的一个按钮,在几分钟(甚至几秒钟)内获得数据库的托管实例。
但我们都可以同意,对于执行这种无上下文的查询,打开网页,在那里输入查询,等待几秒钟并查看执行结果要简单和快速得多。这就是游乐场提供的!一种从浏览器执行 SQL 查询的快速且易于访问的方式
现在我们知道了,
0.1 + 0.2 != 0.3
。浮点数...
总的来说,在线 SQL 游乐场在以下情况下有所帮助
- 数据库维护人员想要检查某个错误是否可以在特定的数据库版本中重现。
- 工程师阅读了关于新的出色 SQL 构造的信息,并对他们使用的(或计划使用的)数据库版本是否支持它感兴趣。
- 您的朋友问您如何在 SQL 中做某事,并且您想分享一段带有执行结果的 SQL 代码片段。
- 等等...
好的,现在我们看到了游乐场的好处。但是,如果我们已经有几个游乐场,甚至包括 ClickHouse 的游乐场,为什么还需要另一个游乐场呢?简短的答案是现有平台的局限性。
大多数 SQL 游乐场旨在模拟 OLTP 数据库。创建一个事务来执行一堆查询。执行后,事务将回滚以返回到初始数据库状态。提供在线游乐场机制的另一种方法是仅允许对现有数据集进行读取查询(这就是 ClickHouse Play 的实现方式)。使用这种方法,有时很难(甚至不可能)获得 SQL 查询的所需逻辑。
此外,这两种方法都意味着对于每个受支持的数据库版本,都需要有一个始终在线的数据库实例。
可能性
简而言之,ClickHouse Fiddle 允许在任意版本的 ClickHouse 中运行多个 SQL 查询,并提供一个唯一的链接来分享执行结果。
也允许写入和 DDL 查询!这意味着您可以创建表,插入一些行并在其上执行查询。来自一次执行的数据在另一次运行中不可访问,隔离是通过容器化实现的(有关更多信息,请参见设计部分)。 对最大执行持续时间和输入/输出大小有一些合理的限制,但它们并不太严格。用户可以进行一些基本执行,以了解一个或另一个 SQL 查询集的逻辑。
请记住,游乐场并非旨在衡量数据库的性能。如果您想了解查询的速度,我们建议您在生产就绪的实例中运行基准测试。
在热数据库版本上执行简单查询目前通常需要 几秒钟(p90 约为 2 秒)。如果一个版本最近已用于另一个查询,我们称该版本为热版本。在这里,您可以看到运行持续时间 90th 百分位的示例
ClickHouse Fiddle 设计
让我们讨论一下游乐场是如何实现的。Fiddle 的设计可以用一张图来概括: 用户的入口点是一个简单的 Web 应用程序,可在 fiddle.clickhouse.com 上访问。用户使用 HTTP API 与平台交互。所有请求都发送到系统的主要组件 — 游乐场核心。
对于每个用户请求,都会创建一个包含所需 ClickHouse 版本的 Docker 容器。游乐场核心将传入的负载分配到可用机器上,并在每台机器上运行 Docker 容器。
为了优化查询执行的延迟,游乐场向 runners 发送活跃度探测,并收集有关已拉取镜像的信息。在负载均衡时,优先考虑具有已拉取镜像的 runners。 让我们更精确地看一下当用户请求平台执行查询时会发生什么
- 游乐场核心使用负载均衡算法选择一台可用的机器。
- 如果所选机器上没有所需 ClickHouse 版本的 Docker 镜像,则从注册表拉取它。
- 创建并运行 Docker 容器。
- 在容器中运行提供的 SQL 查询。
- 等待查询执行并杀死容器。
- 将执行结果保存在查询存储中(以允许通过链接共享它们)。
- 向用户发送包含获取数据的响应。
临时容器通过 cgroups 机制帮助将运行彼此隔离。如果我们将此方法与始终在线的数据库实例进行比较,则在镜像拉取和创建容器时存在延迟,但运行整个平台所需的资源要少得多(对于非频繁使用,1 个 runner 就足够了)。
但是有很多编排系统:Kubernetes、云服务等。为什么还要编写另一个容器管理器?现有的编排系统提供了大量可以使用容器完成的事情。而为此付出的代价是它们的复杂性和缓慢性(在游乐场的目的范围内)。编写的协调器比编排系统更快,因为它很简单,并且需要的计算资源更少。
未来工作和反馈
Fiddle 有很多改进的机会
- 前端功能,例如 SQL 语法高亮
- 协调器分配算法
- 带有预加载数据集的数据库实例
- 通过提前运行容器来减少延迟
- 以及许多其他...
如果您想提出新的改进建议或分享任何其他反馈,请在 Github 存储库中创建一个 issue。我们将不胜感激!
并且 fiddle.clickhouse.com 正在等待您的查询 :)