Heim  >  Artikel  >  Datenbank  >  Was ist das Prinzip der verteilten Redis-Sperre und wie wird sie implementiert?

Was ist das Prinzip der verteilten Redis-Sperre und wie wird sie implementiert?

王林
王林nach vorne
2023-05-27 16:16:283317Durchsuche

1 Sicherheitsproblem bei der Parallelität mit einer Person und einer Bestellung

Die pessimistische Sperre, die im vorherigen Geschäft mit einer Person und einer Bestellung verwendet wurde, kann in einem verteilten System nicht wirksam werden.

Wenn im besten Fall ein Thread den Mutex erfolgreich abrufen und die Reihenfolge abfragen und erstellen kann, können andere Threads nicht eingreifen. Das Prinzip besteht darin, dass es einen Sperrmonitor gibt, der überwacht, wer die Sperre erhalten hat.

Was ist das Prinzip der verteilten Redis-Sperre und wie wird sie implementiert?

Aber das Problem tritt auf:

In einem verteilten System gibt es mehrere verschiedene JVMs. In verschiedenen JVM-Umgebungen gibt es mehrere Sperrlisten, und einige Threads werden in anderen angezeigt. Es kann immer noch die Sperre erhalten.

Was ist das Prinzip der verteilten Redis-Sperre und wie wird sie implementiert?

Zu diesem Zeitpunkt funktionieren die Sperren in der normalen JVM nicht mehr, daher müssen wir verteilte Sperren verwenden.

2 Das Prinzip und die Implementierung verteilter Sperren

2.1 Was ist eine verteilte Sperre?

Es handelt sich um eine Sperre, die die Anforderungen der Sichtbarkeit und des gegenseitigen Ausschlusses mehrerer Prozesse in einem verteilten System oder Clustermodus erfüllen kann.

Das Implementierungsprinzip besteht darin, dass verschiedene JVM-Umgebungen einen Sperrmonitor gemeinsam nutzen. Dies führt nicht dazu, dass mehrere Threads mehrere Sperren verwenden.

Was ist das Prinzip der verteilten Redis-Sperre und wie wird sie implementiert?

Eigenschaften:

Was ist das Prinzip der verteilten Redis-Sperre und wie wird sie implementiert?

2.2 Implementierung einer verteilten Sperre

Es gibt hauptsächlich drei Implementierungsmethoden, wir können sie alle vergleichen.

Wie unten gezeigt:

Was ist das Prinzip der verteilten Redis-Sperre und wie wird sie implementiert?

Hier sprechen wir hauptsächlich über die Implementierung verteilter Sperren basierend auf Redis.

Die Methode zur Implementierung der verteilten Sperre von Reids umfasst hauptsächlich die folgenden zwei Schritte:

1. Erhalten der Sperre

Die Verwendung der setnx-Methode vom Typ String in Redis (Garantie gegenseitiger Exklusivität) ist bereits eine bekannte Methode, um die Sperre zu erhalten sperren. Um einen Absturz des Redis-Servers zu verhindern, müssen wir ein Zeitlimit für die Sperre festlegen, um einen Deadlock zu vermeiden. (Nicht blockierend)

Sie können also den folgenden Code verwenden, um die Sperre zu erhalten

SET lock thread1 nx ex 10

lock ist der Schlüssel der Sperre, thread1 ist der Wert, nx ist die setnx-Methode, und ex besteht darin, den Timeout-Zeitraum festzulegen

2. Die Sperre aufheben

Das Aufheben der Sperre ist einfach, löschen Sie sie einfach.

del lock

Code-Implementierung:

Anforderungen: Definieren Sie eine Schnittstelle und verwenden Sie Redis, um die verteilte Sperrfunktion zu implementieren.

Was ist das Prinzip der verteilten Redis-Sperre und wie wird sie implementiert?

Der Code lautet wie folgt:

Schnittstellencode:

package com.hmdp.utils;
public interface ILock {
    /**
     * 尝试获取锁
     * @param timeoutSec 锁的持有时间,过期自动释放
     * @return true代表获取锁成功,false代表获取锁失败。
     */
    boolean tryLock(long timeoutSec);
    /**
     * 释放锁
     */
    void unlock();
}

Schnittstellenimplementierungsklasse:

package com.hmdp.utils;
import org.springframework.data.redis.core.StringRedisTemplate;
import java.util.concurrent.TimeUnit;
/**
 * @Version 1.0
 */
