一致哈希算法:如何分群,突破集群的“领导者”限制?

一、一致哈希算法的背景1.1 传统哈希算法的问题在传统的哈希算法中,数据存储通常采用如下映射关系:node=hash(key)%Nnode = hash(key) \% Nkey:数据的键N:当前集群中节点的数量问题:当节点数量发生变化(例如从2个节点扩展到3个节点),几乎所有的键都会被重新分配到不同的节点上,导致大量数据迁移。 示例:2个节点:hash(key) % 2 → 节点0、节点1扩展到3个节点:hash(key) % 3 → 节点0、节点1、节点2可以看到,大部分数据的映射发生了变化。 1.2 一致哈希的引入一致哈希算法 使用了一个逻辑哈希环(Hash Ring)的概念,将整个哈希空间(0到2^32-1)组织成一个环形结构。

一、一致哈希算法的背景

1.1 传统哈希算法的问题

在传统的哈希算法中,数据存储通常采用如下映射关系:

node=hash(key)%Nnode = hash(key) \% N

  • key:数据的键
  • N:当前集群中节点的数量

问题:当节点数量发生变化(例如从2个节点扩展到3个节点),几乎所有的键都会被重新分配到不同的节点上,导致大量数据迁移。

示例:

  • 2个节点:hash(key) % 2 → 节点0、节点1
  • 扩展到3个节点:hash(key) % 3 → 节点0、节点1、节点2

可以看到,大部分数据的映射发生了变化。

1.2 一致哈希的引入

一致哈希算法 使用了一个逻辑哈希环(Hash Ring)的概念,将整个哈希空间(0到2^32-1)组织成一个环形结构。每个节点和数据的Key都通过哈希函数映射到哈希环上。数据会存储到顺时针方向上第一个大于等于该Key的节点上。

1.3 一致哈希的优点

  • 数据迁移量小:当一个节点加入或移除时,只影响它在哈希环上的相邻节点。
  • 可扩展性强:节点可以自由加入或退出,不会对整个系统产生大规模影响。
  • 负载均衡:结合虚拟节点(Virtual Node)技术,能有效解决节点分布不均匀的问题。

二、一致哈希算法原理

2.1 哈希环

一致哈希将哈希空间组织成一个逻辑的环形结构,哈希值的范围是 0→232−10 \rightarrow 2^{32}-1。

  • 节点映射:通过哈希函数将每个节点映射到环上的某个位置。
  • Key映射:将每个Key映射到环上的某个位置。
  • 数据存储规则:Key存储到顺时针方向遇到的第一个节点上。

2.2 虚拟节点(Virtual Nodes)

实际场景中,节点可能会分布不均匀,导致某些节点负载较高。为了解决这个问题,引入了虚拟节点,即为每个实际节点分配多个哈希值,使节点分布更加均匀。

2.3 数据迁移

  • 节点增加:新节点只接管部分相邻节点的数据。
  • 节点移除:原本分配到该节点的数据会被顺时针下一个节点接管。

三、一致哈希的核心实现

接下来,我们通过 Go语言 来实现一个简单的一致哈希算法,并添加详细的注释。

3.1 基本结构定义

复制
packageconsistenthash

import (
    "hash/crc32"
    "sort"
    "strconv"
)

// 一致性哈希结构体
typeConsistentHashstruct {
    hash     func(data []byte) uint32   // 哈希函数
    replicasint                        // 虚拟节点倍数
    keys     []int                      // 哈希环上的所有虚拟节点
    nodes    map[int]string             // 虚拟节点到真实节点的映射
}

// 构造函数
funcNewConsistentHash(replicasint, fnfunc(data []byte) uint32) *ConsistentHash {
    m :=&ConsistentHash{
        replicas: replicas,
        hash:     fn,
        nodes:    make(map[int]string),
    }
    ifm.hash==nil {
        m.hash=crc32.ChecksumIEEE// 默认哈希函数
    }
    returnm
}

3.2 添加节点

复制
// 添加节点
func (m*ConsistentHash) AddNode(nodes...string) {
    for_, node :=rangenodes {
        fori :=0; i<m.replicas; i++ {
            // 为每个节点生成多个虚拟节点
            hash :=int(m.hash([]byte(node+strconv.Itoa(i))))
            m.keys=append(m.keys, hash)
            m.nodes[hash] =node
        }
    }
    // 对所有节点进行排序,保证哈希环的有序性
    sort.Ints(m.keys)
}

