第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

為了賬號安全,請及時綁定郵箱和手機立即綁定

我的瀏覽器沒準備好迎接這個挑戰(zhàn)。使用DuckDB、Apache Arrow和Web Workers的真實體驗

作者:Przemyslaw Maciolek

这里是一个介绍

Motif Analytics,我们正在构建一个高度互动的分析工具,它允许用户在相对较大的数据集中发现洞察,完全通过浏览器。我们还提供了一个更传统的云模式,但“本地”(完全通过浏览器)模式对用户来说是一个重要的途径,因为它可以让用户试用 Motif 并看看它是否符合他们的需求,无需做出任何承诺。为了实现这一点,我们采用了多种技术手段,包括 DuckDB WASMApache ArrowWeb Workers

在过去的几个月里,我们发现了一些优点和缺点。虽然这些经验是在我们特定的使用场景下获得的,我们认为它在某种程度上仍然具有普遍性,可能对任何正在开发这种现代、响应式且处理大量数据的 web 应用程序的人来说都是有用的。

并行处理和浏览器有什么关系呢?

通过并行处理加速计算密集型分析任务的想法几乎与计算本身一样古老。它从20世纪60年代和70年代的“共享内存架构”开始,逐步演变为“集群”,“网格计算”,最终发展为“云计算”。我还记得用一些已经被遗忘的技术,比如PVMMPI,构建学术项目时的乐趣,使用诸如。如今的世界已大不相同,但所有数据处理问题在核心上仍保持相似,都是围绕着将大型任务分解成较小的独立部分,并同步它们的执行过程。

高效的多核CPU的出现使得计算密集型任务可以直接在浏览器中运行,更接近用户成为可能。计算密集型任务可以利用Web Workers进行并行处理,这些技术被所有现代浏览器支持,并正逐渐成为编写响应式应用的重要工具,不过也有一些重要的限制。

通过使用熟悉的工具(如使用 SQL 描述查询)可以简化交互式的数据分析。接下来是 DuckDB,一个专为 OLAP (在线分析处理)设计的开源数据库。在数据仓库方面,它就像 Sqlite 对于 RDBMS 一样。它对外部依赖很少,拥有丰富且精美文档的语言(文档精美),并且运行非常快,这主要归功于它利用了数据库分析领域的最新技术。DuckDB WASMDuckDB 的一个特殊版本,编译为 WebAssembly,这使得它可以在浏览器中运行,与页面脚本一起工作。

这两个(“Web Workers” 和 “DuckDB WASM”)可以一起使用,构建一个更复杂的处理框架。比如,可以使用 Web Workers 并行执行一些特定领域的自定义处理代码,然后将结果传给 DuckDB WASM,在那里可以用方便的 SQL 查询来处理并计算聚合。

使用Apache Arrow这样一个语言无关的框架,可以将两者采用标准化的列式内存格式结合在一起。

为了使它更加吸引人,相同的架构也可以在服务器模式下运行。可以像组织Node.js worker threadsDuckDB Node库一样,以非常类似的方式组织它们,从而实现代码复用。

等一下!还有更多的使用案例!DuckDB 也可以用于(快速地)交换数据,比如 Parquet, CSV 或 JSON

尽管这一切听起来令人兴奋,但我们下面会讨论其中带来的挑战。

DuckDB WASM 的性能

虽然 DuckDB WASM 提供了与 任何其他版本的 DuckDB 几乎相同的功能,但它是在 基于栈的虚拟机(WebAssembly) 上执行,而不是作为原生库代码运行。尽管 WASM 被认为运行速度快,但这会增加运行代码时的额外开销。此外,当前的 DuckDB WASM 是单线程引擎(这归因于现已过时的 SharedArrayBuffer 的使用限制),并提供实验性的 COI 支持。

这最终意味着查询运行速度比在本地原生DuckDB实例中(无论是通过shell还是作为Node/Python等库执行)慢得多。

示例 1:TPC-H 线item (lineitem) 查询

那么我们能期待 DuckDB WASM 和原生 CLI 之间性能有何不同呢?这里有一个我在 M1 Pro 上跑的临时测试。

