ab测试工具的安装和使用

linux 系统:使用yum安装

1、安装ab工具用于测试高并发
 命令:  yum install httpd-tools

2、ab --help 查看ab命令的参数

3、常用参数说明
   -n  请求数量
   -c  并发数量
   -p  postfile  可以将post请求中的参数封装在postfile文件里面,
以key=value&形式保存,注意需要&结尾,使用时,使用-p 文件名(postfile)该文件需要自己创建,该参数的使用需要制定-T,一起使用          -T 文件的类型  'application/x-www-form-urlencoded'

postfile文件:  key1=value1&key2=value2&

如下模拟1000个请求10个并发访问某个servlet程序,使用redis存储数据,模拟抢购案例。
[root@localhost bin]# ab -n 100 -c 10  -p  /opt/postfile  -T 'application/x-www-form-urlencoded'   http://192.168.2.150:8080/redis-test3/doSeckill

代码:

@WebServlet("/doseckill")
public class SecKillServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String userid = new Random().nextInt(50000) +"" ;
        String prodid =req.getParameter("prodid");
        boolean if_success=SecKill_ByRedis.doSecKill(userid,prodid);
       // boolean if_success=SecKillByLua.doSecKill(userid,prodid);
        resp.getWriter().print(if_success);
    }
}

调用业务方法:

public class SecKill_ByRedis {
    public static boolean doSecKill(String userid, String prodid) {
        //1.生成key  
        //商品的库存key
        String qtKey = "sk:"+prodid+":qt";
        //秒杀到的用户数量key
        String uidKey = "sk:"+prodid+":usr";
        //Jedis jedis = new Jedis("192.168.151.250", 6379);
        JedisPool jedisPool = JedisPoolUtils.getInstanceJedisPool();
        Jedis jedis = jedisPool.getResource();
        //判断这个用户是否已经秒杀到了
        if(jedis.sismember(uidKey, userid)){
            System.out.println("你已经秒到,不能重复秒杀!");
            jedis.close();
            return false;
        }
        //这个位置没有加锁,导致并发时出问题
        //增加乐观锁事物
        jedis.watch(qtKey);
        String qtStr = jedis.get(qtKey);
        //判断库存是否足够
        if(qtStr == null) {
            System.out.println("没有初始化");
            jedis.close();
            return false;
        }else {
            int qt= Integer.parseInt(qtStr);
            if(qt <= 0 ) {
                System.out.println("已经抢光了....");
                jedis.close();
                return false;
            }
        }
        //组队,之后序马上执行
        Transaction transaction = jedis.multi();
        //减库存
        transaction.decr(qtKey);
        //加人
        transaction.sadd(uidKey, userid);
        //执行队列中的事物
        List<Object> exec = transaction.exec();
        if(exec==null ||exec.size()==0) {
            System.out.println(userid + "秒杀失败....");
            jedis.close();
            return false;
        }
        System.out.println(userid + "秒杀成功....");
        jedis.close();
        return true;
    }
}

使用单例模式获取线程池对象

public class JedisPoolUtils {
    private static volatile JedisPool jedisPool = null;
    private JedisPoolUtils() {
    }
    public static JedisPool getInstanceJedisPool() {
        if(jedisPool == null) {
            synchronized (JedisPoolUtils.class) {
                if(jedisPool == null) {
                    JedisPoolConfig poolConfig = new JedisPoolConfig();
                    //最大的连接数
                    poolConfig.setMaxTotal(200);
                    //空闲时的连接数
                    poolConfig.setMaxIdle(32);
                    //最大的等待时间
                    poolConfig.setMaxWaitMillis(1000*1000);
                    //当没有连接的时间阻塞
                    poolConfig.setBlockWhenExhausted(true);
                    //保证获取的连接可以使用
                    poolConfig.setTestOnBorrow(true);
                    jedisPool = new JedisPool(poolConfig, "192.168.151.250", 6379);
                }
            }
        }
        return jedisPool;
    }
}

秒杀不完问题的解决方案:使用lua脚本,Redis版本需要2.6及以上才可以 secndKill.lua脚本文件内容

local userid=KEYS[1];
local prodid=KEYS[2];
local qtkey="sk:"..prodid..":qt";
local usersKey="sk:"..prodid..":usr';
local userExists=redis.call("sismember",usersKey,userid);
if tonumber(userExists)==1 then
      return 2;
end
local num= redis.call("get" ,qtkey);
if tonumber(num)<=0 then
      return 0;
else
      redis.call("decr",qtkey);
      redis.call("sadd",usersKey,userid);
end
return 1;

java代码:

public class SecKillByLua {
    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 userid, String prodid) {
        JedisPool jedisPool = JedisPoolUtils.getInstanceJedisPool();
        Jedis jedis = jedisPool.getResource();
        String sha1 = jedis.scriptLoad(secKillScript);
        Object result = jedis.evalsha(sha1, 2, userid,prodid);
        String reString = String.valueOf(result);
        if("0".equals(reString)) {
            System.out.println("已经抢空了!!");
        }else if("1".equals(reString)) {
            System.out.println("抢购成功!!");
        }else if("2".equals(reString)) {
            System.out.println("该用户已经抢过!!!");
        }else {
            System.out.println("抢购异常!!!");
        }
        jedis.close();
        return true;
    }
}

 

前端页面:

<body>
<h1>iPhoneX !!!  1元秒杀!!!</h1>
<form id="msform" action="${pageContext.request.contextPath}/doseckill">
    <input type="hidden" id="prodid" name="prodid" value="0101">
    <input type="button"  id="miaosha_btn" name="seckill_btn" value="秒杀点我"/>
</form>
</body>
<script  type="text/javascript" src="${pageContext.request.contextPath}/script/jquery/jquery-3.1.0.js"></script>
<script  type="text/javascript">
$(function(){
    $("#miaosha_btn").click(function(){    
        var url=$("#msform").attr("action");
         $.post(url,$("#msform").serialize(),function(data){
             if(data=="false"){
                alert("抢光了" );
                $("#miaosha_btn").attr("disabled",true);
            }
        } );    
    })
})
</script>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值