運維面試題-redis(轉載)

1.Redis 是一個基於內存的高性能key-value數據庫。

2.Redis相比memcached有哪些優點:

  • memcached全部的值均是簡單的字符串,redis做爲其替代者,支持更爲豐富的數據類型
  • redis的速度比memcached快不少
  • redis能夠持久化其數據

3.Redis是單線程

redis利用隊列技術將併發訪問變爲串行訪問,消除了傳統數據庫串行控制的開銷php

4.Reids經常使用5種數據類型

  • string,list,set,sorted set,hash

6.Reids6種淘汰策略:

  • noeviction: 不刪除策略, 達到最大內存限制時, 若是須要更多內存, 直接返回錯誤信息。大多數寫命令都會致使佔用更多的內存(有極少數會例外。
  • allkeys-lru:全部key通用; 優先刪除最近最少使用(less recently used ,LRU) 的 key。
  • volatile-lru:只限於設置了 expire 的部分; 優先刪除最近最少使用(less recently used ,LRU) 的 key。
  • allkeys-random:全部key通用; 隨機刪除一部分 key。
  • volatile-random: 只限於設置了 expire 的部分; 隨機刪除一部分 key。
  • volatile-ttl: 只限於設置了 expire 的部分; 優先刪除剩餘時間(time to live,TTL) 短的key。

7.Redis的併發競爭問題如何解決?

單進程單線程模式,採用隊列模式將併發訪問變爲串行訪問。Redis自己沒有鎖的概念,Redis對於多個客戶端鏈接並不存在競爭,利用setnx實現鎖。前端

8.Redis是使用c語言開發的。

9.Redis前端啓動命令

./redis-serverjava

10.Reids支持的語言:

java、C、C#、C++、php、Node.js、Go等。git

11.Redis 持久化方案:

Rdb 和 Aofgithub

12.Redis 的主從複製

持久化保證了即便redis服務重啓也不會丟失數據,由於redis服務重啓後會將硬盤上持久化的數據恢復到內存中,可是當redis服務器的硬盤損壞了可能會致使數據丟失,若是經過redis的主從複製機制就能夠避免這種單點故障,redis

13.Redis是單線程的,但Redis爲何這麼快?

一、徹底基於內存,絕大部分請求是純粹的內存操做,很是快速。數據存在內存中,相似於HashMap,HashMap的優點就是查找和操做的時間複雜度都是O(1);算法

二、數據結構簡單,對數據操做也簡單,Redis中的數據結構是專門進行設計的;數據庫

三、採用單線程,避免了沒必要要的上下文切換和競爭條件,也不存在多進程或者多線程致使的切換而消耗 CPU,不用去考慮各類鎖的問題,不存在加鎖釋放鎖操做,沒有由於可能出現死鎖而致使的性能消耗;數組

四、使用多路I/O複用模型,非阻塞IO;這裏「多路」指的是多個網絡鏈接,「複用」指的是複用同一個線程緩存

五、使用底層模型不一樣,它們之間底層實現方式以及與客戶端之間通訊的應用協議不同,Redis直接本身構建了VM 機制 ,由於通常的系統調用系統函數的話,會浪費必定的時間去移動和請求;

14.爲何Redis是單線程的?

Redis是基於內存的操做,CPU不是Redis的瓶頸,Redis的瓶頸最有多是機器內存的大小或者網絡帶寬。既然單線程容易實現,並且CPU不會成爲瓶頸,那就瓜熟蒂落地採用單線程的方案了(畢竟採用多線程會有不少麻煩!)。

15.Redis info查看命令:info memory

16.Redis內存模型

used_memory:Redis分配器分配的內存總量(單位是字節),包括使用的虛擬內存(即swap);Redis分配器後面會介紹。used_memory_human只是顯示更友好。

used_memory_rss:Redis進程佔據操做系統的內存(單位是字節),與top及ps命令看到的值是一致的;除了分配器分配的內存以外,used_memory_rss還包括進程運行自己須要的內存、內存碎片等,可是不包括虛擬內存。

mem_fragmentation_ratio:內存碎片比率,該值是used_memory_rss used_memory的比值。

mem_allocator:Redis使用的內存分配器,在編譯時指定;能夠是 libc 、jemalloc或者tcmalloc,默認是jemalloc;截圖中使用的即是默認的jemalloc。

17.Redis內存劃分

數據

做爲數據庫,數據是最主要的部分;這部分佔用的內存會統計在used_memory中。

進程自己運行須要的內存

Redis主進程自己運行確定須要佔用內存,如代碼、常量池等等;這部份內存大約幾兆,在大多數生產環境中與Redis數據佔用的內存相比能夠忽略。這部份內存不是由jemalloc分配,所以不會統計在used_memory中。

緩衝內存

緩衝內存包括客戶端緩衝區、複製積壓緩衝區、AOF緩衝區等;其中,客戶端緩衝存儲客戶端鏈接的輸入輸出緩衝;複製積壓緩衝用於部分複製功能;AOF緩衝區用於在進行AOF重寫時,保存最近的寫入命令。在瞭解相應功能以前,不須要知道這些緩衝的細節;這部份內存由jemalloc分配,所以會統計在used_memory中。

內存碎片

內存碎片是Redis在分配、回收物理內存過程當中產生的。例如,若是對數據的更改頻繁,並且數據之間的大小相差很大,可能致使redis釋放的空間在物理內存中並無釋放,但redis又沒法有效利用,這就造成了內存碎片。內存碎片不會統計在used_memory中。

18.Redis對象有5種類型

不管是哪一種類型,Redis都不會直接存儲,而是經過redisObject對象進行存儲。

19.Redis沒有直接使用C字符串

(即以空字符’\0’結尾的字符數組)做爲默認的字符串表示,而是使用了SDS。SDS是簡單動態字符串(Simple Dynamic String)的縮寫。

20.Reidis的SDS在C字符串的基礎上加入了free和len字段

21.Reids主從複製

複製是高可用Redis的基礎,哨兵和集羣都是在複製基礎上實現高可用的。複製主要實現了數據的多機備份,以及對於讀操做的負載均衡和簡單的故障恢復。缺陷:故障恢復沒法自動化;寫操做沒法負載均衡;存儲能力受到單機的限制。

22.Redis哨兵

在複製的基礎上,哨兵實現了自動化的故障恢復。缺陷:寫操做沒法負載均衡;存儲能力受到單機的限制。

23.Reids持久化觸發條件

RDB持久化的觸發分爲手動觸發和自動觸發兩種。

24.Redis 開啓AOF

Redis服務器默認開啓RDB,關閉AOF;要開啓AOF,須要在配置文件中配置:

appendonly yes

25.AOF經常使用配置總結

下面是AOF經常使用的配置項,以及默認值;前面介紹過的這裏再也不詳細介紹。

  • appendonly no:是否開啓AOF
  • appendfilename "appendonly.aof":AOF文件名
  • dir ./:RDB文件和AOF文件所在目錄
  • appendfsync everysec:fsync持久化策略
  • no-appendfsync-on-rewrite no:AOF重寫期間是否禁止fsync;若是開啓該選項,能夠減輕文件重寫時CPU和硬盤的負載(尤爲是硬盤),可是可能會丟失AOF重寫期間的數據;須要在負載和安全性之間進行平衡
  • auto-aof-rewrite-percentage 100:文件重寫觸發條件之一
  • auto-aof-rewrite-min-size 64mb:文件重寫觸發提交之一
  • aof-load-truncated yes:若是AOF文件結尾損壞,Redis啓動時是否仍載入AOF文件

26.RDB和AOF的優缺點

RDB持久化

優勢:RDB文件緊湊,體積小,網絡傳輸快,適合全量複製;恢復速度比AOF快不少。固然,與AOF相比,RDB最重要的優勢之一是對性能的影響相對較小。

缺點:RDB文件的致命缺點在於其數據快照的持久化方式決定了必然作不到實時持久化,而在數據愈來愈重要的今天,數據的大量丟失不少時候是沒法接受的,所以AOF持久化成爲主流。此外,RDB文件須要知足特定格式,兼容性差(如老版本的Redis不兼容新版本的RDB文件)。

AOF持久化

與RDB持久化相對應,AOF的優勢在於支持秒級持久化、兼容性好,缺點是文件大、恢復速度慢、對性能影響大。

27.持久化策略選擇

(1)若是Redis中的數據徹底丟棄也沒有關係(如Redis徹底用做DB層數據的cache),那麼不管是單機,仍是主從架構,均可以不進行任何持久化。

(2)在單機環境下(對於我的開發者,這種狀況可能比較常見),若是能夠接受十幾分鍾或更多的數據丟失,選擇RDB對Redis的性能更加有利;若是隻能接受秒級別的數據丟失,應該選擇AOF。

(3)但在多數狀況下,咱們都會配置主從環境,slave的存在既能夠實現數據的熱備,也能夠進行讀寫分離分擔Redis讀請求,以及在master宕掉後繼續提供服務。

28.redis緩存被擊穿處理機制

使用mutex。簡單地來講,就是在緩存失效的時候(判斷拿出來的值爲空),不是當即去load db,而是先使用緩存工具的某些帶成功操做返回值的操做(好比Redis的SETNX或者Memcache的ADD)去set一個mutex key,當操做返回成功時,再進行load db的操做並回設緩存;不然,就重試整個get緩存的方法

29.Redis還提供的高級工具

像慢查詢分析、性能測試、Pipeline、事務、Lua自定義命令、Bitmaps、HyperLogLog、發佈/訂閱、Geo等個性化功能。

30.Redis經常使用管理命令

# dbsize 返回當前數據庫 key 的數量。
# info 返回當前 redis 服務器狀態和一些統計信息。
# monitor 實時監聽並返回redis服務器接收到的全部請求信息。
# shutdown 把數據同步保存到磁盤上,並關閉redis服務。
# config get parameter 獲取一個 redis 配置參數信息。(個別參數可能沒法獲取)
# config set parameter value 設置一個 redis 配置參數信息。(個別參數可能沒法獲取)
# config resetstat 重置 info 命令的統計信息。(重置包括:keyspace 命中數、
# keyspace 錯誤數、 處理命令數,接收鏈接數、過時 key 數)
# debug object key 獲取一個 key 的調試信息。
# debug segfault 製造一次服務器當機。
# flushdb 刪除當前數據庫中全部 key,此方法不會失敗。當心慎用
# flushall 刪除所有數據庫中全部 key,此方法不會失敗。當心慎用

31.Reids工具命令

# redis-server:Redis 服務器的 daemon 啓動程序
# redis-cli:Redis 命令行操做工具。固然,你也能夠用 telnet 根據其純文本協議來操做
# redis-benchmark:Redis 性能測試工具,測試 Redis 在你的系統及你的配置下的讀寫性能
$ redis-benchmark -n 100000 –c 50 模擬同時由 50 個客戶端發送 100000 個 SETs/GETs 查詢
# redis-check-aof:更新日誌檢查
# redis-check-dump:本地數據庫檢查

32.爲何須要持久化?

因爲Redis是一種內存型數據庫,即服務器在運行時,系統爲其分配了一部份內存存儲數據,一旦服務器掛了,或者忽然宕機了,那麼數據庫裏面的數據將會丟失,爲了使服務器即便忽然關機也能保存數據,必須經過持久化的方式將數據從內存保存到磁盤中。

33.判斷key是否存在

exists key +key名字

34.刪除key

del key1 key2 ...

35.緩存和數據庫間數據一致性問題

分佈式環境下(單機就不用說了)很是容易出現緩存和數據庫間的數據一致性問題,針對這一點的話,只能說,若是你的項目對緩存的要求是強一致性的,那麼請不要使用緩存。咱們只能採起合適的策略來下降緩存和數據庫間數據不一致的機率,而沒法保證二者間的強一致性。合適的策略包括 合適的緩存更新策略,更新數據庫後要及時更新緩存、緩存失敗時增長重試機制,例如MQ模式的消息隊列

36.布隆過濾器

bloomfilter就相似於一個hash set,用於快速判某個元素是否存在於集合中,其典型的應用場景就是快速判斷一個key是否存在於某容器,不存在就直接返回。布隆過濾器的關鍵就在於hash算法和容器大小

37.緩存雪崩問題

存在同一時間內大量鍵過時(失效),接着來的一大波請求瞬間都落在了數據庫中致使鏈接異常。

解決方案:

一、也是像解決緩存穿透同樣加鎖排隊。

二、創建備份緩存,緩存A和緩存B,A設置超時時間,B不設值超時時間,先從A讀緩存,A沒有讀B,而且更新A緩存和B緩存;

38.緩存併發問題

這裏的併發指的是多個redis的client同時set key引發的併發問題。比較有效的解決方案就是把redis.set操做放在隊列中使其串行化,必須的一個一個執行,具體的代碼就不上了,固然加鎖也是能夠的,至於爲何不用redis中的事務,留給各位看官本身思考探究。

39.Redis分佈式

redis支持主從的模式。原則:Master會將數據同步到slave,而slave不會將數據同步到master。Slave啓動時會鏈接master來同步數據。

這是一個典型的分佈式讀寫分離模型。咱們能夠利用master來插入數據,slave提供檢索服務。這樣能夠有效減小單個機器的併發訪問數量

40.讀寫分離模型

經過增長Slave DB的數量,讀的性能能夠線性增加。爲了不Master DB的單點故障,集羣通常都會採用兩臺Master DB作雙機熱備,因此整個集羣的讀和寫的可用性都很是高。讀寫分離架構的缺陷在於,無論是Master仍是Slave,每一個節點都必須保存完整的數據,若是在數據量很大的狀況下,集羣的擴展能力仍是受限於單個節點的存儲能力,並且對於Write-intensive類型的應用,讀寫分離架構並不適合。

41.數據分片模型

爲了解決讀寫分離模型的缺陷,能夠將數據分片模型應用進來。

能夠將每一個節點當作都是獨立的master,而後經過業務實現數據分片。

結合上面兩種模型,能夠將每一個master設計成由一個master和多個slave組成的模型。

42. redis常見性能問題和解決方案:

Master最好不要作任何持久化工做,如RDB內存快照和AOF日誌文件

若是數據比較重要,某個Slave開啓AOF備份數據,策略設置爲每秒同步一次

爲了主從複製的速度和鏈接的穩定性,Master和Slave最好在同一個局域網內

儘可能避免在壓力很大的主庫上增長從庫

43.redis通信協議

RESP 是redis客戶端和服務端以前使用的一種通信協議;RESP 的特色:實現簡單、快速解析、可讀性好

44.Redis分佈式鎖實現

先拿setnx來爭搶鎖,搶到以後,再用expire給鎖加一個過時時間防止鎖忘記了釋放。**若是在setnx以後執行expire以前進程意外crash或者要重啓維護了,那會怎麼樣?**set指令有很是複雜的參數,這個應該是能夠同時把setnx和expire合成一條指令來用的!

45.Redis作異步隊列

通常使用list結構做爲隊列,rpush生產消息,lpop消費消息。當lpop沒有消息的時候,要適當sleep一會再重試。缺點:在消費者下線的狀況下,生產的消息會丟失,得使用專業的消息隊列如rabbitmq等。**能不能生產一次消費屢次呢?**使用pub/sub主題訂閱者模式,能夠實現1:N的消息隊列。

46.Redis中海量數據的正確操做方式

利用SCAN系列命令(SCAN、SSCAN、HSCAN、ZSCAN)完成數據迭代。

47.SCAN系列命令注意事項

  • SCAN的參數沒有key,由於其迭代對象是DB內數據;
  • 返回值都是數組,第一個值都是下一次迭代遊標;
  • 時間複雜度:每次請求都是O(1),完成全部迭代須要O(N),N是元素數量;
  • 可用版本:version >= 2.8.0;

48.Redis 管道 Pipeline

在某些場景下咱們在一次操做中可能須要執行多個命令,而若是咱們只是一個命令一個命令去執行則會浪費不少網絡消耗時間,若是將命令一次性傳輸到 Redis中去再執行,則會減小不少開銷時間。可是須要注意的是 pipeline中的命令並非原子性執行的,也就是說管道中的命令到達 Redis服務器的時候可能會被其餘的命令穿插

49.事務不支持回滾

50.手寫一個 LRU 算法

class LRUCache<K, V\> extends LinkedHashMap<K, V\> {
    private final int CACHE\_SIZE;

    /\*\*
     \* 傳遞進來最多能緩存多少數據
     \*
     \* @param cacheSize 緩存大小
     \*/
    public LRUCache(int cacheSize) {
        // true 表示讓 linkedHashMap 按照訪問順序來進行排序,最近訪問的放在頭部,最老訪問的放在尾部。
        super((int) Math.ceil(cacheSize / 0.75) + 1, 0.75f, true);
        CACHE\_SIZE \= cacheSize;
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V\> eldest) {
        // 當 map中的數據量大於指定的緩存個數的時候,就自動刪除最老的數據。
        return size() \> CACHE\_SIZE;
    }
}

51.多節點 Redis 分佈式鎖:Redlock 算法

獲取當前時間(start)。

依次向 N 個 Redis節點請求鎖。請求鎖的方式與從單節點 Redis獲取鎖的方式一致。爲了保證在某個 Redis節點不可用時該算法可以繼續運行,獲取鎖的操做都須要設置超時時間,須要保證該超時時間遠小於鎖的有效時間。這樣才能保證客戶端在向某個 Redis節點獲取鎖失敗以後,能夠馬上嘗試下一個節點。

計算獲取鎖的過程總共消耗多長時間(consumeTime = end - start)。若是客戶端從大多數 Redis節點(>= N/2 + 1) 成功獲取鎖,而且獲取鎖總時長沒有超過鎖的有效時間,這種狀況下,客戶端會認爲獲取鎖成功,不然,獲取鎖失敗。

若是最終獲取鎖成功,鎖的有效時間應該從新設置爲鎖最初的有效時間減去 consumeTime

若是最終獲取鎖失敗,客戶端應該馬上向全部 Redis節點發起釋放鎖的請求。

52.Redis 中設置過時時間主要經過如下四種方式

  • expire key seconds:設置 key 在 n 秒後過時;
  • pexpire key milliseconds:設置 key 在 n 毫秒後過時;
  • expireat key timestamp:設置 key 在某個時間戳(精確到秒)以後過時;
  • pexpireat key millisecondsTimestamp:設置 key 在某個時間戳(精確到毫秒)以後過時;

53.Reids三種不一樣刪除策略

定時刪除:在設置鍵的過時時間的同時,建立一個定時任務,當鍵達到過時時間時,當即執行對鍵的刪除操做

惰性刪除:聽任鍵過時無論,但在每次從鍵空間獲取鍵時,都檢查取得的鍵是否過時,若是過時的話,就刪除該鍵,若是沒有過時,就返回該鍵

按期刪除:每隔一點時間,程序就對數據庫進行一次檢查,刪除裏面的過時鍵,至於要刪除多少過時鍵,以及要檢查多少個數據庫,則由算法決定。

54.定時刪除

  • 優勢:對內存友好,定時刪除策略能夠保證過時鍵會盡量快地被刪除,並釋放國期間所佔用的內存
  • 缺點:對cpu時間不友好,在過時鍵比較多時,刪除任務會佔用很大一部分cpu時間,在內存不緊張但cpu時間緊張的狀況下,將cpu時間用在刪除和當前任務無關的過時鍵上,影響服務器的響應時間和吞吐量

55.按期刪除

因爲定時刪除會佔用太多cpu時間,影響服務器的響應時間和吞吐量以及惰性刪除浪費太多內存,有內存泄露的危險,因此出現一種整合和折中這兩種策略的按期刪除策略。

  1. 按期刪除策略每隔一段時間執行一次刪除過時鍵操做,並經過限制刪除操做執行的時長和頻率來減小刪除操做對CPU時間的影響。
  2. 定時刪除策略有效地減小了由於過時鍵帶來的內存浪費。

56.惰性刪除

  • 優勢:對cpu時間友好,在每次從鍵空間獲取鍵時進行過時鍵檢查並是否刪除,刪除目標也僅限當前處理的鍵,這個策略不會在其餘無關的刪除任務上花費任何cpu時間。
  • 缺點:對內存不友好,過時鍵過時也可能不會被刪除,致使所佔的內存也不會釋放。甚至可能會出現內存泄露的現象,當存在不少過時鍵,而這些過時鍵又沒有被訪問到,這會可能致使它們會一直保存在內存中,形成內存泄露。

57.Reids 管理工具:Redis Manager 2.0

github地址

58.Redis常見的幾種緩存策略

  • Cache-Aside
  • Read-Through
  • Write-Through
  • Write-Behind

59.Redis Module 實現布隆過濾器

Redis module 是Redis 4.0 之後支持的新的特性,這裏不少國外牛逼的大學和機構提供了不少牛逼的Module 只要編譯引入到Redis 中就能輕鬆的實現咱們某些需求的功能。在Redis 官方Module 中有一些咱們常見的一些模塊,咱們在這裏就作一個簡單的使用。

  • neural-redis 主要是神經網絡的機器學,集成到redis 能夠作一些機器訓練感興趣的能夠嘗試
  • RedisSearch 主要支持一些富文本的的搜索
  • RedisBloom 支持分佈式環境下的Bloom 過濾器

60.Redis 究竟是怎麼實現「附近的人」

使用方式

GEOADD key longitude latitude member \[longitude latitude member ...\]

將給定的位置對象(緯度、經度、名字)添加到指定的key。其中,key爲集合名稱,member爲該經緯度所對應的對象。在實際運用中,當所需存儲的對象數量過多時,可經過設置多key(如一個省一個key)的方式對對象集合變相作sharding,避免單集合數量過多。

成功插入後的返回值:

(integer) N

其中N爲成功插入的個數。

相關文章
相關標籤/搜索