mysql性能優化教程(轉)

Mysql 性能優化教程前端

目錄

目錄node

背景及目標mysql

Mysql 執行優化ios

認識數據索引web

爲何使用數據索引能提升效率算法

如何理解數據索引的結構sql

如何理解影響結果集數據庫

理解執行狀態apache

常見分析手段後端

分析流程

總結

Mysql 運維優化

存儲引擎類型

內存使用考量

性能與安全性考量

存儲壓力優化

運維監控體系

Mysql 架構優化

架構優化目標

防止單點隱患

方便系統擴容

安全可控,成本可控

分佈式方案

分庫&拆表方案

主從架構

故障轉移處理

緩存方案

緩存結合數據庫的讀取

緩存結合數據庫的寫入

 

 

 

背景及目標

l  廈門遊家公司(4399.com)用於員工培訓和分享。

l  針對用戶羣爲已經使用過mysql環境,並有必定開發經驗的工程師

l  針對高併發,海量數據的互聯網環境。

l  本文語言爲口語,非學術標準用語。

l  以實戰和解決具體問題爲主要目標,非應試,很是規教育。友情提醒,在校生學習本教程可能對成績提升有害無益。

l  非技術挑戰,非高端架構師培訓,請高手自動忽略。

Mysql 執行優化

認識數據索引

爲何使用數據索引能提升效率

n  數據索引的存儲是有序的

n  在有序的狀況下,經過索引查詢一個數據是無需遍歷索引記錄的

n  極端狀況下,數據索引的查詢效率爲二分法查詢效率,趨近於 log2(N)

如何理解數據索引的結構

n  數據索引一般默認採用btree索引,(內存表也使用了hash索引)。

n  單一有序排序序列是查找效率最高的(二分查找,或者說折半查找),使用樹形索引的目的是爲了達到快速的更新和增刪操做。

n  在極端狀況下(好比數據查詢需求量很是大,而數據更新需求極少,實時性要求不高,數據規模有限),直接使用單一排序序列,折半查找速度最快。

u  實戰範例 : ip地址反查

資源: Ip地址對應表,源數據格式爲  startip, endip, area

源數據條數爲 10萬條左右,呈很大的分散性

目標:    須要經過任意ip查詢該ip所屬地區

性能要求達到每秒1000次以上的查詢效率

挑戰:    如使用 between … and 數據庫操做,沒法有效使用索引。

若是每次查詢請求須要遍歷10萬條記錄,根本不行。

方法:    一次性排序(只在數據準備中進行,數據可存儲在內存序列)

              折半查找(每次請求以折半查找方式進行)

n  在進行索引分析和SQL優化時,能夠將數據索引字段想象爲單一有序序列,並以此做爲分析的基礎。

u  實戰範例:複合索引查詢優化實戰,同城異性列表

資源: 用戶表user,字段 sex性別;area 地區;lastlogin 最後登陸時間;其餘略

目標: 查找同一地區的異性,按照最後登陸時間逆序

          高訪問量社區的高頻查詢,如何優化。

              查詢SQL: select * from user where area=’$area’ and sex=’$sex’ order by lastlogin desc limit 0,30;

挑戰:    創建複合索引並不難, area+sex+lastlogin 三個字段的複合索引,如何理解?

              首先,忘掉btree,將索引字段理解爲一個排序序列。

              若是隻使用area會怎樣?搜索會把符合area的結果所有找出來,而後在這裏面遍歷,選擇命中sex的並排序。 遍歷全部 area=’$area’數據!

              若是使用了area+sex,略好,仍然要遍歷全部area=’$area’ and sex=’$sex’數據,而後在這個基礎上排序!!

              Area+sex+lastlogin複合索引時(切記lastlogin在最後),該索引基於area+sex+lastlogin 三個字段合併的結果排序,該列表能夠想象以下。

              廣州女$時間1

              廣州女$時間2

              廣州女$時間3

              …

              廣州男

….

              深圳女

….

數據庫很容易命中到 area+sex的邊界,而且基於下邊界向上追溯30條記錄,搞定!在索引中迅速命中全部結果,無需二次遍歷!

如何理解影響結果集

n  影響結果集是數據查詢優化的一個重要中間數據

u  查詢條件與索引的關係決定影響結果集

如上例所示,即使查詢用到了索引,可是若是查詢和排序目標不能直接在索引中命中,其可能帶來較多的影響結果。而這會直接影響到查詢效率

u  微秒級優化

l  優化查詢不能只看慢查詢日誌,常規來講,0.01秒以上的查詢,都是不夠優化的。

l  實戰範例

和上案例相似,某遊戲社區要顯示用戶動態,select * from userfeed where uid=$uid order by lastlogin desc limit 0,30;   初期默認以uid爲索引字段,查詢爲命中全部uid=$uid的結果按照lastlogin排序。 當用戶行爲很是頻繁時,該SQL索引命中影響結果集有數百乃至數千條記錄。查詢效率超過0.01秒,併發較大時數據庫壓力較大。

解決方案:將索引改成 uid+lastlogin 複合索引,索引直接命中影響結果集30條,查詢效率提升了10倍,平均在0.001秒,數據庫壓力驟降。

n  影響結果集的常見誤區

u  影響結果集並非說數據查詢出來的結果數或操做影響的結果數,而是查詢條件的索引所命中的結果數。

u  實戰範例

l  某遊戲數據庫使用了innodb,innodb是行級鎖,理論上不多存在鎖表狀況。出現了一個SQL語句(delete from tabname where xid=…),這個SQL很是用SQL,僅在特定狀況下出現,天天出現頻繁度不高(一天僅10次左右),數據表容量百萬級,可是這個xid未創建索引,因而悲慘的事情發生了,當執行這條delete 的時候,真正刪除的記錄很是少,也許一到兩條,也許一條都沒有;可是!因爲這個xid未創建索引,delete操做時遍歷全表記錄,全表被delete操做鎖定,select操做所有被locked,因爲百萬條記錄遍歷時間較長,期間大量select被阻塞,數據庫鏈接過多崩潰。

這種非高發請求,操做目標不多的SQL,因未使用索引,連帶致使整個數據庫的查詢阻塞,須要極大提升警覺。

n  總結:

u  影響結果集是搜索條件索引命中的結果集,而非輸出和操做的結果集。

u  影響結果集越趨近於實際輸出或操做的目標結果集,索引效率越高。

u  請注意,我這裏永遠不會講關於外鍵和join的優化,由於在咱們的體系裏,這是根本不容許的! 架構優化部分會解釋爲何。

理解執行狀態

常見分析手段

l  慢查詢日誌,關注重點以下

n  是否鎖定,及鎖定時間

u  如存在鎖定,則該慢查詢一般是因鎖定因素致使,自己無需優化,需解決鎖定問題。

n  影響結果集

u  如影響結果集較大,顯然是索引項命中存在問題,須要認真對待。

l  Explain 操做

n  索引項使用

u  不建議用using index作強制索引,如未如預期使用索引,建議從新斟酌表結構和索引設置。

n  影響結果集

u  這裏顯示的數字不必定準確,結合以前提到對數據索引的理解來看,還記得嘛?就把索引看成有序序列來理解,反思SQL。

l  Set profiling , show profiles for query操做

n  執行開銷

u  注意,有問題的SQL若是重複執行,可能在緩存裏,這時要注意避免緩存影響。經過這裏能夠看到。

u  執行時間超過0.005秒的頻繁操做SQL建議都分析一下。

u  深刻理解數據庫執行的過程和開銷的分佈

l  Show processlist

n  狀態清單

u  Sleep 狀態, 一般表明資源未釋放,若是是經過鏈接池,sleep狀態應該恆定在必定數量範圍內

l  實戰範例: 因前端數據輸出時(特別是輸出到用戶終端)未及時關閉數據庫鏈接,致使因網絡鏈接速度產生大量sleep鏈接,在網速出現異常時,數據庫 too many connections 掛死。

l  簡單解讀,數據查詢和執行一般只須要不到0.01秒,而網絡輸出一般須要1秒左右甚至更長,本來數據鏈接在0.01秒便可釋放,可是由於前端程序未執行close操做,直接輸出結果,那麼在結果未展示在用戶桌面前,該數據庫鏈接一直維持在sleep狀態!

u  Waiting for net, reading from net, writing to net

l  偶爾出現無妨

l  如大量出現,迅速檢查數據庫到前端的網絡鏈接狀態和流量

l  案例: 因外掛程序,內網數據庫大量讀取,內網使用的百兆交換迅速爆滿,致使大量鏈接阻塞在waiting for net,數據庫鏈接過多崩潰

