听小董谝存储 四

网友投稿 660 2022-11-26

听小董谝存储 四

听小董谝存储 四

我爱glt

目录

​​序章​​

​​第一章 与master交互获取路由​​

​​第二章 转发请求​​

​​第三章 确定读写顺序​​

​​3.1 正常情况下​​

​​3.2 搬迁合并分裂情况下​​

​​3.2.1 三种情况的解释​​

​​3.2.1 三种情况的具体方案​​

​​后续阅读资料​​

序章

前面几章介绍了存储系统整体的架构和master层的一些功能设计。这一节主要聊聊portal这一层的设计。

如下图一,portal是直接对client提供服务的,它的主要功能就是将用户的请求导入特定的particle上。

这一个大功能其实也可以进行拆解,具体为如下三部分:

1 与master交互,获取准确的路由

2 根据key找到对应的particle上的data shard

3在多副本的情况下确定读写顺序

图一 存储系统整体架构

第一章 与master交互获取路由

小菜:老师,前面各种数据结构看得我头疼,你能不能在不提具体实现的情况下,把问题讲清楚。毕竟,我只是想了解存储系统大概是怎么设计的,而不是要真正地去设计一个系统。

老鸟:我想想哈。Master与protal的交互流程参见《听小董谝存储三》4.5节。Master发给portal的就是一个list,每个元素都是一个路由,数据结构就是你之前提到的【slotStart, slotEnd, particleIp1, particlePort1, particleIp2, particlePort2, particleIp3, particlePort3, volumeId, shardId】。然后以跳表的形式存储。(​​转发请求

先把请求的key进行hash,然后对100w取余,获取存放的槽位。在跳表里面找到符合槽位的路由(第一个大于上面计算的槽位号的路由的前一个元素)。取出那个路由对应的机器信息,然后发请求就完了。

小菜:那这个会不会和前面获取路由的时候发生读写冲突?

老鸟:会。

小菜:那咋办?

老鸟:你说呢?

小菜:加锁?

老鸟:加锁。

第三章 确定读写顺序

老鸟:小菜,现在每个数据都存储了3份,你觉得应该怎么读写呢?

小菜:那就给每个data shard都分配一个编号,例如1,2,3。写(包括删除)的时候就先写1号副本,如果成功再写2号,如果还成功就写3号副本。在三次写的过程中,任意一次失败都告知客户端写失败;只有三次都成功才告诉客户端写成功。读的时候就读3就OK了(为什么是3?而不是1)。

3.1 正常情况下

老鸟:你的设计没有什么大问题。图二是我根据你的思路画的图,精简一下,你刚才的编号就换成主副的说法,1号就是主;2,3就是副。你觉得下面的图有什么问题么?

图二 data shard的主从逻辑

小菜:副只提供写服务(大部分情况),主既有写也有读。从上面来看,Particle A的压力有点高呀。我想想,不如把主副本分散到各个机器上,这样负载能均衡一些,如下图三。

图三 data shard的主从逻辑

老鸟:不错。

小菜:我还有一个问题,假如张大爷使用咱们的系统。他先写入鸡蛋的价格是5块钱,写成功了。之后他又更新(更新与写入是一个接口)鸡蛋的价格是6块钱,但是写失败了,此后他再去读,那么读的价格到底是多少钱呢?

老鸟:你提了一个很好的问题。就你上面的案例,他有可能读到5块钱,也有可能读到6块钱。因为,如果他之前写的时候,写主副本就失败了(例如网络超时,请求压根就没有到particle),那么他读到的数据就是5块钱。如果他是写从副本的时候失败了(之前写主已经成功了),但是读的时候因为读的是主副本,那么他就读到六块钱。

小菜:那就是说在不区分错误码的情况下,如果写失败了,那么落地的数据到底是什么样的就是个未知状态了?

老鸟:是的,如果写失败,那么底层到底是个什么状态谁也不知道。就上面你说的例子,就算是网络超时,还分两种,一是发送请求的时候超时,二是写成功了,但是particle返回结果给portal的时候超时了。这种情况下,前者存储的数据还是5,后者存储的数据已经是6。

小菜:还有一个问题,如果遇到读写并发怎么办?

老鸟:所有的client都是通过一个sdk包来连接portal的。SDK会把key经过hash,绑定到某个portal上。这样保证了同一个key都是由一个portal来处理的。在同一个portal内部,请求是串行走的。这样也就规避了读写并发问题。

老鸟:另外咱们前面说的都只是正常情况下的读写流程,一旦发生搬迁分裂合并,情况会比较复杂。

3.2 搬迁合并分裂情况下

小菜:在前面几篇文章里,你就已经提到了搬迁分裂合并这3个词,具体是什么意思呢?能解释一下么。

3.2.1 三种情况的解释

老鸟:好的。先说搬迁吧。

1 搬迁

我们知道数据是存放在3份particle上面的。而particle都是廉价的商用机,很有可能出现各种硬件故障,就算不是硬件故障,单纯断电断网,也会导致不可访问。那此时就只有两份副本可用了,2份副本肯定没有3份副本安全。所以就很有必要把数据从原来的2份副本里搬迁到新的3份副本里。如果做个类比就是张大爷卖鸡蛋,他就有一个账本,原本放在

15号厂房的3号货架的15号货篮里,

为了保证数据安全,咱们还把账本复制了两份分别放在

16号厂房的3号货架的15号货篮里,

17号厂房的3号货架的15号货篮里。

某天15号厂房整体都失火了,那咱们就得从16号厂房(或者17号厂房)3号货架的15号货篮里把账本再复制三份,分别存放到安全的

21号厂房的4号货架的8号货篮,

22号厂房的4号货架的8号货篮,

23号厂房的4号货架的8号货篮里。

这个过程就叫搬迁。

2 分裂

依然用张大爷记账来说。张大爷的业务做得很广,每天都有业务往来。现在是2个账本:

一个放在25号厂房的4号货架的9号货篮,

为了叙述方便,暂时不考虑三副本的问题)。

同时咱们制定了保存规则,每个月前半月的流水记录到9号货篮里,后半个月的流水记录到10号货篮里。

后来张大爷的业务狂飙式发展,两个账本压根就不够用,我们就制定了新的规则:

每个月的第一周的流水存放到22号厂房的4号货架的11号货篮

每个月的第二周的流水存放到22号厂房的4号货架的12号货篮

每个月的第三周的流水存放到22号厂房的4号货架的13号货篮

每个月的第四周的流水存放到22号厂房的4号货架的14号货篮

这个过程就叫分裂。

3 合并

首先一个大前提:咱们每个货架上的货篮数量是有限的。

张大爷后面遭遇禽流感,生意不行了,生意流水大大减少,依然占据了4个货篮,这自然是不合适的。所以我们又把4个货篮减少到3个,记账规则就是:

每个月的第一周放到22号厂房的4号货架的15号货篮

每个月的第二周放到22号厂房的4号货架的16号货篮

每个月的第三第四周放到22号厂房的4号货架的17号货篮

这就是合并

数据发生搬迁分裂合并的概率很高,但是我们得有一个前提,不能因为我们要对数据进行上述操作就要求客户停止读写!所以这里我们要讨论的就是,如何在用户无感知地进行读写的情况下对数据搬迁分裂合并。另外就如上面举的例子,我们进行操作的最小单元就是一个货篮,也就是我们存储系统里面的一个data shard。OK,小菜,说说你的思路吧。

3.2.1 三种情况的具体方案

1 搬迁

小菜:一个一个来,先说搬迁。从阶段来说,应该有搬迁中,搬迁完成后两个状态。当进入搬迁过程中,portal会设置一个标志位,此时新来的数据应该是同时写到两组particle(一共6台机器)一个叫新机器,一个叫旧机器。读的时候,只能读旧数据(具体来说就是读旧数据里面的主那一份),因为数据还没有搬迁完,所以有些数据新机器那里还没有。等到搬迁完成,portal的读写操作就都导向新机器。就机器上的数据就等待回收。简略的说就是搬迁中:双写读旧;搬迁完成:读新写新。整体来说这个阶段可以理解为把所有数据分为两部分,历史数据与新增数据。历史数据由mover进行搬迁,新增数据由portal进行双写。不过portal怎么知道开始搬迁了,什么时候搬迁完成呢?谁来执行搬迁呢?具体怎么搬迁呢?

图四 data shard的搬迁

老鸟:什么时候搬迁,什么时候搬迁完成这两个问题都是由dispatcher告知master的,master收到通知后,会修改自己的路由,然后推给所有的portal。这样portal就知道这阶段变化了。这部分在后面讲dispatcher和mover的时候咱们再详细说。

2 分裂

图五 data shard的分裂

小菜:和搬迁对着看,分裂也就不复杂了。如上图五,分裂之前,槽位1-9的数据都写入某一个data shard A;开始分裂后,槽位1-4新收到的数据写入data shard B和原来的data shard A;槽位5-9的数据写入data shard C 和原来的data shard A。而只要分裂没有结束,所有的读都走到原来的data shard A。

3 合并

图六 data shard的合并

小菜:看完分裂,合并我就不说了。大家看看图六就懂了。嗯不过,就以搬迁为例,我们原来的数据在data shard A,搬迁完成后,数据在data shard B。那data shard B到底在哪?

老鸟:这个由master决定。既然你你问到这里,那我就把dispatcher和mover的功能也简单说说吧。一个典型的搬迁流程如下:

某些组件(至于都是哪些组件,请参考听小董谝存储三,4.3怎么知道路由变更了)发现某个particle出现问题了,就上报给master了。master讲这个机器上所有的data shard的状态都改为Dead。dispatcher发现有dead的data shard了就开始制定搬迁计划,并发给movermover在开始搬迁前,先通知master,请求搬迁了。master收到mover的通知后就修改本地的路由,然后告诉mover该把数据搬迁到哪里,并推送路由给所有的portal。portal收到master新的路由消息后,设置一个特殊的标志位,此后收到的请求都会按照前文说的读写策略进行。mover一直进行数据搬迁,等数据搬迁完成后再通知master和dispatcher。master收到搬迁完成的消息后,修改自己的路由,再推送给protal。portal收到新的路由后,删除之前那个标志位,搬迁结束,数据的读写都由新的data shard承接。

小菜:和我想的差不多,但是mover搬迁的时候,怎么做到不覆盖已经写入的数据呢,还有他是怎么知道历史数据搬迁完了呢?

老鸟:别着急,后面讲mover的时候再说。我乏了。下课

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Git 版本回退的一点思路
下一篇:2017腾讯校招面试回忆(成功拿到offer)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~