openstack cinder-backup流程與源碼分析


在現在的雲計算大數據環境下,備份容災已經變成了一個炙手可熱的話題,今天,和大家一起分享一下openstack是怎么做災備的。

   

【首先介紹快照】

snapshot可以為volume創建快照,快照中保存了volume當前的狀態,此后可以通過snapshot回溯。

   

主要采用了Copy On Write算法。進行快照時,不牽涉到任何檔案復制動作,它所作的只是通知服務器將目前有數據的磁盤區塊全部保留起來,不被覆寫

接下來檔案修改或任何新增、刪除動作,均不會覆寫原本數據所在的磁盤區塊,而是將修改部分寫入其它可用的磁盤區塊中

資源的復制只有在需要寫入的時候才進行,此前,是以只讀方式共享,使實際的拷貝被推遲到實際發生寫入的時候。

   

【備份和快照區別】

openstack中,cinder主要負責volume的創建以及管理工作,cinder-backup負責備份操作,cinder-snapshot負責快照操作。

   

大家都知道,備份和快照具有類似的功能,都可以保存當前volume的內容,以便於以后進行恢復。但是二者在用途上是由差別的:具體表如有以下幾點:

  1. snapshot依賴於源volume,不能獨立存在;而backup不依賴於volume,就算volume被刪除了,也可以單獨做恢復。
  2. snapshot通常和源volume存儲在一起,而backup一般會被作為異地容災放在其他的存儲后端

   

以上兩點,注定了快照和備份是作為不同用法出現的,快照主要用於便捷回溯,備份主要用於異地容災

   

cinder-backup配置】

Cinder backup 功能是由 cinder-backup 服務提供的,openstack 默認沒有啟用該服務,需要手工啟用。

cinder-volume 類似,cinder-backup 也通過 driver 架構支持多種備份 backend,包括 POSIX 文件系統、NFSCephGlusterFSSwift IBM TSM

支持的driver 源文件放在 /cinder/cinder/backup/drivers/

   

不同的備份存儲系統以Driver的形式得以支持,driver.py文件中定義了各種Driver的基類backupDriver,所有具體Driver的實現都位於drivers子目錄,通過配置文件的backup_driver選項指定使用的Driver

如:

backup_drive=cinder.backup.drivers.swift

   

   

backup基本流程】

cinder-backup服務在接到RPC請求后會找到該操作對應的host以及相應的存儲后端Driver,然后調用該Driver中與backup相關的接口,比如backup_volume()restore_backup(),這些接口最終會調用cinder-backup服務中Driver來對該Volume進行備份或者恢復操作。

   

下面代碼是備份一個卷的入口(早期版本的代碼,P版本代碼比較冗長未列)

#cinder/backup/manager.py

class BackupManager(manager.SchedulerDependentManager):

def create_backup(self, context, backup_id):

"""Create volume backups using configured backup service."""

backup = self.db.backup_get(context, backup_id)

 

#創建一個卷先找到對應的主機

volume_host = volume_utils.extract_host(volume['host'], 'backend')

backend = self._get_volume_backend(host=volume_host)

 

self.db.backup_update(context, backup_id, {'host': self.host'service'self.driver_name})

backup_service = self.service.get_backup_driver(context)

 

#調用Driver中與backup相關的接口

self._get_driver(backend).backup_volume(context, backupbackup_service)

 

   

工作流程大致如下:

   

cinder-api接收到備份請求后,會轉發到cinder-backup,由cinder-backup負責監聽請求並轉發,中間會包括一些卷類型的檢查以及服務的檢測,這里不多說,我們主要查看driver的工作情況。

如下圖所示:

   

對於不同的備份后端,后文會對cephchunk兩種模式分別做介紹。

   

【接口介紹】

表中,是backup相關的層次結構,備注了接口功能以及調用關系:

層次

功能

cinder-apiAPI層接口

暴露給客戶端的API接口

cinder-backupAPI層接口

RPC的接口進行封裝使被import

cinder-backupRPCAPI層接口

manager.py進行交互

cinder-backupmanager層接口

cinder-backupdriver進行交互

cinder-backupdriver層接口

與存儲后端或后端提供的庫進行交互

   

【代碼結構】

/cinder/backup/__init__.py

