近乎所有與Java相關的面試都會問到緩存的問題,基礎一點的會問到什么是“二八定律”白热、什么是“熱數(shù)據(jù)和冷數(shù)據(jù)” 敛助,復雜一點的會問到緩存雪崩、緩存穿透屋确、緩存預熱纳击、緩存更新、緩存降級等問題攻臀,這些看似不常見的概念焕数,都與我們的緩存服務器相關,一般常用的緩存服務器有Redis刨啸、Memcached等堡赔,而筆者目前最常用的也只有Redis這一種。
如果你在以前面試的時候還沒有遇到過面試官問你:為什么說Redis是單線程或者Redis為什么這么快设联?善已,那么你看到這篇文章的時候灼捂,你應該覺得是一件很幸運的事情!如果你剛好是一位高逼格的面試官换团,你也可以拿這道題去面試對面“望穿秋水”般的小伙伴悉稠,測試一下他的掌握程度。
好啦艘包!步入正題的猛!我們先探討一下Redis是什么,Redis為什么這么快想虎、然后在探討一下為什么Redis是單線程的秉溉?
?
? ? 一窿侈、Redis簡介
Redis是一個開源的內(nèi)存中的數(shù)據(jù)結構存儲系統(tǒng)季眷,它可以用作:數(shù)據(jù)庫墓猎、緩存和消息中間件胡诗。
它支持多種類型的數(shù)據(jù)結構邓线,如字符串(Strings)、散列(Hash)煌恢、列表(List)骇陈、集合(Set)、有序集合(Sorted Set或者是ZSet)與范圍查詢瑰抵,Bitmaps你雌,Hyperloglogs 和地理空間(Geospatial)索引半徑查詢。其中常見的數(shù)據(jù)結構類型有:String二汛、List婿崭、Set、Hash肴颊、ZSet這5種氓栈。
Redis 內(nèi)置了復制(Replication)、LUA腳本(Lua scripting)婿着、 LRU驅(qū)動事件(LRU eviction)授瘦、事務(Transactions) 和不同級別的磁盤持久化(Persistence),并通過 Redis哨兵(Sentinel)和自動分區(qū)(Cluster)提供高可用性(High Availability)竟宋。
Redis也提供了持久化的選項提完,這些選項可以讓用戶將自己的數(shù)據(jù)保存到磁盤上面進行存儲。根據(jù)實際情況丘侠,可以每隔一定時間將數(shù)據(jù)集導出到磁盤(快照)徒欣,或者追加到命令日志中(AOF只追加文件),他會在執(zhí)行寫命令時蜗字,將被執(zhí)行的寫命令復制到硬盤里面打肝。您也可以關閉持久化功能官研,將Redis作為一個高效的網(wǎng)絡的緩存數(shù)據(jù)功能使用。
Redis不使用表闯睹,他的數(shù)據(jù)庫不會預定義或者強制去要求用戶對Redis存儲的不同數(shù)據(jù)進行關聯(lián)戏羽。
數(shù)據(jù)庫的工作模式按存儲方式可分為:硬盤數(shù)據(jù)庫和內(nèi)存數(shù)據(jù)庫。Redis 將數(shù)據(jù)儲存在內(nèi)存里面楼吃,讀寫數(shù)據(jù)的時候都不會受到硬盤 I/O 速度的限制始花,所以速度極快。
1孩锡、硬盤數(shù)據(jù)庫的工作模式:?
2酷宵、內(nèi)存數(shù)據(jù)庫的工作模式:
看完上述的描述,對于一些常見的Redis相關的面試題躬窜,是否有所認識了浇垦,例如:什么是Redis、Redis常見的數(shù)據(jù)結構類型有哪些荣挨、Redis是如何進行持久化的等男韧。
? ? 二、Redis到底有多快
Redis采用的是基于內(nèi)存的采用的是單進程單線程模型的KV 數(shù)據(jù)庫默垄,由C語言編寫此虑,官方提供的數(shù)據(jù)是可以達到100000+的QPS(每秒內(nèi)查詢次數(shù))。這個數(shù)據(jù)不比采用單進程多線程的同樣基于內(nèi)存的 KV 數(shù)據(jù)庫 Memcached 差口锭!有興趣的可以參考官方的基準程序測試:https://redis.io/topics/benchmarks
橫軸是連接數(shù)朦前,縱軸是QPS。此時鹃操,這張圖反映了一個數(shù)量級韭寸,希望大家在面試的時候可以正確的描述出來,不要問你的時候荆隘,你回答的數(shù)量級相差甚遠恩伺!
? ? 三、Redis為什么這么快
1臭胜、完全基于內(nèi)存莫其,絕大部分請求是純粹的內(nèi)存操作,非乘嗜快速乱陡。數(shù)據(jù)存在內(nèi)存中,類似于HashMap仪壮,HashMap的優(yōu)勢就是查找和操作的時間復雜度都是O(1)憨颠;
2、數(shù)據(jù)結構簡單,對數(shù)據(jù)操作也簡單爽彤,Redis中的數(shù)據(jù)結構是專門進行設計的养盗;
3、采用單線程适篙,避免了不必要的上下文切換和競爭條件往核,也不存在多進程或者多線程導致的切換而消耗 CPU,不用去考慮各種鎖的問題嚷节,不存在加鎖釋放鎖操作聂儒,沒有因為可能出現(xiàn)死鎖而導致的性能消耗;
4硫痰、使用多路I/O復用模型衩婚,非阻塞IO;
5效斑、使用底層模型不同非春,它們之間底層實現(xiàn)方式以及與客戶端之間通信的應用協(xié)議不一樣,Redis直接自己構建了VM 機制 缓屠,因為一般的系統(tǒng)調(diào)用系統(tǒng)函數(shù)的話奇昙,會浪費一定的時間去移動和請求;
以上幾點都比較好理解藏研,下邊我們針對多路 I/O 復用模型進行簡單的探討:
多路I/O復用模型是利用 select敬矩、poll概行、epoll 可以同時監(jiān)察多個流的 I/O 事件的能力蠢挡,在空閑的時候,會把當前線程阻塞掉凳忙,當有一個或多個流有 I/O 事件時业踏,就從阻塞態(tài)中喚醒,于是程序就會輪詢一遍所有的流(epoll 是只輪詢那些真正發(fā)出了事件的流)涧卵,并且只依次順序的處理就緒的流勤家,這種做法就避免了大量的無用操作。
這里“多路”指的是多個網(wǎng)絡連接柳恐,“復用”指的是復用同一個線程伐脖。采用多路 I/O 復用技術可以讓單個線程高效的處理多個連接請求(盡量減少網(wǎng)絡 IO 的時間消耗),且 Redis 在內(nèi)存中操作數(shù)據(jù)的速度非忱稚瑁快讼庇,也就是說內(nèi)存內(nèi)的操作不會成為影響Redis性能的瓶頸,主要由以上幾點造就了 Redis 具有很高的吞吐量近尚。
除了這些蠕啄,針對當前互聯(lián)網(wǎng)公司的技術需求以及結合主流技術,我自己整理了一套系統(tǒng)的架構技術體系,當你技術過硬的時候歼跟,能夠解決技術問題才會服眾和媳。不少公司都很重視高并發(fā)高可用的技術,特別是一線互聯(lián)網(wǎng)公司哈街,分布式留瞳、JVM、spring源碼分析骚秦、微服務等知識點已是面試的必考題撼港,這些東西可能你們平時在工作中接觸過,但是缺少的全面系統(tǒng)的學習骤竹,加入后端開發(fā)群:943918498帝牡,或是關注微信公眾號:Java資訊庫,回復“架構”蒙揣,免費領取架構資料靶溜。
? ? 四、那么為什么Redis是單線程的
我們首先要明白懒震,上邊的種種分析罩息,都是為了營造一個Redis很快的氛圍!官方FAQ表示个扰,因為Redis是基于內(nèi)存的操作瓷炮,CPU不是Redis的瓶頸,Redis的瓶頸最有可能是機器內(nèi)存的大小或者網(wǎng)絡帶寬递宅。既然單線程容易實現(xiàn)娘香,而且CPU不會成為瓶頸,那就順理成章地采用單線程的方案了(畢竟采用多線程會有很多麻煩0炝洹)烘绽。
可以參考:https://redis.io/topics/faq
看到這里,你可能會氣哭俐填!本以為會有什么重大的技術要點才使得Redis使用單線程就可以這么快安接,沒想到就是一句官方看似糊弄我們的回答!但是英融,我們已經(jīng)可以很清楚的解釋了為什么Redis這么快盏檐,并且正是由于在單線程模式的情況下已經(jīng)很快了,就沒有必要在使用多線程了驶悟!
但是胡野,我們使用單線程的方式是無法發(fā)揮多核CPU 性能,不過我們可以通過在單機開多個Redis 實例來完善撩银!
警告1:這里我們一直在強調(diào)的單線程给涕,只是在處理我們的網(wǎng)絡請求的時候只有一個線程來處理,一個正式的Redis Server運行的時候肯定是不止一個線程的,這里需要大家明確的注意一下够庙!例如Redis進行持久化的時候會以子進程或者子線程的方式執(zhí)行(具體是子線程還是子進程待讀者深入研究)恭应;例如我在測試服武器上查看Redis進程,然后找到該進程下的線程:
ps命令的“-T”參數(shù)表示顯示線程(Show threads, possibly with SPID column.)“SID”欄表示線程ID耘眨,而“CMD”欄則顯示了線程名稱昼榛。
警告2:在上圖中FAQ中的最后一段,表述了從Redis 4.0版本開始會支持多線程的方式剔难,但是胆屿,只是在某一些操作上進行多線程的操作!所以該篇文章在以后的版本中是否還是單線程的方式需要讀者考證偶宫!
? ? 五非迹、擴展
以下也是你應該知道的幾種模型,祝你的面試一臂之力纯趋!
1憎兽、單進程多線程模型:MySQL、Memcached吵冒、Oracle(Windows版本)纯命;
2、多進程模型:Oracle(Linux版本)痹栖;
3亿汞、Nginx有兩類進程,一類稱為Master進程(相當于管理進程)揪阿,另一類稱為Worker進程(實際工作進程)疗我。啟動方式有兩種:
(1)單進程啟動:此時系統(tǒng)中僅有一個進程,該進程既充當Master進程的角色图甜,也充當Worker進程的角色碍粥。
(2)多進程啟動:此時系統(tǒng)有且僅有一個Master進程,至少有一個Worker進程工作黑毅。
(3)Master進程主要進行一些全局性的初始化工作和管理Worker的工作;事件處理是在Worker中進行的钦讳。
? ? 原文出處:https://segmentfault.com/a/1190000017121908