SQL數據映射到NoSQL存儲系統的高效方式

SQL數據庫和NoSQL存儲系統都有其各自的優點及局限性,如果你的專案以前是在sql數據庫,現在需要轉到NoSQL上,那麽可以看看本文如何高效的映射過去。

本文我們來看看SQL數據如何高效的映射到NoSQL存儲系統FoundationDB中。
SQL數據庫只限在單機上運行,但它提供了更強的事務管理、schema與查詢功能。
NoSQL數據庫爲了伸縮性與容錯性的目的,放棄了事務管理與schema。
  而FoundationDB的SQL層結合了這兩個方面:它首先是一個開源的SQL數據庫,能夠線性地伸縮與提升容錯性,並且還具有真正的ACID事務功能。曾經互不相容的兩種特性,現在已融合在一個統一的系統中。
  對于處于以下幾種情況的公司來說,這一特性是非常重要的:
新的專案要爲大規模的伸縮性進行計劃。
現有的專案遇到了數據庫伸縮性的瓶頸。
現有的許多專案希望能用一個唯一的、容錯性強的數據庫抽象層統一工作模式。
  在本文中,我將爲讀者介紹FoundationDB,並解釋FoundationDB的SQL層是怎樣將SQL數據映射到FoundationDB中的鍵-值存儲後台系統中的。


 NoSQL數據庫 ——FoundationDB的鍵-值存儲系統
  FoundationDB是一個分布式的鍵-值存儲系統,支持全局ACID事務操作,並且效能出衆。在安裝系統時,可以指定數據分發的級別。數據分發爲容錯性提供了支持:當某個伺服器或網路的某部分産生故障時,數據庫仍然可以正常操作,你的應用也不會受到影響。


 鍵-值與SQL架構
  我們開發的這套架構能夠在鍵-值存儲系統上支持多個層,每個層都能夠在FoundationDB的基礎上提供一套不同的數據模型,例如SQL數據庫、文檔數據庫或圖形數據庫。許多使用者也自行創建了自定義的層。


  下圖中列出架構中的了關鍵部分。處于最底層的是FoundationDB集群,無論集群的實際大小如何,對它的操作與一個單獨的邏輯數據庫並沒有分別。SQL層則以一種無狀態的中間層方式運行在鍵-值存儲系統之上。這一層通過SQL與應用程序進行通信,並使用FoundationDB的客戶端API與鍵-值存儲系統進行通信。由于SQL層是無狀態的,因此可以並行地運行任意數據的SQL層。

SQL數據映射到NoSQL存儲系統的高效方式

 SQL層爲鍵-值存儲系統帶來了如Google的F1般的能力
  SQL層是對SQL與鍵-值存儲API進行轉換的一套邏輯嚴密的層。首先,SQL層會從一條SQL語句開始,將其轉換爲最高效地鍵-值操作。這種方式類似于編譯器將代碼轉換爲低級別的執行格式。並且,這種轉換是完全符合ANSI SQL 92標准的。開發者可以將該功能與ORM、REST API進行接合,或者直接使用SQL層的命令行界面進行調用。從代碼的角度來說,SQL層與鍵-值存儲是完全分離的,它是通過FoundationDB的Java綁定方式與鍵-值存儲進行通信的。感興趣的讀者可以查看FoundationDB的SQL層在GitHub上的代碼庫,其代碼是完全開源的。眼下唯一能夠和這套系統進行比較的是Google的F1,後者是一套基于該公司的Spanner技術所創建的SQL引擎。
  如以下的簡單圖例所示,SQL層是由一系列組件所組成的。應用程序通過某種受支持的SQL客戶端向SQL層發送查詢語句,在解析之後轉換爲一棵計劃節點樹。優化器(Optimizer)會計算最佳的執行計劃,並以一棵操作符樹的方式表現出來,隨後由執行框架(Execution Framework)運行。在執行階段,對數據的請求將被發送到存儲虛擬(Storage Abstraction)層,這一層通過使用Java的鍵-值API在數據與FoundationDB集群之間進行傳輸。數據庫模型將存放在Information Schema層中,這一層將被其它多個組件所調用。

SQL數據映射到NoSQL存儲系統的高效方式

 將SQL數據映射到鍵-值存儲系統
  SQL層需要管理兩種類型的數據,首先是信息Schema的元數據,它負責描述所創建的表與可用的索引。其次,它還需要存儲實際的數據,包括表內容、索引及序列。我們首先來描述一下這些數據是如何保存在鍵-值存儲系統中的。
  本質上講,每個鍵都是對應了某張表中的特定行的指針,而值則包含了該行的數據。鍵的分配是由Table-Group所決定的,它是包含了一個或多個表的組。稍後會對這個概念的細節進行更深入的講解。SQL層會通過使用鍵-值存儲目錄層爲每個Table-Group創建一個目錄,存儲目錄層是爲用戶管理鍵空間的一個工具,它爲每個獨立的目錄分配一個簡短的字節數組,作爲該目錄的唯一鍵。同時,它也維護著其它元數據,以實現通過名稱進行查找的功能。
  下面這個例子演示了如何創建目錄的映射,通過以下語句分配鍵。

