OpenStack的數據庫開發基礎 - SQLAlchemy

jopen 9年前發布 | 21K 次閱讀 分布式/云計算/大數據 SQLAlchemy

OpenStack的數據庫開發基礎 — SQLAlchemy

        前言

        對于一個業務系統,如何高效、平穩地使用數據庫是每一個開發人員都會遇到的問題,OpenStack 也不例外,以 OpenStack 的虛擬網絡組件 Neutron 為例,其數據庫涉及幾百張表,需要維護數據庫版本近百;一些表因為設計原因形成了很高的“熱點”;因為 OpenStack 是分布式的,需要以最好小一點的代價保證操作時的一致性……最重要的是,每個人的數據庫水平都不一樣,怎么保證整個開源社區數百名提交者有一樣的數據庫操 作風格,如何維護這些代碼?

        OpenStack 做為一個完全使用 Python 開發的項目,利用已有的豐富模塊是開發時重要的中心思想之一,同時為了便于整個社區幾百名背景不同水平不同的開發者協作,最終選擇了 SQLAlchemy 和 Alembic 作為數據庫開發的基礎。

        Why SQLAlchemy

        在回答為什么使用 SQLAlchemy 之前,我們先盤點一下目前 Python 能用的 ORM 庫,因為挑一個庫在很大程度上實在挑社區,所以我把最新版的 release 時間也寫出來:

        Storm:最新版 0.20,release 于 2013 年,開發已經比較沉寂……對外鍵的更新、刪除要求比較奇怪。

        SQLObject:最新版 1.7.3,release 于 2014.12.18,開發歷史久,目前活躍度不是很高。

        Django’s ORM:來自于 Django,Django 內置,使用 Django 開發的話會很方便,但它不能脫離 Django 運行,也不能處理一些復雜的請求。

        peewee:最新版 2.4.4 發布于2014.12.3,輕量方便,內置 SQLite、MySQL和PostgreSQL的支持。

        PonyORM:最新版 0.6,release 于 2014.11.5。使用 AGPL 許可。有圖形化的編輯器。非為大型應用設計。

        SQLAlchemy:最新版 0.9.8,release 于 2014.10.13,企業級 API,設計靈活。加入了一些自己的概念,學習曲線較高。

        總結一下,Storm 曾經應用比較廣泛,但現在社區不再活躍,很難保證將來遇到問題能否交給社區解決,而且 Storm 對數據庫架構同步處理的比較奇怪,還有頻繁產生 DDL 操作 造成庫級鎖這些問題無法讓人放心;SQLObject 也是一個很出名的 ORM 庫,但與 SQLAlchemy 相比,后者效率更高,對一些高級特性的支持不如后者。

        SQLAlchemy 的架構

        Summary

        SQLAlchemy 很有特色的一點就是它刻意被分為另種用法,就是 CORE 和 ORM,這是由它的架構決定的。

        

OpenStack的數據庫開發基礎 — SQLAlchemy


        這樣的架構的好處是帶來了 Core 與 ORM 的解耦和,當我們需要高性能的 SQL 執行但又不想拋棄 SQLAlchemy 帶來的session管理、連接池管理、數據庫“中立”的語句編寫等這些好處時我們可以直接用 CORE。直接用 CORE 是什么意思呢?我們看到架構里只有Rational Mapper在 CORE 之上,實際也確實如此,因為Schema、SQL Expression Language還在 CORE 內,所以使用 CORE 可以直接寫純 SQL 語句,我們稱之為Raw SQL的寫法,也可以用SQL Expression,后者因為是相當于寫 Python 代碼,所以可以帶來更好地閱讀性和可維護性,不過Raw SQL更靈活,所以在很復雜的語句面前Raw SQL就更占優勢了。

        再往下看這個圖,我們可以看到 DBAPI 是由Third party libraries實現的,也就是說 SQLAlchemy 并沒有提供直接連接數據庫的功能,而是通過第三方實現:

        

OpenStack的數據庫開發基礎 — SQLAlchemy


        SQLalchemy 對dialect支持很全,就以常見的 MySQL 為例,可以支持:MySQL-Python、OurSQL、PyMySQL、MySQL Connector/Python、CyMySQL、Google Cloud SQL、PyODBC、zxjdbc for Jython,具體可以在 SQAlchemy 的dialects頁面里查到。

        這樣有什么壞處呢,最明顯的就是低效。因為傳統 Python 解釋器 CPython 的實現原因(主要是 C 的問題)長的函數調用棧會帶來顯著地性能問題。 由于路徑過長,不可避免地導致運行時的緩慢。SQLAlchemy 花了很舊去縮短調用路徑和通過 C 代碼處理性能瓶頸,效果還不錯,不過最好還是希望 PyPy 能夠廣泛流行起來,通過JIT緩解這個問題。

        Engine

        上面的圖還是一張抽象程度比較高的,下面我細節點的介紹下 SQLAlchemy 的Engine。

        

OpenStack的數據庫開發基礎 — SQLAlchemy


        對于使用者來說,Engine是核心,因為Connection、 ResultProxy這些都是在Engine之后生成的,建立Engine則有兩個重點,就是Pool和Dialect,前者是做連接池管理,后者則負 責與 DBAPI 的溝通,如同其名字所示,負責“方言”與“普通話”的翻譯。上圖是以psycopg2為例的,使用 MySQL(PyODBC)也是類似的。

        

OpenStack的數據庫開發基礎 — SQLAlchemy


        通過Dialect和ExecutionContext向開發者提供了一致的接 口,前者處理了數據庫的特性,比如使用 PostgreSQL 數據庫其 Array 數據類型、schema、catalog等,后者處理psycopg2 DBAPI 的用法,比如 unicode 字符處理、服務端 cursor 的行為這些。

        所以說,DBAPI中的cursor在 SQLAlchemy 中會被包裝成ExecutionContext和ResultProxy來使用的。

        Schema

        當數據庫的連接和交互處理完了,下一步就是提供非特定的表、字段的建立和操作方法。我們需要首先定義在數據庫中的表和字段的定義,及他們之間的關系, 也就是 Schema。對于數據庫的使用來說,最基本的至少要有兩個元素,那就是Table和Column,SQLAlchemy 使用了這兩個名字來描述表和字段。多個Column組合成Table,然后一些 Table構成MetaData。Schema的結構設計主要來自于 Martin Fowler 撰寫的 Patterns of Enterprise Application Architecture。

        

OpenStack的數據庫開發基礎 — SQLAlchemy


        此外,Table和Column同時繼承自sqlalchemy.schema 和sqlalchemy.sql,使用時既可以在 ORM 的方式中使用,也可以以 SQL Expression Language 使用。在下圖中我們可以看到Table從sqlalchemy.sql中“可以select from”的類繼承,Coloumn從“可以用在 SQL expression”的類繼承。

        

OpenStack的數據庫開發基礎 — SQLAlchemy


        表達式樹

        SQLAlchemy 可以生成結構豐富的各種語句,這是一個詞法分析樹,核心結構是ClauseElement。

        

OpenStack的數據庫開發基礎 — SQLAlchemy


        在 Python 中,得益于其 Magic Method,我們可以用__eq__、__ne__、__le__、__lt__、__add__、__mul__方便的重載運算符。以 Column 為對象的運算符由一個 mixin 類ColumnOperators實現重載。

        編譯

        在這里,編譯指生成 SQL 語句,主要由Compiled類完成,這個類有兩個核心的子類,SQLComplier和DDLCompiler。SQLComplier負責像 SELECT、INSERT、UPDATE、DELETE這些統稱為DQL (data query language) 和 DML (data manipulation language)的操作符的渲染,DDLCompiler負責CREATE和DROP,一般稱為 DDL。此外,還有一個類TypeCompiler處理某些數據庫的特殊語法。

        

OpenStack的數據庫開發基礎 — SQLAlchemy


        Compiled的子類定以了一系列的 visit 開頭的方法,每一個都源于一個ClauseElement的特定子類。然后Compiled對象維護名字、結合參數和子查詢,最終是為了生成一個 SQL 查詢語句。

        

OpenStack的數據庫開發基礎 — SQLAlchemy


        Migration

        我們希望能像管理代碼一樣管理數據庫,可以像 git 一樣給數據庫定義版本、升/降級、打標簽,可以么?答案就是 Alembic。

        Alembic 的作者與 SQLAlchemy 是同一人,使用起來有點像簡化版的 git,在 db 目錄里執行 init,就可以自動生成基本結構和配置文件。配置妥當后使用 alembic 可以生成一個數據庫模版,作為這個“版本”的數據升/降級文件,SQLAlchemy 會自動生成其“版本號”和歷史關系我們所需要做的便只是用調用 SQLAlchemy 和 Alembic 提供的 sa 和 op 定義數據庫表即可。

        有同學可能問我在 SQLAlchemy 上做過一模一樣的定義了,是不是能不要讓我重復勞動啊?或者在我給 SQLAlchemy 做完修改后 Alembic 能不能自動“感知”到這些修改然后自己生成版本文件啊?答案是可以的,配置好元數據來源后,Alembic 可以用–autogenerate自動生成相應的版本文件。

 

        本文來源:優思得云計算

        原文鏈接:https://www.ustack.com/blog/sqlalchemy/

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!