ESDB Processing Extremely Skewed Workloads in Real-time论文翻译

ESDB:实时处理极不均衡的工作负载

摘要

        随着云计算的快速发展,多租户数据库的有效管理已经成为云服务提供商的一个重要挑战。这对阿里巴巴来说尤其重要,因为阿里巴巴拥有一个分布式多租户数据库,支持世界上最大的电子商务平台之一。它为数以千万计的卖家作为租户提供服务,并支持来自数以亿计的买家的交易。买家固有的不平衡的购物偏好在数据库上产生了巨大的倾斜的工作量,这可能会产生不可预测的热点,从而导致大量的吞吐量下降和延迟增加。在本文中,我们介绍了ESDB(ElasticSearch数据库)的架构和实现,这是一个面向云的文档数据库,作为阿里巴巴电子商务平台背后的主要交易数据库,已经在阿里云上运行了5年。ESDB提供了强大的全文搜索和检索能力,并提出了动态二次哈希作为处理极端倾斜工作负载的解决方案。我们用模拟工作负载和现实世界的工作负载对ESDB进行了评估,并证明ESDB大大增强了写的吞吐量,减少了写的完成时间,而没有牺牲查询吞吐量。

关键词:多租户;云原生;负载均衡;面向文档的数据库

1 引言

        随着云计算的盛行,企业正在将其应用程序以及数据库迁移到云端。现如今云供应商为数百万客户提供数据库产品,包括承载数百万用户的应用程序和在线服务。这促使云服务提供商采用分布式多租户数据库,来自多个租户的数据被分配到共享同一组计算和存储资源。这种多租户架构允许高资源利用率,因此,数据库产品具有高弹性和低成本。但另一方面,由于来自不同租户的工作负载之间固有的不平衡,多租户数据库在面对极其倾斜的工作负载时,会出现严重的吞吐量下降。

        阿里巴巴正在运行世界上最大的电子商务平台,其中包括淘宝网、天猫等。作为阿里巴巴电子商务平台的骨干,交易数据库在平时和重度工作负荷下(如重大促销活动期间)都要提供稳定的读/写吞吐量和低响应时间(RT(响应时间))。在阿里巴巴的交易数据库中,交易日志包括结构化数据(如交易ID、卖家ID、创建时间和交易状态)和全文数据(如拍卖标题、卖家和买家的昵称)。从电子商务平台产生的交易日志记录了由买家发起的购物交易,然后通过协调平台依次写入卖家的数据库中。作为目标定位,卖家数据库致力于处理高工作负载,提供高效的面向卖家的查询和分析服务。在阿里云上部署,卖家数据库最初被维护在一个无共享的MySQL集群中,交易日志按其卖家ID组织。随着近年来阿里巴巴交易日志的吞吐量迅速增长,我们观察到卖家数据库开始面临以下两个挑战。

        多样化的数据模式和全文检索。由于交易日志包含各种商品的信息,允许用户为商品添加自定义属性(如尺寸、衣服的材质、食物的重量),这导致了数据模式的多样化(即不同的交易日志有不同的属性)。由于在表中添加所有定制属性的列是不现实的,我们建立了一个 "属性 "列,所有定制的属性被串联起来作为一个字符串。在实践中,已经有超过1500个子属性被添加到交易数据库中。在采用ESDB之前,对 "属性 "列的查询是非常低效的,因为为这样一个非标准的字符串列建立一个合适的索引是不容易的。

        在实践中,卖家经常发现自己需要执行包含非标准字符串或关键词的全文搜索查询。例如,书店卖家通过拍卖标题中的关键词搜索图书交易的交易状态。虽然MySQL提供了模糊搜索(如LIKE,REGEXP)以及使用全文索引的全文搜索,但对这些功能的支持是有限的,而且性能不稳定,特别是随着交易日志多年来的快速增长。因此,它促使我们将我们的骨干从MySQL转移到面向文档的数据库。

        Skewed and unpredictable workloads。另一个挑战是,由于不同卖家进行的交易数量的巨大变化,卖家数据库中的工作负荷分布是极其倾斜的。这种变化在重大销售和促销活动的启动阶段被进一步放大,在此期间,整体吞吐量急剧增加。例如,图1显示了2021年单身节全球购物节前10秒内前1000名卖家的归一化吞吐量。在图中,归一化吞吐量大致遵循幂律曲线,前10名卖家的聚合吞吐量占总吞吐量的14.14%。吞吐量分布的不可预测性增加了另一层复杂性:不同卖家的吞吐量随着时间的推移而大幅波动,这取决于多种因素,如商品促销活动的可用性,库存准备的准备情况等。在实践中,卖家的受欢迎程度会在很短的时间内发生很大的变化,而且顶级卖家的高峰期也很难预测。

ESDB Processing Extremely Skewed Workloads in Real-time论文翻译_第1张图片

        在采用ESDB之前,每个卖家的交易日志都是根据他们的卖家ID唯一地分配到一个MySQL实例。在实践中,当顶级卖家的促销活动开始并带来大量的交易时,写吞吐量很容易压倒实例的写能力。另一方面,大多数实例(针对普通卖家)的利用率很低。这种倾斜的工作负荷的后果是在闲置的实例上浪费资源,在热点实例上的实时查询失败,以及整体性能的下降。例如,大租户的写入延迟(即评估ESDB完成向卖方数据库写入交易日志所需时间的指标)在早年可能会上升到100分钟以上,在这种情况下,卖方将失去根据市场反应调整其销售策略的能力。一个直接的多租户解决方案是允许多个卖家共享一个数据库实例,例如,通过一致的哈希将卖家的交易日志路由到实例。然而,由于不同卖家进行的交易的内在不平衡性,交易日志的分布仍然是倾斜的。因此,我们需要一个工作负载适应性的负载均衡机制,尤其是在工作负载的高波动性和不可预测性下。

        Contributions。在本文中,我们介绍了ESDB,一个云原生多租户数据库,其特点是处理极度倾斜的工作负载。ESDB建立在Elasticsearch的基础上,并继承了其核心特征,如全文搜索、分布式索引和查询,以及使用双哈希作为其请求路由策略。ESDB的创新之处在于一种新的负载均衡技术,该技术能够实现多租户工作负载的自适应路由,以及克服Elasticsearch作为数据库的缺点的优化,如多列查询的高RT(响应时间)和索引计算的高成本。

  • 我们介绍了ESDB的架构,这是一个云原生的面向文档的数据库,作为阿里巴巴电子商务平台背后的主要交易数据库,已经在阿里巴巴云上运行了5年。ESDB为极度倾斜的工作负载提供弹性写入的支持,以及高效的临时查询和实时分析。
  • 我们引入了动态二级哈希,作为解决工作负载的高度不均衡所造成的性能下降的方案。这种机制能够实现实时的工作负载均衡,以允许在不同的实例上实现平衡的写吞吐量。不同于双重哈希,需要读取几乎所有实例获取结果,它避免了分布式查询带来的额外压力。
  • 我们进一步引入了一些优化措施,如采用查询优化器、物理复制、基于频率的索引。这些优化使ESDB能够结合面向文档的数据库的特点(例如,高可扩展性和对全文检索的强大支持),同时为临时查询提供低RT(响应时间)。
  • 最后,我们对ESDB在实验室环境中的模拟工作负载和生产环境中的真实工作负载进行了评估。

        本文的其余部分组织如下。在第2节中,我们介绍了面向文档的数据库的背景,以及负载均衡的一般概念。第3节介绍了ESDB的架构概况。然后,我们在第4节中介绍了动态二次哈希的设计,并在第5节中介绍了优化方法。第6节介绍了ESDB的评估。最后,我们在第7节中讨论了相关工作,并在第8节中得出结论。

2 背景和动机

        在这一节中,我们介绍了面向文档的数据库的背景,以及一个特殊的例子,Elasticsearch,它被用作ESDB的基础。然后我们讨论负载均衡的一般概念,以及动态二次哈希的动机。

2.1 面向文档的数据库

        面向文档的数据库是NoSQL数据库的一个子类,数据以文档的形式存储。与关系型数据库不同,面向文档的数据库没有预定义的数据格式,因此支持灵活的模式。与其他NoSQL数据库相比,在数据库中,面向文档的数据库的优势在于处理复杂的查询和管理复合数据结构,如嵌套文档。一般来说,文档是以文件格式编码的,如JSON、BSON、XML、YAML。这些文件格式暴露了其内部结构,数据库引擎利用这些结构来优化索引和查询。

        虽然主流的面向文档的数据库(如MongoDB、CouchDB和Couchbase)获得了业界的青睐,但是它们的全文搜索性能并不稳定,不能满足我们对大规模实时查询的期望。Elasticsearch和Solr是基于搜索库Lucene的搜索引擎。由于它们提供对文档的操作(例如,数据存储在JSON中),它们也被认为是面向文档的数据库。截至2022年2月,Elasticsearch可以说是最强大、最流行的开源全文搜索工具。除了对全文搜索的强大支持,Elasticsearch还提供了很高的水平可扩展性和可用性,因为它是一个天然的分布式系统,支持低成本的集群扩展、多副本和分布式查询。这个功能对于负载均衡也是至关重要的,因为大租户的交易日志和工作负载应该是分布式的,而不是唯一分配的。此外,Elasticsearch实现了双哈希,这是我们负载均衡方法的基础。因此,我们选择Elasticsearch作为ESDB的主干。

        我们发现Elasticsearch作为卖家的数据库部署后有两个主要的缺点:(1)多列查询的高RT(响应时间)。当查询涉及多列和复杂条件时,Elasticsearch的RT(响应时间)通常比原来的MySQL集群要高。(2) 索引计算成本高。一方面,由于每个分片都有一个分布在不同机器上的副本,对Elasticsearch的索引文件(分段文件)的操作会使计算成本增加一倍。另一方面,为了提高查询效率,我们应该为交易日志的 "属性 "列的子属性建立索引。考虑到子属性的数量在1500左右,这将导致不可接受的计算和存储。在第3节和第5节中,我们将介绍我们对这两个问题的解决方案。

2.2 负载均衡

ESDB Processing Extremely Skewed Workloads in Real-time论文翻译_第2张图片

        典型的负载均衡方法包括分片和双重哈希。分片是一种水平分区方法,通过分片键(如时间、地区、卖方ID)将大表分布在多台机器上。通过分配存储以及工作负载,分片减轻了单机的沉重负担。此外,一些被广泛采用的数据库(如Spanner[28]、MongoDB[40]、ONDB[54]、Couchbase[39])实现了自动分片,自动在机器间进行数据分片和迁移,以平衡工作负载。HBase[18]使用了一种自动增强的重分片方法,一旦分片增长过大,就把一个分片分成两个分片。Yak[44]使用一种基于规则的分片方法,该方法根据全局监控器检测到的指标,使用手动定义的分片规则进行工作负载调度和数据迁移。尽管最优分片策略有可能保证负载均衡,但数据迁移造成的高成本和高风险不能满足实时处理和易变工作负载的要求。

        双重哈希是为解决哈希表中的哈希碰撞而提出的一种经典算法,其中引入了一对独立的二级哈希函数,以便在第一个哈希函数引起碰撞时产生偏移。在一些应用中,两个独立的哈希函数被应用于一个密钥。钥匙k的双哈希结果是p=(h1(k)+ih2(k)) mod N,其中i随着碰撞序列的增长而增加,N是哈希表的大小。

        当数据库(例如Elasticsearch, HBase, OceanBase , OpenTSDB)利用双哈希来实现更均衡的路由时,它通常包括两个独立的哈希函数,分别应用于两个属性。例如,Elasticsearch实现了一个双哈希模块,允许用户选择两个属性k1和k2以及一个全局静态变量s。对应公式如下
p=(h1(k1) + h2(k2)mod s) mod N (1)
其中k1是负载均衡的主要属性(如租户ID),k2是为每个交易唯一生成的密钥(如交易ID),1≤s≤N,s∈Z。

        在公式1中,最大偏移量s在负载均衡和查询效率的权衡中起着重要作用。当s=1时,双哈希退化为哈希,在工作负载均衡中失效,但可以在单个分片上查询(图2(a))。相反,当s=N时,双哈希将记录路由到所有分布式分片,无论它们是否是热点。它使所有租户的工作负载完全平衡,但需要查询执行从所有分布式分片中搜索和汇总查询结果,从而导致低查询吞吐量(图2(b))。一旦数据以分布式方式存储,一些操作,如sort和topK,会更加耗时。在本文中,我们通过用一个能根据租户的实时工作量动态变化的函数来取代静态的s,从而实现支持负载均衡和高查询吞吐量的目标。我们在第4节中介绍了详细的设计。

3 系统概述

        ESDB是一个部署在阿里巴巴云上的分布式数据库系统。它采用无共享架构,每个数据库节点(即物理机或虚拟机)存储所分配的分片和数据,独立处理工作负载。在ESDB集群中,分片和副本(每个分片有一个副本)被随机分配给不同的节点。节点扮演着不同的角色:每个节点既是协调者(在控制层)又是worker(在执行层);每个集群进一步选举一个节点作为主节点。

        图3显示了ESDB的架构概况。除了工作负载处理的三个层次外,该图还包括ESDB的关键功能,即实现实时工作负载均衡和读/写优化。在本节的其余部分,我们将更详细地介绍这些组件。

ESDB Processing Extremely Skewed Workloads in Real-time论文翻译_第3张图片

3.1 应用层

        应用层由ESDB的写客户端和查询客户端组成:

        写客户端在ESDB的负载均衡器的配合下,ESDB的写客户端使用以下技术来加速写和缓解热点问题。
