OpenHarmony 源碼解析之分布式數據庫
1 簡介
本文基于OpenHarmonyOS 3.0 LTS 來講解分布式數據服務(Distributed Data Service,DDS) 提供不同設備間數據庫數據分布式的能力。從架構上來說,分布式數據服務是開源鴻蒙底層服務的基礎服務,與分布式任務調度同層。然而在使用分布式任務調度功能時,基本上都需要進一步要求數據交互功能,完成完整的分布式功能,因此在學習分布式任務調度的同時,不可避免的需要學習分布式數據服務相關的功能與底層服務。
本文在寫作時,調試JS的DEMO時發現了更底層的方舟JS運行層的BUG,提交了ISSUE,并試圖提交了PR。如果大家在運行DEMO時發現問題,請先嘗試合并上述PR并重新全部編譯系統并刷機再試。
1.1 分布式相關
- 《OpenHarmony 源碼解析之分布式任務調度》
- 《OpenHarmony 源碼解析之分布式數據庫》
1.2 OpenHarmony架構圖

2 基礎知識
2.1 概述
先看開源鴻蒙官方文檔對分布式數據服務的描述:
分布式數據服務(Distributed Data Service,DDS) 提供不同設備間數據庫數據分布式的能力。通過結合帳號、應用和數據庫三元組,分布式數據服務對數據進行隔離。在通過可信認證的設備間,分布式數據服務支持數據相互同步,為用戶提供在多種終端設備上一致的數據訪問體驗。
目前開源鴻蒙還沒有整合賬號功能,因此測試的時候賬號可以自由選擇,填寫一致即可。應用和數據庫則必須保持一致,才能進行完整的分布式數據數據隔離,提供數據在多種終端設備上一致的訪問體驗。
2.2 源碼結構
- ├── BUILD.gn
- ├── figures
- │ ├── en-us_image_0000001162536643.png
- │ └── zh-cn_image_0000001162536643.png
- ├── frameworks
- │ ├── innerkitsimpl
- │ │ └── distributeddatafwk # 框架層實現
- │ │ ├── include
- │ │ ├── src
- │ │ └── test
- │ └── jskitsimpl
- │ └── distributeddata # JS接口實現
- │ ├── include
- │ └── src
- ├── interfaces
- │ ├── innerkits # 內部接口,主要是頭文件
- │ │ ├── app_distributeddata
- │ │ │ ├── BUILD.gn
- │ │ │ └── include
- │ │ └── distributeddata
- │ │ ├── BUILD.gn
- │ │ └── include
- │ └── jskits # JS接口,BUILD用
- │ └── distributeddata
- │ └── BUILD.gn
- ├── LICENSE
- ├── OAT.xml
- ├── ohos.build
- ├── README.md
- ├── README_zh.md
- ├── services
- │ └── distributeddataservice
- │ ├── adapter # 適配實現
- │ │ ├── account # 賬號適配
- │ │ ├── autils # 實用庫,包括任務、線程、目錄等
- │ │ ├── broadcaster # 發送廣播
- │ │ ├── BUILD.gn
- │ │ ├── communicator # 通訊適配
- │ │ ├── dfx # 日志、統計、錯誤等相關處理
- │ │ ├── include
- │ │ ├── LICENSE
- │ │ ├── permission # 權限
- │ │ ├── security # 安全相關
- │ │ ├── test
- │ │ └── utils
- │ ├── app # 用戶程序實現
- │ ├── libs
- │ │ └── distributeddb
- │ │ ├── BUILD.gn
- │ │ ├── common
- │ │ ├── communicator # 設備間通訊
- │ │ ├── include
- │ │ ├── interfaces
- │ │ ├── storage # 存儲實現,包括單版本KV、多版本KV、SQLITE3等
- │ │ ├── syncer # 同步
- │ │ └── test
- │ ├── sa_profile
- │ └── test
- └── test
2.3 分布式數據服務架構設計圖