u  Locked狀態

l  有更新操做鎖定

l  一般使用innodb能夠很好的減小locked狀態的產生,可是切記,更新操做要正確使用索引,即使是低頻次更新操做也不能疏忽。如上影響結果集範例所示。

l  在myisam的時代,locked是不少高併發應用的噩夢。因此mysql官方也開始傾向於推薦innodb。

u  Copy to tmp table

l  索引及現有結構沒法涵蓋查詢條件,纔會創建一個臨時表來知足查詢要求,產生巨大的恐怖的i/o壓力。

l  很可怕的搜索語句會致使這樣的狀況,若是是數據分析,或者半夜的週期數據清理任務,偶爾出現,能夠容許。頻繁出現務必優化之。

l  Copy to tmp table 一般與連表查詢有關,建議逐漸習慣不使用連表查詢。

l  實戰範例:

n  某社區數據庫阻塞,求救,經查,其服務器存在多個數據庫應用和網站,其中一個不經常使用的小網站數據庫產生了一個恐怖的copy to tmp table 操做,致使整個硬盤i/o和cpu壓力超載。Kill掉該操做一切恢復。

u  Sending data

l  Sending data 並非發送數據,別被這個名字所欺騙,這是從物理磁盤獲取數據的進程,若是你的影響結果集較多,那麼就須要從不一樣的磁盤碎片去抽取數據,

l  偶爾出現該狀態鏈接無礙。

l  回到上面影響結果集的問題,通常而言,若是sending data鏈接過多,一般是某查詢的影響結果集過大,也就是查詢的索引項不夠優化。

l  若是出現大量類似的SQL語句出如今show proesslist列表中,而且都處於sending data狀態,優化查詢索引,記住用影響結果集的思路去思考。

u  Freeing items

l  理論上這玩意不會出現不少。偶爾出現無礙

l  若是大量出現,內存,硬盤可能已經出現問題。好比硬盤滿或損壞。

u  Sorting for …

l  和Sending data相似,結果集過大,排序條件沒有索引化,須要在內存裏排序,甚至須要建立臨時結構排序。

u  其餘

l  還有不少狀態,遇到了,去查查資料。基本上咱們遇到其餘狀態的阻塞較少,因此不關心。

分析流程

l  基本流程

n  詳細瞭解問題情況

u  Too many connections 是常見表象,有不少種緣由。

u  索引損壞的狀況在innodb狀況下不多出現。

u  如出現其餘狀況應追溯日誌和錯誤信息。

n  瞭解基本負載情況和運營情況

u  基本運營情況

l  當前每秒讀請求

l  當前每秒寫請求

l  當前在線用戶

l  當前數據容量

u  基本負載狀況

l  學會使用這些指令

n  Top

n  Vmstat

n  uptime

n  iostat

n  df

l  Cpu負載構成

n  特別關注i/o壓力( wa%)

n  多核負載分配

l  內存佔用

n  Swap分區是否被侵佔

n  如Swap分區被侵佔,物理內存是否較多空閒

l  磁盤狀態

n  硬盤滿和inode節點滿的狀況要迅速定位和迅速處理

n  瞭解具體鏈接情況

u  當前鏈接數

l  Netstat –an|grep 3306|wc –l

l  Show processlist

u  當前鏈接分佈 show processlist

l  前端應用請求數據庫不要使用root賬號!

n  Root賬號比其餘普通賬號多一個鏈接數許可。

n  前端使用普通賬號,在too many connections的時候root賬號仍能夠登陸數據庫查詢 show processlist!

n  記住,前端應用程序不要設置一個不叫root的root賬號來糊弄!非root帳戶是骨子裏的,而不是名義上的。

l  狀態分佈

n  不一樣狀態表明不一樣的問題,有不一樣的優化目標。

n  參見如上範例。

l  雷同SQL的分佈

n  是否較多雷同SQL出如今同一狀態

u  當前是否有較多慢查詢日誌

l  是否鎖定

l  影響結果集

n  頻繁度分析

u  寫頻繁度

l  若是i/o壓力高,優先分析寫入頻繁度

l  Mysqlbinlog 輸出最新binlog文件,編寫腳本拆分

l  最多寫入的數據表是哪一個

l  最多寫入的數據SQL是什麼

