1. 程式人生 > 實用技巧 >高併發解決方案

高併發解決方案

一、高併發和大流量解決方案

高併發架構相關概念
  併發:在作業系統中,是指一個時間段中有幾個程式都處於已啟動執行到執行完畢之間,且這幾個程式都是在同一個處理機上執行,但任一個時刻點上只有一個程式在處理機上執行;在網際網路時代,所講的併發,高併發通常是指併發訪問,也就是在某個時間點,有多少個訪問同時到來。通常一個系統的日PV在千萬以上,有可能是一個高併發的系統。有的公司完全不走技術路線,全靠機器堆,這不在討論範圍內。
  QPS:每秒鐘請求或者查詢的數量,在網際網路領域,指每秒響應請求數(指HTTP請求);併發連線數是系統同時處理的請求數量
  吞吐量:單位時間內處理的請求數量(通常由QPS與併發數決定)
  響應時間

:從請求發出到收到響應花費的時間。例如系統處理一個HTTP請求需要100ms。
  PV:綜合瀏覽量(pageview),即頁面瀏覽量或者點選量,一個訪客在24小時內訪問的頁面數量;同一個人瀏覽網站同一頁面,只記作一次PV
  UV:獨立訪客(uniquevisitor),即一定時間範圍內相同訪客多次訪問網站,只計算為一個獨立訪客
  頻寬:計算頻寬大小需關注兩個指標,峰值流量和頁面的平均大小
  日網站頻寬=PV/統計時間(換算到s)*平均頁面大小(單位KB)*8;峰值一般是平均值的倍數,根據實際情況來定
  峰值每秒請求數(QPS)=(總PV數*80%)/(6小時秒數*20%);80%的訪問量集中在20%的時間
  壓力測試
:測試能承受的最大併發,測試最大承受的QPS值
  常用效能測試工具:ab,wrk,http_load,web_bench,siege,apachejmeter;ab全稱是apachebenchmark,apache官方推出的工具,建立多個併發訪問執行緒,模擬多個訪問者同時對某一trl地址進行訪問,它的測試目標是基於url的,因此既可以用來測試apache的負載能力,也可以測試nginx,lighthttp,tomcat,IIS等其它web伺服器的壓力;ab的使用:模擬併發請求100次,總共請求5000次,ab -c 100 -n 5000待測試網站;測試機器與被測試機器分開,不要對線上服務做壓力測試,觀察測試工具ab所在機器,以及被測試的前端機的CPU,記憶體,網路等都不超過最高限度的75%

高併發解決方案案例  

流量優化:防盜鏈處理
前端優化:減少HTTP請求,合併css或js,新增非同步請求,啟用瀏覽器快取和檔案壓縮,CDN加速,建立獨立圖片伺服器,
服務端優化:頁面靜態化,併發處理,佇列處理
資料庫優化:資料庫快取,分庫分表,分割槽操作,讀寫分離,負載均衡
web伺服器優化:負載均衡,nginx反向代理,7,4層LVS軟體

二、web資源防盜鏈

盜鏈在自己的頁面上展示一些並不在自己伺服器上的內容,獲得他人伺服器上的資源地址,繞過別人的資源展示頁面,直接在自己的頁面上向終端使用者提供此內容,常見的是小站盜用大站的圖片,音樂,視訊,軟體等資源,通過盜鏈的方法可以減輕自己伺服器的負擔,因為真實的空間和流量均是來自別人的伺服器

防盜鏈:防止別人通過一些技術手段繞過本站的資源展示頁面,盜用本站的資源,讓繞開本站資源展示頁面的資源連結失效,可以大大減輕伺服器及頻寬的壓力

工作原理:通過請求頭中的referer或者簽名,網站可以檢測目標網頁訪問的來源網頁,如果是資原始檔,則可以跟蹤到顯示它的網頁地址,一旦檢測到來源不是本站即進行阻止或者返回制定的頁面,通過計算簽名的方式,判斷請求是否合法,如果合法則顯示,否則返回錯誤資訊

