當前位置:首頁 » 數據倉庫 » 資料庫性能瓶頸
擴展閱讀
webinf下怎麼引入js 2023-08-31 21:54:13
堡壘機怎麼打開web 2023-08-31 21:54:11

資料庫性能瓶頸

發布時間: 2022-04-26 17:40:56

『壹』 如何處理查找,處理資料庫的性能瓶頸

具體問題具體分析,舉例來說明為什麼磁碟IO成瓶頸資料庫的性能急速下降了。

為什麼當磁碟IO成瓶頸之後, 資料庫的性能不是達到飽和的平衡狀態,而是急劇下降。為什麼資料庫的性能有非常明顯的分界點,原因是什麼?

相信大部分做資料庫運維的朋友,都遇到這種情況。 資料庫在前一天性能表現的相當穩定,資料庫的響應時間也很正常,但就在今天,在業務人員反饋業務流量沒有任何上升的情況下,資料庫的變得不穩定了,有時候一個最簡單的insert操作, 需要幾十秒,但99%的insert卻又可以在幾毫秒完成,這又是為什麼了?

dba此時心中有無限的疑惑,到底是什麼原因呢? 磁碟IO性能變差了?還是業務運維人員反饋的流量壓根就不對? 還是資料庫內部出問題?昨天不是還好好的嗎?

當資料庫出現響應時間不穩定的時候,我們在操作系統上會看到磁碟的利用率會比較高,如果觀察仔細一點,還可以看到,存在一些讀的IO. 資料庫伺服器如果存在大量的寫IO,性能一般都是正常跟穩定的,但只要存在少量的讀IO,則性能開始出現抖動,存在大量的讀IO時(排除配備非常高速磁碟的機器),對於在線交易的資料庫系統來說,大概性能就雪崩了。為什麼操作系統上看到的磁碟讀IO跟寫IO所帶來的性能差距這么大呢?

如果親之前沒有注意到上述的現象,親對上述的結論也是懷疑。但請看下面的分解。

在寫這個文章之前,作者閱讀了大量跟的IO相關的代碼,如非同步IO線程的相關的,innodb_buffer池相關的,以及跟讀數據塊最相關的核心函數buf_page_get_gen函數以及其調用的相關子函數。為了將文章寫得通俗點,看起來不那麼累,因此不再一行一行的將代碼解析寫出來。

咱們先來提問題。buf_page_get_gen函數的作用是從Buffer bool裡面讀數據頁,可能存在以下幾種情況。

提問. 數據頁不在buffer bool 裡面該怎麼辦?

回答:去讀文件,將文件中的數據頁載入到buffer pool裡面。下面是函數buffer_read_page的函數,作用是將物理數據頁載入到buffer pool, 圖片中顯示

buffer_read_page函數棧的頂層是pread64(),調用了操作系統的讀函數。


通過解析buf_wait_for_read函數的下層函數,我們知道其實通過首先自旋加鎖pin的方式,超過設定的自旋次數之後,進入等待,等待IO完成被喚醒。這樣節省不停自旋pin時消耗的cpu,但需要付出被喚起時的開銷。

再繼續擴展問題: 如果會話線程A 經過物理IO將數據頁1001讀入buffer之後,他需要修改這個頁,而在會話線程A之後的其他的同樣需要訪問數據頁1001的會話線程,即使在數據頁1001被入讀buffer pool之後,將仍然處於等待中。因為在數據頁上讀取或者更新的時候,同樣需要上鎖,這樣才能保證數據頁並發讀取/更新的一致性。

由此可見,當一個高並發的系統,出現了熱點數據頁需要從磁碟上載入到buffer pool中時,造成的延遲,是難以想像的。因此排在等待熱點頁隊列最後的會話線程最後才得到需要的頁,響應時間也就越長,這就是造成了一個簡單的sql需要執行幾十秒的原因。

再回頭來看上面的問題,mysql資料庫出現性能下降時,可以看到操作系統有讀IO。 原因是,在資料庫對數據頁的更改,是在內存中的,然後通過檢查點線程進行非同步寫盤,這個非同步的寫操作是不堵塞執行sql的會話線程的。所以,即使看到操作系統上有大量的寫IO,資料庫的性能也是很平穩的。但當用戶線程需要查找的數據頁不在buffer pool中時,則會從磁碟上讀取,在一個熱點數據頁不是非常多的情況下,我們設置足夠大的innodb_buffer_pool的size, 基本可以緩存所有的數據頁,因此一般都不會出現缺頁的情況,也就是在操作系統上基本看不到讀的IO。 當出現讀的IO時,原因時在執行buf_read_page_low函數,從磁碟上讀取數據頁到buffer pool, 則資料庫的性能則開始下降,當出現大量的讀IO,資料庫的性能會非常差。

