實戰(zhàn)1|使用分布式緩存Redis實現(xiàn)熱點資源順序訪問
應(yīng)用現(xiàn)狀
在傳統(tǒng)單機(jī)部署的情況下,可以使用Java并發(fā)處理相關(guān)的API(如ReentrantLock或synchronized)進(jìn)行互斥控制。這種Java提供的原生鎖機(jī)制可以保證在同一個Java虛擬機(jī)進(jìn)程內(nèi)的多個線程同步執(zhí)行,避免出現(xiàn)無序現(xiàn)象。
但在互聯(lián)網(wǎng)場景,如商品秒殺中,隨著整個系統(tǒng)的并發(fā)飆升,需要多臺機(jī)器并發(fā)運行,假設(shè)此時兩個用戶的請求同時到來,但落在了不同的機(jī)器上,雖然這兩個請求是可以同時執(zhí)行,但是因為兩個機(jī)器運行在兩個不同的Java虛擬機(jī)里面,他們加的鎖只對屬于自己Java虛擬機(jī)里面的線程有效,對于其他Java虛擬機(jī)的線程是無效的。因此,Java提供的原生鎖機(jī)制在多機(jī)部署場景下失效了,這是因為兩臺機(jī)器加的鎖不是同一個鎖(兩個鎖在不同的Java虛擬機(jī)里面),這樣便會出現(xiàn)庫存超賣的現(xiàn)象。
解決方案
基于存在的現(xiàn)狀,我們只要保證兩臺機(jī)器加的鎖是同一個鎖,用加鎖的方式對某種資源進(jìn)行順序訪問控制。這就需要分布式鎖登場了。
分布式鎖的思路是:在整個系統(tǒng)提供一個全局、唯一的獲取鎖的“東西”,然后每個系統(tǒng)在需要加鎖時,都去問這個“東西”拿到一把鎖,這樣不同的系統(tǒng)拿到的就可以認(rèn)為是同一把鎖。
當(dāng)前分布式加鎖主要有三種方式:(磁盤)數(shù)據(jù)庫、緩存數(shù)據(jù)庫、Zookeeper。
使用分布式緩存服務(wù)中Redis類型的緩存實例實現(xiàn)分布式加鎖,有幾大優(yōu)勢:
1、加鎖操作簡單,使用SET、GET、DEL等幾條簡單命令即可實現(xiàn)鎖的獲取和釋放。
2、性能優(yōu)越,緩存數(shù)據(jù)的讀寫優(yōu)于磁盤數(shù)據(jù)庫與Zookeeper。
3、可靠性強(qiáng),分布式緩存Redis有主備和集群實例類型,避免單點故障。
對分布式應(yīng)用加鎖,能夠避免出現(xiàn)庫存超賣及無序訪問等現(xiàn)象,實戰(zhàn):如何使用Redis對分布式應(yīng)用加鎖。
前提條件
1、已購買彈性云服務(wù)器(ECS)且系統(tǒng)類型為Windows。
2、在ECS上安裝JDK1.8以上版本和Eclipse,下載jedis客戶端(點此處直接下載jar包)。
3、已購買分布式緩存Redis緩存實例且和ECS選擇相同虛擬私有云、子網(wǎng)以及安全組。
操作步驟
1、在ECS上運行Eclipse,創(chuàng)建一個java工程,為示例代碼分別創(chuàng)建一個分布式鎖實現(xiàn)類DistributedLock.java和測試類CaseTest.java,將jedis客戶端作為libs引用到工程中。
2、將分布式緩存Redis緩存實例的連接地址、端口以及連接密碼配置到分布式鎖實現(xiàn)類DistributedLock.java示例代碼文件中。在DistributedLock.java中,host及port配置為實例的連接地址及端口號,在getLockWithTimeout、releaseLock方法中需配置passwd值為實例訪問密碼。
3、將測試類CaseTest中加鎖部分注釋掉,變成無鎖情況。
4、編譯及運行無鎖的類,運行結(jié)果是搶購無序的。
5、取消測試類CaseTest中注釋的加鎖內(nèi)容,編譯并運行得到有序的搶購。
詳細(xì)步驟及代碼詳情請參考:使用DCS實現(xiàn)熱點資源順序訪問
實戰(zhàn)3|使用分布式緩存Redis快速搭建高性能緩存服務(wù)
華為云分布式緩存服務(wù)DCS,提供單機(jī)、主備、集群等豐富的緩存類型,滿足用戶高讀寫性能及快速數(shù)據(jù)訪問的業(yè)務(wù)訴求。華為云控制臺提供一鍵式創(chuàng)建緩存實例,以及豐富的實例管理操作,幫助用戶省去運維煩惱。如何創(chuàng)建并連接一個Redis緩存實例為例,帶大家快速上手分布式緩存技術(shù)。
準(zhǔn)備環(huán)境
登錄華為云控制臺。在控制臺頁面中選擇“網(wǎng)絡(luò)> 虛擬私有云”,創(chuàng)建VPC(虛擬私有云),用于對緩存實例進(jìn)行安全網(wǎng)絡(luò)隔離。
在控制臺頁面中選擇“計算> 彈性云服務(wù)器”,創(chuàng)建一臺彈性云服務(wù)器(ECS),用于下載客戶端連接緩存實例。
創(chuàng)建實例
登錄華為云控制臺,選擇“應(yīng)用服務(wù)> 分布式緩存服務(wù)”,選擇計費模式。
在DCS總覽頁面,單擊“購買緩存實例”,選擇實例配置,創(chuàng)建實例。
連接緩存實例
緩存實例創(chuàng)建成功后,在DCS實例管理頁找到實例連接地址和端口。
登錄ECS,下載和安裝客戶端。
連接實例。
讀寫緩存數(shù)據(jù)。
上述就是創(chuàng)建并連接一個Redis緩存實例為例的教程,快來創(chuàng)建一個高性能的服務(wù)吧。
了解詳情:點擊此處前往
實戰(zhàn)2|使用分布式緩存Redis實現(xiàn)排行榜功能
場景介紹
在網(wǎng)頁和APP中常常需要用到榜單的功能,對某個key-value的列表進(jìn)行降序顯示。當(dāng)操作和查詢并發(fā)大的時候,使用傳統(tǒng)數(shù)據(jù)庫就會遇到性能瓶頸,造成較大的時延。
使用分布式緩存服務(wù)(DCS)的Redis版本,可以實現(xiàn)一個商品熱銷排行榜的功能。它的優(yōu)勢在于:
數(shù)據(jù)保存在緩存中,讀寫速度非???。
提供字符串(String)、鏈表(List)、集合(Set)、哈希(Hash)等多種數(shù)據(jù)結(jié)構(gòu)類型的存儲。
實踐指導(dǎo)
1、準(zhǔn)備一臺彈性云服務(wù)器(ECS),選擇Windows系統(tǒng)類型。
2、在ECS上安裝JDK1.8以上版本和Eclipse,下載jedis客戶端(點此處直接下載jar包)。
3、在華為云控制臺購買DCS緩存實例。注意和ECS選擇相同虛擬私有云、子網(wǎng)以及安全組。
4、在ECS上運行Eclipse,創(chuàng)建一個java工程,為示例代碼創(chuàng)建一個productSalesRankDemo.java文件,并將jedis客戶端作為library引用到工程中。
5、將DCS緩存實例的連接地址、端口以及連接密碼配置到示例代碼文件中。
6、編譯并運行得到結(jié)果。
代碼示例參考:點擊這里前往代碼示例
運行結(jié)果
編譯并運行以上Demo程序,運行結(jié)果:點擊這里前往運行結(jié)果
實戰(zhàn)4|如何發(fā)現(xiàn)和處理大Key和熱Key
如何處理優(yōu)化大Key和熱Key
大Key
進(jìn)行大Key拆分,分為以下幾種場景:
該對象為String類型的大Key:可以嘗試將對象分拆成幾個Key-Value, 使用MGET或者多個GET組成的pipeline獲取值,分拆單次操作的壓力,對于集群來說可以將操作壓力平攤到多個分片上,降低對單個分片的影響。
該對象為集合類型的大Key,并且需要整存整取:在設(shè)計上嚴(yán)格禁止這種場景的出現(xiàn),因為無法拆分。有效的方法是將該大Key從Redis去除,單獨放到其余存儲介質(zhì)上。
該對象為集合類型的大Key,每次只需操作部分元素:將集合類型中的元素分拆。以Hash類型為例,可以在客戶端定義一個分拆Key的數(shù)量N,每次對HGET和HSET操作的field計算哈希值并取模N,確定該field落在哪個Key上,實現(xiàn)上類似于Redis Cluster的計算slot的算法。
將大Key單獨轉(zhuǎn)移到其余存儲介質(zhì)。
無法拆分的大Key建議使用此方法,將不適用Redis能力的數(shù)據(jù)存至其它存儲介質(zhì),如SFS或者其余NoSQL數(shù)據(jù)庫,并在Redis中刪除該大Key。
注意:禁止使用DEL直接刪除大Key,可能會造成Redis阻塞,甚至主備倒換。
合理設(shè)置過期時間并對過期數(shù)據(jù)定期清理。
合理設(shè)置過期時間,避免歷史數(shù)據(jù)在Redis中大量堆積。由于Redis的惰性刪除策略,過期數(shù)據(jù)可能并不能及時清理,如果發(fā)現(xiàn)Redis過期Key清理較慢,建議配置過期Key掃描。
熱Key
使用讀寫分離。
如果熱Key主要是讀流量較大,則可以在客戶端配置讀寫分離,降低對主節(jié)點的影響。還可以增加多個副本以滿足讀需求,但是備機(jī)較多也有相應(yīng)的影響,華為云DCS主備節(jié)點之間使用的是星型復(fù)制,即所有的備節(jié)點都直接和主節(jié)點保持同步,這樣能保證備節(jié)點之間相互獨立,且復(fù)制延遲較小。缺點是在備節(jié)點數(shù)量較多的情況下,主節(jié)點的CPU和網(wǎng)絡(luò)負(fù)載會較高。
使用客戶端緩存/本地緩存。
該方案需要提前了解業(yè)務(wù)的熱點Key有哪些,設(shè)計客戶端/本地和遠(yuǎn)端Redis的兩級緩存架構(gòu),熱點數(shù)據(jù)優(yōu)先從本地緩存獲取,寫入時同時更新,這樣能夠分擔(dān)熱點數(shù)據(jù)的大部分讀壓力。缺點是需要修改客戶端架構(gòu)和代碼,改造成本較高。
設(shè)計熔斷。
熱Key極易造成緩存擊穿,高峰期請求都直接透傳到后端數(shù)據(jù)庫上,從而導(dǎo)致業(yè)務(wù)雪崩。因此熱Key的優(yōu)化一定需要設(shè)計系統(tǒng)的熔斷,在發(fā)生擊穿的場景下進(jìn)行限流和服務(wù)下調(diào),保護(hù)系統(tǒng)的可用性。
如何發(fā)現(xiàn)大Key和熱Key
方法
|
說明
|
---|---|
使用分布式緩存服務(wù)DCS自帶的大Key和熱Key分析工具進(jìn)行分析 |
|
通過redis-cli的bigkeys和hotkeys參數(shù)查找大Key和熱Key |
1、Redis-cli提供了bigkeys參數(shù),能夠使redis-cli以遍歷的方式分析Redis實例中的所有Key,并返回Key的整體統(tǒng)計信息與每個數(shù)據(jù)類型中Top1的大Key,bigkeys僅能分析并輸入六種數(shù)據(jù)類型(STRING、LIST、HASH、SET、ZSET、STREAM),命令示例為:redis-cli -h <實例的連接地址> -p <端口> -a <密碼> --bigkeys。 2、自Redis 4.0版本起,redis-cli提供了hotkeys參數(shù),可以快速幫您找出業(yè)務(wù)中的熱Key,該命令需要在業(yè)務(wù)實際運行期間執(zhí)行,以統(tǒng)計運行期間的熱Key。命令示例為:redis-cli -h <實例的連接地址> -p <端口> -a <密碼> --hotkeys。熱Key的詳情可以在結(jié)果中的summary部分獲取到。 |
通過Redis命令查找大Key |
如果有已知的大Key模式,例如知道其前綴為huaweicloud:msg:test,那么可以通過一個程序,SCAN符合該前綴的Key,然后通過查詢成員數(shù)量和查詢Key大小的相關(guān)命令,來判斷具體的大Key。 1、查詢成員數(shù)量的相關(guān)命令:LLEN,HLEN,XLEN,ZCARD,SCARD 2、查詢Key占用內(nèi)存大小的命令:DEBUG OBJECT,MEMORY USAGE 注意: 該方法會大量消耗計算資源,請知曉并評估其風(fēng)險,不要在業(yè)務(wù)壓力較大的實例使用該方法,否則可能會對正常業(yè)務(wù)造成影響。 |
通過redis-rdb-tools工具找出大Key |
redis-rdb-tools是分析Redis RDB快照文件的開源工具??梢愿鶕?jù)需求自定義分析Redis實例中所有Key的內(nèi)存占用情況。 使用此方法需要在分布式緩存服務(wù)DCS實例備份與恢復(fù)頁簽中導(dǎo)出實例的rdb文件。 注意: 該方法時效性相較于在線分析來說較差,優(yōu)勢在于完全不影響現(xiàn)有業(yè)務(wù)。 |
分布式緩存服務(wù)教程視頻
分布式緩存服務(wù)DCS
04:53
分布式緩存服務(wù)DCS
03:40
分布式緩存服務(wù)DCS
04:16