Openstack 使用migrate進(jìn)行數(shù)據(jù)庫(kù)升級(jí)實(shí)現(xiàn)方案詳細(xì)介紹
Openstack 使用migrate進(jìn)行數(shù)據(jù)庫(kù)升級(jí)實(shí)現(xiàn)方案詳細(xì)介紹
OpenStack中隨著版本的切換,新版本加入一些數(shù)據(jù)庫(kù)表或者增加字段等是必然的事情,如何比較容易的進(jìn)行這些數(shù)據(jù)庫(kù)升級(jí)的適配和管理,這里就要用到oslo_db中的migrate了,這里以為M版本的heat為例,講解一下migrate管理db的原理。
我們使用migrate需要用到的主要包含以下兩部分:1.versions里面的為版本號(hào)+數(shù)據(jù)庫(kù)適配腳本;2.migrate.cfg為migrate需要用到的配置文件,兩部分的命名是固定的。
使用migrate進(jìn)行數(shù)據(jù)庫(kù)升級(jí)非常簡(jiǎn)單,heat這邊提供了heat-manage db_sync, db_version的命令用來(lái)升級(jí)db以及查看當(dāng)前db的版本號(hào),這里以執(zhí)行heat-manages db_sync,看下migrate的過(guò)程。
def db_sync(engine, version=None): path = os.path.join(os.path.abspath(os.path.dirname(__file__)), 'migrate_repo') return oslo_migration.db_sync(engine, path, version, init_version=INIT_VERSION)
heat代碼的入口在這里,需要傳入engine用來(lái)連接db,version為我們需要升級(jí)到的版本,這里沒(méi)有傳,可以看到heat這邊是直接使用oslo_migrate的db_sync方法,我們看下三方庫(kù)中的這個(gè)方法。
def db_sync(engine, abs_path, version=None, init_version=0, sanity_check=True): """Upgrade or downgrade a database. Function runs the upgrade() or downgrade() functions in change scripts. :param engine: SQLAlchemy engine instance for a given database //連接數(shù)據(jù)庫(kù) :param abs_path: Absolute path to migrate repository. //migrate倉(cāng)庫(kù)的絕對(duì)路徑 :param version: Database will upgrade/downgrade until this version. //需要升級(jí)或者降級(jí)到的版本號(hào),如果不傳則默認(rèn)升級(jí)到最新版本 If None - database will update to the latest available version. :param init_version: Initial database version //數(shù)據(jù)庫(kù)的初始版本號(hào),會(huì)以該初始版本為起點(diǎn)升級(jí) :param sanity_check: Require schema sanity checking for all tables //合理性檢查 """ if version is not None: try: version = int(version) except ValueError: raise exception.DBMigrationError(_("version should be an integer")) current_version = db_version(engine, abs_path, init_version) repository = _find_migrate_repo(abs_path) if sanity_check: _db_schema_sanity_check(engine) if version is None or version > current_version: migration = versioning_api.upgrade(engine, repository, version) else: migration = versioning_api.downgrade(engine, repository, version) if sanity_check: _db_schema_sanity_check(engine) return migration
代碼很清晰,簡(jiǎn)潔。可以看到,整個(gè)過(guò)程就是先查詢下當(dāng)前db的版本,然后聲明一個(gè)migrate倉(cāng)庫(kù)示例,對(duì)db做合理性檢查(主要是針對(duì)mysql),然后根據(jù)傳入的version和當(dāng)前的version決定是升級(jí)或者降低,最后再次檢查,整個(gè)migrate就完成了。
首先是查詢當(dāng)前數(shù)據(jù)庫(kù)的版本,
def db_version(engine, abs_path, init_version): """Show the current version of the repository. :param engine: SQLAlchemy engine instance for a given database :param abs_path: Absolute path to migrate repository :param init_version: Initial database version """ repository = _find_migrate_repo(abs_path) try: return versioning_api.db_version(engine, repository) except versioning_exceptions.DatabaseNotControlledError: meta = sqlalchemy.MetaData() meta.reflect(bind=engine) tables = meta.tables if len(tables) == 0 or 'alembic_version' in tables: db_version_control(engine, abs_path, version=init_version) return versioning_api.db_version(engine, repository) else: raise exception.DBMigrationError( _("The database is not under version control, but has " "tables. Please stamp the current version of the schema " "manually."))
首先是根據(jù)傳入的絕對(duì)路徑,構(gòu)造一個(gè)倉(cāng)庫(kù)對(duì)象的示例,這里比較關(guān)鍵,初始化方法如下,可以看到我們前面提到migrate.cfg和versions就是在這里被使用的,而且名字也是固定的,必須為migrate.cfg和versions。
class Repository(pathed.Pathed): """A project's change script repository""" _config = 'migrate.cfg' _versions = 'versions' def __init__(self, path): log.debug('Loading repository %s...' % path) self.verify(path) super(Repository, self).__init__(path) self.config = cfgparse.Config(os.path.join(self.path, self._config)) self.versions = version.Collection(os.path.join(self.path, self._versions)) log.debug('Repository %s loaded successfully' % path) log.debug('Config: %r' % self.config.to_dict())
這里會(huì)驗(yàn)證我們傳入的path下面是否存在versions和migrate.cfg,因此我們的代碼目錄結(jié)構(gòu)也必須按照這個(gè)放。self.config主要是用來(lái)管理migrate.cfg的配置,self.versions主要用來(lái)管理如何升級(jí),repository對(duì)象另外還包含3個(gè)比較重要的屬性,latest:最新的版本(versions中版本號(hào)最大的),這里是73,version_table:用來(lái)記錄和管理migrate版本號(hào)的數(shù)據(jù)庫(kù)表,這里是migrate_version,id用來(lái)存放我們管理的數(shù)據(jù)庫(kù)標(biāo)示,這里是heat,后兩項(xiàng)都是從數(shù)據(jù)庫(kù)里面取。
@property def latest(self): """API to :attr:`migrate.versioning.version.Collection.latest`""" return self.versions.latest @property def version_table(self): """Returns version_table name specified in config""" return self.config.get('db_settings', 'version_table') @property def id(self): """Returns repository id specified in config""" return self.config.get('db_settings', 'repository_id')
回到之前的代碼
try: return versioning_api.db_version(engine, repository) except versioning_exceptions.DatabaseNotControlledError: meta = sqlalchemy.MetaData() meta.reflect(bind=engine) tables = meta.tables if len(tables) == 0 or 'alembic_version' in tables: db_version_control(engine, abs_path, version=init_version) return versioning_api.db_version(engine, repository) else: raise exception.DBMigrationError( _("The database is not under version control, but has " "tables. Please stamp the current version of the schema " "manually."))
這里會(huì)根據(jù)數(shù)據(jù)庫(kù)引擎和剛才的repository實(shí)例對(duì)象獲取當(dāng)前數(shù)據(jù)庫(kù)的版本號(hào),其實(shí)就是從migrate本身所在數(shù)據(jù)表中去查找當(dāng)前的版本號(hào)(version_version),假如是第一次使用migrate,由于還沒(méi)有建立migrate_version表,所以引發(fā)異常。這里會(huì)去查一下當(dāng)前數(shù)據(jù)庫(kù)中的所有數(shù)據(jù)表,如果已有其他數(shù)據(jù)庫(kù)表,則會(huì)引發(fā)DBMigrationError的異常,因?yàn)閙igrate必須在建立其他數(shù)據(jù)表之前先建立才能管控所有的數(shù)據(jù)表,假如我們之前沒(méi)有使用migrate機(jī)制但是想在后面的db控制中使用起來(lái),這里有2個(gè)思路:手動(dòng)插入migrate_version數(shù)據(jù)表并配置合適的版本或者手動(dòng)插入alebic_version。
繼續(xù)往下面看,如果是第一次使用migrate,
db_version_control(engine, abs_path, version=init_version)
會(huì)建立migrate_version,并設(shè)置合適的初始值,也就是傳入的init_version,后續(xù)的數(shù)據(jù)庫(kù)升級(jí)等操作就可以通過(guò)migrate管控起來(lái)了。migrate_version表建立起來(lái)后,就回到了最初的流程,根據(jù)我們db_sync傳入的版本號(hào)和當(dāng)前的版本號(hào),migrate會(huì)執(zhí)行versions里面每個(gè)版本的upgrade()方法直至升級(jí)完成并更新migrate_version中的版本號(hào)。
使用migrate的好處在于,可以很方便的集中記錄和管理每次對(duì)數(shù)據(jù)庫(kù)的變動(dòng),在后續(xù)升級(jí)過(guò)程中,一鍵式完成對(duì)應(yīng)的適配操作,非常方便,并且不會(huì)出現(xiàn)重復(fù)增加字段等操作,在開(kāi)發(fā)過(guò)程中,我們只要知道了migrate的原理,就能很方便的使用起來(lái)了。
感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
- OpenStack Ceilometer用MongoDB解決占用磁盤(pán)空間過(guò)大問(wèn)題
- OpenStack Heat AutoScaling詳解及實(shí)例代碼
- Openstack 網(wǎng)絡(luò)知識(shí)資料詳細(xì)介紹及總結(jié)
- OpenStack 創(chuàng)建windows鏡像實(shí)現(xiàn)步驟
- Openstack 創(chuàng)建項(xiàng)目和虛擬機(jī)詳細(xì)介紹
- openstack 重啟的服務(wù)命令整理總結(jié)
- OpenStack 工作流workflows使用原理詳細(xì)介紹
- Openstack 節(jié)點(diǎn)維護(hù)詳細(xì)講解
- OpenStack之虛機(jī)熱遷移的代碼詳細(xì)解析
- CentOS 一鍵安裝Openstack詳細(xì)介紹
- 一步一步教你安裝openstack(圖文)
相關(guān)文章
openstack云計(jì)算keystone組件工作流程及服務(wù)關(guān)系
這篇文章主要介紹了openstack云計(jì)算keystone組件工作流程及服務(wù)關(guān)系,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-04-04OpenStack虛擬機(jī)快照和增量備份實(shí)現(xiàn)方法
快照針對(duì)要保存的數(shù)據(jù)分為內(nèi)存快照和磁盤(pán)快照,內(nèi)存快照就是保存當(dāng)前內(nèi)存的數(shù)據(jù),磁盤(pán)快照就是保存硬盤(pán)的數(shù)據(jù),這篇文章主要介紹了OpenStack虛擬機(jī)快照和增量備份實(shí)現(xiàn),需要的朋友可以參考下2022-04-04CentOS系統(tǒng)中一鍵安裝Openstack圖文教程
最近在學(xué)習(xí)Openstack,一直想試試安裝一下,可是參考了很多資料,并不如人意。由于一直用的Linux版本為CentOS,大部分Openstack安裝都要求在Ubuntu上進(jìn)行。本文介紹的是在CentOS系統(tǒng)中一鍵安裝Openstack的方法,有需要的朋友們可以參考學(xué)習(xí),下面來(lái)一起看看吧。2016-10-10openstack云計(jì)算keystone架構(gòu)源碼分析
這篇文章主要為大家介紹了openstack云計(jì)算keystone架構(gòu)源碼分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-04-04OpenStack Mitaka 版本中的 domain 和 admin詳解
這篇文章主要介紹了OpenStack Mitaka 版本中的 domain 和 admin詳解,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-03-03OpenStack Tempest的正確的打開(kāi)方式
Tempest 是一個(gè)旨在為云計(jì)算平臺(tái) OpenStack 提供集成測(cè)試的開(kāi)源項(xiàng)目。它是基于 unittest2 和 nose 建立的靈活且易于擴(kuò)展及維護(hù)的自動(dòng)化測(cè)試框架,使得 OpenStack 相關(guān)測(cè)試效率得到大幅度提升。2017-01-01Openstack安裝過(guò)程中遇到的問(wèn)題匯總
本文給大家分享的是作者在Centos7中安裝openstack過(guò)程中出現(xiàn)的一些問(wèn)題的匯總,以及解決的方法,有需要的小伙伴可以參考下2017-04-04