【算法】一致性哈希

一、引言

        在分布式系统中,数据存储和访问的均匀性、高可用性以及可扩展性一直是核心问题。一致性哈希算法(Consistent Hashing)是一种分布式算法,因其出色的分布式数据存储特性,被广泛应用于缓存、负载均衡、数据库分片等场景。主要用于解决缓存和负载均衡等问题。

二、算法原理

        一致性哈希算法的核心思想是将数据映射到一个固定范围的哈希环上,服务器节点也映射到这个哈希环上。数据根据哈希值顺时针查找距离最近的服务器节点,从而完成数据的存储和访问。

哈希环

        一致性哈希算法使用一个长度为2^32的环形哈希空间,通常使用MD5或SHA-1等哈希函数将数据映射到这个空间。

虚拟节点

        为了解决服务器节点分布不均匀的问题,一致性哈希引入了虚拟节点的概念。每个物理节点对应多个虚拟节点,数据映射到虚拟节点上,从而实现数据的均匀分布。

三、数据结构

        一致性哈希算法主要使用的数据结构为哈希环和节点映射表。哈希环用于存储虚拟节点,节点映射表用于存储虚拟节点与物理节点的对应关系。

        哈希环:通过哈希函数计算的一圈环状空间,用来分布数据节点和数据对象。

        节点:数据存储的实际位置,通过节点的哈希值在哈希环上定位。

        数据对象:需要进行负载均衡或分布式存储的实际数据。

四、使用场景

一致性哈希算法广泛应用于以下场景:

        分布式缓存:如Memcached、Redis等。

        负载均衡:如LVS、Nginx等。

        数据库分片:如MySQL分片、MongoDB分片等。

五、算法实现

基本步骤:

        初始化节点:将每个节点通过哈希函数映射到哈希环上。

        数据分配:计算数据对象的哈希值,将其分配给顺时针最近的节点。

一致性哈希算法的伪代码实现:

初始化哈希环
初始化节点映射表哈希函数:hash(key)
{return MD5(key) % 2^32
}添加物理节点:addNode(physicalNode)
{for (i = 0; i < 虚拟节点数; i++){virtualNode = hash(physicalNode + i)哈希环[virtualNode] = physicalNode节点映射表[virtualNode] = physicalNode}
}删除物理节点:removeNode(physicalNode)
{for (virtualNode in 节点映射表){if (节点映射表[virtualNode] == physicalNode){哈希环[virtualNode] = null节点映射表[virtualNode] = null}}
}查找节点:findNode(data)
{dataHash = hash(data)while (哈希环[dataHash] == null){dataHash = (dataHash + 1) % 2^32}return 哈希环[dataHash]
}

六、其他同类算法对比

  1. 简单哈希算法:将数据直接映射到固定数量的服务器节点,当节点数量变化时,大部分数据需要重新映射,不够灵活。
  2. 带有限负载的一致性哈希算法:在一致性哈希基础上,考虑节点负载,实现更均匀的数据分布。

七、多语言实现

  Java

// 省略部分代码,仅展示关键方法
public class ConsistentHashing {private SortedMap<Integer, String> circle = new TreeMap<>();public void addNode(String node) {for (int i = 0; i < VIRTUAL_NODES; i++) {int hash = getHash(node + "#" + i);circle.put(hash, node);}}public void removeNode(String node) {for (int i = 0; i < VIRTUAL_NODES; i++) {int hash = getHash(node + "#" + i);circle.remove(hash);}}public String findNode(String key) {if (circle.isEmpty()) {return null;}int hash = getHash(key);if (!circle.containsKey(hash)) {SortedMap<Integer, String> tailMap = circle.tailMap(hash);hash = tailMap.isEmpty() ? circle.firstKey() : tailMap.firstKey();}return circle.get(hash);}private int getHash(String key) {// 使用MD5散列函数MessageDigest md5 = MessageDigest.getInstance("MD5");md5.reset();md5.update(key.getBytes());byte[] digest = md5.digest();BigInteger bigInt = new BigInteger(1, digest);return bigInt.intValue        return bigInt.intValue() & 0x7fffffff;}
}