CREATE TABLE schema_a.table1(id INT PRIMARY KEY, c CHAR(10));
CREATE TABLE schema_a.table2(id INT PRIMARY KEY);


  在鍵-值存儲系統中有一些預定義的目錄:
SQL數據映射到NoSQL存儲系統的高效方式

  在存儲數據時,可以選擇使用以下三種格式中的一種:“元組(Tuple)”、“原始數據(Row_Data)”或者是“Protobuf”。如果使用默認的Tuple存儲格式,那麽每一行內容都將保存爲一個單獨的鍵-值對,鍵是通過連接以下字符串所生成的元組:目錄前綴、該表在Table-Group中的位置,以及主鍵。而值的內容則是由該行中的所有列所組成的一個元組。
  舉例來說,以下代碼對之前創建的表進行操作,産生對應的鍵與值。

INSERT INTO schema_a.table1 VALUES (1, 'hello'), (2, 'world');
INSERT INTO schema_a.table2 VALUES (5);


SQL數據映射到NoSQL存儲系統的高效方式

  了解了鍵-值存儲系統中鍵的結構之後,你就能夠從存儲系統中直接讀取數據了。我們將使用FoundationDB的Python API來演示這一功能。在SQL層中,鍵與值是通過“.pack()”方法進行編碼,並通過“.unpack()”方法進行解碼的。下面的示例爲你演示如何獲取並解碼數據。

import fdb fdb.api_version(200) 
db = fdb.open() 
directory = fdb.directory.open(db,('sql','data','table','schema_a','table1'))
for key, value in db[directory.range()]:     print fdb.tuple.unpack(key), ' --> ', fdb.tuple.unpack(value)


  以上代碼會輸出類似下面的結果:

(215, 1, 1) --> (1, u'hello') 
(215, 1, 2) --> (2, u'world')


  現在讓我們再來近距離觀察一下Table-Group。每個獨立的表都屬于一個單獨的組,如果某張額外的表能夠創建一個對第一張表的“組外鍵”引用,那麽它也能夠加入到同一個組中。當我們爲某張表創建組外鍵時,字表將與父表所在的目錄進行交互。字表將成爲Table-Group的一部分,在源表之後進行命名。這兩張表的數據在將同一個目錄中進行交互,這保證了範圍掃描的高速,並且在Table-Group之內訪問對象及表連接的開銷極小。爲了演示這一特性,我們將繼續之前的示例,這一次的SQL語句如下:

CREATE TABLE schema_a.table3(id INT PRIMARY KEY, id_1 INT, GROUPING FOREIGN KEY (id_1) REFERENCES schema_a.table1(id));
INSERT INTO schema_a.table3 VALUES (100, 2), (200, 2), (300, 1);


  該語句將返回以下結果:

directory = fdb.directory.open(db,('sql','data','table','schema_a','table1'))
for key, value in db[directory.range()]:   print fdb.tuple.unpack(key), ' --> ', fdb.tuple.unpack(value)
(215, 1, 1)     --> (1, u'hello')
(215, 1, 1, 2, 300) --> (300, 1) 
(215, 1, 2)     --> (2, u'world')
(215, 1, 2, 2, 100) --> (100, 2)
(215, 1, 2, 2, 200) --> (200, 2)


  由于第三張表的鍵都處于第一張表中各行的命名空間範圍內,因此第三張表中所有插入的行都能夠與第一張表的行相關聯。鍵中的兩個額外的值分別對應了Table-Group中的位置以及第三張表中的主鍵。對表1與表3通過引用鍵進行連接也無需通過標准的連接操作實現,直接通過線性掃描就語句了。這種排序方式比起傳統的關系型數據庫系統有著極大的優勢。
  由于鍵都已經經過排序,因此索引可以直接利用這一點所帶來的便利性。所有的表索引只包含一個鍵值,其中包括兩部分內容。每個索引都創建于該表所屬的目錄之下,一個名爲index的子目錄中,這是該鍵元組的第一部分內容。第二個部分是一個組合,首先是該索引所對應的各個列的值,之後則是指定這一行所必須的列的值。
  舉例來說,我們可以爲這張表的c列創建一個索引。

CREATE INDEX index_on_c ON schema_a.table1(c) STORAGE_FORMAT tuple;


  接下來使用Python讀取這個索引的內容,我們需要在Python解釋器中加入以下內容:

directory = fdb.directory.open(db, ('sql', 'data', 'table', 'schema_a', 'table1', 'index_on_c'))
for key, value in db[directory.range()]:   print fdb.tuple.unpack(key), ' --> ', fdb.tuple.unpack(value)


  這段代碼會輸入類似于下圖中的內容,顯示了鍵的兩個組成部分:即該索引所在的目錄的字節值,以及創建索引的c列的值加上主鍵的值。最後一個部分將被索引的值鏈接到某個特定的行,而該索引鍵所對應的值爲空。

(20127, u'hello', 1) --> ()
(20127, u'world', 2) --> ()


  如果要對SQL層的行爲進行更多的控制調整,可以使用以下三種存儲格式:一是之前描述過的元組格式,一是列鍵格式,以及protobuf格式。列健格式會爲某一行的每個列值創建一個獨立的鍵-值對。而protobuf存儲格式爲會每一行創建一個protobuf消息。
  接下來還需要對元數據進行存儲與組織。SQL層使用protobuf消息與基于SQL的數據的結構進行通信。這個結構是由schema、組、表、列、索引與外鍵等對象共同組成的。
 SQL與NoSQL的混合模式
  如果在應用程序級別使用唯讀的鍵-值API,那麽SQL層就能夠在客戶端進行直接訪問。可以通過鍵-值API直接訪問數據,但如果增加或改寫了SQL層所用的關鍵數據,那就很可能破壞系統的運行。這裏例舉一些可能會産生的問題:缺乏對索引的維護、缺乏應有的限定,以及忽略了對數據及元數據的版本維護。而這種方式的好處,哪怕是在進行數據讀取時也並不明顯,因爲SQL層本身的額外開銷就非常小。因此總的來說,效能的開銷主要取決于網路延遲。
 結論
  SQL與NoSQL的結合使用能夠相互利用兩者的優點。FoundationDB的鍵-值存儲系統爲SQL層帶來的好處包括可伸縮性、容錯性及全局ACID的事務屬性。你的應用程序同樣也能從中受益,因此趕緊嘗試一下吧!對應那些要執行大量的小批數據讀取及寫入的應用程序來說,FoundationDB提供了一個高伸縮並且安全的解決方案,並且可以任意使用SQL或NoSQL。

更多相關文章
  • 本文章爲oracle入門的朋友簡單的介紹了關于Oracle10g數據庫幾種存儲格式,有需要學習的朋友可了解一下. 1 操作系統文件.這種是大家最常用的方式了,也是非商業運行模式(比如開發或者開發階段的測試環境)下最常用的形式.當大家安裝Oracle的時候,如果選用了操作系統文件的存儲形式,那麽就會把
  • CentOS 7 安裝分布式存儲系統 Ceph 與使用
    Ceph是一個 Linux PB 級分布式文件系統.Ceph可以:1.可輕松擴展到數 PB
  • R語言中連接SQL數據庫需要安裝其它的擴展包,我們可以選擇ODBC方式還是DBI方式,當然安裝的驅動會不同,本文會詳細講解.數據分析經常需要從外部獲得數據.很多情況下數據存放在關系型數據庫中.一般我們可以用SQL來提取需要的數據,存爲文本再由R來讀入.這種方式結合了數據庫的儲存能力和R的分析能力,速 ...
  • 本文章來給大家介紹利用MySQL用shell命令導入*.sql數據庫的方法,雖然我們可以使用phpmyadmin來導入但是有時數據大了導入會有問題.用phpmyadmin導入數據庫,但是這樣做還有文件上傳大小限制,上
  • asp.net c# 把excel導入mssql sql數據庫並支持多個sheet表asp教程.net c# 把excel導入mssql sql數據庫教程並支持多個sheet表'解決方法一objSheet = (Excel._Worksheet)objSheets.get_Item(Sheets);
  • jsp調用java類並查詢sql數據庫jsp教程調用java類並查詢sql數據庫教程package bean;import java.sql.*;public class MyDb_Page{ private Sta
  • 由于自己在幾百上千的分類今天自己寫的了導入分類的程序,但是生成時出現沒有應欄目數據,可能緩存文件(/data/cache/inc_catalog_base.inc)沒有更新,請檢查是否有寫入權限,經過分析我們修改權限也沒用,只要按下面三步操作就可以了.1. 把inc_catalog_base.inc ...
  • 在php中連接mysql數據庫有 mysql.mysqli.pdo三種方式了,但估計各位對于它們三個的連接與區別估計不是很理解了,下面一聚教程小編爲各位介紹一下吧.一.特性及對比PHP的MySQL擴展是設計開發允許PHP應用與MySQL數據庫交互的早期擴展.mysql擴展提供了一個面向過程 的接口,
一周排行