原文地址: https://github.com/collie/sheepdog/wiki/Sheepdog-Design
Sheeepdog采用完全对称的结构,没有类似元数据服务的中心节点. 这种设计有以下的特点.
1) 性能于容量的线性的可扩展性.
当需要提升性能或容量时,只需向集群中增加新的机器便能使Sheeepdog线性成长.
2) 没有单点故障
即使某台机器发生故障,依然可以通过其他机器访问数据.
3) 容易管理
不需要配置机器角色,当管理员在新增的机器开启Sheepdog守护进程时, Sheepdog会自动检测新加入的机器并配置它成为存储系统中的一员.
Sheepdog是一个分布式存储系统.为Sheepdog客户端(QEMU的块驱动程序)提供对象存储(类似于简单的键值对). 接下来几章将更加详细的阐述Sheepdog各个部分.
1) 对象存储(Object对象存储(Object Storage)
2) )
Sheepdog不同于一般的文件系统, Sheepdog进程为QEMU(Sheepdog进程名)创建一个分布式对象存储系统,它可以存储”对象”.这里的”对象”数据大小可变,并有唯一的标识,通过标识可以进行读/写/创建/删除操作.对象存储组成”网关”和”对象管理器”.
3) 网关(getway)
Getway接收QEMU块驱动的I/O请求(对象id,偏移,长度和操作类型),通过一直散列算法获得目标节点,然后转发I/O请求至该节点.
4) 对象管理器(Object manager)
对象管理器接收getway转发过来的I/O请求,然后对磁盘执行读/写操作.
5) 集群管理器(Cluster manager)
集群管理器管理管理节点成员(探测失败/新增节点并报告节点成员的变化),以及一些需要节点一致的操作(vdi 创建, 快照 vdi等).当前集群管理器使用corosync集群引擎.
6) QEMU 块驱动
QEMU块驱动把VM image分为固定大小(默认4M),并通过其getway存储到对象存储中
每个对象使用一个64bit的整数作为全局标识,并在多台机器存有备份,QEMU块驱动并不关心存储的位置,对象存储系统负责管理存储的位置.
Sheepdog的对象分为以下四种:
1) 数据类型(data object)
它包括虚拟磁盘映射的真实数据,虚拟磁盘映射分为固定大小的数据对象, Sheepdog客户端访问这个对象.
2) vdi object
它包括虚拟磁盘映射的元数据(例:映射名,磁盘大小,创建时间,vdi的数据对象ID等).
3) vmstate object
它存储运行中的VM状态映射.管理员通过它获取实时快照信息.
4) vdi attr object
使用它存储各个vdi的属性,属性为键值对类型,类似于普通文件的扩展信息.
1) 0 - 31 (32 bits): 对象类型详细信息
2) 32 - 55 (24 bits): vdi id
3) 56 - 59 ( 4 bits): 预留
4) 60 - 63 ( 4 bits): 对象类型标识符
每个VDI有一个全局唯一的ID(vdi id), 通过VDI名求得的散列值,低三十二位使用如下:
对象类型 |
低32位的作用 |
数据类型 |
虚拟磁盘映射的索引号 |
Vdi对象 |
未使用(填0) |
Vm状态对象 |
Vm状态映射索引 |
Vdi属性对象 |
键名的散列值 |
1) 数据对象
虚拟磁盘映射的块
2) Vdi对象
3) Vm状态对象
Vm状态映射块
4) Vdi属性对象
前SD_MAX_VDI_ATTR_KEY_LEN位(256位)为属性的键名,余下的是属性指.
从如何访问对象的角度,我们还可以把Sheepdog对象分为以下两类.
1) 只读对象(例:VDI快照数据对象)
只允许一个VM对其读写,其他vm无法访问
2) 可写对象
不允许任何VM对其写,所有VM都可读
Sheepdog对象存储可接收正在写时复制(copy-on-write)的请求.当一个客户端发送一个创建和写的请求时,同时可以指定基本对象(CoW操作的来源),这用于快照和克隆操作.
Sheepdog使用一致性哈希算法决定存放对象的位置,一致性哈希算法提供哈希表,而且增加或介绍节点不回显著的改变对象映射,通过哈希表能使I/O负载均衡.
Sheepdog的数据副本很简单,我们假设只有一个写,所以写冲突不会发生,客户端可以并行发生请求到目标节点,发生读请求到一个目标节点如果客户端自己处理I/O请求顺序.
Getway使用一致性哈希算法计算目标节点并发送写请求到所有目标节点,只有所有副本均更新成功写请求才会成功,这是因为如果一个副本未更新,getway有可能从未更新的节点读取旧数据.
Getway使用一致性哈希算法计算目标节点,并发送读请求到一个目标节点.
1) 修复对象一致性
当某节点在转发I/O请求时crash,有可能破坏副本的一致性,所以当getway第一次读取对象时会试图修复其一致性,从一节点读取整个对象并用它覆盖所有副本.
Sheepdog存储所有成员节点的历史信息,我们把历史版本号叫做”epoch”(详见章节’对象恢复’). 如果getway转发I/O请求至目标节点并且getway与目标节点epoch号不相符,I/O请求失败且getway重试请求直到epcho号相符,这就需要保持副本强一致性.
I/O重试也可能发生在目标节点挂了导致无法完成I/O操作.
对象管理器把对象存储到本地磁盘,当前把每个对象存储为一个文件,这中方法简单.我们也可以使用DBMS(例: BerkeleyDB, Tokyo Cabinet等) 作为对象存储器,但还不支持.
对象存储成如下路径:
/store_dir/obj/[epoch number]/[object ID]
所有对象文件有一个扩展属性: 副本数(sheepdog.copies),
当sheep进程在写操作过程中失败,对象有可能至少部分更新,一般情况这不会有问题,因为如果VM未接收成功消息,不保证所写部分的内容.然而对于vdi对象,我们必须整体更新或整体未更新,因为如果vdi对象只是部分更新,VDI的元数据有可能被破坏. 为例防止这个问题,我们使用日志记录对vdi对象的写操作. 日志过程很简单:
1) 创建日志文件"/store_dir/journal/[epoch]/[vdi object id]"
2) 首先写数据到日志文件
3) 写一个数据到vdi对象
4) 删除日志文件
大多情况, Sheepdo客户端单独访问它们的映射因为我们不允许两个客户端同时访问一个映射,但是某些VDI操作(例:克隆VDI,创建VDI)必须做,因为这些操作更新全局信息,我们使用Corosync集群引擎完成而不是中心服务器.
我们将扩展Sheepdog以支持其他集群管理系统.
本章正在编辑
Sheepdog卷被分为4M的数据对象,刚创建的对象未分配,也就是说,只有写对象被分配.
首先QEMU块驱动通过getway的bdrv_open()从对象存储读取vdi
块驱动通过请求的部分偏移量和大小计算数据对象id, 并向getway发送请求. 当块驱动发送写请求到那些不属于其当前vdi的数据对象是,块驱动发送CoW请求分配一个新的数据对象.
我们可以把快照VDI附加到QEMU, 当块驱动第一次发送写请求到快照VDI, 块驱动创建一个新的可写VDI作为子快照,并发送请求到新的VDI.
当查找VDI对象时:
1) 通过求vdi名的哈希值得到vdi id
2) 通过vdi id计算di对象
3) 发送读请求到vdi对象
4) 如果此vdi不是请求的那个,增加vdi id并重试发送读请求
快照可克隆操作很简单,
1) 读目标VDI
2) 创建一个与目标一样的新VDI
3) 把新vdi的‘'parent_vdi_id''设为目标VDI的id
4) 设置目标vdi的''child_vdi_id''为新vdi的id.
5) 设置目标vdi的''snap_ctime''为当前时间, 新vdi变为当前vdi对象
TODO:当前,回收未使用的数据对象是不会被执行,直到所有相关VDI对象(相关的快照VDI和克隆VDI)被删除.
所有相关VDI被删除后, Sheepdog删除所有此VDI的数据对象,设置此VDI对象名为空字符串.
Sheepdog把成员节点历史存储在存储路径, 路径名如下:
/store_dir/epoch/[epoch number]
每个文件包括节点在epoch的列表信息(IP地址,端口,虚拟节点个数).
1) 从所有节点接收存储对象ID
2) 计算选择那个对象
3) 创建对象ID list文件"/store_dir/obj/[the current epoch]/list"
4) 发送一个读请求以获取id存在于list文件的对象. 这个请求被发送到包含前一次epoch的对象的节点.( The requests are sent to the node which had the object at the previous epoch.)
5) 把对象存到当前epoch路径.
如果QEMU发送I/O请求到某些未恢复的对象, Sheepdog阻塞此请求并优先恢复对象.
Sheepdog的所有请求包含固定大小的头部(48位)和固定大小的数据部分,头部包括协议版本,操作码,epoch号,数据长度等.
操作码 |
描述 |
SD_OP_CREATE_AND_WRITE_OBJ |
发送请求以创建新对象并写入数据,如果对象存在,操作失败 |
SD_OP_READ_OBJ |
读取对象中的数据 |
SD_OP_WRITE_OBJ |
向对象写入数据,如果对象不存在,失败 |
SD_OP_NEW_VDI |
发送vdi名到对象存储并创建新vdi对象, 返回应答vdi的唯一的vdi id |
SD_OP_LOCK_VDI |
与SD_OP_GET_VDI_INFO相同 |
SD_OP_RELEASE_VDI |
未使用 |
SD_OP_GET_VDI_INFO |
获取vdi信息(例:vdi id) |
SD_OP_READ_VDIS |
获取已经使用的vdi id |
操作码 |
描述 |
SD_OP_DEL_VDI |
删除VDI |
SD_OP_GET_NODE_LIST |
获取sheepdog的节点列表 |
SD_OP_GET_VM_LIST |
未使用 |
SD_OP_MAKE_FS |
创建sheepdog集群 |
SD_OP_SHUTDOWN |
停止sheepdog集群 |
SD_OP_STAT_SHEEP |
获取本地磁盘使用量 |
SD_OP_STAT_CLUSTER |
获取sheepdog集群信息 |
SD_OP_KILL_NODE |
退出sheep守护进程 |
SD_OP_GET_VDI_ATTR |
获取vdi属性对象id |
操作码 |
描述 |
SD_OP_REMOVE_OBJ |
删除对象 |
SD_OP_GET_OBJ_LIST |
获取对象id列表,并存储到目标节点 |