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。