实时图数据库中的数据是如何存储的?
显然,不止一种方案可以实现图数据库的存储。无论何种方案,将数据存储到图中,至少有两个部分:
- 顶点的存储
- 边的存储
当然,以上还分别包含点和边的属性等字段的存储。存储的方案可能有:
· 点、边分开存储
· 点、边合并存储
· 点、边、属性分开存储
· 内存存储加速结合外存持久化存储
上图中给出的图数据结构是点、边及属性的“一体化”存储设计方案,橘黄色的是顶点,而蓝色部分是起始顶点的属性,以及边和边对应的属性。这一数据存储模型非常类似谷歌的分布式存储系统(Bigtable),一种典型的宽列存储(wide-column)。这类数据模型设计的好处是:
· 对图遍历来说,这是一种边优先(edge-first)的数据模型
· 数据模型可以用最合适的数据结构进行优化,以获得最佳的遍历性能
· 它将使分区(或分片,取决于你如何看待这个问题)更加容易
· 还有很多其他优势,就此不展开拓展描述
数据的批量加载分几步?
将数据加载到图系统分为三个阶段(这里我们设计并增加了一个内存计算引擎层,来实现所谓的纯实时图计算与查询):
· 第一阶段:初始加载源数据到数据持久层;
· 第二阶段:数据存储后台使用高度并发的加载机制加载到图计算引擎中;
·第三阶段:运行时动态数据的更新,操作包含增删改查(CRUD)的功能,在第一和第二阶段也可以进行这些操作,用于保证计算引擎和持久数据层中的数据一致。
注:实时更新意味着有大量的飞行数据,它们不在内存中,这些变化的数据可能有时间戳,还有可能会引发查询此类数据,例如:证券交易所可能会在图数据库中触发这样的查询:找到所有账户在过去30分钟里与“ABCD”股票操作的交易活动,是否存在可疑的行为(组成犯罪链条或数据上有关联)?
注:如果发现任何两个账户对同一支股票进行配对操作,一个买另一个卖,这种行为将被视为可疑!
图系统如何对大图进行分区?
对一长大图进行分区(分片)可能是一项艰巨的工作,传统上,即使不是完全不可能,也非常具有挑战性。即使对一个图进行了分区,由于子图之间的依赖关系,整个集群系统可能会面临性能指数级降低的风险。
但是,有了上面所示的图数据库数据建模,事情突然变得容易起来,至少有以下4种方法来划分一个图:
· 暴力分区 :暴力划分非常类似随机划分,它基本上忽略了嵌入的图结构(从人类的角度来看,图可能包含形成社区的子图,使得某些子图非常密集,而其他区域非常松散,因此给了划分图的机会),并且只需在任意两个相邻行之间进行剪切(见下表)。
·智能分区:智能分区更智能,因为它使用AI算法来检查原始数据(在数据持久层中),并了解是否有拓扑结构最为稀疏的社区,在现实世界的场景中,没有完全连接的图(意味着根本没有分区的机会,否则,分区的子图是完全相互依赖的,使得任何图的运算都是超慢的…,因此只能在任意两个相邻的社区只是松耦合的地方进行切割。例如,只有少数边连接两个子图,将子图A中的顶点标记为出站顶点,并将子图B中的连接顶点标记为入站顶点。在这个划分之后,如果任何图遍历操作到达出站顶点或连接顶点,则操作可以继续进入另一个子图,并且两个子图的结果可以缝合在一起。智能分区算法又称为:最小割点算法,它被誉为图可扩展性领域的瑰宝。
·基于时间序列的分区:这迎合了数据模型包含时间序列数据的场景,例如,有10亿个账户,每周记录100亿个事务,如果您在过去12个月内查找账户组之间的连接,那么创建一个包含有52个子图的图集是非常有意义的。集群中的每个计算节点(或者是一个小的计算与存储集群)捕获1周的事务数据。每个查询都可以发送到所有52个子图中所对应的一个刀哥子图上进行执行,最后合并(聚合)进行最终结果展示。
·用户定制分区:按照某种用户数据中隐含的行为模式来进行逻辑分区(当然也包含时序图谱分区)。这种分区方式往往在真实业务场景中是最合理的,毕竟人工智能,有多少人工,才有多少智能,除此以外,把分布式HTAP架构交给嬴图数据库就好。
ultipa.partition.status=[true|false]
ultipa.partition.type=[brutal-force|time-series|smart|customized]
ultipa.partition.subgraphs=[1-N]//1 stands for no-partitioning, N is the # of partitions
ultipa.partition.master=[ip-address|null] // master-node ip-address.
ultipa.partition.subgraph-ip=[ipaddress1,ipaddress2,… … paddressN]
上面的配置参数控制图数据库分区的方式(虽然不是一个完整的列表)。
注:除分区外,还需提出以下问题:
· 与其使用分区架构设计,不如考虑多图(图集),类似于关系型数据库中的多表,为什么图数据库不可以有多张图呢?那么这些图之间可以形成某种联动,图与图之间显然可以形成更好的集群规模的高可用性和并发性。关于多图,我们在后面的章节中会有详述。
. 另,构建一张巨无霸大小的图的意义何在?很多互联网公司背景的公司或团队的图数据库的设计一味的鼓吹千亿、万亿量级的图,那么请问,什么样的图的实体会需要千亿到万亿量级呢?商品、用户?全世界才70亿人、100亿部移动设备,也不可能全世界所有的人和手机都在一张图上。而且很多时候,很多所谓的实体,都可以以属性的方式存在,例如地点、时间、机构、POS机等等。很多知识图谱公司,可能是出于底层设计的缺陷,只能逻辑上处理1张图,但是实际上多张图(图集)配合起来才是更加高效和合理的设计思路。
高可用性,可扩展性和其他高级主题
高可用
图数据库系统提供和实现高可用性的方法有多种,它们是:
· 简单的双机集群系统(HA):简单而标准的HA设置非常简单,主服务器和辅助(备份)服务器,各自有100%的图系统。它们保持同步,任何改/添/删操作都通过双机集群系统的体制进行,一旦主服务器关闭,备份服务器则毫无延迟的被激活。这种双机集群系统(HA)也叫热备系统。
· 主从服务器集群系统(MSS或RAFT):一个主服务器和多个从服务器组成一个由多(>=3)台服务器组成的集群,它们都有读的权限,但只有主服务器可以进行改/添/删操作,以保证数据一致性。它非常类似经典的MySQL数据库的主-从双机集群系统的设置。
· 分布式高可用(DHA):>=3个实例构成的分布式、高可用集群。这个模式也可以看做是增强型的Raft,正常情况下会选举出一个leader和多个followers,在leader掉线条件下,剩余的示例会选举出下一个leader来承载读写操作,当无法选举出leader的条件下,剩余的所有实例会继续承载只读的操作,直到leader重新上线后,再同步之前的delta数据。区别于原生的RAFT协议的地方在于,原生的设计中采用的是在线热备份,但是任何时刻只有1个实例节点在服务客户(另外2个只是在线接受数据同步,并没有提供服务输出!)。在高可用模式中,所有的示例都可以接受图计算、查询请求,并能实现多势力之间的数据同步,为了简化系统的复杂度,正常情况下只有leader接受图数据的更新服务(例如对点、边的增删改操作),但是图计算天然的复杂性和特殊性决定了所有实例都需要有写数据库的能力,例如图算法操作全图K-hop查询会涉及到回写到数据库中,那么当follower实例接受到这个请求后,它会在计算完毕后,回写到持久化层,并通知其他leader和followers来同步这一操作。在上面描述的架构设计之上,继续水平延展集群就可以支持超大规模的弹性集群,可以进行全集群范围内的动态更新以及分布式计算与存储,但是这种大规模的集群显然架构的复杂度,系统稳定性及可维护性会是一个显著的挑战,最终会变成客户需要承受的高昂的费用。因此增强型的RAFT分布式集群在相当长的时间内,是客户更容易接受的、务实的解决方案。
· 容灾式分布式高可用(DR-DHA):需要支持同城、异地多数据中心的灾备。与上面的DHA模式类似,但是显然集群的规模更大,跨数据中心的通信因为时延更大而让数据同步显得更为复杂。对于大型企业用户,特别是金融用户而言,这个相对复杂的方案是必要的。
ultipa.ha.status=[true|false]
ultipa.ha.type=[simple|mss|mms]
ultipa.ha.mss.slaves=[1-3] // up to 3 slave nodes.
ultipa.ha.mms.count=[1-4] // total number of masters in the cluster setup.
有2种方法来管理集群系统、可扩展性、故障恢复和其他数据备份操作:
· 管理控制台:管理员控制台上的更改将记录到基础配置文件中,相关服务(和正在运行的实例)需要以顺序和预定义的方式刷新(关闭,使用新配置重新启动)。
· 服务器端配置文件:对于管理员和敢于冒险的开发人员来说,也可以直接修改配置文件,但通常我们不建议这么做,尽管这样做听起来很硬核,但是风险也更高 – 因为没有控制台所提供的质检和纠错服务。
可伸缩性
考虑到商用PC服务器架构和云计算的兴起,横向扩展比纵向扩展越来越受欢迎。
许多开发者认为(有合理的逻辑,但忽略了现实)水平缩放绝对是可行的,但忽略了大多数图形数据集还不够大,不足以需要水平伸缩的事实。
我想非常具体的说:
· 如果你只有10亿条边,在可预见的未来里只有10亿条边的增长,那么你无需为100亿条边的容量做准备,并且一台高配置的机器就可以存储10-20亿条点边的图数据库,为什么还要考虑水平扩展呢?
. 很多研发人员被互联网洗脑到相信唯有水平分布式才代表着系统架构先进性,而忽略了水平分布式系统的维护成本与复杂度以及图计算、图数据库的特点 – 图数据库的本质是面向图的拓扑结构进行价值抽取与模式识别,盲目的分布式除了让系统的性能一塌糊涂,并没有带来任何实质的价值!
如果上面列出的内容对你有意义,那么我们可以继续讨论可伸缩性,并提供两种途径:
· 垂直扩展:是的,单机节点可以非常强大,并且考虑到今天的计算机结构和处理能力,一台2CPU,32核的主板性能比4节点集群(每个实例1个CPU,8核)强大很多。只要有意识的简单升级你的硬件,你就能获得更好的系统性能,特别是在图系统中!通常内存越大,并发计算的性能越高,就能大大提高系统的性能和容量(当然,前提是你的图数据库、图计算软件系统是支持并行计算的!遗憾的是,很多系统都不支持这种高并发计算,例如JanusGraph、 Neo4j等等)。例如,你有一台CPU功能强大的服务器,但是只有64G内存,那么你无法存储100亿条边的数据,现在考虑把内存升级至400G,为达到更高的性能,尽可能使用更高吞吐量的内存。对于强调整体性(全局观)的图计算平台而言,这种扩展基础上的HA配置,要在性能、吞吐率甚至集群健壮性上远好于多节点集群。
·水平扩展:这个问题曾经在前面介绍分区的章节涉及到一部分,一张大图可以被分解为多(通常1–>2–>4–>8–>16)个子图(切图或分片的概念),每张子图存放在一个物理单机中,最理想的情况是这些单机有相同的硬件和软件(操作系统和字典库)配置,来避免部署和运行错误。还有其他一些高级主题需要讨论,例如每台单机是否可以安装成双机集群系统(HA),使用热备份节点,以便在主节点脱机时激活备用节点,从而确保集群范围的操作不会中断。在商用的业务场景中,水平扩展更多的是以多图互动(联动或并发· 处理)的方式来进行,然后配合以RAFT或其它高可用分布式及支持事物一致性的通讯协议来保证集群中的多个节点(实例)中保持(交易)数据的一致性。
ultipa.scalability.status=[true|false]
ultipa.scalability.node-cpu=[1-N] //if N is set to be larger than actually-present,the largest possible CPUs are utilized.
ultipa.scalability.cpu-thread=[1-N] //-ditto
故障与恢复
有两种类型的故障:
· 实例故障:这是更严重的故障类型,它意味着运行实例(最糟糕的情况是,整个双机或集群系统)离线,通常情况下实例会自动重启。如果有热备用实例,它将起到自动接管主实例的作用。但如果没有,这个问题需要一张IT热票,并尽快解决。
· 事务失败:导致事务失败的原因有很多,因为事务失败是ACID类型的,如果它失败了,必须发生某种回滚以确保系统范围内的状态是同步的,否则问题最终会变得更大,通常失败会记录日志供开发人员查看,如果比较复杂,则应发出IT支持通知单。否则,您只能重新运行事务,如果问题不存在,则可能是错误警报。整个事务级的失败相当复杂,或许需要整章整节来讨论这个主题。
下面的配置参数表明事务日志被打开(用于跨集群的实例同步和重放),允许的最大同步等待时间为10秒(大约0.16分钟)。
ultipa.trx.logging=true;
ultipa.trx.max-sync-latency=10; //The value can be a float,with highest precision to micro-second level,such as 0.000100,which means 10 microseconds latency to lerance.
我们上面讨论的所有配置和设置,大体假设了所有图服务器运行在同一个数据中心,毫无疑问,所有的服务器需要连接到同一个高速骨干网,以实现非常小的网络延迟(用于状态和数据同步)。
现在,要解决的一个大问题是:如何支持跨数据中心灾难恢复?
以双数据中心灾备为例,至少有两种方案:
上图的方案采用的是准实时的把主集群的数据同步到异地从集群。当主集群发生故障时,业务可以切换至从集群。这种方案中两个集群间采用日志来异步复制(log replication),这种方案可能在极端情况下会出现数据不一致性(数据短暂的丢失)。
下图中采用的是单集群跨双中心,每个中心有3个副本,任一中心发生灾难,业务连续性虽然可能会被短暂影响,但是因为有多副本数据强一致性的协议机限定,数据不会丢失,并且可以通过(维护人员来手动操作)降低副本数量来快速恢复业务 – 例如在第二个中心中以3副本拉起业务。
在构建业务连续性计划和灾难恢复计划(BD/DR)时,需要考虑的问题(和假设):
· 设计业务连续性和灾难恢复计划(BD/DR规划)
· 建立必须恢复系统和进程的时间框架。
·评估您的IT基础设施,您的数据中心(或云)合同并了解其局限性。
· 评估图数据库在整个IT中的优先级
·实施业务连续性和灾难恢复计划(BD/DR)。
· 通过演习和模拟演习测试真实情况。
·修改你的计划和实施。
考虑前面提到的要点,下面是图集群中用于跨数据中心灾难恢复的(可选)设置参数列表:
ultipa.disaster-recovery.status=[true|false] //if false is on,all other options are ignored.
ultipa.diaster-recovery.log-cache=[1-N] //Minimal cache size=1MB,N shouldn’t be setup as a very large integer,keep it under 1000MB for now and for small inter-datacenter bandwidth.
ultipa.disaster-recovery.latency=[0.1-N] //The value is between 0.1 second to N seconds.
//The below configuration lists all data-centers’master nodes ipaddresses.
ultipa.disaster-recovery.master-ip=[ipaddress1,ipaddress2…] //Usually there are 2 ip-addresses,the sequence is irrelevant,one ipaddres is the primary datacenter’s graph node ip,and the other is for the backup datacenter’graph node ip.
·END