01 前言
在上文《大数据基础-原来这就是路由分片》中,我们简单介绍了什么是路由和分片、讲述了通用的路由分片模型,并介绍了路由分片的常用方法,包括哈希分片和范围分片。
在哈希分片这类路由分片的解决方案中,有几种被广泛熟知和应用的实现方式:
- hash 取模法
- 虚拟桶
- 一致性hash
从本篇开始我们就详细的原理和实现方法来一一讲述。
02 哈希取模大法—真香!
我们首先详细说下第一种最为常见的方法hash取模法,这个名字可能有些同学比较陌生,我相信轮询(Round Robin)这个名词你肯定是知道的。用最直白的话来说就是“雨露均沾”,尽量平均分配到所有节点。这种路由方法的方法在很多服务中都有使用,比如Nginx、LVS等场景,大数据场景下也有很多,比如kafka 的producer选择partition写数据的时候,实际上也是使用的hash取模法,后面聊到各个服务的时候再说。当然各自服务又针对场景有不同的定制,但原理并不复杂,比较适用于无状态或逻辑相对简单的业务场景。(最基本的遍历循环不在本次讨论范围)
此时我们有100个节点,此时有若干个请求过来,我们希望的是尽量将请求平均的分配到后端的节点上,以达到均衡的目的,可以通过哈希函数即可实现数据分片,核心代码只有3行。话不多说我们来简单实现一下。
如下所示,modRequestID得到了对应的节点编号,以此可以将请求相对平均的路由到不同的节点上。基础轮询实现完成。
03 基础轮询的弊端
上面我们阐述了基础轮询的实现原理,实际上逻辑很简单。这里我们脱离哈希分片的范畴再向外扩展一下,假设我们将基础轮询应用在实际服务中,我们就会发现一个问题,当一个服务长期存在且健壮发展时,必然会扩容节点,而机器配置更新换代是很常见的事情,如果我们使用上述方式轮询所有节点则会带来后端节点的压力不均衡,当请求落在较为繁忙的机器上时,会影响处理请求的效率。如何解决呢?
- 多扩容节点,将请求分散到更多节点上,控制节点的实际压力,小于阈值的压力位,这样就可以一定程度上缓解这个问题。当然由此带来的问题就是资源的浪费,随之而来的也就是成本的压力。
- 除了多扩容之外,还有什么办法呢?我们来分析一下矛盾点,由于机器异构导致处理性能有差异,最终导致请求分配在高性能机器上,请求处理速度非常快,而低性能机器上则处理的相对较慢。如果此时我们秉持着“能者多劳”的想法,高性能机器多处理一些,那么通过一些干预方式有针对性的将请求分配,是不是就可以解决这个问题呢?由此我们引入加权轮询的概念。
04 加权轮询—加菜!
同样的,闲话少许,我们直接来实现一把。
运行结果如下所示,是完全符合我们设置的加权规则的。
至此我们通过加权轮询的方式,实现了将请求根据不同权重有针对性的进行分配,解决了集群节点异构带来的问题。
05 基础轮询和加权轮询的制约
基础轮询,其优点在于逻辑比较简单,也比较好上手,但是面临着两难的境地,灵活性比较差。如上述所叙,基础轮询通过将requestID 的hash值对节点数量取模后,进行路由节点选择 。
如果此时增加扩容了一台机器,那么会出现什么问题呢?那就意味着一轮大洗牌,扩容一台机器将全部的映射关系打乱,请求只能按照新的映射关系重新分配一遍,如下所示
那究竟为什么Round Robin 的灵活性那么差呢?我们不妨回到上一篇《大数据基础-原来这就是路由分片》中,
------------------划重点啦!------------------
Round Robin实际上是将物理节点和数据分片的功能合二为一了,也就意味着每个物理节点和数据分片是1:1的关系,因此在通用模型中Key-Partition 和Parition-Machine映射由同一个hash函数来负责了,这也就导致物理节点和分片强耦合,物理节点变动代表着分片变动。这就是hash取模灵活性缺失的最大原因。
加权轮询,准确的说,并不属于哈希分片,但也存在类似的问题,新加入节点后映射关系全部打乱。
写到最后,本来写到这里有关轮询篇就已经写完了,但是在写的时候发现一个有趣的事情,如果结合第一篇《大数据基础-原来这就是路由分片》来对加权轮询进行一定的抽象是什么样子呢?可以把你的想法回复到留言中,请继续关注后面的文章,相信会让你发现架构之美。
原创不易,觉得有点用的话,就请你为本文点个赞吧。
你的支持是我写作的动力。