(1) 单跳路由。Elasticsearch最初的写客户端不知道工作负载的目的地。客户端以轮流的方式将工作负载路由到协调者,这导致了两跳路由(写客户端→协调者→worker)。在ESDB中,我们允许客户端了解路由策略。通过这种方式,我们实现了一跳路由(写客户端→worker),从而加速了写入。
(2) 热点隔离。在写客户端中,workloads会先在队列中缓存,之后成批的发送给worker。一旦一个worker过载(可能是由不均衡的写工作负载和慢查询操作造成的),队列将被阻塞,写延迟将上升。为了解决这个问题,ESDB实现了热点隔离,将热点的工作负载隔离到另一个队列中,这样就不会对其他工作负载产生负面影响。
(3) 工作负载批处理。当一个写客户端检测到一个行(由其行ID识别)将在短时间内被频繁修改时,它将通过把这些修改聚合在一起并只实现该行的最终状态来批处理工作负载。通过采用工作负载批处理,写客户端避免了对同一行的重复写入,从而提高了写入吞吐量。

        查询客户端。ESDB从Elasticsearch继承了RESTful API和查询语言ES-DSL。然而,与SQL相比,ES-DSL对用户不太友好,而且它不支持SQL的所有表达式和数据类型(例如,类型转换表达式date_format)。因此,我们需要一个工具来将SQL查询重写成ES-DSL查询。为了解决这个问题,我们开发了一个插件Xdriver4ES作为SQL和ES-DSL之间的桥梁。Xdriver4ES采用了一个智能翻译器,可以从SQL查询中生成具有成本效益的ES-DSL查询。与SQL不同的是,ES-DSL直接编码查询的AST,然后进行解析以生成执行计划。因此,Xdriver4ES没有从SQL查询中建立AST,而是采用了以下两种优化技术:(1)CNF/DNF转换。考虑到查询是布尔公式,Xdriver4ES将其转换为CNF/DNF,以减少AST的深度。(2) 谓词合并。Xdriver4ES合并涉及同一列的谓词,以减少AST的宽度(例如,将tenant_id=1 OR tenant_id=2合并为tenant_id IN (1,2))。Xdriver4ES进一步利用映射模块,将查询结果转换为SQL引擎所能理解的格式。例如,我们在这个模块中实现了SQL的内置功能,如数据类型转换和IFNULL。通过这种方式,Xdriver4ES允许在ESDB上执行SQL查询。

3.2 控制层

        控制层由一个主节点、协调者节点和一个收集工作负载均衡指标的监视器组成。

        主节点作为整个集群的管理者工作。它负责集群管理任务,如管理元数据、分片分配和rebalance,以及跟踪和监控节点。
协调器节点主要负责将读/写工作负载路由到相应的工作节点。查询结果聚合器,负责行ID的收集,并执行聚合操作(例如全局排序、总和、平均);在执行查询语句期间,协调器首先从所有参与的分片中收集所选行的行ID,然后获取相应的原始数据(由检索的行ID列表表示)。

        负载均衡器。ESDB的负载均衡器是为了生成和提交指示读/写路由器的路由规则而开发的。
由于它是通过动态二次哈希实现,所以路由规则也被称为二次哈希规则。
一旦监测器检测到热点,协调器将生成新的路由规则,这些规则基本上是分割和扩展承载当前热点的分片。通过利用新的路由规则,ESDB将大租户的工作负载分配给更多的分片,从而减轻了过重的节点负担。一旦它从协调者那里收到新的路由规则,主节点就会负责提交这些规则。通过这种方式,负载均衡器确保了整个集群中工作负载路由的一致性。我们在第4节中介绍了负载均衡器的更多设计细节。

        基于频率的索引。为了减轻维护 "属性 "列的子属性索引的成本(见第2.1节),我们采用了基于频率的索引(即只为最经常被查询的子属性建立索引)。这个想法来自于对子属性的读/写频率是不均衡的观察。例如,一些通用的子属性,如 "活动",表示卖家的哪些电子商务活动频繁使用并可能被查询。在实践中,基于频率的索引在查询延迟方面有明显的改善,代价是存储开销略有增加。我们在第6.3.3节展示了基于频率的索引的有效性。

3.3 执行层

        执行层由工作节点组成,工作节点在其本地SSD中维护分片和副本,并执行读/写工作负载。worker节点有一个无共享的架构,每个worker维护自己的存储,与其他worker无关。

        写执行和数据复制。当执行写工作负载时,ESDB继承了Elasticsearch的近实时搜索功能。

  1. 原始数据和索引会先写入内存buffer之后定期刷入到磁盘的segment文件,之后可用于搜索之前。为了解决持久化问题,避免数据丢失,ESDB采用了与磁盘有关的Translog。每一个写的工作负载一旦成功提交,就会被添加到Translog中。这样,如果ESDB遇到进程崩溃或硬件故障,未被刷新到磁盘的数据可以从Translogs中安全恢复。
  2. 段合并是另一个重要的机制,它将较小的段合并到一个大段。它花费了计算资源,但有效地提高了查询效率。

        Elasticsearch采用了一种逻辑复制方案:一个主分片一旦在本地执行了一个写操作,就会把他转发给它的所有副本。换句话说,相同的写操作分别由副本执行,这给集群带来了n倍的计算开销(n是副本的数量)。在ESDB中,写操作仍然被实时转发并添加到副本上的Translogs,但从未被副本执行。相反,它实现了segment文件的物理复制。我们在第5.2节描述了物理复制的细节。

        查询优化器。对于查询工作负载,ESDB使用一个基于规则的优化器建立优化的查询计划。ESDB没有对所有的列使用索引扫描,而是提供了更多的操作,如复合索引扫描和顺序扫描。通过利用不同操作的组合,ESDB大大降低了查询延迟。优化的细节将在第5节介绍。

