导读: 作为一种基础的数据结构,图数据的应用场景无处不在,如社交、风控、搜广推、生物信息学中的蛋白质分析等。如何高效地对海量的图数据进行存储、查询、计算及分析,是当前业界热门的方向。本文将介绍字节跳动自研的图数据库ByteGraph及其在字节内部的应用和挑战。

本文将围绕以下五点展开:

  • 了解图数据库
  • 适用场景介绍举例
  • 数据模型和查询语言
  • ByteGraph架构与实现
  • 关键问题分析

    --

01 了解图数据库

目前,字节内部有如下表三款自研的图数据产品。

1. 对比图数据库与关系数据库

图模型的基本元素包括点、边和属性。举例:张三的好友所在的公司有多少名员工?传统关系型数据库需要多表join,而图作为半结构化数据,在图上进行遍历和属性的过滤会更加高效。

2. 什么是图数据库?

近五年来,图数据库在领域内热度上升趋势非常明显,各个大厂与开源社区都推出了自己的图数据库。用户规模比较大、有一定影响力的查询语言包括Cypher、Apache开源项目的Gremlin等。从集群规模来看,过往有单机数据库,现在大多图数据库都具备分布式能力,这就需要考虑数据的防丢失问题、主副本之间的一致性、多台机器数据上的shard问题。

部分图数据库把图数据库与图计算引擎二者合并在一起,目前字节内部采用的暂时分离的两套系统。

--

02 适用场景介绍举例

1. ByteGraph适用的业务数据模型

ByteGraph初始立项是在2018年,主要目的是对头条的用户行为及好友关系进行存储来替换Mysql;2019年6月承接对抖音用户关系的数据存储任务,接着在字节内部各种微服务重承接了相关业务。

2. 已上线业务场景分类

目前有1.5万台物理机,服务于600+业务集群。

--

03 数据模型和查询语言

1. 有向属性图建模

目前来看,图数据库通常有两大类,一种是属性图,另一种是RDF图。属性图在节点和边上有属性表,从某种角度上讲,它仍带有关系数据库的基本特性,类似表结构的形式,实际是采用Key-Value形式来存储的,如用户A关注了用户B,用户C点赞了某个视频等,则会把关注的时间、点赞时间、评论的内容等以不同的有向边存储在属性图中,用图来描述业务逻辑。

2. Gremlin查询语言接口

选用Gremlin语言是考虑到之后方便对图计算、图数据库二者进行融合,本身是图灵完备的图遍历语言,相较于Cypher等类SQL语言,对于善用Python的数据分析师更容易上手。

举例:写一条用户A所有一跳好友中满足粉丝数量大于100的子集。首先定位用户A在图中的点,其次求一跳查询中的所有邻居,判断入度邻居整体数量是否大于100,拉取满足条件的所有用户。

--

04 ByteGraph架构与实现

1. ByteGraph整体架构

ByteGraph整体架构分为查询引擎层(Graph Query Engine,下文简称GQ)、存储引擎层(Graph Storage Engine,下文简称GS)和磁盘存储层三层,整体上计算和存储分离,每层由多个进程实例组成集群。

2. ByteGraph读写流程

拿“读流程”举例,请求获取用户A的一跳邻居。首先一个查询进来后,从client端随机挑选一个查询层响应,对应到GQ2上,获取对应的数据存放的位置是哪一台机器,接着把请求给到GS1,检查数据是否在该层以及是否为最新数据,如果不在则去KV store把所需数据拉取至GS1 缓存中。

3. ByteGraph实现:GQ

GQ同MySQL的SQL层一样,负责查询的解析和处理,其中的“处理”可以分为下述三个步骤:

  • Parser阶段:利用递归下降解析器将查询语言解析为一个查询语法树。
  • 生成查询计划:将Parser阶段得到的查询语法树按照查询优化策略(RBO&CBO)转换为执行计划。
  • 执行查询计划:理解GS数据分Partition的逻辑,找到相应数据并下推部分算子,保证网络开销不会太大,最后合并查询结果,完成查询计划。

RBO主要基于Gremlin开源实现中的自带优化规则、针对字节应用中的算子下推、自定义的算子优化(fusion)三大规则。CBO本质上是对每个点的出入度做统计,把代价用方程量化表示。

对于不同支持场景使用不同策略,图分区算法的选择与workload强相关,图分区算法能有效减少网络通信次数。

  • Brute force哈希分区:即根据起点和边的类型进行一致性哈希分区,可以大部分查询场景需求,尤其是一度查询场景。
  • 知识图谱场景:点、边类型极多,但每种类型边数量相对较少,此时根据边类型进行哈希分区,将同种边类型数据分布在一个分区内。
  • 社交场景:更容易出现大V,利用facebook于2016年提出的social hash算法,通过离线计算尽量将有关联的数据放置在同一分片内,降低延迟。

4. ByteGraph实现:GS

  • 存储结构

单个Partition定义为一个起点+一种特定的边类型扇出的一跳邻居。在GS中,将一个Partition按照排序键(可显式设置或系统默认维护)组织成Btree。每棵Btree都有独立的WAL序列,独立维护自增logid。这种设计有利于支持GNN场景,做分布式采样。

Edge Page、Meta Page分别是位于Btree中的叶子结点、非叶子结点(充当index作用),分别用于存储图中的边数据和指向子节点的Key。Meta page长度是固定的,但是一个meta page会放多少edge page是可配的,通常配置为2000一片。如上图,Partition在磁盘中将每个page都存储为一个独立的键值对(下文简称KV対)。meta page的key是起点+边类型,edge page的key存在meta page中实现对特定edge page的查找。

单机内存引擎整体采用hash map的结构,partition和page按需加载到内存中,根据LRU策略(Least Recent Used),swap到磁盘;某个page被修改后,WAL同步写到磁盘,page会插入到dirty链表中,考虑当前机器状态,异步写回。

  • 日志管理:单个起点+边类型组成一棵Btree,每个结点是一个KV对。

每棵Btree单一写者,防止并发写入导致不完整;每棵树都有独立的WAL日志流,且写入请求处理流程中只写入WAL,并修改内存中数据,compaction时再将数据落盘,解决由于每个KV对可能由多条边组成而导致的写放大。即使内存数据丢失,仍可通过更新后的logid在磁盘上进行WAL的查询并写入。

  • 缓存实现:根据不同场景及当下cpu的开销有不同策略。

图原生缓存:相对于Memcached等直接缓存二进制数据而言,能更好的理解图的语义,并支持一度查询中的部分计算下推功能。

高性能LRU Cache:支持缓存逐出,且逐出的频率和触发阈值可调;采用numa aware和cpu cacheline aware设计,提高性能;支持Intel AEP等新硬件。

Write-through cache:支持多种与底层存储同步数据的模式,可以每次写入或定时落盘;支持定期与底层存储校验数据,防止数据过旧;支持负缓存等常见优化策略。

缓存与存储分离:当数据规模不变、请求流量增大的情况下,缓存与存储分离的模式可以快速扩容缓存以提高服务能力。

--

05 关键问题分析

1. 索引

  • 局部索引:给定一个起点和边类型,对边上的属性构建索引

    特点:边上元素皆可做索引项,能够加速查询,提高属性过滤和排序性能;但会额外维护一份索引数据,与对应的原数据使用同一条日志流,保证一致性。

  • 全局索引:目前只支持点的属性全局索引,即指定一个属性值查询出对应的点。

    数据存储在不同机器上,索引数据的一致性使用分布式事务解决。

2. 热点读写

  • 热点读

场景举例:某热点视频被频繁刷新,查看其点赞数量。

应用机制:GQ层采用多个bgdb并发处理同一热点的读请求,单节点缓存命中读性能可达20万以上;GS层采用copy on write(即先拷贝,再写入并替换)保证读写、读读均可并发。

  • 热点写

场景举例:某热点视频短时间内被疯狂转发、点赞。

问题溯源:单机cpu使用率被拉高,磁盘写入iops有上限,当客户端写入qps>磁盘iops时,就会发生请求排队。

应对机制:采用group commit机制,即将多个写入请求组合至一个batch写入KV,再批量返回,降低磁盘层iops的上限。

3. 轻重查询资源分配

将轻重查询的资源池分离,轻查询走light线程池,负责数量多的小查询;重查询则走heavy线程池,负责数量少的重查询。当heavy线程池空闲时,轻查询也可走。

4. 高可用

城域网双机房,如国内的两个机房,延迟较低。follow一写多读策略,备机房把写流量转入主机房,只有主机房会把WAL更新到KV存储上。

广域网容灾部署,如新加坡和美国的两台机器,延迟较高。follow了mysql的思想,每次写入在本地写入成功后,会被转化为binlog,再发送给其他单元;并通过hybrid logical clock保证各单元对于一条边的操作顺序一致性。

5. 离线在线数据流融合

导入存量数据、写入在线数据,将二者集成在公司内部数据平台进行离线数据分析,具体流程如图。


今天的分享就到这里,谢谢大家。

本文首发于微信公众号“DataFunTalk”。

