隨着用戶規模的增加,數據庫的壓力也在成倍增長。面對大流量、高併發,UCloud MongoDB 作到了高效,並展示出了更好的性能體驗。算法
—— 優志願 CTO 張海鵬數據庫
背景windows
每一年 6 月下旬到 8 月下旬期間是高考填志願的高峯期,也是優志願後端面臨大流量高併發請求的業務高峯期。優志願 APP 旨在爲 3000 萬高中生提供專業的自主招生、志願填報、留學、遊學等升學規劃服務,經過四年技術的不斷創新和研發,憑藉 「省控線差值法」 等專利級核心算法,目前已累計服務 400 多萬考生,實現錄取成功率高達 99.2%,最大浪費分僅 6 分的成績。而要爲如此多考生提供服務,面對上億條檢索依然穩定,並非簡單的事。後端
面臨的痛點服務器
優志願原先基於物理機自建的 MSSQL(Microsoft SQL Sever)數據庫,面對大流量高併發的業務高峯,暴露了如下問題:架構
1. 跟不上業務彈性擴容的節奏併發
自建 MSSQL 在作讀寫分離、AlwaysOn 配置、給每臺 windows 客戶端配置域名賬戶等操做時十分繁瑣,且隨着業務流量的增加須要不定時的增長服務器及應用配置,從硬件採購、機器部署到應用配置整個週期也較長。運維
2. 性能遭遇瓶頸,DBA 耗時耗力分佈式
另外,因爲優志願的業務場景主要是以查詢、索引操做爲主,讀寫比例大概 7:3,以前自建的 MSSQL 在數據達到千萬條時檢索速度大幅降低,須要及時更新索引目錄,不只影響考生的用戶體驗,且耗費大量的 DBA 人力成本。高併發
通過一番調研對比後,優志願選擇了使用 UCloud MongoDB 產品來解決以上問題。
爲何選擇 UCloud MongoDB?
UCloud MongoDB 是基於成熟雲計算技術的高可用、高性能的數據庫服務,無縫兼容開源的 MongoDB 版本;除了底層採用高可用主從架構外,還提供知足數據分片場景的配置節點和路由節點功能;同時提供災備、備份、監控等全套解決方案。
(圖:在 UCloud 控制檯 UDB 產品界面可選擇建立 MongoDB 實例)
●一鍵建立副本集實現讀寫分離
UCloud MongoDB 默認構建三節點的副本集:Primary 節點 + 一個 Secondary 節點 + 一個 Arbiter 節點構成。經過副本集中建立節點操做可支持擴展更多節點的副本集(例如:五節點、七節點或者更多個節點)。對於優志願讀多寫少的場景及其業務高峯期,用戶能夠按需增刪 Secondary 節點,更好地實現讀取性能的擴展。利用 UCloud MongoDB 副本集讀寫分離解決了大部分讀取的請求,即便數據到達上億條時檢索速度依然很快。副本集架構如圖所示:
![](user-gold-cdn.xitu.io/2019/8/23/1… =jpeg&s=18106) ●靈活高可用集羣架構
爲了解決隨着數據量增多而致使的性能瓶頸,MongoDB 還支持分片集羣,即多個分片能夠組成一個集羣對外提供服務。分片集羣(MongoDB3.4 及以上版本),由 Config Server 三副本 + N 個 Mongos +N 個 shard 數據分片構成,MongoDB 集羣設置好分片規則,經過 mongos 操做數據庫就能自動把對應的數據操做請求轉發到對應的分片機器上。MongoDB 採用 「分片」 可以快速搭建一個高可用可擴展的的分佈式集羣,具備大數據量、高擴展性、高性能、靈活數據模型、高可用性等特性。分片集羣架構如圖:
●彈性擴縮容更省成本
用戶依據業務實際流量能夠彈性擴展 MongoDB 資源,知足不一樣業務階段數據庫性能和存儲空間的需求。在業務高峯期可即時開通所需數據庫資源,無需在業務初期採購高成本硬件,從而有效減小硬件成本投入。在業務低峯期可隨時刪除釋放,避免數據庫資源的閒置浪費。正如優志願 CTO 張海鵬所說:「使用 UCloud MongoDB 數據庫後,運維成本節省了 80%,硬件採購成本減小 55%。」
查詢索引優化,打破性能瓶頸
卡頓現象
在今年高考前夕,優志願新版業務上線後業務出現小高峯的第一天,用戶反饋他們的 APP 登錄界面很是卡頓,經運維排查發現瓶頸出如今數據庫層,並邀請了 UCloud 雲數據庫團隊介入解決相關性能問題。
團隊首先查看了一些常見的會引發 MongoDB 出現卡頓的性能指標,發現大多數指標正常。隨着排查深刻進行,發現實例全局寫鎖的加鎖比例異常高。以下圖所示。
圖中加鎖百分比達到 100%,意味着全部全局寫操做所有卡住,大量的請求在排隊等待加鎖,性能急劇降低。
語句優化
UCloud 雲數據庫團隊針對當時用戶全部慢查詢的整體狀況,以及相關慢查詢的查詢計劃,並結合用戶的索引狀況進行了詳細分析。通過分析後,團隊首先發現用戶的相關表當中一些索引能夠優化,從而提高查詢的效率,所以爲用戶添加了相關的索引。在添加了索引以後,團隊結合監控指標,發現狀況有所改善,可是依舊沒有從根本上解決問題。
而後,團隊仔細分析了用戶耗時最長的典型查詢語句,並模擬執行查看執行計劃。在執行過程當中,團隊發現雖然相關集合已經加上了索引,可是用戶的查詢語句的執行計劃中並無使用最優的索引。進一步分析後,團隊發現用戶的最慢的語句基本都是 aggregate 操做,結合加鎖異常的性能指標,團隊仔細查看了用戶的具體 aggregate 的語句內容。最後發現耗時長的這些 aggregate 操做當中沒有用到分組功能 ($group)。這樣的話其實也能夠經過 MongoDB 最普通的 find 操做來達到一樣的效果。例如原語句:
db.this_collection.aggregate([ {match: { sort: {_id: -1}}, {limit: 1}]) 這條語句作的事情,實際上是在 this_collection 這個集合中,查找 UserId = 12345 而且 還知足 FieldA = 1 或者 FieldB = 2 的文檔記錄。查找到記錄以後,對全部結果的_id 進行倒序排列,而且拿出第一條結果。團隊用下面的 find 語句達到一樣的效果。改造後語句:
db.this_collection.find( { UserId: 12345, {$or: [{FieldA: 1}, {FieldB: 2}]} }).sort({_id: -1}).skip(0).limit(1) MongoDB 的 find () 進行了更加高程度的查詢優化,而且使用 find () 操做還有一個額外的好處,就是用戶能夠在 find () 最後接上 hint () 操做,能夠強制指定使用的索引,使查詢性能大幅提高。好比上面的例子中,若是在 this_collection 這個集合中,對 UserId 有索引,咱們能夠直接強制查詢使用這個索引。具體語句能夠變成:
db.this_collection.find( { UserId: 12345, {$or: [{FieldA: 1}, {FieldB: 2}]} }).sort({_id: -1}).skip(0).limit(1).hint({UserId: 1}) 團隊嘗試改造其中的一條典型耗時語句,而且在模擬環境中執行並查看改造後的執行計劃。結果驚喜地發現,即便在沒有使用 hint 操做的狀況下,find () 操做已經可以使用咱們認爲的最優索引了,通過改造後的查詢性能有了大幅的提高。
當天晚上,UCloud 雲數據庫團隊當即幫助用戶改造了他們最慢的查詢中全部能夠被改造的查詢語句,而且把改造建議同步給用戶。用戶的研發當晚收到改造建議後,緊急修改代碼併發布。
瓶頸解除
發佈後的次日,用戶經過監控界面,能夠看到慢查詢顯著減小,而且加鎖隊列顯著下降,數據庫的負載也明顯下降,整個系統能更高效的提供服務,改造後的監控圖以下:
![]( user-gold-cdn.xitu.io/2019/8/23/1… =jpeg&s=23332) 能夠看到,在改造以後,全局寫鎖的加鎖等待百分比大大減小,慢查詢也大大減小。改造取得了很是好的效果,用戶的 APP 後期再也沒有出現過 DB 層面的性能瓶頸。Prometheus 全方位實時監控及告警
爲了幫助用戶提供更實時的大盤監控,UCloud 在後臺搭建了一套 Prometheus 監控系統,將全部數據庫實例的關鍵性能指標全列出來,相比普通的監控平臺,藉助 Prometheus 能夠更清晰的看到全部數據庫實例當前的狀況,掌握數據庫當前的狀態,也能夠更好的發現數據庫的運行趨勢。
例如鏈接數狀況:
對於每個實例,提供更詳細的監控。例如 WTcache 的狀態: 加鎖的狀態: 監控系統和告警系統相結合,能夠在大於閥值時,直接告警出來,有利於問題的提早發現。藉助 UCloud 搭建的 Prometheus ,用戶無需自行搭建監控系統,也無需關心底層數據存儲、數據展現、系統運維等問題。寫在最後
UCloud 雲數據庫 UDB 自 2013 年正式商用後,一直緊跟開源社區的步伐,目前已經普遍支持業內主流的數據庫類型,除了 MongoDB, 還支持例如 MySQL、PostgreSQL 以及 SQLServer。在開源的基礎上,UCloud 數據庫團隊還自研了分佈式架構、讀寫分離、存儲計算分離等特性。同時,爲了更貼近用戶的使用場景,UCloud 數據庫團隊近期將推出 Cloud DBA 新產品,在控制檯提供 Prometheus 監控入口、界面管理巡檢和 SQL 分析等功能,以更加智能的方式提升 DBA 運維效率。