實現方法:referer:nginx模組ngx_http_referer_module用於阻擋來源非法的域名請求,nginx指令valid_referers none | blocked | server_names | string...,none表示referer來源頭部為空的情況,blocked表示referer來源頭部不為空,但是裡面的值被代理或者防火牆刪除了,這些值都不以http://或者https://開頭,server_names表示referer來源頭部包含當前的server_names,全域性變數$invalid_referer。不能徹底防範,只能提高門檻。也可以針對目錄進行防盜鏈。

傳統防盜鏈遇到的問題:偽造referer:可以使用加密簽名解決

加密簽名:使用第三方模組HttpAccessKeyModule實現Nginx防盜鏈。accesskeyon|off模組開關,accesskey_hashmethodmd5|sha-1簽名加密方式,accesskey_arg GET引數名稱,accesskey_signature加密規則,在nginx的conf中設定

三、減少HTTP請求次數

效能黃金法則:只有10%-20%的終端使用者響應時間花在接收請求的HTML文件上,剩下的80%-90%時間花在HTML文件所引用的所有元件(img,script,css,flash等)進行的HTTP請求上。

如何改善:改善響應時間的最簡單途徑就是減少元件的數量,並由此減少HTTP請求的數量

HTTP連線產生的開銷:域名解析--TCP連線--傳送請求--等待--下載資源--解析時間

減少HTTP請求的方式:

1、圖片地圖:允許在一個圖片上關聯多個URL,目標URL的選擇取決於使用者單擊了圖片上的哪個位置,以位置資訊定位超連結,把HTTP請求減少為一個,可以保證設計的完整性和功能的齊全性,使用maparea標籤;

<img usemap="#map" src="/map.gif?t=111">
<map name="map">
    <area shape="rect" coords="0,0,30,30" href=... title="">
    ...       
</map>

2、CSS Sprites:CSS精靈,通過使用合併圖片,通過指定css的background-image和background-position來顯示元素。圖片地圖與css精靈的響應時間基本上相同,但比使用各自獨立圖片的方式要快50%以上。

3、合併指令碼和樣式表:使用外部的js和css檔案引用的方式,因為這要比直接寫在頁面中效能要更好一點;獨立的一個js比用多個js檔案組成的頁面載入要快38%;把多個指令碼合併為一個指令碼,把多個樣式表合併為一個樣式表

4、圖片使用base64編碼減少頁面請求數:採用base64的編碼方式將圖片直接嵌入到網頁中,而不是從外部載入

四、瀏覽器快取和資料壓縮優化

HTTP快取機制:如果請求成功會有三種情況:

1、 200fromcache:直接從本地快取中獲取相應,最快速,最省流量,因為根本沒有向伺服器進行請求;

2、 304notmodified:協商快取,瀏覽器在本地沒有命中的情況下請求頭中傳送一定的校驗資料到服務端,如果服務端資料沒有改變瀏覽器從本地快取響應,返回304,快速,傳送的資料很少,只返回一些基本的響應頭資訊,資料量很小,不傳送實際響應體;

3、 200 OK:以上兩種快取全部失敗,伺服器返回完整響應,沒有用到快取,相對最慢。

快取策略的選擇:

適合快取的內容:不變的影象,如logo,圖示等,js,css靜態檔案,可下載的內容,媒體檔案;

建議使用協商快取:html檔案,經常替換的圖片,經常修改的js,css檔案,js和css檔案的載入可以加入檔案的簽名來拒絕快取,如a.css?簽名或a.簽名.js;

不建議快取的內容:使用者隱私等敏感資料,經常改變的api資料介面

nginx配置快取策略:  

