如何對DevOps數據庫進行源代碼控制

提綱:

  • 包括索引在內的數據庫模式需要進行源代碼控制
  • 諸如查詢表這類用于控制業務邏輯的數據需要進行源代碼控制
  • 開發人員需要一種能夠便捷地創建本地數據庫的方法
  • 共享數據庫的更新只能通過構建服務器完成

健壯的DevOps環境需要對系統的每個組件進行持續集成。但是,數據庫常常被排除在這之外,這會導致從脆弱的產品發布和低效的開發實踐到讓新入職的程序員工作更困難等一系列問題。

在本文中,我們將討論在成功的持續集成環境中,關系型數據庫和NoSQL數據庫的獨特的一面。

模式的源代碼控制

首先需要解決的就是源代碼控制和模式問題。讓開發人員以一種特別的方式進行數據庫變更是不合適的。這相當于在生產服務器上通過直接編輯JavaScript文件對其進行更改。

在為數據庫規劃源代碼控制時,需要確保囊括了所有內容。這包括但不限于:

  • 表或者集合
  • 約束
  • 索引
  • 視圖
  • 存儲過程、函數以及觸發器
  • 數據庫配置

您可能會想,“我使用的是無模式數據庫,所以我不需要源代碼控制”。即便如此,您仍需要考慮索引和數據庫的整體配置。如果在QA和生產數據庫中索引計劃不同,那么執行性能測試將毫無意義。

數據庫的源代碼控制有兩種基本類型,我們將其稱為“全模式”和“變更腳本”。

全模式源碼控制

“全模式”源碼控制指的是源代碼控制與你所希望的數據庫的外觀看起來十分相似。在使用此模式時,可以看到所有的表和視圖都按照預期的樣子排列,這讓你無需部署數據庫就能夠更容易理解它。

SQL Server的SQL Server Data Tools(SSDT)就是全模式源碼控制的一個例子。這個工具可以通過CREATE腳本的形式表示所有數據庫對象。當想要用SQL創建一個新的對象,只需將最終腳本直接粘貼到處于源代碼控制下的數據庫項目中即可,這就很方便了。

全模式源碼控制的另一個例子是實體框架遷移(Entity Framework Migrations)。在這個案例中,數據庫主要通過C#/VB類的方式而非SQL腳本的方式表現。但同樣,可以通過瀏覽源代碼獲得對數據庫的整體認識。

在使用全模式源碼控制時,通常不需要直接編寫遷移腳本。部署工具通過將數據庫的當前狀態與處于源代碼控制中的理想版本進行比較來確定需要進行哪些更改。這可以讓你快速完成數據庫變更并看到結果。在使用這種類型的工具時,我很少直接更改數據庫,而是使用工具完成大部分工作。

有些情況下,只有工具是不夠的,即使包含部署前和部署后腳本也是如此。在這種情況下,生成的遷移腳本必須由數據庫開發人員或DBA手工修改,這可能會破壞持續部署計劃。這種情況通常發生在對表結構進行重大變更時,因為在這些情況下生成的遷移腳本效率可能較低。

全模式源碼控制的另一個優點是它支持代碼分析。例如,如果列的名稱被更改,但在視圖中未做出相應更新,SSDT將返回一個編譯錯誤。就像應用程序設計語言中的靜態類型一樣,可以捕獲大量錯誤,并且能夠對部署有明顯錯誤的腳本提前防范。

變更腳本源碼控制方式

另一種源代碼控制方式就是變更腳本源碼控制。這種方式不存儲數據庫對象本身,而是存儲創建數據庫對象所需的步驟列表。我曾經成功使用的是Liquibase數據庫,總的來說這類工具的工作機制都差不多。

變更腳本工具的主要優點是可以完全控制最終遷移腳本的樣貌。這使得復雜變更的執行更加容易,例如表的拆分或合并。

不幸的是,這種類型的源代碼控制也存在一些缺陷。首先是需要編寫變更腳本。雖然它的控制力度更強,但同樣也更費時。相比于手寫ALTER TABLE腳本,為C#類添加一個屬性要容易得多。

當使用SchemaBinding之類的功能時,會讓問題更加嚴重。對于不熟悉這個術語的人,可以將其理解為,通過鎖定表的模式啟用SQL Server中的一些高級特性。如果要變更表或視圖的設計,必須首先將SchemaBinding從任何與該表或視圖有關的視圖中移除。如果這些視圖被其他視圖模式綁定(schema-bound),那么這些視圖同樣也需要臨時解除綁定。雖然對于全模式源代碼控制工具來說,生成所有的樣板很容易,但是想要用手工的方式正確地生成它們還是一項相當困難的工作。

變更腳本工具的另一個缺點是它們往往難以理解。例如,如果你希望在不部署表的情況下了解某個表中列的信息,則需要查閱所有涉及該表的變更腳本。這就很容易錯過某些信息。

該如何選擇源代碼控制模型?

從頭開始一個新的數據庫項目時,我會選擇全模式源代碼控制。這種模式會讓開發人員工作更加高效并且只要有一名人員完成設置工作,之后只需要很少的知識就可以正常使用。

對于現存的數據庫,特別是那些已經存續多年的生產環境數據庫,通常選擇變更腳本源代碼控制模式更加合適。全模式工具會對數據庫設計做出某些特定的假設,而更改腳本工具則是通用的。此外,全模式工具構建難度更大,對于某些特殊的數據庫來說,可能根本不可用。

數據管理

根據表中所含數據的性質,表可以被廣泛地分類為“管理表”、“用戶表”或“混合表”。根據表所屬的類別不同,處理這些表的方式也是不同的。

管理表

將數據庫置于源代碼控制之下的一個常見錯誤是遺忘數據。總有一些“查詢表”保存著用戶不打算修改的數據。例如,其中可能包含表驅動的業務規則邏輯、狀態機的各種狀態碼,或者僅僅是與應用程序代碼中的枚舉類相匹配的鍵-值對列表。

這類表中的數據應該被視為源代碼一樣對待。對這類數據的變更需要經過與其他代碼變更相同的評審和QA過程。特別重要的是,為確保這些變更不會被遺漏,這些變更的部署應該與其他應用程序和數據庫部署一并自動完成。

在SQL Server數據工具中,我使用部署后腳本處理此問題。在這個腳本中,我將期望數據填充到一張臨時表中,然后使用MERGE語句更新實際表。

如果源代碼控制工具無法很好地處理這個問題,還可以通過構建獨立工具來執行數據更新。重要的不是如何做,而是這個過程是否易用并且可靠。

用戶表

用戶表指的是用戶可以添加或修改數據的表。因此,這包括可以直接修改的表(例如名稱和地址)和通過操作間接修改的表(例如貨單收據、日志)。

真實的用戶數據基本不會被直接加入源代碼控制中,不過,為開發和測試提供逼真的樣本數據也是一種最佳實踐。這些數據可以直接存儲在數據庫項目中,處于源代碼控制之下的其他地方,如果特別大,也可以保存在獨立的共享文件中。

混合表

混合表指的是即存儲管理數據也存儲用戶數據的表。有兩種方法可以對其進行分區。

列分區是指用戶可以修改某些列,但不能修改其他列。在這種場景下,可以將該表視為有額外限制的普通管理表,用戶控制的列永遠不會被更新。

行分區指的是某些記錄用戶無法修改的情況。我曾經遇到的常見的場景是需要在用戶表中對某些值進行硬編碼。在較大型的系統中,對于每個可以獨立于任何真實用戶進行更改的微服務,可能都有一個獨立的用戶ID。例如,可能是一個被稱為“銀行數據導入器”的用戶。

在我看來,管理行分區混合表的最佳方法是通過保留鍵的方式。當定義identity/auto-number列時,將初始值設置為1,000,通過源代碼控制對編號從1到999的用戶ID進行管理。這需要數據庫允許手動設置identity列中的值。在SQL Server中,是通過SET_IDENTITY_INSERT命令完成的。

