国产av一二三区|日本不卡动作网站|黄色天天久久影片|99草成人免费在线视频|AV三级片成人电影在线|成年人aV不卡免费播放|日韩无码成人一级片视频|人人看人人玩开心色AV|人妻系列在线观看|亚洲av无码一区二区三区在线播放

網(wǎng)易首頁(yè) > 網(wǎng)易號(hào) > 正文 申請(qǐng)入駐

DuckDB 開發(fā)者大會(huì)四連擊:擴(kuò)展,加密,存儲(chǔ)過(guò)程,邊緣分析

0
分享至

DuckDB 最近舉辦了首屆 DuckDB 開發(fā)者大會(huì),里面有四個(gè)有趣的議題,老馮這里從視頻中提取了文字稿,然后請(qǐng) Claude / GPT 整理成完整的文章,在這里與大家分享,看看 DuckDB 生態(tài)的最新進(jìn)展。以及最后附上老馮對(duì) DuckDB 生態(tài)的點(diǎn)評(píng)

四篇演講分別是:

DuckDB 擴(kuò)展:過(guò)去、現(xiàn)在、與未來(lái)

DuckDB 中的存儲(chǔ)與加密

DuckPL:DuckDB 中的一種存儲(chǔ)過(guò)程語(yǔ)音(PL/PGSQL)

GizmoEdge:用于物聯(lián)網(wǎng)的分布式 DuckDB 引擎

DuckDB 擴(kuò)展:過(guò)去、現(xiàn)在與未來(lái) 引言

大家好,我是 Sam Ansmink。今天我將為大家介紹 DuckDB 擴(kuò)展。今天上午 Rusty 已經(jīng)深入講解了擴(kuò)展開發(fā)的細(xì)節(jié),而我會(huì)從更高層次來(lái)審視 DuckDB 擴(kuò)展的全貌——回顧它的發(fā)展歷程,了解當(dāng)前狀態(tài),并展望未來(lái)方向。

今天的內(nèi)容分為三個(gè)部分:首先是簡(jiǎn)介,讓大家對(duì) DuckDB 擴(kuò)展有基本了解;然后我們會(huì)回顧過(guò)去,看看整個(gè)擴(kuò)展框架和生態(tài)系統(tǒng)是如何一步步發(fā)展起來(lái)的;接著是現(xiàn)在,了解當(dāng)前的最佳實(shí)踐和現(xiàn)有功能;最后我會(huì)分享一些未來(lái)的規(guī)劃和發(fā)展方向。

自我介紹

我是 Sam Ansmink,在 DuckDB Labs 工作已經(jīng)超過(guò)四年了。在加入 DuckDB Labs 之前,我在阿姆斯特丹的 CWI(荷蘭國(guó)家數(shù)學(xué)與計(jì)算機(jī)科學(xué)研究中心)完成了碩士論文——那里正是 DuckDB 的誕生地。CWI 有一個(gè)數(shù)據(jù)庫(kù)架構(gòu)研究組,我的碩士論文課題是在 DuckDB 中實(shí)現(xiàn)加密查詢執(zhí)行。

畢業(yè)后我加入了當(dāng)時(shí)還是一家小型創(chuàng)業(yè)公司的 DuckDB Labs,參與開發(fā)了多個(gè)擴(kuò)展,同時(shí)也深度參與了擴(kuò)展框架本身的建設(shè),包括擴(kuò)展模板、各種 API 以及用于部署和測(cè)試的 CI/CD 流水線。

什么是 DuckDB 擴(kuò)展?

DuckDB 擴(kuò)展本質(zhì)上是一種為 DuckDB 核心功能添加或修改功能的方式。它可以實(shí)現(xiàn)很多東西:表函數(shù)、數(shù)據(jù)類型、文件系統(tǒng)、目錄、加密模塊等等。

舉幾個(gè)例子:JSON 擴(kuò)展可以幫你讀取 JSON 文件;PostgreSQL 擴(kuò)展可以與 PostgreSQL 數(shù)據(jù)庫(kù)集成;還有一些更有趣的社區(qū)擴(kuò)展,比如 Google Sheets 擴(kuò)展,可以直接從 Google 表格讀寫數(shù)據(jù)。當(dāng)然也有一些比較小眾的擴(kuò)展,這也是科學(xué)研究的常態(tài)。

為什么需要擴(kuò)展?

這個(gè)問(wèn)題很關(guān)鍵,我認(rèn)為主要有以下幾個(gè)原因:

二進(jìn)制文件大小:DuckDB 是一個(gè)嵌入式數(shù)據(jù)庫(kù),我們希望它能在任何地方運(yùn)行。如果二進(jìn)制文件達(dá)到 3GB,那就成問(wèn)題了,因?yàn)槲覀円残枰诖鎯?chǔ)和內(nèi)存受限的環(huán)境中運(yùn)行。通過(guò)擴(kuò)展機(jī)制,用戶可以自行決定功能集和二進(jìn)制大小之間的平衡。

零依賴:你可能聽說(shuō)過(guò) DuckDB 是零依賴系統(tǒng)。這是真的,但我們確實(shí)想利用很多優(yōu)秀的外部庫(kù)。解決方案就是把這些依賴推到擴(kuò)展里。DuckDB 核心保持零依賴,而擴(kuò)展則可以使用這些依賴來(lái)實(shí)現(xiàn)特定功能。只有當(dāng)你需要某個(gè)功能時(shí),才會(huì)引入相應(yīng)的外部依賴。

功能不兼容:有些功能之間存在互斥性。比如不同的 SQL 方言可能相互不兼容,擴(kuò)展是處理這種情況的好機(jī)制。

不同的維護(hù)者:不同的人可以維護(hù)不同部分的代碼,這也是擴(kuò)展機(jī)制帶來(lái)的靈活性。

如何使用擴(kuò)展?

即使你認(rèn)為自己沒有使用 DuckDB 擴(kuò)展,實(shí)際上你可能已經(jīng)在用了。DuckDB 會(huì)自動(dòng)安裝和加載擴(kuò)展。

舉個(gè)例子,當(dāng)你執(zhí)行一條簡(jiǎn)單的查詢,從網(wǎng)絡(luò)上的 JSON 文件中 SELECT * 時(shí),DuckDB 會(huì)在后臺(tái)自動(dòng)為你安裝和加載兩個(gè)必需的擴(kuò)展(HTTP 文件系統(tǒng)擴(kuò)展和 JSON 擴(kuò)展)。這個(gè)過(guò)程完全透明,你甚至不會(huì)注意到。當(dāng)然,你也可以選擇手動(dòng)安裝和加載擴(kuò)展。

擴(kuò)展從哪里獲???

我們有一個(gè)叫做"擴(kuò)展倉(cāng)庫(kù)"的概念,目前有兩個(gè)倉(cāng)庫(kù):Core(核心)Community(社區(qū))。核心倉(cāng)庫(kù)包含所有由 DuckDB 官方維護(hù)的擴(kuò)展,社區(qū)倉(cāng)庫(kù)則由社區(qū)成員維護(hù)。

使用起來(lái)非常簡(jiǎn)單,直接用 SQL 就可以安裝。默認(rèn)從核心倉(cāng)庫(kù)安裝,如果想安裝社區(qū)擴(kuò)展,只需指定 FROM community 即可。

發(fā)展歷程回顧

讓我們來(lái)看看 DuckDB 擴(kuò)展的發(fā)展歷程:

?2018年:DuckDB 在 CWI 的第一次代碼提交?2020年:擴(kuò)展機(jī)制誕生——這是 DuckDB 能夠?qū)⒋a放入擴(kuò)展并加載的核心能力,至今仍是 DuckDB 加載擴(kuò)展的基礎(chǔ)方式?2021年:核心倉(cāng)庫(kù)建立——用戶可以通過(guò) INSTALL 語(yǔ)法自動(dòng)安裝擴(kuò)展?2023年:C++ 擴(kuò)展模板發(fā)布——這是一個(gè)關(guān)鍵節(jié)點(diǎn),我們不僅自己能構(gòu)建擴(kuò)展,還告訴社區(qū)"你們也可以這樣做"。這個(gè)模板現(xiàn)在被大多數(shù)核心擴(kuò)展和社區(qū)擴(kuò)展使用?2024年:社區(qū)倉(cāng)庫(kù)建立——讓社區(qū)開發(fā)者能夠輕松部署擴(kuò)展,用戶安裝社區(qū)擴(kuò)展和核心擴(kuò)展一樣方便?之后:Rust 擴(kuò)展模板和 C 擴(kuò)展模板相繼發(fā)布

在擴(kuò)展方面,第一個(gè)重要擴(kuò)展是 ICU(國(guó)際組件庫(kù)),它是一個(gè)相當(dāng)大的庫(kù),正是因?yàn)樗罅藷o(wú)法放入核心,才催生了擴(kuò)展機(jī)制。之后陸續(xù)出現(xiàn)了 Parquet、HTTP 文件系統(tǒng)、PostgreSQL、Delta Lake 等擴(kuò)展,最近還有去年發(fā)布的 DuckLake 擴(kuò)展,實(shí)現(xiàn)了我們自己的開放湖倉(cāng)格式。

現(xiàn)狀

DuckDB 擴(kuò)展現(xiàn)在非常普及??匆恍?shù)據(jù):

?32 個(gè)核心擴(kuò)展?145 個(gè)社區(qū)擴(kuò)展?核心擴(kuò)展每周下載超過(guò) 2700 萬(wàn)次?社區(qū)擴(kuò)展每周下載超過(guò) 50 萬(wàn)次

與 DuckDB Python 客戶端的下載量相比,這些數(shù)字也相當(dāng)可觀。這說(shuō)明 DuckDB 擴(kuò)展已經(jīng)成為使用 DuckDB 不可或缺的一部分,這當(dāng)然也與我們的自動(dòng)加載機(jī)制有關(guān),很多人確實(shí)依賴 Parquet、HTTPS 等功能。

當(dāng)前的擴(kuò)展構(gòu)建方式

目前我們有三種擴(kuò)展模板:

1.C++ 擴(kuò)展模板(推薦):使用 DuckDB 的不穩(wěn)定 API2.Rust 擴(kuò)展模板(實(shí)驗(yàn)性):理論上很好但有一些局限,目前也基于不穩(wěn)定 API3.C 擴(kuò)展模板:支持 C 和 C++,是第一個(gè)使用穩(wěn)定 API 的模板

