Config configuration center of SpringCloud Alibaba, detailed explanation of Redis distributed lock

Table of contents

1. Service Configuration Center

1.1 Introduction to Service Configuration Center

 1.2 Nacos Config practice

1.2.1 Nacos config entry case

 1.2.2 Dynamic refresh of Nacos configuration

1.2.3 Configuration sharing

1.2.4 Several concepts of nacos

 

2. Distributed lock

2.1 Introduction to Distributed Locks

 2.2 Redison 

2.2.1 Redisson practice

 2.2.2 Principle of Redisson


 

1. Service Configuration Center

1.1 Introduction to Service Configuration Center

First of all, let's take a look at some issues about configuration files under the microservice architecture:
1. Configuration files are relatively scattered. Under a microservice architecture, configuration files will become more and more with the increase of microservices, and they will be scattered in each microservice, which is difficult to unify-configuration and management.
2. The configuration file cannot distinguish the environment. A microservice project may have multiple environments, for example: test environment, pre-release environment, and production environment. The configuration used in each environment is theoretically different. Once it needs to be modified, we need to manually maintain it under each microservice, which is more difficult.
3. Configuration files cannot be updated in real time. After we modify the configuration file, we must restart the microservice to make the configuration take effect, which is very unfriendly to a running project.


Based on the above problems, we need to join the configuration center to solve these problems.
The idea of ​​the configuration center is:
1. First, put all the various configurations in the project into a centralized place for unified management, and provide a set of standard interfaces.
2. When each service needs to obtain the configuration, it comes to the interface of the configuration center to pull its own configuration.
3. When the various parameters in the configuration center are updated, it can also notify each service to come and synchronize the latest information in real time, so that it can be updated dynamically

After joining the service configuration center, our system architecture diagram will become as follows:
3c36a2dd9c1c4f9c8e7bd5cd1e4bb2eb.png

 1.2 Nacos Config practice

Using nacos as the configuration center is actually treating nacos as a server and each microservice as a client. We store the configuration files of each microservice on nacos, and then each microservice pulls the configuration from nacos. Can.

1.2.1 Nacos config entry case

import dependencies

       <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

To add the configuration of nacos config in the microservice, you cannot use the original application.yml as the configuration file, but create a new bootstrap.yml as the configuration file.

The configuration file priority from high to low is:

bootstrap.properties>bootstrap.yml>application.properties>application.yml

Here is an example of an order microservice, first create a bootstrap.yml file, and then configure it as follows:

spring:
  application:
    name: provider
  profiles:
    active: dev #环境标识
  cloud:
    nacos:
      server-addr: localhost:8848
      config:
        file-extension: yaml #配置文件格式
      discovery:
        cluster-name: BJ
    sentinel:
      transport:
        dashboard: localhost:8080

Then configure the Data ID in the nacos configuration file to configure the order microservice name + environment ID + configuration file format in bootstrap. As shown below;

58b00790fbf94f8f9752d8d6e6646fe6.png

 1.2.2 Dynamic refresh of Nacos configuration

Realize that after modifying the content of the configuration file in the configuration center, the internal references of the program can be automatically refreshed. We can change the items in the DataId configuration file created by ourselves:

config: 
 
appName: product

hardcoded way

 @GetMapping("/test")
    public String test(){
        String property = configurableApplicationContext.getEnvironment().getProperty("config.appName");
        return property;
    }

Annotation method

@RestController
@RefreshScope  /* 只需要在需要动态读取配置的类上添加此注解就可以 */

public class UserController {

    @Value("${config.appName}")
    private String appName;

    @GetMapping("/test")
    public String test(){
        return appName;
    }

}

1.2.3 Configuration sharing

When there are more and more configurations, we find that many configurations are duplicated. At this time, we consider whether it is possible to extract the public configuration files and then share them. There are two scenarios for sharing: the same microservice, sharing in different scenarios (namespaces); sharing between different microservices.

 The same microservice, shared configuration in different scenarios

