8張圖帶你分析Redis與MySQL數據一致性問題

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"前言"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"italic"},{"type":"strong"}],"text":"原創公衆號:bigsai"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於Web來說,用戶量和訪問量增加一定程度上推動項目技術和架構的更迭和進步。可能會有以下的一些狀況:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":"1","normalizeStart":1},"content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","text":"頁面併發量和訪問量並不多,MySQL"},{"type":"codeinline","content":[{"type":"text","text":"足以支撐"}]},{"type":"text","text":"自己邏輯業務的發展。那麼其實可以不加緩存。最多對靜態頁面進行緩存即可。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","text":"頁面的併發量顯著增多,數據庫有些壓力,並且有些數據更新頻率較低"},{"type":"codeinline","content":[{"type":"text","text":"反覆被查詢"}]},{"type":"text","text":"或者查詢速度"},{"type":"codeinline","content":[{"type":"text","text":"較慢"}]},{"type":"text","text":"。那麼就可以考慮使用緩存技術優化。對高命中的對象存到key-value形式的Redis中,那麼,如果數據被命中,那麼可以不經過效率很低的db。從高效的redis中查找到數據。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","text":"當然,可能還會遇到其他問題,你還通過靜態頁面緩存頁面、cdn加速、甚至負載均衡這些方法提高系統併發量。這裏就不做介紹。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/85/85ed5751ed1bc4ec6e44e5413343d1f6.png","alt":"image-20201106173835116","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"緩存思想無處不在"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們從一個算法問題開始瞭解緩存的意義。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" "},{"type":"text","marks":[{"type":"strong"}],"text":"問題1:"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"輸入一個數n(n<20),求"},{"type":"codeinline","content":[{"type":"text","text":"n!"}]},{"type":"text","text":";"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"分析1"},{"type":"text","text":": "}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"單單考慮算法,不考慮數值越界問題。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當然我們知道"},{"type":"codeinline","content":[{"type":"text","text":"n!=n * (n-1) * (n-2) * ... * 1= n * (n-1)!"}]},{"type":"text","text":";"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那麼我們可以用一個遞歸函數解決問題。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"static long jiecheng(int n)\n{\n\tif(n==1||n==0)return 1;\n\telse {\n\t return n*jiecheng(n-1);\n\t}\n}"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" 這樣每輸入求一次需要執行"},{"type":"codeinline","content":[{"type":"text","text":"n"}]},{"type":"text","text":"次。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"問題2:"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"輸入t組數據(可能成百上千),每組一個xi(xi<20),求"},{"type":"codeinline","content":[{"type":"text","text":"xi!"}]},{"type":"text","text":";"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"分析2"},{"type":"text","text":":"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果使用"},{"type":"codeinline","content":[{"type":"text","text":"遞歸"}]},{"type":"text","text":",輸入t組數據,每次輸入爲xi,那麼每次都要執行次數爲:"}]}]}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/c3/c323b51171ffe5cc8b0d86ab2de5df4b.png","alt":null,"title":"","style":[{"key":"width","value":"50%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當每次輸入的Xi過大或者t過大都會造成不小的負擔!時間複雜度爲"},{"type":"text","marks":[{"type":"strong"}],"text":"O(n2)"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"那麼能否換個思想的。沒錯、是"},{"type":"codeinline","content":[{"type":"text","text":"打表"}]},{"type":"text","text":"。打表常用於ACM算法中,常用於解決多組輸入輸出、圖論搜索結果、路徑儲存問題。那麼,對於這個求階乘。我們只需要申請一個數組,按照編號從前往後將在需求的數存到數組中,後面再取得時候直接輸出數組值就可以,思想很明確吧:"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"import java.util.Scanner;\npublic class test {\npublic static void main(String[] args) {\n\t// TODO Auto-generated method stub\n\tScanner sc=new Scanner(System.in);\n\tint t=sc.nextInt();\n\tlong jiecheng[]=new long[21];\n\tjiecheng[0]=1;\n\tfor(int i=1;i<21;i++)\n\t{\n\t\tjiecheng[i]=jiecheng[i-1]*i;\n\t}\n for(int i=0;i"},{"type":"codeinline","content":[{"type":"text","text":"內存"}]},{"type":"text","text":"。我們知道大多數關係數據庫是"},{"type":"codeinline","content":[{"type":"text","text":"基於硬盤讀寫"}]},{"type":"text","text":"的,其效率和資源有限,而redis是基於內存的,其讀寫速度差別差別很大。當併發過高關係數據庫性能達到瓶頸時候,就可以策略性將常訪問數據放到Redis提高系統吞吐和併發量。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於常用網站和場景,關係數據庫主要可能慢在兩個地方:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"讀寫IO性能較差"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一個數據可能通過較大量計算得到"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所以使用緩存能夠減少磁盤IO次數和關係數據庫的計算次數。讀取上速度快也從兩個方面體現:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"基於內存,讀寫較快"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用哈希算法直接定位結果不需要計算"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所以對於像樣的,有點規模的網站,緩存是很 "},{"type":"codeinline","content":[{"type":"text","text":"necessary"}]},{"type":"text","text":"的,而Redis無疑是最好的選擇之一。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/16/16fd3d3966013f30c25e113f88a82358.png","alt":"image-20201106180929673","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"需要注意的問題"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"緩存使用不當會帶來很多問題。所以需要對一些細節進行認真考量和設計。當然最難得數據一致性在下面單獨分析。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"是否用緩存"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"項目不能爲了用緩存而用緩存,緩存並一定適合所有場景,如果對"},{"type":"text","marks":[{"type":"strong"}],"text":"數據一致性要求極高"},{"type":"text","text":",又或者"},{"type":"text","marks":[{"type":"strong"}],"text":"數據頻繁更改而查詢並不多"},{"type":"text","text":",又或者根本沒併發量的、查詢簡單的不一定需要緩存,還可能浪費資源使得項目變得臃腫難維護,並且使用redis緩存多多少少可能會遇到數據一致性問題需要考慮。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"緩存合理設計"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在設計緩存的時候,很可能會遇到多表查詢,如果遇到多表查詢緩存的鍵值對就需要合理考慮,是拆分還是合在一起?當然如果組合種類多但常出現的不多也可以直接緩存,具體的設計要根據項目業務需求來看,並沒有一個非常絕對的標準。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"過期策略選擇"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"緩存裝的是相對熱點和常用的數據,Redis資源也是有限,需要選擇一個合理的策略讓緩存過期刪除。我們學過"},{"type":"codeinline","content":[{"type":"text","text":"操作系統"}]},{"type":"text","text":"也知道在計算機的緩存實現中有先進先出的算法("},{"type":"text","marks":[{"type":"strong"}],"text":"FIFO"},{"type":"text","text":");最近最少使用算法("},{"type":"text","marks":[{"type":"strong"}],"text":"LRU"},{"type":"text","text":");最佳淘汰算法("},{"type":"text","marks":[{"type":"strong"}],"text":"OPT"},{"type":"text","text":");最少訪問頁面算法("},{"type":"text","marks":[{"type":"strong"}],"text":"LFR"},{"type":"text","text":")等磁盤調度算法。設計Redis緩存時候也可以借鑑。根據時間來的FIFO是最好實現的。且Redis在"},{"type":"codeinline","content":[{"type":"text","text":"全局key"}]},{"type":"text","text":"支持過期策略。"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"並且過期時間也要根據系統情況合理設置,如果硬件好點當前可以稍微久一點,但是過期時間過久或者過短可能都不太好,過短可能緩存命中率不高,而過久很可能造成很多冷門數據存儲在Redis中不釋放。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"數據一致性問題★"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面其實提到數據一致性問題。如果對一致性要求極高那麼不建議使用緩存。下面稍微梳理一下緩存的數據。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在Redis緩存中經常會遇到數據一致性問題。對於一個緩存,下面羅列幾種情況:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"讀"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"codeinline","content":[{"type":"text","text":"read"}]},{"type":"text","text":":從Redis中讀取,如果Redis中沒有,那麼就從MySQL中獲取更新Redis緩存。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面流程圖描述常規場景,沒啥爭議:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/d2/d292899310d79d72393e1b70ef4c3adb.png","alt":"image-20201106184713215","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"寫1:先更新數據庫,再更新緩存(普通低併發)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/75/75c10073f2ab054943a313b8e6df7f5b.png","alt":"image-20201106184914749","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"更新數據庫信息,再更新Redis緩存。這是常規做法,緩存基於數據庫,取自數據庫。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但是其中可能遇到一些問題,例如上述如果更新緩存失敗(宕機等其他狀況),將會使得數據庫和Redis數據不一致。"},{"type":"text","marks":[{"type":"strong"}],"text":"造成DB新數據,緩存舊數據"},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"寫2:先刪除緩存,再寫入數據庫(低併發優化)"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/01/014d75d59cd837b025f16a81466f3421.png","alt":"image-20201106184958339","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"解決的問題"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這種情況能夠有效避免"},{"type":"text","marks":[{"type":"strong"}],"text":"寫1"},{"type":"text","text":"中防止寫入Redis失敗的問題。將緩存刪除進行更新。理想是讓下次訪問Redis爲空去MySQL取得最新值到緩存中。但是這種情況僅限於低併發的場景中而不適用高併發場景。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"存在的問題"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"寫2雖然能夠"},{"type":"codeinline","content":[{"type":"text","text":"看似寫入Redis異常的問題"}]},{"type":"text","text":"。看似較爲好的解決方案但是在高併發的方案中其實還是有問題的。我們在"},{"type":"text","marks":[{"type":"strong"}],"text":"寫1"},{"type":"text","text":"討論過如果更新庫成功,緩存更新失敗會導致髒數據。我們理想是刪除緩存讓"},{"type":"codeinline","content":[{"type":"text","text":"下一個線程"}]},{"type":"text","text":"訪問適合更新緩存。問題是:如果這"},{"type":"text","marks":[{"type":"strong"}],"text":"下一個線程來的太早、太巧"},{"type":"text","text":"了呢?"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/8e/8efd5b578bdb7e9a6d74c4518c2871f2.png","alt":"image-20201106191042265","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因爲多線程你也不知道誰先誰後,誰快誰慢。如上圖所示情況,將會出現Redis緩存數據和MySQL不一致。當然你可以對key進行"},{"type":"codeinline","content":[{"type":"text","text":"上鎖"}]},{"type":"text","text":"。但是鎖這種重量級的東西對併發功能影響太大,能不用鎖就別用!上述情況就高併發下依然會造成"},{"type":"text","marks":[{"type":"strong"}],"text":"緩存是舊數據,DB是新數據"},{"type":"text","text":"。並且如果緩存沒有過期這個問題會一直存在。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"寫3:延時雙刪策略"}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/e9/e9ffc29b44cc93e241aee35b077bc0c9.png","alt":"image-20201106191310072","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這個就是延時雙刪策略,能過緩解在"},{"type":"text","marks":[{"type":"strong"}],"text":"寫2"},{"type":"text","text":"中在更新MySQL過程中有讀的線程進入造成Redis緩存與MySQL數據不一致。方法就是"},{"type":"text","marks":[{"type":"strong"}],"text":"刪除緩存->更新緩存->延時(幾百ms)(可異步)再次刪除緩存"},{"type":"text","text":"。即使在更新緩存途中發生"},{"type":"text","marks":[{"type":"strong"}],"text":"寫2"},{"type":"text","text":"的問題。造成數據不一致,但是延時(具體實間根據業務來,一般幾百ms)再次刪除也能很快的解決不一致。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但是就寫的方案其實還是有漏洞的,比如第二次刪除錯誤、多寫多讀高併發情況下對MySQL訪問的壓力等等。當然你可以選擇用MQ等消息隊列異步解決。其實實際的解決很難顧及到萬無一失,所以不少大佬在設計這一環節可能會因爲一些紕漏會被噴。作爲菜菜的筆者在這裏就更不獻醜了,各位大佬歡迎貢獻你們的方案。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"寫4:直接操作緩存,定期寫入sql(適合高併發)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當有"},{"type":"codeinline","content":[{"type":"text","text":"一堆併發(寫)"}]},{"type":"text","text":"扔過來的後,前面幾個方案即使使用消息隊列異步通信但也很難給用戶一個舒適的體驗。並且對大規模操作sql對系統也會造成不小的壓力。所以還有一種方案就是直接操作緩存,將緩存定期寫入sql。因爲Redis這種非關係數據庫又基於內存操作KV相比傳統關係型要快很多。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/11/119a03bf70d0129245b3fe7fae14f146.png","alt":"image-20201106192531468","title":null,"style":null,"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"上面適用於高併發情況下業務設計,這個時候以Redis數據爲主,MySQL數據爲輔助。定期插入(好像數據備份庫一樣)。當然,這種高併發往往會因爲業務對"},{"type":"codeinline","content":[{"type":"text","text":"讀"}]},{"type":"text","text":"、"},{"type":"codeinline","content":[{"type":"text","text":"寫"}]},{"type":"text","text":"的順序等等可能有不同要求,可能還要藉助"},{"type":"codeinline","content":[{"type":"text","text":"消息隊列"}]},{"type":"text","text":"以及"},{"type":"codeinline","content":[{"type":"text","text":"鎖"}]},{"type":"text","text":"完成針對業務上對數據和順序可能會因爲高併發、多線程帶來的不確定性和不穩定性,提高業務可靠性。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"總之,越是"},{"type":"codeinline","content":[{"type":"text","text":"高併發"}]},{"type":"text","text":"、越是對"},{"type":"codeinline","content":[{"type":"text","text":"數據一致性要求高"}]},{"type":"text","text":"的方案在數據一致性的設計方案需要"},{"type":"codeinline","content":[{"type":"text","text":"考慮和顧及"}]},{"type":"text","text":"的"},{"type":"codeinline","content":[{"type":"text","text":"越複雜、越多"}]},{"type":"text","text":"。上述也是筆者針對Redis數據一致性問題的學習和自我發散(胡扯)學習。如果有解釋理解不合理或者還請各位大佬指正!"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最後,感覺不錯的話還請一鍵三連,歡迎關注原創公衆號:「"},{"type":"text","marks":[{"type":"strong"}],"text":"bigsai"},{"type":"text","text":"」,在這裏,不僅能學到知識和乾貨,還給你準備了很多進階資料,回覆「bigsai」口令即可領取!"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ed/eded3adec06b5165335f9a0c9b897a1e.jpeg","alt":null,"title":"","style":[{"key":"width","value":"100%"},{"key":"bordertype","value":"none"}],"href":"","fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章