点击上方蓝色字体,选择“设为星标”
优质文章,及时送达
之前的文章我们介绍了什么是分布式系统,以及分布式系统的一些特点和存在的问题。
我们知道的分布式系统是多台计算机通过网络链接,协同完成计算任务的系统。通过节点的水平扩展我们可以解决系统计算能力和存储能力的瓶颈问题。
那么如何将一个任务分配到分布式系统的节点中运行,并在执行成功之后ack给客户端呢?就引入了我们今天要讨论的如何访问到分布式系统中的服务的话题。
分布式系统中,我们可以将一个大的任务分割到多个节点进行处理,每个节点负责大任务的一个子集,这个过程任务分配的过程是负载均衡。
对于任务或请求分发我们常见的有如下几种方式:
随机访问
轮训访问
哈希算法
范围查找
还有其他一些方式,但基本都是基于以上形态的变种,比如加权轮训,或是根据节点能力的负载均衡算法,一致性哈希算法是为了解决哈希取模带来的数据迁移成本等。
对于无状态服务我们常采用的方式是哈希算法或是其变种算法。对于有状态服务我们常采用的方式是哈希算法或是范围查找。
哈希算法是最常用的一种方式,对哈希值和约定节点数量做取模操作。
哈希取模算法带来的问题是,一旦集群中节点扩缩容会带来所有数据迁移和重新分布这个过程。
解决这种情况可以建立对应关系,将关系交给独立的服务处理,就是在对应关系之上建立一层逻辑映射。另一种方案是可以考虑引入一致性hash算法,一致性hash算法最开始在p2p网络常用的一种算法。
通过一致性哈希函数对数据进行处理,输出值处于一个闭环的环状范围内,也就是哈希环,节点随机分布在整个环上,每个节点负责处理自己开始顺时针方向的下个节点的全部哈希值域上的数据。
一致性哈希算法带来的好处是每次节点上下线,只会影响一部分数据的迁移,成本就小很多。
如果环上节点过少,在节点上下线过程中,同样可能造成数据大范围的迁移,这时我们可以引入虚拟节点概念,虚拟节点个数一般远大于未来集群中节点的个数,将虚拟节点均匀分布到一致性哈希环上,其与正常节点向太。再对数据进行操作时,可以将数据落到虚拟节点上,而减少节点上下线造成大范围数据迁移的问题。
哈希取模还有一个问题是可能因为某个数值数据较多造成数据倾斜问题。所以我们在做数据划分时需要使得每个区间内数据量尽量一样多,当某一部分数据量增加到一定阈值之后,需要考虑对其进行分裂,划分到不同的数据区间去,我们做redis治理时对于大key的处理往往采用这种方式。
数据范围分布是另一种常用的数据分布算法,将数据按照值划分为不同的独立区间,这样就建立了一套关系可以将不同的数据交给不同的节点集群组进行处理了。
有的时候我们对于数据并不关心,我们可以采用数据量分布方式。比如MQ里面的消息,我们可以简单的顺序追加到文件尾部,当文件长度大小达到一定阈值之后,我们可以考虑将其划分到不同的服务器节点上去。
和按数据范围划分一样,我们还是需要记录每个数据的索引和offset信息的分布情况到元数据关系服务的。
数据量分布方式可以解决前面提到的数据倾斜问题,数据可以均衡的切分到多个节点或集群中去。当集群中节点需要再平衡时,只需迁移数据块即可完成。集群也可以持续的线性扩容而没有限制。但是随着数据量增加,维护好元数据信息也成了新的挑战。
为将数据分散到整个分布式系统中,我们一般不是简单的将一台服务器作为一个数据节点,而是将每个数据划分为更小的范畴。
在各种涉及到数据存储相关的中间件中,我们听到的一些数据分割的最小单元往往有不同的叫法,比如segment,chunk,partition等。
通过前面介绍的几种数据访问负载算法,我们知道如果将数据单元划分的过小,元数据的管理成本将会巨大,所以我们对于大量数据单元的处理一般会引入桶的概念。
也就是我们会控制数据的大小,将一定数量的数据单元放在一个桶内,同时将一个桶作为一个数据单元或是节点交给元数据管理服务进行管理,而每个副本都是桶的纬度。
一旦副本分布和机器无关,数据丢失后的恢复效率就会非常高。因为机器的数据丢失,会涉及到数据副本在整个分布式网络所有机器上的迁移,而不是仅仅几个副本所处的机器。机器上数据迁移的成本是非常低的,恢复效率低,也会造成巨大的网络开销。
在准备进行一个数据处理之前,我们需要对数据进行节点的寻址,一般有两种方式本地计算方式和代理服务计算方式。
将计算尽量调度到和存储节点同一台物理机上的计算节点上进行,我们称为本地化计算。本地化计算是计算调度的一种重要优化,体现了一种重要的分布式调度思想:移动数据不如移动计算。hadoop和spark的巨大不同就是在这里。
当然在工程时间中,可以结合业务需求选择合理或是组合的数据分布解决方案,方案是可以灵活组合使用的。
比如解决数据倾斜问题,可以在哈希分割方式上引入按数据量分割的方式,通过设定阈值来解决数据倾斜问题,将数据分裂之后的数据段分布到整个分布式集群中去。