Redis命令之hscan
1、業(yè)務(wù)背景
? ? ? 在互聯(lián)網(wǎng)的項目中為了提高性能和吞吐量,通常需要做一些優(yōu)化和數(shù)據(jù)異構(gòu),比如查詢DB,我們可以優(yōu)化索引,通過命中索引來提高查詢速度,也可以把數(shù)據(jù)異構(gòu)到Redis,雖然Redis的性能非常好也支持5種數(shù)據(jù)結(jié)構(gòu),如果想性能更好的話,可以考慮異構(gòu)到JVM緩存,也就是DB的數(shù)據(jù)異構(gòu)到Redis,Redis的數(shù)據(jù)定期異構(gòu)到JVM緩存
2、帶來問題
? ? 在Redis中通過用一個hashmap來存儲業(yè)務(wù)數(shù)據(jù),當(dāng)這些業(yè)務(wù)數(shù)據(jù)比較小,我們可以通過hGetAll來獲取redis的整個map然后設(shè)置到JVM緩存中,伴隨這業(yè)務(wù)的增長Redis中的key會非常多,這是我們調(diào)用hGetAll獲取數(shù)據(jù)時就會把Redis給hang住,造成整個redis阻塞,進(jìn)而影響整個redis集群的使用,導(dǎo)致其它業(yè)務(wù)調(diào)用redis時性能抖動
3、解決方案
? ? ? 1調(diào)整獲取命令hGetAll改成hscan,分階段獲取
? ? ? 2調(diào)整hash-max-ziplist-entries參數(shù)閾值由于調(diào)整改配置需要重新刷數(shù)據(jù)(不建議)
? ? ? ?我們采取方案1,通過HSCAN來迭代獲取對應(yīng)的值,通過指定游標(biāo)和獲取的數(shù)量,比如一次獲取10個,命令如下HSCAN key cursor [MATCH pattern] [COUNT count]? 它是一個增量式命令,每次查詢都是返回一部分?jǐn)?shù)據(jù),還可以通過它處理模糊查詢,所以不會像hGetAll類命令hang住Redis導(dǎo)致服務(wù)短暫停滯,最開始cursor我們都設(shè)置為0就好,count來控制每次遍歷的數(shù)量,由于這個命令執(zhí)行的時間復(fù)雜度是O(N),所以count越大,每次執(zhí)行時間理論上會越長,可以根據(jù)實際場景進(jìn)行調(diào)整,在遍歷時候判斷返回的游標(biāo)cursor是否為0,如果為0代表整個遍歷結(jié)束。
類似的命令如下:原理都一樣,都是避免把redis的進(jìn)場hang住,
- SCAN?命令用于迭代當(dāng)前數(shù)據(jù)庫中的數(shù)據(jù)庫鍵。
- SSCAN?命令用于迭代集合鍵中的元素。
- HSCAN?命令用于迭代哈希鍵中的鍵值對。
- ZSCAN?命令用于迭代有序集合中的元素(包括元素成員和元素分值)。
4、參考文檔
?http://doc.redisfans.com/key/scan.html#scan??
http://redisdoc.com/database/scan.html#scan
5、測試用例?
測試過程發(fā)現(xiàn)如果map集合的數(shù)據(jù)比較少,比如100個,雖然設(shè)置count只查10個,也會都返回過來?注意點:所有jimdb scan類操作,都要確保在一個副本。
public Map<String,String> hScan(String key) {Map<String,String> allResult =new HashMap<>(1024);CallerInfo callerInfo = Profiler.registerInfo("CacheServicneire_hScan", O2nConstants.APP_NAME,false, true);try {ScanOptions scanOptions = ScanOptions.scanOptions().match("*").count(50).concurrent(1).build();ScanResult<Map.Entry<String, String>> scanResult = cluster.hScan(key,0,scanOptions);if(scanResult !=null && CollectionUtils.isNotEmpty(scanResult.getResult())){allResult.putAll(scanResult.getResult().stream().collect(Collectors.toMap(Entry::getKey,Entry::getValue)));while (scanResult.getCursor()>0){scanResult = cluster.hScan(key,scanResult.getCursor(), scanOptions);if(scanResult !=null && CollectionUtils.isNotEmpty(scanResult.getResult())){allResult.putAll(scanResult.getResult().stream().collect(Collectors.toMap(Entry::getKey,Entry::getValue)));}}}}catch (Exception e) {Profiler.functionError(callerInfo);log.error("執(zhí)行hScan操作失敗, key:{}", key, e);throw e;} finally {Profiler.registerInfoEnd(callerInfo);}return allResult;}?
總結(jié)
以上是生活随笔為你收集整理的Redis命令之hscan的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python是不是现在主流的人工智能编程
- 下一篇: linux cmake编译源码,linu