架構思維:緩存層場景實戰_讀緩存(下)

文章目錄

  • Pre
  • 業務場景
  • 緩存存儲數據的時機與常見問題解決方案
    • 1. 緩存讀取與存儲邏輯
    • 2. 高并發下的緩存問題及解決方案
    • 3. 緩存預熱(減少冷啟動問題)
  • 緩存更新策略(雙寫問題)
    • 1. 先更新緩存,再更新數據庫(不推薦)
    • 2. 先刪除緩存,再更新數據庫(不推薦)
    • 3. 先更新數據庫,再更新緩存(不推薦)
    • 4. 先更新數據庫,再刪除緩存(Cache-Aside模式 推薦?)
    • 5. 延遲雙刪(先刪緩存→更新DB→再刪緩存)(最佳實踐?)
    • 總結:如何選擇緩存更新策略
    • 最終建議
  • 緩存高可用設計核心要點與監控方案
    • 1、緩存高可用設計的5大核心要點
    • 2、緩存監控關鍵指標與工具
    • 3、總結

在這里插入圖片描述


Pre

Java避坑案例 - 高并發場景下的分布式緩存策略

Redis - 緩存設計深度解析:穿透、并發、雪崩與熱點策略

深入理解分布式技術 - 先更新數據庫,還是先更新緩存

架構思維:讀緩存 - 減少數據庫讀操作壓力


業務場景

某系統商品詳情頁因疊加推薦、成交記錄、優惠活動等功能,導致每次訪問需執行數十條SQL,平均響應時間從3.61秒惡化至15.53秒。初期考慮本地緩存(如Guava),但測算發現5萬商品數據需750GB內存(30節點×25GB),成本過高。最終采用分布式緩存方案,將數據集中存儲(如Redis),所有服務節點共享同一緩存源,避免冗余存儲,顯著提升訪問速度至毫秒級,同時降低硬件成本。優化后,異步加載非核心數據(如成交記錄)進一步減輕實時查詢壓力。

技術選型完成后,開始考慮緩存的一些具體問題,先從緩存何時存儲數據入手


緩存存儲數據的時機與常見問題解決方案

1. 緩存讀取與存儲邏輯

  1. 先查緩存:請求到達時,優先從緩存(如Redis)讀取數據。
  2. 緩存未命中:若數據不存在或過期,則查詢數據庫,并將結果寫入緩存。
  3. 返回數據:最終返回緩存中的數據給調用方。

2. 高并發下的緩存問題及解決方案

這種邏輯唯一麻煩的地方是,當用戶發來大量的并發請求時,它們會發現緩存中沒有數據,那么所有請求會同時擠在第2)步,此時如果這些請求全部從數據庫讀取數據,就會讓數據庫崩潰。

數據庫的崩潰可以分為3種情況。

  • 1)單一數據過期或者不存在,這種情況稱為緩存擊穿

    解決方案:第一個線程如果發現Key不存在,就先給Key加鎖,再從數據庫讀取數據保存到緩存中,最后釋放鎖。如果其他線程正在讀取同一個Key值,那么必須等到鎖釋放后才行。關于鎖的問題前面已經講過,此處不再贅述。

  • 2)數據大面積過期或者Redis宕機,這種情況稱為緩存雪崩

    解決方案:設置緩存的過期時間為隨機分布或設置永不過期即可。

  • 3)一個惡意請求獲取的Key不在數據庫中,這種情況稱為緩存穿透

    比如正常的商品ID是從100000到1000000(10萬到100萬之間的數值),那么惡意請求就可能會故意請求2000000以上的數據。這種情況如果不做處理,惡意請求每次進來時,肯定會發現緩存中沒有值,那么每次都會查詢數據庫,雖然最終也沒在數據庫中找到商品,但是無疑給數據庫增加了負擔。這里給出兩種解決辦法。
    ①在業務邏輯中直接校驗,在數據庫不被訪問的前提下過濾掉不存在的Key。
    ②針對惡意請求的Key存放一個空值在緩存中,防止惡意請求騷擾數據庫。

故,總結如下:

  • 緩存擊穿(單一Key失效)

    • 問題:熱點Key失效時,大量請求同時穿透到數據庫。
    • 解決:加鎖(如Redis分布式鎖),僅允許一個線程查詢DB并回填緩存,其余線程等待。
  • 緩存雪崩(大量Key同時失效或Redis宕機)

    • 問題:緩存大面積失效,導致數據庫被壓垮。
    • 解決
      • 設置隨機過期時間(如30分鐘±5分鐘)。
      • 緩存永不過期,后臺異步更新(如定時任務)。
  • 緩存穿透(惡意查詢不存在的數據)

    • 問題:惡意請求查詢不存在的Key,導致頻繁訪問DB。
    • 解決
      1. 業務層校驗:如商品ID范圍檢查(100000~1000000)。
      2. 緩存空值:對不存在的Key存儲null或占位符,并設置較短過期時間。

3. 緩存預熱(減少冷啟動問題)

上面這些邏輯都是在確保查詢數據的請求已經過來后如何適當地處理,如果緩存數據找不到,再去數據庫查詢,最終是要占用服務器額外資源的。那么最理想的就是在用戶請求過來之前把數據都緩存到Redis中。這就是緩存預熱。

其具體做法就是在深夜無人訪問或訪問量小的時候,將預熱的數據保存到緩存中,這樣流量大的時候,用戶查詢就無須再從數據庫讀取數據了,將大大減小數據讀取壓力。

故,總結如下:

  • 時機:在低峰期(如凌晨)提前加載熱點數據到緩存。
  • 方式
    • 定時任務掃描DB并寫入緩存。
    • 啟動時自動加載核心數據。

緩存更新策略(雙寫問題)

關于緩存何時存數據的問題就討論完了,接下來開始討論更新緩存的問題,這部分內容因涉及雙寫(緩存+數據庫),所以會花費一些篇幅。

  • 先更新DB還是緩存?
    • Cache-Aside(旁路緩存):先更新DB,再刪除緩存(推薦)。
    • Write-Through(寫穿透):先更新緩存,再同步到DB(一致性高,但性能較低)。
    • Write-Behind(寫回):先更新緩存,異步刷回DB(高性能,但可能丟數據)。

在緩存更新時,我們需要考慮 數據庫與緩存的一致性,同時避免 并發問題性能瓶頸。以下是 5種常見的緩存更新策略,分析它們的優缺點,并給出推薦方案。


1. 先更新緩存,再更新數據庫(不推薦)

對于這個組合,會遇到這種情況:假設第二步更新數據庫失敗了,要求回滾緩存的更新,這時該怎么辦呢?Redis不支持事務回滾,除非采用手工回滾的方式,先保存原有數據,然后再將緩存更新回原來的數據,這種解決方案有些缺陷。

這里簡單舉個例子。
1)原來緩存中的值是a,兩個線程同時更新庫存。
2)線程A將緩存中的值更新成b,且保存了原來的值a,然后更新數據庫。
3)線程B將緩存中的值更新成c,且保存了原來的值b,然后更新數據庫。
4)線程A更新數據庫時失敗了,它必須回滾,那現在緩存中的值更新成什么呢?理論上應該更新成c,因為數據庫中的值是c,但是,線程A里面無從獲得c這個值。

如果在線程A更新緩存與數據庫的整個過程中,先把緩存及數據庫都鎖上,確保別的線程不能更新,是否可行?當然是可行的。但是其他線程能不能讀取?

假設線程A更新數據庫失敗回滾緩存時,線程C也加入進來,它需要先讀取緩存中的值,這時又返回什么值?

看到這個場景,是不是有點兒熟悉?不錯,這就是典型的事務隔離級別場景。所以就不推薦這個組合,因為此處只是需要使用一下緩存,而這個組合就要考慮事務隔離級別的一些邏輯,成本太大。接著考慮別的組合。

故, 總結如下:

流程

  1. 更新緩存
  2. 更新數據庫
線程A 緩存 數據庫 線程B 線程C 初始狀態:緩存=a,數據庫=a 1. 更新緩存為b(保存舊值a) 2. 更新緩存為c(保存舊值b) 3. 嘗試更新數據庫為b 4. 更新失敗(需回滾) 此時緩存最新值是c\n但線程A只記錄舊值a 5. 嘗試回滾為a(覆蓋當前c值) 6. 讀取緩存值(得到a) 數據不一致:數據庫值為a\n緩存被錯誤回滾為a\n實際數據庫應為c(線程B已更新成功) 如果使用全局鎖: 加鎖(阻塞線程B/C) 更新失敗后回滾 解鎖 讀請求被阻塞直到解鎖 線程A 緩存 數據庫 線程B 線程C

問題

  • 事務回滾困難:如果數據庫更新失敗,緩存無法自動回滾(Redis不支持事務回滾)。
  • 并發問題
    • 線程A更新緩存為 b,線程B更新緩存為 c,最終緩存可能是 bc,而數據庫可能是另一個值。
    • 需要加鎖,但會降低性能。

結論:? 不推薦,容易導致數據不一致。


2. 先刪除緩存,再更新數據庫(不推薦)

使用這種方案,即使更新數據庫失敗了也不需要回滾緩存。這種做法雖然巧妙規避了失敗回滾的問題,卻引出了兩個更大的問題。

1)假設線程A先刪除緩存,再更新數據庫。在線程A完成更新數據庫之前,后執行的線程B反而超前完成了操作,讀取Key發現沒有數據后,將數據庫中的舊值存放到了緩存中。線程A在線程B都完成后再更新數據庫,這樣就會出現緩存(舊值)與數據庫的值(新值)不一致的問題。

2)為了解決一致性問題,可以讓線程A給Key加鎖,因為寫操作特別耗時,這種處理方法會導致大量的讀請求卡在鎖中。

以上描述的是典型的高可用和一致性難以兩全的問題,如果再加上分區容錯就是CAP(一致性Consistency、可用性Availability、分區容錯性Partition Tolerance)了,這里不展開討論,接下來繼續討論另外3種組合


故, 總結如下:

流程

  1. 刪除緩存
  2. 更新數據庫
線程A 緩存 數據庫 線程B 初始狀態:緩存=a(舊值),數據庫=a 1. 刪除緩存Key 2. 開始更新數據為b(未提交) 3. 讀取Key(未命中) 4. 查詢舊值a 5. 寫入緩存值為a(舊值回填) 6. 提交更新為b(完成) 數據不一致:緩存=a(舊值)\n數據庫=b(新值) 加鎖方案導致的問題: 獲取Key鎖(阻塞線程B) 更新期間占用鎖 讀請求等待鎖釋放 釋放鎖 線程A 緩存 數據庫 線程B

問題

  • 緩存與數據庫不一致(舊數據問題):
    • 線程A刪除緩存 → 線程B查詢緩存未命中 → 從DB讀取舊數據并寫入緩存 → 線程A更新DB,導致緩存是舊數據。
  • 高并發下緩存擊穿:大量請求穿透到數據庫。

解決方案

  • 加鎖(如分布式鎖),但會影響性能。

結論:? 不推薦,容易導致緩存與數據庫不一致。


3. 先更新數據庫,再更新緩存(不推薦)

對于組合3,同樣需要考慮兩個問題。
1)假設第一步(更新數據庫)成功,第二步(更新緩存)失敗了怎么辦?
因為緩存不是主流程,數據庫才是,所以不會因為更新緩存失敗而回滾第一步對數據庫的更新。此時一般采取的做法是重試機制,但重試機制如果存在延時還是會出現數據庫與緩存不一致的情況,不好處理。

2)假設兩個線程同時更新同一個數據,線程A先完成了第一步,線程B先完成了第二步怎么辦?線程A把值更新成a,線程B把值更新成b,此時數據庫中的最新值是b,因為線程A先完成了第一步,后完成第二步,所以緩存中的最新值是a,數據庫與緩存的值還是不一致,這個邏輯還是有問題的。

因此,也不建議采用這個組合

故, 總結如下:

流程

  1. 更新數據庫
  2. 更新緩存
線程A 線程B 數據庫 緩存 場景1:緩存更新失敗導致不一致 1. 更新數據為a(成功) 2. 嘗試更新緩存為a(失敗) 3. 讀取數據(命中舊值b) 場景2:并發更新導致順序錯亂 1. 更新數據為a(完成) 2. 更新數據為b(完成) 3. 更新緩存為b(先完成) 4. 更新緩存為a(后完成) 最終狀態:數據庫=b\n緩存=a(不一致) 重試機制問題 更新成功 更新失敗 異步重試更新(延遲) 在此期間讀取舊值 線程A 線程B 數據庫 緩存

問題

  • 緩存更新失敗:如果第二步失敗,緩存仍是舊數據。
  • 并發問題
    • 線程A更新DB為 a,線程B更新DB為 b → 線程B先更新緩存為 b,線程A后更新緩存為 a,導致緩存是 a,而DB是 b

結論:? 不推薦,仍可能不一致。


4. 先更新數據庫,再刪除緩存(Cache-Aside模式 推薦?)

針對組合4,先看看它能不能解決組合3的第二個問題。
假設兩個線程同時更新同一個數據,線程A先完成第一步,線程B先完成第二步怎么辦?
線程A把值更新成a,線程B把值更新成b,此時數據庫中的最新值是b,因為線程A先完成了第一步,所以第二步誰先完成已經不重要了,因為都是直接刪除緩存數據。這個問題解決了。

那么,它能解決組合3的第一個問題嗎?假設第一步成功,第二步失敗了怎么辦?
這種情況的出現概率與組合3相比明顯低不少,因為刪除比更新容易多了。雖然這個組合方案不完美,但出現一致性問題的概率較低。

故, 總結如下:

流程

  1. 更新數據庫
  2. 刪除緩存
線程A 線程B 數據庫 緩存 線程C 場景:組合4(先更新DB再刪緩存) 1. 更新數據為a(成功) 2. 刪除Key(成功) 3. 更新數據為b(成功) 4. 刪除Key(成功) 對比組合3(先更新DB再更新緩存) 更新為a(成功) 更新為b(成功) 更新為b(先完成) 更新為a(后完成) 組合4的核心優勢 5. 讀Key(未命中) 6. 查詢最新值b 7. 回填b(強制重新加載) 線程A 線程B 數據庫 緩存 線程C

優點

  • 緩存刪除失敗概率低(刪除比更新更簡單)。
  • 并發問題較少
    • 即使線程A更新DB后未及時刪除緩存,線程B讀取舊數據,但下次查詢會重新加載最新數據。

問題

  • 短暫不一致
    • 線程A更新DB后,未刪除緩存前,線程B可能讀到舊數據。
  • 緩存擊穿:刪除緩存后,大量請求穿透到DB。

解決方案

  • 延遲雙刪(組合5)可進一步降低不一致概率。
  • 緩存預熱減少擊穿影響。

結論:? 推薦,相比前3種方案更可靠。


5. 延遲雙刪(先刪緩存→更新DB→再刪緩存)(最佳實踐?)

除了組合3會碰到的問題,組合4還會碰到別的問題嗎?

是的。假設線程A要更新數據,先完成第一步更新數據庫,在線程A刪除緩存之前,線程B要訪問緩存,那么取得的就是舊數據。這是一個小小的缺陷。

那么,以上問題有辦法解決嗎?

還有一個方案,就是先刪除緩存,再更新數據庫,再刪除緩存。這個方案其實和先更新數據庫,再刪除緩存差不多,因為還是會出現類似的問題:假設線程A要更新數據庫,先刪除了緩存,這一瞬間線程C要讀緩存,先把數據遷移到緩存;然后線程A完成了更新數據庫的操作,這一瞬間線程B也要訪問緩存,此時它訪問到的就是線程C放到緩存里面的舊數據。

不過組合5出現類似問題的概率更低,因為要剛好有3個線程配合才會出現問題(比先更新數據庫,再刪除緩存的方案多了一個需要配合的線程)。

但是相比于組合4,組合5規避了第二步刪除緩存失敗的問題——組合5是先刪除緩存,再更新數據庫,假設它的第三步“再刪除緩存”失敗了,也沒關系,因為緩存已經刪除了。

其實沒有一個組合是完美的,它們都有讀到臟數據(這里指舊數據)的可能性,只不過概率不同。根據以上分析,組合5相對來說是比較好的選擇。

不過這個組合也有一些問題要考慮,具體如下。

  • 1)刪除緩存數據后變相出現緩存擊穿,此時該怎么辦?此問題在前面已經給出了方案。
  • 2)刪除緩存失敗如何重試?這個重試可以做得復雜一點,也可以做得簡單一點。簡單一點就是使用try…catch…,假設刪除緩存失敗了,在catch里面重試一次即可;復雜一點就是使用一個異步線程不斷重試,甚至用到MQ。不過這里沒有必要大動干戈。而且異步重試的延時大,會帶來更多的讀臟數據的可能性。所以僅僅同步重試一次就可以了。
  • 3)不可避免的臟數據問題。雖然這個問題在組合5中出現的概率已經大大降低了,但是還是有的。關于這一點就需要與業務溝通,畢竟這種情況比較少見,可以根據實際業務情況判斷是否需要解決這個瑕疵。

任何一個方案都不是完美的,但如果剩下1%的問題需要花好幾倍的代價去解決,從技術上來講得不償失,這就要求架構師去說服業務方,去平衡技術的成本和收益。

故, 總結如下:

流程

  1. 刪除緩存
  2. 更新數據庫
  3. 延遲幾百毫秒后,再次刪除緩存
線程A 緩存 數據庫 線程B 線程C 延遲雙刪核心流程 1. 第一次刪除緩存 2. 更新數據為b 3. 延遲500ms后二次刪除緩存 第一次刪除后的讀穿透 4. 讀緩存(未命中) 5. 查詢舊值a(未提交) 6. 回填舊值a 二次刪除后的強一致性 7. 讀緩存(未命中) 8. 查詢新值b(已提交) 9. 回填新值b 最終狀態:緩存=b,數據庫=b(強一致) 線程A 緩存 數據庫 線程B 線程C

優點

  • 減少不一致窗口:第二次刪除能清理可能的臟數據。
  • 避免緩存更新失敗問題:即使第二次刪除失敗,緩存已被第一次刪除,不會長期存儲舊數據。

問題

  • 短暫不一致仍存在(但概率更低)。
  • 實現稍復雜:需要引入延遲任務(如MQ、定時任務)。

適用場景

  • 對一致性要求較高的電商、金融等業務。

結論:? 最佳實踐,比方案4更可靠。 延遲雙刪通過兩次刪除操作建立安全窗口,在工程實踐上實現了性能與一致性的最佳平衡,是分布式系統緩存更新的首選方案 .


總結:如何選擇緩存更新策略

方案描述一致性推薦度
1?? 先更新緩存,再更新DB易回滾問題? 差? 不推薦
2?? 先刪緩存,再更新DB舊數據問題? 差? 不推薦
3?? 先更新DB,再更新緩存并發問題?? 一般? 不推薦
4?? 先更新DB,再刪緩存較可靠? 較好? 推薦
5?? 延遲雙刪最可靠? 最佳??? 最佳

最終建議

  • 普通業務:使用 方案4(先更新DB,再刪緩存),簡單可靠。
  • 高一致性業務(如支付、庫存):使用 方案5(延遲雙刪),減少不一致窗口。
  • 補充優化
    • 緩存預熱減少擊穿影響。
    • 異步重試(如MQ)處理刪除失敗情況。
    • 加鎖(如Redis分布式鎖)防止并發問題。

沒有完美方案,但 方案4和5 在大多數場景下能平衡 性能與一致性


緩存高可用設計核心要點與監控方案


1、緩存高可用設計的5大核心要點

  1. 負載均衡(讀擴展)

    • 目標:通過多節點分攤讀請求壓力。
    • 方案
      • 使用代理層(如Twemproxy、Redis Cluster)自動分配請求。
      • 客戶端分片(如一致性哈希)直接路由請求。
  2. 數據分片(寫擴展)

    • 目標:分散數據存儲與寫壓力。
    • 方案
      • Redis Cluster:自動分片(16384個槽),支持動態擴縮容。
      • Codis:Proxy層分片,兼容原生Redis協議。
  3. 數據冗余(容災)

    • 目標:單節點故障時數據不丟失。
    • 方案
      • 主從復制(Replication):主節點寫,從節點讀+備份。
      • 多副本存儲:如Redis Cluster的每個分片包含主從節點。
  4. 故障自動轉移(Failover)

    • 目標:節點宕機時自動切換,保障服務可用。
    • 方案
      • 哨兵模式(Sentinel):監控主節點,自動選舉新主。
      • Redis Cluster內置Failover:主節點宕機時,從節點自動升級。
  5. 一致性保證

    • 目標:數據分片、故障恢復時避免臟數據。
    • 挑戰:Redis默認異步復制,可能丟失少量數據。
    • 解決方案
      • WAIT命令:同步復制(犧牲性能)。
      • 業務層補償:如定時校對DB與緩存。