  Python

class ConsistentHashing:def __init__(self):self.circle = {}self.virtual_nodes = 100def _hash(self, key):return hash(key)def add_node(self, node):for i in range(self.virtual_nodes):virtual_node = f"{node}-{i}"hash_value = self._hash(virtual_node)self.circle[hash_value] = nodedef remove_node(self, node):for i in range(self.virtual_nodes):virtual_node = f"{node}-{i}"hash_value = self._hash(virtual_node)self.circle.pop(hash_value, None)def get_node(self, key):hash_value = self._hash(key)nodes = sorted(self.circle.keys())for node in nodes:if hash_value < node:return self.circle[node]return self.circle[nodes[0]]

C++

#include <iostream>
#include <string>
#include <unordered_map>
#include <vector>
#include <algorithm>class ConsistentHashing {
private:std::unordered_map<int, std::string> circle;int virtual_nodes;int _hash(const std::string& key) {std::hash<std::string> hash_fn;return hash_fn(key);}public:ConsistentHashing(int virtual_nodes) : virtual_nodes(virtual_nodes) {}void addNode(const std::string& node) {for (int i = 0; i < virtual_nodes; ++i) {std::string virtual_node = node + "-" + std::to_string(i);int hash_value = _hash(virtual_node);circle[hash_value] = node;}}void removeNode(const std::string& node) {for (int i = 0; i < virtual_nodes; ++i) {std::string virtual_node = node + "-" + std::to_string(i);int hash_value = _hash(virtual_node);circle.erase(hash_value);}}std::string getNode(const std::string& key) {int hash_value = _hash(key);auto it = circle.lower_bound(hash_value);if (it == circle.end()) {return circle.begin()->second;}return it->second;}
};

Go

package mainimport ("crypto/md5""fmt""sort""strconv"
)type ConsistentHashing struct {circle    map[int]stringvirtualNodes int
}func NewConsistentHashing(virtualNodes int) *ConsistentHashing {return &ConsistentHashing{circle:    make(map[int]string),virtualNodes: virtualNodes,}
}func (ch *ConsistentHashing) hash(key string) int {hash := md5.Sum([]byte(key))return int(hash[0]) | int(hash[1])<<8 | int(hash[2])<<16 | int(hash[3])<<24
}func (ch *ConsistentHashing) AddNode(node string) {for i := 0; i < ch.virtualNodes; i++ {hash := ch.hash(node + strconv.Itoa(i))ch.circle[hash] = node}
}func (ch *ConsistentHashing) RemoveNode(node string) {for i := 0; i < ch.virtualNodes; i++ {hash := ch.hash(node + strconv.Itoa(i))delete(ch.circle, hash)}
}func (ch *ConsistentHashing) GetNode(key string) string {hash := ch.hash(key)var keys []intfor k := range ch.circle {keys = append(keys, k)}sort.Ints(keys)for _, k := range keys {if hash < k {return ch.circle[k]}}return ch.circle[keys[0]]
}func main() {// Example usage
}

八、实际服务应用场景代码框架