l  是否存在基於同一主鍵的數據內容高頻重複寫入?

n  涉及架構優化部分,參見架構優化-緩存異步更新

u  讀取頻繁度

l  若是cpu資源較高,而i/o壓力不高,優先分析讀取頻繁度

l  程序中在封裝的db類增長抽樣日誌便可,抽樣比例酌情考慮,以不顯著影響系統負載壓力爲底線。

l  最多讀取的數據表是哪一個

l  最多讀取的數據SQL是什麼

n  該SQL進行explain 和set profiling斷定

n  注意斷定時須要避免query cache影響

u  好比,在這個SQL末尾增長一個條件子句 and 1=1 就能夠避免從query cache中獲取數據,而獲得真實的執行狀態分析。

l  是否存在同一個查詢短時間內頻繁出現的狀況

n  涉及前端緩存優化

n  抓大放小,解決顯著問題

u  不苛求解決全部優化問題,可是應以保證線上服務穩定可靠爲目標。

u  解決與評估要同時進行,新的策略或解決方案務必通過評估後上線。

總結

l  要學會怎樣分析問題,而不是單純拍腦殼優化

l  慢查詢只是最基礎的東西,要學會優化0.01秒的查詢請求。

l  當發生鏈接阻塞時,不一樣狀態的阻塞有不一樣的緣由,要找到緣由,若是不對症下藥,就會南轅北轍

n  範例:若是自己系統內存已經超載,已經使用到了swap,而還在考慮加大緩存來優化查詢,那就是自尋死路了。

l  監測與跟蹤要常常作,而不是出問題才作

n  讀取頻繁度抽樣監測

u  全監測不要搞,i/o嚇死人。

u  按照一個抽樣比例抽樣便可。

u  針對抽樣中發現的問題,能夠按照特定SQL在特定時間內監測一段全查詢記錄,但仍要考慮i/o影響。

n  寫入頻繁度監測

u  基於binlog解開便可,可定時或不定時分析。

n  微慢查詢抽樣監測

u  高併發狀況下,查詢請求時間超過0.01秒甚至0.005秒的,建議酌情抽樣記錄。

n  鏈接數預警監測

u  鏈接數超過特定閾值的狀況下,雖然數據庫沒有崩潰,建議記錄相關鏈接狀態。

l  學會經過數據和監控發現問題,分析問題,然後解決問題瓜熟蒂落。特別是要學會在平常監控中發現隱患,而不是問題爆發了纔去處理和解決。


Mysql 運維優化

存儲引擎類型

l  Myisam 速度快,響應快。表級鎖是致命問題。

l  Innodb 目前主流存儲引擎

n  行級鎖

u  務必注意影響結果集的定義是什麼

u  行級鎖會帶來更新的額外開銷,可是一般狀況下是值得的。

n  事務提交

u  對i/o效率提高的考慮

u  對安全性的考慮

l  HEAP 內存引擎

n  頻繁更新和海量讀取狀況下仍會存在鎖定情況

內存使用考量

l  理論上,內存越大,越多數據讀取發生在內存,效率越高

l  要考慮到現實的硬件資源和瓶頸分佈

l  學會理解熱點數據,並將熱點數據儘量內存化

n  所謂熱點數據,就是最多被訪問的數據。

n  一般數據庫訪問是不平均的,少數數據被頻繁讀寫,而更多數據鮮有讀寫。

n  學會制定不一樣的熱點數據規則,並測算指標。

u  熱點數據規模,理論上,熱點數據越少越好,這樣能夠更好的知足業務的增加趨勢。

u  響應知足度,對響應的知足率越高越好。

u  好比依據最後更新時間,總訪問量,回訪次數等指標定義熱點數據,並測算不一樣定義模式下的熱點數據規模

性能與安全性考量

l  數據提交方式

n  innodb_flush_log_at_trx_commit = 1 每次自動提交,安全性高,i/o壓力大

n  innodb_flush_log_at_trx_commit = 2 每秒自動提交,安全性略有影響,i/o承載強。

l  日誌同步

n  Sync-binlog    =1 每條自動更新,安全性高,i/o壓力大

n  Sync-binlog = 0 根據緩存設置狀況自動更新,存在丟失數據和同步延遲風險,i/o承載力強。

l  性能與安全自己存在相悖的狀況,須要在業務訴求層面決定取捨