2.4 數據同步
官方文檔是這么描述的:
通過調用分布式數據服務接口實現分布式數據庫創建、訪問、訂閱功能,服務接口通過操作服務組件提供的能力,將數據存儲至存儲組件,存儲組件調用同步組件實現將數據同步,同步組件使用通信適配層將數據同步至遠端設備,遠端設備通過同步組件接收數據,并更新至本端存儲組件。
2.5 分布式數據
最終一致性:是指某一設備成功增、刪、改數據后,組網內設備可能讀取不到本次更新數據,但在某個時間窗口之后組網內設備的數據能夠達到一致狀態。
強一致性對分布式數據的管理要求非常高,在服務器的分布式場景可能會遇到。因為移動終端設備的不常在線、以及無中心的特性,分布式數據服務不支持強一致,只支持最終一致性。
目前分布式數據的數據模型僅支持KV數據模型,不支持外鍵、觸發器等關系型數據庫中的技術點。雖然開源鴻蒙底層支持基于SQLITE3的關系型數據庫,但是并不在分布式數據層面支持。
當前KV數據模型的限制:
- 設備協同數據庫,Key最大支持896Byte,Value最大支持4MB。
- 單版本數據庫,Key最大支持1KB,Value最大支持4MB。
- 每個程序最多支持同時打開16個DB。
- 當前流控機制針對KvStore的接口1秒最大訪問1000次,1分鐘最大訪問10000次。
- KvManager的接口1秒最大訪問50次,1分鐘最大訪問500次。
2.6 使用前提
從開源鴻蒙的分布式數據源代碼中,可以看到目前只有手機(phone)、穿戴式設備(wearable)、車載系統(ivi)會搭載,其它更輕量的設備可能暫時不支持,或者需要剪裁定制支持。
目前在兩臺標準設備的開源系統鴻蒙上,是默認集成了該功能,可以直接使用的。
開源鴻蒙的分布式數據如果只在單機使用,那么無需前提條件。如果需要其分布式功能,那么就需要設備之間完成組網;而組網的前提條件是完成設備認證。具體步驟,請參考OpenHarmony 源碼解析之分布式任務調度。
3 編程接口
3.1 導入模塊
- import distributedData from '@ohos.data.distributedData';
下面各個接口大多有callback和promise兩種異步方式,本文均以promise方式為例,callback方式大同小異,請自行查閱文檔。
3.2 創建管理器
- distributedData.createKVManager
- createKVManager(config: KVManagerConfig, callback: AsyncCallback<KVManager>): void
- createKVManager(config: KVManagerConfig): Promise<KVManager>
創建一個KVManager對象實例,用于管理數據庫對象,并通過Promise方式返回,此方法為異步方法。
示例:
- let kvManager;
- try {
- const kvManagerConfig = {
- bundleName : 'com.example.datamanagertest',
- userInfo : {
- userId : '0',
- userType : 0
- }
- }
- distributedData.createKVManager(kvManagerConfig).then((manager) => {
- console.log("createKVManager success");
- kvManager = manager;
- }).catch((err) => {
- console.log("createKVManager err: " + JSON.stringify(err));
- });
- } catch (e) {
- console.log("An unexpected error occurred. Error:" + e);
- }
3.3 獲取存儲實例
- kvManager.getKVStore
- getKVStore<T extends KVStore>(storeId: string, options: Options): Promise<T>
通過指定Options和storeId,創建并獲取KVStore數據庫,并通過Promise方式返回,此方法為異步方法。
示例:
- let kvStore;
- try {
- const options = {
- createIfMissing : true,
- encrypt : false,
- backup : false,
- autoSync : true, //手動同步、自動同步
- kvStoreType : 1, //當前只能使用0(默認):表示多設備協同數據庫,1:單版本數據庫
- securityLevel : 3,
- };
- kvManager.getKVStore('storeId', options).then((store) => {
- console.log("getKVStore success");
- kvStore = store;
- }).catch((err) => {
- console.log("getKVStore err: " + JSON.stringify(err));
- });
- } catch (e) {
- console.log("An unexpected error occurred. Error:" + e);
- }
3.4 存、取、刪除、同步
- kvStore.put(key: string, value: Uint8Array | string | number | boolean): Promise<void>
- kvStore.get(key: string): Promise<Uint8Array | string | boolean | number>
- kvStore.delete(key: string): Promise<void>
- kvStore.sync(deviceIdList: string[], mode: SyncMode, allowedDelayMs?: number): void
3.5 注冊事件通知回調
SubscribeType 描述訂閱類型。
- 0: SUBSCRIBE_TYPE_LOCAL 表示訂閱本地數據變更。
- 1: SUBSCRIBE_TYPE_REMOTE 表示訂閱遠端數據變更。
- 2: SUBSCRIBE_TYPE_ALL 表示訂閱遠端和本地數據變更。
- kvStore.on(event: 'dataChange', type: SubscribeType, observer: Callback<ChangeNotification>): void
- kvStore.on(event: 'syncComplete', syncCallback: Callback<Array<[string, number]>>): void
4 小結
以上步驟,均已在DevEco Studio 3.0.0.600 x64中編寫成功,并且在兩臺Hi3516D設備間成功運行,附代碼(分布式任務調度和分布式數據測試.zip)。
再次提醒,分布式數據底層依賴ARK JS引擎,目前發現字符串處理有BUG,如運行出現問題,請先合并PR,然后重新編譯全系統并刷機后再運行DEMO。