本地快取配置:add_header指令:新增狀態碼為2xx和3xx的響應頭資訊,add_headernamevalue [always];,可以設定Pragma/Expires/Cache-Control,可以繼承;expires指令:通知瀏覽器過期時長,expirestime;,為負值時表示Cache-Control: no-cache;,當為正或者0時,就表示Cache-Control: max-age=指定的時間;;當為max時,Cache-Control設定到10年;
協商快取相關配置:Etag指令:指定簽名;etagon|off;,預設是on

前端程式碼和資源的壓縮:

讓資原始檔更小,加快檔案在網路中的傳輸,讓網頁更快的展現,降低頻寬和流量開銷;壓縮方式:js,css,圖片,html程式碼的壓縮,Gzip壓縮

js程式碼壓縮:一般是去掉多餘的空格和回車,替換長變數名,簡化一些程式碼寫法等,程式碼壓縮工具很多UglifyJS(壓縮,語法檢查,美化程式碼,程式碼縮減,轉化)、YUI Compressor(來自yahoo,只有壓縮功能)、Closure Compiler(來自google,功能和UglifyJS類似,壓縮的方式不一樣),有線上工具tool.css-js.com,應用程式,編輯器外掛。

css程式碼壓縮:原理和js壓縮原理類似,同樣是去除空白符,註釋並且優化一些css語義規則等,壓縮工具CSS Compressor(可以選擇模式)。

html程式碼壓縮:不建議使用程式碼壓縮,有時會破壞程式碼結構,可以使用Gzip壓縮,當然也可以使用htmlcompressor工具,不過轉換後一定要檢查程式碼結構。

img壓縮:一般圖片在web系統的比重都比較大,壓縮工具:tinypng,JpegMini,ImageOptim。

Gzip壓縮:配置nginx服務,gzipon|off,gzip_buffers 32 4K|16 8K #緩衝(在記憶體中快取幾塊?每塊多大),gzip_comp_level [1-9] #推薦6壓縮級別(級別越高,壓的越小,越浪費CPU計算資源),gzip_disable #正則匹配UA什麼樣的uri不進行gzip,gzip_min_length 200 #開始壓縮的最小長度,gzip_http_version 1.0|1.1 #開始壓縮的http協議版本,gzip_proxied #設定請求者代理伺服器,該如何快取內容,gzip_typestext/plain applocation/xml #對哪些型別的檔案用壓縮,gzip_vary on|off #是否傳輸gzip壓縮標誌。其他工具:自動化構建工具Grunt。

五、CDN加速

CDN:Content Delivery Network,內容分發網路,儘可能避開網際網路上有可能影響資料傳輸速度和穩定性的瓶頸和環節,使內容傳輸的更快更穩定;在網路各處放置節點伺服器所構成的在現有的網際網路基礎之上的一層智慧虛擬網路;CDN系統能夠實時的根據網路流量和各節點的連線,負載情況以及到使用者的距離和響應時間等綜合資訊將使用者的請求重新導向離使用者最近的服務節點上

CDN的工作原理

  • 傳統訪問:使用者在瀏覽器輸入域名發起請求--解析域名獲取伺服器IP地址--根據IP地址找到對應的伺服器--伺服器響應並返回資料;
  • 使用CDN訪問:使用者發起請求--智慧DNS的解析(根據IP判斷地理位置,接入網型別,選擇路由最短和負載最輕的伺服器)--取得快取伺服器IP--把內容返回給使用者(如果快取中有)--向源站發起請求--將結果返回給使用者--將結果存入快取伺服器

CDN適用場景:站點或者應用中大量靜態資源的加速分發,如css,js,img和html;大檔案下載;直播網站等

CDN的實現:BAT等都有提供CDN服務,可用LVS做4層負載均衡;可用nginx,Varnish,Squid,Apache TrafficServer做7層負載均衡和cache;使用squid反向代理,或者nginx等的反向代理

六、建立獨立的圖片伺服器