n  學會區分什麼場合側重性能,什麼場合側重安全

n  學會將不一樣安全等級的數據庫用不一樣策略管理

存儲壓力優化

l  順序讀寫性能遠高於隨機讀寫

l  日誌類數據可使用順序讀寫方式進行

l  將順序寫數據和隨機讀寫數據分紅不一樣的物理磁盤,有助於i/o壓力的疏解,前提是,你確信你的i/o壓力主要來自於可順序寫操做(因隨機讀寫干擾致使不能順序寫,可是確實能夠用順序寫方式進行的i/o操做)。

運維監控體系

l  系統監控

n  服務器資源監控

u  Cpu, 內存,硬盤空間,i/o壓力

u  設置閾值報警

n  服務器流量監控

u  外網流量,內網流量

u  設置閾值報警

n  鏈接狀態監控

u  Show processlist 設置閾值,每分鐘監測,超過閾值記錄

l  應用監控

n  慢查詢監控

u  慢查詢日誌

u  若是存在多臺數據庫服務器,應有彙總查閱機制。

n  請求錯誤監控

u  高頻繁應用中,會出現偶發性數據庫鏈接錯誤或執行錯誤,將錯誤信息記錄到日誌,查看每日的比例變化。

u  偶發性錯誤,若是數量極少,能夠不用處理,可是需時常監控其趨勢。

u  會存在惡意輸入內容,輸入邊界限定缺少致使執行出錯,需基於此防止惡意入侵探測行爲。

n  微慢查詢監控

u  高併發環境裏,超過0.01秒的查詢請求都應該關注一下。

n  頻繁度監控

u  寫操做,基於binlog,按期分析。

u  讀操做,在前端db封裝代碼中增長抽樣日誌,並輸出執行時間。

u  分析請求頻繁度是開發架構 進一步優化的基礎

u  最好的優化就是減小請求次數!

l  總結:

n  監控與數據分析是一切優化的基礎。

n  沒有運營數據監測就不要妄談優化!

n  監控要注意不要產生太多額外的負載,不要因監控帶來太多額外系統開銷


Mysql 架構優化

架構優化目標

防止單點隱患

l  所謂單點隱患,就是某臺設備出現故障,會致使總體系統的不可用,這個設備就是單點隱患。

l  理解連帶效應,所謂連帶效應,就是一種問題會引起另外一種故障,舉例而言,memcache+mysql是一種常見緩存組合,在前端壓力很大時,若是memcache崩潰,理論上數據會經過mysql讀取,不存在系統不可用狀況,可是mysql沒法對抗如此大的壓力衝擊,會所以連帶崩潰。因A系統問題致使B系統崩潰的連帶問題,在運維過程當中會頻繁出現。

n  實戰範例: 在mysql鏈接不及時釋放的應用環境裏,當網絡環境異常(同機房友鄰服務器遭受拒絕服務攻擊,出口阻塞),網絡延遲加重,空鏈接數急劇增長,致使數據庫鏈接過多崩潰。

n  實戰範例2:前端代碼 一般咱們封裝 mysql_connect和memcache_connect,兩者的順序不一樣,會產生不一樣的連帶效應。若是mysql_connect在前,那麼一旦memcache鏈接阻塞,會連帶mysql空鏈接過多崩潰。

n  連帶效應是常見的系統崩潰,平常分析崩潰緣由的時候須要認真考慮連帶效應的影響,頭疼醫頭,腳疼醫腳是不行的。

方便系統擴容

l  數據容量增長後,要考慮可以將數據分佈到不一樣的服務器上。

l  請求壓力增長時,要考慮將請求壓力分佈到不一樣服務器上。

l  擴容設計時須要考慮防止單點隱患。

安全可控,成本可控

l  數據安全,業務安全

l  人力資源成本>帶寬流量成本>硬件成本

n  成本與流量的關係曲線應低於線性增加(流量爲橫軸,成本爲縱軸)。

n  規模優點

l  本教程僅就與數據庫有關部分討論,與數據庫無關部門請自行參閱其餘學習資料。

      

分佈式方案

分庫&拆表方案

l  基本認識

n  用分庫&拆表是解決數據庫容量問題的惟一途徑。

n  分庫&拆表也是解決性能壓力的最優選擇。

n  分庫 – 不一樣的數據表放到不一樣的數據庫服務器中(也多是虛擬服務器)

n  拆表 – 一張數據表拆成多張數據表,可能位於同一臺服務器,也可能位於多臺服務器(含虛擬服務器)。

l  去關聯化原則

n  摘除數據表之間的關聯,是分庫的基礎工做。

n  摘除關聯的目的是,當數據表分佈到不一樣服務器時,查詢請求容易分發和處理。

n  學會理解反範式數據結構設計,所謂反範式,第一要點是不用外鍵,不容許Join操做,不容許任何須要跨越兩個表的查詢請求。第二要點是適度冗餘減小查詢請求,好比說,信息表,fromuid, touid, message字段外,還須要一個fromuname字段記錄用戶名,這樣查詢者經過touid查詢後,可以當即獲得發信人的用戶名,而無需進行另外一個數據表的查詢。

n  去關聯化處理會帶來額外的考慮,好比說,某一個數據表內容的修改,對另外一個數據表的影響。這一點須要在程序或其餘途徑去考慮。

l  分庫方案

n  安全性拆分

u  將高安全性數據與低安全性數據分庫,這樣的好處第一是便於維護,第二是高安全性數據的數據庫參數配置能夠以安全優先,而低安全性數據的參數配置以性能優先。參見運維優化相關部分。

n  順序寫數據與隨機讀寫數據分庫

u  順序數據與隨機數據區分存儲地址,保證物理i/o優化。這個實話說,我只據說了概念,還沒學會怎麼實踐。

n  基於業務邏輯拆分

u  根據數據表的內容構成,業務邏輯拆分,便於平常維護和前端調用。

u  基於業務邏輯拆分,能夠減小前端應用請求發送到不一樣數據庫服務器的頻次,從而減小連接開銷。

u  基於業務邏輯拆分,可保留部分數據關聯,前端web工程師可在限度範圍內執行關聯查詢。

n  基於負載壓力拆分

u  基於負載壓力對數據結構拆分,便於直接將負載分擔給不一樣的服務器。

u  基於負載壓力拆分,可能拆分後的數據庫包含不一樣業務類型的數據表,平常維護會有必定的煩惱。

l  分表方案

n  數據量過大或者訪問壓力過大的數據表須要切分

n  忙閒分表

u  單數據表字段過多,可將頻繁更新的整數數據與非頻繁更新的字符串數據切分

u  範例 user表 ,我的簡介,地址,QQ號,聯繫方式,頭像 這些字段爲字符串類型,更新請求少; 最後登陸時間,在線時常,訪問次數,信件數這些字段爲整數型字段,更新頻繁,能夠將後面這些更新頻繁的字段獨立拆出一張數據表,表內容變少,索引結構變少,讀寫請求變快。

n  橫向切表

u  等分切表,如哈希切表或其餘基於對某數字取餘的切表。等分切表的優勢是負載很方便的分佈到不一樣服務器;缺點是當容量繼續增長時沒法方便的擴容,須要從新進行數據的切分或轉表。並且一些關鍵主鍵不易處理。

u  遞增切表,好比每1kw用戶開一個新表,優勢是能夠適應數據的自增趨勢;缺點是每每新數據負載高,壓力分配不平均。

u  日期切表,適用於日誌記錄式數據,優缺點等同於遞增切表。

u  我的傾向於遞增切表,具體根據應用場景決定。

n  熱點數據分表

u  將數據量較大的數據表中將讀寫頻繁的數據抽取出來,造成熱點數據表。一般一個龐大數據表常常被讀寫的內容每每具備必定的集中性,若是這些集中數據單獨處理,就會極大減小總體系統的負載。

u  熱點數據表與舊有數據關係

l  能夠是一張冗餘表,即該表數據丟失不會妨礙使用,因源數據仍存在於舊有結構中。優勢是安全性高,維護方便,缺點是寫壓力不能分擔,仍須要同步寫回原系統。

l  能夠是非冗餘表,即熱點數據的內容原有結構再也不保存,優勢是讀寫效率所有優化;缺點是當熱點數據發生變化時,維護量較大。

l  具體方案選擇須要根據讀寫比例決定,在讀頻率遠高於寫頻率狀況下,優先考慮冗餘表方案。

u  熱點數據表能夠用單獨的優化的硬件存儲,好比昂貴的閃存卡或大內存系統。

u  熱點數據表的重要指標

