資料庫也可以像電腦一樣組裝:使用Kafka建立關聯式資料庫 – Robert Yokota

banq發表於2019-09-24

在本文中,我將展示如何擴充套件KCache以實現稱為KarelDB的功能齊全的關聯式資料庫。。此外,我將展示當今如何從現有的開放原始碼元件中組裝資料庫體系結構,就像透過組裝Web伺服器(Jetty)、RESTful API框架(Jersey)、 JSON序列化框架(Jackson)和物件關係對映層(JDBI或Hibernate)等元件來建立Dropwizard這樣的Web框架一樣。

您好,KARELDB
在深入研究構成KarelDB的元件之前,首先讓我向您展示如何快速啟動並執行它。首先,下載一個版本,解壓縮,然後進行修改config/kareldb.properties以指向現有的Kafka代理。然後執行以下命令:

$ bin/kareldb-start config/kareldb.properties


KarelDB執行會,在另一個終端上,輸入以下命令來啟動sqlline,這是用於訪問JDBC資料庫的命令列實用程式:

$ bin/sqlline
sqlline version 1.8.0
 
sqlline> !connect jdbc:avatica:remote:url=http://localhost:8765 admin admin
 
sqlline> create table books (id int, name varchar, author varchar);
No rows affected (0.114 seconds)
 
sqlline> insert into books values (1, 'The Trial', 'Franz Kafka');
1 row affected (0.576 seconds)
 
sqlline> select * from books;
+----+-----------+-------------+
| ID |   NAME    |   AUTHOR    |
+----+-----------+-------------+
| 1  | The Trial | Franz Kafka |
+----+-----------+-------------+
1 row selected (0.133 seconds)


KarelDB現在為您服務啦。

卡夫卡的永續性
KarelDB的核心是KCache,這是由Kafka支援的嵌入式鍵值儲存。許多元件使用Kafka作為簡單的鍵值儲存,包括Kafka ConnectConfluent Schema Registry。KCache不僅概括了此功能,而且還提供了Map基於簡單API的易用性。此外,KCache可以對由Kafka支援的嵌入式鍵值儲存使用不同的實現。

CockroachDB是建立在RocksDB鍵值儲存之上的SQL層,而YugaByteDB既是文件又是建立在RocksDB之上的SQL層。其他資料庫(例如FoundationDB)聲稱是多模型的,因為它們使用鍵值儲存作為基礎一次支援多種型別的模型。
對於KarelDB,預設情況下,KCache配置為由Kafka支援的RocksDB快取。這使KarelDB支援更大的資料集和更快的啟動時間。如果需要,還可以將KCache配置為使用記憶體中的快取而不是RocksDB。

AVRO用於序列化和架構演進
Kafka幾乎已經採用Apache Avro作為其事實上的資料格式,這是有充分理由的。Avro不僅提供緊湊的二進位制格式,而且還對模式演變提供了出色的支援。這種支援是為什麼Confluent Schema Registry選擇Avro作為其提供架構管理的第一種格式的原因。
KarelDB使用Avro定義關係(表)並序列化這些關係的資料。透過使用Avro,KarelDB在執行ALTER TABLE命令時可免費獲得架構演化。

sqlline> !connect jdbc:avatica:remote:url=http://localhost:8765 admin admin 
 
sqlline> create table customers (id int, name varchar);
No rows affected (1.311 seconds)
 
sqlline> alter table customers add address varchar not null;
Error: Error -1 (00000) : 
Error while executing SQL "alter table customers add address varchar not null": 
org.apache.avro.SchemaValidationException: Unable to read schema:
{
  "type" : "record",
  "name" : "CUSTOMERS",
  "fields" : [ {
    "name" : "ID",
    "type" : "int",
    "sql.key.index" : 0
  }, {
    "name" : "NAME",
    "type" : [ "null", "string" ],
    "default" : null
  } ]
}
using schema:
{
  "type" : "record",
  "name" : "CUSTOMERS",
  "fields" : [ {
    "name" : "ID",
    "type" : "int",
    "sql.key.index" : 0
  }, {
    "name" : "NAME",
    "type" : [ "null", "string" ],
    "default" : null
  }, {
    "name" : "ADDRESS",
    "type" : "string"
  } ]
}
 
sqlline> alter table customers add address varchar null;
No rows affected (0.024 seconds)


如上所示,當我們第一次嘗試新增具有NOT NULL約束的列時,Avro會拒絕模式更改,因為新增具有NOT NULL約束的新欄位將導致反序列化失敗,相反,對於沒有該約束的舊記錄領域,當我們新增具有NULL約束的同一列時,ALTER TABLE命令成功。
透過使用Avro進行反序列化,將使用預設值(null如果該欄位是可選的)適當地填充新增到架構中的欄位(無NOT NULL約束)。這些全部由基礎的Avro框架自動處理。
Avro的另一個重要方面是,它定義了資料的標準排序順序,以及比較功能,該功能直接對二進位制編碼的資料進行操作,而無需先反序列化。例如,這允許KarelDB有效地處理鍵範圍查詢。

