成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

面試官:你知道緩存擊穿、緩存穿透、緩存雪崩嗎?

開發 前端
現在執行 SHOW STATUS LIKE 'Threads_connected'? 去查看MySQL連接線程數會發現數值突然升高,當連接數為1283 左右時,就會發現MySQL服務已經斷開連接或者服務器宕機,也就是緩存雪崩的效果。

前言

又到了一年一度的金三銀四了,大家在面試的時候一定被問到過Redis緩存問題吧。可能有些初學者對“緩存擊穿、緩存穿透、緩存雪崩”這幾個名詞感到陌生,或者了解過但是一時半會沒辦法理解。沒關系,希望通過本文可以讓你輕松理解這些概念并掌握其解決方案,然后在即將到來的金三銀四面試中對你有所幫助。

面試題剖析

花里胡哨的名詞

剛開始我以為“緩存擊穿、緩存穿透、緩存雪崩”說的是3個問題,在各個博客以及視頻的講解下越來越繞。最后我捋了一下,這TM不是一個問題嗎。

為了讓大家也繞一繞,我把各博客對“緩存擊穿、緩存穿透、緩存雪崩”的描述貼在這里:

緩存擊穿是指一個熱點的Key在某個瞬間過期失效了,大量的并發請求在緩存獲取不到數據后直接請求數據庫的現象。

緩存穿透是指查詢一個根本不存在的數據,緩存和數據庫都不會命中,導致每次請求都要到數據庫去查詢。

緩存雪崩指的是緩存由于宕機或者某些原因不能提供服務,導致所有的請求去訪問數據庫,造成數據庫查詢壓力驟增從而宕機。

透過現象看本質

我就非常不理解了,為什么把緩存帶來的一個問題分好幾個場景去描述,還這解決方案,那解決方案的,花里胡哨的增加了大家的理解難度。

在我看來“緩存擊穿、緩存穿透,緩存雪崩”都是在說一個問題,那就是:

緩存沒命中,請求落到數據庫了

而“緩存雪崩”才突出了問題的本質:

沒有緩存的緩沖,數據庫承受不了那么大的壓力,可能會造成宕機等問題。

仔細想想是不是這樣?“緩存擊穿、緩存穿透、緩存雪崩”最終的描述都是請求落到數據庫了,只不過場景不同罷了。但不論哪種場景,在并發高的情況下都會給數據庫帶來壓力。

所以,一個問題分這么多場景,引出這么多名詞,我認為就是在增加大家的理解難度。

面試題解決方案

有問題就會有解決方案,既然看了這篇文章就不要死記硬背了,不然過段時間又會忘記,跟著思路順其自然的理解。

透過現象看本質

對于以上的幾個場景,要解決的問題就是:

如何提高緩存命中率。

也就是盡量避免請求打到數據庫中,尤其是高并發的請求。主要涉及兩個層面:

  1. 緩存組件要可靠:首先要確保緩存組件足夠可靠。
  2. 代碼邏輯要嚴謹:在編寫代碼使用緩存時盡量要把各種場景考慮進去,把問題當作功能的一部分。

像“緩存擊穿、緩存穿透”問題的產生都屬于代碼邏輯不嚴謹。熱點Key怎么能突然消失呢?一個相同的請求怎么能并發訪問到數據庫呢?怎么能允許一個不存在的數據一直請求呢?這些問題在我看來都是不應該發生的。

接下來就針對引起“緩存擊穿、緩存穿透、緩存雪崩”的幾個問題進行剖析解決。

提高緩存命中率一:完美處理熱點Key的消失

熱點數據通常分為可控和不可控。拿電商系統來講,商品分類屬于可控,因為基本上這類數據是通過后臺配置的。而一些商品可能會因為某個原因突然爆火成為熱點數據,這類數據屬于不可控。

不論可控或不可控,熱點數據不可以突然就消失,所以在緩存時要有對應的策略。

  • 像商品分類這類數據就可以不設置過期時間。
  • 而像不可控的熱點數據,要靠一些策略避免其過期,比如通過“看門狗”方式監控熱點Key,快過期時進行“續命”。

可以都不設置過期時間,讓淘汰策略去淘汰數據嗎?

非常不建議。

之前生產環境曾遇到過一個問題:用戶每次登錄之后會莫名其妙退出。經過排查發現,原來是因為Redis服務容量不足,所以最近登錄生成的token一直被淘汰。

雖然沒有報錯,但是給用戶帶來不好的體驗,對產品造成非常不好的影響。

當然,避免不了熱點Key被人為刪除或者其他惡意破壞,當發生這種情況怎么辦?

如果熱點Key不存在緩存中,勢必要去數據庫中查詢了。此時,如果并發請求過高,一定不能讓所有請求打到數據庫,可以對該key進行加鎖處理,獲取到鎖的請求去數據庫訪問并緩存,其他請求則等待該key緩存后再訪問緩存。

因為平時寫代碼會很自然考慮到這一點,所以這也是為什么我剛開始一直不理解“緩存擊穿”這樣的問題。

提高緩存命中率二:避免查詢不存在的數據

造成“查詢不存在的數據”的原因要么是代碼或數據出現問題,要么是遭到惡意的攻擊造成的空命中。總之,這種情況無法完全避免。

但是,我們知道哪些數據會被緩存。這樣的話,我們可以將這些數據放在一個“大集合”中,當請求的數據不存在這個“大集合”時,直接返回NULL即可。

那么問題來了:這個“大集合”放在哪里?肯定不能是數據庫,但是內存容量又是有限的。怎么辦?

有一個叫布隆過濾器的數據結構可以解決這個問題。其主要用于檢測一個元素是否在一個集合里,其原理是:數據通過一組哈希函數映射到位圖中,不論該元素多大都只需要占用1位,從而節省大量空間。如下圖

圖片布隆過濾器原理

這樣的話,我就可以將要緩存的數據先放在布隆過濾器中,當查詢的數據不在布隆過濾器時就可以直接返回NULL了。

感興趣的可以看下 面試官:如何在海量數據中快速檢測某個數據

提高緩存命中率三:降低緩存服務的不可用

降低緩存服務的不可用也就是提高緩存服務的可用性,也就是Redis的高可用,這個沒有什么邏輯就不展開了。

面試題案例

模擬案例

現在,通過代碼模擬一個因“緩存擊穿、緩存穿透、緩存雪崩”,請求并發到MySQL服務上,看會發生什么事。

服務器環境:1核1G

編程語言:Java

案例代碼

public class MainTest {
    private static final String DB_URL = "jdbc:mysql://127.0.0.1:3306/test";
    private static final String USER = "root";
    private static final String PASS = "Mysql123.";

    public static void main(String[] args) throws InterruptedException {

        Timer timer = new Timer();
        TimerTask task = new TimerTask() {
            @Override
            public void run() {
                QueryTask.cacheExist = false;
            }
        };
        timer.schedule(task, 60 * 1000);

        while (true) {

            ExecutorService executorService = Executors.newFixedThreadPool(1500);
            for (int i = 0; i <1500 ; i++) {
                executorService.submit(new MainTest.QueryTask());
                System.gc();
            }
        }
    }

    static class QueryTask implements Runnable {
        static boolean cacheExist = true;

        @Override
        public void run() {
            try {

                if (cacheExist) {
                    System.out.println("訪問緩存");
                } else {
                    Class.forName("com.mysql.jdbc.Driver");
                    Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
                    Statement statement = conn.createStatement();
                    Thread.sleep(3000);
                    String query = "SELECT * FROM test_cache";
                    ResultSet rs = statement.executeQuery(query);
                    while (rs.next()) {
                        int id = rs.getInt("id");
                        String value = rs.getString("value");
                        System.out.println("ID: " + id + ", Value: " + value);
                    }

                    rs.close();
                    statement.close();
                    conn.close();
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

上面的代碼主要做了兩件事:

  1. 模擬1500個線程去查詢數據。cacheExist為true時訪問緩存,為false時去請求數據庫。
  2. 通過定時任務在1分鐘后將cacheExist設置為false。各位就想象成熱點Key的突然消失、查詢不存在的數據、redis的宕機。

案例執行效果

代碼在執行1分鐘后就會報下面的錯誤信息:

com.mysql.jdbc.exceptions.jdbc4.MySQLNonTransientConnectionException: Data source rejected establishment of connection,  message from server: "Too many connections"

這是因為MySQL最大連接數只有151,遠遠低于并發線程數1500。

mysql> show variables like '%max_connections%';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 151   |
+-----------------+-------+

此時,我將MySQL最大連接數設置為1500。

mysql> SET GLOBAL max_connections = 1500;
Query OK, 0 rows affected (0.00 sec)

mysql> show variables like '%max_connections%';
+-----------------+-------+
| Variable_name   | Value |
+-----------------+-------+
| max_connections | 1500  |
+-----------------+-------+

現在執行 SHOW STATUS LIKE 'Threads_connected' 去查看MySQL連接線程數會發現數值突然升高,當連接數為1283 左右時,就會發現MySQL服務已經斷開連接或者服務器宕機,也就是緩存雪崩的效果。

圖片圖片

MySQL壓力過高宕機

總結

面試時不要被花里胡哨的問題迷惑住,要思考一下問題的本質。

“緩存擊穿、緩存穿透、緩存雪崩”問題的本質就是:

當緩存沒命中或失效,并發的請求打到數據庫怎么辦?

通過上面的描述,此類問題要有以下考慮:

  1. 提高緩存命中率。比如,要解決熱點Key的突然消失、要避免查詢不存在的數據等。
  2. 數據庫并發請求要設置合理。太低了浪費資源,太高了就會出現MySQL服務宕機情況。

本文轉載自微信公眾號「Hi程序員」,可以通過以下二維碼關注。轉載本文請聯系Hi程序員公眾號。

責任編輯:武曉燕 來源: Hi程序員
相關推薦

2023-12-06 13:38:00

Redis緩存穿透緩存擊穿

2021-06-05 09:01:01

Redis緩存雪崩緩存穿透

2023-03-10 13:33:00

緩存穿透緩存擊穿緩存雪崩

2019-10-12 14:19:05

Redis數據庫緩存

2019-11-05 14:24:31

緩存雪崩框架

2020-03-16 14:57:24

Redis面試雪崩

2020-09-14 06:57:30

緩存穿透雪崩

2022-05-27 07:57:20

緩存穿透緩存雪崩緩存擊穿

2022-03-08 00:07:51

緩存雪崩數據庫

2021-12-25 22:28:27

緩存穿透緩存擊穿緩存雪崩

2022-11-18 14:34:28

2023-11-10 14:58:03

2022-07-11 07:36:36

緩存緩存雪崩緩存擊穿

2023-04-14 07:34:19

2020-10-13 07:44:40

緩存雪崩 穿透

2020-10-23 10:46:03

緩存雪崩擊穿

2020-12-28 12:37:36

緩存擊穿穿透

2020-03-05 09:09:18

緩存原因方案

2024-04-18 11:43:28

緩存數據庫Redis

2024-04-07 00:00:02

Redis雪崩緩存
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 亚洲网在线| 日韩精品视频一区二区三区 | 91av在线免费观看 | 久草精品视频 | 日日夜夜天天干 | 欧美日韩国产三级 | 亚洲 欧美 另类 综合 偷拍 | 亚洲欧美日韩电影 | 亚洲欧洲日韩 | 久久久久久国模大尺度人体 | 国产一区二区三区高清 | 在线观看国产网站 | 日韩av免费看 | 国产精品免费小视频 | 翔田千里一区二区 | 欧美视频一区二区三区 | 午夜视频在线免费观看 | 华人黄网站大全 | 成人欧美一区二区三区黑人孕妇 | 国产成人一区二 | 黄色大片网站 | 毛片免费看| 中文字幕在线二区 | 国产一级片一区二区 | 秋霞在线一区 | 91国内在线观看 | 久久9精品| 欧美性猛片aaaaaaa做受 | 精品久久久久久久 | 欧美久久视频 | 91精品国产乱码麻豆白嫩 | www.久| 午夜影院黄 | 91中文视频 | 自拍偷拍第一页 | 欧美日韩精品一区二区三区四区 | 色婷婷综合久久久中字幕精品久久 | 中文字幕av在线 | av免费观看网站 | 精品国产伦一区二区三区观看说明 | 国产黄色小视频 |