For example, for the order microservice above, the configuration file for the development environment is provider-dev.yaml, and the configuration file for the test environment is provider-test.yaml. The provider.yaml file can be configured for sharing the same microservice in different scenarios.

 

 Sharing shared configuration between different microservices

Create a new all-service.yml file in nacos as a shared configuration, and then import the configuration code as follows:

spring:
  application:
    name: provider
  profiles:
    active: dev
  cloud:
    nacos:
      server-addr: localhost:8848
      config:
        file-extension: yaml
        shared-dataids: allservice.yaml #配置要引入的配置
        refreshable-dataids: allservice.yaml #配置要实现动态配置刷新的配置
      discovery:
        cluster-name: BJ
    sentinel:
      transport:
        dashboard: localhost:8080

1.2.4 Several concepts of nacos

Namespace (Namespace)
Namespace can be used to isolate the configuration of different environments. Generally, an environment is divided into a namespace
configuration group (Group)
Configuration group is used to classify different services into the same group. Generally, the configuration of a project is divided into a set of
configuration sets (Data ID)
In ​​the system, a configuration file is usually a configuration set. The configuration of a general microservice is a configuration set
 

97780940bbbd4df693fd69d6409b6e6b.png

 

2. Distributed lock

2.1 Introduction to Distributed Locks

Distributed lock: A lock that is visible and mutually exclusive to multiple processes in a distributed system or cluster mode.

In a single application development scenario, in a multi-threaded environment, when concurrent synchronization is involved, in order to ensure that a code block can only be accessed by one thread at a time, we can generally use synchronized syntax and ReetrantLock to ensure that this is actually The above is the way of local lock. In other words, within the same JVM, everyone often uses synchronized or Lock to solve security issues between multiple threads. But in the development scenario of distributed cluster work, between JVMs, a more advanced locking mechanism is needed to deal with thread safety issues across JVM processes.

In short, for distributed scenarios, we can use distributed locks, which are a way to control mutually exclusive access to shared resources between distributed systems. For example, in a distributed system, multiple services are deployed on multiple machines. When a user on the client side initiates a data insertion request, if there is no distributed lock mechanism guarantee, then multiple services on multiple machines may Performing concurrent insert operations leads to repeated insertion of data, which will cause problems for some businesses that do not allow redundant data. The distributed lock mechanism is to solve similar problems and ensure mutually exclusive access to shared resources among multiple services. If a service seizes the distributed lock and other services do not acquire the lock, no subsequent operations will be performed. As shown below:

8f423b21e6494996bf593dd95c90c37b.png

 

Distributed locks should have the following characteristics:

  • mutual exclusion. At any one time, only one client can hold the lock.
  • No deadlock will occur. Even if a client crashes while holding the lock and does not actively unlock it, it can ensure that other clients can lock it later.
  • It is fault-tolerant. As long as most of the Redis nodes are running normally, clients can lock and unlock.
  • The trouble should end it. Locking and unlocking must be the same client, and the client itself cannot unlock the lock added by others.


b3f8acd425c74505b925e0ea7b90116a.png

 The core of distributed locks is to achieve mutual exclusion between multiple processes, and there are many ways to meet this, and there are three common ones:

a70f9675ba32423f8358e9eb74c335cc.png

 2.2 Redison 

Redisson is a Java in-memory data grid (In-Memory Data Grid) implemented on the basis of Redis. It not only provides a series of distributed common Java objects, but also provides many distributed services, including the implementation of various distributed locks.

If we have an order spike service in the microservice architecture and require the same coupon, a user can only place an order. In the stand-alone architecture, we can use synchronized or Lock to solve this problem, and lock the process of querying whether the database has placed an order and order deduction of inventory together, and only one thread that obtains the lock is allowed to access. If there is no lock, if one hundred threads access the same user at the same time in a high-concurrency scenario, then multiple threads will perform query operations first. If there is no order information in the database, then these multiple threads will If all meet the requirements, place an order to deduct inventory and generate multiple orders, which will violate the situation that a user can only place an order. In distributed, because multiple services exist in the form of clusters and there are multiple jvm instances, the synchronized or Lock method is only aimed at the same JVM, which requires distributed locks. Here, Redission is used for simulation, simulating the situation where multiple user threads place an order for the same order and deduct inventory in a high-concurrency scenario of a microservice cluster.

