Оказывается, распределённые замки Redis на больших фабриках устроены именно так!

Java

Производите только твердые сухие продукты本文已收录在我的 GitHub 仓库,欢迎Star/fork: Java-Interview-Tutorial

1 локальный замок

Обычно используемые блокировки, поставляемые с JDK, такие как синхронизация или блокировка, могут блокировать только текущий процесс и применимы только к службам с одной архитектурой. В сценариях распределенных мультисервисных экземпляров необходимо использовать распределенные блокировки.

2 Распределенный замок

2.1 Принцип распределенной блокировки

теория туалетной ямы

Вы можете отправиться в одно место одновременно, чтобы «занять яму»:

  • занято, выполните логику
  • в противном случае подождите, пока блокировка не будет снята

вращение за вращением

«Zhankeng» может обращаться к Redis, БД, любому месту, куда могут получить доступ все сервисы.

2.2 Эволюция распределенной блокировки

первый этап

// 占分布式锁,去redis占坑
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "111");
if(lock) {
	//加锁成功... 执行业务
	Map<String, List<Catelog2Vo>> dataFromDb = getDataFromDb();
	redisTemplate . delete( key: "lock");//fHßti
	return dataF romDb ;
} else {
	// 加锁失败,重试。synchronized()
	// 休眠100ms重试
	// 自旋
	return getCatalogJsonFromDbwithRedisLock();
}

сценарий проблемы

  • setnx занимает яму, но бизнес-код ненормальный или программа падает во время выполнения, то есть логика блокировки не выполняется успешно, что приводит к взаимоблокировке

Решение: Установите автоматическое истечение срока действия блокировки, даже если она не будет удалена, она будет удалена автоматически.

второй этап

// 1. 占分布式锁,去redis占坑
Boolean lock = redisTemplate.opsForValue().setIfAbsent( "lock", "110")
if(lock) {
	// 加锁成功...执行业务
	
	// 突然断电
	
	// 2. 设置过期时间
	redisTemplate.expire("lock", timeout: 30, TimeUnit.SECONDS) ;
	Map<String, List<Catelog2Vo>> dataFromDb = getDataFromDb();
	//删除锁
	redisTemplate. delete( key; "lock");
	return dataFromDb;
} else {
	// 加锁失败...重试。 synchronized ()
	// 休眠100ms重试
	// 自旋的方式
	return getCatalogJsonF romDbWithRedisLock();
}

сценарий проблемы

  • Setnx настроен, и я собираюсь установить время истечения срока действия, время простоя и взаимоблокировку.

Решение. Установка времени истечения и заполнителя должна быть атомарной операцией. Redis поддерживает использование команды setNxEx.

третий этап

// 1. 分布式锁占坑
Boolean lock = redisTemplate.opsForValue().setIfAbsent("lock", "110", 300, TimeUnit.SECONDS);
if(lock)(
	// 加锁成功,执行业务
	
	// 2. 设置过期时间,必须和加锁一起作为原子性操作
	// redisTemplate. expire( "lock", з0, TimeUnit.SECONDS);
	Map<String, List<Catelog2Vo>> dataFromDb = getDataFromDb();
	// 删除锁
	redisTemplate.delete( key: "lock")
	return dataFromDb;
else {
	// 加锁失败,重试
	// 休眠100ms重试
	// 自旋
	return getCatalogJsonFromDbithRedislock()
}

четвертый этап

Уже есть lockvalue с UUID, но срок его действия истек! Другие получают блокировку и устанавливают новое значение, поэтому после if чужие блокировки удаляются! ! То есть снятие блокировки не является атомарной операцией.

Map<String, List<Catelog2Vo>> dataFromDb = getDataFromDb();
String lockValue = redisTemplate.opsForValue().get("lock");
if(uuid.equals(lockValue)) {
	// 删除我自己的锁
	redisTemplate.delete("lock");
}

сценарий проблемы

  • Если это просто считается текущим значением, когда блокировка собирается быть удаленной, срок действия блокировки истек, и кто-то другой успешно установил новое значение. Это удаление является чужой блокировкой.
  • решение

Блокировки удаления должны гарантировать атомарность. Используйте скрипты redis+Lua.

Этап пятый

  • Убедитесь, что блокировка/разблокировка являются атомарными операциями.
String script = 
	"if redis.call('get', KEYS[1]) == ARGV[1] 
		then return redis.call('del', KEYS[1]) 
	else 
		return 0 
	end";

Обеспечьте атомарность блокировки [занятость + время истечения срока действия] и удаление блокировки [решение + удаление]. Самое сложное, автоматическое обновление блокировки.

Суммировать

На самом деле, более хлопотным является автоматическое продление блокировки. Так что, будь то крупный завод или малая и средняя компания, мы напрямую выбираем Redisson для решения этих проблем! Не повторяйте создание колес, но также знайте, какие проблемы решает фреймворк, чтобы мы могли быстро устранять неполадки и локализовать возникающие проблемы. В следующей статье мы начнем редиссона, чтобы объяснить, как он продлевает замок~