l  熱點數據的定義須要根據業務模式自行制定策略,常見策略爲,按照最新的操做時間;按照內容豐富度等等。

l  數據規模,好比從1000萬條數據,抽取出100萬條熱點數據。

l  熱點命中率,好比查詢10次,多少次命中在熱點數據內。

l  理論上,數據規模越小,熱點命中率越高,說明效果越好。須要根據業務自行評估。

u  熱點數據表的動態維護

l  加載熱點數據方案選擇

n  定時從舊有數據結構中按照新的策略獲取

n  在從舊有數據結構讀取時動態加載到熱點數據

l  剔除熱點數據方案選擇

n  基於特定策略,定時將熱點數據中訪問頻次較少的數據剔除

n  如熱點數據是冗餘表,則直接刪除便可,如不是冗餘表,須要回寫給舊有數據結構。

u  一般,熱點數據每每是基於緩存或者key-value 方案冗餘存儲,因此這裏提到的熱點數據表,其實更可能是理解思路,用到的場合可能並很少….

l  表結構設計

n  查詢冗餘表設計

u  涉及分表操做後,一些常見的索引查詢可能須要跨表,帶來沒必要要的麻煩。確認查詢請求遠大於寫入請求時,應設置便於查詢項的冗餘表。

u  實戰範例,

l  用戶分表,將用戶庫分紅若干數據表

l  基於用戶名的查詢和基於uid的查詢都是高併發請求。

l  用戶分表基於uid分紅數據表,同時基於用戶名作對應冗餘表。

u  冗餘表要點

l  數據一致性,簡單說,同增,同刪,同更新。

l  能夠作全冗餘,或者只作主鍵關聯的冗餘,好比經過用戶名查詢uid,再基於uid查詢源表。

n  中間數據表

u  爲了減小會涉及大規模影響結果集的表數據操做,好比count,sum操做。應將一些統計類數據經過中間數據表保存。

u  中間數據表應能經過源數據表恢復。

u  實戰範例:

l  論壇板塊的發帖量,回帖量,每日新增數據等

l  網站每日新增用戶數等。

l  後臺能夠經過源數據表更新該數字。

n  歷史數據表

u  歷史數據表對應於熱點數據表,將需求較少又不能丟棄的數據存入,僅在少數狀況下被訪問。

主從架構

l  基本認識

n  讀寫分離對負載的減輕遠遠不如分庫分表來的直接。

n  寫壓力會傳遞給從表,只讀從庫同樣有寫壓力,同樣會產生讀寫鎖!

n  一主多從結構下,主庫是單點隱患,很難解決(如主庫當機,從庫能夠響應讀寫,可是沒法自動擔當主庫的分發功能)

n  主從延遲也是重大問題。一旦有較大寫入問題,如表結構更新,主從會產生巨大延遲。

l  應用場景

n  在線熱備

n  異地分佈

u  寫分佈,讀統一。

u  仍然困難重重,受限於網絡環境問題巨多!

n  自動障礙轉移

u  主崩潰,從自動接管

n  我的建議,負載均衡主要使用分庫方案,主從主要用於熱備和障礙轉移。

l  潛在優化點

n  爲了減小寫壓力,有些人建議主不建索引提高i/o性能,從創建索引知足查詢要求。我的認爲這樣維護較爲麻煩。並且從自己會繼承主的i/o壓力,所以優化價值有限。該思路特此分享,不作推薦。

故障轉移處理

l  要點

n  程序與數據庫的鏈接,基於虛地址而非真實ip,由負載均衡系統監控。

n  保持主從結構的簡單化,不然很難作到故障點摘除。

l  思考方式

n  遍歷對服務器集羣的任何一臺服務器,前端web,中間件,監控,緩存,db等等,假設該服務器出現故障,系統是否會出現異常?用戶訪問是否會出現異常。

n  目標:任意一臺服務器崩潰,負載和數據操做均會很短期內自動轉移到其餘服務器,不會影響業務的正常進行。不會形成惡性的數據丟失。(哪些是能夠丟失的,哪些是不能丟失的)

緩存方案

緩存結合數據庫的讀取

l  Memcached是最經常使用的緩存系統

l  Mysql 最新版本已經開始支持memcache插件,但據牛人分析,尚不成熟,暫不推薦。

l  數據讀取

n  並非全部數據都適合被緩存,也並非進入了緩存就意味着效率提高。