陈宏智:字节跳动自研万亿级图数据库ByteGraph及其应用与挑战的更多相关文章

  1. 腾讯自研万亿级消息中间件TubeMQ为什么要捐赠给Apache?

    导语 | 近日,云+社区技术沙龙“腾讯开源技术”圆满落幕.本次沙龙邀请了多位腾讯技术专家围绕腾讯开源与各位开发者进行探讨,深度揭秘了腾讯开源项目TencentOS tiny.TubeMQ.Kona J ...

  2. 字节跳动已经10万人了?渣本双非Android程序员怎么上车?

    字节跳动已经 10 万人了? 是的,在 2020 年字节跳动的员工总数从 6 万蹿到 10 万,平均每个工作日就有 150 人在办理入职,加入字节跳动全球超过 240 个办公点. 更有统计,在总部北京 ...

  3. Kafka万亿级消息实战

    一.Kafka应用 本文主要总结当Kafka集群流量达到 万亿级记录/天或者十万亿级记录/天  甚至更高后,我们需要具备哪些能力才能保障集群高可用.高可靠.高性能.高吞吐.安全的运行. 这里总结内容主 ...

  4. 杂文笔记《Redis在万亿级日访问量下的中断优化》

    杂文笔记<Redis在万亿级日访问量下的中断优化> Redis在万亿级日访问量下的中断优化 https://mp.weixin.qq.com/s?__biz=MjM5ODI5Njc2MA= ...

  5. 如何基于MindSpore实现万亿级参数模型算法?

    摘要:近来,增大模型规模成为了提升模型性能的主要手段.特别是NLP领域的自监督预训练语言模型,规模越来越大,从GPT3的1750亿参数,到Switch Transformer的16000亿参数,又是一 ...

  6. 腾讯万亿级分布式消息中间件TubeMQ正式开源

    TubeMQ是腾讯在2013年自研的分布式消息中间件系统,专注服务大数据场景下海量数据的高性能存储和传输,经过近7年上万亿的海量数据沉淀,目前日均接入量超过25万亿条.较之于众多明星的开源MQ组件,T ...

  7. 万亿级KV存储架构与实践

    一.KV 存储发展历程 我们第一代的分布式 KV 存储如下图左侧的架构所示,相信很多公司都经历过这个阶段.在客户端内做一致性哈希,在后端部署很多的 Memcached 实例,这样就实现了最基本的 KV ...

  8. js万亿级数字转汉字的封装方法

    要求如图: 实现方法: function changeBillionToCN(c) { // 对传参进行类型处理,非字符串进行转换 if(typeof(c) != "string" ...

  9. 【HBase调优】Hbase万亿级存储性能优化总结

    背景:HBase主集群在生产环境已稳定运行有1年半时间,最大的单表region数已达7200多个,每天新增入库量就有百亿条,对HBase的认识经历了懵懂到熟的过程.为了应对业务数据的压力,HBase入 ...

随机推荐

  1. nfs客户端的一次处理

    为什么要说这个呢,由于节点环境不一致,导致在重建pod时,我们暂且叫该pod为 cxpod,cxpod所在宿主机出现了问题现象如下:一.cxpod始终处于创建中 ContainerCreating [ ...

  2. kubectl get node -n wide --show-labels

    集群环境:1.k8s用的是二进制方式安装2.操作系统是linux (centos)3.操作系统版本为 7.4/7.94.k8s的应用管理.node管理.pod管理等用rancher.k8s令牌以及ma ...

  3. instanceof 和类型转换

    instanceof 和类型转换 instanceof 判断a 和 B 类型是否相似 公式 System.out.println(a instanceof B); //true / false 编译是 ...

  4. 使用Visual Studio 2019开发Qt程序

    安装Qt 如标题,你首先需要到 http://download.qt.io/ 去下载并安装Qt,并在引导下安装MSVC组件(这里不做过多解释) Visual Studio 2019 配置 打开VS20 ...

  5. 论文阅读 Continuous-Time Dynamic Network Embeddings

    1 Continuous-Time Dynamic Network Embeddings Abstract ​ 描述一种将时间信息纳入网络嵌入的通用框架,该框架提出了从CTDG中学习时间相关嵌入 Co ...

  6. HCIE笔记-第三节-数据链路层与MAC地址

    如果数据进行封装时,基于E2或者802.3标准,此时我们称之为是一个以太网数据帧. E2和802.3作用:定义帧头和帧尾的格式. 以太网是现在局域网组网的唯一标准. 数据:对于下层的每个层级而言,上层 ...

  7. 2021.12.10 P5041 [HAOI2009]求回文串(树状数组求逆序对)

    2021.12.10 P5041 [HAOI2009]求回文串(树状数组求逆序对) https://www.luogu.com.cn/problem/P5041 题意: 给一个字符串 \(S\) ,每 ...

  8. Envoy熔断限流实践(二)Rainbond基于RLS服务全局限流

    Envoy 可以作为 Sevice Mesh 微服务框架中的代理实现方案,Rainbond 内置的微服务框架同样基于 Envoy 实现.本文所描述的全局限速实践也是基于 Envoy 已有的方案所实现. ...

  9. java中的stream是啥?

    函数式编程的执行是惰性的,按顺序真正执行的时候才会执行相应的代码.方法: 函数式编程是安全的,用的是monad架构 1 public class StreamTest { 2 3 public sta ...

  10. Java汽车租赁系统[源码+数据库]

    系统名称 Java汽车租赁系统   (源码在文末) 系统概要 汽车租赁系统总共分为两个大的模块,分别是系统模块和业务模块.其中系统模块和业务模块底下又有其子模块. 功能模块 一.业务模块 1.客户管理 ...