1. Что распространяется?
Если вы хотите сказать, что распространяется, то вы должны сначала узнать, какой архитектуры была система до того, как она была распространена, и какие проблемы существовали в предыдущей архитектуре?
Монолитная архитектура
Монолитная архитектура, как следует из названия, заключается в том, чтобы упаковать все бизнес-функции в одно приложение, а затем развернуть его на сервере. Если мы сравним монолитную архитектуру с автомобильным заводом, он должен отвечать за комплектацию всего, от автомобильного двигателя до винта на машине.Если однажды у завода произойдет резкий спад в бизнесе из-за стихийных бедствий или даже остановка производства , то весь завод, будь то двигатели или винты, должен быть остановлен. Реализация его в Интернете означает, что стоимость разработки одной архитектуры высока, а масштаб неудач велик, и его трудно адаптировать к текущему интернет-проекту.распределенный
Поскольку монолитной архитектуры недостаточно для удовлетворения существующих требований высокого параллелизма, высокой производительности и высокой доступности, то приходит дистрибуция.Получается, что мы помещаем все части автомобиля на один завод по производству, и в результате, будут отключения выше.ситуации,тогда как решить распределенную проблему? Так называемое распределение состоит в том, чтобы производить все детали по отдельности.Каждая фабрика производит соответствующие автозапчасти в соответствии со своей специализацией и, наконец, собирает их вместе.Даже если какая-то фабрика останавливает производство по каким-то другим причинам, это все равно не влияет на другие Производственный прогресс, мы можем найти другие фабрики, чтобы заменить остановленные фабрики с небольшими затратами, чтобы гарантировать, что наши производственные задачи могут выполняться нормально.
2. Зачем распределённые блокировки?
Если нет распределенной блокировки
Прежде чем объяснять эту проблему, давайте сначала поговорим о том, какие проблемы будут существовать, если нет распределенной блокировки.Для классического примера, если у нас есть торговый сайт, для продажи доступно только 10 товаров.В это время, после того, как пользователь А заходит , у него есть 1 инвентарь, а затем пользователь А размещает заказ на оплату, и инвентарь вычитается.В процессе оплаты пользователя А случайно заходит пользователь Б и видит, что есть еще один инвентарь.Пользователь Б также начинает разместить заказ на оплату и вычет инвентаря. , то в этом процессе явно есть проблема, естьперепроданПроблема.Распределенная блокировка
Если есть распределенный замок, то не будет проблемы перепроданности.Для простого примера,распределенный как банкомат банка.Вы идете к банкомату, чтобы снять деньги.Если вы идете туда и кто-то оказывается там,то вы определенно не сможет войти. Да, вы должны дождаться, пока человек внутри выйдет, прежде чем вы сможете войти. Точно так же, если вы снимаете деньги, если кто-то снаружи ждет, чтобы снять деньги, то в любом случае он должен ждать, пока вы закончите вынимать его, прежде чем он сможет войти, иначе он не заберет его домой.
3. Распределенная блокировка, реализованная Redis
После краткого ознакомления с распределенными и распределенными блокировками давайте теперь посмотрим, как реализовать распределенную блокировку.Давайте сначала посмотрим, как я использовал Redis для написания распределенной блокировки и посмотрим, что не так?
public Boolean lock(String key, Long waitTime, Long expireTime) {
String value = UUID.randomUUID().toString().replaceAll("-", "").toLowerCase();
Boolean flag = setNx(key, value, expireTime, TimeUnit.SECONDS);
// 尝试获取锁 成功返回
if (flag) {
return flag;
} else {
// 获取失败
// 现在时间
long newTime = System.currentTimeMillis();
// 等待过期时间
long loseTime = newTime + waitTime;
// 不断尝试获取锁成功返回 11 < 11
while (System.currentTimeMillis() < loseTime) {
Boolean testFlag = setNx(key, value, expireTime, TimeUnit.MILLISECONDS);
if (testFlag) {
return testFlag;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}
return false;
}
Сначала попробуйте получить блокировку, если она была получена и одновременно установила время истечения (атомарная операция, предотвращающая взаимоблокировку), получена и возвращена напрямую, проблем вообще нет, но если я установлю время истечения 10 секунд, но мое дело выполняется 12 секунд, потом в это время заходят и другие потоки, потом эта блокировка вообще ни на что не влияет,Уведомление: Все, пожалуйста, не говорите, что я установлю время истечения на 1 минуту и установлю на 10. Не делайте этого, это вылечит симптомы, но не первопричину.
На самом деле должен быть способ.После получения блокировки открывается поток демона, чтобы определить конец выполнения текущего потока.Если нет,сбросить время истечения блокировки. Но мы не будем говорить об этом здесь, а будем напрямую использовать упакованный другими фреймворк.
4. Распределенный замок Redisson
1. Сначала представьте maven
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.11.5</version>
</dependency>
2. Создайте экземпляр Redisson (на основе SpringBoot)
@Bean
public RedissonClient redissonClient() {
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379").setPassword("123456");
RedissonClient redissonClient = Redisson.create(config);
return redissonClient;
}
3. Используйте
На самом деле он очень прост с точки зрения использования.Здесь я должен вам сказать одну вещь, а именно метод lock().Для начала посмотрим на исходный код.Этот метод может устанавливать время истечения,но не будет проверить, выполняется ли задача или нет.В конце, если задача не выполняется и достигнуто время истечения блокировки, поток прерывается, и возникает исключение.
public void lock(long leaseTime, TimeUnit unit) {
try {
this.lock(leaseTime, unit, false);
} catch (InterruptedException var5) {
throw new IllegalStateException();
}
}
информация об исключении
4. Более полный метод lock()
Этому методу не нужно передавать какие-либо параметры, и его базовый метод будет проверять, завершена ли текущая задача по принципу, который мы только что упомянули.Если выполнение не завершено, время истечения блокировки будет соответственно увеличено.
низкоуровневая реализация
private void lock(long leaseTime, TimeUnit unit, boolean interruptibly) throws InterruptedException {
long threadId = Thread.currentThread().getId();
Long ttl = this.tryAcquire(leaseTime, unit, threadId);
if (ttl != null) {
RFuture<RedissonLockEntry> future = this.subscribe(threadId);
this.commandExecutor.syncSubscription(future);
try {
// 校验任务是否执行结束
while(true) {
ttl = this.tryAcquire(leaseTime, unit, threadId);
if (ttl == null) {
return;
}
if (ttl >= 0L) {
try {
this.getEntry(threadId).getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);
} catch (InterruptedException var13) {
if (interruptibly) {
throw var13;
}
this.getEntry(threadId).getLatch().tryAcquire(ttl, TimeUnit.MILLISECONDS);
}
} else if (interruptibly) {
this.getEntry(threadId).getLatch().acquire();
} else {
this.getEntry(threadId).getLatch().acquireUninterruptibly();
}
}
} finally {
this.unsubscribe(future, threadId);
}
}
}
На самом деле, у Redisson есть много других способов решения многих проблем в современном Интернете, но я не буду представлять их здесь по одному, если вы хотите узнать больше, вы можете перейти на официальный сайт Redisson.