Redis - не спал всю ночь и наконец удалил ключ

Redis

предисловие

  Поскольку одно из направлений бизнеса не было идеальным, высшее руководство решило закрыть этот бизнес. Для нашей технической команды все соответствующие ресурсы сервера и другие связанные ресурсы должны быть освобождены. Выпущено 8 серверов приложений; 1 сервер es; удалены бизнес-задачи, связанные с распределенным запланированным центром задач; создано резервное копирование и удаление базы данных MySQL; удалены соответствующие данные бизнес-кэша в Redis. Технический директор назвал меня и попросил взять на себя инициативу, так что моя производительность была вычтена... Что ж, плата~
В остальном все хорошо, скоро будет решено. Только это удаление данных в Redis заставило меня снова не спать всю ночь, что меня реально сломало!

Анализ сложности

Общий сервисный кластер Redis

Поскольку данные этого направления бизнеса относятся к 3G в Redis, нет необходимости строить отдельный сервисный кластер Redis.В соответствии с отношением к экономии мы решили использовать кластер совместно с другими проектами (данная конфигурация кластера: 16 узлов ), 128G памяти, довольно роскошно~) Конфигурация кластера следующая:

   В случае с этим общим кластером просто и грубо релизить нельзя. Поэтому можно только выбрать способ удаления ключа.

Названия ключей не стандартизированы

  Чтобы удалить ключи, необходимо сначала точно определить, какие ключи необходимо удалить.Если вы не удалите ключи, это повлияет на нормальную работу других сервисов! Если для самого ключа установлено время истечения срока действия, но некоторые данные должны быть постоянными. Однако проклятый менеджер проекта торопил ход проекта, в результате чего разработчики не работали во многих местах в процессе разработки.Например, ключ Redis разбросан по каждому углу кода проекта; например, название не очень стандартизирован. Я действительно не знаю, как просмотреть код! О, должно быть нет времени на просмотр, проклятый руководитель проекта...
Наугад вырезал имя ключа в платежном сервисе:

Как насчет этого? Вы думаете, что код, написанный нашими разработчиками, очень низкий~ Не смейтесь, в реальной работе есть кое-что еще ниже этого! Надеюсь, вы не столкнетесь с этим, иначе будет очень больно~

Решения

   После приведенного выше анализа мы можем кратко резюмировать следующее:

  • Что нас действительно волнует, так это те ключи, для которых не установлен срок действия.
  • Удалить ключ по ошибке нельзя, иначе будут потеряны показатели следующего месяца.
  • Из-за наименования и использования ключей и их неправильности найти ключи очень сложно.

Кажется, что способ сканирования соответствующего ключа с помощью команды сканирования не работает. Я могу искать только сквозь человеческую плоть~
К счастью, метод поиска Idea хорош. В этом проекте используется spring-boot-starter-data-redis. Поэтому я нахожу весь код, который работает с redis, ища RedisTemplate и StringRedisTemplate. Конкретные шаги заключаются в следующем:
1. Вычислить префикс Ключа через эти коды и ввести его в текст;
2. Используйте скрипт Python, чтобы загрузить ключ в текст и добавить подстановочный знак «*» за ним;
3. Просканировать эти ключи через команду сканирования через python-скрипт;
4. Для удобства проверки мы не использовали команду del для прямого удаления ключа, перед удалением ключа мы сначала получили его сериализованную длину путем отладки объектного ключа, а затем выполнили удаление и вернули сериализованную длину. Таким образом, мы можем подсчитать длину сериализации всех ключей, чтобы получить освободившееся место. Код ключа следующий:

def get_key(rdbConn,start):
    try:
    keys_list = rdbConn.scan(start,count=2000)
    return keys_list
    except 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_list
    except Exception,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)

   С помощью вышеуказанных методов мы можем подсчитать, сколько памяти было освобождено.
   Так как в этом кластере около 70 миллионов ключей:

   Поэтому, когда наступил следующий день, я сонно посмотрел на него и, наконец, закончил его стирать, время 07:13... Наступает утренний пик...

Чувство стыда, а затем мужество

  Никогда не имел опыта расчистки ресурсов из-за нижестоящего бизнеса. Это происшествие действительно заставило меня ощутить истинность тонкостей. Если мы сможем использовать и спроектировать ключ Redis в соответствии со спецификациями разработки с самого начала, это не будет тратить так много времени. Для того, чтобы сделать именование и использование ключей более стандартизированным, и чтобы избежать такой ситуации в будущем, после пробуждения днем, я добавил конфигурацию и настраиваемую сериализацию ключей в общедоступную библиотеку компонентов Redis, Код выглядит следующим образом:


@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;
    }
    
    @Override
    public 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);
    }
    
    @Override
    public 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;
    }
}

Эффект

   Во избежание такого рода неэффективной работы, которую приходится делать заново, мы оговариваем в спецификации разработки, что использование redis в новых проектах должно устанавливать эту конфигурацию, а префикс устанавливается равным: номер проекта. Кроме того, ключи в модуле должны быть единообразно определены в классе RedisKeyConstant сторонней библиотеки. Конфигурация выглядит следующим образом:

spring: 
    redis: 
        prefix:
            enable: true
            key: E00P01
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
    RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
    redisTemplate.setConnectionFactory(redisConnectionFactory);
    // 支持key前缀设置的key Serializer
    redisTemplate.setKeySerializer(new PrefixStringKeySerializer());
    redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
    return redisTemplate;
}

   С помощью вышеуказанных методов мы можем, по крайней мере, различать ключи из измерения проекта, избегая проблемы дублирования ключей, когда несколько проектов используют один и тот же кластер. Ключи отделены от измерения проекта. Более удобное управление и эксплуатация и обслуживание. Если уровень детализации управления ключами выше, мы можем даже уточнить его для конкретных бизнес-аспектов. Мы проводили стресс-тесты в тестовой среде, и добавление префиксов ключей мало повлияло на производительность Redis. Производительность приемлемая.

Суммировать

   Благодаря этому событию я обнаружил, что для большинства разработчиков разрыв заключается не в интеллекте, а в отношении. Например, проблема, выявленная этим инцидентом: все знают, что нужно следовать спецификациям разработки, но когда дело доходит до настоящей «войны», лишь немногие разработчики, отвечающие за этот проект, могут стабильно хорошо делать эти тонкие вещи. К тому же работа рецензента на самом деле крайне важна.Он как "Дисциплинарно-ревизионная комиссия" Если "Дисциплинарно-ревизионная комиссия" закроет глаза, то будет большая беда! Упоминание о тысяче миль испорчено ежедневной небрежностью~~~
  После этого случая, если Бог даст еще такой шанс, я обязательно скажу руководителю проекта: тогда играй музыку, потом танцуй~



В этой статье описывается, что произошло в моем реальном проекте. Если у вас есть лучшее решение, пожалуйста, не стесняйтесь оставить сообщение или написать по электронной почте: leon.sun@foxmail.com, Спасибо!