n  命中率是第一要評估的數據。

n  如何評估進入緩存的數據規模,以及命中率優化,是很是須要細心分析的。

l  實景分析: 前端請求先鏈接緩存,緩存未命中鏈接數據庫,進行查詢,未命中狀態比單純鏈接數據庫查詢多了一次鏈接和查詢的操做;若是緩存命中率很低,則這個額外的操做非但不能提升查詢效率,反而爲系統帶來了額外的負載和複雜性,得不償失。

n  相關評估相似於熱點數據表的介紹。

n  善於利用內存,請注意數據存儲的格式及壓縮算法。

l  Key-value 方案繁多,本培訓文檔暫不展開。

緩存結合數據庫的寫入

l  利用緩存不但能夠減小數據讀取請求,還能夠減小數據庫寫入i/o壓力

l  緩存實時更新,數據庫異步更新

n  緩存實時更新數據,並將更新記錄寫入隊列

n  可使用相似mq的隊列產品,自行創建隊列請注意使用increment來維持隊列序號。

n  不建議使用 get 後處理數據再set的方式維護隊列

l  測試範例:

l  範例1

$var=Memcache_get($memcon,」var」);

 $var++;

memcache_set($memcon,」var」,$var);

這樣一個腳本,使用apache ab去跑,100個併發,跑10000次,而後輸出緩存存取的數據,很遺憾,並非1000,而是5000多,6000多這樣的數字,中間的數字全在 get & set的過程當中丟掉了。

緣由,讀寫間隔中其餘併發寫入,致使數據丟失。

l  範例2

用memcache_increment來作這個操做,一樣跑測試

會獲得完整的10000,一條數據不會丟。

l  結論: 用increment存儲隊列編號,用標記+編號做爲key存儲隊列內容。

n  後臺基於緩存隊列讀取更新數據並更新數據庫

l  基於隊列讀取後能夠合併更新

l  更新合併率是重要指標

l  實戰範例:

某論壇熱門貼,前端不斷有views=views+1數據更新請求。

緩存實時更新該狀態

後臺任務對數據庫作異步更新時,假設執行週期是5分鐘,那麼五分鐘可能會接收到這樣的請求多達數十次乃至數百次,合併更新後只執行一次update便可。

相似操做還包括遊戲打怪,生命和經驗的變化;我的主頁訪問次數的變化等。

n  異步更新風險

l  先後端同時寫,可能致使覆蓋風險。

l  使用後端異步更新,則前端應用程序就不要寫數據庫,不然可能形成寫入衝突。一種兼容的解決方案是,前端和後端不要寫相同的字段。

l  實戰範例:

用戶在線上時,後臺異步更新用戶狀態。

管理員後臺屏蔽用戶是直接更新數據庫。

結果管理員屏蔽某用戶操做完成後,因該用戶在線有操做,後臺異步更新程序再次基於緩存更新用戶狀態,用戶狀態被複活,屏蔽失效。

l  緩存數據丟失或服務崩潰可能致使數據丟失風險。

l  如緩存中間出現故障,則緩存隊列數據不會回寫到數據庫,而用戶會認爲已經完成,此時會帶來比較明顯的用戶體驗問題。

l  一個不完全的解決方案是,確保高安全性,高重要性數據實時數據更新,而低安全性數據經過緩存異步回寫方式完成。此外,使用相對數值操做而不是絕對數值操做更安全。

n  範例:支付信息,道具的購買與得到,一旦丟失會對用戶形成極大的傷害。而經驗值,訪問數字,若是隻丟失了不多時間的內容,用戶仍是能夠容忍的。

n  範例:若是使用 Views=Views+…的操做,一旦出現數據格式錯誤,從binlog中反推是能夠進行數據還原,可是若是使用Views=特定值的操做,一旦緩存中數據有錯誤,則直接被賦予了一個錯誤數據,沒法回溯!

l  異步更新如出現隊列阻塞可能致使數據丟失風險。

l  異步更新一般是使用緩存隊列後,在後臺由cron或其餘守護進程寫入數據庫。

l  若是隊列生成的速度>後臺更新寫入數據庫的速度,就會產生阻塞,致使數據越累計越多,數據庫響應遲緩,而緩存隊列沒法迅速執行,致使溢出或者過時失效。

相關文章
相關標籤/搜索