2.2.1 Redisson practice

import dependencies

      <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.19.0</version>
        </dependency>

code show as below:

This code simulates querying the order information based on the order id, and then transfers the goodsId in the order information to the product microservice, reduces the inventory of the corresponding product by one, and then returns the modified product information and stores it in the Goods attribute of the product corresponding to the order information. Adding distributed locks is to ensure that this method in different microservice processes in the same cluster can only be processed by the thread that acquires the lock. Since it is a code simulation, it is relatively random when designing the code.

    @GetMapping("/order/pay/{id}")
    public Orders1 pay(@PathVariable("id") Long id){
        RLock lock = redissonClient.getLock("lockorder" + id);
        boolean b = lock.tryLock();
        if(!b) {
            return null;
        }
        try {
            Orders1 orders1 = orders1Mapper.selectById(id);
            Goods goods = feign.goodsservice(orders1.getGoodsId());
            orders1.setGoods(goods);
            return orders1;
        }finally {
            lock.unlock();
        }
    }

The debug verification results are as follows:

The following order microservice clusters are port 8080 and port 9202. First visit port 8080, and then visit port 9202 to verify our conjecture in the debug environment.

333e47fc8ce248aeb93a6c404a4886f9.png

 81e9223dbdcd45ebb8ed4aa505dd52e9.png

 2.2.2 Principle of Redisson

This chapter quotes related descriptions on the Internet

The schematic diagram of Redisson's framework for implementing Redis distributed locks is as follows:

36fa287064ca40c1b9e42bac61b03478.png

 1. Obtaining a lock
A Redission client 1 needs to lock, it will first select a machine according to the hash node, and then send a lua script to redis, for example, the lock key to be locked is "mylock", and set The time is 30 seconds, and the mylock lock will be released after 30 seconds.
2. Lock mutual exclusion mechanism
If the Redission client 2 locks at this time, it will also select a machine according to the hash node, and then execute the same lua script.
It first comes back to judge whether the lock "mylock" exists? If it exists, Redission client 2 will get a number, which is the remaining lifetime of the lock mylock.
At this time, the Redission client 2 will enter a while loop, that is, the CAS will keep spinning and try to lock until it succeeds.
3. Watchdog mechanism
If the Redisson node responsible for storing the distributed lock goes down and the lock happens to be locked, the lock will appear locked.
In order to avoid this from happening, Redisson internally provides a watchdog that monitors the lock. Its function is to continuously extend the validity period of the lock before the Redisson instance is closed. It takes 2 seconds for thread A to get the lock, but the timeout period of the lock is only 1 second, which means that when the lock times out, the business has not been processed yet. At this time, thread B came in and got the lock, which caused the lock and unlock to be not the same thread. The function of the watchdog is that when this situation is encountered, the watchdog will regularly check whether the thread A is still executing tasks, and if it is still executing, it will continue to extend the time.

4. Reentrant lock mechanism
We know that ReentrantLock is a reentrant lock. Its characteristic is that the same thread can repeatedly obtain the lock of the same resource, and Redisson can also satisfy this very well.
When Redisson client 1 obtains the mylock lock, there will be a hash structure data in it, as shown in the following figure:

f354228d1b59446eb080c0922883d118.png
 

5efd4e38ca0047d1a76e13fa5e052510.png

The above picture means the mechanism of reentrant lock. Its biggest advantage is that the same thread does not need to wait for the lock, but can directly perform corresponding operations.

 


5. Release lock mechanism
If it is found that the number of locks has changed to 0, it means that Redisson client 1 no longer holds the lock, and Redisson client 2 can lock it.

 

 

 

Guess you like

Origin blog.csdn.net/qq_43649937/article/details/130585594
Recommended