處理此場景的另一個選擇是使用名為“SystemControlled”的列或者能夠達到類似效果的方法。當設置為1/true時,表示應用程序不可直接修改。如果設置為0/false,則部署腳本會將其忽略。

個人開發數據庫

將模式和數據置于源代碼控制之下,就可以進行下一步并著手設置個人開發數據庫。正如每個開發人員都應該能夠運行自己的web服務器實例一樣,有可能對數據庫設計做出修改的每個開發人員都需要能夠運行自己的數據庫副本。

這一規則經常會被打破,這對開發團隊是相當不利的。在共享環境上做變更的開發人員一定會相互干擾。他們甚至可能會陷入“部署之爭”,每個開發人員都試圖將更改部署到數據庫。當使用全模式工具執行此操作時,開發人員將交替地恢復其他開發人員的變更,甚至都不會意識到這一點。在使用變更腳本工具的情況下,數據庫則可能處于不確定狀態,遷移腳本可能無法正常使用,需要從備份中重新恢復。

另一個問題是模式漂移。這時,開發數據庫與處于源代碼控制下的內容不再匹配。隨著時間的推移,開發數據庫會逐漸積累越來越多的非生產表、測試腳本、臨時視圖和其他垃圾信息需要清除。當每個開發人員都有自己的數據庫時,這樣做要容易得多,因為他們可以隨時重置數據庫。
最后也是最重要的問題是,服務開發人員和UI開發人員需要穩定的平臺來編寫代碼。如果共享數據庫不斷變化,他們就無法有效地工作。在我曾經工作過的一家公司,很少看到開發人員大喊“服務又宕機了!”,然后玩一個小時視頻游戲,等待共享數據庫重新組裝起來。

共享的開發和集成數據庫

對于共享的開發人員數據庫或集成數據庫來說,首要原則就是不能對數據庫直接進行修改。更新共享數據庫的唯一方法就是通過構建服務器以及持續集成/部署流程完成。這不僅可以防止模式漂移,還可以通過有計劃的更新減少中斷的次數。

根據經驗,我會在相關分支進行代碼檢入時同步更新共享開發人員數據庫。這可能會造成中斷,但通常是處于可控范圍的。在進行集成之前,您確實需要先驗證部署腳本的正確性。

對于集成數據庫而言,我更傾向于每日安排一次部署,與服務的部署次數相同。這樣能夠為UI開發人員提供一個相對穩定的工作平臺。對于UI開發人員來說,沒有什么比不知道突然開始失敗的代碼是他們的錯誤還是服務/數據庫中的問題更令人沮喪的了。

數據庫安全和源代碼控制

在數據庫管理中,安全性是一個經常被忽略的方面。具體來說,就是哪些用戶和角色可以訪問哪些表、視圖和存儲過程。在最糟糕的情況下,應用程序可以獲得對數據庫的完全訪問權限。它可以對每個表的每一列進行讀寫操作,甚至是那些與其沒有業務關聯的列。數據泄漏經常是由于實用小程序的訪問權限遠遠超過其所需的訪問權限而造成的。

鎖定數據庫的主要反對意見是,“我們無法預知什么會崩潰”。因為以前從未被鎖定過,所以開發人員根本不知道應用程序實際需要的權限是什么。

解決這一問題的辦法是從第一天起就將權限控制放入源代碼控制中。這樣,當開發人員測試應用程序時,如果權限不正確,一開始就會失敗。這反過來又意味著,當到達QA階段時,所有權限問題都已解決,不存在權限缺失的猜測或風險。

容器化

根據項目的性質不同,數據庫的容器化是一個可選步驟。我將通過兩個案例說明個中原因。

對于第一個案例,這個項目有一個非常簡單的分支結構:有一個“dev”分支,它會導入QA分支,QA分支又會導入階段化分支和最終的生產分支。這可以通過四個共享數據庫實現,管道中的每個階段,各使用一個數據庫。

在第二個案例中,我們有一組重要的特性分支。每個重要的特性分支被進一步細分為開發和QA分支。每個特性必須通過QA檢驗,才能夠成為合并到主分支的候選特性,因此每個重要特性都需要有各自的測試環境。

在第一個案例中,即使web服務確實需要容器,容器化也可能是浪費時間。對于第二個用例,容器化某種程度上則是至關重要的。如果沒有真正的容器(例如Docker),那么在創建新的重要特性分支時,至少可以根據需要生成新環境的部署腳本(例如AWS或Azure)。

關于作者

Jonathan Allen在90年代后期開始為一家醫療診所開發MIS項目,逐步將該項目從Access和Excel升級成企業級的解決方案。在花了五年時間為金融業編寫自動化交易系統之后,他成為了多個項目的顧問,其中包括自動化倉庫的UI、癌癥研究軟件的中間層,以及一家大型房地產保險公司的大數據需求。在空閑時間,他喜歡研究和記錄源于16世紀的武術。

查看英文原文: How to Source Control Your Databases for DevOps

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/280445.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/280445.shtml
英文地址,請注明出處:http://en.pswp.cn/news/280445.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

自定義異常最佳實踐_播放,自定義和組織媒體的最佳文章

自定義異常最佳實踐Computers today are used for much more than generating documents, writing and receiving email, and surfing the web. We also use them to listen to music, watch movies and TV shows, and to transfer media to and from mobile devices. 如今&…

CSS中的路徑裁剪樣式clip-path

前面的話 CSS借鑒了SVG裁剪的概念,設置了clip-path樣式,本文將詳細介紹路徑裁剪clip-path 概述 clip-path屬性可以防止部分元素通過定義的剪切區域來顯示,僅通過顯示的特殊區域。剪切區域是被URL定義的路徑代替行內或者外部svg,或…

socket編程學習筆記

socket編程: 1、網絡基礎知識 兩臺計算機通過網絡進行通信,首先兩臺計算機要有唯一的標識,即唯一的IP地址。其次他們要有共同的語言用來交流即協議。再者,每套主機要有相應的端口號。  TCP/IP協議:   --TCP/IP協議是…

rest_framework04:ModelSerializer/Serializer高級用法

ModelSerializer 1.減小序列化類代碼 2.不需要重寫update,create ser.py class BookModelSerializer(serializers.ModelSerializer):class Meta:modelBookfields__all__ #序列化全部字段# fields(name,price) # 序列化指定字段# exclude(name,) # 與fields 不能…

配置本地及網絡yum源(詳細步驟)

我們以centos6為范例演示 1、[rootCentos6 ~]# cd /etc/yum.repos.d/ [rootCentos6 yum.repos.d]# ls CentOS-Base.repo CentOS-fasttrack.repo CentOS-Vault.repoCentOS-Debuginfo.repo CentOS-Media.repo先羅列出相關文件 2、[rootCentos6 yum.repos.d]# vim CentOS-Base.rep…

macos mojave_如何修復macOS Mojave上的模糊字體(使用亞像素抗鋸齒)

macos mojaveApple’s macOS Mojave disables subpixel antialiasing, also known as font smoothing, by default. On a MacBook Air or a desktop Mac hooked up to a non-Retina display, upgrading will make your fonts look worse. 蘋果的macOS Mojave默認情況下禁用子像…

為什么我要寫博客

原因在這啦 一、我覺得分享是一種精神,分享是我的樂趣所在,不是說我覺得我講得一定是對的,我講得可能很多是不對的,但是我希望我講的東西是我人生的體驗和思考,是給很多人反思,也許給你一秒鐘、半秒鐘&…

一個變量命名神器:支持中文轉變量名

變量命名的規范,對于我們編程,大家都知道是非常重要的,上次給大家推薦過一個命名輔助工具《程序員還在為變量取名苦惱,那是因為你不知道,這個變量命名神器》,但大家一致反饋存在2個問題:1、網速…

rest_framework05:GenericAPIView用法/擴展類5個/子類9個/ViewSetMixin 自定義方法名字

GenericAPIView 1.視圖層類使用GenericAPIView繼承,能簡化類里的方法code。 2.簡化后的方法code格式基本通用,簡單修改即可應用到其他類。 一、class開始加入 queryset Book.objectsserializer_class BookModelSerializer 二、方法里獲取對象 a.查…

1.操作系統概述

2019獨角獸企業重金招聘Python工程師標準>>> 操作系統的發展過程 無操作系統的計算機系統單道批處理系統(50年代,系統資源利用率低)多道批處理系統(60年代)分時系統(70年代)實時系統…

測聽hl和nhl的區別_播放NHL曲棍球的最便宜方法(無電纜)

測聽hl和nhl的區別If you’re like me, you watch hockey, and…basically no other sports. You also, like me, would like to skip the cable subscription. So what’s the cheapest way to watch NHL hockey online so you can cut the cord? 如果您像我一樣,…

制作一個讓客戶滿意的軟件

我看了《構建之法》的第八章“需求分析”我對如何制作一個讓客戶滿意的軟件有了一點兒頭緒,的但是還是有一些迷惑。我通過看書總結和百度查找有了一點兒總結:我們在制作軟件的過程中應該及時與用戶溝通交流,交換意見,并及時實現用…

rest_framework06:自動生成路由\action使用\認證

自動生成路由 # 1.導入routers模塊 from rest_framework import routers# 2.實例化類 routerrouters.SimpleRouter()# 3.注冊 # (前綴,繼承自ModelViewSet視圖類,別名) router.register(books7,views.BooksView) # 不要加斜杠# 4.加入 urlpatternsrouter.urls action使用 裝…

char data[0]在struct末尾的用法

在實際的編程中,我們經常需要使用變長數組,但是C語言并不支持變長的數組。此時,我們可以使用結構體的方法實現C語言變長數組。 struct MyData { int nLen; char data[0];}; 在結構中,data是一個數組名;但該數組沒有元素…

使用Java實現K-Means聚類算法

2019獨角獸企業重金招聘Python工程師標準>>> 關于K-Means介紹很多,還不清楚可以查一些相關資料。 個人對其實現步驟簡單總結為4步: 1.選出k值,隨機出k個起始質心點。 2.分別計算每個點和k個起始質點之間的距離,就近歸類。 3.最終中心點集可以劃分為…

在PowerShell中顯示高級進度條

如果你需要編寫一些PowerShell腳本,尤其在處理一些相對復雜的任務時,你可能希望添加進度條的功能,以便隨時可以了解進展情況。Write-Progress 這個命令可以幫助你完成簡單的需求,請參考官方文檔即可,但下圖一個示例&am…

當檢測到運動時如何自動打開門燈

If it’s dark out and someone comes to your door, you probably can’t see them unless your porch light is on. Furthermore, if a potential burglar approaches your front door, a motion light can help scare them away. 如果天黑了,有人進了您的門&…

分布式系統的那些事兒(六) - SOA架構體系

有十來天沒發文了,實在抱歉!最近忙著錄視頻,同時也做了個開源的后臺管理系統LeeCX,目前比較簡單,但是后續會把各類技術完善。具體可以點擊“原文鏈接”。 那么今天繼續說分布式系統的那些事。 我們現在動不動就講分布式…

rest_framework07:權限/頻率/過濾組件/排序/異常處理封裝Response對象

權限 寫一個類,繼承BasePermission,如果通過返回True,否則False 這里需要配合認證使用,否則沒有user_type屬性。 from rest_framework.permissions import BasePermissionclass UserPermission(BasePermission):def has_permis…

在阿里,我們如何管理測試環境

為什么80%的碼農都做不了架構師?>>> 作者:林帆(花名金戟),阿里巴巴研發效能部技術專家 相關閱讀:在阿里,我們如何管理代碼分支 前言 阿里的許多實踐看似簡單,背后卻蘊涵…