DZone>大数据专区>在Presto中使用一致的哈希方法来提高动态集群中的缓存数据定位性
在Presto中使用一致哈希算法来改善动态集群中的缓存数据位置
本文介绍了一种用于软亲和力调度的新散列算法--一致散列,以解决集群大小变化时的问题。
-
Mar. 28, 22 - 大数据区 -教程
喜欢 (5)
评论
保存
鸣谢
2.14K浏览次数
加入DZone社区,获得完整的会员体验。
使用Alluxio运行Presto在社区中越来越受欢迎。它通过利用SSD或内存来缓存靠近Presto工作者的热数据集,避免了从远程存储读取数据的长延迟。Presto支持基于哈希的软亲和力调度,强制要求在整个集群中只缓存一份或两份相同的数据,这通过允许更多的热数据在本地缓存来提高缓存效率。然而,目前使用的散列算法在集群规模发生变化时并不能很好地工作。本文介绍了一种新的软亲和调度的散列算法--一致散列,以解决这个问题。
软亲和力调度
Presto使用一种叫做软亲和调度的调度策略,将一个分片(最小的数据处理单位)调度给同一个Presto工作者*(首选节点*)。分割和Presto工作者之间的映射是由分割上的散列函数计算出来的,确保同一分割总是被散列到同一工作者。在第一次处理分片时,数据将被缓存在首选工作节点上。当后续查询处理同一分割时,这些请求将再次被安排到同一工作节点。由于数据已经在本地缓存了,所以不需要远程读取。
为了提高负载平衡和处理摇摆不定的工作节点,选择了两个首选节点。如果第一个选择很忙或没有反应,就使用第二个。数据可能会在2个工作节点上进行物理缓存。
关于软亲和调度的更多细节,请阅读《用Alluxio数据缓存改善Presto延迟》。
哈希算法
软亲和调度依赖于哈希算法来计算分裂和工作节点之间的映射。之前,使用的是模块化函数。
WorkerID1 =Hash(splitID) % workerCount
WorkerID2 =Hash(splitID) % workerCount + 1
这种散列策略很简单,在集群稳定且工人节点没有变化时,效果很好。然而,如果一个工作器暂时不可用或停机,工作器数量可能会发生变化,拆分到工作器的映射会完全重新洗牌,导致缓存命中率大幅下降。如果有问题的工作者稍后重新上线,这种重新洗牌就会再次发生。
为了缓解这个问题,Presto在使用模块化计算工位分配时,使用所有工位计数而不是活动工位计数。然而,这只能缓解临时工人节点离线造成的重新洗牌。在有些情况下,由于工作负载的波动,增加/删除工作者是有意义的。在这些情况下,是否有可能仍然保持合理的缓存命中率而不引入大量的重洗?解决方案就是一致哈希。
一致性哈希
一致性散列的概念是由David Karger在1997年提出的,作为一种在不断变化的网络服务器群中分配请求的方法。该技术被广泛用于负载平衡、分布式哈希表等。
一致性哈希是如何工作的?
想象一下,散列输出范围[0, MAX_VALUE]被映射到一个圆上(将MAX_VALUE连接到0)。为了证明一致性哈希的工作原理,假设一个由3个Presto工作节点组成的Presto集群,有10个分片被反复查询。
首先,工人节点被散列到散列环上。对于每个分片,它将被分配到散列环上与其散列值相邻的工作者。
在上面的方案中,分片的分配情况如下。
| 工作者1 | Split1, Split4, Split6, Split8 |
| 工作者2 | 分割0,分割5,分割7 |
| 工人3 | 分割2, 分割3, 分割9 |
移除一个工作器
现在,如果worker2由于某种原因脱机了,根据该算法,Split 0、5和7将被安排给具有下一个哈希值的worker,也就是worker2。
| Worker1 | 分割0、分割1、分割4、分割5、分割6、分割7、分割8 |
| 工作者3 | Split2、Split3、Split9 |
只有被散列到离线工作者(在我们的例子中是 worker3)的分片需要重新散列。其他数据不受影响。如果 worker3 稍后上线,Split2、3 和 9 将再次被哈希到 worker3,而不会影响其他 worker 的命中率。
增加一个工作器
现在,如果工作负载增加,需要向集群中添加另一个工作节点,即worker4。Worker4的散列值在散列环上的情况如下。
在这种情况下,split8将落入worker4的范围,所有其他split的分配不受影响,因此这些split的缓存命中率不会受到影响。新的分配是
| 工作者1 | Split1, Split4, Split6 |
| 工作者2 | Split0, Split5, Split7 |
| 工人3 | 分割2, 分割3, 分割9 |
| 工作者4 | 分割8 |
虚拟节点
从上面可以看出,一致性散列可以保证在节点变化的情况下,平均只有Nsplits/Nnodes的分裂需要被重新散列。然而,由于工人分布缺乏随机性,分片可能不会均匀地分布在所有工人节点上。引入 "虚拟节点 "的概念是为了缓解这个问题。虚拟节点还可以帮助在一个节点断开连接时将其负载重新分配给多个节点,从而减少由于集群不稳定而导致的负载波动。
每个物理工作者节点都有多个虚拟节点映射到它。虚拟节点被放在散列环上。分割将被分配到散列环上的下一个虚拟节点,从而路由到映射到虚拟节点的物理节点。下面的例子显示了一种可能的情况,每个物理工人节点有3个虚拟节点。
| Worker1 | Worker1_v1 | 分割6 |
| Worker1_v2 | Split4, Split8 | |
| 工作者1_v3 | 分割1 | |
| 工作者2 | Worker2_v1 | 分割5,分割7 |
| 工作者2_v2 | 分割0,分割2,分割3 | |
| 工作者2_v3 | 分割9 |
随着散列环上节点数量的增加,散列空间更有可能被均匀地分割。
在一个物理节点宕机的情况下,与该物理节点相对应的所有虚拟节点都将被重新拆分。但现在不是所有的分割都被重新洗牌到同一个节点,而是分布在多个虚拟节点上,从而映射到多个物理节点,提供更好的负载平衡。
下面显示了当 worker3 被移除时,Split2 和 3 被重构到 worker2,而 Split8 被重构到 worker1。
| Worker1 | Worker1_v1 | 分割6 |
| 工作者1_v2 | 分割4,分割8 | |
| 工作者1_v3 | 分割1 | |
| 工作者2 | Worker2_v1 | 分割5,分割7 |
| 工作者2_v2 | 分割0,分割2,分割3 | |
| 工作者2_v3 | 分割9 |
如何在Presto中使用一致的哈希方法?
这目前是我们最近贡献给Presto的一个实验性功能。如果你对测试或合作感兴趣,请随时联系我们。
要使用这个功能,首先要按照这个说明或这个教程启用Presto的缓存。
确保你选择SOFT_AFFINITY作为调度策略。在/catalog/hive.properties ,添加hive.node-selection-strategy=SOFT_AFFINITY 。
启用一致性散列。在config.properties 中,添加node-scheduler.node-selection-hash-strategy=CONSISTENT_HASHING 。
结论
如上所述,当节点被引入或移除时,一致散列可以将工作负载分配的影响降到最低。当集群的工作节点发生变化时,基于一致散列的工作负载调度可以将对现有节点的缓存命中率的影响降到最低。这使得一致性缓存成为一种更好的策略,可用于Presto的集群规模将根据工作负载的需要而扩大或缩小,或者用于部署不完全控制硬件的情况下,工人可能会不时地被重新安置。
在Alluxio社区,我们一直在不断改进Alluxio和数据应用(例如本文中的Presto)之间的整合,无论是在功能还是可用性方面。随着Presto调度中一致性散列的引入,Alluxio可以更好地利用Presto中软亲和力的潜力,具有更高的数据定位和缓存效率,这可以转化为更好的性能和成本效益。我们将继续为数据生态系统带来进一步的改进和优化。
主题。
Presto, 缓存, 散列, 数据定位, 教程, alluxio
经钟蓉蓉许可,发表于DZone。点击这里查看原文。
DZone贡献者所表达的观点属于他们自己。
DZone上的热门文章
评论