融云展位現(xiàn)場溝通
18日上午,融云首席架構(gòu)師李淼為大家分享了《超大規(guī)模即時通訊系統(tǒng)性能優(yōu)化探索及實踐》主題演講,就龐大復雜的系統(tǒng)性能問題該如何定位、分析以及工具排查;高并發(fā)系統(tǒng)的技術要點、難點、重點把控及措施、技巧;特定場景下系統(tǒng)性能問題優(yōu)化可行性解決方案等內(nèi)容進入深度解析。雖然臨近午飯時間,但大量的技術干貨及精彩的案例分享,讓現(xiàn)場一度爆滿,很多嘉賓即使站著也一直堅持聽完整場演講;即便會議結(jié)束,還有很多人與李淼進一步交流。
融云首席架構(gòu)師李淼演講
火爆的演講現(xiàn)場
會議結(jié)束后參會嘉賓與李淼繼續(xù)溝通
以下為演講實錄摘要,希望在適用場景下,對開發(fā)者有所脾益。
各位好,臨近中午了,感謝還有這么多同學和我一起分享。今天的主題是超大規(guī)模即時通訊系統(tǒng)性能優(yōu)化探索及實踐,介紹即時通訊模式下性能優(yōu)化如何完成。通過今天介紹的模型,大家如果有所得的話可以在系統(tǒng)當中做一些應用實踐。
性能問題定位及關注點
首先說性能問題的關注點,對于程序首先最直觀的關注點就是程序的響應時長。前提是響應包括你的應答必須是正確的,如果說性能優(yōu)化完成之后結(jié)果不正確,那可以說整個優(yōu)化失敗。
除了程序響應時長以外我們還會關注系統(tǒng)、數(shù)據(jù)存儲以及數(shù)據(jù)通訊。系統(tǒng)有一些直觀指標可以衡量系統(tǒng)的健康性和系統(tǒng)性能。先說CPU,我們主要關注CPU的負載及使用率;接下來是內(nèi)存,內(nèi)存主要關注正常的內(nèi)存利用率,是否使用了虛擬內(nèi)存,以及內(nèi)存碎片問題;I/O問題則關注磁盤和網(wǎng)絡I/O問題,I/O是整個系統(tǒng)優(yōu)化過程中特別需要關注的點,I/O如果做的好,對于整個平臺的性能提升幫助是最大的,有可能會比前面的CPU和內(nèi)存還要大。
數(shù)據(jù)存儲方面,在即時通訊保證消息可靠性的情況下,優(yōu)先進行消息存儲,通過這種方式保證消息不丟失、不亂序、不重復。對于數(shù)據(jù)存儲而言,其實和I/O有點類似,對于一般的業(yè)務來講,如果數(shù)據(jù)存儲優(yōu)化的好,平臺優(yōu)化方面就完成了60%左右的工作。
一般做系統(tǒng)時都會遇到網(wǎng)絡相關問題,這就會涉及到網(wǎng)絡通訊問題,怎么想辦法降低你的數(shù)據(jù)傳輸量,或者說降低你和網(wǎng)絡之間的交互次數(shù),也是數(shù)據(jù)通訊里面需要完成的一個優(yōu)化。
下面通過三個階段介紹一下融云關于性能問題的定位。第一個階段融云剛剛成立,那個時候性能問題的定位主要是通過系統(tǒng)監(jiān)控,配合著系統(tǒng)日志以及診斷工具,主要監(jiān)控服務器里面的CPU、內(nèi)存及I/O指標。
對于監(jiān)控來講,我們有一個類似業(yè)務監(jiān)控系統(tǒng),定時對每個節(jié)點進行相關性的單元測試,以此來衡量當前服務的健康狀況,以及每個系統(tǒng)的響應速度。當線上出現(xiàn)了系統(tǒng)告警時,配合日志來查看業(yè)務是否正常。
第二個階段,我們嘗試過用一些開源的APM工具。在整個系統(tǒng)當中通訊模型是基于Actor模型做的,所以沒辦法整個構(gòu)建服務監(jiān)控網(wǎng)絡,只能看一些相關數(shù)據(jù)。但在座各位如果開發(fā)系統(tǒng),用APM是一個非常好的工具,可以幫助你進行服務治理,系統(tǒng)監(jiān)控相關的工作,同時APM也有很多商業(yè)解決方案。
第三個階段,我們在對APM調(diào)研以及試用出現(xiàn)問題之后,只能想辦法自研Monitor監(jiān)控系統(tǒng),我們會記錄每個信令的調(diào)用時間和調(diào)用鏈路,后臺有一個數(shù)據(jù)分析平臺,我們查看一些信令前一天和今天的比值,看是不是有幅度變化;同時我們也會配合業(yè)務數(shù)據(jù)量觀測數(shù)據(jù)。一旦某個信令出現(xiàn)異常,我們就會進行線上的服務排查。
實際上對于性能問題的定位來講,第一個階段是最有效的,后面的手段都是輔助研發(fā)人員對于線上問題的定位,這些都是相輔相成的:你判斷問題、定位問題需要工具,工具也可以提高你判斷問題、定位問題的速度。
高并發(fā)系統(tǒng)技術要點
對于高并發(fā)系統(tǒng)來講,其實技術要點很多,我羅列了四條:異步通訊、緩存策略、數(shù)據(jù)結(jié)構(gòu)及算法、數(shù)據(jù)存儲。對于性能優(yōu)化來講,這四點僅僅是一部分,但如果把這四點做好,平臺就能得到一個很大的提升。
首先是異步通訊,對于現(xiàn)在的分布式系統(tǒng)來講,都需要對服務進行拆分,服務拆分以后我們需要通過一種方式將服務串聯(lián)起來,現(xiàn)在有很多開源的解決方案或框架,但是對于RPC來講,一般都是同步調(diào)用,有點類似于訪問數(shù)據(jù)庫,當前的工作線程需要等待調(diào)用端反饋結(jié)果。
如果說某個服務的響應時長十毫秒,對于調(diào)用端來講就需要等待十毫秒,為了解決這個問題,現(xiàn)在很多RPC都支持異步RPC的方式,通過回調(diào)的方式解決同步RPC工作線程占用以及等待的問題。
最后一個是Actor模型,Actor模型實際上在整個軟件系統(tǒng)上是一個屬于多線程數(shù)據(jù)協(xié)調(diào)的模型。所有的請求以及返回結(jié)果會以消息的方式進行傳遞,融云也是使用了Actor模式作為服務間調(diào)用。
第二個是緩存策略,我們對于數(shù)據(jù)分為四層:首先是原始數(shù)據(jù),這個數(shù)據(jù)是保存在數(shù)據(jù)庫里面的;第二個是分布式緩存,對于很多無狀態(tài)的服務而言,性能優(yōu)化大部分依賴于分布式緩存來完成;第三個為了對數(shù)據(jù)訪問進行加速,可能會使用一些本地進程內(nèi)緩存,由于沒有網(wǎng)絡訪問,同時直接的內(nèi)存訪問速度更快,所以本地緩存策略也會作為服務加速的方式;最后就是客戶端緩存了,現(xiàn)在無論是App開發(fā),PC客戶開發(fā)都可以使用用戶側(cè)的數(shù)據(jù)存儲,Web上的H5也可以使用類似local storage解決方案,但是一旦使用了客戶端存儲,我們就需要設計一個健壯的數(shù)據(jù)同步模型。刨除客戶端緩存的問題,為了盡可能達到使熱數(shù)據(jù)離用戶近一些這個目的,我們就需要想盡一切辦法提高緩存的命中率。
第三個是數(shù)據(jù)結(jié)構(gòu)及算法,適合場景的高效數(shù)據(jù)結(jié)構(gòu),首先我們要明確一個事情,適合的場景一定要對整個系統(tǒng)以及業(yè)務有充分的了解,根據(jù)這個方式再選擇合適的數(shù)據(jù)結(jié)構(gòu)。有的時候我們需要在時間復雜度和空間復雜度之間做權(quán)衡,什么時候拿空間換時間,什么時候拿時間換空間。另外就是算法,在開發(fā)過程當中,一定要明確算法的時間復雜度。由于系統(tǒng)里的需求,你需要提高算法復雜度,這個時候開發(fā)人員要和產(chǎn)品人員進行協(xié)調(diào)溝通。算法復雜度太高時,就要想辦法優(yōu)化業(yè)務,甚至說優(yōu)化場景。
第四數(shù)據(jù)存儲,我們依然要提場景的問題。對于一般系統(tǒng)開發(fā)來講,一個關系型數(shù)據(jù)庫基本上就可以滿足業(yè)務需求開發(fā)了,但實際上如果僅僅通過關系型數(shù)據(jù)庫來做的話,即使能滿足業(yè)務需求也不一定可以滿足性能需求。所以說要熟知你的業(yè)務場景,根據(jù)業(yè)務場景選擇合適的數(shù)據(jù)存儲。除此之外,還需要了解這些存儲的原理。
性能優(yōu)化案例
下面分享一下融云做的優(yōu)化案例,融云系統(tǒng)上線過程當中沒有出現(xiàn)太多的性能問題,實際上我們更多處理的是線上的BUG,或者說由于一些低級失誤產(chǎn)生的故障。
首先第一個案例,字典樹在我們優(yōu)化之后變成了雙數(shù)組字典樹,場景主要應用于敏感詞過濾。當時我們字典樹的實現(xiàn)都是以哈希多叉樹來做的,有幾個考慮:第一,敏感詞添加過程當中不需要字典樹重建,另外算法復雜度很低。有次通過監(jiān)控,我們發(fā)了線上用于審核的系統(tǒng)出現(xiàn)了一些性能問題,排查后發(fā)現(xiàn)有大量用戶錄入了很多業(yè)務上的關鍵敏感詞,這時我們將哈希樹調(diào)整為了雙數(shù)組字典樹,場景我們也做了一些優(yōu)化,敏感詞讓用戶進行批量添加,防止每次都會重構(gòu)。另外就是延遲,我們降低了字典樹重構(gòu)的時間。最后,對于審核服務來講,優(yōu)化效果直接將CPU的使用率降低了30%。
另外一個就是跳表,轉(zhuǎn)換成環(huán)形隊列,場景是做一些消息存儲。消息有一個時間遞增的特性,每個消息都會有一個時間遞增的方式,用于跳表方式來講復雜度很低,同時可以進行定向掃描,但是由于我們需要做內(nèi)存保護,要對跳表進行流量控制,插入的過程當中需要對老數(shù)據(jù)進行淘汰,這時就需要一個特別大的鎖把內(nèi)存鎖住,保證線程安全和防止內(nèi)存溢出。但由于業(yè)務量不斷增大,我們換了一個思路,使用環(huán)形隊列,主要底線實現(xiàn)都是以數(shù)組的方式組織,同時改變之前對于消息的定位模式。之前是通過一個用戶請求的時間點開始往后獲取最新數(shù)據(jù),改變模式之后我們通過最新的數(shù)據(jù)往前進行迭代,查到時間點為止,通過這樣的方式整個降低了占用時間,同時針對這塊業(yè)務吞吐量大概提高了百分之百。
性能優(yōu)化案例內(nèi)存優(yōu)化篇。這個場景對于key縮短問題,對于系統(tǒng)當中的用戶ID本身來講長度不可控。我們通過一個哈希算法轉(zhuǎn)變進制,變成64進制,這樣對于超過22個字節(jié)的數(shù)據(jù)進行壓縮,最終優(yōu)化效果把內(nèi)存的利用率降低了大概10%。
第二個內(nèi)存優(yōu)化主要是LRU緩存優(yōu)化,如果有大量冷數(shù)據(jù)訪問到系統(tǒng)中之后,會把熱數(shù)據(jù)沖掉,這對于系統(tǒng)的吞吐量有很大影響。我們優(yōu)化的方式是做了一個二級LRU緩存,將冷熱數(shù)據(jù)按照配比進行隔離,冷數(shù)據(jù)40%,熱數(shù)據(jù)60%,這樣系統(tǒng)里熱數(shù)據(jù)被淘汰的問題便得以緩解了。
性能優(yōu)化案例。數(shù)據(jù)狀態(tài)的延遲寫入,這個場景中消息里會記錄每個用戶的狀態(tài)。如果用戶收了一千條消息,數(shù)據(jù)就要被寫入一千次,我們通過另外一種模式,消息狀態(tài)數(shù)據(jù)一直是在本地內(nèi)存當中進行寫入,待多次寫入直到數(shù)據(jù)不活躍后,我們才將數(shù)據(jù)寫入真實的存儲里。通過這種優(yōu)化,將之前的多次數(shù)據(jù)寫入變成了一次數(shù)據(jù)寫入。
之前監(jiān)控數(shù)據(jù)每天有幾千億次需要存儲和寫入,通過添加緩存區(qū),讓將監(jiān)控數(shù)據(jù)傳輸量降低了兩個數(shù)量級。
數(shù)據(jù)存儲。首先對于消息來講,他的寫入和讀取場景是比較特殊,通過自研的存儲引擎,將存儲的設備降低了一半的數(shù)據(jù)量,同時保證了整個系統(tǒng)的響應速度。另外,調(diào)整了數(shù)據(jù)庫的業(yè)務引擎,對于業(yè)務數(shù)據(jù)占用磁盤比較高的問題,優(yōu)化之后的結(jié)果大概只有之前的30%左右,即存儲降低了70%。
系統(tǒng)設計把控
系統(tǒng)設計把控是一個總結(jié)性的內(nèi)容,對于性能優(yōu)化來講首先應該關注的是系統(tǒng)設計,需要充分理解你的需求以及業(yè)務場景,根據(jù)業(yè)務場景來設計你的整個系統(tǒng),系統(tǒng)設計完成之后,我們要開始進行架構(gòu)設計,現(xiàn)在很多人做架構(gòu)分享,例如現(xiàn)在比較火的微服務。但是這些架構(gòu)設計大家不要拿過來直接引用,需要充分的消化,通過架構(gòu)設計帶入系統(tǒng)設計,進行整個架構(gòu)的演進和迭代。
另外,技術選型需要充分考慮團隊對技術的接受能力,同時一定要對每個你所選東西的原理有充分認識,這樣的話才能做出一個比較好的選擇。
最后是程序?qū)崿F(xiàn),是在開發(fā)過程當中要不停進行迭代、改進和分享。技術沒有好壞之分,只有適合你的場景才是最好的。謝謝大家!