獨立的必要性:分擔web伺服器的I/O負載-將耗費資源的圖片服務分離出來,提高伺服器的效能和穩定性;能夠專門的圖片伺服器進行優化-為圖片服務設定有針對性的快取方案,減少頻寬成本,提高訪問速度;提高網站的可擴充套件性-通過增加圖片伺服器,提高圖片吞吐能力

採用獨立域名:原因:同一域名下瀏覽器的併發連線數有限制,突破瀏覽器連線數的限制;由於cookie的原因,對快取不利,大部分webcache都只快取不帶cookie的請求,導致每次的圖片請求都不能命中cache

獨立後的問題:如何進行圖片上傳和圖片同步:NFS共享方式;利用FTP同步

七、動態語言靜態化

將現有PHP等動態語言的邏輯程式碼生成為靜態HTML檔案使用者訪問動態指令碼重定向到靜態HTML檔案的過程對實時性要求不高的頁面比較適合

原因:動態指令碼通常會做邏輯計算和資料查詢,訪問量越大,伺服器壓力越大;訪問量大時可能會造成CPU負載過高,資料庫伺服器壓力過大;靜態化可以降低邏輯處理壓力,降低資料庫伺服器查詢壓力

靜態化的實現方式:

1.使用模板引擎:可以使用smarty的快取機制生成靜態HTML快取檔案;

2.利用ob系列的函式:ob_start():開啟輸出控制緩衝,ob_ge_contents():返回輸出緩衝區內容,ob_clean():清空輸出緩衝區,ob_end_flush():沖刷出(送出)輸出緩衝區內容並關閉緩衝,可以判斷檔案的inode修改時間,判斷是否過期使用filectime函式

八、動態語言層的併發處理

