一致性哈希(哈希环)解决数据分布问题

哈希算法是程序开发过程中最广泛接触到的的算法之一,典型的应用有安全加密、数据校验、唯一标识、散列函数、负载均衡、数据分片、分布式存储。前些天刚接触到夜莺项目,听介绍目前V6版本集群方式部署,告警生成是通过一致性哈希(哈希环)去分片处理,不过我细想一下,对一致性哈希这个知识点好像了解过,但是又没太深印象,说不出具体是什么原理,怎么用,有哪些注意的地方。本文简单记录,希望也能给其他人作为初步了解所用。
另外强烈推荐大家在需要落地企业级观测平台方案考虑使用 夜莺(nightingale) ,开源、用户多而且社区氛围不错,官方怕大家网络不方便访问,还特地开了答疑论坛。

1.解决怎样的问题

一个常见的结论是在需要均匀的解决数据分布场景时通过引入一致性哈希算法可以很好解决此类问题。

一致性哈希诞生,是麻省理工学院在1997年提出的一种分布式哈希(DHT)实现算法,其设计目标是为了解决因特网中的热点(Hot Spot)问题,将来自网络上的流量动态的均匀分发到不同的服务器处理;
处理大量数据时很可能是遇到类似这样的难点:

  • 1.处理文件很大单台机器内存受限无法计算;
  • 2.如果单台机器处理这样大量数据处理耗时很大;

为了突破单机内存,cup资源限制,借助分片思路,先切分数据,再利用多台机器提高处理速度,最后在合并起来得到最终结果,这个处理过程也是MapReduce的基本思想,不过再思考一下,仅仅是解决上面问题话,一个普通的哈希算法就能解决;为什么会要引入一致性哈希算法呢?

当数据增多,需要扩容机器时,直接加上新机器,那么所有数据会遇到一个问题,就是之前哈希值不对了,通常哈希值计算和机器数量有关,最简单就是对机器数量取模,当数量变化是需要重新计算哈希值,然后搬移数据到正确的机器上,用在缓存场景就相当于所有缓存失效,请求数据穿透缓存,直接请求数据库,这样就很容易发生雪崩效应。所以就需要一种新方法,让加入机器后,不需要做大量数据迁移。

2.原理介绍

ask:致性哈希原理介绍
answer:
一致性哈希是一种用于分布式系统中数据分片和负载均衡的算法。它的核心思想是将数据根据哈希值映射到一个环形空间中,然后将节点也映射到环上。当需要查找某个数据时,先计算该数据的哈希值,然后沿着环的顺时针方向找到第一个大于等于该哈希值的节点,即为该数据所在的节点。这样可以将数据均匀地分布在各个节点上,并且在节点动态添加或删除时,只需要重新映射该节点的哈希值,而不需要重新映射所有数据的哈希值,从而避免了数据迁移的开销。
一致性哈希算法的优点是具有高度的可扩展性和容错性,能够自动适应节点的动态变化,同时保证数据的一致性和负载均衡。它被广泛应用于分布式缓存、分布式数据库、负载均衡等领域。
Powered by ChatGPT

再借用大牛们对一致性哈希原理介绍的,通过hash函数映射到一个哈希环上,哈希环可以理解为一个连续变好的循环链表,一般会用32位的哈希值,可以映射2^32个值。

假设key1和key2经过计算都命中哈希环上一个机器节点0,此时新加入一个节点n,节点n接管了部分原来归属于节点0的区域(只有key2在其中),此时再次访问key1和key2,只会有key2因为变更节点,需要重新迁移数据。

3.一致性哈希优点

从上面原理介绍,我们可以很容易看到一致性哈希算法在可伸缩性的优点,我们简单模拟下看看是否解决之前的雪崩问题,另外这里我们再讨论下它均衡性优点。

我们模拟一下当机器B故障,需要在服务列表里摘除机器B。我们直接将故障机器B从哈希环上移除,原来归属于机器B的数据按照一致性哈希规则,应该被缓存到哈希环上下一个机器节点例如机器C。其他数据并不会因此产生变化,只有一部分缓存失败需要重新构建,从而不至于所有全部缓存失效导致的雪崩效应问题。

不过就像买家秀和买家秀的巨大差距一样,通常理想很丰满,现实很骨感。只是按照上述定义,哈希环上机器映射大概率是没法均分的,缓存对象很大可能被集中在某一台机器上,分布极度不均,产生hash环的偏斜,极端情况下,仍然可能引起系统崩溃。所以一致性哈希算法中使用‘虚拟节点’解决这个问题。

所谓‘虚拟节点’就是有实际节点虚拟复制而来的节点,填充在哈希环上,让机器尽量多,均匀的出现在哈希环上,所以通常是一个实际节点对应多个虚拟节点。有虚拟节点加入后再看哈希环,我们就可以达到良好的均衡性,减少哈希环偏斜带来的影响,缓存也就被均匀分布概率越大。

4. 夜莺项目-告警

根据关键字hashring我们可以看到这些相关的代码,确实都是和告警相关,我们再细细研究一下
hashring在n9e的应用
首先很明显,通过 hashring.go中 DatasourceHashRingType 这个结构体我们可以看这里用的是golang 一致性hash 库consistent,我们再看看具体是如何使用的

package namingimport ("errors""sync""github.com/toolkits/pkg/consistent""github.com/toolkits/pkg/logger"
)
//节点副本个数500
const NodeReplicas = 500
//hashring结构体,一个支持并发的map,key是int类型,value是hashring
type DatasourceHashRingType struct {sync.RWMutexRings map[int64]*consistent.Consistent
}// for alert_rule sharding
var HostDatasource int64 = 100000
//hashring对象实例
var DatasourceHashRing = DatasourceHashRingType{Rings: make(map[int64]*consistent.Consistent)}
//创建一个哈希环方法
func NewConsistentHashRing(replicas int32, nodes []string) *consistent.Consistent {ret := consistent.New()ret.NumberOfReplicas = int(replicas)for i := 0; i < len(nodes); i++ {ret.Add(nodes[i])}return ret
}
//重建key为datasourceId的hashring
func RebuildConsistentHashRing(datasourceId int64, nodes []string) {r := consistent.New()r.NumberOfReplicas = NodeReplicasfor i := 0; i < len(nodes); i++ {r.Add(nodes[i])}DatasourceHashRing.Set(datasourceId, r)logger.Infof("hash ring %d rebuild %+v", datasourceId, r.Members())
}
//根据datasourceId获取hashring,并查询hashring上pk命中的节点
func (chr *DatasourceHashRingType) GetNode(datasourceId int64, pk string) (string, error) {chr.RLock()defer chr.RUnlock()_, exists := chr.Rings[datasourceId]if !exists {chr.Rings[datasourceId] = NewConsistentHashRing(int32(NodeReplicas), []string{})}return chr.Rings[datasourceId].Get(pk) //Get returns an element close to where name hashes to in the circle.
}
//判断datasourceId获取的hashring上pk是否和currentNode相同
func (chr *DatasourceHashRingType) IsHit(datasourceId int64, pk string, currentNode string) bool {node, err := chr.GetNode(datasourceId, pk)if err != nil {if errors.Is(err, consistent.ErrEmptyCircle) {logger.Debugf("rule id:%s is not work, datasource id:%d is not assigned to active alert engine", pk, datasourceId)} else {logger.Debugf("rule id:%s is not work, datasource id:%d failed to get node from hashring:%v", pk, datasourceId, err)}return false}return node == currentNode
}
//根据datasourceId设置hashring
func (chr *DatasourceHashRingType) Set(datasourceId int64, r *consistent.Consistent) {chr.RLock()defer chr.RUnlock()chr.Rings[datasourceId] = r
}

具体用到的地方
1.heartbeat() 维护心跳(实例和集群的对应关系),当发现某台机器离线,也就hashingring节点需要摘除故障节点,调用RebuildConsistentHashRing重建离线实例对应的哈希环,新哈希环的节点摘除离线节点。

    oldss, exists := localss[datasourceIds[i]]if exists && oldss == newss {continue}RebuildConsistentHashRing(datasourceIds[i], servers)

2.syncRecordRules() 同步规则,遍历所有规则,用每个规则匹配PromClientMap 根据当前有效的 datasourceId 和规则的 datasourceId 配置计算有效的cluster列表,确认在哈希环中这条规则是否命中当前节点,命中存入recordRules等待调度(这部分规则应该就是哈希环节点变更迁移的规则,应该是少数),接着在调度缓存中的s.recordRules(这部分规则是哈希环上没有变更节点的规则)

    datasourceIds := s.promClients.Hit(rule.DatasourceIdsJson)for _, dsId := range datasourceIds {if !naming.DatasourceHashRing.IsHit(dsId, fmt.Sprintf("%d", rule.Id), s.aconf.Heartbeat.Endpoint) {continue}recordRule := NewRecordRuleContext(rule, dsId, s.promClients, s.writers)recordRules[recordRule.Hash()] = recordRule}

3.syncAlertRules()同步告警规则,同syncRecordRules类似最后匹配的告警规则添加alertRuleWorkers,进行告警判断调度

4.makeEvent()路由事件,转发对应事件给哈希环上命中的节点。

4.总结和思考

一致性哈希主要解决数据分布场景,它存在这样的优点:

  • 1.可伸缩性
  • 2.负载平衡 (将节点与Hash算法解耦,而且通过交错分配虚拟节点的方式解决了负载不均衡导致的缓存热点问题)

缺点(有个观点是用错了场景才是缺陷,用对了,那是特性):

  • 1.key值通过hash算法算出,映射固定,不灵活,而且节点数量变化时虚拟节点数量也会变化,这种耦合限制哈希算法进一步优化
  • 2.数据分布均匀,不代表流量和负载的均匀,热点key导致节点实际表现不均匀

5.参考资料

https://github.com/ccfos/nightingale
https://time.geekbang.org/column/article/67388
https://www.wikiwand.com/zh-cn/%E4%B8%80%E8%87%B4%E5%93%88%E5%B8%8C
https://juejin.cn/post/7134656152452726792
https://www.geeksforgeeks.org/consistent-hashing-in-distributed-systems/
https://www.zsythink.net/archives/1182
https://blog.csdn.net/randompeople/article/details/103723839

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

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

相关文章

墨尔本python培训班_墨尔本大学商业专业

澳大利亚墨尔本大学作为国际知名的高等教育学府&#xff0c;一直以来在各个专业领域都有着十分出色的表现。墨尔本大学商业专业在最近几年逐渐受到广泛的关注&#xff0c;每年申请留学的人数不断增加。墨尔本大学商业专业是一门综合性的专业课程&#xff0c;该专业毕业生的就业…

墨尔本学计算机硕士专业,2020年墨尔本大学计算机硕士详细介绍

墨尔本大学计算机硕士课程中被ACS(澳大利亚计算机协会)认证的课程&#xff1a; (1)Master of Information Systems (12 subject program) (CRICOS duration: 78 weeks): 学制为1.5年&#xff0c;2月和7月开学;此课程对申请人的本科专业背景无限制性要求&#xff0c;但是要求有一…

墨尔本计算机专业本科几年,墨尔本大学本科计算机科学与软件如何

原标题&#xff1a;墨尔本大学本科计算机科学与软件如何 墨尔本大学本科计算机科学与软件如何 墨尔本大学的计算机科学软件属于研究性项目,将为学生提供承接研究项目的机会,同时也会学习一些职业技巧相关的授果型科目。这个项目将为继续PhD深造提供一条捷径。职业发展:应用程序…

墨尔本大学 计算机科学,计算机科学墨尔本大学

计算机正在改变世界和我们的生活&#xff0c;计算机技术也在不断发展。墨尔本大学计算机科学硕士项目将教授学生一系列专业的知识&#xff0c;以应对计算机技术的不断革新。墨尔本大学计算机科学硕士项目为学生在软件设计&#xff0c;网络安全&#xff0c;信息架构以及编程方面…

关于有朋友遇到的使用 ChatGPT 获得 SAP 相关问题答案不够准确的困扰和我的解答

笔者的 SAP 开发技术交流群里&#xff0c;有朋友提问&#xff1a; 求教一下&#xff0c;哪位大侠知道查看主配方(事务代码C203)的界面里面&#xff0c;那个工序的资源字段是怎么取出来的&#xff08;从哪个数据表来的&#xff09;&#xff1f;多谢 这个朋友反馈&#xff0c;在他…

高考选专业

各省高考成绩已出&#xff0c;又到一年高考季。张雪峰提到&#xff1a;“普通家庭不要光谈理想&#xff0c;也要谈落地。”志愿怎样填报、选专业还是选学校、什么专业好就业、高考志愿主要看什么&#xff1f;针对这些疑问&#xff0c;你对正在选志愿的毕业生们有什么建议吗&…

专家意见何处寻:AI扮演领域专家角色为你答疑解惑

当我们寻求意见或建议时&#xff0c;ChatGPT是一个非常有用的工具。 作为通用的语言模型&#xff0c;ChatGPT 可以提供关于各种话题的建议和意见&#xff0c;如日常生活、工作、学习、人际关系、心理健康、科技和互联网、旅行和休闲、财务和投资、健康和医疗&#xff0c;以及环…

亚马逊跨境电商美国站店铺选品数据分析表,亚马逊美国站店铺产品上架教程

这几年随着跨境电商的逐步火热&#xff0c;越来越多人加入了这个大行业&#xff0c;而亚马逊作为跨境电商最大的渠道自然也是遭到最多的重视&#xff0c;亚马逊美国站点是亚马逊所有站点中市场份额最大的一个站点&#xff0c;今天咱们就来评论下亚马逊美国站什么产品最热销。 ​…

面向 Web 开发人员的 50 个 ChatGPT 提示

使用 ChatGPT 释放您的 Web 开发潜力&#xff01;在本文中&#xff0c;我们提出了 50 个引人入胜的提示&#xff0c;它们将激励和挑战各个级别的 Web 开发人员。无论您是经验丰富的编码员还是刚刚开始编码之旅&#xff0c;这些发人深省的问题都会激发您的创造力&#xff0c;加深…

