您好,登錄后才能下訂單哦!
本篇內容主要講解“怎么把Reids的7千萬個Key刪完”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“怎么把Reids的7千萬個Key刪完”吧!
難點分析
共用Redis服務集群
由于這條業務線的數據在Redis大概在3G左右,完全沒必要單獨建一個Redis服務集群,本著能節約就節約的態度,當初就決定和其他項目共享一個集群(這個集群配置:16個節點,128G內存,還算豪華吧~)集群配置如下:
在這種共用集群的情況下,導致無法簡單粗暴的釋放。因此只能選擇刪除Key的方式。
Key命名不規范
要刪除Key,首先就要精準的定位出哪些Key需要刪除,如果勿刪Key,會影響到其他服務正常運轉!如果Key本身設置了過期時間,但有些數據需是持久化的。然而那該死的項目經理一直催項目進度,導致開發人員在開發過程中很多地方都沒有設計到位,比如Redis Key散落在項目代碼的每個角落;比如命名不是很規范。真不知道是怎么review代碼!哦,想必是沒有時間review,那該死的項目經理……
我隨便截個支付服務中的Key命名:
怎么樣?是不是覺得我們開發人員寫的代碼很low~別笑,在實際工作中,還有比這更low的!希望你別遇到,不然真的很痛苦~
解決思路
經過以上的分析,我們簡單歸納如下:
我們真正關心的是那些未設置過期時間的Key
不能誤刪除Key,否則下個月績效也沒了
由于Key的命名及使用及其不規范,導致Key的定位難度很大
看來,通過scan命令掃描匹配Key的方式行不通了。只能通過人肉搜索了~
幸而Idea的搜索大法好,這個項目中使用的是spring-boot-starter-data-redis.因此我通過搜索RedisTemplate和StringRedisTemplate定位所有操作redis的代碼,具體步驟如下:
1、通過這些代碼統計出Key的前綴并錄入到文本中;
2、通過python腳本把載入文中中的的Key并在后面加上“*”通配符;
3、通過python腳本通過scan命令掃描出這些key;
4、為了便于檢查,我們并沒有直接使用del命令刪除key,在刪除key之前,先通過debug object key的方式得到其序列化的長度,再執行刪除并返回序列化長度。這樣,我們就可以統計出所有key的序列化長度來得到我們釋放的空間大小。關鍵代碼如下:
def get_key(rdbConn,start): try: keys_list = rdbConn.scan(start,count=2000) return keys_list exceptException,e: print e ''' Redis DEBUG OBJECT command got key info ''' def get_key_info(rdbConn,keyName): try: rpiple = rdbConn.pipeline() rpiple.type(keyName) rpiple.debug_object(keyName) rpiple.ttl(keyName) key_info_list = rpiple.execute() return key_info_list exceptException,e: print"INFO : ",e def redis_key_static(key_info_list): keyType = key_info_list[0] keySize = key_info_list[1]['serializedlength'] keyTtl = key_info_list[2] key_size_static(keyType,keySize,keyTtl)
通過以上方式,能夠統計出究竟釋放了多少內存了。
由于這個集群是有這么接近7千萬個key:
因此,等到了第二天天亮,我睡眼朦朧的看了一下,終于刪除完畢了,時間07:13...早高峰即將來臨……
知恥而后勇
從來沒有經歷過因業務下線而清除資源的經驗。這次事情真心讓我覺得細微之處見真功夫的道理。如果一開始我們就能夠遵循開發規范來使用和設計redis key,也不至于浪費這么多時間。為了讓key的命名和使用更加規范,以及今后避免再次遇到這種情況,下午睡醒之后,我就在redis公共組件庫里面添加了一個配置和自定義了key序列化,代碼如下:
@ConfigurationProperties(prefix = "spring.redis.prefix") publicclassRedisKeyPrefixProperties{ privateBoolean enable = Boolean.TRUE; privateString key; publicBoolean getEnable() { return enable; } publicvoid setEnable(Boolean enable) { this.enable = enable; } publicString getKey() { return key; } publicvoid setKey(String key) { this.key = key; } }
/** * @desc 對字符串序列化新增前綴 * @author create by liming sun on 2020-07-21 14:09:51 */ publicclassPrefixStringKeySerializerextendsStringRedisSerializer{ privateCharset charset = StandardCharsets.UTF_8; privateRedisKeyPrefixProperties prefix; publicPrefixStringKeySerializer(RedisKeyPrefixProperties prefix) { super(); this.prefix = prefix; } @Override publicString deserialize(@Nullablebyte[] bytes) { String saveKey = newString(bytes, charset); if(prefix.getEnable() != null&& prefix.getEnable()) { String prefixKey = spliceKey(prefix.getKey()); int indexOf = saveKey.indexOf(prefixKey); if(indexOf > 0) { saveKeysaveKey = saveKey.substring(indexOf); } } return(saveKey.getBytes() == null? null: saveKey); } @Override publicbyte[] serialize(@NullableString key) { if(prefix.getEnable() != null&& prefix.getEnable()) { key = spliceKey(prefix.getKey()) + key; } return(key == null? null: key.getBytes(charset)); } privateString spliceKey(String prefixKey) { if(StringUtils.isNotBlank(prefixKey) && !prefixKey.endsWith(":")) { prefixKeyprefixKey = prefixKey + "::"; } return prefixKey; } }
使用效果
為了避免再次發生這種工作低效而又不得不做的事情,我們在開發規范中規定,新項目中redis的使用必須設置此配置,前綴就設置為:項目編號。另外,一個模塊中的key必須統一定義在二方庫的RedisKeyConstant類中。配置如下:
spring: redis: prefix: enable: true key: E00P01
@Bean publicRedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<String, Object> redisTemplate = newRedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); // 支持key前綴設置的key Serializer redisTemplate.setKeySerializer(newPrefixStringKeySerializer()); redisTemplate.setValueSerializer(newGenericJackson2JsonRedisSerializer()); return redisTemplate; }
通過以上方式,我們至少可以從項目維度來區分出key,避免了多個項目之間共用同一個集群時而導致重復key的問題。從項目維度對key進行了劃分。更方便管理和運維。如果對于key的管理粒度要求更細,我們甚至可以細化到具體業務維度。我們在測試環境進行了壓測,增加key前綴對redis性能幾乎沒有影響。性能方面能接受。
到此,相信大家對“怎么把Reids的7千萬個Key刪完”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。