『貳』 影響資料庫性能的主要因素有哪些

1、1、調整數據結構的設計。這一部分在開發信息系統之前完成,程序員需要考慮是否使用ORACLE資料庫的分區功能,對於經常訪問的資料庫表是否需要建立索引等。

2、2、調整應用程序結構設計。這一部分也是在開發信息系統之前完成,程序員在這一步需要考慮應用程序使用什麼樣的體系結構,是使用傳統的Client/Server兩層體系結構,還是使用Browser/Web/Database的三層體系結構。不同的應用程序體系結構要求的資料庫資源是不同的。

3、3、調整資料庫SQL語句。應用程序的執行最終將歸結為資料庫中的SQL語句執行,因此SQL語句的執行效率最終決定了ORACLE資料庫的性能。ORACLE公司推薦使用ORACLE語句優化器(Oracle Optimizer)和行鎖管理器(row-level manager)來調整優化SQL語句。

4、4、調整伺服器內存分配。內存分配是在信息系統運行過程中優化配置的,資料庫管理員可以根據資料庫運行狀況調整資料庫系統全局區(SGA區)的數據緩沖區、日誌緩沖區和共享池的大小;還可以調整程序全局區(PGA區)的大小。需要注意的是,SGA區不是越大越好,SGA區過大會佔用操作系統使用的內存而引起虛擬內存的頁面交換,這樣反而會降低系統。

5、5、調整硬碟I/O,這一步是在信息系統開發之前完成的。資料庫管理員可以將組成同一個表空間的數據文件放在不同的硬碟上,做到硬碟之間I/O負載均衡。

6、6、調整操作系統參數,例如:運行在UNIX操作系統上的ORACLE資料庫,可以調整UNIX數據緩沖池的大小,每個進程所能使用的內存大小等參數。

實際上,上述資料庫優化措施之間是相互聯系的。ORACLE資料庫性能惡化表現基本上都是用戶響應時間比較長,需要用戶長時間的等待。但性能惡化的原因卻是多種多樣的,有時是多個因素共同造成了性能惡化的結果,這就需要資料庫管理員有比較全面的計算機知識,能夠敏感地察覺到影響資料庫性能的主要原因所在。另外,良好的資料庫管理工具對於優化資料庫性能也是很重要的。

ORACLE資料庫性能優化工具

常用的資料庫性能優化工具有:

1、1、ORACLE資料庫在線數據字典,ORACLE在線數據字典能夠反映出ORACLE動態運行情況,對於調整資料庫性能是很有幫助的。

2、2、操作系統工具,例如UNIX操作系統的vmstat,iostat等命令可以查看到系統系統級內存和硬碟I/O的使用情況,這些工具對於管理員弄清出系統瓶頸出現在什麼地方有時候很有用。

3、3、SQL語言跟蹤工具(SQL TRACE FACILITY),SQL語言跟蹤工具可以記錄SQL語句的執行情況,管理員可以使用虛擬表來調整實例,使用SQL語句跟蹤文件調整應用程序性能。SQL語言跟蹤工具將結果輸出成一個操作系統的文件,管理員可以使用TKPROF工具查看這些文件。

4、4、ORACLE Enterprise Manager(OEM),這是一個圖形的用戶管理界面,用戶可以使用它方便地進行資料庫管理而不必記住復雜的ORACLE資料庫管理的命令。

5、5、EXPLAIN PLAN——SQL語言優化命令,使用這個命令可以幫助程序員寫出高效的SQL語言。

ORACLE資料庫的系統性能評估

信息系統的類型不同,需要關注的資料庫參數也是不同的。資料庫管理員需要根據自己的信息系統的類型著重考慮不同的資料庫參數。

1、1、在線事務處理信息系統(OLTP),這種類型的信息系統一般需要有大量的Insert、Update操作,典型的系統包括民航機票發售系統、銀行儲蓄系統等。OLTP系統需要保證資料庫的並發性、可靠性和最終用戶的速度,這類系統使用的ORACLE資料庫需要主要考慮下述參數:

l l 資料庫回滾段是否足夠?

l l 是否需要建立ORACLE資料庫索引、聚集、散列?

l l 系統全局區(SGA)大小是否足夠?

l l SQL語句是否高效?

2、2、數據倉庫系統(Data Warehousing),這種信息系統的主要任務是從ORACLE的海量數據中進行查詢,得到數據之間的某些規律。資料庫管理員需要為這種類型的ORACLE資料庫著重考慮下述參數:

l l 是否採用B*-索引或者bitmap索引?

l l 是否採用並行SQL查詢以提高查詢效率?

l l 是否採用PL/SQL函數編寫存儲過程?

l l 有必要的話,需要建立並行資料庫提高資料庫的查詢效率

SQL語句的調整原則

SQL語言是一種靈活的語言,相同的功能可以使用不同的語句來實現,但是語句的執行效率是很不相同的。程序員可以使用EXPLAIN PLAN語句來比較各種實現方案,並選出最優的實現方案。總得來講,程序員寫SQL語句需要滿足考慮如下規則:

1、1、盡量使用索引。試比較下面兩條SQL語句:

語句A:SELECT dname, deptno FROM dept WHERE deptno NOT IN

(SELECT deptno FROM emp);

語句B:SELECT dname, deptno FROM dept WHERE NOT EXISTS

(SELECT deptno FROM emp WHERE dept.deptno = emp.deptno);

這兩條查詢語句實現的結果是相同的,但是執行語句A的時候,ORACLE會對整個emp表進行掃描,沒有使用建立在emp表上的deptno索引,執行語句B的時候,由於在子查詢中使用了聯合查詢,ORACLE只是對emp表進行的部分數據掃描,並利用了deptno列的索引,所以語句B的效率要比語句A的效率高一些。

2、2、選擇聯合查詢的聯合次序。考慮下面的例子:

SELECT stuff FROM taba a, tabb b, tabc c

WHERE a.acol between :alow and :ahigh

AND b.bcol between :blow and :bhigh

AND c.ccol between :clow and :chigh

AND a.key1 = b.key1

AMD a.key2 = c.key2;

這個SQL例子中,程序員首先需要選擇要查詢的主表,因為主表要進行整個表數據的掃描,所以主表應該數據量最小,所以例子中表A的acol列的范圍應該比表B和表C相應列的范圍小。

3、3、在子查詢中慎重使用IN或者NOT IN語句,使用where (NOT) exists的效果要好的多。

4、4、慎重使用視圖的聯合查詢,尤其是比較復雜的視圖之間的聯合查詢。一般對視圖的查詢最好都分解為對數據表的直接查詢效果要好一些。

5、5、可以在參數文件中設置SHARED_POOL_RESERVED_SIZE參數,這個參數在SGA共享池中保留一個連續的內存空間,連續的內存空間有益於存放大的SQL程序包。

6、6、ORACLE公司提供的DBMS_SHARED_POOL程序可以幫助程序員將某些經常使用的存儲過程「釘」在SQL區中而不被換出內存,程序員對於經常使用並且佔用內存很多的存儲過程「釘」到內存中有利於提高最終用戶的響應時間。

CPU參數的調整

CPU是伺服器的一項重要資源,伺服器良好的工作狀態是在工作高峰時CPU的使用率在90%以上。如果空閑時間CPU使用率就在90%以上,說明伺服器缺乏CPU資源,如果工作高峰時CPU使用率仍然很低,說明伺服器CPU資源還比較富餘。

使用操作相同命令可以看到CPU的使用情況,一般UNIX操作系統的伺服器,可以使用sar –u命令查看CPU的使用率,NT操作系統的伺服器,可以使用NT的性能管理器來查看CPU的使用率。

資料庫管理員可以通過查看v$sysstat數據字典中「CPU used by this session」統計項得知ORACLE資料庫使用的CPU時間,查看「OS User level CPU time」統計項得知操作系統用戶態下的CPU時間,查看「OS System call CPU time」統計項得知操作系統系統態下的CPU時間,操作系統總的CPU時間就是用戶態和系統態時間之和,如果ORACLE資料庫使用的CPU時間占操作系統總的CPU時間90%以上,說明伺服器CPU基本上被ORACLE資料庫使用著,這是合理,反之,說明伺服器CPU被其它程序佔用過多,ORACLE資料庫無法得到更多的CPU時間。

