First, what is distributed?

In order to say what is distributed, first of all, we should know what kind of architecture is the system before distributed, and what kind of problems exist in the previous architecture?

  • Standalone architecture Before distributed, standalone architecture means that all service functions are packaged into an application and deployed on a server. If we compare monomer architecture to a car factory, then from the car engine to a screw on the car needs to be done by it is responsible for, if one day the factory because of natural disasters led to a sharp fall in the number of business, or even stop production, so the whole factory whether engine maker, or screws of all have to shut down. The implementation of the Internet is the single architecture development cost is high, the failure of the impact of a large range, it is difficult to adapt to the current Internet project.

  • Distributed Since the single architecture is not enough to solve the existing requirements of high concurrency, high performance and high availability, then distributed comes, originally we put all the parts of a car in a factory for production, the result will be the above shutdown, then how to solve the distributed? So-called distributed is to separate all the parts production, each factory according to their own special features to produce the corresponding auto parts, finally unified assembly, even for some other reasons, led to a factory to stop the production, but still does not affect other factory production schedule, we can through a small price to find other factories instead of a shutdown of the plant, Ensure that our production tasks can run normally.

Second, why have distributed lock?

  • Without distributed lock to explain this problem before, our first, if there is no distributed lock have what problem, A classic example, if we have A shopping website, there are only 10 things to sell A commodity, as A user A came in stock, then the user A order payment, deduct inventory, the user A payment of the process, When user B comes in and sees that there is still an inventory, user B also starts to place an order and make payment to reduce the inventory. Then it is obvious that something has gone wrong in this process, and there is an oversold problem.

  • A distributed lock If there is a distributed lock will not oversold problems, for example, distributed like bank ATM, you go to the ATM to withdraw money, if you happened to be inside someone, then you must be into not to, must wait for the people inside come out later you can go in, in the same way, if you are to take money, if there are people outside waiting to get money, In any case he could not go in until he had got it out, or he could go home without it.

Distributed lock implemented by Redis

Distributed locks and distributed locks are introduced briefly, then we now look at how to implement a distributed lock, first look at my previous use of Redis to write a distributed lock, see what the problem is?

public Boolean lock(String key, Long waitTime, Long expireTime) {

        String value = UUID.randomUUID().toString().replaceAll("-"."").toLowerCase();
        Boolean flag = setNx(key, value, expireTime, TimeUnit.SECONDS); // A successful attempt to obtain the lock was returnedif (flag) {
            return flag;
        } elseLong newTime = system.currentTimemillis (); // Wait for expiration time long loseTime = newTime +waitTime; // Attempts to obtain the lock successfully return 11 < 11while (System.currentTimeMillis() < loseTime) {

                Boolean testFlag = setNx(key, value, expireTime, TimeUnit.MILLISECONDS);
                if (testFlag) {
                    return testFlag;
                }
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {

                }
            }
        }
        return false;
    }
Copy the code

Capturing the first attempts to acquire the lock, if at the same time set the expiration time (atomic operations, to prevent deadlocks), access to the direct return, simple to see no problem, but if I set the expiration time of 10 seconds, but my business execution for 12 seconds, so at this time other threads also came in, so the lock didn’t have any effect, pay attention to: You don’t want to say I’m going to set the expiration time to 1 minute and I’m going to set it to 10 minutes. Don’t do that.

In fact, there must be a way, after obtaining the lock, and then open a daemon thread, determine when the current thread is finished execution, if not that reset the lock expiration time. But we won’t say that here, but directly use the framework that others have encapsulated.

Redisson distributed lock

1. First, introduce Maven

<dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.11.5</version>Copy the code

2. Build Redisson instance (based on 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;
}
Copy the code

3, use,



Actually is very simple, and its use need to tell you some here, is the lock () this method, we first look at the source code, this method can be set the expiration time, but it will not go to check whether the task execution, if a task is not end, then came the expiration time to lock, thread interruption, will appear abnormal.

public void lock(long leaseTime, TimeUnit unit) {
        try {
            this.lock(leaseTime, unit, false); } catch (InterruptedException var5) { throw new IllegalStateException(); }}Copy the code

Exception information



4, more perfect method, lock()

This method does not need to pass any arguments, and its underlying method checks whether the current task is completed by using the principle described earlier. If it is not completed, the lock expiration time will be extended accordingly.

The underlying implementation

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 {// Whether the verification task is completewhile(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); }}}Copy the code

There are a lot of other Redisson solutions to the problems of the Internet today, but I won’t go through them all. If you want to learn more, you can go to Redisson’s website.

Redisson website