OpenStack使用Ceph存储,Ceph到底作了什么?

blob.png blob.png

 上面左边是个人我的微信,如需进一步沟通,请加微信。  右边是个人公众号“Openstack私有云”,若有兴趣,请关注。git


原文连接

1 背景知识

1.1 Ceph简介

Ceph是当前很是流行的开源分布式存储系统,具备高扩展性、高性能、高可靠性等优势,同时提供块存储服务(rbd)、对象存储服务(rgw)以及文件系统存储服务(cephfs)。目前也是OpenStack的主流后端存储,和OpenStack亲如兄弟,为OpenStack提供统一共享存储服务。使用Ceph做为OpenStack后端存储,具备以下优势:swift

  • 全部的计算节点共享存储,迁移时不须要拷贝根磁盘,即便计算节点挂了,也能当即在另外一个计算节点启动虚拟机(evacuate)。后端

  • 利用COW(Copy On Write)特性,建立虚拟机时,只须要基于镜像clone便可,不须要下载整个镜像,而clone操做基本是0开销,从而实现了秒级建立虚拟机。微信

  • Ceph RBD支持thin provisioning,即按需分配空间,有点相似Linux文件系统的sparse稀疏文件。建立一个20GB的虚拟硬盘时,最开始并不占用物理存储空间,只有当写入数据时,才按需分配存储空间。app

Ceph的更多知识能够参考官方文档,这里咱们只关注RBD,RBD管理的核心对象为块设备(block device),一般咱们称为volume,不过Ceph中习惯称之为image(注意和OpenStack image的区别)。Ceph中还有一个pool的概念,相似于namespace,不一样的pool能够定义不一样的副本数、pg数、放置策略等。每一个image都必须指定pool。image的命名规范为pool_name/image_name@snapshot,好比openstack/test-volume@test-snap,表示在openstackpool中test-volumeimage的快照test-snap。所以如下两个命令效果是等同的:分布式

rbd snap create --pool openstack --image test-image --snap test-snap
rbd snap create openstack/test-image@test-snap

openstack pool上建立一个1G的image命令为:ide

rbd -p openstack create --size 1024 int32bit-test-1

image支持快照(snapshot)的功能,建立一个快照即保存当前image的状态,至关于git commit操做,用户能够随时把image回滚到任意快照点上(git reset)。建立快照命令以下:oop

rbd -p openstack snap create int32bit-test-1@snap-1

查看rbd列表:源码分析

$ rbd -p openstack ls -l | grep int32bit-test
int32bit-test-1        1024M 2
int32bit-test-1@snap-1 1024M 2

基于快照能够建立一个新的image,称为clone,clone不会当即复制原来的image,而是使用COW策略,即写时拷贝,只有当须要写入一个对象时,才从parent中拷贝那个对象到本地,所以clone操做基本秒级完成,而且须要注意的是基于同一个快照建立的全部image共享快照以前的image数据,所以在clone以前咱们必须保护(protect)快照,被保护的快照不容许删除。clone操做相似于git branch操做,clone一个image命令以下:性能

rbd -p openstack snap protect int32bit-test-1@snap-1
rbd -p openstack clone int32bit-test-1@snap-1 int32bit-test-2

咱们能够查看一个image的子image(children)有哪些,也能查看一个image是基于哪一个image clone的(parent):

$ rbd -p openstack children int32bit-test-1@snap-1
openstack/int32bit-test-2
$ rbd -p openstack info int32bit-test-2 | grep parent
parent: openstack/int32bit-test-1@snap-1

以上咱们能够发现int32bit-test-2int32bit-test-1的children,而int32bit-test-1int32bit-test-2的parent。

不断地建立快照并clone image,就会造成一条很长的image链,链很长时,不只会影响读写性能,还会致使管理很是麻烦。可幸的是Ceph支持合并链上的全部image为一个独立的image,这个操做称为flatten,相似于git merge操做,flatten须要一层一层拷贝全部顶层不存在的数据,所以一般会很是耗时。

$ rbd -p openstack flatten int32bit-test-2
Image flatten: 31% complete...

此时咱们再次查看其parrent-children关系:

rbd -p openstack children int32bit-test-1@snap-1

此时int32bit-test-1没有children了,int32bit-test-2彻底独立了。

固然Ceph也支持彻底拷贝,称为copy

rbd -p openstack cp int32bit-test-1 int32bit-test-3

copy会彻底拷贝一个image,所以会很是耗时,但注意copy不会拷贝原来的快照信息。

Ceph支持将一个RBD image导出(export):

rbd -p openstack export int32bit-test-1 int32bit-1.raw

导出会把整个image导出,Ceph还支持差量导出(export-diff),即指定从某个快照点开始导出:

rbd -p openstack export-diff \
int32bit-test-1 --from-snap snap-1 \
--snap snap-2 int32bit-test-1-diff.raw

以上导出从快照点snap-1到快照点snap-2的数据。

固然与之相反的操做为import以及import-diff。经过export/import支持image的全量备份,而export-diff/import-diff实现了image的差量备份。

Rbd image是动态分配存储空间,经过du命令能够查看image实际占用的物理存储空间:

$ rbd du int32bit-test-1
NAME            PROVISIONED   USED
int32bit-test-1       1024M 12288k

以上image分配的大小为1024M,实际占用的空间为12288KB。

删除image,注意必须先删除其全部快照,而且保证没有依赖的children:

rbd -p openstack snap unprotect int32bit-test-1@snap-1
rbd -p openstack snap rm int32bit-test-1@snap-1
rbd -p openstack rm int32bit-test-1

1.2 OpenStack简介

OpenStack是一个IaaS层的云计算平台开源实现,关于OpenStack的更多介绍欢迎访问个人我的博客,这里只专一于当OpenStack对接Ceph存储系统时,基于源码分析一步步探测Ceph到底作了些什么工做。本文不会详细介绍OpenStack的整个工做流程,而只关心与Ceph相关的实现。

阅读完本文能够理解如下几个问题:

  1. 为何上传的镜像必需要转化为raw格式?

  2. 如何高效上传一个大的镜像文件?

  3. 为何可以实现秒级建立虚拟机?

  4. 为何建立虚拟机快照须要数分钟时间,而建立volume快照可以秒级完成?

  5. 为何当有虚拟机存在时,不能删除镜像?

  6. 为何必定要把备份恢复到一个空卷中,而不能覆盖已经存在的volume?

  7. 从镜像中建立volume,可否删除镜像?

注意本文都是在基于使用Ceph存储的前提下,即Glance、Nova、Cinder都是使用的Ceph,其它状况下结论不必定成立。

(注:原文有源代码,已经超过5000字的篇幅限制,所以作了精简,若是须要看详细推导验证过程,请查看原文连接,另外你能够快速跳到总结部分查看OpenStack各个操做对应的Ceph工做。

2 Glance

2.1 Glance介绍

Glance管理的核心实体是image,它是OpenStack的核心组件之一,为OpenStack提供镜像服务(Image as Service),主要负责OpenStack镜像以及镜像元数据的生命周期管理、检索、下载等功能。Glance支持将镜像保存到多种存储系统中,后端存储系统称为store,访问镜像的地址称为location,location能够是一个http地址,也能够是一个rbd协议地址。只要实现store的driver就能够做为Glance的存储后端,其中driver的主要接口以下:

  • get: 获取镜像的location。

  • get_size: 获取镜像的大小。

  • get_schemes: 获取访问镜像的URL前缀(协议部分),好比rbd、swift+https、http等。

  • add: 上传镜像到后端存储中。

  • delete: 删除镜像。

  • set_acls: 设置后端存储的读写访问权限。

为了便于维护,glance store目前已经做为独立的库从Glance代码中分离出来,由项目glance_store维护。目前社区支持的store列表以下:

  • filesystem: 保存到本地文件系统,默认保存/var/lib/glance/images到目录下。

  • cinder: 保存到Cinder中。

  • rbd:保存到Ceph中。

  • sheepdog:保存到sheepdog中。

  • swift: 保存到Swift对象存储中。

  • vmware datastore: 保存到Vmware datastore中。

  • http: 以上的全部store都会保存镜像数据,惟独http store比较特殊,它不保存镜像的任何数据,所以没有实现add方法,它仅仅保存镜像的URL地址,启动虚拟机时由计算节点从指定的http地址中下载镜像。

。。。。。。。。。。。此处省略分析验证过程。。。。。。。。。。。。。

3 Nova

3.1 Nova介绍

Nova管理的核心实体为server,为OpenStack提供计算服务,它是OpenStack最核心的组件。注意Nova中的server不仅是指虚拟机,它能够是任何计算资源的抽象,除了虚拟机之外,也有多是baremetal裸机、容器等。

不过咱们在这里假定:

  • server为虚拟机。

  • image type为rbd。

  • compute driver为libvirt。

启动虚拟机以前首先须要准备根磁盘(root disk),Nova称为image,和Glance同样,Nova的image也支持存储到本地磁盘、Ceph以及Cinder(boot from volume)中。须要注意的是,image保存到哪里是经过image type决定的,存储到本地磁盘能够是raw、qcow二、ploop等,若是image type为rbd,则image存储到Ceph中。不一样的image type由不一样的image backend负责,其中rbd的backend为nova/virt/libvirt/imageackend中的Rbd类模块实现。

。。。。。。。。。。。此处省略分析验证过程。。。。。。。。。。。。。

4 Cinder

4.1 Cinder介绍

Cinder是OpenStack的块存储服务,相似AWS的EBS,管理的实体为volume。Cinder并无实现volume provide功能,而是负责管理各类存储系统的volume,好比Ceph、fujitsu、netapp等,支持volume的建立、快照、备份等功能,对接的存储系统咱们称为backend。只要实现了cinder/volume/driver.pyVolumeDriver类定义的接口,Cinder就能够对接该存储系统。

Cinder不只支持本地volume的管理,还能把本地volume备份到远端存储系统中,好比备份到另外一个Ceph集群或者Swift对象存储系统中,本文将只考虑从源Ceph集群备份到远端Ceph集群中的状况。

。。。。。。。。。。。此处省略分析验证过程。。。。。。。。。。。。。

5 总结

5.1 Glance

1. 上传镜像

rbd -p ${GLANCE_POOL} create --size ${SIZE} ${IMAGE_ID}rbd -p ${GLANCE_POOL} snap create ${IMAGE_ID}@snap
rbd -p ${GLANCE_POOL} snap protect ${IMAGE_ID}@snap

2. 删除镜像

rbd -p ${GLANCE_POOL} snap unprotect ${IMAGE_ID}@snap
rbd -p ${GLANCE_POOL} snap rm ${IMAGE_ID}@snap
rbd -p ${GLANCE_POOL} rm ${IMAGE_ID}

5.2 Nova

1 建立虚拟机

rbd clone \${GLANCE_POOL}/${IMAGE_ID}@snap \${NOVA_POOL}/${SERVER_ID}_disk

2 建立虚拟机快照

# Snapshot the disk and clone # it into Glance's storage poolrbd -p ${NOVA_POOL} snap create \${SERVER_ID}_disk@${RANDOM_UUID}rbd -p ${NOVA_POOL} snap protect \${SERVER_ID}_disk@${RANDOM_UUID}rbd clone \${NOVA_POOL}/${SERVER_ID}_disk@${RANDOM_UUID} \${GLANCE_POOL}/${IMAGE_ID} # Flatten the image, which detaches it from the # source snapshotrbd -p ${GLANCE_POOL} flatten ${IMAGE_ID} # all done with the source snapshot, clean it uprbd -p ${NOVA_POOL} snap unprotect \${SERVER_ID}_disk@${RANDOM_UUID}rbd -p ${NOVA_POOL} snap rm \${SERVER_ID}_disk@${RANDOM_UUID} # Makes a protected snapshot called 'snap' on # uploaded images and hands it outrbd -p ${GLANCE_POOL} snap create ${IMAGE_ID}@snap
rbd -p ${GLANCE_POOL} snap protect ${IMAGE_ID}@snap

3 删除虚拟机

for image in $(rbd -p ${NOVA_POOL} ls | grep "^${SERVER_ID}");do 
    rbd -p ${NOVA_POOL} rm "$image"; done

5.3 Cinder

1 建立volume

(1) 建立空白卷

rbd -p ${CINDER_POOL} create \--new-format --size ${SIZE} \volume-${VOLUME_ID}

(2) 从快照中建立

rbd clone \${CINDER_POOL}/volume-${SOURCE_VOLUME_ID}@snapshot-${SNAPSHOT_ID} \${CINDER_POOL}/volume-${VOLUME_ID}rbd resize --size ${SIZE} \openstack/volume-${VOLUME_ID}

(3) 从volume中建立

# Do full copy if rbd_max_clone_depth <= 0.if [[ "$rbd_max_clone_depth" -le 0 ]]; then
    rbd copy \
    ${CINDER_POOL}/volume-${SOURCE_VOLUME_ID} \
    ${CINDER_POOL}/volume-${VOLUME_ID}
    exit 0fi# Otherwise do COW clone.# Create new snapshot of source volumerbd snap create \${CINDER_POOL}/volume-${SOURCE_VOLUME_ID}@volume-${VOLUME_ID}.clone_snap
rbd snap protect \${CINDER_POOL}/volume-${SOURCE_VOLUME_ID}@volume-${VOLUME_ID}.clone_snap# Now clone source volume snapshotrbd clone \${CINDER_POOL}/volume-${SOURCE_VOLUME_ID}@volume-${VOLUME_ID}.clone_snap \${CINDER_POOL}/volume-${VOLUME_ID}# If dest volume is a clone and rbd_max_clone_depth reached,# flatten the dest after cloning.depth=$(get_clone_depth ${CINDER_POOL}/volume-${VOLUME_ID})if [[ "$depth" -ge "$rbd_max_clone_depth" ]]; then
    # Flatten destination volume 
    rbd flatten ${CINDER_POOL}/volume-${VOLUME_ID}
    # remove temporary snap
    rbd snap unprotect \
    ${CINDER_POOL}/volume-${SOURCE_VOLUME_ID}@volume-${VOLUME_ID}.clone_snap
    rbd snap rm \
    ${CINDER_POOL}/volume-${SOURCE_VOLUME_ID}@volume-${VOLUME_ID}.clone_snapfi

(4) 从镜像中建立

rbd clone \${GLANCE_POOL}/${IMAGE_ID}@snap \${CINDER_POOL}/volume-${VOLUME_ID}if [[ -n "${SIZE}" ]]; then
    rbd resize --size ${SIZE} ${CINDER_POOL}/volume-${VOLUME_ID}fi

2 建立快照

rbd -p ${CINDER_POOL} snap create \volume-${VOLUME_ID}@snapshot-${SNAPSHOT_ID}rbd -p ${CINDER_POOL} snap protect \volume-${VOLUME_ID}@snapshot-${SNAPSHOT_ID}

3 建立备份

(1) 第一次备份

rbd -p ${BACKUP_POOL} create \
--size ${VOLUME_SIZE} \
volume-${VOLUME_ID}.backup.base
NEW_SNAP=volume-${VOLUME_ID}@backup.${BACKUP_ID}.snap.${TIMESTAMP}
rbd -p ${CINDER_POOL} snap create ${NEW_SNAP}
rbd export-diff ${CINDER_POOL}/volume-${VOLUME_ID}${NEW_SNAP} - \
| rbd import-diff --pool ${BACKUP_POOL} - \
volume-${VOLUME_ID}.backup.base

(2) 增量备份

rbd -p ${CINDER_POOL} snap create \volume-${VOLUME_ID}@backup.${BACKUP_ID}.snap.${TIMESTAMP} rbd export-diff  --pool ${CINDER_POOL} \--from-snap backup.${PARENT_ID}.snap.${LAST_TIMESTAMP} \${CINDER_POOL}/volume-${VOLUME_ID}@backup.${BACKUP_ID}.snap.${TIMESTRAMP} - \| rbd import-diff --pool ${BACKUP_POOL} - \${BACKUP_POOL}/volume-${VOLUME_ID}.backup.base
rbd -p ${CINDER_POOL} snap rm \volume-${VOLUME_ID}.backup.base@backup.${PARENT_ID}.snap.${LAST_TIMESTAMP}

4 备份恢复

rbd export-diff --pool ${BACKUP_POOL} \volume-${SOURCE_VOLUME_ID}.backup.base@backu
相关文章
相关标签/搜索