高併發葵花寶典

雪山飛豬發表於2020-04-20

前言

冰凍三尺非一日之寒,葵花寶典也不是一天寫出來的,系統設計也如此,好的架構是不斷演進的。

一般來說能用單塊架構解決的問題,儘量不要採用分散式。

分散式雖然可以提高系統的響應能力,也帶來了更高的複雜性,如果團隊技術人員水平hold不住的話,反而會產生更多問題,例如問題難以定位、系統效能下降、某種業務實現困難或無法實現等問題。

以下內容由偉大的詩人chenqionghe整理,light weight baby~

一、常用指標

響應時間

直觀反應系統快慢,一般控制在200ms以內,超過1s使用者已經能感覺到慢了

併發數

同時處理請求的數目

QPS

每秒查詢請求數

TPS

每秒執行事務數,著重反應寫

二、奪命三高

沒錯,就是高血壓、高血糖和高脂血,開玩笑啦~

高併發

通過設計讓系統能接收更多的使用者併發請求,承擔更大的流量。
一般考查併發數、QPS和TPS。


示例:廬山百龍霸,併發百龍

高效能

一般指服務響應時間快

  • 使用者視角。APP、瀏覽器上能直觀感受快
  • 開發視角。響應延遲低,系統吞吐量大,併發處理能力強
  • 運維視角。基礎設施配置高,CPU多核心,記憶體容量大


示例:雅典娜之驚歎,三位黃金聖鬥士將自身的究極小宇宙集中在一點進行攻擊

高可用

系統通過設計,減少停工時間,保持服務的高度可用性。
一般會用SLA協議衡量服務可用性,以達到幾個九做為標準
以一年為例,1年 = 365天 = 8760小時

  • 99.9 = 8760 * 0.1% = 8760 * 0.001 = 8.76小時
  • 99.99 = 8760 * 0.0001 = 0.876小時 = 0.876 * 60 = 52.6分鐘
  • 99.999 = 8760 * 0.00001 = 0.0876小時 = 0.0876 * 60 = 5.26分鐘
    SLA提供的可用性越高,那麼一年內停機的時間越小

示例:雅典娜之驚歎,分成不同的小組放招

三、常見招式

分流

本質就是將流量分攤到不同的節點,負載均衡。
常用方法有nginx、haproxy、traefik
舉例:星巴克開分店,增加營業員、擴大面積

快取


將熱點資料先快取起來,先從快取中獲取,提高效率
例如:Redis快取、Memcached快取、模板引擎快取、CPU快取
舉例:提供超市熱賣攤位,提高顧客購買效率;早餐店先提前把早餐做好,顧客來直接取

佇列

  • 提高響應速度。
    未處理完成前提前返回,提高響應速度,處理完後再發通知。

  • 系統解耦
    例如一個下單的資訊需要同步多個子系統,每個子系統都需要儲存訂單的資料的一部分,如果靠訂單服務的團隊維護所有子系統同步,耦合太大,這時候可以通過釋出訂閱模型,訂單服務在訂單變化時傳送一條訊息到一個主題中,所有的下游子系統都訂閱主題,這樣可以每個子系統都可以獲得訂單資料。

  • 緩衝流量,削峰填谷
    為了避免大量的請求衝擊後端服務,可以使用訊息佇列暫存請求,後端服務按照自己的處理能力,從佇列中消費,例如秒殺、埋點場景。

簡單地說,就是業務上游佇列緩衝限速傳送,業務下游佇列緩衝限速執行

秒條場景,一般處理兩種方式:
加鎖。比如golang包中的mutex,也可以利用redis本身操作原子性的特點
寫入訊息佇列。在訊息佇列中做減庫存的操作

舉例:去海盜蝦飯吃飯,先結賬,做好了給你端過來

CDN

CDN(Content Delivery Network)官方定義叫內容分發網路。
簡單的說就是一種快取,原理是將靜態的資源分發到多個地埋位置伺服器上,最終達到就近獲取資料的效果,例如北京地區訪問北京的資料,海南訪問海南的。
當然,這也不用我們自己開發,例如阿里雲、七牛雲等知名雲廠商都提供了CDN服務。
一般使用就是設定CDN回源更新資料的地址,將服務域名解析到雲廠商返回的CNAME上。

舉例:京東購買東西,發貨都直接從最近的倉庫發貨,只有倉庫沒貨了才會到源頭取貨(回源)

池化

一般連線的建立是比較耗資源和時間,一般我們可以使用連線池來提升效率,這就是傳說中的池化技術,常見的有資料庫連線池、執行緒池。
設定空閒連線數和最大連線數,步驟一般如下:

  1. 當前連線數小於空閒連線數,建立
  2. 連線池中有空閒連線直接使用
  3. 沒有空閒連線,當前連線數小於最大連線數,建立
  4. 達到或超過最大連線數,按設定超時時間等待舊連線釋放,超時丟擲錯誤

本質都是空間換時間,一般建立的連線物件會放到一個佇列中。

擴容

  • 垂直擴容
    升配置,例如加CPU核心、加記憶體、改為IO優化型儲存

    示例:倍化之術

  • 水平擴容
    直接加機器,多多益善

    示例:影分身之術

熔斷

當某服務呼叫的時候,如果返回錯誤或者超時次數超過一定閾值後,後續請求不再傳送直接返回錯誤
舉例:就像電路的熔斷器一樣,電流過載,自動斷開電路。
開源方案有:hystrix、traefik、istio

限流

通過限制到達系統的併發請求數量,保證系統能正常響應部分使用者的請求。超過限制的流量,通過拒絕服務的方式保證整體系統的可用性。
舉例:十一假期去莫高窟旅遊,景點只放出有限的門票,門票賣完,新來的客戶不再接待。
可以在系統中埋下限流的程式碼,例如可以使用golang的緩衝channel實現。

降級

就像被沙加剝奪了五感一樣

例如雙十一的時候,開啟淘寶,會發現介面上的資訊少了很多,其實這就是一種降級,關閉或者拒絕很多不重要的功能,節省伺服器資源抵禦高併發大流量。

分層

好處:分工明確,方便複用、容易針對層做擴充套件。
這個分層,可以指程式碼架構,也可以指服務架構,一般不跨層呼叫

  • MVC
    控制器(C)呼叫模型(M)取資料,再通過(V)渲染檢視。
    業務邏輯一般寫到模型中進行復用,但是可能會帶來的是模型之間的職責劃分不明確。
    所以一般還會在其中加入Service層,使Model模型不再存放業務邏輯。

  • Web、Service、Dao

    • Web:表現層。可以簡單理解成Controller和View
    • Service:業務邏輯層。業務邏輯都封裝到這一層,這一層直接呼叫Dao取資料
    • Dao:資料訪問層。負責訪問資料庫,最常見的是AR模型或者ORM

    可以簡單理解成MVC加了一層Service,Controller直接呼叫Service,Service再呼叫Model

  • Web、Service、Manager、Dao
    在Service和Dao之間加了一層Manager,抽取service層之間的共同邏輯。

部署分級

根據優先順序的高低將服務部署到不同的物理機上,可以通過K8S的label選擇最終部署的節點

日誌監控

  • 日誌追蹤。
    使用ELK或者阿里雲日誌服務。請求和打日誌傳遞requestId,查詢根據requestId檢索請求相關的所有日誌
  • 呼叫鏈追蹤.
    開源方案Zipkin,Jaeger 。核心是通過TranceId和SpanId追蹤每次呼叫
  • Prometheus監控
    把需要監控的指標儲存到prometheus中,通過grafanan展示
  • Sentry監控
    統一搜集採集異常日誌,針對500這種錯誤到sentry後臺查詢,比較方便定位問題

查詢優化

簡單地說是可以走索引,像射箭一樣直中目標

  • 優化sql索引。分析sql執行效率,通過加索引優化
  • 引入Elasticsearch。提高搜尋效率,降低模糊搜尋給資料庫帶來的壓力。

讀寫分離

將讀請求和寫請求分推到不同的例項,例如MySQL讀寫分離、Redis讀寫分離
MySQL主從分離核心是binlog,主庫將binlog寫入relay log檔案,從庫過來拉取。

主從同步容易遇到延遲問題,例如主庫已經寫入了,從庫查詢的還是老資料,一般會通過以下方式解決:

  1. 直接讀主庫
  2. 更新主庫前寫快取,讀快取
  3. 直接將更新的資料傳遞,不查庫

分庫分表

一般會配合服務一起拆分

  • 垂直拆分。
    專門的服務使用專門的庫。例如一個購買流程,可以拆分為商品庫、訂單庫。
  • 水平拆分。
    例如將users拆成10個庫,users0、users1...users9,根據某個欄位的取模存放到不同的庫。

缺點:

  • 無法做join
  • 統計數量是個問題
  • 不能再使用事務

相關文章