结果 1 DuckDB(内置库)命令行接口 0.9.2

     D PRAGMA threads=1;  
    D .timer on  
    D select ...  
    ┌──────────────┬──────────────┬──────────┬────────────────────┬─────┐  
    │ l_returnflag │ l_linestatus │ sum_qty  │   sum_base_price   │ ... │  
    │   varchar    │   varchar    │  double  │       double       │ ... │  
    ├──────────────┼──────────────┼──────────┼────────────────────┼─────┤  
    │ A            │ F            │ 380456.0 │ 532348211.6500006 │ ... │  
    │ N            │ F            │   8971.0 │        12384801.37 │ ... │  
    │ N            │ O            │ 742802.0 │ 1041502841.4499991 │ ... │  
    │ R            │ F            │ 381449.0 │  534594445.3500006 │ ... │  
    └──────────────┴──────────────┴──────────┴────────────────────┴─────┘  
    运行时间(秒):实际 0.807 秒,用户 0.590743 秒,系统 0.035380 秒

结果 2:DuckDB WASM Shell 0.9.2 在 Chrome 上

    duckdb> .timer on  
    duckdb> select ...  
    ┌──────────────┬──────────────┬─────────┬────────────────────┬─────┐  
    │ l_returnflag ┆ l_linestatus ┆ sum_qty ┆ sum_base_price     ┆ ... │  
    ╞══════════════╪══════════════╪═════════╪════════════════════╪═════╡  
    │ A            ┆ F            ┆ 380,456 ┆ 532,348,211.6499983 ┆ ... │  
    │ N            ┆ F            ┆ 8,971   ┆ 12,384,801.369999997 ┆ ... │  
    │ N            ┆ O            ┆ 742,802 ┆ 104,150,284.1449979 ┆ ... │  
    │ R            ┆ F            ┆ 381,449 ┆ 534,594,445.3499986 ┆ ... │  
    └──────────────┴──────────────┴─────────┴────────────────────┴─────┘  
    耗时: 03.257 秒 (时间)

我们得到的是0.8s(原生库,单线程)与3.3sWASM),这意味着在这个特定情况下,_WASM_要慢四倍。但等等,如果我们先将数据复制到一个临时表会怎么样?

    创建表 lineitem,其数据来源于 'lineitem.parquet' 文件;

这使得两种情况都更快,分别将时间减少到0.1s(原生库,单线程)和0.4s, WASM,保持了之前的四倍速度差异。

例子 2:调用成本高的函数

再来一个例子怎么样?我们将使用相同的数据集,构建一个不同的查询语句。其中一个会调用一个相对昂贵的函数,该函数需要对每行数据进行执行。

结果 3 DuckDB(内置库)CLI 0.9.2

     D PRAGMA threads=1;  
    D .timer on  
    D select ...  
    ┌──────────────────────────────────┐  
    │             md5_val              │  
    │             varchar              │  
    ├──────────────────────────────────┤  
    │ 0000031428caeaafcddcf1a1f5d4ea26 │  
    │ 000005560d5cc20991b8bb57e64f58a0 │  
    │ 00000aa836f58524e6ae1d75c9246511 │  
    │ 000016d700b533970506d1164d0ee003 │  
    │ 00001921a51a1880a184ed25fc3d95b8 │  
    └──────────────────────────────────┘  
    运行时间(秒): 实际 1.679 秒 耗时 1.533280 秒 系统 0.098910 秒

如果我们增加线程数量会怎么样?在我的 M1 Pro 笔记本电脑上会发生以下事情:

    D PRAGMA threads=8;  
    D select ...  
    ┌──────────────────────────────────┐  
    │             md5_val              │  
    │             字符型              │  
    ├──────────────────────────────────┤  
    │ 0000031428caeaafcddcf1a1f5d4ea26 │  
    │ 000005560d5cc20991b8bb57e64f58a0 │  
    │ 00000aa836f58524e6ae1d75c9246511 │  
    │ 000016d700b533970506d1164d0ee003 │  
    │ 00001921a51a1880a184ed25fc3d95b8 │  
    └──────────────────────────────────┘  
    运行时间 (秒): 实际 0.313 用户时间 1.742058 系统时间 0.019078