關(guān)于維護(hù)者,核心倉(cāng)庫(kù)中的擴(kuò)展分為三類:

?主要核心擴(kuò)展:獲得 DuckDB Labs 最高級(jí)別支持?次要核心擴(kuò)展:可能更實(shí)驗(yàn)性,支持力度稍小?第三方核心擴(kuò)展:由 DuckDB Labs 的合作伙伴維護(hù)

社區(qū)倉(cāng)庫(kù)的擴(kuò)展則由社區(qū)成員維護(hù)。

當(dāng)前面臨的挑戰(zhàn)

我們的主要推薦方式是使用不穩(wěn)定的 C++ API,這帶來(lái)一些問(wèn)題:

?每個(gè)版本都需要重新構(gòu)建所有擴(kuò)展:這是一個(gè)負(fù)擔(dān)?擴(kuò)展維護(hù)成本高:每當(dāng) DuckDB 核心工程師修改了被很多擴(kuò)展使用的 API,就會(huì)破壞這些擴(kuò)展,維護(hù)者需要花時(shí)間修復(fù)?難以編寫文檔:API 是一個(gè)不斷變化的目標(biāo),要么投入大量精力更新文檔,要么文檔就會(huì)過(guò)時(shí)

未來(lái)方向

解決方案是使用穩(wěn)定的 C API。穩(wěn)定 API 帶來(lái)的好處顯而易見:

?穩(wěn)定性:編譯一次的擴(kuò)展可以在多個(gè)版本上持續(xù)工作?良好的互操作性:作為 C API,可以更好地與 Rust 等其他語(yǔ)言集成?擴(kuò)展維護(hù)者可以構(gòu)建擴(kuò)展后"放心忘記",它會(huì)持續(xù)工作

我們的目標(biāo)是:

1.擴(kuò)展 C 擴(kuò)展 API 的功能:目前正在努力添加更多特性,以便更多擴(kuò)展能夠遷移過(guò)來(lái)2.穩(wěn)定化 Rust 和 C 擴(kuò)展模板:利用日益強(qiáng)大的穩(wěn)定 API3.盡可能多地遷移現(xiàn)有擴(kuò)展:評(píng)估哪些適合用 Rust,哪些適合用 C/C++

時(shí)間表方面,雖然我們不傾向于公開承諾日期,但內(nèi)部目標(biāo)是在 v1.6 實(shí)現(xiàn)這些主要改進(jìn)(v1.5 將在幾周后發(fā)布,v1.6 預(yù)計(jì)在幾個(gè)月后,大約今年夏天)。

問(wèn)答環(huán)節(jié)要點(diǎn)

關(guān)于私有擴(kuò)展倉(cāng)庫(kù):DuckDB 已經(jīng)支持這個(gè)功能。你可以將 DuckDB 設(shè)置為無(wú)簽名模式,從任意位置安裝和加載擴(kuò)展;或者編譯你自己的 DuckDB 版本,把閉源擴(kuò)展靜態(tài)鏈接進(jìn)去。

關(guān)于 Iceberg 擴(kuò)展的分區(qū)寫入支持:這是高優(yōu)先級(jí)的功能,預(yù)計(jì)在 V2 支持完成后就會(huì)著手,可能在 v1.5 的某個(gè) bug 修復(fù)版本中就能實(shí)現(xiàn)。

關(guān)于安全性:默認(rèn)模式下 DuckDB 會(huì)自動(dòng)加載擴(kuò)展,這是為了最佳的開箱體驗(yàn)。但如果你構(gòu)建的是安全關(guān)鍵系統(tǒng),可以參考我們的"Securing DuckDB"文檔,比如編譯自己的版本并靜態(tài)加載擴(kuò)展、禁用擴(kuò)展安裝等。

關(guān)于社區(qū)擴(kuò)展的安全審計(jì):首先,自動(dòng)加載只對(duì) DuckDB 核心團(tuán)隊(duì)控制的擴(kuò)展有效,我們永遠(yuǎn)不會(huì)自動(dòng)加載社區(qū)擴(kuò)展。社區(qū)擴(kuò)展的安全管理方式與其他包管理器類似——用戶需要自己評(píng)估是否信任某個(gè)擴(kuò)展。所有社區(qū)擴(kuò)展都必須開源,你不能直接上傳二進(jìn)制文件到社區(qū)倉(cāng)庫(kù)。這需要社區(qū)的共同檢查,我們也會(huì)主動(dòng)排查惡意擴(kuò)展。

總結(jié)

?DuckDB 擁有相當(dāng)完善的擴(kuò)展生態(tài)系統(tǒng)?擴(kuò)展下載量巨大,維護(hù)者社區(qū)不斷壯大,提供了各種我們從未想到過(guò)的功能?目前推薦的 C++ API 能深入 DuckDB 內(nèi)部,但代價(jià)是不穩(wěn)定?我們正在構(gòu)建新的穩(wěn)定 C API,將大大改善擴(kuò)展的維護(hù)體驗(yàn)

DuckDB 中的存儲(chǔ)與加密 引言

大家好,歡迎來(lái)到我的演講。今天我將為大家介紹 DuckDB 中的存儲(chǔ)與加密。你可能會(huì)好奇為什么要把存儲(chǔ)和加密放在一起講——這是因?yàn)橐嬲斫饧用苁侨绾螌?shí)現(xiàn)的,你至少需要從高層次上了解 DuckDB 的存儲(chǔ)機(jī)制是如何工作的。

自我介紹

先介紹一下我自己。我在阿姆斯特丹大學(xué)完成了碩士學(xué)位,碩士論文是在微軟的一個(gè)數(shù)據(jù)庫(kù)團(tuán)隊(duì)(Citus Data)完成的,主題是分布式 PostgreSQL。那是我第一次接觸數(shù)據(jù)庫(kù)內(nèi)核和計(jì)算機(jī)科學(xué)基礎(chǔ)知識(shí),因?yàn)槲冶究破鋵?shí)并不是計(jì)算機(jī)科學(xué)專業(yè)。

但在那之后,我發(fā)現(xiàn)自己非常喜歡這個(gè)領(lǐng)域。于是我獲得了去 CWI 的機(jī)會(huì),在那里從事數(shù)據(jù)庫(kù)與安全交叉領(lǐng)域的研究。最終,這段經(jīng)歷把我?guī)У搅?DuckDB Labs。目前我是 DuckDB Labs 的軟件工程師,過(guò)去一年我為 DuckDB 的加密功能做出了相當(dāng)多的貢獻(xiàn)。

DuckDB 如何保護(hù)你的數(shù)據(jù)?

首先我想強(qiáng)調(diào)的是,DuckDB 保護(hù)的是靜態(tài)數(shù)據(jù)(data at rest)。這意味著數(shù)據(jù)只在寫入磁盤的那一刻才會(huì)被加密。

DuckDB 有兩種加密方式:

1. Parquet 加密

Parquet 加密已經(jīng)存在一段時(shí)間了,大約兩年前在 0.10 版本中就已發(fā)布。DuckLake 在加密模式下也使用 Parquet 加密,本質(zhì)上就是寫入加密的 Parquet 文件。

使用方法很簡(jiǎn)單:通過(guò) PRAGMA 添加加密密鑰,然后就可以將明文 Parquet 文件復(fù)制為加密的 Parquet 文件。

2. 數(shù)據(jù)庫(kù)文件加密

數(shù)據(jù)庫(kù)文件加密不僅加密主數(shù)據(jù)庫(kù)文件,還會(huì)加密預(yù)寫日志(Write-Ahead Log,WAL)和臨時(shí)文件。在本次演講中,我會(huì)按照這個(gè)順序介紹這三種不同類型的文件。

加密數(shù)據(jù)庫(kù)文件也很簡(jiǎn)單:只需在附加數(shù)據(jù)庫(kù)時(shí)指定加密密鑰,還可以選擇指定加密算法(如 GCM)。

加密算法

DuckDB 使用高級(jí)加密標(biāo)準(zhǔn) AES。這個(gè)加密標(biāo)準(zhǔn)有多種加密模式,DuckDB 目前支持兩種:GCMCTR。

今天我不會(huì)深入講解這些加密模式的工作原理,但有一點(diǎn)很重要:這兩種都是隨機(jī)化加密算法。這意味著即使你使用相同的密鑰,對(duì)兩個(gè)完全相同的明文進(jìn)行加密,也會(huì)產(chǎn)生不同的密文(前提是實(shí)現(xiàn)正確)。這一點(diǎn)很重要——攻擊者查看你的加密數(shù)據(jù)時(shí),永遠(yuǎn)無(wú)法推斷出底層數(shù)據(jù)是否相同。

關(guān)于 GCM 模式

GCM 是一種行業(yè)標(biāo)準(zhǔn)加密算法,被廣泛應(yīng)用于各種系統(tǒng)。有幾個(gè)要點(diǎn)需要了解:

?Nonce(一次性數(shù)字)/ 初始化向量(IV):這是一個(gè)唯一的字節(jié)序列,DuckDB 在加密每個(gè)數(shù)據(jù)塊之前自行生成。它確保所有數(shù)據(jù)以隨機(jī)化方式加密。?Tag(標(biāo)簽):GCM 在加密數(shù)據(jù)塊后會(huì)計(jì)算一個(gè)標(biāo)簽,本質(zhì)上類似于校驗(yàn)和,但具有更強(qiáng)的安全保證。

密鑰管理

當(dāng)你輸入加密密鑰時(shí),DuckDB 并不會(huì)直接使用這個(gè)密鑰來(lái)加密數(shù)據(jù)。相反,它會(huì)將你的密鑰輸入一個(gè)密鑰派生函數(shù)(Key Derivation Function)。這個(gè)函數(shù)還會(huì)接收一個(gè)隨機(jī)的數(shù)據(jù)庫(kù)標(biāo)識(shí)符作為輸入,最終生成一個(gè)安全的 32 字節(jié)加密密鑰,這個(gè)密鑰才是實(shí)際用于加密數(shù)據(jù)的密鑰。

這種設(shè)計(jì)的好處是:即使你使用相同的密鑰加密多個(gè)不同的數(shù)據(jù)庫(kù)文件,實(shí)際使用的加密密鑰也是不同的,這是一層額外的安全措施。

重要提示:請(qǐng)永遠(yuǎn)不要使用同一個(gè)密鑰加密多個(gè)不同的文件,這通常被認(rèn)為是不安全的。

