【搬磚-4】分佈式緩存

Redis、Memcached

Redis

1. 定義

Key-Value類型的內存數據庫,很像memcached,整個數據庫統統加載在內存當中進行操作。

  • 可用作消息隊列:List來做FIFO雙向鏈表,實現一個輕量級的高性能消息隊列服務
  • 可用作tag系統:用SortedSet可以做高性能的tag系統

2. 數據類型

字符串、集合、有序集合、列表、哈希

3. 缺點

受到物理內存的限制,不能用作海量數據的高性能讀寫,因此Redis適合的場景主要侷限在較小數據量的高性能操作和運算上。

4. 緩存雪崩

定義
  1. 緩存中的數據過期時間相同,某一時刻全部失效,所有的數據都走數據庫
  2. Redis全部掛掉,所有的數據都走數據庫
解決辦法
  • 事前:
    1. 分析用戶行爲,讓失效時間離散
    2. 用鎖或單線程寫緩存,避免大量的併發請求落在數據庫上
    3. 讓redis數據永不過期
    4. redis 高可用,主從+哨兵,redis cluster,避免全盤崩潰
  • 事中:
    1. 本地緩存Guaua,Caffeine
    2. hystrix限流,未通過的請求走降級,返回默認值,空白頁等等
  • 事後:
    1. Redis持久化,一旦重啓,自動從磁盤上加載數據,快速恢復緩存數據。

4. 緩存穿透

定義
  1. 黑客惡意攻擊,故意請求數據庫中不存在的數,即緩存中也不存在。
    如數據庫 id 是從 1 開始的,結果黑客發過來的請求 id 全部都是負數。這樣的話,緩存中不會有,請求每次都“視緩存於無物”,直接查詢數據庫。這種惡意攻擊場景的緩存穿透就會直接把數據庫給打死。
解決辦法

每次系統 A 從數據庫中只要沒查到,就寫一個空值到緩存裏去,比如 set -999 UNKNOWN。然後設置一個過期時間,這樣的話,下次有相同的 key 來訪問的時候,在緩存失效之前,都可以直接從緩存中取數據。

5. 緩存擊穿

定義
  1. 某個 key 非常熱點,訪問非常頻繁,處於集中式高併發訪問的情況,當這個 key 在失效的瞬間,大量的請求就擊穿了緩存,直接請求數據庫,就像是在一道屏障上鑿開了一個洞。
解決辦法
  1. 將熱點數據設置爲永遠不過期;
  2. 基於 redis 實現分佈式鎖,等待第一個請求構建完緩存之後,再釋放鎖,進而其它請求才能通過該 key 訪問數據。
    setnx是set if not exist的意思,如果key不存在,則設置key的value,過期時間爲expire_secs,返回1代表key不存在,設置成功。
public String get(key) {
    String value = redis.get(key);
    if (value == null) { //代表緩存值過期
        //設置3min的超時,防止del操作失敗的時候,下次緩存過期一直不能load db
        if (redis.setnx(key_mutex, 1, 3 * 60) == 1) {  //代表設置成功
            value = db.get(key);
            redis.set(key, value, expire_secs);
            redis.del(key_mutex);
       	} else {  //這個時候代表同時候的其他線程已經load db並回設到緩存了,這時候重試獲取緩存值即可
               sleep(50);
               get(key);  //重試
       	}
    } else {
        return value;      
    }
}

5. 爲什麼快

1)Redis是純內存數據庫
2)Redis使用的是非阻塞IO,IO多路複用,使用了單線程來輪詢描述符,將數據庫的開、關、讀、寫都轉換成了事件,減少了線程切換時上下文的切換和競爭。
3)Redis採用了單線程的模型
4)數據結構也幫了不少忙,Redis全程使用hash結構,讀取速度快

6. 使用場景

1) 會話緩存

實現session功能

2) 全頁緩存

基於持久化實現,即使Redis重啓,用戶也不會察覺,以String格式存儲

3) 隊列

由於提供list、set操作,所以用在elk中,避免node日誌丟失,輸入時filebeat,輸出是logstash
也可以提供列表的分頁功能,如博客列表的分頁

4) 排行榜/計數器

Redis在內存中對數字進行遞增或遞減的操作實現的非常好。集合(Set)和有序集合(SorteSet)也使得我們在執行這些操作的時候變的非常簡單,如從排序集合中獲取到排名最靠前的10個用戶

5) 發佈/訂閱

7. Redis的java實現客戶端有哪些

Redisson,Jedis,lettuce等等,官方推薦使用Redisson

8. 持久化

持久化就是把內存的數據寫到磁盤中去,防止服務宕機了內存數據丟失。

  • RDB(Redis DataBase)
  • AOF(Append Only File)
    RDB是隔一段時間把數據快照到磁盤的RDB文件中
    AOF持續記錄用戶的讀寫操作到AOF文件中,Redis重啓之後執行一遍,複製用戶操作。
    上述兩種模式都可以定時更新RDB、AOF文件。
    https://www.cnblogs.com/chenliangcl/p/7240350.html

9. Redid vs Memcached區別

  1. Redis單線程,Memcached多線程
  2. Redis value最大1G,Memcached最大1M
  3. Redis支持string,hash,set,sortedset,list,Memcached只支持string
  4. Redis支持持久化,Memcached不支持

10. 假如 Redis 裏面有1億個 key,其中有10w個 key 是以某個固定的已知的前綴開頭的,如何將它們全部找出來?

使用keys指令 keys start*找到

11. 如果這個 Redis 正在給線上的業務提供服務,那使用 keys 指令會有什麼問題?

Redis 是單線程的。keys 指令會導致線程阻塞一段時間,線上服務會停頓,直到指令執行完畢,服務才能恢復。這個時候可以使用 scan 指令,scan 指令可以無阻塞的提取出指定模式的 key 列表,但是會有一定的重複概率,在客戶端做一次去重就可以了,但是整體所花費的時間會比直接用 keys 指令長。

12. RDB 和 AOF 兩者怎麼選擇?

單獨用 RDB 會丟失很多數據,單獨用 AOF 會導致數據恢復沒 RDB 快,當真出什麼問題時第一時間用 RDB 恢復,然後 AOF 做數據補全即可。

13. redis的主從模式?

master 機器去寫,數據同步給別的 slave 機器,他們都拿去讀,分發掉大量的請求,而且擴容的時候還可以輕鬆實現水平擴容。

14. redis的主從如何同步?

啓動一臺 slave 的時候,他會發送一個 psync 命令給 master ,如果是這個 slave 第一次連接到 master,他會觸發一個全量複製。master 就會啓動一個線程,生成 RDB 快照,還會把新的寫請求都緩存在內存中,RDB 文件生成後,master 會將這個 RDB 發送給 slave 的,slave 拿到之後做的第一件事情就是寫進本地的磁盤,然後加載進內存,然後 master 會把內存裏面緩存的那些新命令都發給 slave。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章