2010年, 美國的雲計算公司 Rackspace 想重寫他們的雲平台代碼, 並打算開源他們的技術和代碼; 與此同時, NASA(美國航空航天局)下屬的 Anso Lab 實驗室發布了他們的 Beta 版的雲計算平台代碼;
Rackspace 想和 NASA 共同成立一個開源的雲計算平台項目;
2010年7月, 在奧斯丁, Rackspace 和 NASA 一起創建了 OpenStack 項目, 之后在波特蘭的世界開源大會上, OpenStack 被正式宣布;
開源之后, 大部分公司都選擇了 OpenStack 作為自己的雲計算平台, 國內使用 OpenStack 的公司有 騰訊, 阿里, 百度, 華為, 中國移動等等;
根據 Galera 的用戶案例里面的描述, 中國移動使用 OpenStack 和 Galera Cluster 在生產環境上部署了 1000 多個節點;
Galera 是一家位於芬蘭赫爾辛基的小公司, 他們的產品可以用下面一張圖來介紹;
基於 OpenStack 被大量使用, OpenStack 版本升級成為需要考慮的事, 不能影響生產環境, 要做到 0 停機時間;
OpenStack 實現了自己的滾動升級策略, 主要的思路是;
1. 表結構變更兼容: N 和 N+1 版本的服務同時支持 N+1 版本的一個中間狀態的表結構, 如下;
2. RPC 調用兼容: 類似表結構, RPC調用也做了兼容;
3. 服務之間的調用兼容: 服務之間的 restful 調用通過版本號控制, http://restful-api/v2, http://restful-api/v3;
這里舉例說下第1點---表結構變更的支持:
假如有一張表, 有3個屬性:
用戶名,
特長,
性別;
N版本插入了這樣一條數據:
用戶名: 吳藝凡,
特長: 牙簽,
性別: 男;
N+1 版本想刪除屬性 "性別", 流程大概是這樣的;
1. N+1 的 expand 階段不刪除列, 但是服務不會再操作 "性別" 這一列;
這個時候 N 版本仍舊可以對表進行增刪改查操作;
2. 逐步下線 N 版本的服務, 上線 N+1 版本的服務;
3. 變更表為 contract 階段, 這個時候刪除 "性別" 列;
如果場景不是刪除列而是增加列, 則 N+1 版本的服務在 contract 階段會用兩種方法填充新列:
1. 服務在訪問表時觸發對列數據的填充;
2. 執行 contract 遷移的時候對列數據填充;
上面就是簡單的表結構變更流程;
OpenStack 的滾動升級策略大概是從 Newton 版本開始的, 時間是在 2016年;
離開 OpenStack, 我們講一下 Google;
2013年, Google 的分布式數據庫 F1 取得成功, Google 發布了幾篇關於分布式數據庫的論文; 論述了 F1 的原理;
后來的很多分布式數據庫都是以 Google 的論文作為基礎開發出來的;
Google的其中一篇論文講述了數據庫升級時, 表結構變更的場景:
"Online, Asynchronous Schema Change in F1" --- F1 中的在線, 異步表結構變更;
Google論文原文鏈接: http://static.googleusercontent.com/media/research.google.com/zh-CN//pubs/archive/41376.pdf
因為某種原因打不開, 您可以自行搜索一下 PDF 版;
Google F1 的背景就不講了, 它是一個 分布式數據庫, 解決傳統 MySQL 和 Oracle 的問題; 這里稍微講一下為什么需要在線表結構變更:
傳統數據庫在表結構變更時, 操作期間數據庫無法提供服務;
即使有很多服務做熱備, 但是數據庫升級時服務不能訪問數據庫, 所以服務不可用;
Google 的論文可以保證在表結構變更期間, 服務仍然可以訪問數據庫;
以增加表字段為例, 大體上講講這篇論文:
如果要增加一個主鍵列, 列狀態需要有如下的狀態變更流程:
absent --> delete only --> write only --(db reorg)--> public
不存在 --> 只能被刪 --> 只能被寫 --重組數據--> 公共狀態
這里的狀態在論文的中 3.1 節有定義: 3.1 Schema elements and states;
比如: 一個 delete-only 的表或列, 不能被讀, 只能被刪, 一個 delete-only 的索引, 只能被刪或者更新, 並且更新操作只能刪除索引對應的鍵值對, 而不能創建;
A delete-only table, column, or index cannot have their key–value pairs read by user transactions and 1. if E is a table or column, it can be modified only by delete operations. 2. if E is an index, it is modified only by delete and update operations. Moreover, update operations can delete key–value pairs corresponding to updated index keys, but they cannot create any new ones.
下面是增刪改表結構的流程, 其中紅框部分是增加表字段的流程; 參見論文中的 Figure 3;
對於主鍵, 是上面提到的: absent --> delete only --> write only --(db reorg)--> public;
對於可選字段, 流程簡單一點 absent --> delete only --(db reorg)--> public;
除了狀態約束, 還加入了新的約束: lease(租期);
兩個相鄰的租期之間的操作是相容的;
以增加可選列為例;
absent --> delete only --(db reorg)--> public;
1. 計算節點1 在 t1 時間點同步到的列狀態為absent;
2. t1+1 時間點列狀態變為 delete only;
3. 計算節點2 的租期在 t1+2 過期, 它重新同步表狀態, 獲取的列的狀態為 delete only;
4. 計算節點2 在 t1+3 時間點執行SQL: insert xxx into xxx, 新增加的列的狀態為 delete only, 所以這列不會進入數據;
5. 計算節點1 在 t1+4 時間點 執行SQL: delete xxx from xxx, 它緩存的列狀態為absent, 新列對它不可見, 它不需要刪除新列的數據;
這個場景的關鍵點是 delete only 狀態, 他可以保證 absent 狀態的計算節點的操作不會留下orphan data(孤兒數據);
兩個相鄰的租期的計算節點的操作, 對於對方是兼容的;
如果一個計算節點無法在租期過后重新同步表狀態怎么辦? 論文沒提到, 其實很簡單, 把這個計算節點殺掉就可以了;
我們再回頭看看剛才 OpenStack 的滾動升級策略, 和 Google 的 這篇論文很像; 只是 OpenStack 把這種思想用在了業務服務的層面上;
完;