高併發編程(四)高併發解決方案從前端到數據庫

 1. 高併發和大流量解決方案

高併發架構相關概念
  併發:在操作系統中,是指一個時間段中有幾個程序都處於已啓動運行到運行完畢之間,且這幾個程序都是在同一個處理機上運行,但任一個時刻點上只有一個程序在處理機上運行;在互聯網時代,所講的併發,高併發通常是指併發訪問,也就是在某個時間點,有多少個訪問同時到來。通常一個系統的日PV在千萬以上,有可能是一個高併發的系統。有的公司完全不走技術路線,全靠機器堆,這不在討論範圍內。
  QPS:每秒鐘請求或者查詢的數量,在互聯網領域,指每秒響應請求數(指HTTP請求);併發連接數是系統同時處理的請求數量
  吞吐量:單位時間內處理的請求數量(通常由QPS與併發數決定)
  響應時間:從請求發出到收到響應花費的時間。例如系統處理一個HTTP請求需要100ms。
  PV:綜合瀏覽量(page view),即頁面瀏覽量或者點擊量,一個訪客在24小時內訪問的頁面數量;同一個人瀏覽網站同一頁面,只記作一次PV
  UV:獨立訪客(unique visitor),即一定時間範圍內相同訪客多次訪問網站,只計算爲一個獨立訪客
  帶寬:計算帶寬大小需關注兩個指標,峯值流量和頁面的平均大小
  日網站帶寬=PV/統計時間(換算到s)*平均頁面大小(單位KB)*8;峯值一般是平均值的倍數,根據實際情況來定
  峯值每秒請求數(QPS)=(總PV數*80%)/(6小時秒數*20%);80%的訪問量集中在20%的時間
  壓力測試:測試能承受的最大併發,測試最大承受的QPS值
  常用性能測試工具:ab,wrk,http_load,web_bench,siege,apache jmeter;ab全稱是apache benchmark,apache官方推出的工具,創建多個併發訪問線程,模擬多個訪問者同時對某一trl地址進行訪問,它的測試目標是基於url的,因此既可以用來測試apache的負載能力,也可以測試nginx,lighthttp,tomcat,IIS等其它web服務器的壓力;ab的使用:模擬併發請求100次,總共請求5000次,ab -c 100 -n 5000 待測試網站;測試機器與被測試機器分開,不要對線上服務做壓力測試,觀察測試工具ab所在機器,以及被測試的前端機的CPU,內存,網絡等都不超過最高限度的75%
  QPS達到極限:隨着QPS的增長,每個階段需要根據實際情況來進行優化,優化的方案也與硬件條件、網絡帶寬息息相關;QPS達到50,可以稱之爲小型網站,一般的服務器就可以應付;QPS達到100,假設關係型數據庫的每次請求在0.01s完成,假設單頁面只有一個SQL查詢,那麼100QPS意味着1s完成100次請求,但是此時並不能保證數據庫查詢能完成100次,數據庫緩存層,數據庫的負載均衡;QPS達到800,假設使用百兆帶寬,意味着網站出口的實際帶寬是8M左右,假設每個頁面只有10k,在這個併發條件下,百兆帶寬已經喫完,CDN加速,負載均衡;QPS達到1000,假設使用memcache緩存數據庫查詢數據,每個頁面對memcache的請求遠大於直接對db的請求,memcache的悲觀併發數在2w左右,但有可能在之前內網帶寬已經喫光,表現出不穩定,靜態HTML緩存;QPS達到2000,這個級別下,文件系統訪問鎖都成爲了災難,做業務分離,分佈式存儲

高併發解決方案案例
  流量優化:防盜鏈處理
  前端優化:減少HTTP請求,合併css或js,添加異步請求,啓用瀏覽器緩存和文件壓縮,CDN加速,建立獨立圖片服務器,
  服務端優化:頁面靜態化,併發處理,隊列處理
  數據庫優化:數據庫緩存,分庫分表,分區操作,讀寫分離,負載均衡
  web服務器優化:負載均衡,nginx反向代理,7,4層LVS軟件

 

前端併發解決方案:

1. 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。不能徹底防範,只能提高門檻。也可以針對目錄進行防盜鏈。

//在nginx的conf中配置
location ~.*\.(gif|jpg|png|flv|swf|rar|zip)$
{
    valid_referers none blocked zi.com *.zi.com;
    if($invalid_referer)
    {
        #return 403;
        rewrite ^/ http://www.zi.com/403.jpg;
    }    
}

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

  加密簽名:使用第三方模塊HttpAccessKeyModule實現Nginx防盜鏈。accesskey on|off 模塊開關,accesskey_hashmethod md5|sha-1 簽名加密方式,accesskey_arg GET參數名稱,accesskey_signature 加密規則,在nginx的conf中設置

