前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >CDW中分析查询的内存优化

CDW中分析查询的内存优化

作者头像
大数据杂货铺
发布2022-03-29 19:50:07
9440
发布2022-03-29 19:50:07
举报
文章被收录于专栏:大数据杂货铺大数据杂货铺

如今,超过 1,000 名客户使用 Apache Impala 来支持他们在本地和基于云的部署中的分析。分析师和开发人员组成的大型用户社区受益于 Impala 的快速查询执行,帮助他们更有效地完成工作。对于这些用户而言,性能和并发性始终是首要考虑因素。

确保良好性能和并发性的一项重要技术是有效地使用内存。如果我们可以更好地利用内存,查询排队等待空闲内存的时间就会减少,因此结果会更快地返回。同样,随着可用内存的更好利用,更多用户可以在任何给定时间查询数据,因此更多人可以同时使用仓库。最终结果——更快乐的用户,以及更多的用户。

这篇文章解释了 Cloudera 数据平台 (CDP) 中提供的 Impala 如何能够从可用内存中获取更多的新技术。

Impala 一直专注于效率和速度,使用 C++ 编写并有效地使用运行时代码生成和多线程等技术。您可以在此处阅读有关 Impala 性能和查询技术的先前博客文章 - “ Apache Impala 的新多线程模型”、“保持小查询快速 - Apache Impala 中的短查询优化”和“选择性查询的更快性能”。

分析 SQL的工作负载大量使用聚合和连接。因此,在 Impala 等分析引擎中优化此类运算符的性能和效率可能非常有益。现在,我们将研究一种用于在 TPC-DS 10000 工作负载上将聚合和连接的峰值内存使用量减少多达 50%,并将每个节点级别的峰值节点内存使用量减少 18% 的技术。

哈希表

Impala 中的聚合和连接都使用哈希表,我们将展示如何减少操作的大小。Impala 中的HashTable类实现包含一个连续的Bucket数组,每个Bucket包含一个指向数据的指针或一个指向名为DuplicateNode的重复条目的链接列表的指针。

这些是Bucket和DuplicateNode的结构(为简单起见,更改了一些细节):

代码语言:javascript
复制
struct DuplicateNode {
    bool matched; // 1-byte
    // padding of 7-bytes
    DuplicateNode* next; // 8-byte pointer to next DuplicateNode
    Data* data; // 8-byte pointer to data being hashed


  };


  struct Bucket {
    bool filled; // 1-byte
    bool matched; // 1-byte
    bool hasDuplicates; // 1-byte
    // padding of 1-byte
    uint32_t hash; // 4-byte
    // bucketData is a pointer to DuplicateNode or
    // pointer to Data.
    union {
      Data* data; // pointer to data being hashed
      DuplicateNode* duplicates;
    } bucketData; // 8-byte
  };

在评估struct的大小时,这些是内存对齐的一些规则,假设是 64 位系统:

  1. 单个成员的内存地址从可被其大小整除的内存地址开始。因此,指针将从可被 8 整除的内存开始,bool可被 1 整除,uint32_t可被 4 整除。如果需要,成员将在前面加上填充,以确保起始地址可被其大小整除。
  2. 结构的大小将与其最大的成员对齐。例如,在最大成员上方的两个struct中,都是一个大小为 8 字节的指针。因此,struct的大小也将是 8 的倍数。

根据上述规则,上述代码段中的Bucket注释为每个成员占用的大小,并在需要的地方进行填充。Bucket的总大小为 16 个字节。同样,DuplicateNode的总大小为 24 字节。

我们决定通过从两者中删除 bool 字段来减小Bucket和DuplicateNode的大小,将大小分别减小到 12 字节和 16 字节。但是 12 字节不是Bucket的有效大小,因为它需要是 8 字节的倍数(结构的最大成员的大小)。在这种情况下,我们可以使用__attribute__ ((packed))来确保 struct 打包,使大小为 12 字节。

我们如何实现删除这些布尔值,因为它们需要存在于每个 Bucket 和 DuplicateNode 中?

我们决定删除所有bool成员,方法是将它们折叠成一个已经是struct一部分的指针。

将数据折叠成指针

Intel Level 5 提议 64 位内存地址

在 64 位架构上,指针使用 8 个字节存储内存地址。但在 x86 和 ARM 等架构上,线性地址长度限制为 48 位,其中 49 到 64 位保留供将来使用。在未来英特尔的第 5 级分页提案(白皮书)中,它计划在 x86 上放宽对 57 位的限制,这意味着我们可以使用最重要的 7 位——即 58 到 64 位——来存储额外的数据。需要注意的是,即使读取内存只需要 64 位中的 48 位,处理器也会检查有效位 (48…64) 是否相同——即符号扩展。如果不是,这样的地址将导致故障。这意味着折叠指针可能并不总是存储有效的可寻址内存。因此,折叠指针需要在取消引用之前进行符号扩展。

我们使用上述技术将填充、匹配和hasDuplicates 折叠到指针bucketData中。折叠和结构打包后,我们将得到一个12 字节的Bucket大小。同样DuplicateNode可以减少到 16 字节而不是 24 字节。总的来说,我们将这两个结构的内存需求从 40 字节减少到 28 字节,减少了 30%。

其他需求

在我们的实现中,要求Bucket的大小和哈希表中的桶数必须是2的幂。这些要求是出于以下原因:

  1. 内部内存分配器以 2 的幂分配内存以避免内部碎片。因此,桶数 * sizeof( Bucket ) 应该是 2 的幂。
  2. 桶数 ('N') 是 2 的幂,可实现更快的模运算。

当 N 是 2 的幂时,可以使用较快的按位运算 (hash & (N-1)),而不是使用缓慢的模运算 (hash % N)。

因此,从Bucket中删除了一个 4 字节的哈希字段,并将其单独存储在HashTable类中的新数组hash_array_中。这样可以确保sizeof(Bucket)为 8,即 2 的幂。分离哈希的另一个优点是现在不需要打包Bucket 。

实验评价:

我们对该技术进行了广泛的评估,以了解它如何影响性能和内存利用率。我们使用了 3 个基准:

  1. Microbenchmark:我们在较少的行上运行了 60 次构建和探测方法,以评估性能和消耗的内存。
  2. 十亿行的基准测试:在单个守护程序上,我们针对十亿行运行构建和探测基准测试,以测量性能和消耗的内存。
  3. TPC-DS-10000:规模为 10000 的整个 TPC-DS 基准测试在 17 节点集群上运行以测量性能。它还测量了节点和操作员级别消耗的峰值内存。

Microbenchmark

图 2a内存基准

图 2a 显示了内存基准测试的结果。基准名称采用memory_XX_YY格式,其中XX是插入哈希表的值的数量,YY表示唯一值的百分比。我们看到构建哈希表时内存消耗减少了 30%。

图 2b 运行时基准

图 2b 显示了性能基准测试的结果。build_XX_YY表示构建基准,其中插入了XX值, YY是唯一值的百分比。类似地,probe_XX_YY将探测由XX行和YY唯一值构建的哈希表。这些基准测试运行 60 次,并重复 10 次以找出每毫秒的迭代次数。图 2b 显示了对这 60 次运行测量的迭代次数的第 90 个百分位数。由于这种变化,我们观察到这些哈希表操作的运行时间没有显着差异。

十亿行基准

我们为此基准使用了 TPC-DS销售和项目表。sales有s_item_id (int)、s_quantity(int) 、s_date(date)列,而items有i_item_id (int)和i_price (double)列。sales有 10 亿行,items有 3000 万行。

建立基准

我们对销售额进行了 Group By 查询,以测量构建哈希表的性能和内存。

查询:

代码语言:javascript
复制
select count(*) from sales group by s_item_id having count(*) > 9999999999;

分组聚合内存使用

随着变化

没有变化

峰值分配

累积 分配

峰值分配

累积 分配

1.14G

1.85G

1.38G

2.36GB

图 3a

如图 3a 所示,我们看到峰值分配减少了 17%,累积分配减少了21%。在运行 20 次时,我们没有看到任何性能下降。在这两种情况下,有变化和没有变化的 Geomean 都在 68 秒左右。

探针基准

为了测量探针,我们在items和sales之间运行了一个连接查询,其中sales在探针端,items在构建端。由于我们仅在提议的连接中的较小表上构建哈希表,因此该基准测试的目标不是测量内存的减少,而是测量通过sales表探测 10 亿行时的任何性能差异。

但是,我们为此目的创建了 3 种销售表:

  1. sales_base :它随机生成了 10 亿行,与 Build 基准测试中使用的行相同。
  2. sales_30 :它有 10 亿行,其中 30% 的行是唯一的。
  3. sales_60 :它有 10 亿行,其中 60% 的行是唯一的。

我们在两次运行中都看到了相似的性能,我们的更改在sales_base上稍快,如图 3b 所示。因此,在减少内存消耗的同时,我们没有测量聚合查询运行时的任何退化。

表类型

GEOMEAN 超过 20 次运行(秒)

随着变化

无变化

销售量

110.8551081

114.6912898

销售额_30

103.2863058

102.4787489

销售额_60

84.12813181

84.8765098

图 3b

TPCDS-10000规模

我们针对规模为 10000 的 TPC-DS 工作负载评估了新的哈希实现。我们在一个 17 节点集群上运行所有工作负载查询,数据存储在 HDFS 中。

图 4a

每个操作减少:

对于每个查询,我们计算了单个 Join 和 Aggregation 运算符的最大内存减少百分比。我们只考虑了大于 10 MB 的运算符。根据图 4a,我们发现对于 99 个查询中的 42 个,内存消耗减少了 10% 以上。此外,对于其中 24 个查询,我们发现内存消耗减少了 20% 以上。

每节点内存减少:

在计算所涉及节点的平均峰值内存消耗时,28 个查询显示内存减少超过 5%,11 个查询显示内存减少超过 10%,如图 4b 所示。此外,我们看到 q72 最多减少了 18%。

图 4b

图 4c

考虑到查询在任何节点中消耗的最大峰值内存,27 个查询显示减少了 5%,11 个查询显示减少了 10% 以上,如图 4c 所示。对于 q65,观察到的最大减少量超过 20%。

结论

如上一节所示,我们看到节点级别和操作级别的内存显着减少,而没有任何性能下降。

这种内存效率和性能优化,以及 Impala 中的许多其他优化,使其成为商业智能和分析工作负载的首选,特别是在规模上。现在越来越多的数据仓库在云中完成,其中大部分在 Cloudera Data Warehouse 数据服务中,性能提升直接等同于成本节约。查询运行得越快,资源就可以越快释放,因此用户不再为它们付费。第三方最近的一项基准测试显示 Cloudera 如何在云数据仓库市场上具有最佳性价比。

原文作者:Justin Hayes

原文链接:https://blog.cloudera.com/memory-optimizations-for-analytic-queries-in-cloudera-data-warehouse/

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-03-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 大数据杂货铺 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 哈希表
  • 将数据折叠成指针
  • 其他需求
  • 实验评价:
  • Microbenchmark
    • 十亿行基准
      • 建立基准
        • 探针基准
          • TPCDS-10000规模
            • 每个操作减少:
              • 每节点内存减少:
                • 结论
                相关产品与服务
                数据保险箱
                数据保险箱(Cloud Data Coffer Service,CDCS)为您提供更高安全系数的企业核心数据存储服务。您可以通过自定义过期天数的方法删除数据,避免误删带来的损害,还可以将数据跨地域存储,防止一些不可抗因素导致的数据丢失。数据保险箱支持通过控制台、API 等多样化方式快速简单接入,实现海量数据的存储管理。您可以使用数据保险箱对文件数据进行上传、下载,最终实现数据的安全存储和提取。
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档