《Windows Azure Storage》阅读笔记

631 阅读6分钟

更多精采文章,欢迎关注作者的微信公众号:码工笔记

前段时间阅读了一下微软在 2011 年发表的论文《Windows Azure Storage》,现总结如下:

文章介绍了Windows Azure高可用、高可靠、强一致性分布式云存储系统的总体设计机制。

用户请求存储对象使用如下形式的URL:

http(s)://AccountName.<service>.core.windows.net/PartitionName/ObjectName

  • AccountName:用户名,唯一确定存储集群和数据中心
  • service:主要有三种取值(blob,table 或 queue)分别对应三种不同类型的数据
  • PartitionName:分片名,用于水平扩展,可根据不同的访问流量迁移到不同的存储结点上
  • ObjectName:对象名,一个地象隶属于一个分片,可对同一个分片内的多个对象进行原子操作

image.png

注意到 URL 中的 host 部分含有账户信息(AccountName)。WAS中 Location Service 负责账户管理,它会将账户(AccountName)分配到特定的 Storage Stamp上,并更新 DNS。每个账户分配到一个 Storage Stamp上,也可以配置别的 Storage Stamp 来做异步容灾备份。

Location Service本身也被部署在两个地理上隔离的机房以实现容灾。

用户请求的URL经 DNS 转换后得到分配给它的 Storage Stamp 的虚拟IP地址(VIP),然后请求会被发送给对应的 Storage Stamp 来处理。

Storage Stamp 对应一个机房,一般有10~20组以上的机柜,每个机柜上有18个存储节点,软件上其组织成一个分层结构,主要包括:

  • Frontend Layer 这一层是一系列无状态的中转代理服务,主要用来将用户请求转发到下层服务。 一般会部署多个节点做负载均衡,节点也会缓存Partition map和热数据来缩短响应时间。

  • Partition Layer 这一层处理用户数据对象的存储,WAS支持三种类型的数据对象:Blob,Table和Queue。

每种数据对象有自己的partition name和object name(可选)

  • Blob对象的partition name就是Blob对象名
  • 对Table来说,表中每一行都有个主键,主键有两个属性:Partion name和Object name。这样可以让表中多行相关的数据放在一个partion上,这样可以支持对这些数据进行事务处理。
  • 对Queue来说,partition name是Queue名,队列中的每条消息有自己的Object name

不同的Partition name对象会被分配到不同的个Partition Server(PS)上进行存储。

Partition name与PS的分配关系叫做Partition Map Table,由Partition Manager(PM)来维护,支持根据Partition的访问负载情况将各分片动态分割、合并以及在Partition Server间的迁移。分片的跨机房异步备份也由Partition Manager负责。Partition Manager是一个高可用的分布式服务,通过一个类似Google chubby的锁服务来选出leader和维护租约。

image.png

Partition数据的具体存储由partition server负责。每个对象在存储形式上主要分为几部分:

  • WAL: 外部数据写入时先写到wal,再存到memtable中
  • Memtable:内存数据,保持按key有序,一般使用b+树
  • Row stream:memtable 隔一段时间序列化到硬盘上,以stream形式存储
  • Blob stream:blob数据从wal中直接转到blob stream中
  • bloom filter:用来加快不存在数据的查询速度

image.png

其中 WAL、Row stream、Blob stream都是以Stream形式存储在硬盘上的,Stream的存储由下一层的Stream Layer实现。

  • Stream Layer 这一层负责Stream对象的分布式存储。从上层来看,一个Stream对象表示一个很大的文件(有自己的文件名),Stream layer提供了一套类似文件系统的命名空间和API,不过只支持追加写。上层可以调用它提供的open/close/delete/rename/read/append/concatenate接口来操作这些Stream对象。

Stream只支持追加写,已有数据不能被修改,而且追加操作是原子的,所追加的Block要么全部成功,要么全部失败。

image.png

Stream由一系列连续的数据块(称为Extent)组成,每个Extent又由多个小数据块Block组成。

其中一个Extent对应到硬盘上的一个实体文件,一般1G左右,是分布式备份的最小单元,对Extent的写操作只能append,支持。Extent是备份操作的最小单元。

Block是client侧按顺序append到Extent尾部的数据块,大小一般不大于4M,校验和及一致性检验以Block的粒度来完成。

软件服务层面主要有两中角色:Stream manager(SM)和Extent node(EN)。

image.png

Stream manager负责维护其所管辖的各Stream中包含哪些Extent的信息,并将各Extent分配给多个Extent node(同时维护具体分配信息)进行存储,Stream manager不维护Block这一粒度的信息。

Extent node负责Extent文件的存储,每个Extent都会被存储到三个不同的Extent node上。其中,直接接受用户写的Extent node叫做primary EN,另外两个叫做secondary EN。EN只知道Extent和Block,它不维护Stream这一粒度的信息。

当client要往Stream layer写数据时,他先要联系Stream manager给他在对应的Stream中分配一个Extent,SM会指定3个EN(并指明其中那个是primary),将这些信息返回给client。client后续就可以直接往primary EN写数据了,在整个Extent写完(到达指定的阈值)之前,都不需要再联系SM(Hot path上不包含SM)。

Primary EN在接收到client的写数据请求后,在存盘的同时,还会将写请求以自己决定的顺序(与自己写盘顺序一致)同步发给另外两个secondary EN。只有3个备份都写成功以后才会给client返回写成功。如果secondary EN因为各种原因(如连接失败或硬盘满等)未写成功,primary EN会给client返回写失败。

Client接收到写失败后或是Extent内容超过指定阈值时,需要联系SM,执行seal extent的操作。这时SM会先向该extent所对应的3个EN发送commit length query,三者各自向SM报告自己的extent最后写入的offset,SM取3者的最小值然后将这个值带在seal请求里发给3个EN,EN接收到seal请求后就会停止对此extent的后续写操作,并记录extent最后seal的offset,此后extent就变为只读文件了,它的有效长度就是seal的长度。

SM会定时轮询所有EN的状态及其存储数据的情况,如果发现某些数据备份数<3,则会分配新的EN来增加备份数。如果发现某些Extent已经没有任何Stream引用,则会将其进行GC并通知EN回收相应的硬盘空间。

Stream layer的数据一致性由以下两点保证:

  • Client的写数据请求返回成功后,WAS能保证从任何一个备份读出来的内容都完全一致
  • 一个Extent在seal之后,各备份都包含完全相同的数据。