搞懂這些Redis知識(shí)點(diǎn)陕凹,吊打面試官宵睦!
一文掌握Redis主從復(fù)制、哨兵次泽、Cluster三種集群模式
Redis 5 HyperLogLog 布隆過(guò)濾器 GeoHash 和 scan
Geohash算法原理及實(shí)現(xiàn)(附代碼)
Redis主從+KeepAlived實(shí)現(xiàn)高可用(不做讀寫分離,寫壓力大可以采取cluster分片的方式)
分布式緩存集群方案特性使用場(chǎng)景(Memcache/Redis(Twemproxy/Codis/Redis-cluster))優(yōu)缺點(diǎn)對(duì)比及選型
redis 簡(jiǎn)介
簡(jiǎn)單來(lái)說(shuō) redis 就是一個(gè)數(shù)據(jù)庫(kù)席爽,不過(guò)與傳統(tǒng)數(shù)據(jù)庫(kù)不同的是 redis 的數(shù)據(jù)是存在內(nèi)存中的意荤,所以存寫速度非常快只锻,因此 redis 被廣泛應(yīng)用于緩存方向玖像。另外,redis 也經(jīng)常用來(lái)做分布式鎖齐饮。redis 提供了多種數(shù)據(jù)類型來(lái)支持不同的業(yè)務(wù)場(chǎng)景捐寥。除此之外,redis 支持事務(wù) 祖驱、持久化握恳、LUA腳本、LRU驅(qū)動(dòng)事件羹膳、多種集群方案睡互。
為什么要用 redis /為什么要用緩存
主要從“高性能”和“高并發(fā)”這兩點(diǎn)來(lái)看待這個(gè)問(wèn)題。
高性能:
假如用戶第一次訪問(wèn)數(shù)據(jù)庫(kù)中的某些數(shù)據(jù)陵像。這個(gè)過(guò)程會(huì)比較慢就珠,因?yàn)槭菑挠脖P上讀取的。將該用戶訪問(wèn)的數(shù)據(jù)存在數(shù)緩存中醒颖,這樣下一次再訪問(wèn)這些數(shù)據(jù)的時(shí)候就可以直接從緩存中獲取了妻怎。操作緩存就是直接操作內(nèi)存,所以速度相當(dāng)快泞歉。如果數(shù)據(jù)庫(kù)中的對(duì)應(yīng)數(shù)據(jù)改變的之后逼侦,同步改變緩存中相應(yīng)的數(shù)據(jù)即可!
image
高并發(fā):
直接操作緩存能夠承受的請(qǐng)求是遠(yuǎn)遠(yuǎn)大于直接訪問(wèn)數(shù)據(jù)庫(kù)的腰耙,所以我們可以考慮把數(shù)據(jù)庫(kù)中的部分?jǐn)?shù)據(jù)轉(zhuǎn)移到緩存中去榛丢,這樣用戶的一部分請(qǐng)求會(huì)直接到緩存這里而不用經(jīng)過(guò)數(shù)據(jù)庫(kù)。
image
為什么要用 redis 而不用 map/guava 做緩存?
緩存分為本地緩存和分布式緩存挺庞。以 Java 為例晰赞,使用自帶的 map 或者 guava 實(shí)現(xiàn)的是本地緩存,最主要的特點(diǎn)是輕量以及快速,生命周期隨著 jvm 的銷毀而結(jié)束掖鱼,并且在多實(shí)例的情況下然走,每個(gè)實(shí)例都需要各自保存一份緩存,緩存不具有一致性戏挡。
使用 redis 或 memcached 之類的稱為分布式緩存芍瑞,在多實(shí)例的情況下,各實(shí)例共用一份緩存數(shù)據(jù)褐墅,緩存具有一致性拆檬。缺點(diǎn)是需要保持 redis 或 memcached服務(wù)的高可用,整個(gè)程序架構(gòu)上較為復(fù)雜掌栅。
redis 和 memcached 的區(qū)別
對(duì)于 redis 和 memcached 的區(qū)別有下面四點(diǎn)秩仆。
redis支持更豐富的數(shù)據(jù)類型(支持更復(fù)雜的應(yīng)用場(chǎng)景):Redis不僅僅支持簡(jiǎn)單的k/v類型的數(shù)據(jù),同時(shí)還提供list猾封,set澄耍,zset,hash等數(shù)據(jù)結(jié)構(gòu)的存儲(chǔ)晌缘。memcache支持簡(jiǎn)單的數(shù)據(jù)類型齐莲,String。
Redis支持?jǐn)?shù)據(jù)的持久化磷箕,可以將內(nèi)存中的數(shù)據(jù)保持在磁盤中选酗,重啟的時(shí)候可以再次加載進(jìn)行使用,而Memecache把數(shù)據(jù)全部存在內(nèi)存之中。
集群模式:memcached沒(méi)有原生的集群模式岳枷,需要依靠客戶端來(lái)實(shí)現(xiàn)往集群中分片寫入數(shù)據(jù)芒填;但是 redis 目前是原生支持 cluster 模式的.
Memcached是多線程,非阻塞IO復(fù)用的網(wǎng)絡(luò)模型空繁;Redis使用單線程的多路 IO 復(fù)用模型殿衰。
redis 和 memcached 的區(qū)別
redis 常見數(shù)據(jù)結(jié)構(gòu)以及使用場(chǎng)景分析
1. String
常用命令:set,get,decr,incr,mget 等。
String數(shù)據(jù)結(jié)構(gòu)是簡(jiǎn)單的key-value類型盛泡,value其實(shí)不僅可以是String闷祥,也可以是數(shù)字。 常規(guī)key-value緩存應(yīng)用傲诵; 常規(guī)計(jì)數(shù):微博數(shù)凯砍,粉絲數(shù)等。
2.Hash
常用命令:hget,hset,hgetall 等拴竹。
Hash 是一個(gè) string 類型的 field 和 value 的映射表悟衩,hash 特別適合用于存儲(chǔ)對(duì)象,后續(xù)操作的時(shí)候栓拜,你可以直接僅僅修改這個(gè)對(duì)象中的某個(gè)字段的值座泳。 比如我們可以Hash數(shù)據(jù)結(jié)構(gòu)來(lái)存儲(chǔ)用戶信息斑响,商品信息等等。比如下面我就用 hash 類型存放了我本人的一些信息:
key=JavaUser293847value={“id”:1,“name”:“SnailClimb”,“age”:22,“l(fā)ocation”:“Wuhan,Hubei”}
3.List
常用命令:lpush,rpush,lpop,rpop,lrange等
list 就是鏈表钳榨,Redis list 的應(yīng)用場(chǎng)景非常多,也是Redis最重要的數(shù)據(jù)結(jié)構(gòu)之一纽门,比如微博的關(guān)注列表薛耻,粉絲列表,消息列表等功能都可以用Redis的 list 結(jié)構(gòu)來(lái)實(shí)現(xiàn)赏陵。
Redis list 的實(shí)現(xiàn)為一個(gè)雙向鏈表饼齿,即可以支持反向查找和遍歷,更方便操作蝙搔,不過(guò)帶來(lái)了部分額外的內(nèi)存開銷缕溉。
另外可以通過(guò) lrange 命令,就是從某個(gè)元素開始讀取多少個(gè)元素吃型,可以基于 list 實(shí)現(xiàn)分頁(yè)查詢证鸥,這個(gè)很棒的一個(gè)功能,基于 redis 實(shí)現(xiàn)簡(jiǎn)單的高性能分頁(yè)勤晚,可以做類似微博那種下拉不斷分頁(yè)的東西(一頁(yè)一頁(yè)的往下走)枉层,性能高。
4.Set
常用命令:sadd,spop,smembers,sunion 等
set 對(duì)外提供的功能與list類似是一個(gè)列表的功能赐写,特殊之處在于 set 是可以自動(dòng)排重的鸟蜡。
當(dāng)你需要存儲(chǔ)一個(gè)列表數(shù)據(jù),又不希望出現(xiàn)重復(fù)數(shù)據(jù)時(shí)挺邀,set是一個(gè)很好的選擇揉忘,并且set提供了判斷某個(gè)成員是否在一個(gè)set集合內(nèi)的重要接口,這個(gè)也是list所不能提供的端铛∑可以基于 set 輕易實(shí)現(xiàn)交集、并集沦补、差集的操作乳蓄。
比如:在微博應(yīng)用中,可以將一個(gè)用戶所有的關(guān)注人存在一個(gè)集合中夕膀,將其所有粉絲存在一個(gè)集合虚倒。Redis可以非常方便的實(shí)現(xiàn)如共同關(guān)注、共同粉絲产舞、共同喜好等功能魂奥。這個(gè)過(guò)程也就是求交集的過(guò)程,具體命令如下:
sinterstore key1 key2 key3? ? 將交集存在key1內(nèi)
5.Sorted Set
常用命令:zadd,zrange,zrem,zcard等
和set相比易猫,sorted set增加了一個(gè)權(quán)重參數(shù)score耻煤,使得集合中的元素能夠按score進(jìn)行有序排列。
舉例:在直播系統(tǒng)中,實(shí)時(shí)排行信息包含直播間在線用戶列表哈蝇,各種禮物排行榜棺妓,彈幕消息(可以理解為按消息維度的消息排行榜)等信息,適合使用 Redis 中的 SortedSet 結(jié)構(gòu)進(jìn)行存儲(chǔ)炮赦。
redis 設(shè)置過(guò)期時(shí)間
Redis中有個(gè)設(shè)置時(shí)間過(guò)期的功能怜跑,即對(duì)存儲(chǔ)在 redis 數(shù)據(jù)庫(kù)中的值可以設(shè)置一個(gè)過(guò)期時(shí)間。作為一個(gè)緩存數(shù)據(jù)庫(kù)吠勘,這是非常實(shí)用的性芬。如我們一般項(xiàng)目中的 token 或者一些登錄信息,尤其是短信驗(yàn)證碼都是有時(shí)間限制的剧防,按照傳統(tǒng)的數(shù)據(jù)庫(kù)處理方式植锉,一般都是自己判斷過(guò)期,這樣無(wú)疑會(huì)嚴(yán)重影響項(xiàng)目性能峭拘。
我們 set key 的時(shí)候俊庇,都可以給一個(gè) expire time,就是過(guò)期時(shí)間鸡挠,通過(guò)過(guò)期時(shí)間我們可以指定這個(gè) key 可以存活的時(shí)間暇赤。
如果假設(shè)你設(shè)置了一批 key 只能存活1個(gè)小時(shí),那么接下來(lái)1小時(shí)后宵凌,redis是怎么對(duì)這批key進(jìn)行刪除的鞋囊?
定期刪除+惰性刪除。
通過(guò)名字大概就能猜出這兩個(gè)刪除方式的意思了瞎惫。
定期刪除:redis默認(rèn)是每隔 100ms 就隨機(jī)抽取一些設(shè)置了過(guò)期時(shí)間的key溜腐,檢查其是否過(guò)期,如果過(guò)期就刪除瓜喇。注意這里是隨機(jī)抽取的挺益。為什么要隨機(jī)呢?你想一想假如 redis 存了幾十萬(wàn)個(gè) key 乘寒,每隔100ms就遍歷所有的設(shè)置過(guò)期時(shí)間的 key 的話望众,就會(huì)給 CPU 帶來(lái)很大的負(fù)載!
惰性刪除:定期刪除可能會(huì)導(dǎo)致很多過(guò)期 key 到了時(shí)間并沒(méi)有被刪除掉伞辛。所以就有了惰性刪除烂翰。假如你的過(guò)期 key,靠定期刪除沒(méi)有被刪除掉蚤氏,還停留在內(nèi)存里甘耿,除非你的系統(tǒng)去查一下那個(gè) key,才會(huì)被redis給刪除掉竿滨。這就是所謂的惰性刪除佳恬,也是夠懶的哈捏境!
但是僅僅通過(guò)設(shè)置過(guò)期時(shí)間還是有問(wèn)題的。我們想一下:如果定期刪除漏掉了很多過(guò)期 key毁葱,然后你也沒(méi)及時(shí)去查垫言,也就沒(méi)走惰性刪除,此時(shí)會(huì)怎么樣倾剿?如果大量過(guò)期key堆積在內(nèi)存里骏掀,導(dǎo)致redis內(nèi)存塊耗盡了。怎么解決這個(gè)問(wèn)題呢柱告?
redis 內(nèi)存淘汰機(jī)制。
redis 內(nèi)存淘汰機(jī)制(MySQL里有2000w數(shù)據(jù)笑陈,Redis中只存20w的數(shù)據(jù)际度,如何保證Redis中的數(shù)據(jù)都是熱點(diǎn)數(shù)據(jù)?)
redis 配置文件 redis.conf 中有相關(guān)注釋涵妥,大家可以自行查閱或者通過(guò)這個(gè)網(wǎng)址查看:http://download.redis.io/redis-stable/redis.conf
redis 提供 6種數(shù)據(jù)淘汰策略:
volatile-lru:從已設(shè)置過(guò)期時(shí)間的數(shù)據(jù)集(server.db[i].expires)中挑選最近最少使用的數(shù)據(jù)淘汰
volatile-ttl:從已設(shè)置過(guò)期時(shí)間的數(shù)據(jù)集(server.db[i].expires)中挑選將要過(guò)期的數(shù)據(jù)淘汰
volatile-random:從已設(shè)置過(guò)期時(shí)間的數(shù)據(jù)集(server.db[i].expires)中任意選擇數(shù)據(jù)淘汰
allkeys-lru:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí)乖菱,在鍵空間中,移除最近最少使用的key(這個(gè)是最常用的).
allkeys-random:從數(shù)據(jù)集(server.db[i].dict)中任意選擇數(shù)據(jù)淘汰
no-eviction:禁止驅(qū)逐數(shù)據(jù)蓬网,也就是說(shuō)當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí)窒所,新寫入操作會(huì)報(bào)錯(cuò)。這個(gè)應(yīng)該沒(méi)人使用吧帆锋!
備注: 關(guān)于 redis 設(shè)置過(guò)期時(shí)間以及內(nèi)存淘汰機(jī)制吵取,我這里只是簡(jiǎn)單的總結(jié)一下,后面會(huì)專門寫一篇文章來(lái)總結(jié)锯厢!
redis 持久化機(jī)制(怎么保證 redis 掛掉之后再重啟數(shù)據(jù)可以進(jìn)行恢復(fù))
很多時(shí)候我們需要持久化數(shù)據(jù)也就是將內(nèi)存中的數(shù)據(jù)寫入到硬盤里面皮官,大部分原因是為了之后重用數(shù)據(jù)(比如重啟機(jī)器、機(jī)器故障之后回復(fù)數(shù)據(jù))实辑,或者是為了防止系統(tǒng)故障而將數(shù)據(jù)備份到一個(gè)遠(yuǎn)程位置捺氢。
Redis不同于Memcached的很重一點(diǎn)就是,Redis支持持久化剪撬,而且支持兩種不同的持久化操作摄乒。Redis的一種持久化方式叫快照(snapshotting,RDB),另一種方式是只追加文件(append-only file,AOF).這兩種方法各有千秋残黑,下面我會(huì)詳細(xì)這兩種持久化方法是什么馍佑,怎么用,如何選擇適合自己的持久化方法梨水。
快照(snapshotting)持久化(RDB)
Redis可以通過(guò)創(chuàng)建快照來(lái)獲得存儲(chǔ)在內(nèi)存里面的數(shù)據(jù)在某個(gè)時(shí)間點(diǎn)上的副本挤茄。Redis創(chuàng)建快照之后炕贵,可以對(duì)快照進(jìn)行備份卵牍,可以將快照復(fù)制到其他服務(wù)器從而創(chuàng)建具有相同數(shù)據(jù)的服務(wù)器副本(Redis主從結(jié)構(gòu)挑辆,主要用來(lái)提高Redis性能),還可以將快照留在原地以便重啟服務(wù)器的時(shí)候使用区匠。
快照持久化是Redis默認(rèn)采用的持久化方式,在redis.conf配置文件中默認(rèn)有此下配置:
save 900 1? ? ? ? ? ? ? #在900秒(15分鐘)之后帆喇,如果至少有1個(gè)key發(fā)生變化钓简,Redis就會(huì)自動(dòng)觸發(fā)BGSAVE命令創(chuàng)建快照。save 300 10? ? ? ? ? ? #在300秒(5分鐘)之后评凝,如果至少有10個(gè)key發(fā)生變化追葡,Redis就會(huì)自動(dòng)觸發(fā)BGSAVE命令創(chuàng)建快照。save 60 10000? ? ? ? #在60秒(1分鐘)之后奕短,如果至少有10000個(gè)key發(fā)生變化宜肉,Redis就會(huì)自動(dòng)觸發(fā)BGSAVE命令創(chuàng)建快照。
AOF(append-only file)持久化
與快照持久化相比翎碑,AOF持久化 的實(shí)時(shí)性更好谬返,因此已成為主流的持久化方案。默認(rèn)情況下Redis沒(méi)有開啟AOF(append only file)方式的持久化日杈,可以通過(guò)appendonly參數(shù)開啟:
appendonly yes
開啟AOF持久化后每執(zhí)行一條會(huì)更改Redis中的數(shù)據(jù)的命令遣铝,Redis就會(huì)將該命令寫入硬盤中的AOF文件。AOF文件的保存位置和RDB文件的位置相同莉擒,都是通過(guò)dir參數(shù)設(shè)置的酿炸,默認(rèn)的文件名是appendonly.aof。
在Redis的配置文件中存在三種不同的 AOF 持久化方式涨冀,它們分別是:
appendfsync always? ? #每次有數(shù)據(jù)修改發(fā)生時(shí)都會(huì)寫入AOF文件,這樣會(huì)嚴(yán)重降低Redis的速度appendfsync everysec? #每秒鐘同步一次填硕,顯示地將多個(gè)寫命令同步到硬盤appendfsync no? ? ? #讓操作系統(tǒng)決定何時(shí)進(jìn)行同步
為了兼顧數(shù)據(jù)和寫入性能,用戶可以考慮 appendfsync everysec選項(xiàng) 鹿鳖,讓Redis每秒同步一次AOF文件廷支,Redis性能幾乎沒(méi)受到任何影響。而且這樣即使出現(xiàn)系統(tǒng)崩潰栓辜,用戶最多只會(huì)丟失一秒之內(nèi)產(chǎn)生的數(shù)據(jù)恋拍。當(dāng)硬盤忙于執(zhí)行寫入操作的時(shí)候,Redis還會(huì)優(yōu)雅的放慢自己的速度以便適應(yīng)硬盤的最大寫入速度藕甩。
Redis 4.0 對(duì)于持久化機(jī)制的優(yōu)化
Redis 4.0 開始支持 RDB 和 AOF 的混合持久化(默認(rèn)關(guān)閉施敢,可以通過(guò)配置項(xiàng)aof-use-rdb-preamble開啟)。
如果把混合持久化打開狭莱,AOF 重寫的時(shí)候就直接把 RDB 的內(nèi)容寫到 AOF 文件開頭僵娃。這樣做的好處是可以結(jié)合 RDB 和 AOF 的優(yōu)點(diǎn), 快速加載同時(shí)避免丟失過(guò)多的數(shù)據(jù)。當(dāng)然缺點(diǎn)也是有的腋妙, AOF 里面的 RDB 部分是壓縮格式不再是 AOF 格式默怨,可讀性較差。
補(bǔ)充內(nèi)容:AOF 重寫
AOF重寫可以產(chǎn)生一個(gè)新的AOF文件骤素,這個(gè)新的AOF文件和原有的AOF文件所保存的數(shù)據(jù)庫(kù)狀態(tài)一樣匙睹,但體積更小愚屁。
AOF重寫是一個(gè)有歧義的名字,該功能是通過(guò)讀取數(shù)據(jù)庫(kù)中的鍵值對(duì)來(lái)實(shí)現(xiàn)的痕檬,程序無(wú)須對(duì)現(xiàn)有AOF文件進(jìn)行任伺讀入霎槐、分析或者寫入操作。
在執(zhí)行 BGREWRITEAOF 命令時(shí)梦谜,Redis 服務(wù)器會(huì)維護(hù)一個(gè) AOF 重寫緩沖區(qū)丘跌,該緩沖區(qū)會(huì)在子進(jìn)程創(chuàng)建新AOF文件期間,記錄服務(wù)器執(zhí)行的所有寫命令唁桩。當(dāng)子進(jìn)程完成創(chuàng)建新AOF文件的工作之后闭树,服務(wù)器會(huì)將重寫緩沖區(qū)中的所有內(nèi)容追加到新AOF文件的末尾,使得新舊兩個(gè)AOF文件所保存的數(shù)據(jù)庫(kù)狀態(tài)一致荒澡。最后报辱,服務(wù)器用新的AOF文件替換舊的AOF文件,以此來(lái)完成AOF文件重寫操作
redis 事務(wù)
Redis 通過(guò) MULTI仰猖、EXEC、WATCH 等命令來(lái)實(shí)現(xiàn)事務(wù)(transaction)功能奈籽。事務(wù)提供了一種將多個(gè)命令請(qǐng)求打包饥侵,然后一次性、按順序地執(zhí)行多個(gè)命令的機(jī)制衣屏,并且在事務(wù)執(zhí)行期間躏升,服務(wù)器不會(huì)中斷事務(wù)而改去執(zhí)行其他客戶端的命令請(qǐng)求,它會(huì)將事務(wù)中的所有命令都執(zhí)行完畢狼忱,然后才去處理其他客戶端的命令請(qǐng)求膨疏。
在傳統(tǒng)的關(guān)系式數(shù)據(jù)庫(kù)中,常常用 ACID 性質(zhì)來(lái)檢驗(yàn)事務(wù)功能的可靠性和安全性钻弄。在 Redis 中佃却,事務(wù)總是具有原子性(Atomicity)、一致性(Consistency)和隔離性(Isolation)窘俺,并且當(dāng) Redis 運(yùn)行在某種特定的持久化模式下時(shí)饲帅,事務(wù)也具有持久性(Durability)。
緩存雪崩和緩存穿透問(wèn)題解決方案
緩存雪崩
簡(jiǎn)介:緩存同一時(shí)間大面積的失效瘤泪,所以灶泵,后面的請(qǐng)求都會(huì)落到數(shù)據(jù)庫(kù)上,造成數(shù)據(jù)庫(kù)短時(shí)間內(nèi)承受大量請(qǐng)求而崩掉对途。
解決辦法:
事前:盡量保證整個(gè) redis 集群的高可用性赦邻,發(fā)現(xiàn)機(jī)器宕機(jī)盡快補(bǔ)上。選擇合適的內(nèi)存淘汰策略实檀。
事中:本地ehcache緩存 + hystrix限流&降級(jí)惶洲,避免MySQL崩掉
事后:利用 redis 持久化機(jī)制保存的數(shù)據(jù)盡快恢復(fù)緩存
image
緩存穿透
簡(jiǎn)介:一般是黑客故意去請(qǐng)求緩存中不存在的數(shù)據(jù)按声,導(dǎo)致所有的請(qǐng)求都落到數(shù)據(jù)庫(kù)上,造成數(shù)據(jù)庫(kù)短時(shí)間內(nèi)承受大量請(qǐng)求而崩掉湃鹊。
解決辦法: 有很多種方法可以有效地解決緩存穿透問(wèn)題儒喊,最常見的則是采用布隆過(guò)濾器,將所有可能存在的數(shù)據(jù)哈希到一個(gè)足夠大的bitmap中币呵,一個(gè)一定不存在的數(shù)據(jù)會(huì)被 這個(gè)bitmap攔截掉怀愧,從而避免了對(duì)底層存儲(chǔ)系統(tǒng)的查詢壓力。另外也有一個(gè)更為簡(jiǎn)單粗暴的方法(我們采用的就是這種)余赢,如果一個(gè)查詢返回的數(shù)據(jù)為空(不管是數(shù) 據(jù)不存在芯义,還是系統(tǒng)故障),我們?nèi)匀话堰@個(gè)空結(jié)果進(jìn)行緩存妻柒,但它的過(guò)期時(shí)間會(huì)很短扛拨,最長(zhǎng)不超過(guò)五分鐘。
如何解決 Redis 的并發(fā)競(jìng)爭(zhēng) Key 問(wèn)題
所謂 Redis 的并發(fā)競(jìng)爭(zhēng) Key 的問(wèn)題也就是多個(gè)系統(tǒng)同時(shí)對(duì)一個(gè) key 進(jìn)行操作举塔,但是最后執(zhí)行的順序和我們期望的順序不同绑警,這樣也就導(dǎo)致了結(jié)果的不同!
推薦一種方案:分布式鎖(zookeeper 和 redis 都可以實(shí)現(xiàn)分布式鎖)央渣。(如果不存在 Redis 的并發(fā)競(jìng)爭(zhēng) Key 問(wèn)題计盒,不要使用分布式鎖,這樣會(huì)影響性能)
基于zookeeper臨時(shí)有序節(jié)點(diǎn)可以實(shí)現(xiàn)的分布式鎖芽丹。大致思想為:每個(gè)客戶端對(duì)某個(gè)方法加鎖時(shí)北启,在zookeeper上的與該方法對(duì)應(yīng)的指定節(jié)點(diǎn)的目錄下,生成一個(gè)唯一的瞬時(shí)有序節(jié)點(diǎn)拔第。 判斷是否獲取鎖的方式很簡(jiǎn)單咕村,只需要判斷有序節(jié)點(diǎn)中序號(hào)最小的一個(gè)。 當(dāng)釋放鎖的時(shí)候蚊俺,只需將這個(gè)瞬時(shí)節(jié)點(diǎn)刪除即可懈涛。同時(shí),其可以避免服務(wù)宕機(jī)導(dǎo)致的鎖無(wú)法釋放泳猬,而產(chǎn)生的死鎖問(wèn)題肩钠。完成業(yè)務(wù)流程后,刪除對(duì)應(yīng)的子節(jié)點(diǎn)釋放鎖暂殖。
在實(shí)踐中价匠,當(dāng)然是從以可靠性為主。所以首推Zookeeper呛每。
參考:
http://www.reibang.com/p/8bddd381de06
如何保證緩存與數(shù)據(jù)庫(kù)雙寫時(shí)的數(shù)據(jù)一致性踩窖?
你只要用緩存,就可能會(huì)涉及到緩存與數(shù)據(jù)庫(kù)雙存儲(chǔ)雙寫晨横,你只要是雙寫洋腮,就一定會(huì)有數(shù)據(jù)一致性的問(wèn)題箫柳,那么你如何解決一致性問(wèn)題?
一般來(lái)說(shuō)啥供,就是如果你的系統(tǒng)不是嚴(yán)格要求緩存+數(shù)據(jù)庫(kù)必須一致性的話悯恍,緩存可以稍微的跟數(shù)據(jù)庫(kù)偶爾有不一致的情況,最好不要做這個(gè)方案伙狐,讀請(qǐng)求和寫請(qǐng)求串行化涮毫,串到一個(gè)內(nèi)存隊(duì)列里去,這樣就可以保證一定不會(huì)出現(xiàn)不一致的情況
串行化之后贷屎,就會(huì)導(dǎo)致系統(tǒng)的吞吐量會(huì)大幅度的降低罢防,用比正常情況下多幾倍的機(jī)器去支撐線上的一個(gè)請(qǐng)求。
還有一種方式就是可能會(huì)暫時(shí)產(chǎn)生不一致的情況唉侄,但是發(fā)生的幾率特別小咒吐,就是先更新數(shù)據(jù)庫(kù),然后再刪除緩存属划。
這種情況不存在并發(fā)問(wèn)題么恬叹?
不是的。假設(shè)這會(huì)有兩個(gè)請(qǐng)求同眯,一個(gè)請(qǐng)求A做查詢操作绽昼,一個(gè)請(qǐng)求B做更新操作,那么會(huì)有如下情形產(chǎn)生
(1)緩存剛好失效
(2)請(qǐng)求A查詢數(shù)據(jù)庫(kù)嗽测,得一個(gè)舊值
(3)請(qǐng)求B將新值寫入數(shù)據(jù)庫(kù)
(4)請(qǐng)求B刪除緩存
(5)請(qǐng)求A將查到的舊值寫入緩存
ok绪励,如果發(fā)生上述情況肿孵,確實(shí)是會(huì)發(fā)生臟數(shù)據(jù)唠粥。
然而,發(fā)生這種情況的概率又有多少呢停做?
發(fā)生上述情況有一個(gè)先天性條件晤愧,就是步驟(3)的寫數(shù)據(jù)庫(kù)操作比步驟(2)的讀數(shù)據(jù)庫(kù)操作耗時(shí)更短,才有可能使得步驟(4)先于步驟(5)蛉腌」俜荩可是,大家想想烙丛,數(shù)據(jù)庫(kù)的讀操作的速度遠(yuǎn)快于寫操作的(不然做讀寫分離干嘛舅巷,做讀寫分離的意義就是因?yàn)樽x操作比較快,耗資源少)河咽,因此步驟(3)耗時(shí)比步驟(2)更短钠右,這一情形很難出現(xiàn)。
如何解決上述并發(fā)問(wèn)題忘蟹?
首先飒房,給緩存設(shè)有效時(shí)間是一種方案搁凸。其次,采用異步延時(shí)刪除策略狠毯,保證讀請(qǐng)求完成以后护糖,再進(jìn)行刪除操作。