NDB
支援線上 Schema 變更。Schema 物件,例如 Table
或 Index
,具有 4 位元組的schema 物件版本識別碼,可以在 ndb_desc 工具的輸出中觀察到(請參閱ndb_desc — 描述 NDB 表格),如下所示(強調文字)
$> ndb_desc -c 127.0.0.1 -d test t1
-- t1 --
Version: 33554434
Fragment type: HashMapPartition
K Value: 6
Min load factor: 78
Max load factor: 80
Temporary table: no
Number of attributes: 3
Number of primary keys: 1
Length of frm data: 269
Row Checksum: 1
Row GCI: 1
SingleUserMode: 0
ForceVarPart: 1
FragmentCount: 4
ExtraRowGciBits: 0
ExtraRowAuthorBits: 0
TableStatus: Retrieved
HashMap: DEFAULT-HASHMAP-240-4
-- Attributes --
c1 Int PRIMARY KEY DISTRIBUTION KEY AT=FIXED ST=MEMORY AUTO_INCR
c2 Int NULL AT=FIXED ST=MEMORY
c4 Varchar(50;latin1_swedish_ci) NOT NULL AT=SHORT_VAR ST=MEMORY
-- Indexes --
PRIMARY KEY(c1) - UniqueHashIndex
PRIMARY(c1) - OrderedIndex
NDBT_ProgramExit: 0 - OK
schema 物件版本識別碼(或簡稱為「schema 版本」)由主要版本和次要版本組成;主要版本佔用 schema 版本的(單個)最低有效位元組,次要版本佔用其餘的(3 個最高有效位元組)。當以十六進位表示法檢視 schema 版本時,您可以更容易地看到這兩個元件。在剛才顯示的範例輸出中,schema 版本顯示為 33554434
,以十六進位表示(視需要填補前導零)為 0x02000002
;這相當於主要版本 2,次要版本 2。將索引新增至表格 t1
會導致 ndb_desc 回報的 schema 版本推進至 50331650
,或十六進位的 0x03000002
,這相當於主要版本 2(3 個最低有效位元組 00 00 02
),次要版本 3(最高有效位元組 03
)。次要 schema 版本在新增表格時從 0 開始。
此外,每個 NDB API 資料庫物件類別都有自己的 getObjectVersion()
方法,如同 Object::getObjectVersion()
,會傳回物件的 schema 物件版本。這包括 Object
的執行個體,以及 Table
、Index
、Column
、LogfileGroup
、Tablespace
、Datafile
和 Undofile
,以及 Event
。(不過,NdbBlob::getVersion()
的用途和功能與剛才列出的方法完全無關。)
被視為向後相容的 Schema 變更 — 例如在表格結尾新增 DEFAULT
或 NULL
資料行 — 會導致表格物件的次要版本遞增。未被視為向後相容的 Schema 變更 — 例如從表格中移除資料行 — 會導致主要版本遞增。
雖然導致 Schema 主要版本變更的操作實作實際上可能包含受影響表格的 2 個複本(卸除並重新建立表格),但最終結果可以觀察為表格主要版本的增加。
從 NDB 用戶端抵達的查詢和 DML 操作也具有相關聯的 schema 版本,會在資料節點中開始處理時進行檢查。如果請求的 schema 版本與受影響資料庫物件的最新 schema 版本僅在次要版本元件上有所不同,則該操作會被視為相容,並允許繼續。如果 schema 版本在主要 schema 版本上有所不同,則將會遭到拒絕。
此機制允許以各種方式變更資料節點中的 schema,而不需要用戶端進行同步 schema 變更。用戶端不需要在準備好之前移動到新的 schema 版本。因此,查詢和 DML 操作可以繼續不間斷地進行。
NDB API 和 schema 物件版本。 NDB API 應用程式通常使用與 Ndb
物件相關聯的 NdbDictionary
物件來擷取 schema 物件。會根據需求從資料節點擷取 schema 物件;使用信號來取得表格或索引定義;然後,建構應用程式可以使用的本機記憶體物件。NDB
在內部快取 schema 物件,因此後續每次依名稱請求相同表格或索引都不需要發送信號。
全域 schema 快取。 為了避免每次查詢 schema 物件時都必須向資料節點發送信號,每個 Ndb_cluster_connection
都會使用 schema 快取。這稱為全域 schema 快取。就跨越多個 Ndb 物件而言,這是全域的。會自動將已具現化的表格和索引物件放入此快取中,以節省未來的信號和具現化成本。快取會維護每個物件的參考計數;此計數會用來判斷何時可以刪除給定的 schema 物件。可以使用明確的 API 方法呼叫或本機 schema 快取操作來修改 schema 物件的參考計數。
本機 schema 快取。 除了每個連線的全域 schema 快取之外,每個 Ndb
物件的 NdbDictionary
物件都有本機 schema 快取。此快取包含全域 schema 快取中保留的物件指標。每個在全域 schema 快取中保留 schema 物件參考的本機 schema 快取都會將全域 schema 快取參考計數增加 1。擁有每個 Ndb
物件的本機 schema 快取允許查詢 schema 物件,而不需要任何鎖定。當刪除相關聯的 Ndb
物件時,本機 schema 快取通常會被清空(在此過程中會減少全域快取參考計數)。
沒有 schema 變更的操作。 在以下列出的情況下,正常操作會按照以下步驟進行
-
某些用戶端(Ndb 物件)第一次要求表格。 檢查本機快取;此嘗試會導致未命中。然後也會檢查全域快取(使用鎖定),結果是另一個未命中。
由於沒有快取命中,因此會向資料節點發送信號;節點的回應會用來具現化表格物件。會將已具現化資料物件的指標新增至全域快取;另一個這類指標會新增至本機快取,且參考計數會設定為 1。表格的指標會傳回至用戶端。
-
第二個用戶端(不同的 Ndb 物件)也依名稱要求存取相同的表格。 檢查本機快取會導致未命中,但檢查全域快取會產生命中。
結果,會將物件指標新增至本機快取,全域參考計數會遞增 — 因此其值現在為 2 — 並且會將物件指標傳回至用戶端。不會將新的指標新增至全域快取。
第二次,第二個用戶端依名稱要求存取相同的表格。 檢查本機快取,產生命中。會立即將物件指標傳回至用戶端。沒有指標會新增至本機或全域快取,且物件的參考計數不會遞增(因此參考計數會保持 2 不變)。
-
第二個用戶端刪除 Ndb 物件。 這個用戶端的本機 schema 快取中的物件會在全域快取中將其參考計數遞減。
這會將全域快取參考計數設定為 1。由於它還不是 0,因此還不會採取任何動作來移除父系
Ndb
物件。
Schema 變更。 假設物件的 schema 永遠不會變更,則第一次擷取的 schema 版本會用於應用程式程序的生命週期,並且只有在所有本機快取參考(也就是對 Ndb
物件的所有參考)都刪除時,才會刪除記憶體中的物件。這不太可能發生,除非在關閉或叢集連線重設期間。
如果物件的 schema 在應用程式執行時以向後相容的方式變更,則會產生以下影響
資料節點的次要版本會遞增。(使用舊 schema 版本進行中的 DML 操作仍然會成功。)
後續擷取最新版本 schema 物件的 NDB API 用戶端接著會擷取新的 schema 版本。
具有快取舊版本的 NDB API 用戶端不會使用新的 schema 版本,除非它們的本機和全域快取失效。
訂閱事件的 NDB API 用戶端可以觀察到表格的
TE_ALTER
事件,並且可以使用它來觸發 schema 物件快取失效。可以呼叫
removeCachedTable()
或removeCachedIndex()
來移除每個本機快取項目。這會從本機快取中移除該項目,並遞減全域快取中的參考計數。當(而且如果)全域快取參考計數達到零時,可以刪除舊的快取物件。或者,可以透過呼叫
invalidateTable()
或invalidateIndex()
來移除本地快取條目,並使全域快取條目失效。後續對此和其他客戶端呼叫getTable()
或getIndex()
,會透過發出訊號給資料節點並實例化新的物件,來傳回新的結構描述物件版本。新的
Ndb
物件會像平常一樣,根據全域表格快取的需求填入其本地表格快取。這表示,一旦舊的結構描述物件在全域快取中失效,這些物件將會擷取首次快取表格物件時所知的最新表格物件。
當進行不相容的結構描述變更時(也就是結構描述主要版本變更),一旦新的版本提交,使用舊版本的 NDB API 請求會立即失敗。這也可以用作擷取新結構描述物件版本的觸發器。
以下清單總結了結構描述版本變更的處理規則
線上結構描述變更(次要版本變更)不會影響現有的客戶端(
Ndb
物件);客戶端可以繼續使用舊的結構描述物件版本只有當客戶端自願透過進行 API 呼叫來移除快取的物件時,它才能觀察到新的結構描述物件版本。
當
Ndb
物件移除快取的物件並被刪除時,舊結構描述物件版本的參考計數會減少。當此參考計數達到 0 時,該物件可以被刪除。
結構描述物件生命週期的含義。結構描述物件(例如 Table
或 Index
)的壽命受限於從中取得該物件的 Ndb
物件的壽命。當結構描述物件的父 Ndb
物件被刪除時,使 Ndb
物件保持存活的參考計數會遞減。如果這個 Ndb
物件持有給定結構描述物件版本的最後一個剩餘參考,則刪除該 Ndb
物件也可能導致結構描述物件的刪除。因此,此時不能有其他執行緒正在使用該物件。
當應用程式中保存指向結構描述物件的指標,並在多個 Ndb
物件之間使用時,必須謹慎。結構描述物件的使用壽命不應超過建立它的 Ndb
物件的壽命。
應用程式可以非同步且彼此獨立地回應向後相容的結構描述變更,僅在必要時才移至新的結構描述。不同的執行緒可以同時操作不同的結構描述物件版本。
因此,務必確保結構描述物件的壽命不會超過用於建立它們的 Ndb
物件。為了幫助防止這種情況發生,您可以採取以下任何動作來使舊的結構描述物件失效
若要在需要時觸發失效,請使用 NDB API
TE_ALTER
事件(請參閱 Event::TableEvent)。使用外部觸發器來啟動失效。
明確執行定期失效。
透過這些方式使快取失效,可讓應用程式根據需要取得新的結構描述物件版本。
此外,值得注意的是,並非所有 NDB API Table
getter 方法都會傳回指標;它們當中的許多(除了 Table::getName()
)會傳回表格名稱。這些方法包括 Index::getTable()
、NdbOperation::getTableName()
、Event::getTableName()
和 NdbDictionary::getRecordTableName()
。