Spring Cloud microservices series of articles, click above to collect↑
1. Beginning
In a single application, we can use Java’s synchronized
or lock
to use locks, but in a microservice scenario, an application will deploy multiple instances, which requires To ensure that multiple threads of multiple instances can only have one thread operating resources at the same time, distributed locks are required.
The basic principle of Redisson distributed lock is implemented through Redis’s setnx
command. When a process needs to acquire a lock, it creates a key
in Redis to represent the name of the lock by calling Redis’s setnx
command. If this is successfully created
key
means that the lock is acquired successfully and the corresponding business logic can be executed. If the creation of key
fails, it means that the lock has been acquired by other processes, and the current process needs to wait until it acquires the lock. After the business logic is executed, the lock needs to be released, that is, the key
of the lock needs to be deleted through the del
command of Redis
so that other processes can obtain it. locked.
To give a common example: when you go to the toilet, push the door to see if there is anyone inside (try to get the lock). If there is someone inside, you need to wait at the door (wait for the lock). When he finishes using the toilet, the door will be opened (release the lock). , you closed the door (locked it) when you entered, and opened the door (released the lock) after taking off your pants, defecating, and lifting your pants.
In this article, we will demonstrate it through the example of snapping up Moutai.
There are three steps to buying Moutai:
- Determine whether inventory is sufficient
- Create new order
- Deduct inventory.
2. Install and run Redis
Redisson
is based on Redis
. We need to download and run Redis
first.
Redis
is an in-memory database, Redisson
= Redis
+ son
(son).
2.1 Windows
-
Github download address: https://github.com/redis-windows/redis-windows/releases
-
Github download is very slow, network disk download (recommended):
“Redis-7.0.8-Windows-x64.zip” comes from UC network disk sharing
https://drive.uc.cn/s/4087d341fd084
Start Redis
# Start service redis-server.exe redis.conf # Configuration file name of the old version redis-server.exe redis.windows.conf
- You need to specify the
redis.conf
configuration file. You can set the port, password, etc. in theredis.conf
file.
Enter the Redis command line interface
# redis command line interface redis-cli.exe # Set key-value pairs set mykey hello # Get value get mykey
2.2 Linux
Taking CentOS as an example, install it through the yum
command.
# Installation sudo yum install redis # start up sudo systemctl start redis # Enter the redis command line interface redis-cli # Set key-value pairs set mykey hello # Get value get mykey
3. Business SQL script
Execute the following SQL script
- Generate product table
product
- Generate product order table
product_order
- Insert a record into the product table. The total quantity of Kweichow Moutai is 100 bottles.
CREATE TABLE `product` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'primary key id', `name` varchar(20) NOT NULL DEFAULT '' COMMENT 'product name', `number` int(11) NOT NULL DEFAULT 0 COMMENT 'item quantity', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE `product_order` ( `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'primary key id', `product_id` bigint(20) DEFAULT NULL COMMENT 'product id', `number` int(11) DEFAULT NULL COMMENT 'number', `create_time` datetime DEFAULT NULL COMMENT 'Creation time', PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; INSERT INTO `product` VALUES (1, 'Kweichow Moutai', 100);
4. SpringBoot integration Redisson
4.1 pom.xml
Add redisson-spring-boot-starter
package dependency
<dependency> <groupId>org.redisson</groupId> <artifactId>redisson-spring-boot-starter</artifactId> <version>3.16.8</version> </dependency>
4.2 application.properties
redis related configuration
# redis related spring.redis.host=localhost spring.redis.port=6379
4.3 buy()
How to purchase goods
- Determine whether the inventory quantity is sufficient
- Create Order
- Deduct inventory quantity
@Resource private RedissonClient redissonClient; @Override public Boolean buy(Long productId, Integer number) {<!-- --> RLock lock = redissonClient.getLock("lock_key_" + productId); try {<!-- --> boolean lockRes = lock.tryLock(5, TimeUnit.SECONDS); if (!lockRes) {<!-- --> throw new RuntimeException("Failed to acquire lock~"); } Product product = productService.getById(productId); log.info("Inventory quantity: {}", product.getNumber()); // ① Determine whether the inventory is sufficient if (product.getNumber() < number) {<!-- --> throw new RuntimeException("Insufficient stock"); } // ②Create order ProductOrder order = new ProductOrder(); order.setProductId(productId); order.setNumber(1); order.setCreateTime(LocalDateTime.now()); save(order); log.info("Create order: {}", order); // ③ Reduce inventory product.setNumber(product.getNumber() - 1); productService.updateById(product); log.info("Inventory reduction: {}", product); } catch (InterruptedException e) {<!-- --> throw new RuntimeException("An exception occurred~"); } finally {<!-- --> // release lock lock.unlock(); } return true; }
"lock_key_" + productId
The product ID is locked here. Only one request thread can operate this product at the same time, and other request threads must wait.- Locking the product ID indicates that each product is independently locked, which is equivalent to closing the door of that pit when you go to the toilet instead of closing the bathroom door.
lock.tryLock(5, TimeUnit.SECONDS)
, here set the locking time to 5 seconds. If the current requesting thread has not completed the operation within 5 seconds, the lock will be automatically released and the next thread will come. Perform operations.
4.4 Analysis of locking and non-locking
What problems will occur if there is no lock?
Assume that there is only one bottle of Moutai left in stock, and User A and User B initiate a request to purchase one bottle of Moutai at the same time. User A’s request thread determines that the inventory is sufficient, but has not yet completed the order creation and inventory reduction operations (the operation requires access to the database, which is relatively time-consuming). hour). At this time, user B’s request thread determines that the inventory quantity is 1 and the inventory is sufficient. It also enters the order creation and inventory reduction operations. Finally, two orders are created and the inventory is reduced twice.
After we lock the product, when user A’s request thread performs the purchase operations of determining inventory, creating orders, and reducing inventory, user B’s request thread needs to wait for user A to complete this series of operations and release the lock before proceeding. implement.
5. Test
Interface address: http://localhost:8100/product/buy
Use JMeter to create 10 threads to simulate multiple users’ simultaneous cyclic request interfaces. When no locks are applied, the following are the results of the real test: 100 bottles of Moutai generated 204 orders.
When locked, 100 orders for 100 bottles of Moutai will be generated normally.
For the use of JMeter, you can read the previous article Sentinel Flow Control and Interface Protection
.
6. Conclusion
Here we use a simple example of buying Moutai to demonstrate locks. Redisson distributed locks can be used for single entities or microservices. They are locked with the help of redis middleware. As shown above, we can create multiple microservice instances and then call the interface results. Same thing.
Remember: During limited-time sales events, a large number of users request to purchase the same product through the network at the same time, which may cause concurrent sales in the system, leading to problems such as sold out or oversold products. In this case, locks must be used, whether it is a single application or a microservice.
The complete code of the Spring Cloud microservice series is in the sourcecode/spring-cloud-demo
directory of the warehouse.
gitee (recommended): https://gitee.com/cunzaizhe/xiaohuge-blog
github: https://github.com/tigerleeli/xiaohuge-blog
Follow the WeChat public account: “Brother Xiaohu’s Technology Blog”, let us become better programmers together!