结果 4: DuckDB WASM Shell 0.9.2 在 Chrome 119.0 浏览器中

    duckdb> .timer on  
    duckdb> select ...  
    ┌──────────────────────────────────┐  
    │ md5_val                          │  
    ╞══════════════════════════════════╡  
    │ 0000031428caeaafcddcf1a1f5d4ea26 │  
    │ 000005560d5cc20991b8bb57e64f58a0 │  
    │ 00000aa836f58524e6ae1d75c9246511 │  
    │ 000016d700b533970506d1164d0ee003 │  
    │ 00001921a51a1880a184ed25fc3d95b8 │  
    └──────────────────────────────────┘  
    用时: 01.881 秒

现在,两者的时长几乎相同。我们得到了1.7秒(原生库,单线程)和1.9秒(‘WASM’),在执行查询作为WASM时,性能下降了约10%,真的挺厉害!

外卖

一如既往,结果会根据数据集的特性和查询复杂度有所不同,但观察到这种差异并不令人惊讶。与原生版本不同,WASM 在虚拟机中运行。而且,使用多个工人的功能相对较新(在 next-coi 实验版本 中,单线程限制将被解除),我还不确定是否可以推荐使用这种方法。

除了上述问题外,分配给 WASM 的内存受到浏览器的限制(在 Chrome 中,每个标签页的限制目前为 4GB)。当你试图加载更大的数据集或执行复杂的连接操作时,这一点可能会导致痛苦的体验。 DuckDB 以“从不会因为内存不足而崩溃”著称(确实如此,详情参见此处),但 WASM 还不能使用本地持久性来在处理查询时将溢出的数据存储,当数据无法在可用内存中容纳时。不过,这种情况有望很快得到改善,正在进行相关工作。直到这一改进实现之前,这仍然是一个已知的 WASM 限制问题。

尽管如此,DuckDB WASM 目前是(如果不是最快的)最快的浏览器内查询引擎。然而,在可能的情况下,运行本地代码(不受浏览器限制)将始终更快,并支持更大规模的查询。

Web Worker 线程和模式一致性

我们架构中使用_Web Workers_来并行化处理一个复杂任务,并将输出传递给DuckDB。在讨论一些具体细节之前,值得一提的是,使用_Web Workers_与在Golang、_Java_或_Rust_中编写并发代码相比有很大差异。Surma 在他的文章中详细讨论了这一点(链接),但简而言之,_Web Workers_是相互独立的,只能通过传递_字节数组缓冲区(即共享数组缓冲区可转移的数组缓冲区_)来通信

这意味着用于同步的消息量应该相对较小,并且在选择序列化和反序列化的具体方法时必须格外小心。这也是_Apache Arrow_在这里非常适用的原因之一,其_IPC(交互进程通信)_缓冲区非常契合(向量数据模型甚至无需序列化,可以直接传递内存片段)。

DuckDB 在执行查询时读取 Arrow 格式的数据只增加很小的开销,这让它在低延迟分析应用中特别有用。

此架构大多可以像下图所示那样实现。

在我们运行 SQL 查询之前,只需要从工作人员收集 Apache Arrow 表并将其传递给 DuckDB ,形成一个单一的逻辑表。实现这一目标的代码如下代码片段所示:

不幸的是,运行它会失败并出现以下错误:

转换错误:无法将 '公元前4世纪' 插入到 'books' 表中:无法将 '公元前4世纪' 转换为 DOUBLE  
       在 O.onMessage(index.js:11583:17) 出现错误

每个 Arrow Table 本身都是一个有效的表格,并且所有列名都匹配,但由于它们的模式存在细微差异,因此在执行插入操作时会被 DuckDB 拒绝。事实证明,即使是在更简单的情况下,例如,某些分区中的字段可能为 null,这也可能变得比较棘手,如 ARROW-2860 中所述,该问题已经存在了 5 年之久。

使用多个 Arrow 表,每个可能包含一组不同的 BatchRecords 记录,并不像是 Apache Arrow 规范 中所提到的那样处理,所以也许可以将其视为“灰色地带”,因此,可能最好尽量避免遇到这种情况。

最终,似乎没有简单的通用解决方案来解决模式一致性的方案。C++ Arrow API 提供了 ConcatenateTables,可以通过将 unify_schemas 属性设置为 true 来处理某些情况(并根据需要提供更多 详细信息),但无法从 JavaScript(或其他无法通过 FFI 调用 C++ 的语言)中调用。也有一些尝试填补这一空白的项目,例如 Apache Arrow 的 WebAssembly 实现,但这些项目看起来 没有活跃开发 或基于 较旧的 Arrow 版本