// CacheServer.java
public class CacheServer {private ConsistentHashing consistentHashing;public CacheServer() {consistentHashing = new ConsistentHashing();// 初始化服务器节点consistentHashing.addNode("Server1");consistentHashing.addNode("Server2");// ... 添加更多服务器节点}public void put(String key, String value) {String server = consistentHashing.findNode(key);// 将数据存储到对应的服务器storeData(server, key, value);}public String get(String key) {String server = consistentHashing.findNode(key);// 从对应的服务器获取数据return getData(server, key);}private void storeData(String server, String key, String value) {// 实现数据存储逻辑,例如通过网络发送到指定服务器}private String getData(String server, String key) {// 实现数据获取逻辑,例如通过网络从指定服务器获取数据return "value"; // 示例返回值}public void addServer(String server) {consistentHashing.addNode(server);}public void removeServer(String server) {consistentHashing.removeNode(server);}public static void main(String[] args) {CacheServer cacheServer = new CacheServer();cacheServer.put("key1", "value1");String value = cacheServer.get("key1");System.out.println("Retrieved value: " + value);// 动态添加和删除服务器cacheServer.addServer("Server3");cacheServer.removeServer("Server1");}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/874549.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在浏览器中测试JavaScript代码方法简要介绍

在浏览器中测试JavaScript代码方法简要介绍 在浏览器中测试JavaScript代码是前端开发中的一个重要技能。方法如下&#xff1a; 1. 浏览器控制台 最简单和直接的方法是使用浏览器的开发者工具中的控制台&#xff08;Console&#xff09;。 步骤&#xff1a; 在大多数浏览器…

iOS ------ weak的基本原理

1.weak的基本概念 weak弱引用&#xff0c;所引用的对象的引用计数不会加一&#xff0c;引用对象被释放的时候会自动设置为nil多用于解决对象间的相互引用造成内存泄露的循环引用的问题 2.实现原理 Person *object [[Person alloc] init]; id __weak objc object;Runtime维…

Redis 7.x 系列【26】集群模式动态扩容、动态缩容

有道无术&#xff0c;术尚可求&#xff0c;有术无道&#xff0c;止于术。 本系列Redis 版本 7.2.5 源码地址&#xff1a;https://gitee.com/pearl-organization/study-redis-demo 文章目录 1. 动态扩容1.1 安装、启动1.2 加入新节点1.3 分配哈希槽1.4 加入从节点 2. 缩容2.1 删…

护眼灯和普通台灯有什么区别?解密护眼灯行业常见的四大选购套路

护眼灯和普通台灯有什么区别&#xff1f;随着护眼台灯的普及&#xff0c;市场上涌现了许多新兴品牌。然而&#xff0c;并非所有品牌都具备专业的技术研发实力。因此&#xff0c;网络上关于护眼台灯的各种问题也日益增多&#xff0c;如耐磨性差、耐高温性不足&#xff0c;甚至可…

python实现图像缩放算法

图像缩放算法 1.最近邻插值图像缩放算法详解算法步骤Python 实现详细解释 优缺点2.双线性插值图像缩放算法详解算法步骤Python 实现详细解释 优缺点3.双三次插值图像缩放算法详解算法步骤Python 实现详细解释 优缺点 1.最近邻插值图像缩放算法详解 最近邻插值&#xff08;Near…

go-kratos 学习笔记(4) 服务注册与发现 nacos注册

接口实现​ Registry 接口分为两个&#xff0c;Registrar 为实例注册和反注册&#xff0c;Discovery 为服务实例列表获取 type Registrar interface {// 注册实例Register(ctx context.Context, service *ServiceInstance) error// 反注册实例Deregister(ctx context.Context…

ubuntu系统vscode调试c/c++大中型项目

文章目录 1. 插件2. 项目工程3. vsode的配置setting.jsonc_cpp_properties.json 4. 启动调试 前置阅读 vscode调试第一篇 1. 插件 c/c, cmake, cmake tools 2. 项目工程 对于我的项目需要用到很多的三方库&#xff0c;三方库的版本又会有很多&#xff0c;一般都是用cmake编译…

QT写一个mainWindow

切换风格的写法&#xff1a; 先看看样式效果&#xff1a; mian_window.h文件 #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow>class MainWindow : public QMainWindow {Q_OBJECTpublic:MainWindow(QWidget *parent nullptr);~MainWindow();void Ini…

对比预测编码表示学习

对比预测编码表示学习 引言 文章主要提出如下几点&#xff1a;首先将高维数据压缩到更加紧凑的潜在嵌入&#xff08;latent embdding&#xff09;空间&#xff0c;在这个空间中条件预测更容易被建模。第二&#xff0c;在这个潜在空间中使用自回归模型&#xff0c;以对未来的多…

DC系列靶场---DC 2靶场的渗透测试(一)

信息收集 Nmap扫描 nmap -sV -p- -sC -T4 172.30.1.141 域名解析 echo 172.30.1.141 dc-2 >> /etc/hosts 目录枚举 gobuster dir -u http://172.30.1.141 -w work/lab/CTF/ATT_CK_01/SecLists-master/Discovery/Web-Content/big.txt -x .php,.rar,.html,.zip -t 20 -b…

探索XEX数字资产交易的优势与操作指南

随着数字资产市场的快速发展&#xff0c;越来越多的投资者开始关注并参与其中。XEX交易所作为一个新兴的数字资产交易平台&#xff0c;以其用户友好的界面和高效的交易服务&#xff0c;迅速吸引了大量用户。本文将介绍XEX数字资产交易的主要特点和优势&#xff0c;帮助新手更好…

物联网在电力行业的应用

作者主页: 知孤云出岫 这里写目录标题 作者主页:物联网在电力行业的应用简介主要应用领域代码案例分析1. 智能电表数据采集和分析2. 设备监控和预测性维护3. 能耗管理和优化4. 电力负载预测5. 分布式能源管理6. 电动汽车充电管理7. 电网安全与故障检测 物联网在电力行业的应用…

python+onlyoffice+vue3项目实战20240722笔记,环境搭建和前后端基础代码

开发后端 先创建data目录,然后在data目录下创建一个test.docx测试文档。 后端代码: import json import req import api from api import middleware, PlainTextResponseasync def doc_callback(request):data = await api.req.get_json(request)print("callback ==…

数据结构——堆(C语言版)

树 树的概念&#xff1a; 树&#xff08;Tree&#xff09;是一种抽象数据结构&#xff0c;它由节点&#xff08;node&#xff09;的集合组成&#xff0c;这些节点通过边相连&#xff0c;把 节点集合按照逻辑顺序抽象成图像&#xff0c;看起来就像一个倒挂着的树&#xff0c;也…

使用C#手搓Word插件

WordTools主要功能介绍 编码语言&#xff1a;C#【VSTO】 1、选择 1.1、表格 作用&#xff1a;全选文档中的表格&#xff1b; 1.2、表头 作用&#xff1a;全选文档所有表格的表头【第一行】&#xff1b; 1.3、表正文 全选文档中所有表格的除表头部分【除第一行部分】 1.…

java面向对象进阶篇--《多态》

目录 一、前言 二、认识多态 方法重写&#xff08;Override&#xff09;&#xff1a; 方法重载&#xff08;Overload&#xff09;&#xff1a; 示例&#xff1a; Person类&#xff08;父类&#xff09; Administrator&#xff08;子类&#xff09; Student&#xff08;子…

docker搭建ES 8.14 集群

参考&#xff1a;【docker搭建es8集群kibana】_docker 安装生产级 es 8.14 集群-CSDN博客 1、之前已搭建一台单机版的dockerES集群 参见 Elasticsearch docker 安装_docker 安装es8.14.3-CSDN博客 2、现在需要重新搭建为docker ES集群 准备新搭建3个点 一、准备工作 提前开…

构建网络安全之盾:应对“微软蓝屏”教训的全面策略

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

深度学习模型Transformer结构

Transformer结构是一种基于自注意力&#xff08;Self-Attention&#xff09;机制的深度学习模型&#xff0c;最初由Vaswani等人在2017年的论文《Attention Is All You Need》中提出&#xff0c;用于解决自然语言处理&#xff08;NLP&#xff09;领域的任务&#xff0c;如机器翻…

MySQL --- 库的操作

一、创建数据库 create database [ if not exists ] 数据库名; // []中的为可选项 在创建库时&#xff0c;也可以指定数据库采用的字符集(character set)和数据库字符集的校验规则(collate) (当我们创建数据库没有指定字符集和校验规则时&#xff0c;系统使用默认字符集&#x…