1. 程式人生 > >【乾貨】分散式記憶體資料庫新架構,極速OLTP應用新利器

【乾貨】分散式記憶體資料庫新架構,極速OLTP應用新利器

TimesTen Scaleout,它實際上是一款關係型資料庫,不過是在執行的期間,把資料全量載入到記憶體當中來進行實現。

【乾貨】分散式記憶體資料庫新架構,極速OLTP應用新利器

Oracle TimesTen

先簡單的說一下TimesTen Scaleout的歷史,它實際上是一款關係型資料庫,不過是在執行的期間,把資料全量載入到記憶體當中來進行實現。TimesTen從1998年開始在全球作為首款記憶體關係型資料庫上市,到現在已經過去了20年,這些年裡我們一直在做的一件事,縱向的提高它的效能。

因為大家都知道,從過去20年的發展歷程來看,硬體的資源本身容量越來越大,效能越來越好,價格越來越便宜。因此TimesTen為了應對硬體變更的需求,需要不斷提高縱向效能,隨之從單機的方式實現到過渡的分散式。

但是現在又有很多的新挑戰來臨了,現在很多的客戶不單單是要縱向的擴容,而且希望橫向的擴充套件。為了應對這個需求,我們提供了分散式的全新解決方案。我們強調同一款產品,兩種部署方式,也就是說你從網上下載的軟體,實際上就是一個安裝包。安裝包解壓縮之後,可以按照自己的需要以基於主備備的傳統的方式來實現縱向的擴容能力,也可以使用我們提供全新的分散式的方式來管理資料。

這兩者之間應對的方向是有區別的,單機的處理能力也非常好,而且對應用來說非常簡單。在主備這樣的傳統的部署方式下我們能提供一個超低延時的能力。但是如果要做分片、分佈,提高高併發的讀寫的能力,可能還需要引入網路。這種情況下,可以考慮在稍微犧牲網路延遲,以提高吞吐量。

TimesTen Classic核心技術

剛才強調了TimesTen是一款關係型資料庫,這裡可能需要重申一下什麼叫關係型資料庫。在分佈情況下,我們強調的是原子性一致性,隔離性和永續性。支援標準的SQL,同時整個資料庫執行在記憶體當中,可以通過應用程序嵌入式的訪問資料庫,來實現微秒級響應的能力。

我們知道常規的計算下,要求一個IO的響應時間是1/1000秒,相當於是微秒級。磁碟的響應式微秒級,那記憶體的響應其實是納秒級的。所以說在記憶體計算裡面,我們能做到微秒級的資料庫級別的響應,伴隨單位時間內的超高的吞吐量,這就是TimesTen過去20年一直在做的一個縱向的吞吐的能力。

作為企業級的產品,實際上TimesTen在中國已經有差不多十年的歷史,從07、08年開始中國的各大運營商都陸續地採用TimesTen作為計費的系統來控制餘額。類似這些服務在後臺,實際上使用的很多都是TimesTen的技術。他們在使用時候有持有化的要求,TimesTen同樣能夠很好的滿足。

此外我們對Oracle資料庫也有很好的相容性,包括對Oracle的資料型別,PL/以及豐OCI的介面都有良好的一個整合。同時對Oracle後臺的資料互動,也可以做到用快取方式部署的整合。

架構圖:Classic Instance

從18.1開始,我們的安裝方式發生了一點的變化,在分散式架構下,解壓縮即安裝。我們例項有別Oracle的例項,Oracle的例項是在記憶體中運算的一個程式,但是TimesTen裡面它相當於Oracle_home有一系列的可修改的軟體包,裡面包含一系列可執行檔案,同時有一組程序,這一組程序本身只支援一套或多套資料庫的。

【乾貨】分散式記憶體資料庫新架構,極速OLTP應用新利器

這是什麼意思呢?我們來看一下上圖,首先有這樣一個硬體環境,然後我們定義一個例項。在這個例項裡面,安裝解壓縮完之後,建立例項啟動了一個守護程序,它會拉起一個記憶體結構,記憶體結構就是TimesTen記憶體資料庫,這個資料庫會被subdaemon程序接管,subdaemon程序本身還會去做持久化的相關的維護,

資料庫構建起來之後要開放給應用連線,因此我們會有一個server的程序,類似於oracle的監聽程式。監聽程序開啟之後,可以做很多的應用訪問。如果說有高可用需求的話,也可以通過複製的代理程式去跟遠端的主備備程序做一個實時的複製。

對於oracle資料庫,我們還開放一個快取的能力,可以快取oracle資料庫裡面的熱點資料子集到TimesTen。這樣就能加速響應時間,並且減少了對oracle的負載壓力。

同時作為一個比較成熟的核心引擎,我們還支援的豐富的這監控管理工具,這是產品本身自帶的。對於微秒級響應的能力,實際上是建議將應用跟TimesTen部署在同一臺機器上,通過一個本地庫檔案的連結,它會將這個程序直接嵌入到TimesTen裡面進行訪問。這樣的話就完全去除了網路開銷,完全沒有網路只是記憶體對記憶體的一個指標變數的偏移巡視,所以效能會非常好。

應用連線

從應用角度來講,使用TimesTen可以使用直連的模式進行訪問,這個效能是最好的,只不過它需要將應用程式跟TimesTen部署在同一臺機器上。如果說有遠端的解耦的架構,可以部署在其他的主機上,裝TimesTen的客戶端,然後通過呼叫TimesTen的TCP/IP的方式去訪問資料庫,資料庫最後解析也會通過server變成一個直連到TimesTen本地。

應用開發

連線的介面也是非常豐富的,在過去20年的沉澱裡面,我們基本支援當前主流的所有的API的介面,基於oracle OCA的支援的能力,得以支援主流的 Python、nodeJs、Ruby、Go等程式語言的介面。

連線方式方面,為了哪些沒有使用過TimesTen的客戶,能力開放的相對標準。直連的話,可以通過修改JDBC,就像連線oracle一樣,將連線串指向TimesTen資料庫名就可以了。如果是cs的方式,只需客戶端去配置一個連線串,就可以連線了。

記憶體結構

【乾貨】分散式記憶體資料庫新架構,極速OLTP應用新利器

說到核心技術,先要談一談我們的記憶體資料庫的記憶體結構,記憶體結構本身在從TimesTen設計的第一天開始,就將資料全量載入到記憶體作為一個前提進行運算。所以我們在打造的時候,實際上是先有記憶體結構,再有磁碟的非同步映象。

我們在打造的時候,實際上先構建了一個DbHdr,用於存取資料庫的基礎資訊,然後有一個永久區域,這個永久區域是被持久化的。裡面包含的就是使用者真正關心的資料,以及系統中相對關鍵的一些原資料,包括表、索引。

這裡面強調一點,在記憶體裡邊,我們用的詞不是以block的方式儲存,而是以page的方式存儲存。在TimesTen記憶體結構裡面,頁的大小是不固定的,我們定義的是存取一個page,會存取256行的資料,行數是基於行儲存的技術,而行儲存技術本身取決column。

接下來就是一個臨時區域,裡面存放了大量的臨時的資訊,它是不被持久化的。比如說建的一些臨時表,臨時索引用來做編譯,有一些鎖的資源排序的資源,包括連線的一些基本資訊和我們快取的一些SQL命令,

最後就是作為關係資料庫,需要記錄DML的變化,TimesTen在這裡有一個log nuffer的區域,通過多軌的方式來進行記憶體當中的保留。所以說從應用角度來講的話,訪問任何資料在記憶體裡面只是做一個指標的偏移,返回給應用。

TimesTen是基於行的記憶體資料庫技術,這樣的記憶體技術,首先在作業系統層面上需要用huge的方式來鎖定住的內容結構,尤其是在linux市場,如果是大於256G的容量,從產品角度本身沒有一個設計的上線,共享記憶體段的大小,可以隨著作業系統硬體資源釋放出來的。但是需要在作業系統上配置一下,linux上的記憶體段預設限制是256G的。

此外在超大單機處理能力的情況下,還需要考慮NUMA的這樣的多核技術,比如說現在的作業系統,支援多槽位的cpu處理,這些槽位之間的CPU處理,在CPU級別的一級快取,二級快取之間,所存取的資訊是不被共享記憶體本身共享的。因此我們建議繫結4槽位cpu,以這樣的方式來避免NUMA的影響,繫結例項到對應的cpu的槽位。