資料庫管理員還可以通過查看v$sesstat數據字典來獲得當前連接ORACLE資料庫各個會話佔用的CPU時間,從而得知什麼會話耗用伺服器CPU比較多。

出現CPU資源不足的情況是很多的:SQL語句的重解析、低效率的SQL語句、鎖沖突都會引起CPU資源不足。

1、資料庫管理員可以執行下述語句來查看SQL語句的解析情況:

SELECT * FROM V$SYSSTAT

WHERE NAME IN

('parse time cpu', 'parse time elapsed', 'parse count (hard)');

這里parse time cpu是系統服務時間,parse time elapsed是響應時間,用戶等待時間

waite time = parse time elapsed – parse time cpu

由此可以得到用戶SQL語句平均解析等待時間=waite time / parse count。這個平均等待時間應該接近於0,如果平均解析等待時間過長,資料庫管理員可以通過下述語句

SELECT SQL_TEXT, PARSE_CALLS, EXECUTIONS FROM V$SQLAREA

ORDER BY PARSE_CALLS;

來發現是什麼SQL語句解析效率比較低。程序員可以優化這些語句,或者增加ORACLE參數SESSION_CACHED_CURSORS的值。

2、資料庫管理員還可以通過下述語句:

SELECT BUFFER_GETS, EXECUTIONS, SQL_TEXT FROM V$SQLAREA;

查看低效率的SQL語句,優化這些語句也有助於提高CPU的利用率。

3、3、資料庫管理員可以通過v$system_event數據字典中的「latch free」統計項查看ORACLE資料庫的沖突情況,如果沒有沖突的話,latch free查詢出來沒有結果。如果沖突太大的話,資料庫管理員可以降低spin_count參數值,來消除高的CPU使用率。

內存參數的調整

內存參數的調整主要是指ORACLE資料庫的系統全局區(SGA)的調整。SGA主要由三部分構成:共享池、數據緩沖區、日誌緩沖區。

1、 1、 共享池由兩部分構成:共享SQL區和數據字典緩沖區,共享SQL區是存放用戶SQL命令的區域,數據字典緩沖區存放資料庫運行的動態信息。資料庫管理員通過執行下述語句:

select (sum(pins - reloads)) / sum(pins) "Lib Cache" from v$librarycache;

來查看共享SQL區的使用率。這個使用率應該在90%以上,否則需要增加共享池的大小。資料庫管理員還可以執行下述語句:

select (sum(gets - getmisses - usage - fixed)) / sum(gets) "Row Cache" from v$rowcache;

查看數據字典緩沖區的使用率,這個使用率也應該在90%以上,否則需要增加共享池的大小。

2、 2、 數據緩沖區。資料庫管理員可以通過下述語句:

SELECT name, value FROM v$sysstat WHERE name IN ('db block gets', 'consistent gets','physical reads');

來查看資料庫數據緩沖區的使用情況。查詢出來的結果可以計算出來數據緩沖區的使用命中率=1 - ( physical reads / (db block gets + consistent gets) )。

這個命中率應該在90%以上,否則需要增加數據緩沖區的大小。

3、 3、 日誌緩沖區。資料庫管理員可以通過執行下述語句:

select name,value from v$sysstat where name in ('redo entries','redo log space requests');查看日誌緩沖區的使用情況。查詢出的結果可以計算出日誌緩沖區的申請失敗率:

申請失敗率=requests/entries,申請失敗率應該接近於0,否則說明日誌緩沖區開設太小,需要增加ORACLE資料庫的日誌緩沖區。

『叄』 如何優化資料庫的性能

--資料庫性能調優
--1.聚集索引、主鍵
--2.盡量不要用臨時表
--3.多多使用事務
--4.表設計要規范
--5.不要使用游標
--6.避免死鎖
--7.不要打開大數據集
--8.最好不要select *
--9.不要使用text數據類型,用varchar
--10.不要給諸如「性別」列創建索引
--11.不要使用Insert插入大量的數據
--12.盡量用join代替where,因為where進行全表搜索

『肆』 怎樣查出SQLServer的性能瓶頸

自定義性能監控

在這一點上,我假定你已經閱讀了,或者至少瀏覽了所有監控步驟的建議。我猜你也許讀了一些,但那些真正不適合於你。既然大部分的SQLServer安裝稍微有點不同,那麼這是有意義的。因此我建議你為你特定的環境自定義這個監控,添加或刪除一些步驟使其更適合你的需求。

使用Word或Excel維護你的監控列表

當你對你的每一個SQLServer進行監控時,你需要一個方法去記錄結果。當你有大量的選項時,從這一系列的文章里復制適合的監控列表到你的Word或Excel文檔作為起點是比較快速的方法。你可能要為每個伺服器創建一個單獨的監控列表。如果你決定為你的監控表格使用Excel的話,你能輸入所有的監控列表項目作為行,每一個監控的伺服器作為單獨的列。這樣你能快速的查看每個SQLServer的結果。

設置SQLServer和資料庫的優先順序

如果你管理大量的SQLServer和資料庫,你也許不知道從哪兒開始性能監控。理論上,你應該設置SQLServer和資料庫的優先順序,一些需要立即進行最多的性能監控,而其他的則不必進行那麼多的監控。這會幫助你決定從哪兒開始。最可能的是,你將不會立即監控全部。相反,要在能監控的時候監控,按照從最重要到最不重要的順序進行。

謹記性能監控的關鍵

當對SQLServer進行監控的時候

,記住目的是分辨並糾正容易的問題。但是,正如你所料,你將可能也分辨出一些更難於解決的問題。為了幫助你更好的管理有限的時間,你現在需要著眼於那些容易的問題,把困難的問題留到容易的問題先解決完之後。所以在你執行監控和分辨問題時,按照難易程度分類設置它們的優先順序,將困難的問題留待你有足夠時間處理它們的時候。

不要過早行動

當你執行監控時,你可能會急於對偶然遇到的問題進行糾正和修改。大多數情況下,那樣做可能不是問題。但理論上,最好先執行監控,然後基於你的發現,決定正式動手解決你分辨出的問題,然後系統地實現它們。

一個推薦步驟,但或許會招來很多疑問

理想情況下,如有很多的時間,在伺服器上執行一個性能基準是一個好的想法,然後執行監控,做任何需要的更改,再執行另一個性能基準去看看有什麼情況發生。這會立即讓你知道你所做的是否有幫助,大多數情況下,沒有做正確的事。雖然這個建議被強烈的推薦,也許從時間來看不很實際。但如果你有時間的話,應該認真考慮。

另一個推薦步驟,但或許也會招來很多疑問

在執行監控之後,你也許發現在單個的SQLServer上所有需要的更改僅只有一兩個,但在其他SQLServer上,也許需要做一打的更改。如果有那麼的更改要做,不要立刻全部實現它們,僅僅一次一個或幾個的更改也許是一個明智的選擇。這樣,你能夠看看每個或每批更改對伺服器產生的效果。如果你一次做了很多的更改,那麼遇到問題時,你將不會知道是由哪個更改引起的問題,這要求你回滾所有的更改,然後一個一個的測試它們直到找到問題所在為止。

這個建議不會有太多疑問

如果你要做更改的伺服器是有緊要事務的生產伺服器,你要對你做的更改倍加小心。理論上,你應該在生產伺服器應用更改之前在測試用的SQLServer上測試所有的更改。如果你不實踐,那麼每次僅做一個更改,確信如果有任何問題你知道怎樣回滾更改。另外,試著選取一天中不很忙的時候做更改,萬一有問題的話。

有一個取消計劃

你因監控而做出的大多數更改應該能夠很容易的回滾。但一些也許不那麼容易。在那些情況下,你需要有一個萬一需要的取消計劃。例如,在你做出任何關鍵的更改之前備份系統和用戶資料庫。那樣,即使出現問題,你也能將你的伺服器恢復到更改之前的狀態。我不是嚇唬你不要做更改,但你總應該有所准備。

記錄所有更改

當你基於性能監控做出更改時,確定你對所有的更改做了記錄。這樣,即使後來有什麼問題,你也能更容易的找出錯誤所在。最容易記錄下你的更改的方法可能就是把它們添加到你的監控表格里,或者其他你用來收集監控信息的文檔里。

每年都要執行SQLServer的性能監控

許多SQLServer(並非全部)隨著時間而改變。設置改變,打了SP補丁,甚至數據也改變了。所有的這些都會影響性能。確定你SQLServer最優性能的最好方法是做一個手工的性能監控。

『伍』 如何提高資料庫性能,減少資料庫伺服器壓力瓶頸一兩個

如果是在本身配置上的原因(配置低,產品老化等),可以考慮增加配置,提高性能;如果是各種應用造成的資源浪費引起,那麼可以對伺服器做一些優化,關掉一些不必須要的應用。伺服器廠商也就那麼多個,比如國內的正睿、浪潮、曙光、聯想等,國外的戴爾、惠普等

『陸』 有哪些手段可以查看mysql資料庫性能瓶頸

通過sysbench的oltp_read_write測試來模擬業務壓力、以此來給指定的硬體環境配置一份比較合理的MySQL配置文件。


環境介紹

硬體配置


軟體環境



優化層級與指導思想

優化層級

MySQL資料庫優化可以在多個不同的層級進行,常見的有:

  • SQL優化

  • 參數優化

  • 架構優化

  • 本文重點關註:參數優化

    指導思想

  • 日誌先行 -- 一個事務能否成功提交的關鍵是日誌是否成功落盤,與數據沒有太大的關系;也就是說對寫的優化可以表述為各方面的資源向寫操作傾斜。

  • 瓶頸分析 -- 通過show global status 的各個計數器的值基本上就能分析出當前瓶頸所在,再結合一些簡單的系統層面的監控工具如top iostat 就能明確瓶頸。

  • 整體性能是「讀」&「寫」之間的再平衡。

『柒』 如何查看 mysql 性能瓶頸

通過sysbench的oltp_read_write測試來模擬業務壓力、以此來給指定的硬體環境配置一份比較合理的MySQL配置文件。


環境介紹

硬體配置

軟體環境


優化層級與指導思想

優化層級

MySQL資料庫優化可以在多個不同的層級進行,常見的有:

  • SQL優化

  • 參數優化

  • 架構優化

  • 本文重點關註:參數優化

    指導思想

  • 日誌先行 -- 一個事務能否成功提交的關鍵是日誌是否成功落盤,與數據沒有太大的關系;也就是說對寫的優化可以表述為各方面的資源向寫操作傾斜。

  • 瓶頸分析 -- 通過show global status 的各個計數器的值基本上就能分析出當前瓶頸所在,再結合一些簡單的系統層面的監控工具如top iostat 就能明確瓶頸。

  • 整體性能是「讀」&「寫」之間的再平衡。

『捌』 資料庫寫不進去數據,可能跟linux性能有關系嗎

資料庫寫不進數據,不一定是和linux性能有關,一般如下幾種可能:
1:資料庫寫入語句錯誤
2:資料庫所在的磁碟滿
3:資料庫(表)被加鎖
4:資料庫性能到達瓶頸無法響應
5:linux性能到達瓶頸無法響應(一般是磁碟IO的瓶頸)
6:執行資料庫寫入的程序有問題
通過分析資料庫日誌,系統日誌,寫入程序的日誌,可以分析出問題的。

『玖』 一個關系資料庫系統的最大的性能瓶頸在哪方面

(30)[答案]B [考點]資料庫設計基礎 [評析] 此題為資料庫的基本概念,如果你完全沒學過資料庫,可以對照辦工軟體的電子表格進行如下理解: 選擇:我們根據某條件選擇出一行或多行元組(一個元組即為二維表中的一行) 投影:按欄位(也稱屬性,比如學生關系(學號,姓名,出生年月,性別),學號、姓名……都是屬性)選取一列或多列(一個二維表中所有元組在某一列或幾列上截取出來)。 連接:2個或2個以上的表連接組成一張新的表,通常有條件連接。比如學生關系(學號,姓名,系號),又有一張系表(系號,系名,主任),2張表可以合並為一張這樣的表(學號,姓名,系號,系名,主任)

『拾』 資料庫瓶頸方面什麼技術提供了

介面響應時長過長
上個月我們經理把我叫了過去,說我們的產品的某些頁面打開速度太慢了,要等好幾秒。我十分驚訝,因為我把所有的功能都看過一遍的,沒有哪個功能效率這么低下。我看了一下數據才明白,新客戶的數據是老客戶的數十倍,導致資料庫查詢時長翻了更多倍。