CALCITE SQL

Apache Calcite是一個SQL框架,用於處理查詢解析,最佳化和執行,但不包含資料儲存。Calcite允許將關係表示式下推到資料儲存中,以進行更有效的處理。否則,Calcite可以使用內建的列舉來處理查詢呼叫約定,該約定允許將資料儲存表示為可以透過迭代器介面訪問的一組元組。嵌入式鍵值儲存是此類元組的完美表示,因此KarelDB將處理鍵查詢和鍵範圍過濾(使用Avro的排序順序支援),但將查詢處理推遲到Calcite的可列舉約定。Calcite專案的一個不錯的方面是它將繼續為可列舉的約定開發最佳化,這將自動使KarelDB受益。
Calcite支援符合ANSI的SQL,包括一些較新的功能,例如JSON_VALUE和JSON_QUERY。

sqlline> create table authors (id int, json varchar);
No rows affected (0.132 seconds)
 
sqlline> insert into authors 
       > values (1, '{"name":"Franz Kafka", "book":"The Trial"}');
1 row affected (0.086 seconds)
 
sqlline> insert into authors 
       > values (2, '{"name":"Karel Capek", "book":"R.U.R."}');
1 row affected (0.036 seconds)
 
sqlline> select json_value(json, 'lax $.name') as author from authors;
+-------------+
|   AUTHOR    |
+-------------+
| Franz Kafka |
| Karel Capek |
+-------------+
2 rows selected (0.027 seconds)



支援事務和MVCC的OMID
儘管Apache Omid最初旨在與HBase一起使用,但它是用於支援鍵值儲存上的事務的通用框架。此外,Omid使用基礎鍵值儲存來持久儲存與交易有關的後設資料。這使得將Omid與現有鍵值儲存(例如KCache)整合起來特別容易。
Omid實際上需要鍵值儲存中的一些功能,即多版本資料和原子比較和設定功能。KarelDB將這些功能放在KCache之上,以便可以利用Omid對事務管理的支援。Omid利用鍵值儲存的這些功能來使用多版本併發控制(MVCC)提供快照隔離。MVCC是用於在其他關聯式資料庫(例如Oracle和PostgreSQL)中實現快照隔離的一種常用技術。
下面我們可以看到一個示例,該示例說明回滾事務將如何在事務開始之前恢復資料庫的狀態。

sqlline> !autocommit off
 
sqlline> select * from books;
+----+-----------+-------------+
| ID |   NAME    |   AUTHOR    |
+----+-----------+-------------+
| 1  | The Trial | Franz Kafka |
+----+-----------+-------------+
1 row selected (0.045 seconds)
 
sqlline> update books set name ='The Castle' where id = 1;
1 row affected (0.346 seconds)
 
sqlline> select * from books;
+----+------------+-------------+
| ID |    NAME    |   AUTHOR    |
+----+------------+-------------+
| 1  | The Castle | Franz Kafka |
+----+------------+-------------+
1 row selected (0.038 seconds)
 
sqlline> !rollback
Rollback complete (0.059 seconds)
 
sqlline> select * from books;
+----+-----------+-------------+
| ID |   NAME    |   AUTHOR    |
+----+-----------+-------------+
| 1  | The Trial | Franz Kafka |
+----+-----------+-------------+
1 row selected (0.032 seconds)


事務當然可以跨越多行和多個表。

AVATICA 實現JDBC
KarelDB實際上可以以兩種模式執行,即作為嵌入式資料庫還是作為伺服器。對於伺服器,KarelDB使用Apache Avatica提供RPC協議支援。Avatica既提供包裝KarelDB的伺服器框架,又提供可以使用Avatica RPC與伺服器通訊的JDBC驅動程式。
使用Kafka的一個優點是多個伺服器都可以“尾隨”同一組主題。這允許多個KarelDB伺服器作為群集執行,而沒有單點故障。在這種情況下,其中一臺伺服器將被選為領導者,而其他伺服器將成為跟隨者(或副本)。當關注者收到JDBC請求時,它將使用Avatica JDBC驅動程式將JDBC請求轉發給領導者。如果領導者失敗,將選出一名跟隨者為新領導者。

元件資料庫
如今,開源庫已經實現了很多年前基於元件的軟體開發所希望實現的目標。使用開源庫,可以透過整合一些精心設計的元件來組裝諸如關聯式資料庫之類的複雜系統,其中每個元件都專門從事一項功能特別出色的事情。
上面我已經展示了KarelDB是幾個現有開源元件的集合:


目前,KarelDB被設計為可複製的單節點資料庫,但它不是分散式資料庫。同樣,KarelDB是一個普通的關聯式資料庫,並且不處理流處理。對於分散式,流相關的資料庫,請考慮改用經過生產驗證的KSQL
KarelDB仍處於初期階段,但是如果您對使用Kafka備份原始的關係資料感興趣,請嘗試一下。

相關文章