Microsoft Advertising是一個功能強大的廣告平臺,可幫助您將您的廣告精準投放給正確的客戶。在2019財年,搜索廣告收入為Microsoft帶來了76億美元的收入。自2015年以來,我們一直在使用Azure SQL,回顧過去真是令人難以置信:我們的可用性、性能、可伸縮性、可靠性和效率都得到了極大的提高。Azure SQL一直是Microsoft Advertising平臺賴以吸引我們數(shù)百萬客戶并完成數(shù)十億美元業(yè)務(wù)的基礎(chǔ)。在這篇博客中,我們將分享我們?nèi)绾卧贏zure上重新設(shè)計了我們的系統(tǒng),如何利用眾多令人興奮的Azure SQL功能,以及隨著Azure SQL的持續(xù)提供創(chuàng)新和卓越表現(xiàn),Microsoft Advertising平臺如何實現(xiàn)蓬勃發(fā)展。
我們把時間快速退回到5年前。那時候,我們在本地運行Microsoft Advertising系統(tǒng)。業(yè)務(wù)的高速增長導(dǎo)致數(shù)據(jù)呈爆炸式增長,每秒快速查詢量(QPS)增長并且業(yè)務(wù)需求日趨復(fù)雜。作為一個多租戶系統(tǒng),無論帳戶大小如何,我們都必須良好應(yīng)對。但本地數(shù)據(jù)庫系統(tǒng)無法進行擴展并滿足不斷增長的需求。最重要的是,大家都知道SAN存儲很難升級、維護和維修。運營成本不斷增加。
01重新構(gòu)建數(shù)據(jù)層架構(gòu)
我們意識到我們需要徹底改變架構(gòu)。我們的設(shè)計理念是將特定帳戶的數(shù)據(jù)分布到一組數(shù)據(jù)庫服務(wù)器上。這樣,數(shù)據(jù)的分布變得更加均勻,并且可以同時從多個數(shù)據(jù)庫中提取服務(wù)。我們看中了Azure SQL的功能、靈活性和可操作性,選擇了它作為我們的平臺。
使用Azure SQL,我們可以快速輕松地添加/刪除實例。它可以提供ACID事務(wù)處理,這對我們的應(yīng)用情形很重要。我們實施了水平分區(qū)以擴展數(shù)據(jù),這種技術(shù)稱為分片;對于特定的客戶,數(shù)據(jù)平均分布在N個分片上。在我們的實現(xiàn)中,這N個分片構(gòu)成了我們所謂的分片組。隨著每個分片組中數(shù)據(jù)量的增大或縮小,我們在現(xiàn)有分片組之間進行拆分或合并。我們的設(shè)計原則之一是,無論每個帳戶大小如何,都對其進行分片,并且代碼和分片邏輯之間沒有耦合,服務(wù)代碼假定數(shù)據(jù)庫可以N種方式分片。
ACID
https://en.wikipedia.org/wiki/ACID
分片
https://en.wikipedia.org/wiki/Shard_(database_architecture)
受Google F1設(shè)計的啟發(fā),我們將數(shù)據(jù)庫數(shù)據(jù)組織結(jié)構(gòu)更改為類似于下圖的層次結(jié)構(gòu).
Google F1
https://research.google/pubs/pub41344/
通過這種數(shù)據(jù)表示,屬于客戶的廣告組級別數(shù)據(jù)很可能會在物理存儲中被群集在一起。在我們的用例中,由于可以從磁盤上的一組連續(xù)頁面中檢索CustomerId的數(shù)據(jù)而無需聯(lián)接其他表,因此有意在子表中引入受控的冗余并復(fù)制子表中的關(guān)鍵列提高了我們的性能。因此,SQL需要從磁盤加載的頁面更少,從而獲得更好的性能。這種技術(shù)對我們非常有效,使我們能夠?qū)崿F(xiàn)延遲目標。
02重新構(gòu)建服務(wù)層架構(gòu)
由于數(shù)據(jù)層已經(jīng)發(fā)生了巨大的變化,數(shù)據(jù)現(xiàn)在已采用分布式形式,因此我們也必須大力改變服務(wù)層。
首要原則是在設(shè)計時要考慮橫向擴展。收到請求時,無論哪個服務(wù)器接收到該請求,都將成為該請求的主服務(wù)器。當主服務(wù)器估計增加的并行度將減少查詢處理延遲時,它將選擇分布式執(zhí)行而不是集中式執(zhí)行。在分布式執(zhí)行的情況下,它將請求分發(fā)給其對等方,等待響應(yīng),然后合并結(jié)果。然后將最終的合并結(jié)果發(fā)送給客戶。
我們還決定,業(yè)務(wù)邏輯應(yīng)盡可能駐留在服務(wù)中,而不是駐留在存儲層中。這種模式非常適合我們的大規(guī)模數(shù)據(jù)處理用例。對于我們的多租戶需要大量數(shù)據(jù)處理的方案,投擲大量便宜的機器來執(zhí)行業(yè)務(wù)邏輯和處理已證明是非常有益的。
最后,由于我們的服務(wù)需要同時連接到許多數(shù)據(jù)庫,因此我們與開發(fā)團隊制定了新的編程范例。我們構(gòu)建了負責處理SQL數(shù)據(jù)庫連接重用和生命周期管理的庫代碼。我們告訴開發(fā)人員避免串行讀取,使用批處理,使用IDataReader并行流式傳輸數(shù)據(jù)以僅進行正向處理(與使用DataSet和DataTable相對)。根據(jù)我們的經(jīng)驗,使用DataTable會降低性能,特別是在高吞吐量數(shù)據(jù)處理的情況下。因此,我們轉(zhuǎn)向構(gòu)建純內(nèi)存中的C#對象,而不是依靠DataTable進行內(nèi)存中聯(lián)接和數(shù)據(jù)處理。為了最大化性能,我們還避免使用任何對象關(guān)系映射(ORM)庫,而是編寫特定于場景的代碼(通常使用并行運行的任務(wù))來聯(lián)接和處理所有數(shù)據(jù)。我們在整個堆棧中使用async,以避免在等待I/O時出現(xiàn)不必要的線程池阻塞。
03利用Azure SQL的新功能
Azure SQL提供了許多很棒的功能,我們對此深表感謝。下面列舉其中幾個:
Columnstore幫助我們針對數(shù)據(jù)不經(jīng)常更改的分析和審計情形優(yōu)化存儲。使用Columnstore而不是Rowstore表可以幫助我們節(jié)省30%到40%的空間,并且由于采用了批處理操作模式而提高了性能。對存檔數(shù)據(jù)使用存檔壓縮使我們能夠節(jié)省另外30%的空間,而不會對性能產(chǎn)生明顯影響。
對于不適合使用Columnstore索引的表,頁面壓縮可幫助我們在應(yīng)用場景中省高達50%的空間,而不會帶來任何明顯的性能降級。
表分區(qū),將它與常規(guī)索引維護結(jié)合使用,可幫助我們控制空間消耗。
AlwaysOn可用性組、活動異地復(fù)制和長期備份保留(LTR)是非常好的保持業(yè)務(wù)連續(xù)性的功能。
DNS別名提供了一個轉(zhuǎn)換層,可以將客戶端應(yīng)用程序重定向到其他服務(wù)器。在災(zāi)難恢復(fù)應(yīng)用情形中,這非常方便。
DMV、XEvents和查詢存儲(QDS)可提供非常出色的性能故障排除功能。
Columnstore
https://docs.microsoft.com/sql/relational-databases/indexes/columnstore-indexes-overview
頁面壓縮
https://docs.microsoft.com/sql/relational-databases/data-compression/page-compression-implementation
表分區(qū)
https://docs.microsoft.com/sql/relational-databases/partitions/partitioned-tables-and-indexes
AlwaysOn可用性組
https://docs.microsoft.com/azure/sql-database/sql-database-high-availability
活動異地復(fù)制
https://docs.microsoft.com/en-us/azure/sql-database/sql-database-active-geo-replication
長期備份保留(LTR)
https://docs.microsoft.com/azure/sql-database/sql-database-long-term-retention
DNS別名
https://docs.microsoft.com/azure/sql-database/dns-alias-overview
DMV
https://docs.microsoft.com/azure/sql-database/sql-database-monitoring-with-dmvs
XEvents
https://docs.microsoft.com/azure/sql-database/sql-database-xevent-db-diff-from-svr
查詢存儲(QDS)
https://docs.microsoft.com/sql/relational-databases/performance/monitoring-performance-by-using-the-query-store
在Azure SQL上運行的Microsoft Advertising系統(tǒng)在支持客戶不斷增長的參與方面也表現(xiàn)良好。盡管這些年來負載顯著增加,但我們?nèi)匀贿_到并超過了性能SLA。我們的客戶對此十分滿意。我們并沒有就此止步,而是堅持不懈地致力于提高系統(tǒng)效率。Azure SQL具有很好的靈活性,在它上面花錢可以購買一些性能,但是我們認為從我們的代碼中提升性能比花大筆錢要有趣得多。那么,我們?nèi)绾沃Ц侗M可能少的費用卻又能獲得最高的性能呢?最好的技術(shù)就是改進我們的代碼使它變得更好,這樣即使在便宜的Azure SQL上運行速度也能足夠快。我們的系統(tǒng)從P11開始,然后降級到P6;現(xiàn)在,在我們對代碼進行了相當大的改進之后,我們在P4上運行OLTP系統(tǒng)。此外,我們使用以下方法來充分利用Azure SQL的所有強大功能。
04完全利用只讀副本
許多開發(fā)人員沒有意識到,一旦為高級/業(yè)務(wù)關(guān)鍵數(shù)據(jù)庫設(shè)置了單個異地副本,我們實際上就可以查詢四個數(shù)據(jù)庫副本—主數(shù)據(jù)庫、主數(shù)據(jù)庫的本地輔助數(shù)據(jù)庫、異地輔助主數(shù)據(jù)庫和異地輔助主數(shù)據(jù)庫的本地輔助數(shù)據(jù)庫。
Microsoft Advertising中的一種工作負載具有兩種不同的查詢模式:交互式UI調(diào)用(QPS低,但具有嚴格的延遲要求)和報告調(diào)用(對于大量數(shù)據(jù)而言QPS高,但是具有較低的延遲要求)。為了避免這兩種類型的調(diào)用相互干擾,我們曾經(jīng)還托管額外的副本,而事實證明這樣做的成本非常高。本地輔助功能被證明是可以“救命”的。我們設(shè)計了一種新方案:將通過UI進行的調(diào)用同時轉(zhuǎn)到兩個副本:主副本+異地輔助主副本,哪個先返回便使用哪個。報表調(diào)用也會同時轉(zhuǎn)到兩個副本:主本地輔助副本+異地輔助本地輔助副本,哪個先返回便使用哪個。這樣一來,我們將Azure SQL的這部分成本減少了一半。要注意的一件事是,有時主副本和輔助副本之間會存在復(fù)制延遲,因此請確保您的應(yīng)用場景可以容忍和處理這種延遲。
05定期清理數(shù)據(jù)以保持整潔
為了降低Azure SQL成本并確保出色的查詢性能,對于我們來說最重要的是開發(fā)一個穩(wěn)健的數(shù)據(jù)清理基礎(chǔ)架構(gòu),用于定期清理已刪除的實體和老舊審核數(shù)據(jù)。清理需要占用大量CPU和I/O,因為需要檢查所有表。通過大量的調(diào)整,我們現(xiàn)在已經(jīng)能夠優(yōu)化清理操作,使其對系統(tǒng)的影響減至最小。我們利用Azure SQL的彈性作業(yè)來清理數(shù)據(jù)。
06負載平衡
負載均衡器是一項基礎(chǔ)架構(gòu)功能,可幫助我們將數(shù)據(jù)均衡分布到各數(shù)據(jù)庫服務(wù)器。目的是消除熱點并分散客戶數(shù)據(jù),避免增長高峰。它以在線方式將客戶數(shù)據(jù)從繁忙的分片組移動到更空閑的分片組,此操作對客戶的影響非常小。僅當客戶活動低于閾值時才鎖定和切換分區(qū),從而將對客戶的影響減至最小。如果客戶仍在進行大量更改,則負載均衡器將退出并重試。它會持續(xù)運行,確保將我們的數(shù)據(jù)盡可能高效地打包。
07結(jié)論
Azure SQL是云中全托管SQL的最佳選擇。Microsoft Advertising非常高興在這個夢幻般的平臺上運行并實現(xiàn)蓬勃發(fā)展。目前,我們正在測試最新的炫酷技術(shù)—Hyperscale!它支持高達100 TB的存儲,近乎即時的數(shù)據(jù)庫備份,快速擴展等等。利用遷移到Hyperscale服務(wù)層的數(shù)據(jù)庫,我們已經(jīng)看到了顯著的性能改進。我們將很快完成其余數(shù)據(jù)庫的遷移。