聊一聊安全且正確使用緩存的那些事 —— 關於緩存可靠性、關乎數據一致性

来源:https://www.cnblogs.com/softwarearch/archive/2022/11/01/16834547.html
-Advertisement-
Play Games

在分散式系統盛行的今天,緩存充當著扛壓屏障的作用,一旦緩存出現問題,對系統影響也是致命的。本文我們一起聊聊如何安全且可靠的使用緩存,聊聊緩存擊穿、緩存雪崩、緩存穿透以及數據一致性、熱點數據淘汰機制等。 ...


大家好,又見面了。


本文是筆者作為掘金技術社區簽約作者的身份輸出的緩存專欄系列內容,將會通過系列專題,講清楚緩存的方方面面。如果感興趣,歡迎關註以獲取後續更新。


在上一篇文檔《聊一聊作為高併發系統基石之一的緩存,會用很簡單,用好才是技術活》中,我們對緩存的龐大體系進行了個初步的探討,浮光掠影般的介紹了本地緩存集中緩存多級緩存的不同形式,也走馬觀花似的初識了緩存設計的關鍵原則與需要關註的典型問題

作為《深入理解緩存原理與實戰設計》系列專欄的第二篇內容,從本篇開始,我們將聚焦緩存體系中的具體場景,分別進行深入的闡述與探討。本篇我們就一起具體地聊一聊緩存使用中需要關註的典型問題可靠性防護措施。

在分散式系統盛行的今天,尤其是在一些用戶體量比較大的互聯網業務系統裡面,緩存充當著扛壓屏障的作用。當前各互聯網系統可以扛住動輒數萬甚至數十萬的併發請求量,緩存機制功不可沒。而一旦緩存出現問題,對系統的影響往往也是致命的。所以在緩存的使用時必須要考慮完備的兜底與災難應對策略。

熱點數據與淘汰策略

大部分服務端使用的抗壓型緩存,為了保證緩存執行速度,普遍都是將數據存儲在記憶體中。而受限於硬體與成本約束,記憶體的容量不太可能像磁碟一樣近乎無限的去隨意擴容使用。對於實際數據量極其龐大且無法將其全部存儲於緩存中的時候,我們需要保證存儲在緩存中的有限部分數據要儘可能的命中更多的請求,即要求緩存中存儲的都是熱點數據

說到這裡,就會存在一個不得不面對的問題:當數據量超級大而緩存的記憶體容量有限的情況下,如果容量滿了該怎麼辦

斷舍離!

緩存實現的時候,必須要有一種機制,能夠保證記憶體中的數據不會無限制增加 —— 也即數據淘汰機制數據淘汰機制,是一個成熟的緩存體系所必備的基礎能力。這裡有個概念需要釐清,即數據淘汰策略與數據過期是兩個不同的概念。

  • 數據過期,是緩存系統的一個正常邏輯,是符合業務預期的一種數據刪除機制。即設定了有效期的緩存數據,過期之後從緩存中移除。

  • 數據淘汰,是緩存系統的一種“有損自保”的降級策略,是業務預期之外的一種數據刪除手段。指的是所存儲的數據沒達到過期時間,但緩存空間滿了,對於新的數據想要加入緩存中時,緩存模塊需要執行的一種應對策略。

我們把緩存當做一個容器,試想一下,一個容器已滿的情況下,繼續往裡面放東西,可以有什麼應對之法?無外乎兩種:

  1. 直接拒絕,因為滿了,放不下了。

  2. 從容器裡面扔掉一些已有內容,然後騰挪出部分空間出來,將新的東西放進來。

