前言算法
關係型數據庫發展至今,細節上以作足文章,在尋求自身突破發展的過程當中,內存與分佈式數據庫是當下最流行的主題,這與性能及擴展性在大數據時代的需求交相輝映.SQL Server做爲傳統的數據庫也在最新發布版本SQL Server 2014中提供了新利器 SQL Server In-Memory OLTP(Hekaton),使得其在OLTP系統中的性能有了幾十倍甚至上百倍的性能提高,本篇文章爲你們探究一二.sql
大數據時代的數據如何組織應用?這恐怕衆口不一.但不能否認,關係型數據依舊是當下世界最有效的應用方式.做爲應用技術,也必將伴隨着應用的需求而不斷演化.信息爆炸對信息處理提出了更爲嚴苛的需求,單從傳統的OLTP系統來看,性能和擴展性即是應用者最爲關注的方面.假如應用者告訴你我須要當下數據庫訪問量100倍的計算資源,單純硬件?顯然新的技術應用呼之而出.數據庫
傳統關係型數據庫自誕生起自身不斷完善的同時也伴隨着硬件的飛速發展,性能提高上伴隨處理器神奇的摩爾定律,TPC-C,TPC-E等指標不斷提高,而隨着今年來處理器物理工藝接近極限,CPU的主頻速度幾乎再也不提高,這時計算機朝着多核方向進展,同時內存成本也在線性下降,再也不如此昂貴,目前內存的成本已經低於10$/GB. 而固態硬盤(SSD)的普遍應用也使得傳統數據庫在性能上有更多的延伸.面對這些新的硬件環境傳統的關係型數據庫天然也有其設計之初不可避免的自身性能瓶頸.安全
SQL Server 2014的傳統引擎中引入緩衝池擴展(Buffer Pool Extension)功能利用SSD的高IOPS做爲緩衝池的有利延伸,構成了熱,活,冷三層數據體系,有效緩解磁盤的壓力.咱們能夠把更多的數據放入內存,SSD中,但即使如此數據庫的性能仍是被自身的一些架構和處理方式所約束着. 就着前面的假設,咱們要把事務處理能力提高100倍.假設咱們如今的處理能力是100 TPS,而這時每一個事務因此得平均CPU指令爲100萬個,以此提高10倍1000 TPS,每一個事務的CPU指令就需降爲10萬個,而再提高10倍10000 TPS每一個事務的CPU指令就需降爲1萬個,這在現有的數據庫系統中是不可能實現的,因此咱們依舊須要新的處理方式.數據結構
傳統數據庫引擎面臨的問題 多線程
有的朋友可能會說把全部數據都放入內存中就是內存數據庫,就不存在短板了,但即使如此咱們仍面臨以下主要問題:架構
1:保護內存中的數據結構而採用的閂鎖(latch)引發的熱點 (hot spots) 問題.併發
2:使用鎖機制控制多版本併發帶來的阻塞等問題.app
3:使用解釋型(interpretation)語言的執行計劃的執行效率問題.分佈式
咱們簡單看下上述問題的由來
1:假設我有一個查詢Q1須要訪問一個數據頁 頁號7,此時數據頁不在Buffer Pool(BP)中,爲此係統爲其分配了內存架構,並去磁盤取相關數據頁置入BP中此過程正常大概10-20ms,而此時剛好另外一個查詢Q2需訪問數據頁號7,因爲BP中已經存在應該頁架構,若是此時容許Q2讀取,則Q2將會髒讀.所以引入閂鎖,當Q1去磁盤讀取數據時BP中的相應架構被閂鎖保護,Q2讀相應的頁時將被阻塞,知道Q1完成相應操做並釋放閂鎖,以下圖1-1所示
如今有數據庫系統中爲保證多線程下的共享數據一致性,內存任何數據結構都需被閂鎖保護.而當大量併發進程同時訪問一個數據頁(結構)就形成了熱點問題.消耗了大量CPU的同時影響了併發吞吐.
圖1-1
2:假設有以下兩個操做,都對數據庫中的某個值進行修改
A=1000
Q1: A = A + 100 Q2: A = A + 500
在數據庫中的操做爲
Q1: Read A, A=A+100, Write A
Q2: Read A, A=A+500, Write A
若是是串行前後執行,則沒有問題,但若是同時執行則能夠出現數據的不一致情形.
Q1,Q2同時讀取了A的原始值後,進行修改,則數據不一致如圖1-2
圖1-2
爲了解決此問題,已故的業界大神,圖靈獎的得到者Jim Gray提出了兩階段鎖概念 (Two-Phase Locking),合理地解決了併發一致性問題,並被絕大多數數據庫系統應用並改進(如SQL Server中數據不一樣粒度下併發兼容情形引入的意向鎖).
本例中當Q1讀取A時,對A加排他鎖,當Q2試圖讀取時就會被阻塞,需等待Q1的事務完成後釋放鎖資源後才能繼續讀取.如圖1-3
圖1-3
但也正由於鎖的引入,使得事務間可能出現相互阻塞,而且須要特定的進行管理鎖資源,且需對死鎖等問題即時檢測,而這些問題天然地會影響併發性能.
3:熟悉SQL Server的人都知道一條語句在SQL Server中執行,現有進行綁定,語義分析,基於成本的優化等一些列過程而後生成相應的解釋性語言執行計劃,而引擎在執行相應的執行計劃時會調用相應的數據庫函數,運行每個運算符,若是數據在硬盤上則會去硬盤上取數據…這些情形使得執行解釋性語言時高時間消耗的同時也打斷CPU流水,使得CPU的效率沒法充分發揮,而若是數據均在內存中,則能夠採用更高效的方式處理.而絕大多數關係型數據庫系統的執行計劃均爲解釋性語言.
面對這些問題,巨頭數據庫廠商們都提供了相應的內存數據庫解決方案,如Oracle的Timesten,還有最新圖靈獎得到者Michael Stonebraker教授的研究H-store演化出的商業產品VoltDB等.而微軟的SQL Server 2014也推出了內存數據庫SQL Server In-Memory OLTP(開發代號Hekaton),接下來咱們就簡要的看下Hekaton如何應對上面的問題,使得性能獲得新的昇華.
SQL Server Hekaton的應對方式
SQL Server Hekaton是一個基於內存優化的高性能的OLTP數據庫引擎,且數據是可持久化的,他徹底集成於SQL Server內(可與傳統引擎,基於列存儲引擎混合透明使用 如圖2-1),且是基於現代多核CPU架構設計.
圖2-1
應對上述三點性能瓶頸,熱點上Hekaton採用」Bw-tree」數據結構實現Latch-free,併發鎖上採用樂觀併發中多版本時間戳數據行控制實現無鎖事務,解釋性語言執行效率採用截執行計劃編譯爲機器代碼(DLL)提高CPU效率.下面針對這三點來簡要說明下.
Hekaton中的數據頁大小是彈性的,以便於增量更新Delta update,由於現有傳統的update in place會使得現有的CPU Cache失效,在多核架構下會使得性能受限.數據頁在內存中經過映射表管理,將每一個數據頁的邏輯ID與物理地址一一映射.如圖2-2
圖 2-2
在對數據進行更新時採用Compare and Swap(CAS)實現無鎖(Latch free)操做
CAS:經過比對物理地址的值與攜帶值是否匹配,匹配則可操做,不匹配則拒絕操做.
如某個進程在攜帶的地址M的值爲20,匹配地址M的實際值,若是爲20則能夠修改,不然拒絕如圖2-3
圖2-3
在對數據頁進行增量更新時每次操做均會在數據上生成一個新的增量地址做爲數據頁的訪問入口,並採用CAS完成映射表中(mapping table)物理新地址的映射(delta address),並對針對同一數據頁可能出現的同時更新進行仲裁,此時勝出者將進行更新,而失敗者能夠進行重試,遺憾的是目前SQL Server只會對失敗操做拋出錯誤信息,須要咱們本身捕捉錯誤信息並重試,具體可參考聯機文檔.具體如圖2-4所示
圖2-4
這樣的操做方式下,當更新鏈過長時訪問數據會形成時間複雜度提高從而影響性能,SQL server會在合適的情形下進行整理,生成新的數據頁,並將物理地址指向新的數據頁,而老的數據頁鏈表將會做爲垃圾回收釋放內存.如圖2-5
圖2-5
因爲數據頁是彈性的,因此可能形成數據頁過大或是過程,Hekaton中會在其認爲合適的情形下進行頁分裂或是合併.限於篇幅這裏就不在詳細敘述了,在實現Latch-free中全部內存中的操做都是經過一個或多個原子操做完成.感興趣的朋友能夠參考微軟的相關文獻.
有的朋友可能會說閂鎖自己是保護內存結構的輕量級鎖,何況不一樣類型的閂鎖可能兼容,Latch-free對性能幫助能有多大呢?實際SQL Server在訪問內存中數據時,閂鎖自己用做控制數據訪問時成本很高,爲此會在數據上加自旋鎖(Spin lock)供線程探測數據是否能夠訪問,Spin lock實現即一個Bit位(0或1),線程會一直探測內存中的這個Bit位以試圖得到自旋鎖,若是能夠訪問則訪問,不然自旋,若是幾千次的探測仍沒法訪問則停下」休息」這個稱做一次碰撞.可是在自旋的過程CPU負荷狀態,所以也就形成CPU資源白白浪費.生產中咱們可能看到CPU高啓,而併發卻上不去,訪問變慢,其中的一個緣由就是大量進程訪問熱點數據下大量自旋鎖徵用使得性能受限.而在Hekaton中無閂鎖的狀況下就不存在這樣問題,單從這個角度來看隨着線程的增長性能也是線性放大.固然除了Latch-free,其餘的兩個方面Hekaton一樣表現出色.
前文中敘述可知,關係型數據庫中事務是靠鎖來保證多版本併發控制的,由此帶來的阻塞死鎖等問題相信全部的DBA都印象深入.而Hekaton中採用樂觀併發下多版本數據加時間戳的形式實現.下面來簡要解下.
Hekaton中將一個事務分爲三個階段,正常事務處理步驟用於咱們的數據操做DML則建立新的版本行.驗證提交階段驗證這個事務是否能夠安全提交(根據版本數據).提交處理階段用於寫日誌,並將新的版本行數據對其它事務可見.如圖2-6
圖2-6
咱們經過一個實例簡要說明下:事務過程採用Timestamps(時間戳(全局時鐘))標記事務和行版本,每一個事務開始時賦予開始時間戳Begin_TS,用於讀取正確的行版本(數據行一樣均具備時間戳),行版本數據結束時間戳End_TS通常爲正無窮(+∞),當進行數據更新時建立新的版本行,並將舊的版本行End_TS修改成事務ID Xb(此處非時間戳),新的版本行的Begin_TS一樣標記爲事務ID (Xb).而後獲取事務的End_TS (惟一),確承認提交後,提交事務,並將新舊版本的事務ID(Xb)替換成獲取的End_TS.至此完成一次操做.未涉及任何鎖,閂鎖,阻塞.如圖2-7
圖2-7
有的同窗看到上圖可能回想,這樣Xa讀取的版本行是正確的嗎?他爲何不能讀到Xb的新行數據.咱們來簡單分析下
Xa開始時分配的時間戳爲25,Xb爲35,這就意味着Xb的結束時間戳必定大於35此時Xa讀取數據,時間戳範圍應爲Begin_TS-20, End_TS-+∞,而Xa的Begin_TS小於Xb的Begin_TS,因此讀取正確如圖2-8.
2-8
實際上Hekaton中規定 查詢的可見值區間必須覆蓋此查詢的開始時間戳好比一個查詢事務的開始時間戳爲30,他可見的行版本能夠包括10至+∞,20至150,但不能看到40至+∞
如圖2-9
圖2-9
有的同窗可能會想,隨着訪問,DML的增長,會累積大量的無用數據佔用內存,實際上根據查詢自身的事務時間戳,如上當最古老的事務開始時間戳大於等於50時,舊版本的數據就能夠安全的清除釋放內存了. 清除工做可使多線程並行執行,對新能影響很小.
從圖2-6中能夠看到,並非每一個事務均可以安全提交的,在驗證階段,Hekaton會根據用戶設定的隔離級別進行驗證.Hekaton爲樂觀併發,提供三種隔離級別的支持分別爲快照隔離級別(Snapshot Isolation),可重複讀隔離級別(Repeatable Reads Isolation)及序列化隔離級別(Serializable),這與傳統的關係型數據相似, Snapshot中是無需驗證的,而可重複則需在提交前再次驗證與事務開始時的數據是否一致,如一致則可提交,不然不可提交.而序列化中顧名思義讀取的區間數據都需一致,不然失敗.有同窗可能會想序列化中將匹配多少數據啊,成本是否是過高了,別忘了這是在內存中,依然比傳統的序列化成本要低不少.熟悉樂觀級別的同窗都知道,傳統的樂觀併發級別下回滾成本是很是高的,而Hekaton中採用驗證的方式有效的規避了這項成本.提交就是寫日誌記錄變化,並將數據行中事務ID替換成獲取的時間戳,對其餘事務可見.
固然提升寫日誌,咱們都知道磁盤終究是瓶頸,爲此Hekaton也有其特定的優化方式來緩解這個問題,限於篇幅這裏就不在敘述.並且針對一些特定的場景咱們能夠選擇只保留Schema而無需數據持久化(如遊戲的場景數據等).
最後,針對CPU執行效率將執行計劃由解釋性語言(Interpreted)替換爲機器語言(Native).
優化器能夠說是關係型數據庫最複雜的部分了,簡單說下SQL Server優化器處理過程:一條語句交給優化器會進行綁定解析,生成解析樹,而後進行語義分析生成邏輯執行計劃,最後優化器再爲邏輯執行計劃基於成本生成物理的執行計劃.而Hekaton中,若是咱們選擇Native方式執行(將所執行語句經過存儲過程特殊編譯),在生成邏輯執行計劃以後將會根據不一樣的算法,成本預估生成不一樣的物理執行計劃,而後將物理執行計劃轉譯成C語言代碼再經過編譯器將其編譯成DLL即機器代碼.如圖2-10
圖2-10
曾經微博上有朋友問爲何Mysql重構優化器時爲何要將parsing, optimizing, execution三個模塊分開而不是混在一塊兒了,我想這裏可能就找到答案了,一個優秀RDBMS它自身的健壯是多麼重要.
在Native下,全部的執行都是」Goto」,直接讀取數據,不再用一個一個的function的調用,極大提高CPU的工做效率.有人可能會問這樣每次都編譯將是很是大的工做成本,實際上Hekaton將指定查詢(存儲過程)編譯成DLL文件,只是在第一次將其載入內存就能夠了.對於即席查詢是不能夠的.
Hekaton在機器代碼下執行效率大幅提高,如下是微軟給出的測試數據
a. Interpreted與Native的對比,其中分爲是否爲內存優化表,查詢單條數據所消耗的CPU指令 如圖2-11
圖2-11
b.隨機查找1000萬數據普通表與Hekaton內存優化表查詢時間對比圖2-12
圖2-12
c. 普通表與Hekaton內存優化表內存中隨機更新數據對比,此時不寫日誌如圖2-13
圖2-13
Hekaton應用案例
Hekaton,古希臘語中表示百倍,雖然目前還未達到願景,我想這個出色的團隊必定可以作到.
SQL Server有了這個新利器,在應對性能問題上更加出色.在微軟的官方網站上有大量案例,這裏咱們列舉幾個.
Bwin,歐洲最大的在線博彩公司,採用Hekaton後,線上每秒批處理由15000提高到250000.
EdgeNet,硅谷著名的數據服務商,採用Hekaton後,線上入庫數據量由7450/s提高到126665/s
均由近17倍的速度提高如圖3-1
圖3-1
而將易車的惠買車的訪問量在Hekaton模擬運行時,各項性能指標都表現的很淡定.
如圖3-2
圖3-2
Hekaton不只爲咱們解決了很多場景下的性能問題,我想面對特定場景中的一些棘手問題也有必定的幫助.好比電商熱衷的秒殺/搶購.這裏筆者就不在敘述業內朋友研究的排隊論,批量提交等等辦法.實際上計算機在當下廣泛應用都是模擬三維空間內的人爲活動,試想下,搶購的過程終究有成功或是失敗,就好像你在搶購熱銷產品時被身手矯健的大媽推到一邊你沒搶到同樣,這不正好符合Hekaton中的事務機制?…咱們在設計網上產品活動的時候是否該想一想模擬到現實中是什麼樣子的?對此,我認爲咱們須要的是可控,而不是控制.
結語
最後,這麼多帶給人驚喜振奮的數據庫,他就天衣無縫嗎?固然不是.Hekaton的樂觀併發級別限定使得其並不適合大量更新衝突的場景,其以空間換速度的設計要求會消耗大量內存,須要應用者合理規劃設計…請牢記」任何術都是有缺陷的」 沒有哪項技術/架構時天衣無縫的,合適的場景選擇合理的技術/架構纔是咱們的初衷.
認爲有幫助的同窗請點贊