location ~.*\.(gif|jpg|png|flv|swf|rar|zip)$
{
    accesskey on;
    accesskey_hashmethod md5;
    accesskey_arg sign;
    accesskey_signature "jason$remote_addr";
}


<?php
$sign = md5('jason'.$SERVER['REMOTE_ADDR']);
echo '<img src=".logo.png?sign='.$sign.'">';

2. 減少HTTP請求次數

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

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

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

  疑問:DNS緩存,查找DNS緩存也需要時間,多個緩存就要查找多次有可能緩存會被清除;Keep-Alive,HTTP1.1協議規定請求只能串行發送,前面的一個請求完成才能開始下個請求

  減少HTTP請求的方式:圖片地圖:允許在一個圖片上關聯多個URL,目標URL的選擇取決於用戶單擊了圖片上的哪個位置,以位置信息定位超鏈接,把HTTP請求減少爲一個,可以保證設計的完整性和功能的齊全性,使用map和area標籤;

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

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

    合併腳本和樣式表:使用外部的js和css文件引用的方式,因爲這要比直接寫在頁面中性能要更好一點;獨立的一個js比用多個js文件組成的頁面載入要快38%;把多個腳本合併爲一個腳本,把多個樣式表合併爲一個樣式表

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

3. 瀏覽器緩存和數據壓縮優化

  HTTP緩存機制:如果請求成功會有三種情況:200 from cache:直接從本地緩存中獲取相應,最快速,最省流量,因爲根本沒有向服務器進行請求;304 not modified:協商緩存,瀏覽器在本地沒有命中的情況下請求頭中發送一定的校驗數據到服務端,如果服務端數據沒有改變瀏覽器從本地緩存響應,返回304,快速,發送的數據很少,只返回一些基本的響應頭信息,數據量很小,不發送實際響應體;200 OK:以上兩種緩存全部失敗,服務器返回完整響應,沒有用到緩存,相對最慢。

  瀏覽器認爲本地緩存可以使用,不會去請求服務端。相關header:pragma:HTTP1.0時代的遺留產物,該字段被設置爲no-cache時,會告知瀏覽器禁用本地緩存,即每次都向服務器發送請求;expires:HTTP1.0時代用來啓用本地緩存的字段,瀏覽器與服務器的時間無法保持一致,如果時間差距大,就會影響緩存結果;cache-control:HTTP1.1針對expires時間不一致的解決方案,告知瀏覽器緩存過期的時間間隔而不是時刻,即使具體時間不一致,也不影響緩存的管理;可以設置的值:no-store:禁止瀏覽器緩存響應;no-cache:不允許直接使用本地緩存,先發起請求和服務器協商;max-age=delta-seconds:告知瀏覽器該響應本地緩存有效的最長期限,以秒爲單位;優先級:pragma >cache-control > expires。當瀏覽器沒有命中本地緩存,如本地緩存過期或者響應中聲明不允許直接使用本地緩存,那麼瀏覽器肯定會發起服務端請求;

  服務端會驗證數據是否修改,如果沒有通知瀏覽器使用本地緩存。相關header:last-modified:通知瀏覽器資源的最後修改時間;if-modified-since:得到資源的最後修改時間後,會將這個信息通過它提交到服務器做檢查,如果沒有修改,返回304狀態碼;ETag:HTTP1.1推出,文件的指紋標識符,如果文件內容修改,指紋會改變;if-none-match:本地緩存失效,會攜帶此值去請求服務端,服務端判斷該資源是否改變,如果沒有改變,直接使用本地緩存,返回304

  緩存策略的選擇:適合緩存的內容:不變的圖像,如logo,圖標等,js,css靜態文件,可下載的內容,媒體文件;建議使用協商緩存:html文件,經常替換的圖片,經常修改的js,css文件,js和css文件的加載可以加入文件的簽名來拒絕緩存,如a.css?簽名或a.簽名.js;不建議緩存的內容:用戶隱私等敏感數據,經常改變的api數據接口

  nginx配置緩存策略:
  本地緩存配置:add_header指令:添加狀態碼爲2xx和3xx的響應頭信息,add_header name value [always];,可以設置Pragma/Expires/Cache-Control,可以繼承;expires指令:通知瀏覽器過期時長,expires time;,爲負值時表示Cache-Control: no-cache;,當爲正或者0時,就表示Cache-Control: max-age=指定的時間;;當爲max時,Cache-Control設置到10年;
  協商緩存相關配置:Etag指令:指定簽名;etag on|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服務,gzip on|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_types text/plain applocation/xml #對哪些類型的文件用壓縮,gzip_vary on|off #是否傳輸gzip壓縮標誌。其他工具:自動化構建工具Grunt。

4. CDN加速

  CDN:Content Delivery Network,內容分發網絡,儘可能避開互聯網上有可能影響數據傳輸速度和穩定性的瓶頸和環節,使內容傳輸的更快更穩定;在網絡各處放置節點服務器所構成的在現有的互聯網基礎之上的一層智能虛擬網絡;CDN系統能夠實時的根據網絡流量和各節點的連接,負載情況以及到用戶的距離和響應時間等綜合信息將用戶的請求重新導向離用戶最近的服務節點上。本地cache加速,提高了企業站點(尤其含有大量img和靜態頁面站點)的訪問速度;跨運營商的網絡加速,保證不同網絡的用戶都得到良好的訪問質量;遠程訪問用戶根據DNS負載均衡技術智能自動選擇cache服務器;自動生成服務器的遠程Mirror cache服務器,遠程用戶訪問時從cache服務器上讀數據,減少遠程訪問的帶寬,分擔網絡流量,減輕原站點web服務器負載等功能;廣泛分佈的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等的反向代理

5. 建立獨立的圖片服務器

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

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

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

6. 動態語言靜態化

  將現有PHP等動態語言的邏輯代碼生成爲靜態HTML文件,用戶訪問動態腳本重定向到靜態HTML文件的過程。對實時性要求不高的頁面比較適合。原因:動態腳本通常會做邏輯計算和數據查詢,訪問量越大,服務器壓力越大;訪問量大時可能會造成CPU負載過高,數據庫服務器壓力過大;靜態化可以降低邏輯處理壓力,降低數據庫服務器查詢壓力

  靜態化的實現方式:
  使用模板引擎:可以使用smarty的緩存機制生成靜態HTML緩存文件;$smarty->cache-dir = $ROOT."/cache";//緩存目錄,$smarty->caching=true;//是否開啓緩存,$smarty->cache_lifetime="3600";//緩存時間,$smarty->display(string template[, string cache_id[, string compile_id]]);,$smarty->clear_all_cache();//清除所有緩存,$smarty->clear_cache('a.html');//清除指定的緩存,$smarty->clear_cache('a.html', $art_id);//清除同一個模板下的指定緩存號的緩存
  利用ob系列的函數:ob_start():打開輸出控制緩衝,ob_ge_contents():返回輸出緩衝區內容,ob_clean():清空輸出緩衝區,ob_end_flush():沖刷出(送出)輸出緩衝區內容並關閉緩衝,可以判斷文件的inode修改時間,判斷是否過期使用filectime函數

 

程序併發解決方案

1 引入分佈式緩存redis 、Memcache

 

Memcache

memcache是一套分佈式的高速緩存系統,由LiveJournal的Brad Fitzpatrick開發,但目前被許多網站使用以提升網站的訪問速度,尤其對於一些大型的、需要頻繁訪問數據庫的網站訪問速度提升效果十分顯著 [1]  。這是一套開放源代碼軟件,以BSD license授權發佈。

MemCache的工作流程如下:先檢查客戶端的請求數據是否在memcached中,如有,直接把請求數據返回,不再對數據庫進行任何操作;如果請求的數據不在memcached中,就去查數據庫,把從數據庫中獲取的數據返回給客戶端,同時把數據緩存一份到memcached中(memcached客戶端不負責,需要程序明確實現);每次更新數據庫的同時更新memcached中的數據,保證一致性;當分配給memcached內存空間用完之後,會使用LRU(Least Recently Used,最近最少使用)策略加上到期失效策略,失效數據首先被替換,然後再替換掉最近未使用的數據。 [2] 

Memcache是一個高性能的分佈式的內存對象緩存系統,通過在內存裏維護一個統一的巨大的hash表,它能夠用來存儲各種格式的數據,包括圖像、視頻、文件以及數據庫檢索的結果等。簡單的說就是將數據調用到內存中,然後從內存中讀取,從而大大提高讀取速度。

Memcache是danga的一個項目,最早是LiveJournal 服務的,最初爲了加速 LiveJournal 訪問速度而開發的,後來被很多大型的網站採用。

Memcached是以守護程序(監聽)方式運行於一個或多個服務器中,隨時會接收客戶端的連接和操作。

 

 

Redis

redis是一個key-value存儲系統。和Memcached類似,它支持存儲的value類型相對更多,包括string(字符串)、list(鏈表)、set(集合)、zset(sorted set --有序集合)和hash(哈希類型)。這些數據類型都支持push/pop、add/remove及取交集並集和差集及更豐富的操作,而且這些操作都是原子性的。在此基礎上,redis支持各種不同方式的排序。與memcached一樣,爲了保證效率,數據都是緩存在內存中。區別的是redis會週期性的把更新的數據寫入磁盤或者把修改操作寫入追加的記錄文件,並且在此基礎上實現了master-slave(主從)同步。

Redis 是一個高性能的key-value數據庫。 redis的出現,很大程度補償了memcached這類key/value存儲的不足,在部 分場合可以對關係數據庫起到很好的補充作用。它提供了Java,C/C++,C#,PHP,JavaScript,Perl,Object-C,Python,Ruby,Erlang等客戶端,使用很方便。 [1] 

Redis支持主從同步。數據可以從主服務器向任意數量的從服務器上同步,從服務器可以是關聯其他從服務器的主服務器。這使得Redis可執行單層樹複製。存盤可以有意無意的對數據進行寫操作。由於完全實現了發佈/訂閱機制,使得從數據庫在任何地方同步樹時,可訂閱一個頻道並接收主服務器完整的消息發佈記錄。同步對讀取操作的可擴展性和數據冗餘很有幫助。

redis的官網地址,非常好記,是redis.io。(特意查了一下,域名後綴io屬於國家域名,是british Indian Ocean territory,即英屬印度洋領地)

目前,Vmware在資助着redis項目的開發和維護。

 

 

Redis和Memcache區別

 

1.Redis是什麼

這個問題的結果影響了我們怎麼用Redis。如果你認爲Redis是一個key value store, 那可能會用它來代替MySQL;如果認爲它是一個可以持久化的cache, 可能只是它保存一些頻繁訪問的臨時數據。Redis是REmote DIctionary Server的縮寫,在Redis在官方網站的的副標題是A persistent key-value database with built-in net interface written in ANSI-C for Posix systems,這個定義偏向key value store。還有一些看法則認爲Redis是一個memory database,因爲它的高性能都是基於內存操作的基礎。另外一些人則認爲Redis是一個data structure server,因爲Redis支持複雜的數據特性,比如List, Set等。對Redis的作用的不同解讀決定了你對Redis的使用方式。

互聯網數據目前基本使用兩種方式來存儲,關係數據庫或者key value。但是這些互聯網業務本身並不屬於這兩種數據類型,比如用戶在社會化平臺中的關係,它是一個list,如果要用關係數據庫存儲就需要轉換成一種多行記錄的形式,這種形式存在很多冗餘數據,每一行需要存儲一些重複信息。如果用key value存儲則修改和刪除比較麻煩,需要將全部數據讀出再寫入。Redis在內存中設計了各種數據類型,讓業務能夠高速原子的訪問這些數據結構,並且不需要關心持久存儲的問題,從架構上解決了前面兩種存儲需要走一些彎路的問題。

2. Redis不可能比Memcache快

很多開發者都認爲Redis不可能比Memcached快,Memcached完全基於內存,而Redis具有持久化保存特性,即使是異步的,Redis也不可能比Memcached快。但是測試結果基本是Redis佔絕對優勢。一直在思考這個原因,目前想到的原因有這幾方面。

Libevent。和Memcached不同,Redis並沒有選擇libevent。Libevent爲了迎合通用性造成代碼龐大(目前Redis代碼還不到libevent的1/3)及犧牲了在特定平臺的不少性能。Redis用libevent中兩個文件修改實現了自己的epoll event loop(4)。業界不少開發者也建議Redis使用另外一個libevent高性能替代libev,但是作者還是堅持Redis應該小巧並去依賴的思路。一個印象深刻的細節是編譯Redis之前並不需要執行./configure。

CAS問題。CAS是Memcached中比較方便的一種防止競爭修改資源的方法。CAS實現需要爲每個cache key設置一個隱藏的cas token,cas相當value版本號,每次set會token需要遞增,因此帶來CPU和內存的雙重開銷,雖然這些開銷很小,但是到單機10G+ cache以及QPS上萬之後這些開銷就會給雙方相對帶來一些細微性能差別(5)。

3. 單臺Redis的存放數據必須比物理內存小

Redis的數據全部放在內存帶來了高速的性能,但是也帶來一些不合理之處。比如一箇中型網站有100萬註冊用戶,如果這些資料要用Redis來存儲,內存的容量必須能夠容納這100萬用戶。但是業務實際情況是100萬用戶只有5萬活躍用戶,1周來訪問過1次的也只有15萬用戶,因此全部100萬用戶的數據都放在內存有不合理之處,RAM需要爲冷數據買單。

這跟操作系統非常相似,操作系統所有應用訪問的數據都在內存,但是如果物理內存容納不下新的數據, 操作系統會智能將部分長期沒有訪問的數據交換到磁盤,爲新的應用留出空間。現代操作系統給應用提供的並不是物理內存,而是虛擬內存(Virtual Memory)的概念。

基於相同的考慮,Redis 2.0也增加了VM特性。讓Redis數據容量突破了物理內存的限制。並實現了數據冷熱分離。

4. Redis的VM實現是重複造輪子

Redis的VM依照之前的epoll實現思路依舊是自己實現。但是在前面操作系統的介紹提到OS也可以自動幫程序實現冷熱數據分離,Redis只需要OS申請一塊大內存,OS會自動將熱數據放入物理內存,冷數據交換到硬盤,另外一個知名的“理解了現代操作系統(3)”的Varnish就是這樣實現,也取得了非常成功的效果。

作者antirez在解釋爲什麼要自己實現VM中提到幾個原因(6)。主要OS的VM換入換出是基於Page概念,比如OS VM1個Page是4K, 4K中只要還有一個元素即使只有1個字節被訪問,這個頁也不會被SWAP, 換入也同樣道理,讀到一個字節可能會換入4K無用的內存。而Redis自己實現則可以達到控制換入的粒度。另外訪問操作系統SWAP內存區域時block進程,也是導致Redis要自己實現VM原因之一。

5. 用get/set方式使用Redis

作爲一個key value存在,很多開發者自然的使用set/get方式來使用Redis,實際上這並不是最優化的使用方法。尤其在未啓用VM情況下,Redis全部數據需要放入內存,節約內存尤其重要。

假如一個key-value單元需要最小佔用512字節,即使只存一個字節也佔了512字節。這時候就有一個設計模式,可以把key複用,幾個key-value放入一個key中,value再作爲一個set存入,這樣同樣512字節就會存放10-100倍的容量。

這就是爲了節約內存,建議使用hashset而不是set/get的方式來使用Redis,詳細方法見參考文獻(7)。

6. 使用aof代替snapshot

Redis有兩種存儲方式,默認是snapshot方式,實現方法是定時將內存的快照(snapshot)持久化到硬盤,這種方法缺點是持久化之後如果出現crash則會丟失一段數據。因此在完美主義者的推動下作者增加了aof方式。aof即append only mode,在寫入內存數據的同時將操作命令保存到日誌文件,在一個併發更改上萬的系統中,命令日誌是一個非常龐大的數據,管理維護成本非常高,恢復重建時間會非常長,這樣導致失去aof高可用性本意。另外更重要的是Redis是一個內存數據結構模型,所有的優勢都是建立在對內存複雜數據結構高效的原子操作上,這樣就看出aof是一個非常不協調的部分。

其實aof目的主要是數據可靠性及高可用性,在Redis中有另外一種方法來達到目的:Replication。由於Redis的高性能,複製基本沒有延遲。這樣達到了防止單點故障及實現了高可用。

高併發場景下緩存常見問題

 

緩存一致性

緩存併發問題

緩存穿透問題

緩存的雪崩現象

請參考我的文章redis一文弄懂

 

2 引入第三方通信組件(Kafka、RabbitMQ)

消息隊列

消息隊列的特性

業務無關:只做消息分發

FIFO:先投遞先到達

容災:節點的動態增刪和消息的持久化

性能:吞吐量提升、系統內部通信效率提高

爲什麼需要消息隊列

【生產】和【消費】的速度或穩定性等因素不一致

消息隊列的好處

業務解耦

最終一致性 

廣播

錯峯有流控

詳情請參考我的文章消息中間件的應用


3 業務的橫向拆分(集羣)縱向查分(微服務)

應用拆分-原則

 

業務優先

循序漸進

兼顧技術:重構、分層

可靠測試

 

應用拆分-思考

 

應用之間通信:RPC(dubbo等)、消息隊列

應用之間數據庫設計:每個應用都有獨立的數據庫

避免事務操作跨應用

 

Dubbo

微服務

應用限流

應用限流-算法

數器法

滑動窗口

漏捅算法

令牌通算法

詳情請參考我的文章    構建微服務

 

3 數據庫高併發解決方案

數據庫切庫、分庫、分表

 

數據庫瓶頸

    單個庫數據量太大(1T-2T):多個庫

    單個數據庫服務器壓力過大、讀寫瓶頸:多個庫

    單個表數據量過大:分表

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章