進一步地,當決定採用先從容器中扔掉一些已有內容的時候,又會面臨一個新的抉擇,應該扔掉哪些內容?實踐中常用的也有幾種方案:

  1. 一切隨緣,隨機決定。從容器中現有的內容中隨機扔掉剔除一些。

  2. 按需排序,保留常用。即基於LRU策略,將最久沒有被使用過的數據給剔除掉。

  3. 提前過期,淘汰出局。對於一些設置了過期時間的記錄,將其按照過期時間點進行排序,將最近即將過期的數據剔除(類似讓其提前過期)。

  4. 其它策略。自行實現緩存時,除了上述集中常見策略,也可以根據業務的場景構建業務自定義的淘汰策略。比如根據創建日期、根據最後修改日期、根據優先順序、根據訪問次數等等。

一些主流的緩存中間件的淘汰機制大都也是遵循上述的方案來實現的。比如Redis提供了高達6種不同的數據淘汰機制,供使用方按需選擇,將有限的空間僅用來存儲熱點數據,實現緩存的價值最大化。如下:

從上圖可以看出,Redis對隨機淘汰和LRU策略進行的更精細化的實現,支持將淘汰目標範圍細分為全部數據和設有過期時間的數據,這種策略相對更為合理一些。因為一般設置了過期時間的數據,本身就具備可刪除性,將其直接淘汰對業務不會有邏輯上的影響;而沒有設置過期時間的數據,通常是要求常駐記憶體的,往往是一些配置數據或者是一些需要當做白名單含義使用的數據(比如用戶信息,如果用戶信息不在緩存里,則說明用戶不存在),這種如果強行將其刪除,可能會造成業務層面的一些邏輯異常。

緩存雪崩:避免緩存的集中失效

為了限制緩存的數量,很多的緩存記錄都會設置一定的有效期,到期後自動失效。這種在一些批量緩存構建或者全量緩存重建時,因為設置了相同的失效時間,會導致大量甚至全部的緩存數據在短時間內集體失效,這樣會導致大量的請求無法命中緩存而直接流轉到了下游模塊,導致系統癱瘓,也即緩存雪崩

其實解決的思路也很簡單,避免出現集中失效就好咯。如何避免呢?

一種簡單的策略,就是批量載入的場景,將過期時間在一個固定時間段內以毫秒級別進行隨機打散,比如本來要設置每條記錄過期時間為5分鐘,則批量載入的時候可以設置過期時間為5~10分鐘之間的任意一個毫秒數。這樣就可以有效的避免數據集中失效,避免出現緩存雪崩而影響業務穩定。

此外,在一些大型系統裡面,尤其是一些分散式微服務化的系統中,很多情況下都會有多個獨立的緩存服務,而最終持久化數據則集中存儲。如果某個獨立緩存真的出現了緩存雪崩,業務層面應該如何將受損範圍控制在僅自身模塊、避免殃及資料庫以及下游公共服務模塊,進而避免業務出現系統性癱瘓呢?這個就需要結合服務治理中的一些手段來綜合防範了,比如服務降級服務熔斷、以及介面限流等策略。

緩存擊穿:有效的冷數據預熱載入機制

正如前面所提到的,基於記憶體的緩存,受記憶體容量限制,往往都會載入一些熱點數據。而這些熱點緩存數據,可以命中大部分的業務請求。少部分沒有命中緩存的數據,則直接轉由業務模塊進行處理(比如從MySQL裡面進行查詢)。

先來看一個例子:

互動論壇系統,使用Redis作為緩存,緩存最近1年的帖子信息。如果用戶查看的帖子是最近1年的,則直接從Redis中查詢並返回,如果用戶查看的帖子是1年前的,則從MySQL中進行撈取並返回。

因為論壇系統中,大部分人會閱讀或者查看的都是最近新發的帖子,只有極少數的人可能會偶爾“挖墳”查看一年前的歷史帖子。系統上線前會根據冷熱請求的比例與總量情況,評估需要部署的硬體規模,以確保可以支撐住線上正常的訪問請求。但為了避免緩存數據被無限撐滿,一般業務緩存數據都會設置一個過期時間,來保證緩存數據的定期清理與更新。

近段時間,娛樂圈的雷聲不斷,各種新鮮的大瓜也讓吃瓜群眾撐到打嗝。

