Redis集群最大節(jié)點個數是多少?
16384個
Redis集群的主從復制模型是怎樣的?
為了使在部分節(jié)點失敗或者大部分節(jié)點無法通信的情況下集群仍然可用奥额,所以集群使用了主從復制模型邢笙,每個點都會有N-1個復制品
Redis和 Redisson有什么關系?
Redisson是一個高級的分布式協調redis客服端级乍,能幫助用戶在分布式環(huán)境中輕松實現一些java的對象(Bloom filter,BitSet锋叨,set, SetMultimap, ScoredSortedSet奥裸,SortedSet, Map沪袭,ConcurrentMap刺彩, List, List Multimap枝恋, Queue创倔, BlockingQueue, Deque焚碌, Blocking Deque畦攘, Semaphore, Lock十电, ReadWriteLock知押, Atomi cLong, CountDownLa鹃骂, Publish/ Subscribe台盯, HyperLogLog)
MySQL里有2000w數據, redis中只存20w的數據畏线,如何保證 redis中的數據都是熱點數據?
redis內存數據集大小上升到一定大小的時候静盅,就會實行數據淘汰策略。
Redis集群方案應該怎么做?都有哪些方案?
1.codis.
目前用的最多的集群方案寝殴,基本和 twemproxy一致的效果蒿叠,但它支持在節(jié)點數量改變情況下,舊節(jié)點數據可恢復到新hash節(jié)點蚣常。
2.redis cluster3.0
自帶的集群市咽,特點在于他的分布式算法不是一致性hash,而是hash槽的概念抵蚊,以及自身支持節(jié)點設置從節(jié)點施绎。
3.在業(yè)務代碼層實現
起幾個毫無關聯的 redis實例,在代碼層對key進行hash計算贞绳,然后去對應的 redis實例操作數據谷醉。這種方式對hash層代碼要求比較高,考慮部分包括熔酷,節(jié)點失效后的替代算法方案孤紧,數據震蕩后的自動腳本恢復,實例的監(jiān)控等等拒秘。
Redis集群方案什么情況下會導致整個集群不可用?
有A号显,B臭猜,C三個節(jié)點的集群,在沒有復制模型的情況下押蚤,如果節(jié)點B失敗了蔑歌,那么整個集群就會因為缺少5501-11000這個范圍的槽而不可用。
假如 Redis里面有1億個key揽碘,其中有10w個key是以某個固定的已知的前綴開頭的次屠,如果將它們全部找出來?
使用keys指令可以掃出指定模式的key列表。
對方接著追問如果這個 redis正在給線上的業(yè)務提供服務雳刺,那使用keys指令會有什么問題?這個時候你要回答 redis關鍵的一個特性redis的單線程的劫灶。keys指令會導致線程阻塞一段時間,線上服務會停頓掖桦,直到指令執(zhí)行完畢本昏,服務才能恢復。這個時候可以使用scan指令枪汪,scan指令可以無阻塞的提取出指定模式的key列表涌穆,但是會有一定的重復概率,在客戶端做一次去重就可以了雀久,但是整體所花費的時間會比直接用keys指令長宿稀。
主從數據庫不一致如何解決場景描述?
對于主從庫赖捌,讀寫分離祝沸,如果主從庫更新同步有時差,就會導致主從庫數據的不一致
1巡蘸、忽略這個數據不一致奋隶,在數據一致性要求不高的業(yè)務下,未必需要時時一致性
2悦荒、強制讀主庫,使用一個高可用的主庫嘹吨,數據庫讀寫都在主庫搬味,添加一個緩存,提升數據讀取的性能蟀拷。
3碰纬、選擇性讀主庫,添加一個緩存问芬,用來記錄必須讀主庫的數據悦析,將哪個庫,哪個表此衅,哪個主鍵强戴,作為緩存的key亭螟,設置緩存失效的時間為主從庫同步的時間,如果緩存當中有這個數據骑歹,直接讀取主庫预烙;如果緩存當中沒有這個主鍵,就到對應的從庫中讀取道媚。
緩存與數據庫不一致怎么辦扁掸?
假設采用的主存分離,讀寫分離的數據庫最域,如果一個線程A先刪除緩存數據谴分,然后將數據寫入到主庫當中,這個時候镀脂,主庫和從庫同步沒有完成狸剃,線程B從緩存當中讀取數據失敗,從從庫當中讀取到舊數據狗热,然后更新至緩存钞馁,這個時候,緩存當中的就是舊的數據匿刮。
發(fā)生上述不一致的原因在于僧凰,主從庫數據不一致問題,加入了緩存之后熟丸,主從不一致的時間被拉長了训措;
處理:在從庫有數據更新之后,將緩存當中的數據也同時進行更新光羞,即當從庫發(fā)生了數據更新之后绩鸣,向緩存發(fā)出刪除,淘汰這段時間寫入的舊數據纱兑。
1.Redis支持哪幾種數據類型
String字符串
格式: set key value
string類型是二進制安全的呀闻。意思是redis的string可以包含任何數據。比如jpg圖片或者序列化的對象 潜慎。
string類型是Redis最基本的數據類型捡多,一個鍵最大能存儲512MB。
使用場景:
緩存功能:字符串最經典的使用場景铐炫,redis最為緩存層垒手,Mysql作為儲存層,絕大部分請求數據都是redis中獲取倒信,由于redis具有支撐高并發(fā)特性科贬,所以緩存通常能起到加速讀寫和降低 后端壓力的作用。
計數器:許多運用都會使用redis作為計數的基礎工具鳖悠,他可以實現快速計數榜掌、查詢緩存的功能优妙,同時數據可以一步落地到其他的數據源。如:視頻播放數系統(tǒng)就是使用redis作為視頻播放數計數的基礎組件唐责。
共享session:出于負載均衡的考慮鳞溉,分布式服務會將用戶信息的訪問均衡到不同服務器上,用戶刷新一次訪問可能會需要重新登錄鼠哥,為避免這個問題可以用redis將用戶session集中管理熟菲,在這種模式下只要保證redis的高可用和擴展性的,每次獲取用戶更新或查詢登錄信息都直接從redis中集中獲取朴恳。
限速:處于安全考慮抄罕,每次進行登錄時讓用戶輸入手機驗證碼,為了短信接口不被頻繁訪問于颖,會限制用戶每分鐘獲取驗證碼的頻率呆贿。Hash(哈希)
格式: hmset name key1 value1 key2 value2
Redis hash 是一個鍵值(key=>value)對集合。
Redis hash是一個string類型的field和value的映射表森渐,hash特別適合用于存儲對象做入。
使用場景:
哈希結構相對于字符串序列化緩存信息更加直觀,并且在更新操作上更加便捷同衣。所以常常用于用戶信息等管理竟块,但是哈希類型和關系型數據庫有所不同,哈希類型是稀疏的耐齐, 而關系型數據庫是完全結構化的浪秘,關系型數據庫可以做復雜的關系查詢,而redis去模擬關系型復雜查詢 開發(fā)困難埠况,維護成本高耸携。List(列表)
Redis 列表是簡單的字符串列表,按照插入順序排序辕翰。你可以添加一個元素到列表的頭部(左邊)或者尾部(右邊)
格式: lpush name value
在 key 對應 list 的頭部添加字符串元素
格式: rpush name value
在 key 對應 list 的尾部添加字符串元素
格式: lrem name index
key 對應 list 中刪除 count 個和 value 相同的元素
格式: llen name
返回 key 對應 list 的長度
使用場景:
消息隊列: redis的lpush+brpop命令組合即可實現阻塞隊列夺衍,生產者客戶端是用lupsh從列表左側插入元素,多個消費者客戶端使用brpop命令阻塞時的“搶”列表尾部的元素金蜀,多個客戶端保證了消費的負載均衡 和高可用性Set(集合)
格式: sadd name value
Redis的Set是string類型的無序集合刷后。集合是通過哈希表實現的,所以添加渊抄,刪除,查找的復雜度都是O(1)丧裁。
使用場景:
標簽(tag):集合類型比較典型的使用場景护桦,如一個用戶對娛樂、體育比較感興趣煎娇,另一個可能對新聞感興趣二庵,這些興趣就是標簽贪染,有了這些數據就可以得到同一標簽的人,以及用戶的共同愛好的標簽催享,這些數據對于用戶體驗以及曾強用戶粘度比較重要杭隙。(用戶和標簽的關系維護應該放在一個事物內執(zhí)行,防止部分命令失敗造成數據不一致)zset(sorted set:有序集合)
格式: zadd name score value
Redis zset 和 set 一樣也是string類型元素的集合,且不允許重復的成員因妙。不同的是每個元素都會關聯一個double類型的分數痰憎。redis正是通過分數來為集合中的成員進行從小到大的排序。
zset的成員是唯一的,但分數(score)卻可以重復攀涵。
使用場景:
排行榜:有序集合經典使用場景铣耘。例如視頻網站需要對用戶上傳的視頻做排行榜,榜單維護可能是多方面: 按照時間以故、按照播放量蜗细、按照獲得的贊數等蜈项。
2.Redis的持久化方式
持久化就是把內存的數據寫到磁盤中去吹截,防止服務宕機了內存數據丟失。Redis 提供了兩種持久化方式:RDB(默認) 和AOF 驱入。
- RDB
快照(snapshotting)持久化(RDB)
Redis可以通過創(chuàng)建快照來獲得存儲在內存里面的數據在某個時間點上的副本昆烁。Redis創(chuàng)建快照之后吊骤,可以對快照進行備份,可以將快照復制到其他服務器從而創(chuàng)建具有相同數據的服務器副本(Redis主從結構善玫,主要用來提高Redis性能)水援,還可以將快照留在原地以便重啟服務器的時候使用。
save 900 1 #在900秒(15分鐘)之后茅郎,如果至少有1個key發(fā)生變化蜗元,Redis就會自動觸發(fā)BGSAVE命令創(chuàng)建快照。
save 300 10 #在300秒(5分鐘)之后系冗,如果至少有10個key發(fā)生變化奕扣,Redis就會自動觸發(fā)BGSAVE命令創(chuàng)建快照。
save 60 10000 #在60秒(1分鐘)之后掌敬,如果至少有10000個key發(fā)生變化惯豆,Redis就會自動觸發(fā)BGSAVE命令創(chuàng)建快照。
默認開啟奔害,會按照配置的指定時間將內存中的數據快照到磁盤中楷兽,創(chuàng)建一個dump.rdb文件,Redis啟動時再恢復到內存中华临。Redis會單獨創(chuàng)建fork()一個子進程芯杀,將當前父進程的數據庫數據復制到子進程的內存中,然后由子進程寫入到臨時文件中,持久化的過程結束了揭厚,再用這個臨時文件替換上次的快照文件却特,然后子進程退出,內存釋放筛圆。
需要注意的是裂明,每次快照持久化都會將主進程的數據庫數據復制一遍,導致內存開銷加倍太援,若此時內存不足闽晦,則會阻塞服務器運行,直到復制結束釋放內存粉寞;都會將內存數據完整寫入磁盤一次尼荆,所以如果數據量大的話,而且寫操作頻繁唧垦,必然會引起大量的磁盤I/O操作捅儒,嚴重影響性能,并且最后一次持久化后的數據可能會丟失振亮;
- AOF
開啟AOF持久化后每執(zhí)行一條會更改Redis中的數據的命令巧还,Redis就會將該命令寫入硬盤中的AOF文件。AOF文件的保存位置和RDB文件的位置相同坊秸,都是通過dir參數設置的麸祷,默認的文件名是appendonly.aof。
在Redis的配置文件中存在三種不同的 AOF 持久化方式:
appendonly yes
appendfsync always #每次有數據修改發(fā)生時都會寫入AOF文件,這樣會嚴重降低Redis的速度
appendfsync everysec #每秒鐘同步一次褒搔,顯示地將多個寫命令同步到硬盤
appendfsync no #讓操作系統(tǒng)決定何時進行同步
以日志的形式記錄每個寫操作(讀操作不記錄)阶牍,只需追加文件但不可以改寫文件,Redis啟動時會根據日志從頭到尾全部執(zhí)行一遍以完成數據的恢復工作星瘾。包括flushDB也會執(zhí)行走孽。主要有兩種方式觸發(fā):有寫操作就寫、每秒定時寫(也會丟數據)琳状。
因為AOF采用追加的方式磕瓷,所以文件會越來越大,針對這個問題念逞,新增了重寫機制困食,就是當日志文件大到一定程度的時候,會fork出一條新進程來遍歷進程內存中的數據翎承,每條記錄對應一條set語句硕盹,寫到臨時文件中,然后再替換到舊的日志文件(類似rdb的操作方式)叨咖。默認觸發(fā)是當aof文件大小是上次重寫后大小的一倍且文件大于64M時觸發(fā)莱睁。
當兩種方式同時開啟時待讳,數據恢復Redis會優(yōu)先選擇AOF恢復芒澜。一般情況下仰剿,只要使用默認開啟的RDB即可,因為相對于AOF痴晦,RDB便于進行數據庫備份南吮,并且恢復數據集的速度也要快很多。開啟持久化緩存機制誊酌,對性能會有一定的影響部凑,特別是當設置的內存滿了的時候,更是下降到幾百reqs/s碧浊。所以如果只是用來做緩存的話涂邀,可以關掉持久化。
3.redis設置過期時間
Redis中有個設置時間過期的功能箱锐,即對存儲在 redis 數據庫中的值可以設置一個過期時間比勉。作為一個緩存數據庫,這是非常實用的驹止。如我們一般項目中的 token 或者一些登錄信息浩聋,尤其是短信驗證碼都是有時間限制的,按照傳統(tǒng)的數據庫處理方式臊恋,一般都是自己判斷過期衣洁,這樣無疑會嚴重影響項目性能。
我們 set key 的時候抖仅,都可以給一個 expire time坊夫,就是過期時間,通過過期時間我們可以指定這個 key 可以存活的時間撤卢。如果假設你設置了一批 key 只能存活1個小時环凿,那么接下來1小時后,redis是怎么對這批key進行刪除的凸丸?
定期刪除+惰性刪除
- 定期刪除:redis默認是每隔 100ms 就隨機抽取一些設置了過期時間的key拷邢,檢查其是否過期,如果過期就刪除屎慢。
- 惰性刪除 :定期刪除可能會導致很多過期 key 到了時間并沒有被刪除掉瞭稼。所以就有了惰性刪除。
4.redis內存淘汰機制
volatile-lru:從已設置過期時間的數據集(server.db[i].expires)中挑選最近最少使用的數據淘汰
volatile-ttl:從已設置過期時間的數據集(server.db[i].expires)中挑選將要過期的數據淘汰
volatile-random:從已設置過期時間的數據集(server.db[i].expires)中任意選擇數據淘汰
allkeys-lru:當內存不足以容納新寫入數據時腻惠,在鍵空間中环肘,移除最近最少使用的key(這個是最常用的).
allkeys-random:從數據集(server.db[i].dict)中任意選擇數據淘汰
no-eviction:禁止驅逐數據,也就是說當內存不足以容納新寫入數據時集灌,新寫入操作會報錯悔雹。
5.redis 事務
Redis事務功能是通過MULTI复哆、EXEC、DISCARD和WATCH 四個原語實現的
Redis會將一個事務中的所有命令序列化腌零,然后按順序執(zhí)行梯找。
- redis 不支持回滾“Redis 在事務失敗時不進行回滾,而是繼續(xù)執(zhí)行余下的命令”益涧, 所以 Redis 的內部可以保持簡單且快速锈锤。
- 如果在一個事務中的命令出現錯誤,那么所有的命令都不會執(zhí)行闲询;
- 如果在一個事務中出現運行錯誤久免,那么正確的命令會被執(zhí)行。
1)MULTI命令用于開啟一個事務扭弧,它總是返回OK阎姥。 MULTI執(zhí)行之后,客戶端可以繼續(xù)向服務器發(fā)送任意多條命令鸽捻,這些命令不會立即被執(zhí)行呼巴,而是被放到一個隊列中,當EXEC命令被調用時泊愧,所有隊列中的命令才會被執(zhí)行伊磺。
2)EXEC:執(zhí)行所有事務塊內的命令。返回事務塊內所有命令的返回值删咱,按命令執(zhí)行的先后順序排列屑埋。 當操作被打斷時,返回空值 nil 痰滋。
3)通過調用DISCARD摘能,客戶端可以清空事務隊列,并放棄執(zhí)行事務敲街, 并且客戶端會從事務狀態(tài)中退出团搞。
4)WATCH 命令可以為 Redis 事務提供 check-and-set (CAS)行為。 可以監(jiān)控一個或多個鍵多艇,一旦其中有一個鍵被修改(或刪除)逻恐,之后的事務就不會執(zhí)行,監(jiān)控一直持續(xù)到EXEC命令峻黍。
緩存問題
緩存穿透:
數據庫和緩存中都沒有數據复隆,如果此時大量的請求過來,所有的請求會直接訪問數據庫姆涩,造成數據庫壓力過大挽拂。
解決:
1.直接返回空數據 null
2.使用布隆過濾器 校驗key(并不能百分之百保證一定能夠)
緩存擊穿:
緩存中沒有,數據庫中有骨饿,(有可能是在某一個key剛剛過期的時候 大量請求訪問該數據) 所有的請求都去數據庫獲取數據亏栈,造成數據庫壓力過大台腥。
解決:
1、對于獲取數據的操作 加鎖 如果緩存中沒有 此時會有一個請求去數據庫獲取數據 并放入緩存 其他請求再次判斷緩存中是否有數據 從緩存中獲取
2绒北、熱點數據永不過期
緩存雪崩:
緩存中大量的數據黎侈,同時過期。如果此時大量請求過來镇饮,全部打到數據庫蜓竹,造成數據庫壓力過大。
解決:
1.設置過期時間為隨機時間
2.熱點數據永不過期
緩存和數據庫 雙寫一致性储藐?(緩存中的數據都是數據中來的)
在更新緩存方面,對于更新完數據庫嘶是,是更新緩存呢钙勃,還是刪除緩存。又或者是先刪除緩存聂喇,再更新數據庫辖源,其實大家存在很大的爭議。
解決方案:
1.先更新數據庫希太,再更新緩存 (普遍反對克饶,舉例當你對某個商品的價格進行了改變,先改了數據庫的價格誊辉,然后用戶用緩存的價格下單了矾湃,損失慘重)
2.先刪緩存,再更新數據庫
這個情況也會有一點小問題堕澄,但是我們可以用延時雙刪來盡可能規(guī)避邀跃。
延時雙刪
A進行寫操作 刪除緩存
B查詢數據 緩存中沒有 去數據庫拿 拿到以后放入緩存中 此時緩存中存放的臟數據
A 更新數據庫
A睡小會兒
A再次刪緩存 (放入消息隊列中 重試 如果還不行 手動刪除)