在数据库工程团队实习期间,我花费了上个暑假的时间分析了Facebook的数据库工作负载(workload)并帮助开发了一款称为LinkBench的数据库性能测试工具。这个周我们很荣幸的将LinkBench发布到了 GitHub上,并希望它能够成为每个需要进行性能测试和数据库调优工作的开发者手中的利器。
Facebook社交图谱(social graph)和MySQL
MySQL作为公司基础架构的重要组件,早期就被Facebook用于存储像文章,评论,赞(likes)和页面之类的数据。
我们展现数据的一种方式就是社交图谱(social graph),其中的对象如人(people),文章(posts),评论(comments)和页面(pages)是通过节点间不同的关系类型(模型) 相互关联(图中的有向边-directed edges)的。不同的关联关系类型可以表示好友关系(friendship between two users),用户喜欢某个对象的关系(user like another object),还可以表示文章属主(ownership of post)关系等等。
为什么需要一款新的数据库性能测试工具?
过去的5到10年里,数据库领域又迎来了一次创新的高潮,像NoSQL和NewSQL已经成为了关系数据库(relational databases)的强力竞争者。与此同时硬件领域也在迅速地发展,固态存储设备和多核CPU已经成为业界的主流,能够为数据库提供巨大的性能提升。虽然我们已经能够通过让MySQL使用FlashCache来发挥出固态存储设备的优势,但是对基于固态存储的数据库优化还有很多工作要做,只有这样才能最大限度的发掘出硬件的性能。
这些改变对Facebook来说意味着什么?首先,它意味着在提高响应速度的同时我们有更多的机会来提高数据库基础设施(infrastructure) 的效率,如降低能源的使用和硬件的开销。其次,它意味着我们需要对那些为解决Facebook负载而即将上线的数据库系统在适应性 (suitability)和性能方面做一次系统的评估。
MySQL很好地兼顾了灵活性、性能和易于管理的特性,但是我们的数据库项目团队仍不断地探索在MySQL中存储社交图谱数据的其他方法。起初我们使用一些开源的性能测试工具来评测数据库系统。然而,数据库性能测试的黄金法则是要在真实的产品负载情况下去测试系统的性能,但是一般的工具都达不到这样的要求。当需要对Facebook基础设施中的某个重要组件进行调整时,我们需要理解在生产负载的情况下数据库系统是如何运作的。
并且我们认为对于其他构建于数据库和社交应用之上的社区来说它们也能够从基于数据存储、检索社交网络和其他具有图谱结构数据的性能评测中获益。对于那些迅速发展、拥有海量数据和丰富的数据模型的应用来说,它们对数据库系统的需求都是各不相同的,但是用于测试这些系统负载的性能测试工具却没有几个。
LinkBench通过生成(replicate)混合了数据模型,图谱结构和请求等数据来填充数据库的方式实现了对存储着社交图谱的MySQL进行负载测试的目标。LinkBench是一个用于生成图(graph-serving)的性能测试工具,而不是处理图(graph-processing)的测试工具--区别在于前者会模拟在一个交互式的社交应用中的那些具有事务性的动作(transactional workload),而后者只是模拟动作的流程(analytics workload)。这个测试工具不是用于解决图的社区发现问题(find graph communities)或图的切分问题(graph partitioning),而是用来实时地查询并更新数据库中的图谱。例如,对于图的查询比较常见的形式就是找到所有来自节点X并且是A类型的所有的边,而更新操作就是插入、删除边或者更新图中的节点或边。举个更新操作的例子,如“从user4插入一个好友关系的边到user63459821”。
理解Facebook社交图谱的工作负载
我实习的大部分时间都用于分析社交图谱的数据和数据库查询时的负载,因而我提取了许多LinkBench可以用来对负载进行建模的关键参数。
LinkBench使用的一个特别重要的属性就是出度分布(out-degree distribution),它控制图中每个节点的出度。出度在过去人们研究过的许多网络中像人际关系网或网页间的链接都遵循着幂律分布(power- law distributions),这对于包含着各种节点类型的社交图谱也同样适用,如下图所示:
LinkBench也需要模拟在生产环境下对数据库的查询操作。Facebook网站和手机应用所使用的数据大部分来自于内存缓存,只有所有写操作和小部分读缓存缺失(cache-miss)情况下才会使用到MySQL。Facebook的工作负载主要是以大量的读操作为主的,因此即使在缓存命中率很高时,读操作缺失(read miss)也远大于写操作的。
通过将数据库查询划分为针对关系(边)和对象(节点)的许多小的核心操作,我们就可以逐个地分析在生产数据库环境下对社交图谱的每个操作的性能了。下面的表列出了用于保存或查询图谱时所对应的查询或更新操作。
下面的图展示了在生产环境中的某个数据库实例上不同的操作随着时间的推移而产生的负载变化。从图中可以看到对于边的操作和读操作,特别是边界扫描 (edge range scan)会给系统带来极大的负担。举个边界扫描的例子,如“按最早到最近的时间顺序找出某个文章的所有评论”或“找出某个用户的所有好友”。
在真实环境中的MySQL实例上,对社交图谱的各种操作随着时间的变化图。百分比是按相对于当前实例上每秒平均操作数计算得来的。
通过对负载跟踪(workload trace),并进一步分析了不同操作的访问模式(access pattern)后,我发现了一些更有趣的东西:
- 通过对数据库中一些使用频繁(hot)、次频繁(warm)和大量不频繁(cold)的行(rows)进行实验,发现对节点(nodes)和边 (edges)的读、写访问模式也都遵循着幂律分布(power-law distribution)。这对一般的数据库来说是正常的,但是由于Facebook使用了像memcached之类的内存缓存技术,我们不确定这是否对访问模式产生了影响。
- 图谱的结构对访问模式也有重要的影响:与高出度节点相连接的边通常比那些与低出度节点相连接的边会有更频繁的读、写操作。
我可以从产生这些效果的负载跟踪中提取到相关参数,并可以在LinkBench中重现。
#p#
LinkBench的架构
LinkBench被设计为可定制和可扩展的。它允许我们通过生成社交图谱的子集来模拟负载,这一特性对评估数据库处理特定关联类型的性能来说是至关重要的。例如,将以写为主(write-heavy)和读为主(read-heavy)的关联类型分别存储到不同的数据库后端是有必要的,因此我们可以针对每种类型做单独的性能测试。它也允许我们使用比较容易的方法来编写适配器从而支持新的数据库系统,因此我们可以比较出在相同的负载下它与MySQL的性能差异。
真正的性能测试工作是由LinkBench driver负责的,它是一个用于生成社交图谱和各种操作的Java程序。测试工作分为两个阶段:载入阶段(load phase),会生成一个初始的图谱并载入(loaded in bulk)到数据库中;请求阶段(request phase),许多请求线程会用各种操作对数据库进行并发访问。在请求阶段,各种操作的延迟和吞吐量都会被统计并给出报告。
Driver在两个阶段的具体行为是通过一个配置文件进行控制的,通过这个配置文件可以轻松地控制性能测试中的各个参数。
测试结果
我们对打了Facebook补丁(请看http://www.facebook.com/MySQLatFacebook) 的MySQL 5.1.53进行性能测试。我们在数据库中生成了12亿个节点和49亿条边,用MySQL标准的未经压缩的InnoDB表存储,占用了1.4TB硬盘空间。MySQL服务器拥有2个CPU,8+核心(8+ cores/socket),144G内存,以及16kB读取延迟(read latency at 16kB)小于500μs的固态硬盘。
我们对不同级别的负载进行了一系列的性能测试。为了测试MySQL服务器的最大吞吐量,我们运行了100个请求线程,每个线程都以最快的速度对MySQL 进行请求。我们获得了一个在每秒11029个请求条件下系统吞吐量的测试结果。这次试验的请求延迟如下表所示,表明系统在极高的负载下仍能进行响应。即使 MySQL处于吞吐量满载的情况时,延迟的中位数(median latencies)也是很低的。为了模拟真实产品环境下服务器不会一直满载运行的场景,LinkBench能够调节(throttle)请求的数量,在这种情况下延迟还可以再低。
MySQL LinkBench的操作延迟是以ms计算的。延迟指的是从LinkBench driver调用Graph Store adapter开始,到返回时为止。
我们也收集了系统资源利用的跟踪报告来更好地理解服务器的行为。
下面展示的吞吐量和I/O利用率随时间的变化图表明服务器需要一些时间来“热身(warm up)”才能达到一个稳定的状态。当MySQL处于“热身”状态时,两种竞争效应(two competing effects)会引起吞吐量上下波动。数据库缓冲池(buffer pool)起初是空的,因此很少的操作可以通过缓存的数据来完成。当数据库“热身”完后,缓冲池充满了来自磁盘的页面(pages),因此大部分的读就不需要进行I/O操作并能迅速地完成。然而,随着时间的推移,缓冲池中的大部分页面(pages)都变成了脏数据--例如,页面包含了还未写入磁盘的数据- 因此当清除脏数据(dirty pages)时会导致对磁盘更频繁的写操作。
CPU利用率统计图表明MySQL服务器的性能在当前负载下是不依赖于计算量(not compute-bound)大小的,因为用户的CPU利用率一直处于50%左右。以 每秒的操作数(operations/second) 或MB/s测得的高I/O利用率表明MySQL在固态存储设备上可获得更高的I/O能力。
获取LinkBench
想要获取LinkBench以及更多关于使用LinkBench和按需定制的信息请访问我们的Github页面: http://github.com/facebook/linkbench
英文原文:LinkBench: A database benchmark for the social graph
译文链接:http://www.oschina.net/translate/linkbench-a-database-benchmark-for-the-social-graph