当前位置:网站首页>Redis transaction - detailed implementation process of seckill case simulation
Redis transaction - detailed implementation process of seckill case simulation
2022-07-23 10:23:00 【Java shaping】
Concurrent simulation tool : Use ab Simulation test
CentOS6 Default installation
CentOS7 Manual installation required
Connected to the Internet :yum install httpd-tools
vim postfile Simulate form submission parameters , With & The end of the symbol ; Store the current directory .
Content :prodid=0101&
ab -n 2000 -c 200 -k -p ~/postfile -T application/x-www-form-urlencoded http://192.168.2.115:8081/Seckill/doseckill
One 、 Solve the point : Inventory should be reduced , The number of successful people will increase
Two 、 Oversold problem
resolvent : Use optimistic locks to eliminate users
// Add optimistic lock jedis.watch(qtkey); //3. Determine inventory String qtkeystr = jedis.get(qtkey); if(qtkeystr==null || "".equals(qtkeystr.trim())) { System.out.println(" Uninitialized inventory "); jedis.close(); return false ; } int qt = Integer.parseInt(qtkeystr); if(qt<=0) { System.err.println(" It's been seconds "); jedis.close(); return false; } // Add business Transaction multi = jedis.multi(); //4. reduce stock //jedis.decr(qtkey); multi.decr(qtkey); //5. Add people //jedis.sadd(usrkey, uid); multi.sadd(usrkey, uid); // Perform transactions List<Object> list = multi.exec(); // Determine whether the transaction commit failed if(list==null || list.size()==0) { System.out.println(" Seckill failure "); jedis.close(); return false; } System.err.println(" Seckill success "); jedis.close();
Solved the oversold problem
3、 ... and 、 Connection timeout
Solve through connection pool
![]()
package com.atguigu; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; public class JedisPoolUtil { private static volatile JedisPool jedisPool = null; private JedisPoolUtil() { } public static JedisPool getJedisPoolInstance() { if (null == jedisPool) { synchronized (JedisPoolUtil.class) { if (null == jedisPool) { JedisPoolConfig poolConfig = new JedisPoolConfig(); poolConfig.setMaxTotal(200); poolConfig.setMaxIdle(32); poolConfig.setMaxWaitMillis(100*1000); poolConfig.setBlockWhenExhausted(true); poolConfig.setTestOnBorrow(true); // ping PONG jedisPool = new JedisPool(poolConfig, "192.168.44.168", 6379, 60000 ); } } } return jedisPool; } public static void release(JedisPool jedisPool, Jedis jedis) { if (null != jedis) { jedisPool.returnResource(jedis); } } }
package com.atguigu; import java.io.IOException; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.slf4j.LoggerFactory; import ch.qos.logback.core.rolling.helper.IntegerTokenConverter; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisCluster; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; import redis.clients.jedis.ShardedJedisPool; import redis.clients.jedis.Transaction; /** * */ public class SecKill_redis { public static void main(String[] args) { Jedis jedis =new Jedis("192.168.44.168",6379); System.out.println(jedis.ping()); jedis.close(); } // Second kill process public static boolean doSecKill(String uid,String prodid) throws IOException { //1 uid and prodid Judge not empty if(uid == null || prodid == null) { return false; } //2 Connect redis //Jedis jedis = new Jedis("192.168.44.168",6379); // Get through connection pool jedis object JedisPool jedisPoolInstance = JedisPoolUtil.getJedisPoolInstance(); Jedis jedis = jedisPoolInstance.getResource(); //3 Splicing key // 3.1 stock key String kcKey = "sk:"+prodid+":qt"; // 3.2 Second kill successful users key String userKey = "sk:"+prodid+":user"; // Monitor inventory jedis.watch(kcKey); //4 Get inventory , If inventory null, The second kill hasn't started yet String kc = jedis.get(kcKey); if(kc == null) { System.out.println(" The second kill hasn't started yet , Please wait "); jedis.close(); return false; } // 5 Judge whether the user repeats the second kill operation if(jedis.sismember(userKey, uid)) { System.out.println(" It's a second kill , You can't repeat the second kill "); jedis.close(); return false; } //6 Judge if the quantity of goods , Inventory quantity is less than 1, End of seckill if(Integer.parseInt(kc)<=0) { System.out.println(" The second kill is over "); jedis.close(); return false; } //7 Second kill process // With a transaction Transaction multi = jedis.multi(); // Team operation multi.decr(kcKey); multi.sadd(userKey,uid); // perform List<Object> results = multi.exec(); if(results == null || results.size()==0) { System.out.println(" The second kill failed ...."); jedis.close(); return false; } //7.1 stock -1 //jedis.decr(kcKey); //7.2 Add successful users to the list //jedis.sadd(userKey,uid); System.out.println(" The second kill succeeded .."); jedis.close(); return true; } }
- Link pool parameters
- MaxTotal: Control one pool How many can be allocated jedis example , adopt pool.getResource() To get ; If the assignment is -1, It means no limit ; If pool Has been allocated MaxTotal individual jedis example , Now pool The status of is exhausted.
- maxIdle: Control one pool How many states are there at most idle( Free ) Of jedis example ;
- MaxWaitMillis: Said when borrow One jedis When an instance , Maximum wait milliseconds , If the wait time is exceeded , Throw it directly JedisConnectionException;
- testOnBorrow: To obtain a jedis Check the connection availability when the instance is running (ping()); If true, Obtained jedis Instances are available ;
3、 ... and 、 Inventory remaining problems
It's been seconds , But there are still stocks . reason , Namely Optimistic locks cause many requests to fail . The first order didn't arrive in seconds , The next few seconds may be up .
resolvent :LUA Script
Lua It's a small Scripting language ,Lua Scripts can be easily C/C++ Code calls , You can also call... In reverse C/C++ Function of ,Lua There is no powerful library , A complete Lua The interpreter is nothing but 200k, therefore Lua Not suitable as a language for developing standalone applications , But as a Embedded scripting language .
A lot of applications 、 The game uses LUA As its own embedded scripting language , To achieve configurability 、 Extensibility .
This includes the Warcraft map 、 World of warcraft 、 The door of Bode 、 Angry birds and many other game plug-ins or plug-ins .
LUA Script in redis Advantages in :
Will be complex or multi-step redis operation , Write it as a script , Submit to redis perform , Reduce repeated connections redis The number of times . Lifting performance .
LUA The script is similar to redis Business , It has certain atomicity , Will not be interrupted by other orders , You can do some redis Transactional operations .
But notice redis Of lua Script function , Only in Redis 2.6 The above version can only be used .
utilize lua Scripts weed out users , Solve the oversold problem .
redis 2.6 After the version , adopt lua Script solution Competition problem , It's actually redis Take advantage of its single threaded feature , Using task queue to solve the problem of multitask concurrency .
package com.atguigu; import java.io.IOException; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; import org.slf4j.LoggerFactory; import ch.qos.logback.core.joran.conditional.ElseAction; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisCluster; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; import redis.clients.jedis.ShardedJedisPool; import redis.clients.jedis.Transaction; public class SecKill_redisByScript { private static final org.slf4j.Logger logger =LoggerFactory.getLogger(SecKill_redisByScript.class) ; public static void main(String[] args) { JedisPool jedispool = JedisPoolUtil.getJedisPoolInstance(); Jedis jedis=jedispool.getResource(); System.out.println(jedis.ping()); Set<HostAndPort> set=new HashSet<HostAndPort>(); // doSecKill("201","sk:0101"); } static String secKillScript ="local userid=KEYS[1];\r\n" + "local prodid=KEYS[2];\r\n" + "local qtkey='sk:'..prodid..\":qt\";\r\n" + "local usersKey='sk:'..prodid..\":usr\";\r\n" + "local userExists=redis.call(\"sismember\",usersKey,userid);\r\n" + "if tonumber(userExists)==1 then \r\n" + " return 2;\r\n" + "end\r\n" + "local num= redis.call(\"get\" ,qtkey);\r\n" + "if tonumber(num)<=0 then \r\n" + " return 0;\r\n" + "else \r\n" + " redis.call(\"decr\",qtkey);\r\n" + " redis.call(\"sadd\",usersKey,userid);\r\n" + "end\r\n" + "return 1" ; static String secKillScript2 = "local userExists=redis.call(\"sismember\",\"{sk}:0101:usr\",userid);\r\n" + " return 1"; public static boolean doSecKill(String uid,String prodid) throws IOException { JedisPool jedispool = JedisPoolUtil.getJedisPoolInstance(); Jedis jedis=jedispool.getResource(); //String sha1= .secKillScript; String sha1= jedis.scriptLoad(secKillScript); Object result= jedis.evalsha(sha1, 2, uid,prodid); String reString=String.valueOf(result); if ("0".equals( reString ) ) { System.err.println(" Empty !!"); }else if("1".equals( reString ) ) { System.out.println(" Panic buying !!!!"); }else if("2".equals( reString ) ) { System.err.println(" The user has robbed !!"); }else{ System.err.println(" Panic buying exception !!"); } jedis.close(); return true; } }
边栏推荐
- Qt报错:错误 C2039 “Value“: 不是 “`global namespace‘“ 的成员
- 【代码案例】网页版表白墙 & 待办事项 (包含完整源码)
- [c#] IEnumerable可枚举类型接口分析yield
- Online English learning system based on s2sh+mysql
- 32-spark的分区算子介绍、广播变量和累加器
- 【MySQL】游标「Cursor」
- "Lost wake up problem" in multithreading | why do wait() and notify() need to be used with the synchronized keyword?
- Three goals and eight tasks of intelligent construction pilot city notice
- 如何在OneFlow中新增算子
- Is there a fraud in opening an account with Huatai Securities? Is it safe
猜你喜欢

仅用5000行代码,在V853上AI渲染出一亿幅山水画

Android development learning diary - content provider (cross application database modification)

L-cysteine modified gold nanoparticles (Cys GNPs) and bovine serum albumin / biotinylated albumin nanoparticles

MD5加密解密网站测试,MD5加密还安全吗?

宇视NVR设备接入EasyCVR平台,离线后无法上线该如何解决?

"Lost wake up problem" in multithreading | why do wait() and notify() need to be used with the synchronized keyword?

Arcgis 计算两个栅格图层相关性

Use and implementation of enumeration classes

Read write barrier in memory barrier -- concurrency problem

Data middle office, Bi business interview (III): how to choose the right interviewees
随机推荐
使用IDEA的反编译插件 反编译jar包/class文件/修改jar包
Is it safe for Huatai Securities to open an account online? Is it true
禅道的甘特图功能是什么
金仓数据库 KingbaseES SQL 语言参考手册 (8. 函数(六))
The technical points of the new project can be guided if necessary
谈谈实施数据治理时常犯的10大错误
Target detection XML file to achieve mixup data enhancement (modifying the file path can be used directly, which is very convenient)
Ten year structure five year Life-05 first business trip
Sum of three numbers: (sort + double pointer + pruning)
智能建造试点城市通知的三大目标和八项任务
Network communication principle and IP address allocation principle. The seven layers of the network are physical layer, data link layer, network layer, transmission layer, session layer, presentation
2. Judgment statement
适合拼多多小商家配件的一些思路跟技巧
leetcode-99.恢复二叉搜索树
Moment get week, month, quarter, year
【C语言基础】15 位运算
网络数据泄露事件频发,个人隐私信息如何保护?
RichView TextBox Items 文本框
MySQL基础篇(运算符、排序分页、多表查询、函数)
客户至上 | 国产BI领跑者,思迈特软件完成C轮融资