持久化——檢查點

從企業角度來講,很多客戶都會關心一個問題,掉電了怎麼辦? 這裡就來講一講TimesTen是怎麼處理這個問題。

舉個例子,剛才都提到了TimesTen本身是通過檢查點的方式來做資料檔案的在磁碟上的存放,實際上這個檢查點是記憶體的一個實時映象,也就是說記憶體的快照。

接下來主要講的是在事務處理的變化過程中的刷出的機制,前面提到到了持久化的區域是DbHdr加永久區域,永久區域裡面的資料是按頁的方式來存取的,每個頁裡面儲存的是某個對應表裡面的256行中的部分行數的資訊。這些資訊有可能被修改, 在被修改的過程中,會發生什麼情況呢?

【乾貨】分散式記憶體資料庫新架構,極速OLTP應用新利器

假設T0時刻資料庫已經持久化了一次到ds1檔案上,在T1時刻我們發現有一些事物進來了,對page 0進行了修改,page 0裡面的資訊是ds1裡剛才沒有的一些髒資料。Page 2對 ds0來說也進行了修改,DS0還沒有被做下一次檢查點,所以說它在做檢查點之前,對於ds0來說page 2裡面是髒資料。

這個時刻我們發生了一個檢查點的觸發操作,預設是十分鐘,因為DbHdr有一些連線資訊,所以會被持久化。Page 2裡面的資訊由於是被標記成了髒資料,所以它是按頁的髒資料的方式去刷出到ds0的檔案裡面,這是一個增量刷出的過程,之後它之前被標記的髒資料就會被清除掉。

接下來在T3時刻我們又做了一些修改,髒字節也標記到對應的頁上了。之後我們會針對標記的頁進行檢查點的觸發。觸發的時候,我們會把對應的髒資料刷出到ds1檔案,他們是交替著寫,也就意味著在同一個時間點,極限場景下會有一個正在寫出的一個ds1,同時還有一個ds0,ds0配合事務日誌的方式,就可以實現恢復。

持久化——事物日誌

事務日誌在記憶體結構裡面是有一個log buffer區域,它是通過多軌的方式進行一個刷出,刷出是在作業系統檔案上承載了數日的檔案。檔案寫滿之後會增加,增加的大小是可配置的。

事務日誌的重新整理分為兩種,第一種是預設的非同步的重新整理,任何一個事務過來都會定期的觸發重新整理。刷出的過程是多條的效能最好的這樣方式。但是有些場景,比如說金融客戶有些關鍵的業務需要持久化到磁碟再返回給應用,這種情況下我們也支援同步的刷出。

非同步和同步之間是在資料庫級別進行了預設配置,你也可以在連線級別、事務級別,進行修改。

持久化——恢復

對於資料的載入我們有檢查點檔案,配合的事務日誌檔案在磁碟上,資料庫的重新載入需要讀取記憶體映象,如果是髒的checkpoint檔案,可以讀到連續的共享終端中,因為它是一個快照,所以說會直接把之前的結構在記憶體裡面做一個映象的回放。

構建到記憶體段之後的話,還可以基於日誌做事務的前滾和回滾,最後達到一個一致性的點,一直讀到事務日誌的最後收尾的標記,之後,該回滾的回滾。

在探測裡面如果說檢查點中沒有包含的資料發生了索引的改變,比如checkpoint的檢查點做完之後,又做了一些事務的變化,這個變化影響到了某些索引,索引再重新載入的時候,它是沒有被持久化的,需要被重建,重建的過程也是可以並行執行的。只有髒頁索引才會被重建,不是所有的索引都會被重建。之後仍然會把能力開放給應用進行正常的訪問。

併發能力

作為OLTP優化的關係型資料庫。我們也是又隔離機制的,通過Read committed的方式預設進行這樣的行為的,也就是說讀寫之間不互斥。

在讀寫的過程中,如果讀操作還沒讀取到目標前,目標就已經被寫入了,這時候寫的操作實際上會影射出來一個新的版本,這個版本本身是沒有被提交的,所以讀取的時候讀的是早期的版本,一旦目標被修改提交之後,後續發起的所有的讀取操作,讀取的資料就是修改過的資料。

同時TimesTen也支援隔離機制,採用線性隔離的方式,這種方式對會對單執行緒有很大的優化,但是對併發來,它會有很多的共享鎖排查鎖這樣的機制,所以要儘可能在高併發系統上避免隔離機制。

索引

資料庫事務處理的應用肯定需要修改資料庫,修改之後的資料查詢,就涉及到索引。TimesTen支援兩種主要型別的查詢,第一個查詢的方式是基於雜湊索引,這種方式對等值查詢的效能是最好,但是對範圍查詢來說不太適合。

缺點在於它需要維護一個雜湊連結串列,這個雜湊連結串列的估值是整個表全量值的一個超集,不能小於總行數。

另一種方式是我們預設的索引建立,它能夠很好的做範圍查詢,等值查詢的效能也不會特別差。更主要的是在高併發的維護情況下,這種新的索引模式對讀完全沒有鎖。對寫來說,由於B-tree索引是分節點的維護,減少了熱點徵用,以細粒度閂鎖的設計,來減少對整個b-tree鎖的對併發的影響。

TimesTen Scaleout

市場上有很多的客戶對分散式的強烈需求,同時客戶自己本身也在做各種的分片的一個嘗試來應對他們海量資料高併發的處理。

這種情況下,TimesTen進行了核心的改造,改造的量並不是特別大,我們引入了管理例項的概念。管理例項有點類似於剛才介紹的傳統模式,但是它裡面存放的東西只是元資料,實際的資料是放在資料例項裡面進行管理的。

【乾貨】分散式記憶體資料庫新架構,極速OLTP應用新利器

這個圖裡面唯一有一個變化的地方,僅僅是database變成了database Element。Element只是整個分散式叢集裡面的一個節點,裡面存放的只是N分之一的資料,資料是打散的。

為了解決分散式裡面的全域性一致性的問題,我們引入了一個叫Epoch的機制,它配合著全域性事務的概念,能夠做到在分散式裡面保證原子性。基於這個前提就可以做到分散式裡面的強一致性。

基於這樣的全新的架構基礎上,我們做了很多的封裝,在例項級別可以跟內部通道,跟其他的例項進行自動的內部的互動。

同時還引入了管理例項的概念,所以管理例項會直接跟TimesTen例項進行通訊,來做實時狀態的變更和叢集拓撲關係的變更。

這樣的能力使得我們可以實現在一個位置在管理例項上,一鍵安裝一鍵管理。對資料庫來說,不管是十個節點,20個節點,30個節點,只用在管理節點上執行一個命令進行配置,剩下的任務是由管理例項自動的去做,不需要登入到具體的資料例項進行配置。

High Availability

在企業級的需求裡邊,他們對TimesTen早期有一個很強的訴求,就是不用複製的方式幫實現高可用。

雖然TimesTen從引擎來講的話,原生支援複製,但是我們在分散式架構裡面做了很大的改造,讓它支援多副本的技術。在Aynchronous的架構下面,首先配置的主機,用Data Space Group來隔離物理位置, 之後在一對機房的兩個節點,可以分配成一個副本,這樣兩個副本就實時同步了。

在這個基礎上,我們整個資料庫是基於多個副本級的方式來呈現給這個應用的。副本集現在支援的是兩副本,後續會支援三副本。

基於之前介紹的核心的原理,我們的例項級別和資料庫級別有持久化能力,這些能力開放到分散式裡面,就是一個個的節點,叫做Element。Element有自己的持久化,存放的資料是一小部分的資料單元,並且有能力接受應用的訪問,這就意味著所有的節點,即使在高可用的方式下,都是全讀全寫的能力開放給應用。

內部因為我們要做一致性的OLTP的應用訪問,所以是基於優化的兩階段提交,來實現事務的強一致性。

TimesTen Scaleout Architecture Overview

【乾貨】分散式記憶體資料庫新架構,極速OLTP應用新利器