指定並導入cinder-backupAPI類;

/cinder/backup/api.py

處理所有與卷備份服務相關的請求

class API(base.Base): 卷備份管理的接口API

主要定義了卷的備份相關的三個操作的API

create:實現卷的備份的建立;

delete:實現刪除卷的備份;

restore:實現恢復備份;

這三個操作都需要通過backup_rpcapi定義的RPC框架類的遠程調用來實現

/cinder/backup/driver.py

class BackupDriver(base.Base): 所有備份驅動類的基類

/cinder/backup/manager.py

備份的管理操作的實現

核心代碼;

class BackupManager(manager.SchedulerDependentManager):塊存儲設備的備份管理;

主要實現的是三個遠程調用的方法:

create_backup:實現卷的備份的建立(對應api.py中的create方法);

restore_backup:實現恢復備份(對應api.py中的restore方法);

delete_backup:實現刪除卷的備份(對應api.py中的delete方法);

/cinder/backup/rpcapi.py

volume rpc API客戶端類

class BackupAPI(cinder.openstack.common.rpc.proxy.RpcProxy):volume rpc API客戶端類

主要實現了三個方法:

create_backup:遠程調用實現卷的備份的建立(對應api.py中的create方法);

restore_backup:遠程調用實現恢復備份(對應api.py中的restore方法);

delete_backup:遠程調用實現刪除卷的備份(對應api.py中的delete方法);

/cinder/backup/drivers/ceph.py

ceph備份服務實現

class CephBackupDriver(BackupDriver):Ceph對象存儲的Cinder卷備份類;

這個類確認備份Cinder卷到Ceph對象存儲系統;

/cinder/backup/drivers/swift.py

swift作為后端的備份服務的實現

class SwiftBackupDriver(ChunkedBackupDriver):swift作為后端的備份服務的各種管理操作實現類;

/cinder/backup/drivers/tsm.py

IBM Tivoli存儲管理(TSM)的備份驅動類;

class TSMBackupDriver(BackupDriver):實現了針對TSM驅動的卷備份的備份、恢復和刪除等操作;

/cinder/backup/drivers/other driver

同上

   

   

chunk driver

swiftnfsGoogleglusterfsposix的備份是基於chunk的備份。

其中有兩個參數解釋一下:

chunk_size

表示將volume分成多大的塊進行備份。

NFS中這個值叫做backup_file_size,默認是1999994880 Byte,大約1.8G

Swift中這個值叫做backup_swift_object_size,默認是52428800Byte,也就是50M

Ceph中這個值叫做backup_ceph_chunk_size,默認值是128M

sha_block_size

這個值用於增量備份,它決定了增量備份的粒度。

NFS中,這個值叫做backup_sha_block_size_bytes

Swift中,這個值叫做backup_swift_block_size

默認都是32768Byte,也就是32K

Ceph,沒有對應的概念。

   

swiftnfsGoogleglusterfsposix繼承自ChunkedBackupDriver(/cinder/backup/chunkeddriver.py),實現機制為將原始volume拆分成chunk,然后保存到對應的存儲上

做全量備份時,每次從volume讀入chunk_size字節數據,從頭sha_block_size個字節做一次SHA計算,並保存結果,然后chunk_size數據(可壓縮)保存到存儲上,形成一個object,循環將整個volume保存到backend 上,會生成兩個文件:metadatasha256file

   

其中metadata記錄volume對應存儲上的哪些objectobject大小、壓縮算法、長度、偏移量

sha256file按順序記錄每次SHA計算結果

當增量備份時,將每sha_block_size數據的SHA值與上次保存在sha256file中的SHA值比對若不等則備份相應sha_block

   

全量備份恢復時先指定volume id通過metadata文件將存儲端的備份文件和volume對應起來,而增量備份恢復時,由於增量備份的特性,使得增量備份間有依賴,形成備份鏈

   

配置如下:

[DEFAULT]

backup_driver = cinder.backup.drivers.nfs

 

backup_mount_point_base = /backup_mount

backup_share=172.16.8.99:/backup

   

手動啟動cinder-backup服務:

/usr/bin/python /usr/local/bin/cinder-backup --config-file /etc/cinder/cinder.conf

   

我們可以通過日志去查看cinder-backup到底做了些什么事情:

  1. 啟動 backup 操作,mount NFS
  2. 創建 volume 的臨時快照。
  3. 創建存放 backup container 目錄。
  4. 對臨時快照數據進行壓縮,並保存到 container 目錄。
  5. 創建並保存 sha256(加密)文件和 metadata 文件。
  6. 刪除臨時快照。

   

Backup 完成后,可以通過 cinder backup-list 查看當前存在的 backup

查看一下 container 目錄的內容,發現下面有以下內容:

backup-00001

壓縮后的 backup 文件

backup_metadata

metadata 文件

backup_sha256file

sha值文件

   

cinder backup-create中有以下幾個可選項:

--force

允許 backup 已經 attached volume

--incremental

表示可以執行增量備份。
如果之前做過普通(全量)備份,之后可以通過增量備份大大減少需要備份的數據量。

   

【恢復操作】

restore 的過程其實很簡單,兩步走:

在存儲節點上創建一個空白 volume

backup 的數據 copy 到空白 volume 上。

   

詳細流程如下:

  1. cinder-api 發送 restore 請求
  2. cinder-api 發送消息
  3. cinder-scheduler 挑選最合適的 cinder-volume
  4. cinder-volume 創建空白 volume
  5. 啟動 restore 操作,mount NFS
  6. 讀取 container 目錄中的 metadata
  7. 將數據解壓並寫到 volume 中。
  8. 恢復 volume metadata,完成 restore 操作。

   

所以,其實對於卷恢復來講,其實就是創建了一個與原備份卷時間點內容相同的新卷,不會對老的卷造成任何的影響

   

CEPH備份】

按照cinder-volume所用的backend分兩種情況介紹:一種是使用非RBD作為backend,另一種是使用RBD作為backend

   

cinder-volume使用非RBD作為backend

這種情況下比較簡單,並且僅支持全量備份

在創建備份時,首先創建一個base backup image,然后每次從源卷讀入chunk_size(即backup_ceph_chunk_size,默認是128MB)大小的數據,寫入到backup image,直到把整個源卷都復制完。

注意,這里不支持對chunk的壓縮

因為volume上的數據都會寫入到創建的這個backup image上去,也就是說volumebackup是一對一的,因此也不需要metadata文件

   

cinder-volume使用RBD作為backend

在這種情況下,即cinder-volumecinder-backup都是用rbd作為backend,是支持增量備份的。

增量備份的實現完全依賴於ceph處理差量文件的特性,所謂ceph處理差量文件的能力,即ceph可以將某個rbd image不同時刻的狀態進行比較,並且將其差量導出成文件。

另外,ceph也可以將這個差量文件導入到某個image中。

   

全量備份:

  1. 調用librbd創建backup base image,與源 volume 大小一致,name 的形式為 "volume-VOLUMD_UUID.backup.base"
  2. 調用cinder-volumerbd driver獲取該image相關元數據( 池子、用戶、配置文件等);
  3. 從源卷傳輸數據到該image;

    rbd image 新建一個快照,name形式為 backup.BACKUP_ID.snap.TIMESTRAMP

    rbd image 上使用 export-diff 命令導出從剛開始創建時到上一步快照時的差異數據其實就是現在整個rbd的數據,然后通過import-diff將差量數據導入剛剛在備份集群上新創建的base image中。

       

增量備份:

  1. 判斷是否有backup base image;
  2. 若沒有,判斷source image是否具有snap(from_snap),有的話刪除該snap;

    若有,尋找滿足"^backup.([a-z0-9-]+?).snap.(.+)$" 的最近一次快照,若不存在則報錯;

  3. source image創建一個新的snapname 形式為 backup.BACKUP_ID.snap.TIMESTRAMP;
  4. rbd image 上使用export-diff命令導出與最近的一次快照比較的差量數據,然后使用import-diff進行數據傳輸

   

ceph 增量備份其實就是基於ceph rbdexport-diffimport-diff 功能實現的:

export-diff

將某個 rbd image 在兩個不同時刻的數據狀態比較不同后導出補丁文件。

import-diff

將某個補丁文件合並到某個 rbd image 中。

   

恢復時相反,只需要從備份集群找出對應的快照並導出差量數據,導入到原volume即可。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM