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ù)即可讶凉!
高并發(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ù)懂讯。
為什么要用 redis 而不用 map/guava 做緩存?
下面的內(nèi)容來(lái)自 segmentfault 一位網(wǎng)友的提問(wèn)荷憋,地址:https://segmentfault.com/q/1010000009106416
緩存分為本地緩存和分布式緩存。以 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 我總結(jié)了下面四點(diǎn)∷芫叮現(xiàn)在公司一般都是用 redis 來(lái)實(shí)現(xiàn)緩存,而且 redis 自身也越來(lái)越強(qiáng)大了填具!
- 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ù)用模型。
來(lái)自網(wǎng)絡(luò)上的一張圖凉蜂,這里分享給大家琼梆!
redis 常見(jiàn)數(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=JavaUser293847
value={
“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)存開(kāi)銷。
另外可以通過(guò) lrange 命令,就是從某個(gè)元素開(kāi)始讀取多少個(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 中的 Sorted Set 結(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)人使用吧运挫!
4.0版本后增加以下兩種:
- volatile-lfu:從已設(shè)置過(guò)期時(shí)間的數(shù)據(jù)集(server.db[i].expires)中挑選最不經(jīng)常使用的數(shù)據(jù)淘汰
- allkeys-lfu:當(dāng)內(nèi)存不足以容納新寫入數(shù)據(jù)時(shí)状共,在鍵空間中,移除最不經(jīng)常使用的key
備注: 關(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)有開(kāi)啟AOF(append only file)方式的持久化算吩,可以通過(guò)appendonly參數(shù)開(kāi)啟:
appendonly yes
開(kāi)啟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 開(kāi)始支持 RDB 和 AOF 的混合持久化(默認(rèn)關(guān)閉溪食,可以通過(guò)配置項(xiàng) aof-use-rdb-preamble
開(kāi)啟)错沃。
如果把混合持久化打開(kāi),AOF 重寫的時(shí)候就直接把 RDB 的內(nèi)容寫到 AOF 文件開(kāi)頭玉掸。這樣做的好處是可以結(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文件重寫操作
更多內(nèi)容可以查看我的這篇文章:
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)求而崩掉捧请。
解決辦法(中華石杉老師在他的視頻中提到過(guò)疹蛉,視頻地址在最后一個(gè)問(wèn)題中有提到):
- 事前:盡量保證整個(gè) redis 集群的高可用性,發(fā)現(xiàn)機(jī)器宕機(jī)盡快補(bǔ)上育韩。選擇合適的內(nèi)存淘汰策略闺鲸。
- 事中:本地ehcache緩存 + hystrix限流&降級(jí)摸恍,避免MySQL崩掉
- 事后:利用 redis 持久化機(jī)制保存的數(shù)據(jù)盡快恢復(fù)緩存
緩存穿透
簡(jiǎn)介:一般是黑客故意去請(qǐng)求緩存中不存在的數(shù)據(jù)误墓,導(dǎo)致所有的請(qǐng)求都落到數(shù)據(jù)庫(kù)上,造成數(shù)據(jù)庫(kù)短時(shí)間內(nèi)承受大量請(qǐng)求而崩掉然想。
解決辦法: 有很多種方法可以有效地解決緩存穿透問(wèn)題变泄,最常見(jià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卢鹦。
參考:
如何保證緩存與數(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)求。