Redis命令之hscan
1、業務背景
? ? ? 在互聯網的項目中為了提高性能和吞吐量,通常需要做一些優化和數據異構,比如查詢DB,我們可以優化索引,通過命中索引來提高查詢速度,也可以把數據異構到Redis,雖然Redis的性能非常好也支持5種數據結構,如果想性能更好的話,可以考慮異構到JVM緩存,也就是DB的數據異構到Redis,Redis的數據定期異構到JVM緩存
2、帶來問題
? ? 在Redis中通過用一個hashmap來存儲業務數據,當這些業務數據比較小,我們可以通過hGetAll來獲取redis的整個map然后設置到JVM緩存中,伴隨這業務的增長Redis中的key會非常多,這是我們調用hGetAll獲取數據時就會把Redis給hang住,造成整個redis阻塞,進而影響整個redis集群的使用,導致其它業務調用redis時性能抖動
3、解決方案
? ? ? 1調整獲取命令hGetAll改成hscan,分階段獲取
? ? ? 2調整hash-max-ziplist-entries參數閾值由于調整改配置需要重新刷數據(不建議)
? ? ? ?我們采取方案1,通過HSCAN來迭代獲取對應的值,通過指定游標和獲取的數量,比如一次獲取10個,命令如下HSCAN key cursor [MATCH pattern] [COUNT count]? 它是一個增量式命令,每次查詢都是返回一部分數據,還可以通過它處理模糊查詢,所以不會像hGetAll類命令hang住Redis導致服務短暫停滯,最開始cursor我們都設置為0就好,count來控制每次遍歷的數量,由于這個命令執行的時間復雜度是O(N),所以count越大,每次執行時間理論上會越長,可以根據實際場景進行調整,在遍歷時候判斷返回的游標cursor是否為0,如果為0代表整個遍歷結束。
類似的命令如下:原理都一樣,都是避免把redis的進場hang住,
- SCAN?命令用于迭代當前數據庫中的數據庫鍵。
- SSCAN?命令用于迭代集合鍵中的元素。
- HSCAN?命令用于迭代哈希鍵中的鍵值對。
- ZSCAN?命令用于迭代有序集合中的元素(包括元素成員和元素分值)。
4、參考文檔
?http://doc.redisfans.com/key/scan.html#scan??
http://redisdoc.com/database/scan.html#scan
5、測試用例?
測試過程發現如果map集合的數據比較少,比如100個,雖然設置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("執行hScan操作失敗, key:{}", key, e);throw e;} finally {Profiler.registerInfoEnd(callerInfo);}return allResult;}?
總結
以上是生活随笔為你收集整理的Redis命令之hscan的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python是不是现在主流的人工智能编程
- 下一篇: 设计模式之工厂模式类图