In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/02 Report--
This article introduces how the actual combat and inventory reduction of redis lua script is realized, the content is very detailed, interested friends can refer to it, hope to be helpful to you.
Preface
We all know that redis is an indispensable kv middleware for high-performance and high-concurrency systems. It is famous for its high performance and high concurrency. We often use it as cache to cache hot data or constant data in redis. When querying, we directly query redis to reduce the pressure on db. In distributed systems, we also use it as distributed locks, distributed id, idempotents to solve some distributed problems. Redis also supports lua scripts. And it can guarantee the atomicity in the process of lua script execution, which makes its application scenarios are many and typical. In redisson, a redis client, its various distributed lock layers are implemented using lua. The main purpose of this article is to learn how to write a redis lua script and how to use it in redisson, a redis client, to write a lua script for redis inventory reduction in a real-time scenario, and to test the effect in a pseudo-real environment.
1.redisson introduction
Redisson is a redis client, it has rich functions, and supports a variety of redis modes, what stand-alone, cluster, Sentinel support, a variety of distributed lock implementation, what distributed reentry lock, red lock, read-write lock, semaphore, and then it operates the common data structures of redis is as simple as operating various collections of jdk.
Let's demonstrate a little bit here, without too much introduction, api is just an api after all, and the interesting things are all kinds of principles behind it.
Maven dependence
Org.redisson redisson 3.8.1
Create a RedissonClient object
Config config = new Config (); config.useSingleServer () .setAddress ("redis://xxx:xx"); RedissonClient redissonClient = Redisson.create (config)
It has a lot of functions, but here are just some commonly used ones, such as Bloom filters, queues, and so on.
/ / stringredissonClient.getBucket ("name"). Set ("zhangsan"); redissonClient.getBucket ("name"). Get (); / / hashRMap user = redissonClient.getMap ("user"); user.put ("name", "zhangsan"); user.put ("age", 11); / / listRList names = redissonClient.getList ("names"); names.add ("zhangsan"); names.add ("lisi"); names.add ("wangwu"); / / setRSet nameSet = redissonClient.getSet ("names") NameSet.add ("lisi"); nameSet.add ("lisi"); / / lockRLock lock = redissonClient.getLock ("lock"); lock.lock (); lock.unlock (); / / distributed idRAtomicLong id = redissonClient.getAtomicLong ("id"); long l = id.incrementAndGet (); 2. Redis lua scripting and execution
In fact, the lua script in redis is not difficult, and you don't need to relearn the lua language. It all depends on the feeling. When you use it, check the grammar and ok it.
Only one redis.call () in the script should be regarded as a function (the method is also OK). For example, if I want to use the lua script to implement the set action, I can write it like this.
Return redis.call ('set','name','zhangsan')
In fact, it is the same as redis interactive commands, and then use Lua language to do some conditional branches, loops and so on, and complete some slightly more complex logic.
Write down the logic of inventory deduction by yourself, and you will know this thing.
The above is an introduction to the writing of the lua script, and let's introduce the execution below.
Whether it is the client brought by redis itself, or jedis,jediscluster,redistemplate,redisson, these clients all support lua script api. In fact, eval,evalsha,scriptload commands are used more frequently. Here I take a screenshot of the introduction of redis script commands above in the rookie tutorial.
It's useless to talk about it, but here you can directly use the redisson client to practice it.
Public class RedisLua {private static final Config config; private static final RedissonClient redisson; static {config = new Config (); config.useSingleServer () .setAddress ("redis://ip:port"); redisson = Redisson.create (config);} public static void main (String [] args) throws InterruptedException {redisson.getBucket ("name"). Set (11); RScript script = redisson.getScript () String result = script.eval (RScript.Mode.READ_ONLY, new StringCodec (), "return redis.call ('get','name');", RScript.ReturnType.VALUE); System.out.println (result);}}
You can see that you use the getScript method to get a script object, and then call the eval method of the script object. This script object actually uses multiple methods, evalSha, etc., you can study it yourself. Then I use the lua script to get the name value I entered into the set above.
When we read the introduction of script commands in the rookie tutorial above, we also found that there is key. Arg... These things, I think, are replaced dynamically (passing parameters).
For example, if I don't get the key value of name now, I want to get the value of age, or I want to set a value directly. At this time, I can have two variables in the lua script equivalent to the parameters you pass.
KEYS [1] ARGV [1]
You can think of it as an array, but its position starts at 1.
RScript script = redisson.getScript (); List keys=new ArrayList (); keys.add ("age"); String re = script.eval (RScript.Mode.READ_WRITE, new StringCodec (), "return redis.call ('set',KEYS [1], ARGV [1]);", RScript.ReturnType.VALUE, keys,1); Object age = redisson.getBucket ("age"). Get (); System.out.println (age)
KEYS [1] corresponds to the age, ARGV [1] corresponds to 1, and KEYS [2] corresponds to the second element in the keys set.
3.redis inventory reduction lua script
Let's first introduce how to place an order to reduce inventory. In fact, general inventory has available inventory and preemptive inventory, and then when you place an order, subtract the available inventory from the quantity of goods you buy to see if it is less than 0. If it is less than 0, it means that the inventory is not enough and you are not allowed to place an order for purchase. If the available inventory is sufficient, the available inventory minus the quantity of goods purchased, preemptive inventory plus the quantity of goods you buy. When the user overdue or manually cancels the order, he will go to the preemptive warehouse minus the number of goods purchased by the user, the available inventory plus the number of goods, in fact, there is also a sold inventory, merchant delivery, sold inventory plus the number of goods, preemption minus the number of goods, generally speaking, this logic.
Now you can think about what you would do if you were asked to place an order to preempt inventory. Needless to say, there are three inventory fields in the database.
First of all, you have to query the sellable inventory, and then compare it with the number of goods purchased. If the salable inventory is greater than the number of purchased goods, you can buy, update the sellable inventory and preempt inventory.
If you do not add some special means to deal with the logic of the above code, it will definitely be oversold in ok, high concurrency scenarios.
What if it's a second kill scene? Blood loss.
At this time, we may add some special measures to solve the problem, such as adding locks, adding distributed locks, and locking the business logic of this section, so that the phenomenon of overselling will not occur at this time, but if this situation is sold out, the database will be queried all the time. When the second kill, the traffic is so high, you can not let such a large traffic directly check the database, if the goods are sold out and return directly, there is no need to query the database.
In general, the inventory of goods will be synchronously pushed to redis. When the traffic comes over, the inventory of redis will be deducted first. If redis is successful, the inventory in the database will be deducted. If the inventory in redis is gone, it will be returned directly to ok, so that large traffic will not directly impact the database. If redis wants to achieve this logic, it needs the atomicity of the lua script.
Next we will implement the lua script deduction inventory logic.
Public static final String LOCK_STOCK_LUA= "local counter = redis.call ('hget',KEYS [1], ARGV [1]);\ n" + "local result = counter-ARGV [2] "+" if (result > = 0) then\ n "+" redis.call ('hset',KEYS [1], ARGV [1], result) \ n "+" redis.call ('hincrby',KEYS [1], ARGV [3], ARGV [2]);\ n "+" return 1;\ n "+" end \ n "+" return 0;\ n "
I've already written it here. Post it directly.
The data design looks like this, using hash data structures
Commodity: {
"Sale inventory": 100
"preemptive inventory": 0
"inventory sold": 0
}
Local counter = redis.call ('hget',KEYS [1], ARGV [1])
Get the quantity of inventory available for sale
Local result = counter-ARGV [2]; if (result > = 0) then
The available inventory minus the number of goods to be purchased, if it is greater than 0, indicates that the inventory is sufficient.
Redis.call ('hset',KEYS [1], ARGV [1], result); redis.call (' hincrby',KEYS [1], ARGV [3], ARGV [2]); return 1
Reset the amount of inventory available for sale, increase preemptive inventory, and then return 1
If the stock is not enough, return 0 directly.
4. Actual combat 4.1 inventory reduction logic
In fact, the logic of inventory reduction is to use the lua script to reduce redis inventory first, and then reduce the real inventory in the database if it succeeds. If the reduction of redis inventory fails and the inventory is insufficient, it will not follow the logic of reducing real inventory.
In this case, I wrote an inventory service to achieve this logic, but I always feel that there are all kinds of data inconsistencies, of course, it is not oversold, but undersold, so I won't send it out here.
4.2 pressure test
Our actual combat was carried out in Aliyun.
Redis chooses container service, which is charged by seconds, and configured with 0.5c1g.
Mysql is also the container service of choice, and the configuration is 0.5c1g
Inventory service is a CVM, which is billed by the hour. The configuration is 2c4g, because multiple services and instances are to be deployed, and the choice is relatively large.
Stress testing is also used by Aliyun's performance testing service.
Redis monitoring, as you can see, this concurrency is drizzle for redis. Cpu only uses 7%.
The speed of the CVM is a bit slow. Without screenshots, the cpu and memory are about 50%.
Mysql database, you can see cpu going up, memory going up.
Database data:
It can be found that there is no oversold phenomenon.
About the redis lua script actual combat and inventory reduction is how to share here, I hope the above content can be of some help to you, can learn more knowledge. If you think the article is good, you can share it for more people to see.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.