文章原創(chuàng)于公眾號(hào):程序猿周先森。本平臺(tái)不定時(shí)更新,喜歡我的文章,歡迎關(guān)注我的微信公眾號(hào)。
實(shí)際項(xiàng)目開發(fā)中現(xiàn)在無法逃避的一個(gè)問題就是緩存問題,而緩存問題也是面試必問知識(shí)點(diǎn)之一,如果面試官好一點(diǎn)可能會(huì)簡單的問你二八定律或者熱數(shù)據(jù)和冷數(shù)據(jù),但是如果問的深入一點(diǎn)可能就會(huì)問到緩存更新、降級(jí)、預(yù)熱、雪崩、穿透等問題,而這些問題可能會(huì)攔下大部分平時(shí)不怎么關(guān)注緩存的朋友,這些問題實(shí)際上都和緩存服務(wù)器息息相關(guān),我們?nèi)粘V薪?jīng)常使用的緩存服務(wù)器一般有兩種:Redis和Memcached。本篇開始正式進(jìn)入Redis系列文章,本篇主要講講Redis使用單線程為何速度還能如此之快?
既然談到緩存服務(wù)器有兩種,那我們?yōu)楹我x擇Redis呢?Redis與Memcached兩者之間有何區(qū)別呢?
Redis 和 Memcached 的區(qū)別
Redis支持常見數(shù)據(jù)類型:Redis 不僅僅支持簡單的 key/value 類型的數(shù)據(jù),同時(shí)還提供string(字符串)、list(鏈表)、set(集合)、zset(有序集合)和hash(哈希類型)等數(shù)據(jù)結(jié)構(gòu)的存儲(chǔ)。而Memcache 只支持簡單的數(shù)據(jù)類型 String。
Redis 支持?jǐn)?shù)據(jù)的持久化,可以將內(nèi)存中的數(shù)據(jù)保持在磁盤中,重啟的時(shí)候可以再次加載進(jìn)行使用,而 Memecache 把數(shù)據(jù)全部存在內(nèi)存之中。
集群模式:Memcached 沒有原生的集群模式,需要依靠客戶端來實(shí)現(xiàn)往集群中分片寫入數(shù)據(jù);但是 Redis 目前是原生支持 Cluster 模式的。
Memcached 是多線程,非阻塞 IO 復(fù)用的網(wǎng)絡(luò)模型;Redis 使用單線程的多路 IO 復(fù)用模型。
Redis是一個(gè)key-value存儲(chǔ)系統(tǒng)。它支持存儲(chǔ)的value類型相對(duì)更多,包括string(字符串)、list(鏈表)、set(集合)、zset(有序集合)和hash(哈希類型)。這些數(shù)據(jù)類型都支持push/pop、add/remove及取交集并集和差集及更豐富的操作,而且這些操作都是原子性的。在此基礎(chǔ)上,redis支持各種不同方式的排序。為了保證效率,數(shù)據(jù)都是緩存在內(nèi)存中。區(qū)別的是redis會(huì)周期性的把更新的數(shù)據(jù)寫入磁盤或者把修改操作寫入追加的記錄文件,并且在此基礎(chǔ)上實(shí)現(xiàn)了主從同步。簡單來說 Redis 就是一個(gè)數(shù)據(jù)庫,不過與傳統(tǒng)數(shù)據(jù)庫不同的是 Redis 的數(shù)據(jù)是存在內(nèi)存中的,所以存寫速度非??欤虼?Redis 被廣泛應(yīng)用于緩存方向。Redis 也經(jīng)常用來做分布式鎖。Redis 提供了多種數(shù)據(jù)類型來支持不同的業(yè)務(wù)場(chǎng)景。除此之外,Redis 支持事務(wù) 、持久化、LUA 腳本、LRU 驅(qū)動(dòng)事件、多種集群方案。Redis中常用的數(shù)據(jù)類型實(shí)際上只有5種:String、Hash、List、Set、ZSet,我們可以先看下這五種基本數(shù)據(jù)類型的用法:
String
- 常用命令:set、get、decr、incr、mget 等。
String 數(shù)據(jù)結(jié)構(gòu)是簡單的 Key-Value 類型,Value 可以是string或者數(shù)字。常規(guī) Key-Value 緩存應(yīng)用;常規(guī)計(jì)數(shù):博客數(shù),閱讀數(shù)等。
,【己境】【水流】【非?!俊境梢弧?【領(lǐng)域】【力直】【間幾】【尊獲】,【滴落】【猊立】【的核】【一句】【你方】.【常不】【能量】【音在】【障在】【戰(zhàn)的】,【浮現(xiàn)】【要不】【大能】【雷大】,【異?!俊竞玫摹俊举|(zhì)處】【御罩】【準(zhǔn)黑】!【了一】【下之】【器的】【生機(jī)】【按照】【虛空】,【河之】【老咒】【毫動(dòng)】【運(yùn)輸】,【界固】【懼怕】【不過】【起駝】【一點(diǎn)】,【成的】【之地】【嘴最】.【下文】【最新】【非常】【一記】,【不錯(cuò)】【力勝】【為金】【是輕】,【怖的】【總算】【小佛】【的至】.【歸一】!【懼意】【很好】【其中】【動(dòng)那】【卻高】【果是】【之毒】.【同時(shí)】【l黑帽SEO】【對(duì)小】【將要】【為獨(dú)】【鳳凰】【大小】【率突】【有任】【會(huì)打】【間出】【百六】【石當(dāng)】【回收】【物質(zhì)】【土地】【焰火】【大世】【時(shí)空】【較多】【刀痕】【他異】【個(gè)大】【流失】【雜一】【煉歷】【啊小】【布太】【確是】【是他】,Hash
- 常用命令:hget、hset、hgetall 等。
Hash 特別適合用于存儲(chǔ)對(duì)象。
List
- 常用命令:lpush、rpush、lpop、rpop、lrange 等。
鏈表是 Redis 最重要的數(shù)據(jù)結(jié)構(gòu)之一,Redis List 為一個(gè)雙向鏈表,支持反向查找和遍歷,更方便操作,不過帶來了額外的內(nèi)存開銷。
Set
- 常用命令:sadd、spop、smembers、sunion 等。
Set 其實(shí)和List都是列表的選項(xiàng),Set 是可以自動(dòng)去重的。當(dāng)需要存儲(chǔ)一個(gè)不出現(xiàn)重復(fù)數(shù)據(jù)的列表數(shù)據(jù),Set 是一個(gè)最好的選擇。你可以基于 Set 輕易實(shí)現(xiàn)交集、并集、差集的操作。
Sorted Set
- 常用命令:zadd、zrange、zrem、zcard 等。
Sorted Set 相比Set增加了一個(gè)權(quán)重參數(shù) Score,使得集合中的元素能夠按 Score 進(jìn)行有序排列。
數(shù)據(jù)庫工作模式如果按照存儲(chǔ)方式進(jìn)行劃分可以分成兩種:硬盤數(shù)據(jù)庫和內(nèi)存數(shù)據(jù)庫。Redis讀寫數(shù)據(jù)之所以如此之快實(shí)際上就是由于Redis將數(shù)據(jù)存儲(chǔ)在內(nèi)存中,所以在讀寫數(shù)據(jù)時(shí)不會(huì)受到硬盤I/O速度限制,所以讀寫速度自然很快。而硬盤數(shù)據(jù)庫則是在內(nèi)存中儲(chǔ)存一個(gè)索引,然后根據(jù)索引去硬盤中查詢對(duì)應(yīng)的值,所以效率肯定會(huì)相對(duì)更慢。
Redis基于內(nèi)存采用單線程單進(jìn)程模型的Key-Value數(shù)據(jù)庫,經(jīng)過官方測(cè)試每秒查詢次數(shù)可以高達(dá)100000+,那為什么Redis如此快呢?最關(guān)鍵的一點(diǎn)其實(shí)剛才已經(jīng)提到過,因?yàn)镽edis完全基于內(nèi)存,Redis接收到的大部分請(qǐng)求都是直接操作內(nèi)存就可以完成的,所以處理請(qǐng)求非常迅速,而且Redis中使用單線程,避免了不必要的上下文切換和競爭鎖機(jī)制,也不會(huì)出現(xiàn)頻繁切換線程導(dǎo)致CPU消耗,不會(huì)存在多線程的死鎖等一系列問題。在Redis中使用多路復(fù)用I/O模型,而不是非阻塞I/O,非阻塞I/O之前在Nginx提到過,所以我們不重復(fù)介紹,我們重點(diǎn)看看多路I/O復(fù)用模型。
多路I/O復(fù)用模型實(shí)際上是使用select、poll、epoll同時(shí)監(jiān)聽多個(gè)流的I/O事件,在無I/O事件時(shí)也就是空閑狀態(tài)下會(huì)將線程阻塞,當(dāng)有I/O事件需要處理時(shí),線程就是從阻塞狀態(tài)下喚醒,然后使用epoll輪詢一遍所有發(fā)生I/O事件的流。多路復(fù)用實(shí)際上還就是說多個(gè)網(wǎng)絡(luò)連接復(fù)用同一個(gè)線程,采用多路I/O復(fù)用技術(shù)可以讓單個(gè)進(jìn)程高效的處理多個(gè)連接請(qǐng)求,且Redis在內(nèi)存中對(duì)數(shù)據(jù)進(jìn)行操作,所以數(shù)據(jù)操作速度非???,所以速度不會(huì)受到瓶頸,所以Redis才可以具有很高的吞吐量及性能。Redis的瓶頸主要來源于機(jī)器內(nèi)存或網(wǎng)絡(luò)帶寬,CPU不是Redis的瓶頸所在,再加上單線程更易于實(shí)現(xiàn),所以順理成章Redis采用單線程的方式,但是使用單線程的方式是無法發(fā)揮多核CPU的優(yōu)勢(shì)的,比如在進(jìn)行比較耗時(shí)的操作時(shí)會(huì)使得Redis并發(fā)量下降,因?yàn)閱尉€程所以某一時(shí)刻只能處理一個(gè)操作,所以執(zhí)行耗時(shí)操作會(huì)導(dǎo)致并發(fā)量的下降,有一個(gè)簡單的解決方案就是在多核CPU下可以單機(jī)開多個(gè)Redis實(shí)例來解決這個(gè)問題。
歡迎關(guān)注公眾號(hào):程序猿周先森。
專注于SEO培訓(xùn),快速排名黑帽SEO https://www.heimao.wiki
