您好,登錄后才能下訂單哦!
前言
關系型數據庫發展至今,細節上以做足文章,在尋求自身突破發展的過程中,內存與分布式數據庫是當下最流行的主題,這與性能及擴展性在大數據時代的需求交相輝映。
SQL Server作為傳統的數據庫也在最新發布版本SQL Server 2014中提供了新利器 SQL Server In-Memory OLTP(Hekaton),使得其在OLTP系統中的性能有了幾十倍甚至上百倍的性能提升,本篇文章為大家探究一二。
大數據時代的數據如何組織應用?這恐怕眾口不一。但不可否認,關系型數據依舊是當下世界最有效的應用方式。作為應用技術,也必將伴隨著應用的需求而不斷演化。
信息爆炸對信息處理提出了更為嚴苛的需求,單從傳統的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倍10000TPS每個事務的CPU指令就需降為1萬個,這在現有的數據庫系統中是不可能實現的,所以我們依舊需要新的處理方式。
一、傳統數據庫引擎面臨的問題
有的朋友可能會說把所有數據都放入內存中就是內存數據庫,就不存在短板了,但即便如此我們仍面臨如下主要問題:
1.保護內存中的數據結構而采用的閂鎖(latch)引起的熱點 (hot spots)問題。
2.使用鎖機制控制多版本并發帶來的阻塞等問題。
3.使用解釋型(interpretation)語言的執行計劃的執行效率問題。
我們簡單看下上述問題的由來
1.假設我有一個查詢Q1需要訪問一個數據頁 頁號7,此時數據頁不在BufferPool(BP)中,為此系統為其分配了內存架構,并去磁盤取相關數據頁置入BP中此過程正常大概10-20ms,而此時恰好另一個查詢Q2需訪問數據頁號7,由于BP中已經存在應該頁架構,如果此時允許Q2讀取,則Q2將會臟讀。
因此引入閂鎖,當Q1去磁盤讀取數據時BP中的相應架構被閂鎖保護,Q2讀相應的頁時將被阻塞,知道Q1完成相應操作并釋放閂鎖,如下圖1-1所示:
圖1-1
現在有數據庫系統中為保證多線程下的共享數據一致性,內存任何數據結構都需被閂鎖保護。而當大量并發進程同時訪問一個數據頁(結構)就造成了熱點問題。消耗了大量CPU的同時影響了并發吞吐。
2.假設有如下兩個操作,都對數據庫中的某個值進行修改:
A=1000
Q1:A = A + 100Q2: 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
為了解決此問題,已故的業界大神,圖靈獎的獲得者JimGray提出了兩階段鎖概念 (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:
圖2-1
應對上述三點性能瓶頸,熱點上Hekaton采用”Bw-tree”數據結構實現Latch-free,并發鎖上采用樂觀并發中多版本時間戳數據行控制實現無鎖事務,解釋性語言執行效率采用截執行計劃編譯為機器代碼(DLL)提升CPU效率。
下面針對這三點來簡要說明下。
Hekaton中的數據頁大小是彈性的,以便于增量更新Delta update,因為現有傳統的update in place會使得現有的CPU Cache失效,在多核架構下會使得性能受限。數據頁在內存中通過映射表管理,將每個數據頁的邏輯ID與物理地址一一映射。如圖2-2:
圖2-2
在對數據進行更新時采用Compareand 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),可重復讀隔離級別(RepeatableReads Isolation)及序列化隔離級別(Serializable),這與傳統的關系型數據類似,Snapshot中是無需驗證的,而可重復則需在提交前再次驗證與事務開始時的數據是否一致,如一致則可提交,否則不可提交。
而序列化中顧名思義讀取的區間數據都需一致,否則失敗。有同學可能會想序列化中將匹配多少數據啊,成本是不是太高了,別忘了這是在內存中,依然比傳統的序列化成本要低很多。
熟悉樂觀級別的同學都知道,傳統的樂觀并發級別下回滾成本是非常高的,而Hekaton中采用驗證的方式有效的規避了這項成本。提交就是寫日志記錄變化,并將數據行中事務ID替換成獲取的時間戳,對其他事務可見。
當然提高寫日志,我們都知道磁盤終究是瓶頸,為此Hekaton也有其特定的優化方式來緩解這個問題,限于篇幅這里就不在敘述。而且針對一些特定的場景我們可以選擇只保留Schema而無需數據持久化(如游戲的場景數據等)。
最后,針對CPU執行效率將執行計劃由解釋性語言(Interpreted)替換為機器語言(Native)。
優化器可以說是關系型數據庫最復雜的部分了,簡單說下SQLServer優化器處理過程:一條語句交給優化器會進行綁定解析,生成解析樹,然后進行語義分析生成邏輯執行計劃,最后優化器再為邏輯執行計劃基于成本生成物理的執行計劃。
而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的樂觀并發級別限定使得其并不適合大量更新沖突的場景,其以空間換速度的設計要求會消耗大量內存,需要應用者合理規劃設計……
請牢記“任何技術都是有缺陷的”,沒有哪項技術/架構是完美無缺的,合適的場景選擇合理的技術/架構才是我們的初衷。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。