密鑰驗(yàn)證機(jī)制

當(dāng)你加密數(shù)據(jù)庫(kù)文件時(shí),我們會(huì)使用一個(gè)小技巧來(lái)驗(yàn)證解密時(shí)使用的密鑰是否正確。我們會(huì)加密一段已知的明文——在 DuckDB 中這段文本叫做"ducky"——并將其作為元數(shù)據(jù)存儲(chǔ)在數(shù)據(jù)庫(kù)頭部。當(dāng)你嘗試讀取加密文件時(shí),我們首先會(huì)查找這段元數(shù)據(jù)并嘗試解密。如果成功,說(shuō)明密鑰正確;如果失敗,我們會(huì)提前終止并報(bào)錯(cuò)。

安全的密鑰緩存

如果密鑰驗(yàn)證通過(guò),我們會(huì)將密鑰存儲(chǔ)在一個(gè)安全的加密密鑰緩存中。這個(gè)緩存與普通緩存不同:我們精確跟蹤密鑰存儲(chǔ)的位置,并鎖定密鑰所在的內(nèi)存區(qū)域,防止密鑰被意外交換到磁盤。此外,當(dāng)你不再使用密鑰時(shí),我們會(huì)確保密鑰從內(nèi)存中被完全清除。

DuckDB 存儲(chǔ)結(jié)構(gòu)

要理解加密機(jī)制,需要先了解 DuckDB 的存儲(chǔ)結(jié)構(gòu)。

文件頭部

當(dāng) DuckDB 寫入文件時(shí),首先會(huì)寫入數(shù)據(jù)庫(kù)頭部:一個(gè)主頭部和兩個(gè)數(shù)據(jù)庫(kù)頭部。

主頭部包含:

?校驗(yàn)和(檢查頭部是否損壞)?魔數(shù)(Magic bytes)?存儲(chǔ)版本?標(biāo)志位(例如指示文件是否已加密)?數(shù)據(jù)庫(kù)標(biāo)識(shí)符?加密元數(shù)據(jù)

數(shù)據(jù)庫(kù)頭部包含:

?迭代計(jì)數(shù)?文件中的塊數(shù)量?塊大小?向量大小?序列化兼容性版本

數(shù)據(jù)存儲(chǔ)

在頭部和元數(shù)據(jù)之后,DuckDB 以行組(Row Groups)的形式存儲(chǔ)實(shí)際數(shù)據(jù)。這與 Parquet 類似,DuckDB 中一個(gè)行組大約包含 12 萬(wàn)行。行組被分割成列段(Column Segments,內(nèi)部稱為 Column Data),列段又進(jìn)一步劃分為(Blocks)。

塊的結(jié)構(gòu)很簡(jiǎn)單:

?固定大小為 256 KB?包含一個(gè) 8 字節(jié)的塊頭部(存儲(chǔ)檢查點(diǎn)信息)?其余空間用于存儲(chǔ)數(shù)據(jù)

值得注意的是,DuckDB 在存儲(chǔ)數(shù)據(jù)到塊之前會(huì)先嘗試壓縮數(shù)據(jù),256 KB 的塊大小對(duì)我們使用的壓縮算法來(lái)說(shuō)效率很高。

主數(shù)據(jù)庫(kù)加密

注意:1.4 版本和 1.5 版本的加密結(jié)構(gòu)略有不同,我這里介紹的是即將在大約兩周后發(fā)布的 DuckDB 1.5 版本的結(jié)構(gòu)。

頭部加密

DuckDB 不加密主數(shù)據(jù)庫(kù)頭部,原因有二:

1.主頭部不包含敏感數(shù)據(jù),攻擊者讀取也無(wú)妨2.我們需要讀取其中的加密元數(shù)據(jù)來(lái)確定使用的加密算法、密鑰大小等信息

但是,后續(xù)的數(shù)據(jù)庫(kù)頭部以及之后的所有數(shù)據(jù)都會(huì)被加密

塊級(jí)加密

我們選擇在塊級(jí)別進(jìn)行加密,主要有三個(gè)原因:

1.壓縮優(yōu)先:我們可以先壓縮數(shù)據(jù)再加密,減少需要加密的數(shù)據(jù)量2.大小合適:塊的大小剛好可以容納初始加密開銷3.按需解密:執(zhí)行查詢時(shí),你很可能不需要讀取整個(gè)數(shù)據(jù)庫(kù)文件,這樣可以只解密計(jì)算查詢結(jié)果所需的那些塊

對(duì)于加密的塊,塊頭部從 8 字節(jié)變?yōu)?40 字節(jié)

?前 12 字節(jié):Nonce?接下來(lái) 16 字節(jié):Tag?4 字節(jié)空白(用于對(duì)齊)?8 字節(jié):加密后的校驗(yàn)和

我們也會(huì)加密校驗(yàn)和,這是一個(gè)額外的安全措施,防止攻擊者提前讀取。

預(yù)寫日志(WAL)加密

預(yù)寫日志是一個(gè)追加式文件。當(dāng)你對(duì)數(shù)據(jù)庫(kù)做出更改時(shí),更改會(huì)先寫入 WAL,然后才會(huì)傳播到主數(shù)據(jù)庫(kù)文件。WAL 主要用于崩潰恢復(fù),也對(duì) ACID 事務(wù)(原子性、一致性、隔離性、持久性)很重要,某些數(shù)據(jù)庫(kù)系統(tǒng)還用它來(lái)提升性能。

WAL 結(jié)構(gòu)

WAL 的結(jié)構(gòu)如下:

?首先是元數(shù)據(jù)(WAL 版本)?然后是數(shù)據(jù)庫(kù)標(biāo)識(shí)符(用于確認(rèn) WAL 是否屬于當(dāng)前數(shù)據(jù)庫(kù)文件)?之后按條目存儲(chǔ)每個(gè)更改

每個(gè) WAL 條目包含:

?長(zhǎng)度前綴(指示需要讀取多少字節(jié))?校驗(yàn)和(檢查條目是否損壞)?條目?jī)?nèi)容

WAL 刷新時(shí)機(jī)

大多數(shù)時(shí)候你可能不會(huì)注意到 WAL 的寫入,因?yàn)?WAL 會(huì)在特定時(shí)間點(diǎn)被刷新:

1.手動(dòng)觸發(fā)檢查點(diǎn)時(shí)2.DuckDB 執(zhí)行自動(dòng)檢查點(diǎn)時(shí)(當(dāng) WAL 超過(guò)一定大小時(shí))3.正常關(guān)閉數(shù)據(jù)庫(kù)時(shí)(如果崩潰,WAL 會(huì)被保留用于恢復(fù))

WAL 加密方式

對(duì)于 WAL 加密:

?元數(shù)據(jù)保持明文:我們需要確定 WAL 是否已加密?按條目加密:每個(gè)條目單獨(dú)加密

加密后的條目結(jié)構(gòu):

?長(zhǎng)度(明文,因?yàn)樾枰酪饷芏嗌僮止?jié))?Nonce?加密后的校驗(yàn)和和條目?jī)?nèi)容?Tag

臨時(shí)文件加密

臨時(shí)文件在數(shù)據(jù)溢出到磁盤時(shí)產(chǎn)生,這可能發(fā)生在執(zhí)行需要大型聚合或大型連接的復(fù)雜查詢時(shí)。

通常 DuckDB 會(huì)在查詢執(zhí)行后自動(dòng)清理這些文件,但在崩潰情況下它們可能會(huì)被遺留。因此我們也需要加密這些文件。臨時(shí)文件的結(jié)構(gòu)與塊和 WAL 條目類似,加密方式也相同。

我們?cè)谌ツ?11 月發(fā)布了一篇博客文章,如果你想了解更多關(guān)于 WAL 加密或臨時(shí)文件加密的內(nèi)容,可以參考那篇文章。

加密 API

正如剛才 Sam 在擴(kuò)展演講中提到的,DuckDB 不希望有任何外部依賴,但我們確實(shí)需要一個(gè)proper加密 API。OpenSSL 是理想選擇,但我們不能直接將它鏈接到 DuckDB 核心中。

從 mbedTLS 到 OpenSSL

最初的 Parquet 加密實(shí)現(xiàn)使用了一個(gè)叫 mbedTLS 的庫(kù),我們精簡(jiǎn)后放入了 DuckDB 核心。但問(wèn)題是 mbedTLS 只依賴純計(jì)算,不利用任何硬件指令,導(dǎo)致速度相當(dāng)慢。

我們需要 OpenSSL。

巧妙的解決方案

我們注意到,使用 DuckDB 的人通常也會(huì)使用 HTTPS 擴(kuò)展,而這個(gè)擴(kuò)展需要 OpenSSL。所以我們做了一個(gè)技巧:當(dāng)你加載 HTTPS 擴(kuò)展時(shí),我們會(huì)用 OpenSSL 的加密 API 覆蓋 mbedTLS 的加密 API。這樣,只要加載了 HTTPS 擴(kuò)展,你的加密就會(huì)獲得硬件加速。

實(shí)際上,現(xiàn)在我們?cè)诖蠖鄶?shù)情況下會(huì)自動(dòng)加載 HTTPS 擴(kuò)展。這是因?yàn)閷懭爰用軘?shù)據(jù)庫(kù)需要使用安全的隨機(jī)數(shù)生成器,而安全的隨機(jī)數(shù)生成器需要專用的硬件指令支持。因此,我們禁用了 mbedTLS 寫入加密數(shù)據(jù)庫(kù)文件的功能。

好消息是,使用 OpenSSL 時(shí),讀取加密數(shù)據(jù)幾乎不會(huì)有明顯的性能下降,因?yàn)樗浅?臁?/p>

總結(jié)

本次演講的主要要點(diǎn):

?DuckDB 能夠通過(guò) Parquet 加密數(shù)據(jù)庫(kù)文件加密來(lái)加密靜態(tài)數(shù)據(jù)?加密范圍包括數(shù)據(jù)庫(kù)文件、預(yù)寫日志和臨時(shí)文件?加密密鑰得到安全管理?加密帶來(lái)的性能開銷可以忽略不計(jì)

感謝大家!

問(wèn)答環(huán)節(jié)要點(diǎn)

Q:加密塊是如何被掃描的?元數(shù)據(jù)和統(tǒng)計(jì)信息存儲(chǔ)在哪里?

A:DuckDB 在存儲(chǔ)實(shí)際數(shù)據(jù)之前會(huì)存儲(chǔ)大量元數(shù)據(jù),包括指向特定行組統(tǒng)計(jì)信息的指針等?;谶@些信息,DuckDB 可以跳過(guò)大量數(shù)據(jù),并且知道需要解密哪些塊。元數(shù)據(jù)不在塊本身中,而是單獨(dú)存儲(chǔ)的。

Q:如果只需要檢索塊中的一行數(shù)據(jù),是否需要解密整個(gè)塊?

A:理論上如果使用 CTR 模式可以實(shí)現(xiàn)隨機(jī)訪問(wèn),但 DuckDB 目前的實(shí)現(xiàn)需要解密整個(gè)塊。不過(guò)實(shí)際上,即使你只需要讀取一行數(shù)據(jù),DuckDB 也需要讀取整個(gè)塊。

Q:用于驗(yàn)證密鑰的"ducky"這個(gè)詞很短,是否存在碰撞風(fēng)險(xiǎn)?

A:確實(shí)存在一定風(fēng)險(xiǎn),但我們不想占用太多空間,這是一個(gè)權(quán)衡。未來(lái)可能會(huì)調(diào)整這個(gè)設(shè)計(jì)。

Q:塊頭部中的空白部分是什么用途?

A:有兩個(gè)原因。首先,Nonce 的大小理論上可以改變(雖然我們現(xiàn)在固定為 12 字節(jié))。其次,塊頭部設(shè)為 40 字節(jié)是因?yàn)槲覀冃枰?jì)算整個(gè)塊數(shù)據(jù)的校驗(yàn)和,校驗(yàn)和需要 8 字節(jié)對(duì)齊,所以用 4 字節(jié)的空白來(lái)實(shí)現(xiàn)正確的對(duì)齊。

Q:Nonce 是如何生成的?是隨機(jī)生成一次然后遞增嗎?

A:Nonce 由隨機(jī)數(shù)生成器生成 12 字節(jié)的隨機(jī)數(shù)據(jù)。根據(jù)加密模式不同,加密 API 會(huì)在這 12 字節(jié)末尾添加計(jì)數(shù)器,所以實(shí)際的 Nonce 是 16 字節(jié)。每加密 16 字節(jié)數(shù)據(jù),計(jì)數(shù)器就會(huì)遞增。這由加密 API 內(nèi)部處理。

Q:既然有認(rèn)證標(biāo)簽,校驗(yàn)和還有必要嗎?

A:嚴(yán)格來(lái)說(shuō)不是必需的,不做校驗(yàn)和可以作為一個(gè)優(yōu)化。但我們選擇保留它,寧可安全一些。

Q:數(shù)據(jù)庫(kù)大小會(huì)增加多少?

A:對(duì)于常規(guī)數(shù)據(jù)庫(kù)加密,大小開銷基本可以忽略。WAL 的大小會(huì)增加得更多,因?yàn)槊總€(gè)條目都需要存儲(chǔ) Nonce 和 Tag。如果你進(jìn)行大量快速更新,WAL 可能會(huì)顯著增長(zhǎng),但這種情況比較少見。

Q:密鑰管理有什么最佳實(shí)踐?比如是否可以使用外部密鑰保管庫(kù)?

A:我的建議是:你輸入的密鑰越安全,加密就越安全。我們確實(shí)允許使用很短的用戶密鑰,但顯然這會(huì)影響最終加密的安全性。大多數(shù)用戶會(huì)使用 KMS(密鑰管理服務(wù))來(lái)管理密鑰。

DuckPL:在 DuckDB 中實(shí)現(xiàn) PL/pgSQL 用戶自定義函數(shù) 演講者介紹

大家好,我先簡(jiǎn)單介紹一下自己。我從2020年初就開始成為 DuckDB 的長(zhǎng)期貢獻(xiàn)者,這要感謝 Hannes——因?yàn)樗?dāng)時(shí)不想實(shí)現(xiàn)遞歸 CTE。而我今天要講的用戶自定義函數(shù)項(xiàng)目,恰恰需要用到遞歸 CTE,所以我最終自己動(dòng)手實(shí)現(xiàn)了它。

在 DuckDB 項(xiàng)目中,當(dāng)查詢?nèi)ハ嚓P(guān)化或優(yōu)化器的某些地方出現(xiàn)問(wèn)題時(shí),我通常也會(huì)參與修復(fù)。在日常工作中,我來(lái)自學(xué)術(shù)界,主要研究方向是查詢優(yōu)化、執(zhí)行引擎設(shè)計(jì),以及用戶自定義函數(shù)——更具體地說(shuō),是如何消除它們。今天來(lái)介紹這個(gè)項(xiàng)目確實(shí)有點(diǎn)諷刺。我對(duì)編譯器和編程語(yǔ)言也很感興趣,這一點(diǎn)待會(huì)兒會(huì)變得很重要。

DuckDB 用戶自定義函數(shù)的現(xiàn)狀

目前 DuckDB 支持宏(Macro),這是一種簡(jiǎn)單的文本替換機(jī)制,可以用于簡(jiǎn)單的表達(dá)式。它們確實(shí)很好用,也有很多用戶在使用。但問(wèn)題是,你無(wú)法在其中使用 if 語(yǔ)句——比如當(dāng)條件為真時(shí)執(zhí)行某些操作,條件為假時(shí)執(zhí)行其他操作。你也無(wú)法在里面放入 CREATE TABLE 語(yǔ)句然后返回結(jié)果。

我知道你們中的大多數(shù)人可能會(huì)用 Python 或 R 來(lái)定義 UDF,這當(dāng)然沒問(wèn)題。但我認(rèn)為這在某種程度上打破了 DuckDB"單文件、零依賴"的承諾。這正是我想要解決的問(wèn)題——DuckPL 項(xiàng)目的核心理念就是在 DuckDB 內(nèi)部提供 PL/SQL 接口。

DuckPL 是什么

我想提供的是讓用戶能夠直接在數(shù)據(jù)庫(kù)系統(tǒng)內(nèi)部使用用戶自定義函數(shù)的能力。舉個(gè)簡(jiǎn)單的例子,這個(gè)函數(shù)計(jì)算 Collatz 猜想需要多少步才能達(dá)到終點(diǎn)。有趣的是,我可以使用 while 循環(huán)、if 語(yǔ)句、在代碼中定義變量,當(dāng)然也可以返回值并調(diào)用這個(gè)函數(shù)。

如果你問(wèn)我大學(xué)里的德國(guó)同事,他們會(huì)說(shuō):"你不需要 UDF,用純 SQL 就行。"對(duì)于這個(gè)簡(jiǎn)單的例子來(lái)說(shuō)確實(shí)可以,但當(dāng) UDF 變得復(fù)雜時(shí),純 SQL 方案就不那么容易實(shí)現(xiàn)了。而且如果能在系統(tǒng)內(nèi)部直接執(zhí)行這些函數(shù),就不需要任何外部依賴。

讓我演示一下。我這里運(yùn)行著一個(gè)內(nèi)存數(shù)據(jù)庫(kù),直接把剛才幻燈片上的 Collatz 函數(shù)粘貼進(jìn)去,函數(shù)就注冊(cè)到數(shù)據(jù)庫(kù)系統(tǒng)中了?,F(xiàn)在我們可以直接調(diào)用它——它能工作,計(jì)算出了結(jié)果。就這么簡(jiǎn)單。我可以使用循環(huán)、條件判斷,想做什么都可以,而且一切都在系統(tǒng)內(nèi)部完成。

系統(tǒng)架構(gòu)

要讓這個(gè)演示正常工作,需要幾個(gè)關(guān)鍵組件。

解析器:我們使用 PostgreSQL 方言,因?yàn)?DuckDB 本身就依賴 PostgreSQL 解析器。但 Mark 在2018年左右把 PL/pgSQL 相關(guān)的解析代碼從系統(tǒng)中移除了,所以我們需要兩個(gè)解析器——一個(gè)解析 CREATE FUNCTION 語(yǔ)句,另一個(gè)解析 PL/pgSQL 函數(shù)體。函數(shù)體實(shí)際上就是兩個(gè)美元符號(hào)之間的字符串。目前我們依賴 libpg_query 的解析基礎(chǔ)設(shè)施,但 DuckDB 正在遷移到 PEG 解析器,我們也會(huì)跟進(jìn)。

轉(zhuǎn)換器:我們需要把 PostgreSQL 的抽象語(yǔ)法樹轉(zhuǎn)換成我們自己的內(nèi)部表示。如果你看過(guò) PostgreSQL 的代碼(請(qǐng)不要這樣做),你會(huì)發(fā)現(xiàn)它有五種不同的節(jié)點(diǎn)類型來(lái)表示循環(huán)——整數(shù)循環(huán)和查詢結(jié)果循環(huán)用的是不同的結(jié)構(gòu)。我們不這樣做。我們的內(nèi)部表示是語(yǔ)法無(wú)關(guān)的,因?yàn)槲覀兿M軌蛱鎿Q前端。目前我們追求 PostgreSQL 兼容性,但將來(lái)按照 DuckDB"友好 SQL"的理念,我們會(huì)設(shè)計(jì)自己的語(yǔ)言。

我們的內(nèi)部語(yǔ)言非常精簡(jiǎn)但足夠強(qiáng)大。比如 while 循環(huán),我們不直接表示為 while 循環(huán),而是轉(zhuǎn)換成一個(gè)"永遠(yuǎn)循環(huán)"加上 break 語(yǔ)句——本質(zhì)上就是基于 goto 的程序。這樣做簡(jiǎn)化了很多工作,也方便未來(lái)引入新的前端,比如 PL/Python 或 DuckDB 專用語(yǔ)言。

持久化存儲(chǔ):我們希望 UDF 是持久化的。但目前擴(kuò)展 catalog 的鉤子不多,所以我們借鑒了 DuckLake 處理宏的方式——直接把 UDF 定義存在表里。這樣做很簡(jiǎn)單,還能享受加密等好處。我們不只存儲(chǔ)用戶提供的 PL/SQL 代碼,還會(huì)把函數(shù)體序列化成 DuckDB 格式的 blob 存儲(chǔ),避免每次調(diào)用都重新解析。

執(zhí)行引擎設(shè)計(jì)

執(zhí)行方面有一個(gè)關(guān)鍵點(diǎn)我想詳細(xì)說(shuō)明。目前我們實(shí)現(xiàn)的是簡(jiǎn)單的樹遍歷解釋器,但我們使用了一個(gè)技巧。普通的樹遍歷解釋器會(huì)使用 C++ 調(diào)用棧來(lái)存儲(chǔ)狀態(tài),但這在 DuckDB 中是個(gè)問(wèn)題,因?yàn)槟銦o(wú)法暫停和恢復(fù)執(zhí)行。特別是對(duì)于表值函數(shù),這會(huì)在不使用 DuckDB 執(zhí)行器基礎(chǔ)設(shè)施的情況下填滿內(nèi)存。

所以我們使用顯式棧,在堆上而不是調(diào)用棧上管理。這讓我們可以根據(jù)執(zhí)行情況推入新的棧幀。比如執(zhí)行循環(huán)時(shí),我們把循環(huán)壓棧,然后繼續(xù)執(zhí)行循環(huán)內(nèi)部;檢查條件時(shí)再壓入一個(gè)新幀;根據(jù)條件結(jié)果決定是跳轉(zhuǎn)到 break 還是繼續(xù)執(zhí)行。

這種設(shè)計(jì)讓我們能夠?qū)崿F(xiàn)流式返回。我再演示一個(gè)例子:這個(gè) infinite 函數(shù)返回一個(gè)大整數(shù)集合,內(nèi)部是一個(gè)永不終止的循環(huán),不斷遞增并返回值。如果在 PostgreSQL 上運(yùn)行這個(gè)函數(shù),它會(huì)永遠(yuǎn)執(zhí)行下去,無(wú)法返回任何結(jié)果,也無(wú)法用 LIMIT 中斷。

但在 DuckPL 中,我們模仿 DuckDB 物理算子的行為:填滿一個(gè)數(shù)據(jù)塊后就把控制權(quán)交還給 DuckDB,告訴它"我還有更多輸出"。系統(tǒng)可以決定是否需要更多輸出。這樣我們就能實(shí)現(xiàn)提前終止。

SELECT * FROM infinite() LIMIT 10 * 2048;

這條查詢?cè)?DuckDB 的術(shù)語(yǔ)中就是讀取10個(gè)數(shù)據(jù)塊,執(zhí)行完全正常,而不是無(wú)限循環(huán)。我們還可以組合使用這些函數(shù)——比如把 infinitecollatz 結(jié)合使用。

表達(dá)式求值優(yōu)化

在 PL 解釋系統(tǒng)中,表達(dá)式求值是性能的關(guān)鍵。代碼中那些黑框部分都是 SQL 表達(dá)式——我們添加了 while 循環(huán)等控制流,但表達(dá)式仍然是純 SQL。

如果用慢方法,每個(gè)表達(dá)式都包裝成 SELECT 語(yǔ)句執(zhí)行。想象一下,如果循環(huán)執(zhí)行一千次迭代,那就是一千個(gè)查詢,非常慢。

我們的做法是直接使用表達(dá)式執(zhí)行器。雖然系統(tǒng)并不直接支持這樣做,但我們還是這么做了。簡(jiǎn)單來(lái)說(shuō),我們準(zhǔn)備一個(gè)查詢?nèi)?SELECT x > 1,從語(yǔ)句中提取 x > 1 這個(gè)表達(dá)式,然后直接用表達(dá)式執(zhí)行器對(duì)數(shù)據(jù)塊執(zhí)行,而不是跑完整的查詢執(zhí)行器。

結(jié)果相當(dāng)不錯(cuò)——對(duì)于這類函數(shù),我們快了大約30倍。

當(dāng)前支持的功能

DuckPL 目前還沒有開源,你們還用不了。但我們已經(jīng)支持了相當(dāng)多的功能:

?標(biāo)量函數(shù)和表值函數(shù)?變量和賦值?所有數(shù)據(jù)類型,包括用戶自定義類型?復(fù)合類型,如表類型(比如 TPC-H 的 lineitem)?控制流方面已經(jīng)功能完整:if、所有類型的循環(huán)、break、continue、return 和 return next?支持帶簡(jiǎn)單操作的游標(biāo)(fetch into 變量),但還不支持高級(jí)游標(biāo)操作如滾動(dòng)、跳轉(zhuǎn)?支持 printf 風(fēng)格的調(diào)試(使用 RAISE)

不支持或暫不支持的功能

?動(dòng)態(tài) SQL:DuckDB 已經(jīng)有 query() 函數(shù)可以輸入字符串得到結(jié)果,所以我們不需要重復(fù)實(shí)現(xiàn)?高級(jí)游標(biāo)功能:暫未規(guī)劃,看社區(qū)反饋?觸發(fā)器:因?yàn)?DuckDB 本身不支持觸發(fā)器

未來(lái)規(guī)劃

?支持注冊(cè)為聚合函數(shù)和窗口函數(shù)?異常處理(try-catch 語(yǔ)義)?事務(wù)支持(目前會(huì)產(chǎn)生嵌套連接問(wèn)題)?UDF 優(yōu)化器?編譯到純 SQL:很多 UDF 其實(shí)可以用 WITH RECURSIVE 等純 SQL 表達(dá),這樣就能充分利用 DuckDB 執(zhí)行引擎的性能

未來(lái)愿景

PostgreSQL 只允許你定義函數(shù)并在查詢中調(diào)用。我認(rèn)為在 DuckDB CLI 中提供類似 REPL 的體驗(yàn)會(huì)是很好的補(bǔ)充。比如用 LET 語(yǔ)句定義變量,直接在 CLI 中寫循環(huán)、打印輸出,用 DuckDB CLI 替代 Python CLI。

我們還會(huì)遷移到 PEG 解析器基礎(chǔ)設(shè)施,利用我們?cè)?UDF 編譯方面的研究成果,逐步把這個(gè)想法產(chǎn)品化。

總結(jié)

我們的路線圖是:

1.PostgreSQL 兼容性優(yōu)先:大量現(xiàn)有代碼庫(kù)可以幾乎無(wú)縫從 PostgreSQL 遷移到 DuckDB,沒有學(xué)習(xí)曲線,而且 LLM 也能生成這些代碼2.智能執(zhí)行:在兼容性基礎(chǔ)上追求速度3.混合執(zhí)行和 CLI 功能:最終目標(biāo)

問(wèn)答環(huán)節(jié)

問(wèn):執(zhí)行引擎是否應(yīng)用了向量化?

目前還沒有,現(xiàn)在是逐行執(zhí)行。我們當(dāng)然想改進(jìn),但這還是第一個(gè)版本,連 alpha 都算不上。

問(wèn):能否從內(nèi)部表示反編譯回源代碼?

我們不需要,因?yàn)槲覀兇鎯?chǔ)了用戶的原始輸入。

問(wèn):有沒有考慮用 V8 或 JIT 編譯來(lái)解決解釋器的性能瓶頸?

我對(duì)這個(gè)做過(guò)大量研究。瓶頸不在于解釋本身,而在于命令式執(zhí)行和聲明式 SQL 執(zhí)行之間的阻抗不匹配。這個(gè)問(wèn)題用 JIT 解決不了。

Gizmo Edge:基于 DuckDB 的分布式物聯(lián)網(wǎng)邊緣分析引擎 演講者介紹

大家好,我是來(lái)自 Gizmo Data 的 Philip Moore。今天我要介紹的是 Gizmo Edge,這是一個(gè)為物聯(lián)網(wǎng)設(shè)計(jì)的預(yù)覽版分布式引擎,用于在邊緣執(zhí)行分析任務(wù)。它基于 DuckDB 構(gòu)建,我非常高興能來(lái)到這里與大家交流。

簡(jiǎn)單介紹一下我自己:我是一個(gè)數(shù)據(jù)狂熱者和構(gòu)建者,從事數(shù)據(jù)相關(guān)工作已經(jīng)超過(guò)25年。職業(yè)生涯的大部分時(shí)間我都在使用 Oracle,后來(lái)轉(zhuǎn)向開源技術(shù),并立刻愛上了 DuckDB——它是一個(gè)出色的嵌入式引擎,速度極快,具備我們都喜愛的所有優(yōu)點(diǎn)。

我曾是美國(guó)海軍陸戰(zhàn)隊(duì)員,那是很多年、很多磅、很多頭發(fā)以前的事了。我對(duì) DuckDB 有過(guò)一些小貢獻(xiàn),比如構(gòu)建了 struct_insert 函數(shù)讓你可以修改結(jié)構(gòu)體,引入了 hugeintbit_count 等功能。我還曾經(jīng)請(qǐng)求過(guò)加密功能,看到它最終實(shí)現(xiàn)真的很棒。

為什么要?jiǎng)?chuàng)建 Gizmo Edge

我創(chuàng)建 Gizmo Edge 是因?yàn)橄胍粋€(gè)能夠在邊緣執(zhí)行分析的引擎。DuckDB 和 SQLite 的嵌入式特性首次使這成為可能。實(shí)際上我最初是用 SQLite 開始構(gòu)建的,待會(huì)兒會(huì)解釋為什么轉(zhuǎn)向了 DuckDB。

物聯(lián)網(wǎng)領(lǐng)域面臨幾個(gè)核心挑戰(zhàn):

數(shù)據(jù)量持續(xù)增長(zhǎng):物聯(lián)網(wǎng)傳感器、移動(dòng)設(shè)備、邊緣節(jié)點(diǎn)產(chǎn)生的數(shù)據(jù)量巨大,增長(zhǎng)速度遠(yuǎn)超集中化處理的能力。

數(shù)據(jù)傳輸成本高昂:從云端下載數(shù)據(jù)到設(shè)備的出口流量費(fèi)用非常昂貴。

延遲問(wèn)題嚴(yán)重:通常需要等待數(shù)據(jù)被攝入云存儲(chǔ),可能需要數(shù)小時(shí)甚至數(shù)天才能讀取和聚合數(shù)據(jù)。

Gizmo Edge 是一個(gè)分布式引擎,讓你可以在邊緣設(shè)備上使用 DuckDB,實(shí)現(xiàn)分治策略處理分析工作負(fù)載,或者從邊緣設(shè)備拉取數(shù)據(jù)進(jìn)行聚合。

創(chuàng)建的初衷

讓我創(chuàng)建這個(gè)項(xiàng)目的直接原因是:我當(dāng)時(shí)在 Kroger 工作,我們有數(shù)十億行交易數(shù)據(jù),花費(fèi)數(shù)百萬(wàn)美元在 Oracle Exadata 這樣的技術(shù)上來(lái)處理。即使這樣,運(yùn)行一個(gè)查詢?nèi)匀恍枰却宸昼?。這讓我非常沮喪——為什么我們不能把數(shù)據(jù)分發(fā)到一千個(gè)工作節(jié)點(diǎn)上,讓每個(gè)節(jié)點(diǎn)獨(dú)立處理各自的數(shù)據(jù)塊呢?

我到處尋找能做到這一點(diǎn)的技術(shù),包括 Spark,但都不太理想。所以我決定自己創(chuàng)建,而 DuckDB 讓這成為可能。

我對(duì)異構(gòu)工作節(jié)點(diǎn)特別著迷。想想典型的 Spark 集群、Databricks 集群或 Snowflake,所有工作節(jié)點(diǎn)都是統(tǒng)一的——相同的機(jī)器、相同的存儲(chǔ)特性、相同的 CPU、相同的內(nèi)存。我想要的是一個(gè)由各種不同設(shè)備組成的工作節(jié)點(diǎn)集群。

當(dāng)然,核心是 DuckDB 驅(qū)動(dòng)。另外,Apache Arrow 對(duì)我來(lái)說(shuō)也非常重要——我之前在 Voltron Data 工作時(shí)引入了 Apache Arrow,它真正革新了數(shù)據(jù)傳輸方式。Arrow 可以發(fā)送高度壓縮的列式數(shù)據(jù),傳輸效率高,而且是零拷貝的,不需要反復(fù)序列化和反序列化。這讓數(shù)據(jù)從邊緣設(shè)備傳輸?shù)絽f(xié)調(diào)器變得更加流暢。

架構(gòu)概述

Gizmo Edge 的架構(gòu)是這樣的:中間有一個(gè)集中式協(xié)調(diào)器,終端用戶向協(xié)調(diào)器發(fā)送 SQL 查詢,協(xié)調(diào)器將工作分發(fā)到各個(gè)工作節(jié)點(diǎn)。這些工作節(jié)點(diǎn)可以是異構(gòu)的——可以是 iPhone(聽起來(lái)很瘋狂)、筆記本電腦、MacBook、臺(tái)式機(jī)、Kubernetes 節(jié)點(diǎn)、Linux 服務(wù)器,甚至是物聯(lián)網(wǎng)設(shè)備。由于 DuckDB 的嵌入式特性,它幾乎可以在任何設(shè)備上運(yùn)行。

服務(wù)器/協(xié)調(diào)器的職責(zé)是:解析 SQL,檢測(cè)聚合函數(shù),決定是分發(fā)查詢還是在服務(wù)器端本地運(yùn)行(比如簡(jiǎn)單的 SELECT *)。它將工作分發(fā)給工作節(jié)點(diǎn),并聚合最終結(jié)果。

工作節(jié)點(diǎn)的職責(zé)是:下載各自的數(shù)據(jù)分片,使用 DuckDB 本地執(zhí)行查詢,通過(guò) WebSocket 以 Arrow IPC 格式返回結(jié)果。它們可以運(yùn)行在 Kubernetes、Linux、macOS、iOS、Windows 等任何平臺(tái)上。

客戶端是一個(gè)交互式 SQL REPL,帶有基于 Web 的 SQL 導(dǎo)航器。你可以開啟或關(guān)閉分布式模式,并接收服務(wù)器返回的結(jié)果。

整個(gè)數(shù)據(jù)傳輸都使用 Arrow 格式。

查詢執(zhí)行流程

當(dāng)你發(fā)出查詢時(shí),流程是這樣的:

1.工作節(jié)點(diǎn)首先向服務(wù)器認(rèn)證,請(qǐng)求獲取數(shù)據(jù)分片2.服務(wù)器驗(yàn)證后發(fā)送數(shù)據(jù)分片,保留 MD5 哈希,同時(shí)分享 SHA-256 哈希給工作節(jié)點(diǎn)3.工作節(jié)點(diǎn)解壓數(shù)據(jù),驗(yàn)證 SHA 哈希匹配,然后計(jì)算 MD5 哈希發(fā)回服務(wù)器4.服務(wù)器確認(rèn)工作節(jié)點(diǎn)確實(shí)處理了數(shù)據(jù),建立信任5.查詢到來(lái)時(shí),服務(wù)器解析并決定是否分發(fā)6.工作節(jié)點(diǎn)執(zhí)行查詢,以 Arrow 格式返回結(jié)果7.服務(wù)器聚合結(jié)果并發(fā)送給客戶端

如果需要額外安全性,還可以啟用 mTLS。

DuckDB 的使用方式

每個(gè)工作節(jié)點(diǎn)都運(yùn)行 DuckDB。它們接收一個(gè) Zstandard 壓縮的數(shù)據(jù)分片,解壓后從 Parquet 文件創(chuàng)建 DuckDB 數(shù)據(jù)庫(kù)。執(zhí)行完成后,通過(guò) Arrow 格式將結(jié)果發(fā)回服務(wù)器。

服務(wù)器端使用 PyArrow 進(jìn)行零拷貝的表連接,然后執(zhí)行匯總查詢,按分組鍵進(jìn)一步聚合所有工作節(jié)點(diǎn)的結(jié)果。

查詢轉(zhuǎn)換

用戶發(fā)出的查詢不一定是直接分發(fā)給工作節(jié)點(diǎn)的查詢。比如平均值(AVG)——你不能對(duì)平均值再求平均值,那樣會(huì)得到錯(cuò)誤結(jié)果。

假設(shè)用戶查詢:

SELECT AVG(quantity), AVG(extended_price) FROM ...

實(shí)際分發(fā)給工作節(jié)點(diǎn)的是:

SELECT SUM(quantity), COUNT(quantity), SUM(extended_price), COUNT(extended_price) FROM ...

收回結(jié)果后,服務(wù)器計(jì)算 SUM(sum) / SUM(count) 得到正確的平均值。

服務(wù)器必須解析查詢,理解聚合函數(shù)和分組鍵,然后進(jìn)行相應(yīng)轉(zhuǎn)換。

分片管理

目前 Gizmo Edge 還是原型階段,分片是預(yù)先構(gòu)建的。理想情況下,工作節(jié)點(diǎn)應(yīng)該能夠動(dòng)態(tài)查詢?cè)拼鎯?chǔ)中的 Parquet 文件塊。在演示中,我使用的是 TPC-H 100GB 數(shù)據(jù)集(相比 10TB 來(lái)說(shuō)很?。?。

分片存儲(chǔ)在云存儲(chǔ)中,服務(wù)器維護(hù)一個(gè)分片清單。當(dāng)工作節(jié)點(diǎn)簽入時(shí),服務(wù)器根據(jù)分發(fā)情況決定分配哪個(gè)分片。

定向廣播(Targeted Broadcast)

對(duì)于分析用例,我開發(fā)了一種叫"定向廣播"的技術(shù)。它特別適合星型模式——有一個(gè)中心事實(shí)表和周圍的維度表。

工作原理是:

1.首先獲取事實(shí)表的一個(gè)哈希分區(qū)塊2.然后過(guò)濾維度表,只保留支持該分片中事實(shí)數(shù)據(jù)所需的記錄

這樣每個(gè)工作節(jié)點(diǎn)就擁有一個(gè)微型星型模式、微型數(shù)據(jù)倉(cāng)庫(kù)。這帶來(lái)很多好處:

?內(nèi)連接是無(wú)損的?連接操作完全卸載到工作節(jié)點(diǎn)?服務(wù)器不需要做任何連接?工作節(jié)點(diǎn)之間不需要相互通信?工作節(jié)點(diǎn)可以獨(dú)立完成連接、過(guò)濾、聚合、分組和排序

未來(lái)我們計(jì)劃使用 DuckDB 的布隆過(guò)濾器功能,雖然可能有一些誤報(bào),但會(huì)在連接時(shí)被丟棄,這將大大加速分片生成過(guò)程。

技術(shù)棧

預(yù)覽版是用 Python 寫的(我知道這總是引來(lái)笑聲),如果是生產(chǎn)版本可能會(huì)用 C++ 或 Rust。我們使用 DuckDB 最新版本,用 PostgreSQL 解析器提取 SQL 標(biāo)記來(lái)確定分組鍵、聚合函數(shù)、排序和限制等。數(shù)據(jù)序列化使用 Apache Arrow IPC,網(wǎng)絡(luò)通信使用 WebSocket 實(shí)現(xiàn)低延遲連接。

部署方式

可以在本地筆記本上運(yùn)行,可以部署到 Kubernetes,也可以在各種邊緣設(shè)備上運(yùn)行。我的演示使用 Azure Kubernetes Service 集群。

為什么 DuckDB 是完美選擇

?嵌入式零依賴:不需要安裝一堆庫(kù),易于部署到邊緣設(shè)備?我的轉(zhuǎn)型故事:最初用 SQLite 構(gòu)建時(shí),我和 SQLite 的創(chuàng)始人 Richard Hipp 交流,他告訴我 DuckDB——一個(gè)像 SQLite 一樣自包含但專為 OLAP 優(yōu)化、速度極快的分析引擎。然后我聯(lián)系了 Hannes,很早就開始使用 DuckDB?跨平臺(tái)運(yùn)行:我們用 DuckDB 的 TPC-H 生成器構(gòu)建分片?全面使用 Arrow:數(shù)據(jù)傳輸統(tǒng)一使用 Arrow 格式?豐富的 SQL 支持:不過(guò)由于分布式和無(wú)共享架構(gòu)的特性,窗口函數(shù)等功能還不支持

現(xiàn)場(chǎng)演示

讓我打開瀏覽器連接到 Gizmo Edge。這是一個(gè) SQL IDE 界面,有一個(gè)小型模式瀏覽器,可以看到 TPC-H 模式。

運(yùn)行一個(gè)查詢——你可以看到它分發(fā)到了 98 個(gè)運(yùn)行在 Azure Kubernetes 上的 Linux 工作節(jié)點(diǎn),還有一個(gè) macOS 工作節(jié)點(diǎn)。那個(gè) macOS 工作節(jié)點(diǎn)在哪里?就是這臺(tái) MacBook。

清除日志,再次執(zhí)行。你可以看到工作節(jié)點(diǎn)上有活動(dòng)——它收到了查詢。用戶請(qǐng)求的是平均值,實(shí)際發(fā)送給工作節(jié)點(diǎn)的是求和和計(jì)數(shù)。工作節(jié)點(diǎn)執(zhí)行查詢(在 iOS 和 macOS 上會(huì)導(dǎo)出為 Parquet),耗時(shí)不到 0.05 秒,因?yàn)樗挥写蠹s 1GB 的數(shù)據(jù)。然后通過(guò) WebSocket 發(fā)送 Base64 編碼的 Parquet 數(shù)據(jù)。服務(wù)器還會(huì)給反饋:"你是最快的"或者"你不是最快的工作節(jié)點(diǎn),換份工作吧"。

現(xiàn)在來(lái)點(diǎn)更刺激的——我要拿出我的 iPhone。

(連接 iPhone 到 Gizmo Edge 服務(wù)器)

再運(yùn)行一個(gè)查詢——成功了!iOS 工作節(jié)點(diǎn)、macOS 工作節(jié)點(diǎn),加上 98 個(gè) Linux 工作節(jié)點(diǎn),總共 100 個(gè)工作節(jié)點(diǎn)。它們各自處理自己的數(shù)據(jù)塊,以 Arrow 或 Parquet 格式返回結(jié)果,服務(wù)器進(jìn)行最終聚合。

有些查詢不適合分發(fā),比如沒有聚合的 SELECT——你不想讓一堆工作節(jié)點(diǎn)往服務(wù)器發(fā)送數(shù)百萬(wàn)行數(shù)據(jù)。解析器會(huì)檢測(cè)這種情況,讓服務(wù)器本地執(zhí)行。

有趣的是,iPhone 居然比我的 MacBook 還快,它們處理的數(shù)據(jù)量相同。我喜歡看它們競(jìng)速。

萬(wàn)億行挑戰(zhàn)

現(xiàn)在切換到深色模式,來(lái)點(diǎn)真正刺激的。

這個(gè)數(shù)據(jù)集有一個(gè)叫 measurements 的表。讓我先看看:

SELECT * FROM measurements;

這不會(huì)分發(fā),因?yàn)槭?SELECT *。表結(jié)構(gòu)很簡(jiǎn)單,只有 station 和 measure 兩列。讓我們看看有多少行:

SELECT COUNT(*) FROM measurements;

一萬(wàn)億行記錄!

有人做過(guò)萬(wàn)億行聚合嗎?數(shù)據(jù)量非常大。我參加了 Coiled 公司的萬(wàn)億行挑戰(zhàn),想看看 Gizmo Edge 能否完成。

查詢很簡(jiǎn)單:

ORDER BY station;

沒有 WHERE 子句,必須掃描所有數(shù)據(jù),不能作弊。

讓我們運(yùn)行它——我們把查詢分發(fā)到了 一千個(gè)工作節(jié)點(diǎn)。它們正在處理... 完成了!

一萬(wàn)億行記錄,幾秒鐘完成!

(掌聲)

每個(gè)工作節(jié)點(diǎn)大約有 10 億行數(shù)據(jù)。我們還可以加一些計(jì)算:

GROUP BY station;

可以看到有 412 行結(jié)果,每行代表約 250 億條記錄被聚合成一個(gè)值。

當(dāng)然也可以加過(guò)濾條件:

SELECT ... WHERE station = 'ABHA'

瞬間完成!DuckDB 不需要索引。工作節(jié)點(diǎn)找到目標(biāo)行后,返回更小的結(jié)果集給服務(wù)器。

未來(lái)計(jì)劃

這仍是原型階段,用 Python 寫的,但已經(jīng)非??炝恕H绻?Rust 或 C++ 重寫會(huì)更好。我們的計(jì)劃包括:

?更智能的查詢規(guī)劃?動(dòng)態(tài)工作節(jié)點(diǎn)發(fā)現(xiàn)和自動(dòng)注冊(cè)?自動(dòng)擴(kuò)縮容?利用 DuckDB 擴(kuò)展生態(tài)系統(tǒng)?生產(chǎn)級(jí)加固和安全最佳實(shí)踐

問(wèn)答環(huán)節(jié)

問(wèn):分片具體如何工作?如果我有 S3 上的數(shù)據(jù)集,如何分發(fā)到工作節(jié)點(diǎn)?

目前是手動(dòng)過(guò)程。你需要知道整體數(shù)據(jù)集大小和想要多少分片。比如我有一千個(gè)工作節(jié)點(diǎn),一萬(wàn)億行,就除以一千,每個(gè)分片大約 10 億行、2GB 左右。理想情況下應(yīng)該能動(dòng)態(tài)分片——如果啟動(dòng)一千個(gè)工作節(jié)點(diǎn),它們應(yīng)該知道各自獲取千分之一的數(shù)據(jù)。更進(jìn)一步,應(yīng)該考慮設(shè)備能力:iPhone 可能只能處理 1GB,而 64 核的 Kubernetes 節(jié)點(diǎn)可以處理幾十億行。

問(wèn):非可加性聚合函數(shù)如何處理?比如 COUNT DISTINCT?還有連接策略?

COUNT DISTINCT 是個(gè)很好的問(wèn)題,在零售領(lǐng)域尤其常見——你想知道有多少獨(dú)立顧客購(gòu)買了某類產(chǎn)品。

有幾種方法:

1.近似方法:使用 HyperLogLog 草圖。Rusty 構(gòu)建了一個(gè)草圖擴(kuò)展,可以在工作節(jié)點(diǎn)構(gòu)建草圖,發(fā)送到服務(wù)器聚合,得到約 99% 準(zhǔn)確的 NDV 值2.精確方法:如果基數(shù)較低(百萬(wàn)級(jí)以下),可以使用位圖,每個(gè)不同值對(duì)應(yīng)一個(gè)位位置,然后位或聚合所有位圖,得到 100% 準(zhǔn)確的結(jié)果

中位數(shù)可能比較棘手,但也有近似計(jì)算方法。這些功能還沒有全部實(shí)現(xiàn),但 DuckDB 生態(tài)系統(tǒng)有很多工具可用。

關(guān)于連接:內(nèi)連接工作得很好。DuckDB 自己決定使用哈希連接還是嵌套循環(huán)連接。但左外連接目前不支持,因?yàn)楣ぷ鞴?jié)點(diǎn)只有支持其事實(shí)數(shù)據(jù)的定向維度集,處理外連接需要更高級(jí)的架構(gòu)。

如果想了解更多,請(qǐng)?jiān)L問(wèn) gizmodata.com 查看 Gizmo Edge。代碼倉(cāng)庫(kù)目前還不公開,但可能有一天會(huì)開源。另外也請(qǐng)關(guān)注 Gizmo SQL,這是一個(gè)用 C++ 寫的項(xiàng)目,讓你可以在本地或云端把 DuckDB 作為服務(wù)器運(yùn)行。

謝謝大家!

老馮點(diǎn)評(píng)

熟悉老馮的人都知道,老馮最愛的數(shù)據(jù)庫(kù)是 PostgreSQL,而要說(shuō)第二喜歡的數(shù)據(jù)庫(kù),當(dāng)屬 DuckDB。

我之前寫過(guò)幾篇文章,提出過(guò)一個(gè)觀點(diǎn): 世界。原因很簡(jiǎn)單:DuckDB 正在變成“分析能力的通用部件”——它不是要替代一切,而是特別適合被集成、被嵌入、被當(dāng)作加速器或計(jì)算單元。

DuckDB 和 PostgreSQL 的相似度也確實(shí)高得離譜,至少體現(xiàn)在兩點(diǎn)上:

第一,它的可擴(kuò)展性在主流數(shù)據(jù)庫(kù)里幾乎僅次于 PG:擴(kuò)展機(jī)制成熟,生態(tài)繁榮,而且正在從“不穩(wěn)定 C++ API”向“穩(wěn)定 C API”過(guò)渡,這一步如果走順,會(huì)顯著降低生態(tài)維護(hù)成本,進(jìn)一步加速擴(kuò)展爆發(fā)。

第二,它高度以 PG 語(yǔ)法為基礎(chǔ)做增量改進(jìn):你能感受到 DuckDB 的設(shè)計(jì)哲學(xué)不是“推倒重來(lái)”,而是“站在 PG 語(yǔ)法與用戶習(xí)慣上,把分析體驗(yàn)推到極致”。這次 DuckPL 直接以 PL/pgSQL 為藍(lán)本,更是把“PG 兼容”從 SQL 表層推進(jìn)到“數(shù)據(jù)庫(kù)內(nèi)編程模型”這一層。說(shuō)得直白點(diǎn):DuckDB 不是在蹭 PG,它是在主動(dòng)把自己納入廣義 PG 生態(tài),換取開發(fā)者心智與遷移成本優(yōu)勢(shì)。

也正因此,PG 世界對(duì) DuckDB 的接納度非常高,甚至可以說(shuō)幾年前就開始了“”:把 DuckDB 作為 OLAP 引擎/加速器,嵌進(jìn) Postgres 發(fā)行版、托管服務(wù)、數(shù)倉(cāng)產(chǎn)品、混合架構(gòu)里。現(xiàn)在你能看到的典型選手游:


這場(chǎng)比賽的看點(diǎn)從來(lái)不只是“誰(shuí)把擴(kuò)展裝上了”,而是誰(shuí)能把工程邊界、查詢語(yǔ)義、數(shù)據(jù)同步、權(quán)限/安全、運(yùn)維體驗(yàn)做成一套可長(zhǎng)期使用的產(chǎn)品級(jí)方案??p合不難,縫合得優(yōu)雅才難。

作為對(duì)照,最近也能看到另一條有意思的路線:把 DuckDB 縫進(jìn) MySQL 體系(阿里云的 ALISQL)。這件事從工程角度當(dāng)然值得尊重:能在既有體系里引入更強(qiáng)的分析能力,說(shuō)明團(tuán)隊(duì)有沉淀,也愿意啃硬骨頭。


老實(shí)說(shuō),我覺得挺有意思的,阿里對(duì)于 MySQL 的執(zhí)念似乎非常深。要給 MySQL 的兄弟謀出路,繼續(xù)給 MYSQL 續(xù)命,這種想法老馮也可以理解,但很明顯:就算你給 DuckDB 打錢贊助,人家也不會(huì)在原則問(wèn)題上妥協(xié) —— 他們做了 MySQL 語(yǔ)法的兼容修改,想要提交給 DuckDB 上游,被拒絕了。

因?yàn)檫@里的基本現(xiàn)實(shí)就是 了。這一點(diǎn)從資本市場(chǎng),以及所有云廠商的技術(shù)布局都可以明顯看出來(lái)。強(qiáng)行為一個(gè)即將死亡的技術(shù)續(xù)命,雖然有一種悲壯的美感,但并沒有什么用。老馮覺得阿里云數(shù)據(jù)庫(kù)技術(shù)團(tuán)隊(duì)在做 MySQL 上還是有沉淀的,也是有情懷的技術(shù)人。所以老馮不會(huì)嘲笑、揶揄他們 —— 這只是技術(shù)方向上的問(wèn)題,我還是希望他們能走出一條自己的道路。

再把鏡頭拉遠(yuǎn)一點(diǎn):,其實(shí)已經(jīng)開局了。Agent 會(huì)把“數(shù)據(jù)讀寫、語(yǔ)義理解、工具調(diào)用、反饋迭代”壓成一個(gè)閉環(huán),而數(shù)據(jù)庫(kù)就是這個(gè)閉環(huán)里最硬的地基之一:性能、可靠性、權(quán)限、安全、可觀測(cè)、可擴(kuò)展,一個(gè)都繞不過(guò)去。在這場(chǎng)比賽里,我認(rèn)為 :生態(tài)、可擴(kuò)展性、工程成熟度、以及越來(lái)越強(qiáng)的“作為平臺(tái)”的屬性,都是它的不可動(dòng)搖的護(hù)城河。

但如果你問(wèn)我:有沒有誰(shuí)有那么一絲機(jī)會(huì)從 PG 的碗里搶飯?我會(huì)點(diǎn)名兩個(gè)嵌入式數(shù)據(jù)庫(kù):SQLite 和 DuckDB。

它們占據(jù)了一個(gè)非常微妙的生態(tài)位:離應(yīng)用更近、分發(fā)更輕、嵌入更自然,特別適合成為 Agent 世界里的“本地事實(shí)庫(kù)/本地分析引擎/邊緣計(jì)算單元”。這類位置一旦卡住,影響力往往不是靠“替代 PG”獲得的,而是靠“繞開傳統(tǒng)數(shù)據(jù)庫(kù)交付路徑”獲得的——這才是它們真正危險(xiǎn)(也真正迷人)的地方。我認(rèn)為,他們也會(huì)在自己的細(xì)分領(lǐng)域里大放光彩。

特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺(tái)“網(wǎng)易號(hào)”用戶上傳并發(fā)布,本平臺(tái)僅提供信息存儲(chǔ)服務(wù)。

Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.

相關(guān)推薦
熱點(diǎn)推薦
寧波銀行發(fā)布貴金屬業(yè)務(wù)市場(chǎng)風(fēng)險(xiǎn)提示

寧波銀行發(fā)布貴金屬業(yè)務(wù)市場(chǎng)風(fēng)險(xiǎn)提示

財(cái)經(jīng)網(wǎng)
2026-03-26 18:32:12
中美衛(wèi)星導(dǎo)航用戶數(shù)量懸殊:GPS用戶數(shù)超60億,中國(guó)北斗令人意外

中美衛(wèi)星導(dǎo)航用戶數(shù)量懸殊:GPS用戶數(shù)超60億,中國(guó)北斗令人意外

混沌錄
2026-03-18 23:54:31
告別聲剛落,大陸強(qiáng)音起蔡正元今日入獄,國(guó)臺(tái)辦這句狠話破防綠營(yíng)

告別聲剛落,大陸強(qiáng)音起蔡正元今日入獄,國(guó)臺(tái)辦這句狠話破防綠營(yíng)

阿離家居
2026-03-27 04:34:34
日媒在報(bào)道張雪峰的時(shí)候,用了一個(gè)詞,我覺得太恰當(dāng)了

日媒在報(bào)道張雪峰的時(shí)候,用了一個(gè)詞,我覺得太恰當(dāng)了

輝哥說(shuō)動(dòng)漫
2026-03-27 07:12:50
廣東男子掃墓時(shí)發(fā)現(xiàn)“黑色巨物”在動(dòng)!湊近一看,瞬間頭皮發(fā)麻……

廣東男子掃墓時(shí)發(fā)現(xiàn)“黑色巨物”在動(dòng)!湊近一看,瞬間頭皮發(fā)麻……

珠海消防
2026-03-25 20:08:08
46 歲張柏芝三亞生圖流出,肚子上的軟肉,打了整個(gè)內(nèi)娛的臉

46 歲張柏芝三亞生圖流出,肚子上的軟肉,打了整個(gè)內(nèi)娛的臉

橙星文娛
2026-03-26 13:40:27
為嫁給美國(guó)人,56歲南京大媽奔赴美國(guó),2年后嫁給70歲美國(guó)老頭

為嫁給美國(guó)人,56歲南京大媽奔赴美國(guó),2年后嫁給70歲美國(guó)老頭

情感藝術(shù)家
2026-03-08 22:07:38
拒絕回歸WCBA!李月汝再赴美國(guó),官宣重磅決定,韓旭也要這么干了

拒絕回歸WCBA!李月汝再赴美國(guó),官宣重磅決定,韓旭也要這么干了

萌蘭聊個(gè)球
2026-03-26 13:09:33
中國(guó)的隱忍,正在延緩第三次世界大戰(zhàn)!

中國(guó)的隱忍,正在延緩第三次世界大戰(zhàn)!

南權(quán)先生
2026-03-23 15:11:48
徐昕拼下兩雙卻輸球,是廣州最大悲哀?劉維偉賽后發(fā)言更扎心

徐昕拼下兩雙卻輸球,是廣州最大悲哀?劉維偉賽后發(fā)言更扎心

林子說(shuō)事
2026-03-27 00:33:44
廈門一女子長(zhǎng)期遭家暴離家不敢歸,丈夫向法院申請(qǐng)宣告其死亡,十多年后決心離婚才知道自己“死了”!

廈門一女子長(zhǎng)期遭家暴離家不敢歸,丈夫向法院申請(qǐng)宣告其死亡,十多年后決心離婚才知道自己“死了”!

環(huán)球網(wǎng)資訊
2026-03-26 14:44:08
少一人也能贏!姆巴佩滿血?dú)w來(lái)先拔頭籌,法國(guó)2-1力克巴西

少一人也能贏!姆巴佩滿血?dú)w來(lái)先拔頭籌,法國(guó)2-1力克巴西

仰臥撐FTUer
2026-03-27 07:58:03
你們都是什么時(shí)候?qū)δ信麻_竅的?網(wǎng)友:果然還是攔不住有心人

你們都是什么時(shí)候?qū)δ信麻_竅的?網(wǎng)友:果然還是攔不住有心人

夜深愛雜談
2026-02-21 21:37:02
你見過(guò)天才嗎?網(wǎng)友:有些領(lǐng)域,努力在天賦面前,一文不值

你見過(guò)天才嗎?網(wǎng)友:有些領(lǐng)域,努力在天賦面前,一文不值

帶你感受人間冷暖
2026-03-20 00:47:24
蘇州市人民商場(chǎng)龍鳳珠寶品牌店涉嫌銷售“假大牌” 品牌總部回應(yīng)

蘇州市人民商場(chǎng)龍鳳珠寶品牌店涉嫌銷售“假大牌” 品牌總部回應(yīng)

生活視覺攝影
2026-03-26 13:33:29
新華社消息|伊朗官員:美以襲擊已造成伊朗至少1750人死亡

新華社消息|伊朗官員:美以襲擊已造成伊朗至少1750人死亡

新華社
2026-03-26 10:06:18
唯一不含草酸的蔬菜!比薺菜、韭菜還鮮嫩,鮮嫩營(yíng)養(yǎng)正當(dāng)時(shí),好吃

唯一不含草酸的蔬菜!比薺菜、韭菜還鮮嫩,鮮嫩營(yíng)養(yǎng)正當(dāng)時(shí),好吃

阿龍美食記
2026-03-24 09:50:48
中國(guó)肺癌發(fā)病率世界第一!提醒:罪魁禍?zhǔn)滓丫境觯?種食物要少吃

中國(guó)肺癌發(fā)病率世界第一!提醒:罪魁禍?zhǔn)滓丫境觯?種食物要少吃

健康之光
2026-03-23 20:10:05
美空軍雜志:美軍戰(zhàn)損2架F-35、9架F-15、6架F-16、7架加油機(jī)!

美空軍雜志:美軍戰(zhàn)損2架F-35、9架F-15、6架F-16、7架加油機(jī)!

勝研集
2026-03-25 00:02:51
國(guó)產(chǎn)筆記本CPU偷梁換柱翻車!官方終于回應(yīng):生產(chǎn)失誤、全額退款

國(guó)產(chǎn)筆記本CPU偷梁換柱翻車!官方終于回應(yīng):生產(chǎn)失誤、全額退款

快科技
2026-03-25 10:14:04
2026-03-27 08:55:00
老馮云數(shù) incentive-icons
老馮云數(shù)
數(shù)據(jù)庫(kù)老司機(jī),云計(jì)算泥石流,PostgreSQL大法師
140文章數(shù) 55關(guān)注度
往期回顧 全部

科技要聞

OpenAI果斷砍掉"成人模式",死磕生產(chǎn)力

頭條要聞

牛彈琴:一直贏的特朗普心里更慌了 又給自己續(xù)了10天

頭條要聞

牛彈琴:一直贏的特朗普心里更慌了 又給自己續(xù)了10天

體育要聞

申京努力了,然而杜蘭特啊

娛樂要聞

劉曉慶妹妹發(fā)聲!稱姐姐受身邊人挑撥

財(cái)經(jīng)要聞

很反常!油價(jià)向上,黃金向下

汽車要聞

一汽奧迪A6L e-tron開啟預(yù)售 CLTC最大續(xù)航815km

態(tài)度原創(chuàng)

親子
房產(chǎn)
健康
教育
軍事航空

親子要聞

在那聲嘆息里,產(chǎn)后媽媽終于找回了弄丟的自己

房產(chǎn)要聞

突發(fā),三亞又有大批征遷補(bǔ)償方案出爐!

轉(zhuǎn)頭就暈的耳石癥,能開車上班嗎?

教育要聞

老師最大的管理能力,是處理情緒的能力!

軍事要聞

擔(dān)心特朗普突然停戰(zhàn) 以總理下令48小時(shí)盡力摧毀伊設(shè)施

無(wú)障礙瀏覽 進(jìn)入關(guān)懷版