一致性哈希函数处理负载均衡(简单实现,勿喷)

一致性哈希算法是分布式系统中常用的负载均衡算法,特别适合动态变化的服务节点场景。它的核心思想是将服务节点和数据映射到一个虚拟的哈希环上,通过哈希值定位数据所属的节点。当节点增加或减少时,一致性哈希算法能够最小化数据迁移的影响。

算法设计:

1.数据结构:

  • 哈希环 :使用 map(有序map) / unordered_map(键无序map) 来存储虚拟节点和真实节点的映射关系。

  • 虚拟节点:为了提高负载均衡的均匀性,为每个真实节点创建多个虚拟节点。

  • 哈希函数:选择MD5作为哈希函数,将节点和 key 映射到一个 32 位的哈希值。

2.代码实现:

cpp 复制代码
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include <algorithm>
#include <functional>
#include <openssl/md5.h>  // 使用 MD5 作为哈希函数

class ConsistentHash {
public:
    // 添加节点
    void AddNode(const std::string& node, int virtualNodeCount) {
        for (int i = 0; i < virtualNodeCount; ++i) {
            std::string virtualNode = node + "#" + std::to_string(i);
            size_t hash = Hash(virtualNode);
            ring_[hash] = node;
        }
    }

    // 删除节点
    void RemoveNode(const std::string& node) {
        auto it = ring_.begin();
        while (it != ring_.end()) {
            if (it->second == node) {
                it = ring_.erase(it);
            } else {
                ++it;
            }
        }
    }

    // 根据 key 获取目标节点
    std::string GetNode(const std::string& key) {
        if (ring_.empty()) {
            throw std::runtime_error("No nodes available in the ring.");
        }

        size_t hash = Hash(key);
        auto it = ring_.lower_bound(hash);  // 找到第一个大于等于 hash 的节点

        if (it == ring_.end()) {
            // 如果没找到,则选择环中的第一个节点
            it = ring_.begin();
        }

        return it->second;
    }

private:
    // 哈希函数(使用 MD5)
    size_t Hash(const std::string& key) {
        unsigned char digest[MD5_DIGEST_LENGTH];
        MD5((const unsigned char*)key.c_str(), key.size(), digest);

        // 将 MD5 哈希值转换为 size_t
        size_t hash = 0;
        for (int i = 0; i < 4; ++i) {  // 简化 故只取前 4 个字节作为哈希值
            hash = (hash << 8) | digest[i];
        }
        return hash;
    }

    // 哈希环,存储哈希值到节点的映射
    std::map<size_t, std::string> ring_;
};

代码说明:

  1. 虚拟节点

    • 每个真实节点对应多个虚拟节点(通过 AddNode 方法的 virtualNodeCount 参数控制)。

    • 虚拟节点的数量越多,负载分布越均匀,但也会增加内存开销。

    • 优化分析:虚拟节点的引入是为了解决一致性哈希算法在节点数量较少时负载不均衡的问题。可以进一步优化虚拟节点的生成方式,可以根据节点的权重动态调整虚拟节点的数量

  2. 哈希环

    • 使用 map 存储哈希值到节点的映射,map 本身是有序的,便于快速查找。
  3. 节点查找

    • 使用 lower_bound 方法在哈希环中查找第一个大于等于 key 哈希值的节点。

    • 如果没找到(即 key 的哈希值大于所有节点的哈希值),则选择环中的第一个节点。

  4. 动态节点变化

    • 通过 AddNodeRemoveNode 方法支持节点的动态添加和删除。

    • 当节点变化时,只有部分 key 需要重新映射,其他 key 的映射关系保持不变

    • 优化分析:

      可以进一步优化节点变化的处理效率,在删除节点时,批量移除虚拟节点,减少遍历哈希环的次数。在添加节点时,预分配虚拟节点的哈希值,减少哈希计算的开销

测试:

cpp 复制代码
int main() {
    ConsistentHash ch;

    // 添加节点,假设每个节点有 3 个虚拟节点
    ch.AddNode("Node1", 3);
    ch.AddNode("Node2", 3);
    ch.AddNode("Node3", 3);

    // 测试 key 的路由
    std::vector<std::string> keys = {"Key1", "Key2", "Key3", "Key4", "Key5"};
    for (const auto& key : keys) {
        std::string node = ch.GetNode(key);
        std::cout << "Key: " << key << " -> Node: " << node << std::endl;
    }

    // 删除一个节点
    ch.RemoveNode("Node2");
    std::cout << "\n 删除Node2:\n";

    // 再次测试 key 的路由
    for (const auto& key : keys) {
        std::string node = ch.GetNode(key);
        std::cout << "Key: " << key << " -> Node: " << node << std::endl;
    }

    return 0;
}

结果:

cpp 复制代码
Key: Key1 -> Node: Node1
Key: Key2 -> Node: Node3
Key: Key3 -> Node: Node2
Key: Key4 -> Node: Node1
Key: Key5 -> Node: Node3

删除 Node2:
Key: Key1 -> Node: Node1
Key: Key2 -> Node: Node3
Key: Key3 -> Node: Node1
Key: Key4 -> Node: Node1
Key: Key5 -> Node: Node3

当与具体场景的负载均衡结合:

  1. 服务注册 :当服务节点注册时,调用 AddNode 方法将其添加到哈希环中。

  2. 服务发现 :当客户端发起请求时,调用 GetNode 方法根据请求的 key 找到目标节点。

  3. 动态变化 :当服务节点下线时,调用 RemoveNode 方法将其从哈希环中移除。

相关推荐
Doopny@12 分钟前
数字组合(信息学奥赛一本通-1291)
数据结构·算法·动态规划
原来是猿1 小时前
蓝桥备赛(13)- 链表和 list(上)
开发语言·数据结构·c++·算法·链表·list
项目申报小狂人1 小时前
高性能算法NGO!北方苍鹰优化算法(Northern Goshawk Optimization,NGO)
算法·数学建模
且听风吟ayan1 小时前
leetcode day26 重复的子字符串
算法·leetcode·c#
仟濹1 小时前
【算法 C/C++】二维差分
c语言·c++·算法
*星星之火*2 小时前
【GPT入门】第9课 思维树概念与原理
gpt·算法·深度优先
总斯霖2 小时前
题解:士兵排列
数据结构·c++·算法
稳兽龙2 小时前
P4268 [USACO18FEB] Directory Traversal G
c++·算法·换根dp
我是大咖3 小时前
c语言笔记 一维数组与二维数组
c语言·笔记·算法
誓约酱3 小时前
(每日一题) 力扣 283 移动零
linux·c语言·数据结构·c++·算法·leetcode