推薦架構

  • 中小規模:Redis Sentinel + 主從復制。
  • 大規模:Redis Cluster(內置分片、Failover)。

2、緩存監控關鍵指標與工具

  1. 核心監控指標

    • 命中率keyspace_hits / (keyspace_hits + keyspace_misses),低于80%需優化緩存策略。
    • 內存使用used_memory,避免超過最大內存(maxmemory)觸發淘汰。
    • 慢查詢slowlog分析耗時命令(如KEYS *、大Value操作)。
    • 延遲redis-cli --latency,超過1ms需排查網絡或阻塞命令。
    • 連接數connected_clients,防止連接泄漏。
  2. 開源監控工具

    • RedisLive:實時儀表盤展示關鍵指標。
    • Prometheus + Grafana:自定義報警與可視化。
    • Redis-exporter:為Prometheus提供Redis指標。
  3. 自研監控建議

    • 定時巡檢腳本:檢查INFO命令輸出的關鍵指標。
    • 自動化報警:如內存使用率超90%、命中率低于70%時觸發告警。

3、總結

  • 高可用核心:分片擴展寫、冗余保障讀、自動Failover。
  • 監控關鍵點:命中率、內存、慢查詢、延遲。
  • 工具選型
    • 快速上手:RedisLive。
    • 長期運維:Prometheus+Grafana。

最終建議:根據業務規模選擇Redis Sentinel或Cluster,并配套監控告警體系,確保緩存穩定支撐業務高峰。

在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/79058.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/79058.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/79058.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Odrive源碼分析(七) 逆park變換

Odrive源碼分析(七) Park逆變換 Odrive中FOC部分代碼分散在各個對象中,并不是集中在某一塊,所以試圖在某一段代碼就能得到FOC全貌是不現實的。 先看下FOC的整個流程: 控制變量到三相電流輸出的關鍵部分分為Park逆變換和SVPWM。本文主要討論…

Flink Hive Catalog最佳實踐

Flink Hive Catalog 最佳實踐 一、配置與初始化 依賴管理 Hive Connector 版本對齊:需確保 flink-sql-connector-hive 版本與 Hive 版本嚴格匹配(如 Hive 3.1.3 對應 flink-sql-connector-hive-3.1.3_2.12),同時添加 Hadoop 遮蔽…

通過人類和機器人演示進行聯合逆向和正向動力學的機器人訓練

25年3月來自哥倫比亞大學的論文“Train Robots in a JIF: Joint Inverse and Forward Dynamics with Human and Robot Demonstrations”。 在大型機器人演示數據集上進行預訓練是學習各種操作技能的強大技術,但通常受到收集以機器人為中心數據的高成本和復雜性限制…

金融簡單介紹及金融詐騙防范

在當今社會,金融學如同一股無形卻強大的力量,深刻影響著我們生活的方方面面。無論是個人的日常收支、投資理財,還是國家的宏觀經濟調控,都與金融學緊密相連。? 一、金融學的概念? 金融學,簡單來說,是研…

JavaScript `new Date()` 方法移動端 `兼容 ios`,ios環境new Date()返回NaN

在 iOS 環境下,new Date() 方法會返回 NaN,這通常是由于時間字符串的格式問題。iOS 的 Date 構造函數對時間字符串的格式要求比其他平臺更嚴格。 原因:ios端不兼容“-”為連接符的時間。 解決辦法: 替換時間格式 IOS 不支持某…

【網絡編程】網絡編程基礎和Socket套接字

目錄 一. 網絡編程的概念 二. 網絡編程基礎知識 1)網卡 2)接收端和發送端 3)客戶端和服務器 4)請求和響應 5)客戶端和服務器的交互模式 三. Socket 套接字模型 一. 網絡編程的概念 網絡編程 是通過編程實現不同…

盛水最多的容器問題詳解:雙指針法與暴力法的對比與實現