請求技術支撐
於是我找到技術中台負責人,希望他們能提供一套資料庫緩存訪問方案。當查詢數據時不優先查詢資料庫,而是查詢緩存來提高查詢效率。得到的答復是近期太忙,沒時間整這個。

團隊自己做臨時緩存
由於技術中台暫時沒有時間來做支撐,所以我們團隊只能暫時做一個臨時緩存方案。於是我讓我們團隊的人員自行把高頻查詢並且不太會變動的數據,如部門結構和用戶信息等數據,在查詢的時候先從redis中讀取,redis中沒有的話再從資料庫中讀取並存入redis中。
這個流程看著沒什麼問題,但有非常重要的一點需要確認,就是如果資料庫中的數據修改了,怎麼去通知redis更新數據。換而言之,也就是如何保證緩存數據和資料庫數據的一致性?

緩存數據一致性
其實這個問題上到軟體,下到硬體工程師都會遇到,也都有不同的解決方案。因為我大學的專業是嵌入式系統,所以對於硬體的緩存也有所耳聞。如cpu需要保證自身的多級高速緩存間的數據一致性,以及緩存和內存間的數據一致性等。而我們軟體因為查詢數據的來源不同,所以對應的每級緩存也不同。

多級緩存概念
多級緩存或者多級存儲這個概念可能不是很好理解,大致意思是說我們需要的數據,我們第一時間去哪裡找,那麼這個地方就叫做一級緩存。如果一級緩存沒找到,再去找的地方就被稱作二級緩存,以此類推。那為什麼叫做緩存?大致是為了突出一個臨時存儲以及訪問速度快的特點吧,大約就是數據暫緩存儲區以及查找緩沖區的一個意思。

臨時的兩級存儲框架
說回到我們的項目,我們將常訪問的數據從資料庫中復制到redis中一份,每次訪問先從redis中讀取,讀不到再從資料庫中讀取。所以可以認為我們當前的一級緩存是redis,二級緩存是資料庫。當數據量沒有到非常龐大的時候,只要保證了緩存一致性,用這套方案也不會有什麼問題。但如果從redis訪問的數據頻率過高,超過了redis所在伺服器的帶寬呢?

接入緩存框架的兩個問題
第一個問題就是我最開始說的,數據一致性問題。第二個是剛提到的redis帶寬成為瓶頸的問題。如果將我遇到的這兩個問題更通用性地梳理一遍,那就是各級緩存間的數據一致性保證方法和緩存遇到瓶頸時如何去提升。

數據一致性方案
我能想到的有兩種解決方案,第一種是定時刷新,第二種是修改通知。如果對於允許有讀取到舊數據的場景,那麼定時刷新肯定是比較好的方案,因為實現起來簡單。但是如果不希望讀到舊數據,那麼就需要在數據被修改的時候通知到上一級緩存,讓上一級緩存把舊數據刪了。當下一次需要用到數據的時候,上一級緩存就會來重新獲取數據並保存了。但是這種情況也有問題,如果不提前存到緩存中會導致第一次訪問時過慢。如果提前存入緩存會導致當上一級緩存被清空時,大量請求數據會同時到達下一級緩存那裡,造成擁塞。但這些也都是有對應的解決方案的。

緩存遇到瓶頸
還記得我們為什麼要引入緩存么?因為資料庫遇到了瓶頸。那引入的redis緩存遇到瓶頸了怎麼辦呢?同樣的解決方案,引入更快速的緩存。但別忘了,一定要有保證數據一致性的方案。Redis這一級別的緩存,可以認為是放在內存中的,難道我們要引入比內存更高效的cpu的高速緩存么?我們軟體也不具備這個權利啊。有一點我剛才有提到,redis瓶頸是因為帶寬的原因,因為redis是一個用網線連接的「內存」。所以,我們可以使用的更高效的緩存就是本地內存。於是,後期的優化方案可以改為一級緩存為內存,二級緩存為redis,三級緩存為資料庫。

最後
如果是以前,我一定會按照我的想法全部自己寫一套緩存框架。但是後來發現我在大學時期自己想出來的一些好的框架,都有對應的更好用的開源框架(對於這個之後我可以專門寫一篇博客)。之後到底是我們團隊自己寫,還是用現有的開源的框架,已經不重要了。重要的是我在這次遇到的這個問題中收獲了自己的思考。