日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

redis通过key模糊搜索_Redis—熬了一个通宵,终于把Key删完了!

發(fā)布時間:2024/9/18 数据库 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 redis通过key模糊搜索_Redis—熬了一个通宵,终于把Key删完了! 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

前言

由于有一條業(yè)務(wù)線不理想,高層決定下架業(yè)務(wù)。對于我們技術(shù)團(tuán)隊(duì)而言,其對應(yīng)的所有服務(wù)器資源和其他相關(guān)資源都要釋放。釋放了8臺應(yīng)用服務(wù)器;1臺es服務(wù)器;刪除分布式定時任務(wù)中心相關(guān)的業(yè)務(wù)任務(wù);備份并刪除MySQL數(shù)據(jù)庫;刪除Redis中相關(guān)的業(yè)務(wù)緩存數(shù)據(jù)。CTO指名點(diǎn)姓讓我?guī)ь^沖鋒,才扣了我績效……好吧,沖~
其他都還好,不多時就解決了。唯獨(dú)這刪除Redis中的數(shù)據(jù),害得我又熬了一個通宵,真是折煞我也!

難點(diǎn)分析

共用Redis服務(wù)集群

由于這條業(yè)務(wù)線的數(shù)據(jù)在Redis大概在3G左右,完全沒必要單獨(dú)建一個Redis服務(wù)集群,本著能節(jié)約就節(jié)約的態(tài)度,當(dāng)初就決定和其他項(xiàng)目共享一個集群(這個集群配置:16個節(jié)點(diǎn),128G內(nèi)存,還算豪華吧~)集群配置如下:


在這種共用集群的情況下,導(dǎo)致無法簡單粗暴的釋放。因此只能選擇刪除Key的方式。

Key命名不規(guī)范

要刪除Key,首先就要精準(zhǔn)的定位出哪些Key需要刪除,如果勿刪Key,會影響到其他服務(wù)正常運(yùn)轉(zhuǎn)!如果Key本身設(shè)置了過期時間,但有些數(shù)據(jù)需是持久化的。然而那該死的項(xiàng)目經(jīng)理一直催項(xiàng)目進(jìn)度,導(dǎo)致開發(fā)人員在開發(fā)過程中很多地方都沒有設(shè)計(jì)到位,比如Redis Key散落在項(xiàng)目代碼的每個角落;比如命名不是很規(guī)范。真不知道是怎么review代碼!哦,想必是沒有時間review,那該死的項(xiàng)目經(jīng)理……
我隨便截個支付服務(wù)中的Key命名:


怎么樣?是不是覺得我們開發(fā)人員寫的代碼很low別笑,在實(shí)際工作中,還有比這更low的!希望你別遇到,不然真的很痛苦

解決思路

經(jīng)過以上的分析,我們簡單歸納如下:

  • 我們真正關(guān)心的是那些未設(shè)置過期時間的Key
  • 不能誤刪除Key,否則下個月績效也沒了
  • 由于Key的命名及使用及其不規(guī)范,導(dǎo)致Key的定位難度很大

看來,通過scan命令掃描匹配Key的方式行不通了。只能通過人肉搜索了~
幸而Idea的搜索大法好,這個項(xiàng)目中使用的是spring-boot-starter-data-redis.因此我通過搜索RedisTemplate和StringRedisTemplate定位所有操作redis的代碼,具體步驟如下:
1.通過這些代碼統(tǒng)計(jì)出Key的前綴并錄入到文本中;
2.通過python腳本把載入文中中的的Key并在后面加上“*”通配符;
3.通過python腳本通過scan命令掃描出這些key;
4.為了便于檢查,我們并沒有直接使用del命令刪除key,在刪除key之前,先通過debug object key的方式得到其序列化的長度,再執(zhí)行刪除并返回序列化長度。這樣,我們就可以統(tǒng)計(jì)出所有key的序列化長度來得到我們釋放的空間大小。 關(guān)鍵代碼如下:

def get_key(rdbConn,start):try:keys_list = rdbConn.scan(start,count=2000)return keys_listexcept Exception,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_listexcept Exception,e:print "INFO : ",edef 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)

通過以上方式,能夠統(tǒng)計(jì)出究竟釋放了多少內(nèi)存了。
由于這個集群是有這么接近7千萬個key:


因此,等到了第二天天亮,我睡眼朦朧的看了一下,終于刪除完畢了,時間07:13...早高峰即將來臨……

知恥而后勇

從來沒有經(jīng)歷過因業(yè)務(wù)下線而清除資源的經(jīng)驗(yàn)。這次事情真心讓我覺得細(xì)微之處見真功夫的道理。如果一開始我們就能夠遵循開發(fā)規(guī)范來使用和設(shè)計(jì)redis key,也不至于浪費(fèi)這么多時間。為了讓key的命名和使用更加規(guī)范,以及今后避免再次遇到這種情況,下午睡醒之后,我就在redis公共組件庫里面添加了一個配置和自定義了key序列化,代碼如下:

@ConfigurationProperties(prefix = "spring.redis.prefix") public class RedisKeyPrefixProperties {private Boolean enable = Boolean.TRUE;private String key;public Boolean getEnable() {return enable;}public void setEnable(Boolean enable) {this.enable = enable;}public String getKey() {return key;}public void setKey(String key) {this.key = key;} } /*** @desc 對字符串序列化新增前綴* @author create by liming sun on 2020-07-21 14:09:51*/ public class PrefixStringKeySerializer extends StringRedisSerializer {private Charset charset = StandardCharsets.UTF_8;private RedisKeyPrefixProperties prefix;public PrefixStringKeySerializer(RedisKeyPrefixProperties prefix) {super();this.prefix = prefix;}@Overridepublic String deserialize(@Nullable byte[] bytes) {String saveKey = new String(bytes, charset);if (prefix.getEnable() != null && prefix.getEnable()) {String prefixKey = spliceKey(prefix.getKey());int indexOf = saveKey.indexOf(prefixKey);if (indexOf > 0) {saveKey = saveKey.substring(indexOf);}}return (saveKey.getBytes() == null ? null : saveKey);}@Overridepublic byte[] serialize(@Nullable String key) {if (prefix.getEnable() != null && prefix.getEnable()) {key = spliceKey(prefix.getKey()) + key;}return (key == null ? null : key.getBytes(charset));}private String spliceKey(String prefixKey) {if (StringUtils.isNotBlank(prefixKey) && !prefixKey.endsWith(":")) {prefixKey = prefixKey + "::";}return prefixKey;} }

使用效果

為了避免再次發(fā)生這種工作低效而又不得不做的事情,我們在開發(fā)規(guī)范中規(guī)定,新項(xiàng)目中redis的使用必須設(shè)置此配置,前綴就設(shè)置為:項(xiàng)目編號。另外,一個模塊中的key必須統(tǒng)一定義在二方庫的RedisKeyConstant類中。配置如下:

spring: redis: prefix:enable: truekey: E00P01 @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(redisConnectionFactory);// 支持key前綴設(shè)置的key SerializerredisTemplate.setKeySerializer(new PrefixStringKeySerializer());redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());return redisTemplate; }

通過以上方式,我們至少可以從項(xiàng)目維度來區(qū)分出key,避免了多個項(xiàng)目之間共用同一個集群時而導(dǎo)致重復(fù)key的問題。從項(xiàng)目維度對key進(jìn)行了劃分。更方便管理和運(yùn)維。如果對于key的管理粒度要求更細(xì),我們甚至可以細(xì)化到具體業(yè)務(wù)維度。我們在測試環(huán)境進(jìn)行了壓測,增加key前綴對redis性能幾乎沒有影響。性能方面能接受。

總結(jié)

通過本次事情,我發(fā)現(xiàn)對于大多數(shù)開發(fā)者而言,差距其實(shí)不在于智力,而是在于態(tài)度。比如這次事件暴露出來的問題:大家都知道要遵循開發(fā)規(guī)范,然而到了真正“打仗”的時候,負(fù)責(zé)這個項(xiàng)目的開發(fā)者卻沒有幾個人能始終如一的做好這些細(xì)微之事。另外,reviewer的工作其實(shí)是極其重要的,他就像那“紀(jì)檢委”,如果“紀(jì)檢委”都放水睜一只眼閉一只眼,那麻煩可就大了!千里之提,毀于日常的點(diǎn)滴松懈啊~~~
經(jīng)過這次事件之后,如果上天再給一次這樣的機(jī)會,我一定會對項(xiàng)目經(jīng)理說:接著奏樂,接著舞~

作者:浪漫先生
原文鏈接:https://juejin.im/post/5f18423fe51d453493113f5c

總結(jié)

以上是生活随笔為你收集整理的redis通过key模糊搜索_Redis—熬了一个通宵,终于把Key删完了!的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。