文章目錄 問題描述方法探討方法一:暴力法(Brute Force)思路代碼實現復雜度分析 方法二:雙指針法(Two Pointers)思路正確性證明代碼實現復雜度分析 方法對比總結 摘要 盛水最多的容器(Container …

圖論-BFS搜索圖/樹-最短路徑問題的解決

續上篇~圖論--DFS搜索圖/樹-CSDN博客 先看第一次學習的博客!!👇👇👇👇 👉 有一些問題是廣搜 和 深搜都可以解決的,例如島嶼問題,這里我們記dfs的寫法就好啦,…

C++進階——C++11_智能指針

目錄 1、問題引入 2、RAII和智能指針 3、C標準庫的智能指針 3.1 auto_ptr (不好) 3.2 unique_ptr 3.3 shared_ptr (重點) 3.4 weak_ptr (重點) 4、shared_ptr的循環引用問題(重點) 5、shared_ptr的線程安全問題 6、C11智能指針和boost的關系 7、內存泄漏 7.1 什么是…

數據庫的基本原則

數據庫的核心原則 原子性與持久性:原子性(Atomicity)確保一個事務中的所有操作要么全部完成,要么完全不執行,不會出現部分完成的情況。持久性(Durability)則保證一旦事務提交成功,即…

Java設計模式實戰:裝飾模式在星巴克咖啡系統中的應用

一、裝飾模式簡介 裝飾模式(Decorator Pattern)是一種結構型設計模式,它允許向一個現有的對象添加新的功能,同時又不改變其結構。這種模式創建了一個裝飾類,用來包裝原有的類,并在保持類方法簽名完整性的前…

使用MPI-IO并行讀寫HDF5文件

使用MPI-IO并行讀寫HDF5文件 HDF5支持通過MPI-IO進行并行讀寫,這對于大規模科學計算應用非常重要。下面我將提供C和Fortran的示例程序,展示如何使用MPI-IO并行讀寫HDF5文件。 準備工作 在使用MPI-IO的HDF5之前,需要確保: HDF5庫編譯時啟用…

七、自動化概念篇

自動化測試概念 自動化測試是把以人為驅動的測試行為轉化為機器執行的一種過程。通常,在設計了測試用例并通過評審之后,由測試人員根據測試用例中描述的過程一步步執行測試,得到實際結果與期望結果的比較。在此過程中,為了節省人…

redis cluster 的通信機制

Redis Cluster 的通信機制是其分布式架構的核心,基于 Gossip 協議 和 Cluster Bus 實現節點間狀態同步與數據協調。以下是其通信機制的核心要點: 二進制協議:數據以字節流形式編碼(如Protobuf、Thrift、MQTT、Gossip)。…

CTF web入門之文件上傳

知識點 產生文件上傳漏洞的原因 原因: 對于上傳文件的后綴名(擴展名)沒有做較為嚴格的限制 對于上傳文件的MIMETYPE(用于描述文件的類型的一種表述方法) 沒有做檢查 權限上沒有對于上傳的文件目錄設置不可執行權限,(尤其是對于shebang類型的文件) 對于web server對于上傳…

PhotoShop學習09

1.彎曲鋼筆工具 PhotoShop提供了彎曲鋼筆工具可以直觀地創建路徑,只需要對分段推拉就能夠進行修改。彎曲港幣工具位于工具面板中的鋼筆工具里,它的快捷鍵為P。 在使用前,可以把填充和描邊選為空顏色,并打開路徑選項,勾…

tsconfig.json配置不生效

說明一下我遇到的問題,這是我的配置文件代碼的 {"compilerOptions": {"module": "none","target": "ES5","outFile": "./dist/bundle.js"} } 和我想象不同的是,我編譯成 js 沒…

源代碼加密之零日攻擊

# SDC沙盒:有效防御零日攻擊的多層防護體系 在當今復雜多變的網絡安全環境中,零日攻擊已成為企業面臨的重大威脅之一。零日攻擊利用尚未被公眾發現或尚未被軟件供應商修復的漏洞進行攻擊,具有極高的隱蔽性和破壞性。SDC沙盒作為一種先進的數…

記錄一次TDSQL網關夯住故障

環境信息: TDSQL-MySQL同城雙中心集群,集中式實例,一主三副本,每個中心兩個db副本,每個中心一個VIP,V每個IP通過硬件做負載均衡指向該中心兩個proxy,操作系統為麒麟v10 arm。 故障描述&#xf…

代碼隨想錄八股訓練營完結總結

! 40天的訓練營,我總結了自己完整的八股文,后續在面試過程中可以補充 很感謝這次訓練營,真的高頻,在面試中能擊中60%以上,剩下的就靠平時的積累了。 感謝訓練營的小伙伴,很多次想偷懶&#x…