当前位置: 首页 > backend >正文

一致性哈希

https://github.com/apache/brpc/blob/master/docs/cn/consistent_hashing.md#%E6%A6%82%E8%BF%B0

概述

一些场景希望同样的请求尽量落到一台机器上,比如访问缓存集群时,我们往往希望同一种请求能落到同一个后端上,以充分利用其上已有的缓存,不同的机器承载不同的稳定working set。而不是随机地散落到所有机器上,那样的话会迫使所有机器缓存所有的内容,最终由于存不下形成颠簸而表现糟糕。 我们都知道hash能满足这个要求,比如当有n台服务器时,输入x总是会发送到第hash(x) % n台服务器上。但当服务器变为m台时,hash(x) % n和hash(x) % m很可能都不相等,这会使得几乎所有请求的发送目的地都发生变化,如果目的地是缓存服务,所有缓存将失效,继而对原本被缓存遮挡的数据库或计算服务造成请求风暴,触发雪崩。一致性哈希是一种特殊的哈希算法,在增加服务器时,发向每个老节点的请求中只会有一部分转向新节点,从而实现平滑的迁移。这篇论文中提出了一致性hash的概念。

一致性hash满足以下四个性质:

  • 平衡性 (Balance) : 每个节点被选到的概率是O(1/n)。
  • 单调性 (Monotonicity) : 当新节点加入时, 不会有请求在老节点间移动, 只会从老节点移动到新节点。当有节点被删除时,也不会影响落在别的节点上的请求。
  • 分散性 (Spread) : 当上游的机器看到不同的下游列表时(在上线时及不稳定的网络中比较常见), 同一个请求尽量映射到少量的节点中。
  • 负载 (Load) : 当上游的机器看到不同的下游列表的时候, 保证每台下游分到的请求数量尽量一致。

实现方式

所有server的32位hash值在32位整数值域上构成一个环(Hash Ring),环上的每个区间和一个server唯一对应,如果一个key落在某个区间内, 它就被分流到对应的server上。

当删除一个server的,它对应的区间会归属于相邻的server,所有的请求都会跑过去。当增加一个server时,它会分割某个server的区间并承载落在这个区间上的所有请求。单纯使用Hash Ring很难满足我们上节提到的属性,主要两个问题:

  • 在机器数量较少的时候, 区间大小会不平衡。
  • 当一台机器故障的时候, 它的压力会完全转移到另外一台机器, 可能无法承载。

为了解决这个问题,我们为每个server计算m个hash值,从而把32位整数值域划分为n*m个区间,当key落到某个区间时,分流到对应的server上。那些额外的hash值使得区间划分更加均匀,被称为虚拟节点(Virtual Node)。当删除一个server时,它对应的m个区间会分别合入相邻的区间中,那个server上的请求会较为平均地转移到其他server上。当增加server时,它会分割m个现有区间,从对应server上分别转移一些请求过来。

由于节点故障和变化不常发生,我们选择了修改复杂度为O(n)的有序数组来存储hash ring,每次分流使用二分查找来选择对应的机器,由于存储是连续的,查找效率比基于平衡二叉树的实现高。线程安全性请参照Double Buffered Data章节.

使用方式

我们内置了分别基于murmurhash3和md5两种hash算法的实现,使用要做两件事:

  • 在Channel.Init 时指定load_balancer_name为 “c_murmurhash” 或 “c_md5”。
  • 发起rpc时通过Controller::set_request_code(uint64_t)填入请求的hash code。

request的hash算法并不需要和lb的hash算法保持一致,只需要hash的值域是32位无符号整数。由于memcache默认使用md5,访问memcached集群时请选择c_md5保证兼容性,其他场景可以选择c_murmurhash以获得更高的性能和更均匀的分布。

虚拟节点个数

通过-chash_num_replicas可设置默认的虚拟节点个数,默认值为100。对于某些特殊场合,对虚拟节点个数有自定义的需求,可以通过将load_balancer_name加上参数replicas=配置,如:

channel.Init("http://...", "c_murmurhash:replicas=150", &options);
http://www.xdnf.cn/news/6213.html

相关文章:

  • 数据结构:ArrayList简单实现与常见操作实例详解
  • C#高级编程:加密解密
  • 自动化测试避坑指南:5大常见问题与应对策略
  • Java面向对象三大特性深度解析
  • Pass-the-Hash攻击原理与防御实战指南
  • 进程间通信(Windows事件)
  • 【教程】Docker方式本地部署Overleaf
  • 内存划分包括 Flash存储器、SRAM 和 外设寄存器
  • nginx 出现大量connect reset by peer
  • 第二章日志分析-apache日志分析
  • 秒删node_modules[无废话版]
  • 数据结构(八)——查找
  • 达梦数据库 【-6111: 字符串转换出错】问题处理
  • HVV蓝队实战面试题
  • 全新开发-iVX图形化编程VS完整IDE
  • 有关多线程
  • vue中,created和mounted两个钩子之间调用时差值受什么影响
  • Ubuntu摄像头打开失败
  • 16S18S_OTU分析(3)
  • 正则表达式(二)-高级应用_谨慎使用
  • Spark之搭建Yarn模式
  • 日本动漫风格人像街拍Lr调色预设,手机滤镜PS+Lightroom预设下载!
  • 【PostgreSQL数据分析实战:从数据清洗到可视化全流程】附录-D. 扩展插件列表(PostGIS/PostgREST等)
  • 搭建Caffeine+Redis多级缓存机制
  • ChatGPT 能“记住上文”的原因
  • nputop:昇腾 NPU 交互式监控工具
  • 基于 NanoDet 的工厂巡检机器人目标识别系统研究与实现​
  • Fluent Bit持久化配置:保障数据可靠传输的关键
  • MVCC:数据库并发控制的利器
  • 【计算机哲学故事1-5】版本更新:拒绝停滞,成长是最好的修复