前言
Redis 是單進(jìn)程箱熬,但線程IO復(fù)用馁害,基于事件窄俏,類似于Netty。因?yàn)槭菃尉€程碘菜,所以浪費(fèi)了凹蜈,多核,如果開啟集群效果會(huì)更好
NoSql的最大優(yōu)勢就是存儲(chǔ)的內(nèi)存中
Redis支持持久化到硬盤炉媒,支持?jǐn)?shù)據(jù)機(jī)構(gòu)更多踪区,且支持分布式,沒有主節(jié)點(diǎn)之分吊骤,當(dāng)集群中任意兩個(gè)節(jié)點(diǎn)宕機(jī)缎岗,不會(huì)導(dǎo)致數(shù)據(jù)的不可用。
Redis和Memcached整體對比
Redis的作者Salvatore Sanfilippo曾經(jīng)對這兩種基于內(nèi)存的數(shù)據(jù)存儲(chǔ)系統(tǒng)進(jìn)行過比較白粉,總體來看還是比較客觀的传泊,現(xiàn)總結(jié)如下:
- 性能對比:由于Redis只使用單核,而Memcached可以使用多核鸭巴,所以平均每一個(gè)核上Redis在存儲(chǔ)小數(shù)據(jù)時(shí)比Memcached性能更高眷细。而在100k以上的數(shù)據(jù)中,Memcached性能要高于Redis鹃祖,雖然Redis最近也在存儲(chǔ)大數(shù)據(jù)的性能上進(jìn)行優(yōu)化溪椎,但是比起Memcached,還是稍有遜色恬口。
- 內(nèi)存使用效率對比:使用簡單的key-value存儲(chǔ)的話校读,Memcached的內(nèi)存利用率更高,而如果Redis采用hash結(jié)構(gòu)來做key-value存儲(chǔ)祖能,由于其組合式的壓縮歉秫,其內(nèi)存利用率會(huì)高于Memcached。
- Redis支持服務(wù)器端的數(shù)據(jù)操作:Redis相比Memcached來說养铸,擁有更多的數(shù)據(jù)結(jié)構(gòu)和并支持更豐富的數(shù)據(jù)操作雁芙,通常在Memcached里,你需要將數(shù)據(jù)拿到客戶端來進(jìn)行類似的修改再set回去钞螟。這大大增加了網(wǎng)絡(luò)IO的次數(shù)和數(shù)據(jù)體積兔甘。在Redis中,這些復(fù)雜的操作通常和一般的GET/SET一樣高效鳞滨。所以裂明,如果需要緩存能夠支持更復(fù)雜的結(jié)構(gòu)和操作,那么Redis會(huì)是不錯(cuò)的選擇。
分布式分析
什么是哈希槽闽晦,就是根據(jù)key計(jì)算hash扳碍,根據(jù)hash到內(nèi)置的哈希槽中尋找,這些哈希槽會(huì)適當(dāng)?shù)拇笾戮鶆虻姆旁诮Y(jié)群中每個(gè)節(jié)點(diǎn)中
為什么
當(dāng)你往Redis Cluster中加入一個(gè)Key時(shí)仙蛉,會(huì)根據(jù)crc16(key) mod 16384計(jì)算這個(gè)key應(yīng)該分布到哪個(gè)hash slot中笋敞,一個(gè)hash slot中會(huì)有很多key和value。你可以理解成表的分區(qū)荠瘪,使用單節(jié)點(diǎn)時(shí)的redis時(shí)只有一個(gè)表夯巷,所有的key都放在這個(gè)表里;改用Redis Cluster以后會(huì)自動(dòng)為你生成16384個(gè)分區(qū)表哀墓,你insert數(shù)據(jù)時(shí)會(huì)根據(jù)上面的簡單算法來決定你的key應(yīng)該存在哪個(gè)分區(qū)趁餐,每個(gè)分區(qū)里有很多key。
Redis 集群中內(nèi)置了 16384 個(gè)哈希槽篮绰,當(dāng)需要在 Redis 集群中放置一個(gè) key-value 時(shí)后雷,redis 先對 key 使用 crc16 算法算出一個(gè)結(jié)果,然后把結(jié)果對 16384 求余數(shù)吠各,這樣每個(gè) key 都會(huì)對應(yīng)一個(gè)編號在 0-16383 之間的哈希槽臀突,redis 會(huì)根據(jù)節(jié)點(diǎn)數(shù)量大致均等的將哈希槽映射到不同的節(jié)點(diǎn)。
使用哈希槽的好處就在于可以方便的添加或移除節(jié)點(diǎn)贾漏。
當(dāng)需要增加節(jié)點(diǎn)時(shí)候学,只需要把其他節(jié)點(diǎn)的某些哈希槽挪到新節(jié)點(diǎn)就可以了;
當(dāng)需要移除節(jié)點(diǎn)時(shí)纵散,只需要把移除節(jié)點(diǎn)上的哈希槽挪到其他節(jié)點(diǎn)就行了梳码;
內(nèi)部機(jī)制,與我何干伍掀,對于我們來說掰茶,在新增或移除節(jié)點(diǎn)的時(shí)候不要讓我們先停掉所有的 redis 服務(wù)我就謝天謝地了,這點(diǎn)它做到了硕盹。
下面我們就開始動(dòng)手搭建一個(gè) redis 集群來體驗(yàn)一下符匾。
Redis配置信息
- daemonize no 默認(rèn)情況下叨咖,redis不是在后臺(tái)運(yùn)行的瘩例。如果需要在后臺(tái)運(yùn)行,把該項(xiàng)的值更改為yes甸各;
- pidfile /var/run/redis.pid當(dāng)Redis在后臺(tái)運(yùn)行的時(shí)候垛贤,Redis默認(rèn)會(huì)把pid文件放在/var/run/redis.pid,你可以配置到其他地址趣倾。當(dāng)運(yùn)行多個(gè)redis服務(wù)時(shí)聘惦,需要指定不同的pid文件和端口;
- port 6379指定redis運(yùn)行的端口儒恋,默認(rèn)是6379善绎;
- bind 127.0.0.1 指定redis只接收來自于該IP地址的請求黔漂,如果不進(jìn)行設(shè)置,那么將處理所有請求禀酱。在生產(chǎn)環(huán)境中最好設(shè)置該項(xiàng)炬守;
- loglevel debug 指定日志記錄級別,其中Redis總共支持四個(gè)級別:debug剂跟、verbose减途、notice、warning曹洽,默認(rèn)為verbose鳍置。debug表示記錄很多信息,用于開發(fā)和測試送淆。verbose表示記錄有用的信息税产,但不像debug會(huì)記錄那么多。notice表示普通的verbose坊夫,常用于生產(chǎn)環(huán)境砖第。warning 表示只有非常重要或者嚴(yán)重的信息會(huì)記錄到日志;
- logfile /var/log/redis/redis.log 配置log文件地址环凿,默認(rèn)值為stdout梧兼。若后臺(tái)模式會(huì)輸出到/dev/null;
- databases 16 可用數(shù)據(jù)庫數(shù)智听,默認(rèn)值為16羽杰,默認(rèn)數(shù)據(jù)庫為0,數(shù)據(jù)庫范圍在0-(database-1)之間到推;
- save 900 1保存數(shù)據(jù)到磁盤考赛,格式為save <seconds> <changes>,指出在多長時(shí)間內(nèi)莉测,有多少次更新操作颜骤,就將數(shù)據(jù)同步到數(shù)據(jù)文件rdb。相當(dāng)于條件觸發(fā)抓取快照捣卤,這個(gè)可以多個(gè)條件配合忍抽。save 900 1就表示900秒內(nèi)至少有1個(gè)key被改變就保存數(shù)據(jù)到磁盤;
- rdbcompression yes 存儲(chǔ)至本地?cái)?shù)據(jù)庫時(shí)(持久化到rdb文件)是否壓縮數(shù)據(jù)董朝,默認(rèn)為yes鸠项;
- dbfilename dump.rdb本地持久化數(shù)據(jù)庫文件名,默認(rèn)值為dump.rdb子姜;
- dir ./ 工作目錄祟绊,數(shù)據(jù)庫鏡像備份的文件放置的路徑。這里的路徑跟文件名要分開配置是因?yàn)閞edis在進(jìn)行備份時(shí),先會(huì)將當(dāng)前數(shù)據(jù)庫的狀態(tài)寫入到一個(gè)臨時(shí)文件中牧抽,等備份完成時(shí)嘉熊,再把該臨時(shí)文件替換為上面所指定的文件。而這里的臨時(shí)文件和上面所配置的備份文件都會(huì)放在這個(gè)指定的路徑當(dāng)中扬舒,AOF文件也會(huì)存放在這個(gè)目錄下面记舆。注意這里必須指定一個(gè)目錄而不是文件;
- slaveof <masterip> <masterport> 主從復(fù)制呼巴,設(shè)置該數(shù)據(jù)庫為其他數(shù)據(jù)庫的從數(shù)據(jù)庫泽腮。設(shè)置當(dāng)本機(jī)為slave服務(wù)時(shí),設(shè)置master服務(wù)的IP地址及端口衣赶。在Redis啟動(dòng)時(shí)诊赊,它會(huì)自動(dòng)從master進(jìn)行數(shù)據(jù)同步;
- masterauth <master-password> 當(dāng)master服務(wù)設(shè)置了密碼保護(hù)時(shí)(用requirepass制定的密碼)slave服務(wù)連接master的密碼府瞄;
- slave-serve-stale-data yes 當(dāng)從庫同主機(jī)失去連接或者復(fù)制正在進(jìn)行碧磅,從機(jī)庫有兩種運(yùn)行方式:如果slave-serve-stale-data設(shè)置為yes(默認(rèn)設(shè)置),從庫會(huì)繼續(xù)相應(yīng)客戶端的請求遵馆。如果slave-serve-stale-data是指為no鲸郊,除去INFO和SLAVOF命令之外的任何請求都會(huì)返回一個(gè)錯(cuò)誤"SYNC with master in progress";
- repl-ping-slave-period 10從庫會(huì)按照一個(gè)時(shí)間間隔向主庫發(fā)送PING货邓,可以通過repl-ping-slave-period設(shè)置這個(gè)時(shí)間間隔秆撮,默認(rèn)是10秒;
- repl-timeout 60 設(shè)置主庫批量數(shù)據(jù)傳輸時(shí)間或者ping回復(fù)時(shí)間間隔换况,默認(rèn)值是60秒职辨,一定要確保repl-timeout大于repl-ping-slave-period;
- requirepass foobared 設(shè)置客戶端連接后進(jìn)行任何其他指定前需要使用的密碼戈二。因?yàn)閞edis速度相當(dāng)快舒裤,所以在一臺(tái)比較好的服務(wù)器下,一個(gè)外部的用戶可以在一秒鐘進(jìn)行150K次的密碼嘗試觉吭,這意味著你需要指定非常強(qiáng)大的密碼來防止暴力破解腾供;
- rename-command CONFIG "" 命令重命名,在一個(gè)共享環(huán)境下可以重命名相對危險(xiǎn)的命令鲜滩,比如把CONFIG重名為一個(gè)不容易猜測的字符:# rename-command CONFIG b840fc02d524045429941cc15f59e41cb7be6c52伴鳖。如果想刪除一個(gè)命令,直接把它重命名為一個(gè)空字符""即可:rename-command CONFIG ""绒北;
- maxclients 128設(shè)置同一時(shí)間最大客戶端連接數(shù)黎侈,默認(rèn)無限制察署。Redis可以同時(shí)打開的客戶端連接數(shù)為Redis進(jìn)程可以打開的最大文件描述符數(shù)闷游。如果設(shè)置 maxclients 0,表示不作限制。當(dāng)客戶端連接數(shù)到達(dá)限制時(shí)脐往,Redis會(huì)關(guān)閉新的連接并向客戶端返回max number of clients reached錯(cuò)誤信息休吠;
- maxmemory <bytes> 指定Redis最大內(nèi)存限制。Redis在啟動(dòng)時(shí)會(huì)把數(shù)據(jù)加載到內(nèi)存中业簿,達(dá)到最大內(nèi)存后瘤礁,Redis會(huì)先嘗試清除已到期或即將到期的Key,Redis同時(shí)也會(huì)移除空的list對象梅尤。當(dāng)此方法處理后柜思,仍然到達(dá)最大內(nèi)存設(shè)置,將無法再進(jìn)行寫入操作巷燥,但仍然可以進(jìn)行讀取操作赡盘。注意:Redis新的vm機(jī)制,會(huì)把Key存放內(nèi)存缰揪,Value會(huì)存放在swap區(qū)陨享;
- maxmemory-policy volatile-lru 當(dāng)內(nèi)存達(dá)到最大值的時(shí)候Redis會(huì)選擇刪除哪些數(shù)據(jù)呢?有五種方式可供選擇:volatile-lru代表利用LRU算法移除設(shè)置過過期時(shí)間的key (LRU:最近使用 Least Recently Used )钝腺,allkeys-lru代表利用LRU算法移除任何key抛姑,volatile-random代表移除設(shè)置過過期時(shí)間的隨機(jī)key,allkeys_random代表移除一個(gè)隨機(jī)的key艳狐,volatile-ttl代表移除即將過期的key(minor TTL)定硝,noeviction代表不移除任何key,只是返回一個(gè)寫錯(cuò)誤毫目。
注意:對于上面的策略喷斋,如果沒有合適的key可以移除,寫的時(shí)候Redis會(huì)返回一個(gè)錯(cuò)誤蒜茴; - appendonly no 默認(rèn)情況下星爪,redis會(huì)在后臺(tái)異步的把數(shù)據(jù)庫鏡像備份到磁盤,但是該備份是非常耗時(shí)的粉私,而且備份也不能很頻繁顽腾。如果發(fā)生諸如拉閘限電、拔插頭等狀況诺核,那么將造成比較大范圍的數(shù)據(jù)丟失抄肖,所以redis提供了另外一種更加高效的數(shù)據(jù)庫備份及災(zāi)難恢復(fù)方式。開啟append only模式之后窖杀,redis會(huì)把所接收到的每一次寫操作請求都追加到appendonly.aof文件中漓摩。當(dāng)redis重新啟動(dòng)時(shí),會(huì)從該文件恢復(fù)出之前的狀態(tài)入客,但是這樣會(huì)造成appendonly.aof文件過大管毙,所以redis還支持了BGREWRITEAOF指令對appendonly.aof 進(jìn)行重新整理腿椎,你可以同時(shí)開啟asynchronous dumps 和 AOF;
- appendfilename appendonly.aof AOF文件名稱,默認(rèn)為"appendonly.aof";
- appendfsync everysec Redis支持三種同步AOF文件的策略: no代表不進(jìn)行同步夭咬,系統(tǒng)去操作啃炸,always代表每次有寫操作都進(jìn)行同步,everysec代表對寫操作進(jìn)行累積卓舵,每秒同步一次南用,默認(rèn)是"everysec",按照速度和安全折中這是最好的掏湾。
- slowlog-log-slower-than 10000 記錄超過特定執(zhí)行時(shí)間的命令裹虫。執(zhí)行時(shí)間不包括I/O計(jì)算,比如連接客戶端融击,返回結(jié)果等恒界,只是命令執(zhí)行時(shí)間⊙庾欤可以通過兩個(gè)參數(shù)設(shè)置slow log:一個(gè)是告訴Redis執(zhí)行超過多少時(shí)間被記錄的參數(shù)slowlog-log-slower-than(微妙)十酣,另一個(gè)是slow log 的長度。當(dāng)一個(gè)新命令被記錄的時(shí)候最早的命令將被從隊(duì)列中移除际长,下面的時(shí)間以微妙微單位耸采,因此1000000代表一分鐘。注意制定一個(gè)負(fù)數(shù)將關(guān)閉慢日志工育,而設(shè)置為0將強(qiáng)制每個(gè)命令都會(huì)記錄虾宇;
- hash-max-zipmap-entries 512 && hash-max-zipmap-value 64 當(dāng)hash中包含超過指定元素個(gè)數(shù)并且最大的元素沒有超過臨界時(shí),hash將以一種特殊的編碼方式(大大減少內(nèi)存使用)來存儲(chǔ)如绸,這里可以設(shè)置這兩個(gè)臨界值嘱朽。Redis Hash對應(yīng)Value內(nèi)部實(shí)際就是一個(gè)HashMap,實(shí)際這里會(huì)有2種不同實(shí)現(xiàn)怔接。這個(gè)Hash的成員比較少時(shí)Redis為了節(jié)省內(nèi)存會(huì)采用類似一維數(shù)組的方式來緊湊存儲(chǔ)搪泳,而不會(huì)采用真正的HashMap結(jié)構(gòu),對應(yīng)的value redisObject的encoding為zipmap扼脐。當(dāng)成員數(shù)量增大時(shí)會(huì)自動(dòng)轉(zhuǎn)成真正的HashMap岸军,此時(shí)encoding為ht;
- list-max-ziplist-entries 512 list數(shù)據(jù)類型多少節(jié)點(diǎn)以下會(huì)采用去指針的緊湊存儲(chǔ)格式瓦侮;
- list-max-ziplist-value 64數(shù)據(jù)類型節(jié)點(diǎn)值大小小于多少字節(jié)會(huì)采用緊湊存儲(chǔ)格式艰赞;
- set-max-intset-entries 512 set數(shù)據(jù)類型內(nèi)部數(shù)據(jù)如果全部是數(shù)值型,且包含多少節(jié)點(diǎn)以下會(huì)采用緊湊格式存儲(chǔ)肚吏;
- zset-max-ziplist-entries 128 zsort數(shù)據(jù)類型多少節(jié)點(diǎn)以下會(huì)采用去指針的緊湊存儲(chǔ)格式方妖;
- zset-max-ziplist-value 64 zsort數(shù)據(jù)類型節(jié)點(diǎn)值大小小于多少字節(jié)會(huì)采用緊湊存儲(chǔ)格式。
- activerehashing yes Redis將在每100毫秒時(shí)使用1毫秒的CPU時(shí)間來對redis的hash表進(jìn)行重新hash罚攀,可以降低內(nèi)存的使用党觅。當(dāng)你的使用場景中雌澄,有非常嚴(yán)格的實(shí)時(shí)性需要,不能夠接受Redis時(shí)不時(shí)的對請求有2毫秒的延遲的話仔役,把這項(xiàng)配置為no。如果沒有這么嚴(yán)格的實(shí)時(shí)性要求是己,可以設(shè)置為yes又兵,以便能夠盡可能快的釋放內(nèi)存;