最终,你可能还是得自己处理这种情况,或者(最好)尽量避免一开始就处理“模式协调”的问题,虽然有时候这可能不太现实。

能力上的缺口和……错误

最近_DuckDB WASM_ 很受欢迎,但最常被使用的是 _Python_ 和 Java 库(一年前,它们的下载量远超 _Nodejs_ 库[详情])。因此,无论是 _WASM__还是 _Node.js DuckDB_ 库,可能还不算是非常成熟的产品。社区非常活跃,_DuckDB__团队也付出了很多努力,但简单来说,各种问题和不足还是经常遇到的。

从个人角度来看,这里有几个例子:最近我遇到了一些。

  • 查询某些 JSON 字符串或 Parquet 文件 会抛出“内存访问超出边界”错误。似乎在 DuckDB WASM v1.27.0 或更早版本中不会发生,因此降级到旧版本是一个可行的临时解决办法,直到修复完成。
  • 只有第一个表被 register_buffer() 注册 — 该函数暗示可以传递多个 Apache Arrow 表,这些表可以组成一个单一逻辑的 DuckDB 表。但实际上却不是这样。我发现的解决方法是单独注册每个 Apache Arrow 表并将其合并到一个临时表中。更好的方法可能是合并所有记录批次,然后注册一个单一的 Apache Arrow 表。
  • 在某些 UNION ALL 和 ORDER BY 查询时崩溃 — 此问题的修复正在积极开发中。这使得 DuckDB Node 库无法继续使用,整个过程需要重启(真糟糕!)。降级到 DuckDB v0.8 可作为临时的解决办法。

这一切可能看起来有点平淡无奇,但也可能是项目突然受到广泛关注后必然经历的初期成长阶段。社区欢迎贡献者,并在这里说明了如何贡献,与其他任何开源项目一样,最终发现和修复问题的主动权也掌握在我们,用户手中。帮助修复这些问题

此外,几个月前的一些限制现在已经不再存在,这要归功于团队的努力。例如,现在可以在DuckDB WASM中使用许多扩展了。几个月前,我为了获得更好的JSON支持不得不编写了一些临时解决方案。现在,由于启用了JSON扩展,这些临时解决方案已经不需要了(这只是许多改进中的一个)。这将是另一个帖子的话题,但DuckDB的扩展架构真的很令人印象深刻

收尾

快速构建浏览器内的处理栈可以通过使用最近流行的技術来加速。使用 DuckDB WASM(数据交换和 SQL 查询),Web Workers(并行处理计算密集型、特定领域的任务),并通过 Apache Arrow 将它们连接起来。

遗憾的是,它们都有局限性,有时需要额外的努力才能让它们协同工作。我相信很多这些问题会在接下来的几个月里解决掉。例如,通过增加对OPFS的支持,并采用_COI_版本,_DuckDB WASM_的容量限制应该会有很大改善。希望这些“初期问题”会随着社区更多的测试而逐渐减少,发现的bug也会被解决。

从开发人员的角度来看,这可以被视为一个机会。DuckDB带来了许多所需的功能,并且正处于快速增长的轨迹上。我们将会看到它在更多场景中得到应用。尽管它目前还存在一些挑战,但这恰好为加入社区、帮助发展并同时学习提供了绝佳机会。

如果你想了解更多,可以给我们发邮件至 mikpanko@gmail.com。

點擊查看更多內(nèi)容
TA 點贊

若覺得本文不錯,就分享一下吧!

評論

作者其他優(yōu)質(zhì)文章

正在加載中
  • 推薦
  • 評論
  • 收藏
  • 共同學(xué)習(xí),寫下你的評論
感謝您的支持,我會繼續(xù)努力的~
掃碼打賞,你說多少就多少
贊賞金額會直接到老師賬戶
支付方式
打開微信掃一掃,即可進行掃碼打賞哦
今天注冊有機會得

100積分直接送

付費專欄免費學(xué)

大額優(yōu)惠券免費領(lǐng)

立即參與 放棄機會
微信客服

購課補貼
聯(lián)系客服咨詢優(yōu)惠詳情

幫助反饋 APP下載

慕課網(wǎng)APP
您的移動學(xué)習(xí)伙伴

公眾號

掃描二維碼
關(guān)注慕課網(wǎng)微信公眾號

舉報

0/150
提交
取消