AI | 浅谈AI技术以及其今后发展

文章概要 近期AI成为热点话题&#xff0c; GPT&#xff0c; new bing&#xff0c; bard&#xff0c;AI 绘画等 AI 编程工具引发大量讨论。请结合自身学习与工作经历&#xff0c;一起来聊聊你对AI技术以及其今后发展的看法吧。 &#x1f31f;&#x1f31f;&#x1f31f;个人简介…

ChatGPT代码解释器提示词

【金山文档】 GPT-4代码解释器关键词 https://kdocs.cn/l/ccnmshBHAE3H

Unity之ASE实现影魔灵魂收集特效

前言 我们今天来实现一下Dota中的影魔死亡后,灵魂收集的特效。效果如下: 实现原理 1.先添加一张FlowMap图,这张图的UV是根据默认UV图,用PS按照我们希望的扭曲方向修改的如下图所示: 2.通过FlowMap图,我们和原UV图:Texture Coordinates 进行插值。这样我么就得到了一…

《炉石传说》架构设计赏析(2):Scene管理

欢迎来的我的酒馆&#xff0c;快来火炉旁暖暖你的靴子。哈哈&#xff0c;我们继续欣赏炉石的代码。欢迎转载&#xff0c;请注明作者【燕良游戏开发】及原文地址&#xff1a;http://blog.csdn.net/neil3d/article/details/39231541 上篇文章我们分析到SceneMgr处理了Scene的加载…

RPG游戏《黑暗之光》流程介绍与代码分析之(六):背包系统的实现(下)

接着&#xff08;上&#xff09;部分的内容&#xff0c;本节关注物品栏中一些功能的实现&#xff0c;及 拾取操作的模拟背包的显示与隐藏物品提示信息 5.4 拾取模拟 有了&#xff08;上&#xff09;部分的铺垫&#xff0c;本节的目标是实现物品拾取功能。 物品拾取功能的逻辑分…

Unity3d开发MOBA游戏类《王者荣耀》记录(一)

由于最近工作忙&#xff0c;之前一直想写的王者荣耀教程直接就忘记了&#xff0c;最新才记起来&#xff0c;现在继续更新~。 上一篇起始大概介绍了一下我对这个工程的简单思路现在开始一步步实现&#xff0c;首先先创建一个Unity3d工程&#xff0c;这里我先用5.4.0吧&#xff…

《炉石传说》架构设计赏析(3):Gameplay初探

经过前面两篇文章的分析&#xff0c;我们对炉石的代码已经不陌生了&#xff0c;接下来我初步尝试分析其游戏逻辑代码。欢迎转载&#xff0c;请注明作者【燕良游戏开发】及原文地址&#xff1a;http://blog.csdn.net/neil3d/article/details/39453291 经过前面的分析&#xff0…

RPG游戏《黑暗之光》流程介绍与代码分析之(四):任务系统的实现

第四章&#xff1a;任务系统 这部分主要对任务系统进行设计&#xff0c;游戏的关键因素之一就是任务系统与玩家的交互&#xff0c;但在代码实现中并不算复杂。本篇博客主要通过一下几个方面实现任务系统。 任务模型的导入与任务UI界面的创建任务的接受与完成针对不同对象的指针…

RPG游戏《黑暗之光》流程介绍与代码分析之(二):角色创建界面的实现

第二章 角色创建 上一章中完成了初始化的场景界面的创建&#xff0c;本章就接着上一篇博客的内容&#xff0c;介绍角色创建的方法。 2.1 角色创建的UI界面 角色创建的背景采用与加载界面所用背景相同&#xff0c;并且Camera不需要移动。 创建的UI界面与之前类似&#xff0c;其中…

【游戏开发渲染】Unity ShaderGraph使用教程与各种特效案例:Unity2022(持续更新)

文章目录 一、ShaderGraph前言二、ShaderGraph科普1、渲染管线&#xff08;Render Pipline&#xff09;2、可编程渲染管线&#xff0c;SRP&#xff08;Scriptable Render Pipline&#xff09;3、高清渲染管线&#xff0c;HDRP&#xff08;High Definition Render Pipleline&…

RPG游戏《黑暗之光》流程介绍与代码分析之(十五):主角受攻击效果以及场景切换

十五章&#xff1a;主角受攻击效果以及场景切换 本篇博客将《黑暗之光》开发的最后工作做完&#xff0c;包括之前未实现的主角被击效果&#xff0c;以及实际运行中的场景切换。 15.1 主角的受攻击效果 我们参照WolfBaby中的受攻击效果&#xff08; 链接&#xff09;&#xff0c…