TimesTen的軟體安裝,需要先準備zookeeper。它是作為輕量級的成員管理的角色來管理例項之間的行為。我們建議使用內外網的架構,當然我們也支援單網絡卡,不過單網絡卡的吞吐量會混雜內部事務和外部的應用連線。因此還是建議使用雙網絡卡,做兩個內網和外網的隔離。之後可以選一個節點作為的管理節點,管理節點本身在生產環境上,可以使用高可用的方式進行儲備,這都是自動可以配置的。

之後選擇一個拓普關係,建立資料例項的屬性,一旦配置好之後就可以在管理實力上進行一鍵的安裝配置把資料庫拉起來。

如果需要一鍵日誌收集或者一鍵的備份,可以配一個資料庫。通過管理節點的命令了,來實現整個的自動化的管理。

對於圖形化管理,可以使用SQL DEVELOPER工具,通過SSh的方式連到管理例項上進行管理。

效能小貼士通用篇

首先講一下普世性的優化貼士,比如在使用記憶體技術的時候,我們需要儘可能節省你的記憶體空間,所以建議在TimesTen裡面使用原生的欄位。對於變長的欄位合理使用Inline和out of line。

作為關係資料庫的肯定要做到合理使用的索引,通過我們的索引指南來選擇是使用雜湊哈斯範圍索引,同時還需要更新優化器的統計資訊,因為TimesTen本身也是基於成本的優化器,對於SQL來說的也需要做好正常的資料量變更之後的更新同資訊的收集,讓資料庫真實的執行計劃能夠反映資料的實際情況。

最後就是資料庫本身的配置,包括基於目標負載和硬體等優化資料庫引數,使用HDD儲存需要將檢查點檔案和事務日誌檔案隔離I/O,避免I/O爭用,使用huge pages,無法使用的情況下,則考慮在記憶體中鎖定資料庫。

Scaleout篇

在分散式裡面首先引入的是網路,我們建議是使用萬兆網進行內部的配置。儘可能的是選擇大容量的主機要好於低配的小組機,因為你有更少的網路開銷,能夠充分發揮的縱向的併發的能力。

優化方面,對於表的分佈,如果是超大表的解決方案,可能要考慮用雜湊的分佈打散。

在分散式中,TimesTen還追加了全域性索引和本地索引的概念。在分佈鍵選擇的時候可以選擇某一個主鍵,或者是任何的組合鍵,作為雜湊分佈的分佈鍵。

應用篇

在應用開發角度我們也有一定的優化建議的。比如說使用引數化的SQL,而不是用硬寫的方式將絕對的查詢值寫到SQL的變數中。而且我們建議在每一次發起連線的時候做一個parse,這樣生成的執行計劃就避免了硬解析和軟解析,甚至會複用它的執行計劃到其他的連線,由此效能方面會減少很多的不必要的開銷。

有時候SQL中還會涉及隱含的資料型別或者字符集的轉換,如果能的避免的話,也可以減少不必要的開銷。

同時剛才強調了TimesTen裡面的記憶體結構是以256行作為一個page存放。所以從插入批處理的角度來講,我們可以以256行的倍數進行批處理,這樣的話能夠充分利用它page的能力,減少行插入的效能損耗。

適用場景

如果低延遲需求,比如要求的響應時間在一毫秒,或者是幾毫秒這樣非常苛刻的場景下,我們建議使用TimesTen傳統的方式進行部署, 這樣即使在單機的情況下也能達到每秒千萬級的查詢能力。我們的主備備方式,可以實現縱向的企業的能力的擴充套件。在橫向能實現讀的能力的擴充套件。

如果有oracle資料庫做加速,可以通過read-only或者read-write-caching的方式進行配置,將oracle的熱點資料子集載入到TimesTen當中進行運算,資料的同步是由快取的代理和複製代理來實現。

如果說在亞毫秒級或者是十毫秒以上容忍度的情況下,對高併發有上億次的TS需求。TimesTen現在極限的場景測試能達到10億每秒的查詢能力。

所以說這種分散式的架構裡面響應時間不是他的優勢,但是在多節點同步的高併發處理上,他有絕對的讀寫擴充套件的能力,這是需要大家綜合考量的點。