3.3 获取节点

复制
// 获取节点
func (m*ConsistentHash) GetNode(keystring) string {
    iflen(m.keys) ==0 {
        return""
    }
    hash :=int(m.hash([]byte(key)))
    // 顺时针找到第一个大于哈希值的节点
    idx :=sort.Search(len(m.keys), func(iint) bool {
        returnm.keys[i] >=hash
    })
    ifidx==len(m.keys) {
        idx=0// 环状回到第一个节点
    }
    returnm.nodes[m.keys[idx]]
}

3.4 移除节点

复制
// 移除节点
func (m*ConsistentHash) RemoveNode(nodestring) {
    fori :=0; i<m.replicas; i++ {
        hash :=int(m.hash([]byte(node+strconv.Itoa(i))))
        delete(m.nodes, hash)
        fori, v :=rangem.keys {
            ifv==hash {
                m.keys=append(m.keys[:i], m.keys[i+1:]...)
                break
            }
        }
    }
}

3.5 测试示例

复制
packagemain

import (
    "fmt"
    "consistenthash"
)

funcmain() {
    ch :=consistenthash.NewConsistentHash(3, nil)
    ch.AddNode("NodeA", "NodeB", "NodeC")

    fmt.Println("Key-1 is mapped to:", ch.GetNode("Key-1"))
    fmt.Println("Key-2 is mapped to:", ch.GetNode("Key-2"))

    ch.AddNode("NodeD") // 添加新节点

    fmt.Println("After adding NodeD:")
    fmt.Println("Key-1 is mapped to:", ch.GetNode("Key-1"))
    fmt.Println("Key-2 is mapped to:", ch.GetNode("Key-2"))
}

四、一致哈希的优缺点

4.1 优点

  • 扩展性强:节点加入/退出只影响少部分数据。
  • 负载均衡:结合虚拟节点,负载更均匀。
  • 容错性强:节点故障时,影响范围较小。

4.2 缺点

  • 虚拟节点配置:虚拟节点的配置需要平衡性能和分布。
  • 数据倾斜:即使使用虚拟节点,仍然可能存在轻微的不均匀。

五、总结

一致哈希算法 是解决分布式KV存储中数据迁移问题的重要手段。通过逻辑哈希环和虚拟节点技术,可以有效避免传统哈希算法的迁移瓶颈,并实现较好的负载均衡。

相关资讯

进我的收藏夹吃灰吧:大模型加速超全指南来了

2023 年,大型 语言模型(LLM)以其强大的生成、理解、推理等能力而持续受到高度关注。然而,训练和部署 LLM 非常昂贵,需要大量的计算资源和内存,因此研究人员开发了许多用于加速 LLM 预训练、微调和推理的方法。最近,一位名为 Theia Vogel 的博主整理撰写了一篇长文博客,对加速 LLM 推理的方法进行了全面的总结,对各种方法展开了详细的介绍,值得 LLM 研究人员收藏查阅。以下是博客原文内容。之前,我使用经典的自回归采样器手动制作了一个 transformer,大致如下:这种推理方法很优雅,是 LL

融合趋势下基于 Flink Kylin Hudi 湖仓一体的大数据生态体系

本文由 T3 出行大数据平台负责人杨华和资深大数据平台开发工程师王祥虎介绍 Flink、Kylin 和 Hudi 湖仓一体的大数据生态体系以及在 T3 的相关应用场景,内容包括: 湖仓一体的架构 Flink/Hudi/Kylin 介绍与融合 T3 出行结合湖仓一体的实践

Snowflake如日中天是否代表Hadoop已死?大数据体系到底是什么?

作者 | 阿里云计算平台研究员关涛、阿里巴巴项目管理专家王璀任何一种技术都会经历从阳春白雪到下里巴人的过程,就像我们对计算机的理解从“戴着鞋套才能进的机房”变成了随处可见的智能手机。在前面20年中,大数据技术也经历了这样的过程,从曾经高高在上的 “火箭科技(rocket science)”,成为了人人普惠的技术。回首来看,大数据发展初期涌现了非常多开源和自研系统,并在同一个领域展开了相当长的一段“红海”竞争期,例如Yarn VS Mesos、Hive VS Spark、Flink VS SparkStreaming