cube.js 生产集成使用的几点说明
cube.js 官方已经提供了相关的生产部署说明,但是还是有点简单,有些还是我们需要关注解决
schema 存储问题
默认是基于文件系统存储的,可选的解决方法,扩展接口,支持基于s3的存储
- 几个问题
生产环境如何更新schema同时进行重编译,可以基于api进行控制(重启也是可以解决的。。。)
相关schema 版本api
module.exports = {
schemaVersion: ({ securityContext }) => tenantIdToDbVersion[securityContext.tenantId],
};
schema 生成问题
应该通过获取表的schema(可以基于information schema 解决)然后进行选择表映射的处理
- 几个问题
很多时候表之前是有关系的,这个然后进行处理,以及生成相关schema,同时因为schema的
特殊性,最好唯一(尤其是需要集成多租户模式的时候),同时我们可以通过公用以及独立服务
访问的模式提供schema service 的暴露以及访问(数据隔离以及数据安全)
同时对于数据schema的规划比较重要(有些可能是需要共享的,有些可能是独立的,这个和数据的存储
也有点关系)
数据权限的问题
这个属于一个通用的问题,解决方法可能很多,从机制上我们已经规避数据权限与数据的太多耦合,同时也
应该实现数据权限的最小化,以及分级控制(比如通用schema,独立主题schema),安全很重要,而且cube.js
是基于jwt 模式的,我们应该规避敏感信息的暴露,使用cube.js SECURITY_CONTEXT 进行行级别的访问控制
也是一种方法,但是很多时候我们的业务模型可能是不能这么搞的,一种方法可以进行业务数据关联(基于通用
cube schema 以及结合SECURITY_CONTEXT)同时我们需要注意jwt token 的维护
同时queryTransformer 也是一个不错的选择,参考扩展
module.exports = {
queryTransformer: (query, { securityContext }) => {
const user = securityContext.u;
if (user.filterByRegion) {
query.filters.push({
member: 'Regions.id',
operator: 'equals',
values: [user.regionId],
});
}
return query;
},
};
- 一些解决方法
cube.js 的SECURITY_CONTEXT 更多的是关于row 级别的数据访问过滤,但是对于进一步的数据权限可能就比较
弱了,我们可以结合casbin 实现更加灵活的访问控制
实际部署问题
最好实际的ci、cd 很重要,可以方便我们的扩展以及无停机的业务部署
- 几个问题
schema 生成之后是需要进行校验的(有依赖其他schema以及编译错误的问题)
statsbot 的解决方法值得借鉴(分为了两个步骤,保存文件以及编译schema)
我们可以的解决方法是借鉴类似的,可以自己实现schema 编译的处理
参考代码(实际可以自己扩展为基于内存的schema 编译处理,memfs是一个不错的选择)
const schmeacompiler = require("@cubejs-backend/schema-compiler")
const filRepo = require("@cubejs-backend/server-core/dist/src/core/FileRepository")
const fs = require("fs")
const result = schmeacompiler.compile(new filRepo.FileRepository("./myrepo"),{
maxQueryCacheSize:1000,
maxQueryCacheAge:100
})
result.then(data=>{
console.log(data)
})
对于实际的运行我们可以基于容器进行解决
数据预聚合处理
推荐使用外部数据预聚合处理模式,可以配置独立的数据库实例进行数据加速的处理
元数据&&schema 接口暴露问题
statsbot的解决方法基于了graphql 进行解决,实际上也是cube.js 是包含的,可以直接复用(基于graphql 可能会更灵活点)
schmea 依赖&&版本问题
schema 之间是包含依赖关系的,比如一个cube schema引用其他cube schema 就存在依赖管理的问题
- 几个问题
依赖修改,以及编译问题,这个还算简单,依赖的会基于文件自动处理
版本的问题,我们可以结合类似git 的模式解决(简单的方法是直接数据库存储base64 或者文本内容,同时关联版本)
如何提供playground 给用户使用
playground 是一个很不错的工具,可以方便我们测试使用,cube.js 的playgroud 也是一个独立的软件包,官方代码中
对于playground的处理就是基于了一个配置参数,同时集成了自己开发的playground 使用了serve-static模块,同时
对于常见的操作进行提供的能力做了包装
- 集成playground的核心处理部分
核心还是利用了server-core 提供的暴露exprss 的能力,当然我们也可以自己基于此进行扩展使用initApp方法集成playground
public async initApp(app: ExpressApplication) {
checkEnvForPlaceholders();
const apiGateway = this.apiGateway();
apiGateway.initApp(app);
if (this.options.devServer) {
this.devServer.initDevEnv(app, this.options);
} else {
app.get('/', (req, res) => {
res.status(200)
.send('<html><body>Cube.js server is running in production mode. <a href="https://cube.dev/docs/deployment#production-mode">Learn more about production mode</a>.</body></html>');
});
}
}
说明
statsbot 是一个值得学习借鉴的产品(cube.js 团队的saas服务)
参考资料
http://help.statsbot.co/en/
https://github.com/streamich/memfs
https://cube.dev/docs/dev-tools/dev-playground