有一天,娛樂圈當紅流量明星李某某突然被爆料與某網紅存在某些不正當的關係,甚至被爆有多次PC被捕的驚天大瓜,引起粉絲和路人的強烈關註。

吃瓜群眾們群情高漲、熱搜一波蓋過一波、帖子的瀏覽量光速攀升,論壇系統在緩存模塊的加持下,雖然整體CPU和記憶體占用都飆升上去了,倒也相安無事。

但天有不測風雲,恰好這個時候,這條帖子的記錄在緩存中過期被刪除了。然後狂濤巨浪般的請求涌向了後端的資料庫,讓資料庫原地癱瘓,進而陸陸續續殃及了整個論壇系統。這就是典型的一個緩存擊穿的問題。

緩存擊穿和前面提到的緩存雪崩產生的原因其實很相似。區別點在於:

  • 緩存雪崩是大面積的緩存失效導致大量請求涌入資料庫。

  • 緩存擊穿是少量緩存失效的時候恰好失效的數據遭遇大併發量的請求,導致這些請求全部涌入資料庫中。

針對這種情況,我們可以為熱點數據設置一個過期時間續期的操作,比如每次請求的時候自動將過期時間續期一下。此外,也可以在資料庫記錄訪問的時候藉助分散式鎖來防止緩存擊穿問題的出現。當緩存不可用時,僅持鎖的線程負責從資料庫中查詢數據並寫入緩存中,其餘請求重試時先嘗試從緩存中獲取數據,避免所有的併發請求全部同時打到資料庫上。如下圖所示:

對上面的處理過程描述說明如下:

  1. 沒有命中緩存的時候,先請求獲取分散式鎖,獲取到分散式鎖的線程,執行DB查詢操作,然後將查詢結果寫入到緩存中;

  2. 沒有搶到分散式鎖的請求,原地自旋等待一定時間後進行再次重試;

  3. 未搶到鎖的線程,再次重試的時候,先嘗試去緩存中獲取下是否能獲取到數據,如果可以獲取到數據,則直接取緩存已有的數據並返回;否則重覆上述123步驟。

按照上面的策略,經過一番通宵緊急上線操作後,系統終於恢復了正常。正當開發人員長舒了口氣準備下班回家睡覺的時候,系統警報再次響起,系統再次宕機了。

有人扒出了一個2年前的帖子,這個帖子在2年前就已經爆料李某某由於PC被警方拘捕,當時大家都不信。於是這個2年前的帖子得到了眾人狂熱的轉發與閱讀查看。

其實宕機的原因很明顯,因為系統只規劃緩存了最近1年的所有帖子信息,而對超過1年的帖子的操作,都會直接請求到資料庫上。這個2年前的帖子突然爆火導致大量的用戶來請求直接打到了下游,再次將資料庫壓垮 —— 也就是說又一次出現了緩存擊穿,在同一塊石頭上摔倒了兩次!

對於業務中最常使用的旁路型緩存而言,通常會先讀取緩存,如果不存在則去資料庫查詢,並將查詢到的數據添加到緩存中,這樣就可以使得後面的請求繼續命中緩存。

但是這種常規操作存在個“漏洞”,因為大部分緩存容量有限制,且很多場景會基於LRU策略進行記憶體中熱點數據的淘汰,假如有個惡意程式(比如爬蟲)一直在刷歷史數據,容易將記憶體中的熱點數據變為歷史數據,導致真正的用戶請求被打到資料庫層。因而又出現了一些業務場景,會使用類似上面所舉的例子的策略,緩存指定時間段內的數據(比如最近1年),且數據不存在時從DB獲取內容之後也不會回寫到緩存中。針對這種場景,在緩存的設計時,需要考慮到對這種冷數據的加熱機制進行一些額外處理,如設定一個門檻,如果指定時間段內對一個冷數據的訪問次數達到閾值,則將冷數據加熱,添加到熱點數據緩存中,並設定一個獨立的過期時間,來解決此類問題。

比如上面的例子中,我們可以約定同一秒內對某條冷數據的請求超過10次,則將此條冷數據加熱作為臨時熱點數據存入緩存,設定緩存過期時間為30天(一般一個陳年八卦一個月足夠消停下去了)。通過這樣的機制,來解決冷數據的突然竄熱對系統帶來的不穩定影響。如下圖所示:

又是一番緊急上線,終於,系統又恢復正常了。

緩存穿透:合理的防身自保手段

我們的系統對外開放並運行的時候,面對的環境險象環生。你不知道請求是來自一個正常用戶還是某些別有用心的盜竊者、亦或是個純粹的破壞者。

還是上面的論壇的例子:

用戶在互動論壇上點擊帖子並查看內容的時候,界面調用查詢帖子詳情介面時會傳入帖子ID,然後後端基於帖子ID先去緩存中查詢,如果緩存中存在則直接返回數據,否則會嘗試從MySQL中查詢數據並返回。

有些人盯上了論壇的內容,便搞了個爬蟲程式,模擬帖子ID的生成規則,調用查詢詳情介面並傳入自己生成的ID去遍歷挖取系統內的帖子數據,這樣導致很多傳入的ID是無效的、系統內並不存在對應ID的帖子數據。

所以,上面大量無效的ID請求到系統內,因為無法命中緩存而被轉到MySQL中查詢,而MySQL中其實也無法查詢到對應的數據(因為這些ID是惡意生成的、壓根不存在)。大量此類請求頻繁的傳入,就會導致請求一直依賴MySQL進行處理,極易衝垮下游模塊。這個便是經典的緩存穿透問題(緩存穿透緩存擊穿非常相似,區別點在於緩存穿透的實際請求數據在資料庫中也沒有,而緩存擊穿是僅僅在緩存中沒命中,但是在資料庫中其實是存在對應數據的)。

緩存穿透的情況往往出現在一些外部干擾或者攻擊情景中,比如外部爬蟲、比如黑客攻擊等等。為瞭解決緩存穿透的問題,可以考慮基於一些類似白名單的機制(比如基於布隆過濾器的策略,後面系列文章中會詳細探討),當然,有條件的情況下,也可以構建一些反爬策略,比如添加請求簽名校驗機制、比如添加IP訪問限制策略等等。

緩存的數據一致性

緩存作為持久化存儲(如資料庫)的輔助存在,畢竟屬於兩套系統。理想情況下是緩存數據與資料庫中數據完全一致,但是業務最常使用的旁路緩存架構下,在一些分散式或者高併發的場景中,可能會出現緩存不一致的情況。

資料庫更新+緩存更新

在數據有變更的時候,需要同時更新緩存和資料庫兩個地方的數據。因為涉及到兩個模塊的數據更新,所以會有2種組合情況:

  • 先更新緩存,再更新資料庫
  • 先更新資料庫, 再更新緩存

單線程場景下,如果更新緩存和更新資料庫操作都是成功的,則可以保證資料庫與緩存數據是一致的。但是在多線程場景下,由於由於更新緩存和更新資料庫是兩個操作,不具備原子性,就有可能出現多個併發請求交叉的情況,進而導致緩存和資料庫中的記錄不一致的情況。比如下麵這個場景:

這種情況下,有很多的人會選擇結合資料庫的事務來一起控制。因為資料庫有事務控制,而Redis等緩存沒有事務性,所以會在一個DB事務中封裝多個操作,比如先執行資料庫操作,執行成功之後再進行緩存更新操作。這樣如果緩存更新失敗,則直接將當前資料庫的事務回滾,企圖用這種方式來保證緩存數據與DB數據的一致。

乍看似乎沒毛病,但是細想一下,其實是有前提條件的。我們知道資料庫事務的隔離級別有幾種不同的類型,需要保證使用的事務隔離級別為Serializable或者Repeatable Read級別,以此來保證併發更新的場景下不會出現數據不一致問題,但這也降低了併發效率,提高資料庫的CPU負載(隔離級別與併發性能存在一定的關聯關係,見下圖所示)。

所以對於一些讀多寫少、寫操作併發競爭不是特別激烈且對一致性要求不是特別高的情況下,可以採用事務(高隔離級別) + 先更新資料庫再更新緩存的方式來達到數據一致的訴求。

資料庫更新+緩存刪除

在旁路型緩存的讀操作分支中,從緩存中沒有讀取到數據而改為從DB中獲取到數據之後,通常都會選擇將記錄寫入到緩存中。所以我們也可以在寫操作的時候選擇將緩存直接刪除,等待後續讀取的時候重新載入到緩存中。

這樣也會有兩種組合情況:

  • 先刪除緩存,再更新資料庫
  • 先更新資料庫,再刪除緩存

這種也會出現前面說的先操作成功,後操作失敗的問題。
我們先看下先刪除緩存再更新資料庫的操作策略。如果先刪除緩存成功,然後更新資料庫失敗,這種情況下,再次讀取的時候,會從DB裡面將舊數據重新載入回緩存中,數據是可以保持一致的。

雖然更新資料庫失敗這種場景下不會出現問題,但是在資料庫更新成功這種正常情況下,卻可能會在併發場景中出現問題。因為常見的緩存(如Redis)是沒有事務的,所以可能會因為併發處理順序的問題導致最終數據不一致。如下圖所示:

上圖中,因為刪除緩存更新DB非原子操作,所以在併發場景下可能的情況:

  1. A請求執行更新數據操作,先刪除了緩存中的數據;

  2. A這個時候還沒來及往DB中更新數據的時候,B查詢請求恰好進入;

  3. B先查詢緩存發現緩存中沒有數據,又從資料庫中查詢記錄並將記錄寫入緩存中(相當於A剛刪了緩存,B又將原樣數據寫回緩存了);

  4. A執行完成更新邏輯,將變更後的數據寫入到DB中。

一番操作完成後,實際上緩存中存儲的是A修改前的內容,而DB中存儲的是A修改後的數據,兩者因此出現了不一致的問題。這樣導致後面的查詢請求依舊是從緩存中獲取到舊數據,而更新後的新數據無法生效。

那麼,如果採用先更新資料庫,再刪除緩存的策略,又會有何種表現呢?假設資料庫更新成功,但是緩存刪除失敗,我們也可以通過資料庫事務回滾的方式將資料庫更新操作回滾掉,這樣在非併發狀態下,可以確保資料庫與緩存中數據是一致的。

當然,因為基於資料庫事務機制來控制,需要註意下事務的粒度不能過大,避免事務成為阻塞系統性能的瓶頸。在對併發性能要求極高的情況下,可以考慮非事物類的其餘方式來實現,如重試機制、或非同步補償機制、或多者結合方式等。

比如下圖所示的這種策略:

上圖的數據更新處理策略,可以有效的保證數據的最終一致性,降低極端情況可能出現數據不一致的概率,並兜底增加了數據不一致時的自恢復能力。

具體處理邏輯說明如下:

  • 先執行資料庫的數據更新操作。

  • 更新成功,再去執行緩存記錄刪除操作。

  • 緩存如果刪除失敗,則按照預定的重試策略(比如對於指定錯誤碼進行重試,最多重試3次,每次重試間隔100ms等)進行重試。

  • 如果緩存刪除失敗,且重試依舊失敗,則將此刪除事件放入到MQ中。

  • 獨立的補償邏輯,會去消費MQ中的消息事件請求,然後按照補償策略繼續嘗試刪除。

  • 每個緩存記錄設定過期事件,極端情況下,重試刪除、補償刪除等策略全部失敗時,等到數據記錄過期自動從緩存中淘汰,作為兜底策略

這種處理方式,雖然依舊無法百分百保證數據一致,但是整體出現數據不一致情況的概率與可能性非常的小。

實際使用場景中,對於一致性要求不是特別高、且併發量不是特別大的場景,可以選擇基於資料庫事務保證的先更新資料庫再更新/刪除緩存。而對於併發要求較高、且數據一致性要求較好的時候,推薦選擇先更新資料庫,再刪除緩存,並結合刪除重試 + 補償邏輯 + 緩存過期TTL等綜合手段

小結回顧

本篇內容中,我們主要探討了下緩存的使用過程中的一些典型異常的觸發場景防護策略,並一起聊了下保持緩存與資料庫數據一致性的一些保障手段。

關於這些內容,我們本篇就聊到這裡。

那麼,你是否在使用緩存的時候遇到過類似的問題呢?你是如何解決這些問題的呢?你關於這些問題你是否有更好的理解與應對策略呢?歡迎評論區一起交流下,期待和各位小伙伴們一起切磋、共同成長。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Ajax Ajax 即“Asynchronous Javascript And XML”(非同步 JavaScript 和 XML),是指⼀種創建互動式⽹⻚應⽤的⽹⻚開發技術。 Ajax 是⼀種⽤於創建快速動態⽹⻚的技術。 Ajax 是⼀種在⽆需重新載入整個⽹⻚的情況下,能夠更新部分⽹⻚的技術。 通過 ...
  • 多線程 核心點:線程安全 創建線程的兩種方式 線程生命周期 獲取、修改線程名 獲取當前線程對象 靜態方法 sleep() 通過異常終止線程的睡眠 interrupt() 強行終止線程 合理終止線程的方式 瞭解(靜態方法,讓位 yield();實例方法 join(),合併線程) 線程安全 同步非同步 線 ...
  • 網站地址:https://learngitbranching.js.org/?locale=zh_CN 網站以沙盒闖關的方式學習Git各個命令,每次關卡都介紹本次要學習的Git指令,通過沙盒+命令行的方式來引導你通過已經學習到的Git指令來通過關卡。 看首頁,我們可以看到很多關卡,滑鼠放到關卡的數字 ...
  • JavaScript03 11.DOM 官方文檔:https://www.w3school.com.cn/js/js_htmldom.asp 基本介紹: DOM全稱是Document Object Model,文檔對象模型。 當網頁被載入時,瀏覽器會創建頁面的文檔對象模型(Document Obje ...
  • Rule90 第一次見這東西有點莫名其妙,但是其實看懂了之後就是左移和右移相異或,註意這裡使用的是邏輯右移,會自動補零,不能使用算數左移<<<。 module top_module( input clk, input load, input [511:0] data, output reg[511: ...
  • 1.封裝函數,可以判斷一個數字是否為偶數 def func(n): if n%2==0: print("%d是偶數"%n) else: print("%d是奇數"%n) func(11) # 11是奇數 2.封裝函數,可以實現1-n之間所有偶數的列印 def func(n): for i in ra ...
  • 這不光棍節快到了,表弟準備寫一封情書給他的女神,想在光棍節之前脫單。 為了提高成功率,於是跑來找我給他參謀參謀,本來我是不想理他的,不過誰讓他是我表弟呢(請我洗jio),於是教給他程式員的終極浪漫絕招,先假裝給女神拍照,然後再把情書寫到她的照片上列印出來送給她,嘿嘿~ 實現步驟 想要實現把情書寫在像 ...
  • 前言 大家好,我是棧長。 最近,棧長又參加了騰訊雲小伙伴邀請的Techo Day 技術開放日 2.0的線上活動,這一期又是乾貨滿滿,主要是雲原生和微服務方面的,比如:雲原生網關、容器、安全、雲監控、灰度發佈等等,這些內容都與我們現有的微服務系統息息相關。 令棧長印象最深刻的就是微服務灰度發佈這個主題 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...