4 负载均衡

        ESDB的负载均衡器被设计为满足以下两个要求。

  1. 查询效率。多个租户的数据应该被放在尽可能少的分片上,以避免在太多的分片上执行查询。
  2. 负载均衡。工作负载在多个分片上的分布应尽可能均匀,以避免单一分片上的过载。

        在实践中,我们将小租户的数据限制在单个分片上和将大租户的数据分布在多个分片上,对这两个矛盾的要求进行了权衡(见图2(c))。

ESDB Processing Extremely Skewed Workloads in Real-time论文翻译_第4张图片

4.1 动态二次哈希

        动态二次哈希的关键点是在二次哈希期间采用一个适应工作量的偏移函数L(K1)。与公式1相比,固定的最大偏移量s被替换为L(K1)。1≤L(K1)≤N,L(K1)∈Z,L(K1)为租户K1实时工作负载和当前存储容量
p=(h1(k1) + h2(k2)mod s) mod N (1)
p=(h1(k1) + h2(k2)mod L(K1)) mod N (2)
        图4描述了三种不同的路由策略:哈希、双重哈希和动态二级哈希。
        哈希法:只能根据分区密钥(如租户ID)的1级哈希来路由工作负载,因此当它需要平衡多租户的工作负载时,就会出现问题。每次都是固定的一个。
普通的双重哈希:能够根据两个键(即租户ID和记录ID)的2级哈希将租户的工作负载路由到一组固定的连续分片,但不能管理动态工作负载。每次都是固定的范围。
动态二级哈希:也将工作负载路由到连续的分片,当工作负载增加时,它能够扩展到连续的分片(例如,图4中L(K1)从8增加到16)。可以动态扩展分片范围。

        在实践中,二次哈希的最大偏移量s=L(K1)依赖于两个指标:

  1. 当前存储量。假设具有较大存储比例的租户更有可能具有较大的即将到来的工作负载。因此,我们为租户选择较大的s。值得注意的是,为了满足查询效率的要求,我们对大多数存储比例较小的租户设置s=1。
  2. 实时工作负载。根据工作负载监控器定期报告的实时写吞吐量比例,负载均衡器将为被认为是热点的租户扩大最大偏移量s。这种对s的调整发生在ESDB的运行期间。

ESDB Processing Extremely Skewed Workloads in Real-time论文翻译_第5张图片

ESDB Processing Extremely Skewed Workloads in Real-time论文翻译_第6张图片

4.2 读写一致性 Read-your-writes Consistency

        尽管动态二级哈希可以实现灵活的路由策略,但二级哈希偏移的变化会给读写一致性带来风险,因为它打破了记录和分片之间的静态映射。例如,对于租户k1来说,如果它的最大偏移量s在运行期间改变为s′,就很难找到所有承载过k1的历史记录的分片:二级哈希结果从h2(k2)mod s变为h2(k2)mod s′。这种不一致会导致严重的问题,如不同分片的重复索引、删除失败和不正确的查询结果。为了解决这个问题,我们在ESDB负载均衡器的运行期间维护了一个二级哈希规则列表R。每个二次哈希规则被维护为一个元组(t, s, k_list),其中t代表规则生效的时间,s是二次哈希的最大偏移量,k_list记录在二次哈希中采用s的租户ID。二级哈希规则列表包括在ESDB的初始化和负载均衡运行时建立的二级哈希规则。

        用哈希规则进行负载均衡。算法1演示了ESDB如何通过更新哈希规则列表来执行负载均衡。在初始化阶段(第5-10行),负载均衡器从每个租户的当前存储中建立二级哈希规则。在运行阶段(第11-21行),负载均衡器根据实时工作负载的波动,更新二级哈希规则列表R。具体来说,我们根据存储比例或实时工作负载比例为 "热 "租户手动设计新的二级哈希规则。在实践中,
对于s其为2的指数(例如,1,2,4),以限制二级哈希规则的数量,并加速规则列表中的搜索。负载均衡器使用算法2,以更新R(第9行和第18行)。

        写操作(如INSERT、UPDATE、DELETE)(通过租户ID k1、记录ID k2和记录创建时间t_c(create)标识),到达协调器节点,协调器负责从R中选择一个匹配的二级哈希规则。该规则(t, s, k_list)必须满足以下三个条件:

  1. t必须是早于记录的创建时间t_c。
  2. k1在k_list中。
  3. s是所有满足前两个条件的规则中最大的一个。

        这样,创建新记录的工作负载(INSERT)和修改现有记录的工作负载(UPDATE、DELETE)都被路由到正确的分片。

        读操作(SELECT)到达时,ESDB查询客户端使用k1的匹配二级哈希规则(t, s, k_list)来决定查询应该在哪个连续的分片上执行,即从分片h1(k1) mod N到分片(h1(k1) + s-1) mod N。

4.3 共识

        在ESDB中,每个节点都是一个协调者,负责将工作负载路由到匹配的分片。因此,一旦任何节点上产生了新的规则,整个系统必须对二级哈希规则列表R达成共识,以确保严格的一致性。也就是说,所有协调者对于相同的写操作总是使用相同的二级哈希规则。

        在过去的几十年里,人们为分布式交易提出了经典的共识协议。2PC和3PC是旨在实现事务原子性的承诺协议(提交或中止的二元共识)。它们不能保证在网络分区或节点故障时R的严格一致性。Paxos、Raft和ZAB解决了一些问题,如容错、领导者选举、崩溃恢复,以达到跨副本的共识。然而,在决定二级哈希规则的情况下,不一定需要它们。这是因为R是一个append only的列表,每个规则都与有效时间有关。因此,我们不需要决定规则的排序(因为它们是按有效时间排序的),相反,对于每条规则来说,它被简化为决定是承诺还是中止。因此,我们可以使用更有效的承诺协议(例如,2PC)来达成关于二级哈希规则的共识。在ESDB中,我们提出了一个2PC的变体协议,其灵感来自于Spanner的提交等待机制,以解决工作负载阻塞的问题。图5显示了这个协议的概况。

ESDB Processing Extremely Skewed Workloads in Real-time论文翻译_第7张图片

        准备阶段。每当协调者节点建立了一个二级哈希规则,它就会将新的规则发送给ESDB集群的Master。Master决定规则生效的有效时间t(使用本地时间),人工配置的时间间隔T,t = timer.now() + T.Next ,主节点将有效时间作为建议广播给所有参与者节点()。当一个参与者收到建议时,它检查其所有记录是否在有效时间之前被创建如果这个条件得到满足,参与者会阻止所有创建时间晚于有效时间的工作负载,并向主节点回复一个接受信息。否则,参与方会向主节点报告错误。如果主节点收到任何错误信息或检测到任何超时(参与者在T/2内没有回应),这个二级哈希规则将被终止。否则,提交阶段开始。

        提交阶段。主节点向所有参与的协调者广播提交消息以及二级哈希规则。由于所有节点在上一阶段达成了共识,它们将接受提交消息并将该规则添加到它们的本地二级哈希规则列表中。一旦提交阶段完成,各节点将删除工作负载的执行块(即继续处理创建时间大于有效时间的工作负载)。

        选择时间间隔。时间间隔T为系统提供一个缓冲期,以便就二级哈希规则达成共识。T应远远大于广播的往返延迟(如100ms)和整个集群的本地时钟偏差的最大值(在ESDB中不超过1s),以确保严格的一致性。同时,T应短于我们预期的负载均衡时间(如60s),以保证有效性。只要T大于集群达成共识的时间,ESDB的共识协议就能实现工作负载处理的无阻塞。

        容错性。尽管ESDB的共识协议保证了R的严格一致性,但在提交阶段,它仍然会受到网络分区和节点故障的影响。ESDB采用了一种自动容错的解决方案。然而,它依赖于对网络分区和节点故障的检测,也就是说,它需要区分暂时没有响应的节点和故障节点。一个典型的解决方案是使用一个预先定义的超时;在ESDB中,我们手动验证一个提出的警报(一个节点变得无响应),以明确决定是否发生了节点故障或网络分区。

5 优化

        ESDB主要关注单表的多列SFW(SELECT-FROM-WHERE)查询,其中多个谓词通过AND和OR操作符连接。在部署优化之前,ESDB的查询性能在只涉及几列的情况下是不错的。然而,与MySQL集群相比,我们观察到ESDB的多列查询的开销超过10倍。(卖家的查询通常涉及10个以上的列)。经过性能分析,我们发现次优性能主要来自于Lucene的僵化查询计划。为了解决这个问题,我们引入了一个查询优化器(见5.1节)。

ESDB Processing Extremely Skewed Workloads in Real-time论文翻译_第8张图片

5.1 查询优化器

        作为一个例子,考虑一个涉及四列的查询(如图6所示)。由Lucene生成的执行计划如图7所示。首先,Lucene为每一列生成张贴列表,其中记录了所选行的行ID,通过搜索对应的索引。然后,它通过交叉和联合对发布列表进行汇总。这个查询计划引入了大量的开销,因为发布列表是按顺序生成的。当某一列的选择性很高,并且发布列表增长得过大时,它将变得更加耗时。为了解决这个问题,我们让ESDB结合了关系型数据库的特点:复合索引、顺序扫描和基于规则的优化器(RBO),产生具有成本效益的查询计划。

ESDB Processing Extremely Skewed Workloads in Real-time论文翻译_第9张图片

        复合索引。在关系型数据库中,复合索引是建立在以特定顺序串联的多个列上的。利用复合索引的优势,通常可以避免耗时的操作,如表扫描,从而加速涉及多列的查询[24]。同时,复合索引的适用性有限,因为列必须符合最左的顺序(即最左原则)。例如,如果复合索引建立在两列column1_column2上,我们既可以查询(column1),也可以查询(column1, column2);另一方面,关于(column2)的查询不能利用这个复合索引。为了提高复合索引的可用性,DBA要在大量的列组合中手动建立复合索引[27]。

        Elasticsearch使用Bkd-tree[55]为数字数据和多维(如地理信息)数据建立索引。Bkd-tree是一种结合了kd-tree[57]和B+树的索引结构。与B+树不同,Bkd-树能够沿着不同的维度划分搜索空间。因此,不需要遵循最左边的原则,这使得复合索引更加灵活。此外,它优化了磁盘I/O,并通过动态地维护kd树的森林,大大减少了插入和删除的开销[55]。然而,Bkd-tree受到维数诅咒的影响,随着维数的增加,搜索性能会下降[15]。在ESDB中,我们建立了串联的列,并在这些列上建立单维的Bkd树作为复合索引。虽然这种设计的灵活性较低,但ESDB的复合索引搜索性能很快,能够覆盖实际应用场景中的大部分查询工作负载。

        复合索引的另一个挑战是当我们连接列的时候,键的大小不断增加,这使得键的比较等操作变得昂贵。为了解决这个问题,我们利用了共同前缀的优势:由于串联的键在复合索引中被排序,Bkd树中的叶子节点通常包含有共同前缀的键。通过利用共同的前缀,我们设法提高了存储效率,并减少了密钥比较的成本。

        顺序扫描。传统数据库中支持的另一个重要操作是顺序扫描。虽然它被认为效率较低,但这种操作需要较少的I/O,并且在列的选择性或cardinality较低时(例如性别列)表现更好。然而,Elasticsearch并没有实现顺序扫描,因为这与搜索引擎的核心理念相悖,搜索引擎通常是为全文搜索和排名而设计的,不需要获取原始文档。在ESDB中,我们将顺序扫描作为复合索引的一个辅助手段来实现。基于复合索引搜索产生的发帖列表,ESDB对相应的Doc值进行顺序扫描[2],生成一个过滤后的发帖列表。通过这种方式,顺序扫描成为一种有效的搜索操作,并能够在某些情况下加速查询(例如,对于包括没有索引的列的查询)。在实践中,我们维护一个扫描列表,其中包括能够从顺序扫描中受益的列的名称。

        基于规则的优化器。最后,我们为多列SFW查询引入ESDB的基于规则的优化器(RBO)。RBO根据以下访问路径的可用性和排名,为不同的列选择执行计划。- 当由AND连接的谓词使用一些复合索引中的列时,复合索引是可用的。在这种情况下,我们使用最长匹配来选择包含尽可能多列的复合索引。

  • 当通过AND连接的谓词使用不包括在任何复合索引中的列,但包括在扫描列表中时,可以使用顺序扫描。
  • 当通过AND连接的谓词使用不包括在任何复合索引或扫描列表中的列时,或者谓词通过OR连接时,可以使用单列索引。

        图8描述了示例查询(如图6所示)的优化查询计划。发布列表A是由复合索引tenant_id_created_time生成的。在对状态的Doc值进行扫描后,最终结果是过滤后的发帖列表B和发帖列表C的联合,后者是由单一索引搜索产生的。

ESDB Processing Extremely Skewed Workloads in Real-time论文翻译_第10张图片

5.2 物理复制

        与要求副本执行相同的写工作负载(即日志复制)不同,物理复制框架,例如Lucene Replicator和Solr 7的TLOG[10],不要求副本执行相同的写入工作负载(即逻辑复制),而是直接复制段文件。当主分片刷新一个新的段文件时,它初始化一个复制过程,在此期间,副本计算段差(即位于两个分片上的段文件之间的差异),并从远程分片上请求缺少的段。

        ESDB采用了物理复制,目的是减少复制过程中产生的CPU开销。具体来说,我们设计它是为了克服以往工作中看到的两个缺点。1)冗长的单体复制过程,很容易被新一轮的复制过程打断;2)复制大型合并段所造成的较长的可见性延迟(即一个段在主分片和复制段上变得可见的时间戳之间的间隔)。ESDB的物理复制框架(如图9所示)由三种复制机制组成。

        Real-time synchronization of Translog。Translog的实时同步。由于Translog是ESDB的持久性保证,我们要求它应该在主分片和副本之间进行实时同步。一旦写工作负载被成功执行,主分片就会将其转发到复制区。然后,复制区将收到的写工作负载添加到其本地Translog中。通过这种方式,ESDB确保所有副本能够在副本失败或主/副本切换的情况下在本地恢复数据。

        Quick incremental replication of refreshed segments。ESDB进一步采用了快速增量复制机制,以避免长时间的复制过程,因为这很容易被打断。图9描述了快速增量复制的六个步骤。

  1. 主分片建立一个当前本地段的快照,并在每次刷新操作完成后将其添加到快照列表中(显示为黄色框)。
  2. 最新的快照(即本例中的快照3)被选为当前主状态。
  3. 主分片锁定当前快照中的段(即段A和段B),并将其发送到副本中。
  4. 复制器根据其本地快照和从主分片收到的快照计算段差。基于段差,副本要么请求段(即段B),要么删除已经被主分片删除的段。
  5. 主分片发送由副本请求的段。
  6. 复制完成后,副本通知主碎片解锁当前快照中的分段。

        当刷新间隔较短时,上述机制稳定了物理复制过程,并保证了最新片段的复制。

        合并段的预复制。由于合并的段通常很大,用快速增量复制合并的段会导致复制刷新的段的延迟。例如,如果图9中的快照3包含段C,复制将请求段B和段C一起。为了解决这个问题,我们进一步引入了对合并段的预复制。当一个合并段产生时,主分片立即开始将其复制到副本中。这种预复制是与快速增量复制一起独立运行的。通过这种方式,合并段永远不会出现在段差中,因此对刷新段的复制的影响有限。

ESDB Processing Extremely Skewed Workloads in Real-time论文翻译_第11张图片

7 相关工作

        针对不同的应用,人们提出了不同的负载均衡技术。Google Slicer[14]提出了一种加权移动分片算法,该算法根据 "权重"(评估偏斜度的指标)和 "密钥流失"(分裂/合并的成本)自动执行冷分片的合并和热分片的分割。Facebook的Shard Manager[47]将热分片从过载的服务器中移出。CockroachDB[62]、Spanner[28]、HBase[18]、Yak[44]使用重新分片的方法,自动分割和移动 "热 "租户的分片。实时迁移是另一种基于迁移的负载均衡技术,它将热点的整个数据库应用跨节点移动。著名的应用程序,如Zephyr[31]、ProRea[58]和Slacker[21],采用不同的成本优化,以尽量减少服务中断和停机时间。Albatross[29]是一种用于共享存储数据库架构的实时迁移技术。Albatross不是迁移数据,而是迁移数据库的缓存和事务的状态。虽然有效,但基于迁移的负载均衡器引入了额外的带宽和计算开销,消耗了已经非常有限的资源。

        E-Store[61]识别元组级的热点,并使用智能启发式方法来生成最佳的数据迁移计划以实现负载均衡。SPORE[38]在分布式内存缓存系统中使用流行键值图元的自适应复制。与数据迁移相比,SPORE产生的开销较少,并将 "热 "图元的工作负载分散到多个节点。SWAT[50]实现了一种负载均衡的方法,它将副本角色交换为主要和次要副本,以处理不平衡的工作负载。虽然是轻量级的,但这三种方法并不适合我们的应用,因为我们的主要极度不均是由于租户不平衡导致,而非图元(tuples)或者副本。Centrifuge[13]使用连续密钥范围和服务器之间的临时租约来为内存服务器池提供一致性。它通过改变从虚拟节点到物理工人节点的映射来平衡工作负载,这不能用于解决单一的热点。LogStore[25]通过在运行期间维护和更新一个路由表来实现实时工作负载均衡。通过使用最大流量算法,LogStore生成的路由计划可以最大限度地提高整体写入吞吐量。然而,LogStore的路由器没有读与写的一致性保证,这使得它在处理UPDATE和DELETE工作负载时有风险。

8 结论

        ESDB采用了动态二次哈希,这是一种轻量级的负载均衡技术,可以实时消除多租户工作负载的热点。与哈希和双重哈希相比,动态二级哈希满足了高效的查询和负载均衡,从而克服了这两种技术的缺点。此外,我们引入了优化措施,大大减少了计算开销和查询延迟。

你可能感兴趣的:(分布式存储,数据库,elasticsearch,大数据,分布式存储)