后台秒杀架构设计与实现(一)

后台秒杀架构设计与实现(一)

本文只讲处理秒杀请求、减库存操作,前端的CDN加速,防作弊,防刷不在此列;本文利用redis watch实现乐观锁来处理减库存请求。
本文适用于用户量大,商品库存量少场景,若是库存量大场景,适合队列异步实现。

  • 流程图
    这里写图片描述

测试入口类

package com.liushao.redislockframework;

import java.util.Date;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import redis.clients.jedis.Jedis;

/**
 * 测试抢购
 */
public class SecKillTest {
    public static void main(String[] args) {

        final String watchkey = "watchkey";
        ExecutorService executor = Executors.newFixedThreadPool(200);

        Jedis jedis = RedisUtils.getJedis();
        jedis.set(watchkey, "0");// 重置watchkey为0
        jedis.del("setsucc", "setfail");// 清空抢成功、失败两个set
        RedisUtils.returnResource(jedis);
        long starttime = new Date().getTime();

        //模拟100万人抢10个商品
        for (int i = 0; i < 1000000; i++) {
            executor.execute(new SecKillThread(UUID.randomUUID().toString(), starttime));
        }
        executor.shutdown();
    }
}

redis连接池

package com.liushao.redislockframework;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public class RedisUtils {

    private RedisUtils(){

    }

    private static  JedisPool jedisPool = null;
    //获取链接
    public static synchronized Jedis getJedis(){
        if(jedisPool==null){
            JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
            //指定连接池中最大空闲连接数
            jedisPoolConfig.setMaxIdle(10);
            //链接池中创建的最大连接数
            jedisPoolConfig.setMaxTotal(100);
            //设置创建链接的超时时间
            jedisPoolConfig.setMaxWaitMillis(2000);
            //表示连接池在创建链接的时候会先测试一下链接是否可用,这样可以保证连接池中的链接都可用的。
            jedisPoolConfig.setTestOnBorrow(true);
            jedisPool = new JedisPool(jedisPoolConfig, "127.0.0.1", 6379);
        }
        return jedisPool.getResource();
    }

    //返回链接
    public static void returnResource(Jedis jedis){
        jedisPool.returnResourceObject(jedis);
    }

}

具体实现类

package com.liushao.redislockframework;

import java.util.Date;
import java.util.List;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

public class SecKillThread implements Runnable {
    final String watchkey = "watchkey";// 监视keys
    final int sku_num = 10; //总库存
    private long starttime; //秒杀开始时间
    private String userid;  //用户id
    private static boolean flag = true; //秒杀结束标识

    public SecKillThread(String userid, long starttime) {
        this.userid = userid;
        this.starttime = starttime;
    }

    public void run() {
        if (flag) {
            Jedis jedis = RedisUtils.getJedis();
            try {
                jedis.watch(watchkey);// watchkeys
                int succ_count = Integer.valueOf(jedis.get(watchkey));
                if (succ_count < sku_num) {
                    Transaction tx = jedis.multi();// 开启事务
                    tx.incr(watchkey);
                    List<Object> list = tx.exec();// 提交事务,如果此时watchkey被改动了,则返回null
                    if (list != null) {
                        System.out.println("用户:" + userid + "抢购成功,当前抢购成功人数:"
                                + (succ_count + 1));
                        //抢购成功业务逻辑
                        jedis.sadd("setsucc", userid);
                        //可直接入库持久化
                        //。。。。
                    } else {
                        System.out.println("用户:" + userid + "抢购失败");
                    /* 抢购失败业务逻辑 */
                        jedis.sadd("setfail", userid);
                    }
                } else {
                    //抢购结束,拒绝后续申请
                    flag = false;
                    //System.out.println("抢购结束");
                    jedis.sadd("setfail", userid);
                    return;
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                RedisUtils.returnResource(jedis);
                System.out.println("总耗时:" + (new Date().getTime() - starttime));
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值