#星光计划2.0# OpenHarmony 源码解析之分布式数据库 原创 精华
作者:卞绍雷
【本文正在参与51CTO HarmonyOS技术社区创作者激励计划-星光计划2.0】
1 简介
本文基于OpenHarmonyOS 3.0 LTS
来讲解分布式数据服务(Distributed Data Service,DDS) 提供不同设备间数据库数据分布式的能力。从架构上来说,分布式数据服务是开源鸿蒙底层服务的基础服务,与分布式任务调度同层。然而在使用分布式任务调度功能时,基本上都需要进一步要求数据交互功能,完成完整的分布式功能,因此在学习分布式任务调度的同时,不可避免的需要学习分布式数据服务相关的功能与底层服务。
本文在写作时,调试JS的DEMO时发现了更底层的方舟JS运行层的BUG,提交了ISSUE,并试图提交了PR。如果大家在运行DEMO时发现问题,请先尝试合并上述PR并重新全部编译系统并刷机再试。
1.1 分布式相关
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。
更多原创内容请关注:开鸿 HarmonyOS 学院
入门到精通、技巧到案例,系统化分享HarmonyOS开发技术,欢迎投稿和订阅,让我们一起携手前行共建鸿蒙生态。