思维碎片
提示
磐石 DB
的设计仍在逐步改进与完善中,本文将随时发生变化,感兴趣的朋友们可以时刻保持关注;- 在下方的版权声明中有本文作者的联系方式,有不同意见和相关建议的朋友可以与其保持联系;
- 也可在本文底部的评论区登录 Github 后,直接发表您的观点;
版权声明
- 文章作者: flytreeleft - flytreeleft@crazydan.org
- 文章链接: https://studio.crazydan.org/docs/panshi-db/system-design/thoughts
- 版权声明: 本文章采用许可协议《署名 4.0 国际 (CC BY 4.0)》。 转载或商用请注明来自 Crazydan Studio!
备注
很多技术都可以从差量的角度去重新认识。ChatDB 将数据库作为符号化的
Memory 来使用,这可以从差量的角度得到解释:生成的 SQL
就是对数据的一种差量描述,应用差量后得到新的数据。这些
Delta 甚至可以满足结合律。在表数据库空间中的所有数据都具有唯一的坐标:
(tableName, rowId, fieldName)
。
所谓的 Compositional Progamming 看起来像是将程序结构映射到类型空间,然后在类型空间中定义了某种 Delta,而且这个 Delta 满足结合律和交换律。 但是从广义的可扩展设计角度看,类型系统其实不是一种合适的 Delta 空间,因为 Delta 的应用依赖于结构空间中的坐标唯一性, 而类型系统本身的含义是多个结构具有同一种类型,这就导致作为定位坐标系来说它是不合适的。
以上文字来自 这里。
- 考虑在数据空间应用 可逆计算
- 列数据是业务无关的,在存储层之上需通过 DSL 建立列数据与行数据的映射关系, 多条行数据(同类型或不同类型均可)可以映射到相同的列数据上,在存储层面降低数据的冗余度
- 行数据(一条 DSL 结构化数据)是有唯一定位坐标的,对其做增删改操作,本质上就是做差量计算
- 技术:
IndexR
,HDFS
,Erlang/Elix
,Mnesia
,RabbitMQ
- 参考:postgresql,用 tikv 做存储
- 事实库(
Factbase
): 事实即信息,知识为关系或函数 - 内容即地址:根据任意字段(含 id)内容直接寻址到所在的记录
- 索引:
B-Tree
,B+Tree
- 在应用端协调事务和锁?
- 对于不可变数据,多个节点之间的增量同步,只需要同步底层(实际操作数据)的变更函数即可,也即操作的可回放,同步后,记录操作序号和数据变更版本。可以同步指定序列范围内的操作,也可以同步指定变更版本范围内的数据,也可以仅同步指定类型的数据。全量同步一般采用数据同步方式,完成后,再采用增量同步
- 字段数据类型仅做声明用,在取数据时才转换类型,实际存储采用统一类型(字符串,二进制)
- 支持将数据集映射为文件以便于直接查看和读取
- 可回演任意时间段内的数据操作过程(可展示并发读写及最终写入的动图)
- 库文件自包含(即自身记录其必要信息),可直接做整体迁移,无需提供其他信息
- 超高压缩比,超快压缩、解压缩
- 加密:数据内容分块加密,降低少量内容的增减而造成的整体加密结果的不同而造成的存储浪费
- 使用应用时钟以避免物理时钟无法进行无偏差的同步问题。从任何节点均可得到全局同步的应用时钟
- 浮点数可以记录计算式而非计算结果,确保精度任意,比较操作精确
- 虚拟属性:其值由真实属性值计算的结果,只读,可按真实属性做权限控制,比如,普通用户只能看脱敏后的某属性,脱敏属性即为虚拟属性
- 影子对象:其部分或全部属性映射至其他对象的属性,且对这些属性的修改将直接作用在映射的对象属性上。可用于应用兼容性支持,不同应用数据对多个应用整合后的数据的无感知更新。存在转换函数(必须幂等)的,需将转换结果保持下来,减少重复计算和动态数据不能索引的问题。
- 结构化数据在内存和交换传输中,其二进制布局需采用占用空间最小的方案,包括压缩,共享结构信息,属性值采用紧凑的数组形式等
- 面向模型存储,由驱动将模型转换为 json 或 xml 等;数据库自动处理新旧模型的差异,支持实时转换或自动升级,驱动也可扫描自定义的转换接口进行升级;提供数据库层面的字段过滤;
- 不限层级的递归引用查询和过滤判断
- 支持在数据库层面或驱动层面进行字段数据的预处理(如,去除空白等),预处理函数可动态或静态设置,在模型中声明
- 支持回滚到指定的时间点,从该时间点开始重新写入新的数据。实现上依然不对已写入数据做删除或覆盖,在新的库指向前一个库的衍生点即可
- 可从任意变更位置衍生出分支,用于测试等需求,避免大量的数据迁移
- 读写过程异步且互不干扰,读数据时,正在写入的以及在写队列中的数据将被合并到返回结果中(不好,容易产生幻影数据)
- 从任意节点均可获取到集群的全部节点,采用响应式方式推送节点更新等信息,驱动端根据连接情况自动切换连接节点,客户端与服务端采用 http3 协议连接以避免节点变动时的重建连接
- 水平扩展时在后台自动同步已有数据,但不影响新增节点增加新的数据,即,读写与同步互不影响。若读数据时,节点的数据未同步完成,则将请求转发到数据已同步的节点
- 仅保持较小的恢复日志(及时刷入前面的数据)以提升恢复速度
- 数据受损后,能够尽可能恢复尽可能多的数据
- 所有的查询(含子查询,并以 join 方式重构查询,可重构为多级视图)均生成物化视图(自动建表,关联表更新时自动刷新物化视图),也可指定创建临时视图。查询中的多个过滤条件可在物化视图之上进行并行过滤,再将结果按 or 或 and 进行合并
- 所有数据以二进制方式存储,底层存储不区分数据类型。数据类型在返回结果时再做转换,转换包括类型转换和函数处理等
- 存储层做数据去重、排序和压缩,视图层建立数据与模型的映射,每个字段仅引用数据的位置即可
- 可存储任意大小和类型的文件,自动为文件内容建立全文索引(可识别多种格式),大文件切割为块存储,创建内容寻址标识,文件内容去重,记录修订历史,可映射(部分或全部,以过滤结果为准)为本地文件直接读写
- 支持树形结构数据:https://segmentfault.com/a/1190000004672312#articleHeader5 (可以支持树形结构的视图并提供相关的查询和统计函数)
- 以实现语言作为查询语言,不创造新的语言。如 lisp 那样,为查询提供专属的执行环境,可避免破坏性(威胁系统和数据的)操作。以
collection stream
机制执行数据查询和过滤 - 数据类型即为一类数据的集合,理论上都是可以枚举的,只是有些类型的集合量为无穷大;结构体(
Record
)也是一种类型,定义数据结构就是新增一种类型的数据; - 数值仅有整形和浮点型两种,支持任意精度的数值计算,计算方式采用算术运算方式计算,不使用机器计算,避免浮点溢出和精度丢失等问题
- 不同的数据类型涉及不同的操作函数,需对这些操作函数进行打包管理
- 数据关系使用随机字符串作为引用,再对该关系添加名称、别名(列表)、描述等,以便于查看和查询;不同类型的数据拥有不同的关系集合;
- 每一个数据类型实例都有自己的名称和标识,名称可以包含任意字符,展示时显示名称,唯一识别通过标识(自动生成,不能修改,不能指定,全球唯一,可包含空间限定符),数据交换时,必须包含名称(首次交换时必须有)、标识、当前版本
- 数据预处理:在存储前选对数据做预处理,再对结果做后续处理,预处理包括 trim、类型转换等。对
null
的场景,参考Elm
的Maybe
等 - 模型结构,模型属性类型是变化的,需提供自动的数据迁移能力
- 数据交换没有编解码操作
- 树的作用在于规模降级,将数据分散在不同分支,使操作尽在某个分支上进行,避免处理整个数据集合
- 以函数作为最小单元,在函数内可以包含多个处理,仅当所有处理均成功后,事物才是成功的,否则,撤销执行中对数据的变更(即丢弃产生的数据新历史记录)
- 需要考虑批量更新时的性能、互斥、节点同步等问题
- 采用自建的文件系统,有自己的数据组织结构,一般使用独立分区,特定情况下,可以将文件格式化为分区
- 敏感数据处理:以视图方式对敏感数据做脱敏处理,脱敏可以是替换为无意义的字符串,也可以采用随机字符串。在创建测试用的数据分支时,可以采用此方案,将某个版本的生产数据映射至测试库,并用视图向测试环境提供脱敏后的敏感数据
- 通过数据空间(或名字空间?)划分和隔离各类数据,数据空间等同于 MySQL 中的一个 database,数据空间数据可放在某个磁盘分区,或者一个数据空间一个独立的磁盘分区,磁盘分区将格式化为数据库的数据存储格式,各个分区有独立的数据结构和数据元,但支持多个分区存储
- 数据元与数据的结构分离,以引用方式建立属性与数据元的关联。数据结构可随时变更,但数据元只能追加,不能删除,修改或移动
- 支持分级挂载(可卸载)和管理数据,应对父子公司的数据处理需求
- 注册查询结果更新监听,在某个查询对应的结果发生变化时,向监听者发送变更结果,再由监听者更新其缓存数据,从而实现缓存数据的实时更新
- 集群节点之间使用相对时间,每个节点都有自己的时钟,新节点的接入需要获取其他节点的当前时钟,节点重新上线时,需要得到其下线时的时钟与同步时同步节点的时钟间隔,同步节点再将间隔内的数据同步给上线节点。时钟同步时可能需要挂起节点,暂停节点的活动,以避免时钟同步过程中产生时钟差异。被挂起的节点,其时间是不流逝的,也不会感知到时间被暂停了,也就是,节点的时钟就是节点的活动次数,有一次活动,其时钟便加一。节点间的时钟产生差异后,需要及时同步时钟?
- 数据的同步,通过变更历史确定,即,同步是将节点之间的变更历史同步,同步后,节点之间的变更历史记录将保持一致
- 可在数据的索引标识中记录必要的冗余信息,如,数据类型、长度、关联对象标识、在数据压缩区的位置/长度、等,用于快速定位目标
- 采用算术编码做压缩,并以编码结果或者编码结果的 hash 值作为唯一标识?不同数据长度、不同数据类型,划分到不同的数据区,再对数据区的数据做动态压缩(流压缩),新的数据在已有数据的计算结果上叠加计算。在部分解压时,根据记录的数据位置和长度,边解压边判断,不再指定位置的数据直接丢弃,直到到达数据所在位置才开始取数据,并在指定长度后结束解压。压缩区需记录数据真实大小,以此判断是采用全部解压,还是丢弃式解压。数据都是追加,不存在删除和更新,符合流式数据的特征。动态压缩会不断重写磁盘,可按固定块方式存储,超过固定块大小时,则开始新的压缩块,后续新增数据追加到新的压缩块内。
- 原数据为压缩包时,先解压再存储至数据压缩区,读取后,再压缩回原数据
- 数据结构的变更只有新增和废弃两种,修改属于“先废弃后新增”
- 节点加入集群需得到所有节点的许可,许可申请由接入到的节点代理,申请代理节点得到所有已在线节点的许可后,向接入节点返回已得到许可的消息,并附带集群信息,和已在线节点信息,未获批的节点将被拒绝加入。节点信息包括数据同步状态,节点时钟等
- 数据写入时由应用在数据操作代码(发给数据库的即是该代码)中声明要锁定的所有目标数据(可以是过滤器指定范围),再编写对对象的数据变更逻辑。锁定时,即开启事务,锁定需得到所有在线节点的同意,若某个节点(同时只会有一个节点锁定某条数据)已经锁定目标数据,则写入节点(操作请求接收节点)需等待该节点(涉及多条数据时,可能同时有多个锁定节点)的解锁,节点完成解锁后,将最新的目标数据回传给写入节点,写入节点再按照得到的最新数据做后续更新。可独立申请锁定,并在业务处理完毕后显式解锁(通过锁定标识),默认为,锁定与数据操作在相同代码内,若代码内没有主动解锁,则在代码执行完毕后自动解锁
- 数据被删除,仅做删除标记,也不更新关联方的引用,仅在查询时通过标记关联,减少关联查询和数据移动:或者其他不操作关联方的方式
- 每次变更都是向数据库新增一个
层
(layer
),不同层之间的时间戳不同,某个层内涉及的变更数据有多个。在变更后,直接将数据指向最新的层即可,底层修改仅有一次操作。事务完成后,向数据库添加所有操作产生的最后一个层。 RC4
流密码 对称密码- 图片等二进制数据也是有内部结构的,将其(图片自身的像素信息)定义为一种数据,并包含创建时间等扩充的属性
- 支持异常信息国际化,携带变更对象数据
- 按地域、组织结构做分级,父级直接可见子级数据,子级之间数据不可见,按证书链方式,由父级向子级下发证书以用于接入认证和数据加密,从而实现父级对子级数据的解密,但子级之间不能解密数据
- 全文检索的检索词,实际上可以按单字索引其存在位置,再对词内的单字索引位置取交集,得到同时的存在位置,再检查单字在各个位置内是否是挨着的即可。多词组合查询可字词并发查询,再取交集或并集以得到最终结果
- 不同层级负责不同的事务,其处理的数据的复杂度逐级增强、稳定性逐级减弱。也就是在整个进程监督树(
Erlang Supervisor
)中,越靠近根节点,进程所处理的数据越简单,进程的文档性也越强 - 差异,相当于对值求导?
- 在需要所有节点响应,但部分节点未响应时,可采用异步延迟提交,并在用户端提示等待信息
- 有关系的数据要以图形展示才会更清晰直观,需要能够自动识别相同关系的数据并图形展示出来,比如,物体的空间位置移动
- 流式处理,以支持分批次、并行读写数据,避免一次性加载全量数据
- 保持幂等性
- 排序:对于无自动排序特征的数据,支持手动整理和更新数据相对位置(增加前继标识),使得查询结果按指定的顺序返回
- 关系也是一种
Subject
,从意义上包括静态关系和动态关系,前者是主体的属性,后者是主体间的相互作用 - 以结构为核心,而不是以对象为中心。相似即可复用
- 对象之间仅关联是确定的,而对象自身的结构是不确定的,也不需要对关联的目标对象的结构做规范化,只需要目标对象是能够安装确定的规则进行自动识别,并向用户展示即可
- 数据的各种关系决定了数据的所有者、处理形式等,如,数据的创建者往往为数据的所有者,或者根据创建者所在的组织,可以确定数据为其所在组织所有。所以,数据搜集需要自动添加内在的数据关联,也需要在搜集和管理过程中不断变更数据结构(通过用户界面操作),不断调整数据关联。这需要数据库能够应对频繁的数据结构变更和数据关联变更,能够处理任意层级和任意复杂度的数据关联,并且对任意规模的数据量都能以恒定的效率完成查询和变更
- 以 tuple 结构存储数据结构(含数据创建时间和创建者等数据)和数据自身,从而避免对数据属性的占用:
{%{definition: %{...}, creator: %{...}, created_at: ..., updated_at: ...}, %{id: ..., ...}}
- 提供对不同时间点的变更的对比功能,以确认和排查变更是否存在问题,并及时做出恢复处理
- 批量更新的数据具有一些相同的变更信息,如更新时间,可以共享,避免重复存储
- 底层按数据类型和数据长度分区存储,结构数据之间共享相同类型的底层数据。结构数据有唯一标识,引用版本列表,版本引用共享的结构信息和按结构排列的数据信息,数据信息仅记录与上个版本的差异,同结构的数据可以共享基础的数据信息,也就是在同一基础数据上做版本变更
- 自带枚举类型,实际按数字存储,返回结果前还原;字符串等,在底层都通过数字索引建立映射关系
- 任意层级的结构都可以通过路径唯一标识进行引用,使其变为只有一个层级的结构,也就是结构坐标也有唯一标识
参考资料
附录
- 理论手稿
- 算数编码实现