程序&執行緒&協程&多執行緒等(具體看這裡https://www.cnblogs.com/sunny0824/p/13699056.html

九、資料庫快取層的優化

mysql等一些常見的關係型資料庫的資料都儲存在磁碟當中,在高併發場景下,業務應用對mysql產生的增刪改查的操作造成的巨大的IO開銷和查詢壓力,這無疑對資料庫和伺服器都是一種巨大的壓力。

為了解決此類問題,快取資料的概念應運而生。極大的解決資料庫伺服器的壓力,提高應用資料的響應速度。常見的快取形式:記憶體快取檔案快取

快取資料是為了讓客戶端很少甚至不訪問資料庫伺服器進行資料的查詢,高併發下,能最大程度的降低對資料庫伺服器的訪問壓力。預設情況下:使用者請求->資料查詢->連線資料庫伺服器並查詢資料->將資料快取起來(html,記憶體,json,序列化資料)->顯示給客戶端;使用者再次請求或者新使用者訪問->資料查詢->直接從快取中獲取資料->顯示給客戶端

mysql的查詢快取:query_cache_type:查詢快取型別,有0,1,2三個取值,0則不使用查詢快取,1表示始終使用查詢快取,2表示按需使用查詢快取。

方法memcache 與redis

1. 使用memcache快取查詢資料

memcache工作原理:是一個高效能的分散式的記憶體物件快取系統,通過在記憶體裡維護一個統一的巨大的hash表,能夠用來儲存各種格式的資料,包括影象,視訊,檔案以及資料庫檢索的結果等,簡單的說就是將資料呼叫到記憶體,然後從記憶體中讀取,從而大大提高讀取速度。

memcache工作流程:先檢查客戶端的請求資料是否在memcache中,如有,直接把請求資料返回,不再對資料庫進行任何操作;如果請求的資料不在memcache中,就去查資料庫,把從資料庫中獲取的資料返回給客戶端,同時把資料快取一份到memcache中。

memcache方法:獲取:get(key)設定:set(key, val, expire)刪除:delete(key)

2. 使用redis快取查詢資料:

與memcache的區別

  • 效能相差不大,redis在2.0版本後增加了自己的VM特性,突破實體記憶體的限制,memcache可以修改最大可用記憶體,採用LRU演算法;
  • redis依賴客戶端來實現分散式讀寫,memcache本身沒有資料冗餘機制;
  • redis支援快照,AOF,依賴快照進行持久化,aof增強了可靠性的同時,對效能有所影響,memcache不支援持久化,通常做快取,提升效能;
  • memcache在併發場景下,用cas保證一致性,redis事務支援比較弱,只能保證事務中的每個操作連續執行;
  • redis支援多種類的資料型別;redis用於資料量較小的高效能操作和運算上,memcache用於在動態系統中減少資料庫負載,提升效能,適合做快取,提高效能

十、mysql資料庫層的優化

優化方向:資料表資料型別優化索引優化sql語句優化儲存引擎的優化資料表結構設計的優化資料庫伺服器架構的優化

  • 資料表資料型別優化:欄位使用什麼樣的資料型別更合適,效能更快,tinyint、smallint、bigint,考慮空間和範圍的問題;char、varchar,儲存字串長度是否固定;enum,特定固定的分類可以使用enum儲存,效率更快;IP地址的儲存,ip2long(),使用整型儲存IP地址
  • 索引的優化:建立合適的索引,索引在什麼場景下效率最高,索引的建立原則:不是越多越好,在合適的欄位上建立合適的索引,複合索引的字首原則,like查詢%的問題,全表掃描優化,or條件索引使用情況,字串型別索引失效的問題
  • sql語句的優化:優化查詢過程中的資料訪問,優化長難句、特定型別的查詢語句。使用limit,返回列不用*,變複雜為簡單,切分查詢,分解關聯查詢,優化count(),優化關聯查詢,優化子查詢,優化groupby和distinct,優化limit和union
  • 儲存引擎的優化:儘量使用innoDB儲存引擎
  • 資料表結構設計的優化:分割槽操作,通過特定的策略對資料表進行物理拆分,對使用者透明,partitionby;分庫分表,水平拆分,垂直拆分
  • 資料庫架構的優化:主從複製,讀寫分離,雙主熱備,binlog日誌,中繼日誌,主從庫binlog的交換,事件傳輸;負載均衡,通過LVS的三種基本模式實現負載均衡,mycat資料庫中介軟體實現負載均衡

十一、 web伺服器的負載均衡

七層負載均衡的實現:

基於URL等應用層資訊的負載均衡,nginxproxy是它一個很強大的功能,實現了7層負載均衡,功能強大,效能卓越,執行穩定,配置簡單靈活,能夠自動剔除工作不正常的後端伺服器,上傳檔案使用非同步模式,支援多種分配策略,可以分配權重,分配方式靈活。

nginx負載均衡內建策略IP Hash,加權輪詢擴充套件策略fair策略,通用hash,一致性hash

加權輪詢:首先將請求都分給高權重的機器,直到該機器的權值降到了比其他機器低,才開始將請求分給下一個高權重的機器,當所有後端機器都down掉時,nginx會立即將所有機器的標誌位清成初始狀態,以避免造成所有的機器都處在timeout的狀態;

IP Hash:流程和輪詢很類似,只是其中的演算法和具體的策略有些變化,演算法是一種變相的輪詢演算法;

fair:根據後端伺服器的響應時間判斷負載情況,從中選出負載最輕的機器進行分流;

通用hash,一致性hash:通用hash比較簡單,可以以nginx內建的變數為key進行hash,一致性hash採用了nginx內建的一致性hash環,支援memcache

nginx配置:

http {
    upstream cluster{
        #ip_hash;
        server srv1 weight=1;
        server srv2;
        server srv3;
    } 
    server {
        listen 80;
        location / {
            proxy_pass http://cluster;
        }
    }   
}  

四層負載均衡的實現:

通過報文中的目標地址和埠,再加上負載均衡裝置設定的伺服器選擇方式,決定最終選擇的內部伺服器。LVS實現伺服器叢集負載均衡有三種方式,NAT,DR和TUN。