使用工具ab模拟测试
CentOS6 默认安装
CentOS7需要手动安装
有网络的话直接安装:
yum install httpd-tools
没网络:进入cd /run/media/root/CentOS 7 x86_64/Packages
(路径跟centos6不同),顺序安装
apr-1.4.8-3.el7.x86_64.rpm
apr-util-1.5.2-6.el7.x86_64.rpm
httpd-tools-2.4.6-67.el7.centos.x86_64.rpm
(1)通过ab测试
创建文件postfile,填写参数
vim postfile 模拟表单提交参数,以&符号结尾;存放当前目录。
postfile文件的内容:
prodid=0101&
添加请求:
ab -n 2000 -c 200 -k -p ~/postfile -T application/x-www-form-urlencoded http://192.168.2.115:8080/Seckill/doseckill
~/postfile是存储参数的文件
http://192.168.2.115:8081/Seckill/doseckill是本地Java Web项目
-n 2000表示请求数量为2000
-c 200表示并发数量为200
-k:启用HTTP KeepAlive功能,即在一个HTTP会话中执行多个请求。默认时,不启用KeepAlive功能。
(2)超卖
并发情况下会出现超卖问题,即库存为负值。
利用乐观锁淘汰用户,解决超卖问题。
ab -n 2000 -c 200 -k -p postfile -T 'application/x-www-form-urlencoded' http://192.168.140.1:8080/seckill/doseckill
增加-r参数,-r Don’t exit on socket receive errors.(抛出异常继续执行测试任务)
ab -n 2000 -c 100 -r -p postfile -T 'application/x-www-form-urlencoded' http://192.168.140.1:8080/seckill/doseckill
ab -n 2000 -c 100 -p postfile -T 'application/x-www-form-urlencoded' http://192.168.137.1:8080/seckill/doseckill
已经秒光,可是还有库存。原因,就是乐观锁导致很多请求都失败。先点的没秒到,后点的可能秒到了。
节省每次连接redis服务带来的消耗,把连接好的实例反复利用。通过参数管理连接的行为。
链接池参数:
乐观锁会造成库存遗留问题,当第一个请求修改了版本号之后,之后的请求发现版本号不一样会中断请求,所以即使还有库存,也不会在执行请求了,就造成了库存遗留问题,可使用LUA脚本解决这个问题。
Lua 是一个小巧的脚本语言,Lua脚本可以很容易的被C/C++ 代码调用,也可以反过来调用C/C++的函数,Lua不适合作为开发独立应用程序的语言,而是作为嵌入式脚本语言。
争抢问题
,实际上是redis 利用其单线程的特性,用任务队列的方式解决多任务并发问题。使用工具ab模拟并发测试,会出现超卖情况。查看库存会出现负数。手动请求,非并发。
解决超卖问题,但出现遗留库存和连接超时。
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;
}
//解决超时问题
jedisPool = new JedisPool(poolConfig, "192.168.44.168", 6379, 60000 );
Luau脚本,嵌入Java语言中
//Lua脚本
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" ;
Redis中添加库存:
库存为500
set sk:0101:qt 500
模拟并发:
http://192.168.146.1:8080/SecKill根据项目实际访问路径填写
ab -n 2000 -c 200 -k -p postfile -T 'application/x-www-form-urlencoded' http://192.168.222.1:8080/SecKill
ab并发测试访问超时了,应该是服务器上访问不了本地Java项目:
贴一个手动模拟的非并发:
Redis中商品库存为0了: