Go 如何編寫簡單的內存鍵值數據庫
從 Postgres 到 Redis,再到 Prometheus,我們都使用並從事過各種數據庫的開發。我花了很多時間來閱讀其中一些數據庫的源代碼,對於那些像我一樣好奇的少數人來說,他們有興趣學習如何編寫一個數據庫。本書旨在記錄這一過程。
GitHub-arriqaaq/flashdb:
FlashDB is an embeddable, in-memory key/value database in Go (with Redis like commands)
01
內存數據庫
傳統數據庫的數據主要保存在機械硬盤或者固態硬盤, 內存數據庫則主要將數據保存在內存中,並通過消除對磁盤的訪問來實現最小的響應時間。兩者的不同主要體現在內存數據庫是將數據保存在主存或者 RAM 中,而傳統的數據庫則是通過驅動磁盤來獲取數據。
內存數據庫相比傳統數據庫更不穩定,由於所有的數據都存儲與管理在主存中,當計算機斷電或 RAM 崩潰時,數據將會丟失。
內存數據庫可以通過將每個操作存儲在日誌中或採取快照的方式在磁盤上持久化數據。
02
目標
我們的目標是用 Go 編寫一個簡單、快速、嵌入式和可持久化的鍵 / 值數據庫,並且實現以下功能:
-
支持類似 Redis 的數據結構 string, hash, set, zset
-
具有低延時和高吞吐量
-
支持事務,ACID 語義
-
僅可寫入的持久化文件格式
-
可以通過使用 TTL 來處理數據過期
03
開始
我們要建立的是一個非常簡單的 KV(鍵 / 值)存儲,以便讓每個人都能輕鬆理解和實現。在 Go 中,有相當多的嵌入式鍵 / 值存儲可用,以下是一些例子:
-
BadgerDB - BadgerDB 是一個完全用 Go 編寫的嵌入式、可持久化、簡單而快速的鍵值(KV)數據庫。它旨在成爲 RocksDB 等非基於 Go 實現的鍵值存儲的高性能替代品
-
BoltDB - BoltDB 是一個基於 B+ 樹的嵌入式 Go 鍵 / 值數據庫
-
BuntDB - BuntDB 是一個應用於 Go 的嵌入式內存鍵 / 值數據庫,具有自定義索引和地理空間支持
-
go-memdb - 基於不可變基數樹的 Golang 內存數據庫
-
nutsdb - 一個基於磁盤的鍵值存儲
讀起來容易做起來難。雖然我們可以通過閱讀龐大的代碼庫來了解其內部結構,但這對很多人來說依舊是一個障礙。我們的初衷是爲任何想學習關於如何編寫一個簡單的 ACID 數據庫的新手提供橋樑。
NutsDB 是我在 2-3 年前讀到的第一批簡單易懂的代碼之一。因此,我們選擇由易於理解的組合庫組成的 FlashDB。
04
架構
FlashDB 的架構很簡單並且支持各種 Redis 命令。Redis 本質上不是一個普通的鍵值存儲,而是一個數據結構服務器,支持不同種類的值。事實上,Redis 使用以下數據結構實現了各種類型。
05
字符串
Redis 字符串類型是能與 Redis 鍵關聯的最簡單的值類型。由於 Redis 鍵是字符串,當我們把字符串類型也作爲一個值時,實際上是把一個字符串映射到另一個字符串。這是用**可變基數樹(ART)**實現的,這樣可以很容易進行掃描。
- String
(https://github.com/arriqaaq/skiplist)
06
哈希
用哈希表示對象很方便,而實際上哈希中可放入的字段數量並沒有實際限制(除了可用的內存),所以你可以在應用程序中以許多不同的方式使用哈希。這是用一個非常簡單的 HashMap 數據結構實現的。
-
Hash
(https://github.com/arriqaaq/hash)
07
集合
Redis 集合是無序的字符串集合。我們可以對集合進行一些操作,比如檢測某個元素是否已經存在,查找多個集合之間的交集、並集或差集等。這也是用一個簡單的 HashMap 數據結構實現的。
- Set
(https://github.com/arriqaaq/set)
08
有序集合
有序集合是一種數據類型,類似於集合與哈希的混合體。和集合一樣,有序集合也是由唯一的、不重複的字符串元素組成的。所以從某種意義上說,有序集合也是一個集合。
雖然集合內的元素並不是有序的,但有序集合中的每個元素都與一個浮點值相關,稱爲分數(該類型類似於哈希,因爲每個元素都被映射到一個值)。
這是對用於字符串的跳錶結構稍加修改實現的。
-
ZSet
(https://github.com/arriqaaq/zset)
09
持久化
雖然已經有了很多持久化機制,但我選擇了一個簡單的 append-only 日誌設計方式,因爲它比較容易實現和理解。
AOF(僅可寫入的文件) 記錄了服務器收到的每一個寫操作,這些操作將在服務器啓動時再重放,重建原始數據集。命令的記錄格式與 API 協議本身相同,以只寫入的方式進行。當日志過大時,FlashDB 能夠在後臺分片處理日誌。這是基於 wal 實現的。
-
Append Only Log
(https://github.com/arriqaaq/aol)
總結
綜上,FlashDB 僅依靠上述五個簡單的庫就完成了,具有事務與 ACID 支持,易於理解。但我希望這對任何有興趣學習如何編寫數據庫的人來說都是一個有用的教程。
GitHub - arriqaaq/flashdb:
FlashDB is an embeddable, in-memory key/value database in Go (with Redis like commands)
講座
最近在 Golang meetup 上分享了這個項目,這是幻燈片的內容:
https://www.canva.com/design/DAE8sGRyC2o/ZCuCaezQ6dYA0Oq24QxjUQ/view?utm_content=DAE8sGRyC2o&utm_campaign=designshare&utm_medium=link&utm_source=publishsharelink
原文地址:
https://aly.arriqaaq.com/building-a-database-in-go
原文作者:Farhan Aly
本文永久鏈接:https://github.com/gocn/translator/blob/master/2022/w17_Writing_a_simple_in-memory_key-value_Database_in_Go.md
譯者:張宇
校對:小超人
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/cRiv7yp9fNyvP5r8HAaEBQ