public class SimpleRedisLock implements ILock {
    //Redis
    private StringRedisTemplate stringRedisTemplate;
    //业务名称,也就是锁的名称
    private String name;
    public SimpleRedisLock(StringRedisTemplate stringRedisTemplate, String name) {
        this.stringRedisTemplate = stringRedisTemplate;
        this.name = name;
    }
    //key的前缀
    private static final String KEY_PREFIX = "lock:";
    @Override
    public boolean tryLock(long timeoutSec) {
        //获取线程id,当作set的value
        long threadId = Thread.currentThread().getId();
        Boolean success = stringRedisTemplate.opsForValue()
                .setIfAbsent(KEY_PREFIX + name, threadId+"", timeoutSec, TimeUnit.SECONDS);
        return Boolean.TRUE.equals(success);
    }
    //释放锁
    @Override
    public void unlock() {
        //删除key
        stringRedisTemplate.delete(KEY_PREFIX+name);
    }
}

Geschäftsschicht erwirbt Sperren und gibt Sperren frei (Coupon-Flash-Sale-Geschäftsmodifikation)

package com.hmdp.service.impl;
import com.hmdp.dto.Result;
import com.hmdp.entity.SeckillVoucher;
import com.hmdp.entity.VoucherOrder;
import com.hmdp.mapper.VoucherOrderMapper;
import com.hmdp.service.ISeckillVoucherService;
import com.hmdp.service.IVoucherOrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.utils.RedisIdWorker;
import com.hmdp.utils.SimpleRedisLock;
import com.hmdp.utils.UserHolder;
import org.springframework.aop.framework.AopContext;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.time.LocalDateTime;
/**
 * <p>
 *  服务实现类
 * </p>
 *
 */
@Service
public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService {
 
    @Resource
    private ISeckillVoucherService iSeckillVoucherService;
    @Resource
    private RedisIdWorker redisIdWorker;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Override
    public Result seckillVoucher(Long voucherId) {
        //1.获取优惠券信息
        SeckillVoucher voucher = iSeckillVoucherService.getById(voucherId);
        //2.判断是否已经开始
        if (voucher.getBeginTime().isAfter(LocalDateTime.now())){
            Result.fail("秒杀尚未开始!");
        }
        //3.判断是否已经结束
        if (voucher.getEndTime().isBefore(LocalDateTime.now())){
            Result.fail("秒杀已经结束了!");
        }
        //4.判断库存是否充足
        if (voucher.getStock() < 1) {
            Result.fail("库存不充足!");
        }
        //5.扣减库存
        boolean success = iSeckillVoucherService.update()
                .setSql("stock = stock-1").eq("voucher_id",voucherId).gt("stock",0)
                .update();
        if (!success){
            Result.fail("库存不充足!");
        }
        Long userId = UserHolder.getUser().getId();
        //1.创建锁对象
        SimpleRedisLock lock = new SimpleRedisLock(stringRedisTemplate, "order:" + userId);
        //2.尝试获取锁
        boolean isLock = lock.tryLock(1200);
        if (!isLock){
            //获取锁失败
            return Result.fail("一个用户只能下一单!");
        }
        try {
            IVoucherOrderService proxy = (IVoucherOrderService) AopContext.currentProxy();
            return proxy.createVoucherOrder(voucherId);
        } finally {
            //释放锁
            lock.unlock();
        }
    }
    @Transactional
    public Result createVoucherOrder(Long voucherId) {
        Long userId = UserHolder.getUser().getId();
        //6.根据优惠券id和用户id判断订单是否已经存在
        //如果存在,则返回错误信息
        int count = query().eq("user_id", userId).eq("voucher_id", voucherId).count();
        if (count > 0) {
            return Result.fail("用户已经购买!");
        }
        //7. 创建订单
        VoucherOrder voucherOrder = new VoucherOrder();
        //7.1添加订单id
        Long orderId = redisIdWorker.nextId("order");
        voucherOrder.setId(orderId);
        //7.2添加用户id
        voucherOrder.setUserId(userId);
        //7.3添加优惠券id
        voucherOrder.setVoucherId(voucherId);
        save(voucherOrder);
        //8.返回订单id
        return Result.ok(orderId);
    }
}

Das obige ist der detaillierte Inhalt vonWas ist das Prinzip der verteilten Redis-Sperre und wie wird sie implementiert?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen