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

来源:互联网 发布:大数据设计哪些技术 编辑:程序博客网 时间:2024/05/21 00:44

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

本文只讲处理秒杀请求、减库存操作,前端的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));            }        }    }}
原创粉丝点击