微吼云上線多路互動直播服務 加速多場景互動直播落地
773
2025-04-01
愿打開此篇對你有所幫助。
@[toc]
本文部分是我曾經的手稿,今天在草稿箱里面發現,居然沒發出去。。。。。
部分是別的大佬的(下面那些實踐方案)。
高性能開發十大必須掌握的核心技術
我們循序漸進,從內存、磁盤I/O、網絡I/O、CPU、緩存、架構、算法等多層次遞進,串聯起高性能開發十大必須掌握的核心技術。
- I/O優化:零拷貝技術 - I/O優化:多路復用技術 - 線程池技術 - 無鎖編程技術 - 進程間通信技術 - RPC && 序列化技術 - 數據庫索引技術 - 緩存技術 && 布隆過濾器 - 全文搜索技術 - 負載均衡技術
I/O優化:零拷貝技術
從磁盤讀文件、再通過網絡發送數據,數據從磁盤到網絡,兜兜轉轉需要拷貝四次,其中CPU親自搬運都需要兩次。
最近在學習nginx的底層設計,正好有看到這個。后面可以在nginx系列里面補上這個。
零拷貝技術,解放CPU,文件數據直接從內核發送出去,無需再拷貝到應用程序緩沖區,白白浪費資源。
Linux API:
ssize_t sendfile( int out_fd, int in_fd, off_t *offset, size_t count );
函數名字已經把函數的功能解釋的很明顯了:發送文件。指定要發送的文件描述符和網絡套接字描述符,一個函數搞定!
I/O優化:多路復用技術
每個線程都要阻塞在recv等待對方的請求,這來訪問的人多了,線程開的就多了,大量線程都在阻塞,系統運轉速度也隨之下降。
這個時候,你需要多路復用技術,使用select模型,將所有等待(accept、recv)都放在主線程里,工作線程不需要再等待。
過了一段時間之后,網站訪問的人越來越多了,就連select也開始有點應接不暇,老板繼續讓你優化性能。
這個時候,你需要升級多路復用模型為epoll。
select有三弊,epoll有三優。
select底層采用數組來管理套接字描述符,同時管理的數量有上限,一般不超過幾千個,epoll使用樹和鏈表來管理,同時管理數量可以很大。 select不會告訴你到底哪個套接字來了消息,你需要一個個去詢問。epoll直接告訴你誰來了消息,不用輪詢。 select進行系統調用時還需要把套接字列表在用戶空間和內核空間來回拷貝,循環中調用select時簡直浪費。epoll統一在內核管理套接字描述符,無需來回拷貝。
用上了epoll多路復用技術,開發了3.0版本,你的網站能同時處理很多用戶請求了。
之前的方案中,工作線程總是用到才創建,用完就關閉,大量請求來的時候,線程不斷創建、關閉、創建、關閉,開銷挺大的。這個時候,你需要:
線程池技術
我們可以在程序一開始啟動后就批量啟動一波工作線程,而不是在有請求來的時候才去創建,使用一個公共的任務隊列,請求來臨時,向隊列中投遞任務,各個工作線程統一從隊列中不斷取出任務來處理,這就是線程池技術。
多線程技術的使用一定程度提升了服務器的并發能力,但同時,多個線程之間為了數據同步,常常需要使用互斥體、信號、條件變量等手段來同步多個線程。這些重量級的同步手段往往會導致線程在用戶態/內核態多次切換,系統調用,線程切換都是不小的開銷。
在線程池技術中,提到了一個公共的任務隊列,各個工作線程需要從中提取任務進行處理,這里就涉及到多個工作線程對這個公共隊列的同步操作。
有沒有一些輕量級的方案來實現多線程安全的訪問數據呢?這個時候,你需要:
無鎖編程技術
多線程并發編程中,遇到公共數據時就需要進行線程同步。而這里的同步又可以分為阻塞型同步和非阻塞型同步。
阻塞型同步好理解,我們常用的互斥體、信號、條件變量等這些操作系統提供的機制都屬于阻塞型同步,其本質都是要加“鎖”。
與之對應的非阻塞型同步就是在無鎖的情況下實現同步,目前有三類技術方案:
Wait-free Lock-free Obstruction-free
三類技術方案都是通過一定的算法和技術手段來實現不用阻塞等待而實現同步,這其中又以Lock-free最為應用廣泛。
Lock-free能夠廣泛應用得益于目前主流的CPU都提供了原子級別的read-modify-write原語,這就是著名的CAS(Compare-And-Swap)操作。在Intel x86系列處理器上,就是cmpxchg系列指令。
我們常常見到的無鎖隊列、無鎖鏈表、無鎖HashMap等數據結構,其無鎖的核心大都來源于此。在日常開發中,恰當的運用無鎖化編程技術,可以有效地降低多線程阻塞和切換帶來的額外開銷,提升性能。
服務器上線了一段時間,發現服務經常崩潰異常,排查發現是工作線程代碼bug,一崩潰整個服務都不可用了。于是你決定把工作線程和主線程拆開到不同的進程中,工作線程崩潰不能影響整體的服務。這個時候出現了多進程,你需要:
進程間通信技術
提起進程間通信,你能想到的是什么?
管道 命名管道 socket 消息隊列 信號 信號量 共享內存
以上各種進程間通信的方式詳細介紹和比較,推薦一篇文章再探進程間通信,這里不再贅述。
Scale-out(橫向拓展)
采用分布式部署的方式把流量分開,讓每個服務器都承擔一部分并發和流量。這也是我最喜歡的一種方法。
緩存
使用緩存來提高系統的性能。
為什么緩存可以大幅度提升系統的性能呢?
那肯定是要更普通磁盤進行對比的啊。我們來看看普通磁盤的速度:
普通磁盤的尋道時間是 10ms 左右,而相比于磁盤尋道花費的時間,CPU 執行指令和內存尋址的時間都在是 ns(納秒)級別,從千兆網卡上讀取數據的時間是在μs(微秒)級別。所以在整個計算機體系中,磁盤是最慢的一環,甚至比其它的組件要慢幾個數量級。因此,我們通常使用以內存作為存儲介質的緩存,以此提升性能。
至于緩存為什么快,因為它是內置的啊,在內存中。不過也有個缺點,就是燒內存。
異步
這是業務層面的異步。
內核層面的異步,需要調用內核指定的異步函數(aio族),不然,不論阻塞還是非阻塞都是同步。
高性能、高可用、高拓展 解決方案
以下實踐方案,有些我已經試過了,有些還沒體驗但是知道那么一回事兒,有些則不知道啥時候能實踐了。
? 高性能的實踐方案
1、集群部署,通過負載均衡減輕單機壓力。 2、多級緩存,包括靜態數據使用CDN、本地緩存、分布式緩存等,以及對緩存場景中的熱點key、緩存穿透、緩存并發、數據一致性等問題的處理。 3、分庫分表和索引優化,以及借助搜索引擎解決復雜查詢問題。 4、考慮NoSQL數據庫的使用,比如HBase、TiDB等,但是團隊必須熟悉這些組件,且有較強的運維能力。 5、異步化,將次要流程通過多線程、MQ、甚至延時任務進行異步處理。 6、限流,需要先考慮業務是否允許限流(比如秒殺場景是允許的),包括前端限流、Nginx接入層的限流、服務端的限流。 7、對流量進行削峰填谷,通過MQ承接流量。 8、并發處理,通過多線程將串行邏輯并行化。 9、預計算,比如搶紅包場景,可以提前計算好紅包金額緩存起來,發紅包時直接使用即可。 10、緩存預熱,通過異步任務提前預熱數據到本地緩存或者分布式緩存中。 11、減少IO次數,比如數據庫和緩存的批量讀寫、RPC的批量接口支持、或者通過冗余數據的方式干掉RPC調用。 12、減少IO時的數據包大小,包括采用輕量級的通信協議、合適的數據結構、去掉接口中的多余字段、減少緩存key的大小、壓縮緩存value等。 13、程序邏輯優化,比如將大概率阻斷執行流程的判斷邏輯前置、For循環的計算邏輯優化,或者采用更高效的算法。 14、各種池化技術的使用和池大小的設置,包括HTTP請求池、線程池(考慮CPU密集型還是IO密集型設置核心參數)、數據庫和Redis連接池等。 15、JVM優化,包括新生代和老年代的大小、GC算法的選擇等,盡可能減少GC頻率和耗時。 16、鎖選擇,讀多寫少的場景用樂觀鎖,或者考慮通過分段鎖的方式減少鎖沖突。
上述方案無外乎從計算和 IO 兩個維度考慮所有可能的優化點,需要有配套的監控系統實時了解當前的性能表現,并支撐你進行性能瓶頸分析,然后再遵循二八原則,抓主要矛盾進行優化。
? 高可用的實踐方案
1、對等節點的故障轉移,Nginx和服務治理框架均支持一個節點失敗后訪問另一個節點。 2、非對等節點的故障轉移,通過心跳檢測并實施主備切換(比如redis的哨兵模式或者集群模式、MySQL的主從切換等)。 3、接口層面的超時設置、重試策略和冪等設計。 4、降級處理:保證核心服務,犧牲非核心服務,必要時進行熔斷;或者核心鏈路出問題時,有備選鏈路。 5、限流處理:對超過系統處理能力的請求直接拒絕或者返回錯誤碼。 6、MQ場景的消息可靠性保證,包括producer端的重試機制、broker側的持久化、consumer端的ack機制等。 7、灰度發布,能支持按機器維度進行小流量部署,觀察系統日志和業務指標,等運行平穩后再推全量。 8、監控報警:全方位的監控體系,包括最基礎的CPU、內存、磁盤、網絡的監控,以及Web服務器、JVM、數據庫、各類中間件的監控和業務指標的監控。 9、災備演練:類似當前的“混沌工程”,對系統進行一些破壞性手段,觀察局部故障是否會引起可用性問題。
高可用的方案主要從冗余、取舍、系統運維3個方向考慮,同時需要有配套的值班機制和故障處理流程,當出現線上問題時,可及時跟進處理。
? 高擴展的實踐方案
1、合理的分層架構:比如上面談到的互聯網最常見的分層架構,另外還能進一步按照數據訪問層、業務邏輯層對微服務做更細粒度的分層 (但是需要評估性能,會存在網絡多一跳的情況)。 2、存儲層的拆分:按照業務維度做垂直拆分、按照數據特征維度進一步做水平拆分(分庫分表)。 3、業務層的拆分:最常見的是按照業務維度拆(比如電商場景的商品服務、訂單服務等), 也可以按照核心接口和非核心接口拆,還可以按照請求源拆(比如To C和To B,APP和H5)。
插播一條: 對吞吐量(TPS)、QPS、并發數、響應時間(RT)幾個概念做下了解
吞吐量
==吞吐量是指系統在單位時間內處理請求的數量==。對于無并發的應用系統而言,吞吐量與響應時間成嚴格的反比關系,實際上此時吞吐量就是響應時間的倒數。前面已經說過,對于單用戶的系統,響應時間(或者系統響應時間和應用延遲時間)可以很好地度量系統的性能,但對于并發系統,通常需要用吞吐量作為性能指標。
對于一個多用戶的系統,如果只有一個用戶使用時系統的平均響應時間是t,當有你n個用戶使用時,每個用戶看到的響應時間通常并不是n×t,而往往比n×t小很多(當然,在某些特殊情況下也可能比n×t大,甚至大很多)。這是因為處理每個請求需要用到很多資源,由于每個請求的處理過程中有許多步驟難以并發執行,這導致在具體的一個時間點,所占資源往往并不多。也就是說在處理單個請求時,在每個時間點都可能有許多資源被閑置,當處理多個請求時,如果資源配置合理,每個用戶看到的平均響應時間并不隨用戶數的增加而線性增加。實際上,不同系統的平均響應時間隨用戶數增加而增長的速度也不大相同,這也是采用吞吐量來度量并發系統的性能的主要原因。==一般而言,吞吐量是一個比較通用的指標==,兩個具有不同用戶數和用戶使用模式的系統,如果其最大吞吐量基本一致,則可以判斷兩個系統的處理能力基本一致。
QPS(每秒查詢率)
==每秒查詢率QPS是對一個特定的查詢服務器在規定時間內所處理流量多少的衡量標準==,在因特網上,作為域名系統服務器的機器的性能經常用每秒查詢率來衡量。對應fetches/sec,即每秒的響應請求數,也即是最大吞吐能力。
并發數
==并發用戶數是指系統可以同時承載的正常使用系統功能的用戶的數量==。與吞吐量相比,并發用戶數是一個更直觀但也更籠統的性能指標。實際上,并發用戶數是一個非常不準確的指標,因為用戶不同的使用模式會導致不同用戶在單位時間發出不同數量的請求。
響應時間
==響應時間是指系統對請求作出響應的時間==。直觀上看,這個指標與人對軟件性能的主觀感受是非常一致的,因為它完整地記錄了整個計算機系統處理請求的時間。由于一個系統通常會提供許多功能,而不同功能的處理邏輯也千差萬別,因而不同功能的響應時間也不盡相同,甚至同一功能在不同輸入數據的情況下響應時間也不相同。所以,在討論一個系統的響應時間時,人們通常是指該系統所有功能的平均時間或者所有功能的最大響應時間。當然,往往也需要對每個或每組功能討論其平均響應時間和最大響應時間。
需要指出的是,響應時間的絕對值并不能直接反映軟件的性能的高低,軟件性能的高低實際上取決于用戶對該響應時間的接受程度。對于一個游戲軟件來說,響應時間小于100毫秒應該是不錯的,響應時間在1秒左右可能屬于勉強可以接受,如果響應時間達到3秒就完全難以接受了。而對于編譯系統來說,完整編譯一個較大規模軟件的源代碼可能需要幾十分鐘甚至更長時間,但這些響應時間對于用戶來說都是可以接受的。
寫在最后,本篇核心
貪多嚼不爛,合適的才是最好的。
1、==最簡單的系統設計滿足業務需求和流量現狀,選擇最熟悉的技術體系==。
2、隨著流量的增加和業務的變化,修正架構中存在問題的點,如單點問題,橫向擴展問題,性能無法滿足需求的組件。
在這個過程中,選擇社區成熟的、團隊熟悉的組件幫助我們解決問題,在社區沒有合適解決方案的前提下才會自己造輪子。
3、當對架構的小修小補無法滿足需求時,考慮重構、重寫等大的調整方式以解決現有的問題。
任務調度 數據庫
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。