redisはwatch、multi、execコマンドに有利で、秒殺機能を実現する

5348 ワード

1、注意点:redis watchコマンドは、1つ(または複数)のkeyを監視するために使用され、トランザクションが実行される前にこの(またはこれら)keyが他のコマンドによって変更されると、トランザクションが中断されます.モニタはEXECコマンドまで継続します(トランザクションのコマンドはEXEC以降に実行されるため、MULTIコマンドの後でWATCHモニタのキー値を変更できます)
2:コードは次のとおりです.
public class JedisRunnable implements Runnable {

    private Jedis jedis = JedisUtil.getJedis();
    private String userId;

    public JedisRunnable(String userId) {
        this.userId = userId;
    }

    public void run() {

        try {
            //     ,     key      ,      OK,         。
            jedis.watch(RedisSecKiller.WATCH_KEY);
            //        
            int leftGoodsNum = Integer.valueOf(jedis.get(RedisSecKiller.WATCH_KEY));
            //         0 ,         1     。
            if (leftGoodsNum > 0) {
                //   jedis  
                Transaction tx = jedis.multi();
                //    :      Goods      1  ,  tx.exec()           Goods      。
                tx.decrBy(RedisSecKiller.WATCH_KEY, 1);
                //    :      Goods      1,  tx.exec()           "OK"。
//                tx.set(RedisSecKiller.WATCH_KEY, String.valueOf(leftGoodsNum - 1));
                //     ,     。
                List results = tx.exec();
                // leftGoodsNum  Goods     1,          1  。
                //     ,      ,leftGoodsNum Goods    (        )    。
//                System.out.println("      :" + leftGoodsNum);
//                System.out.println("        :" + results);
                // results null   ,                ,    。
                if (results == null || results.isEmpty()) {
                    String failUserInfo = "fail---" + userId;
                    //       results.get(0)          。
                    String failMsg = "  " + failUserInfo + ",    ,      :" + leftGoodsNum +
                            ",               。";
                    System.out.println(failMsg);
                    //             Redis。
                    jedis.setnx(failUserInfo, failMsg);
                } else { //   tx.exec()      ,       。
                    for (Object succ : results) {
                        String succUserInfo = "succ" + succ.toString() + "---" + userId;
                        String succMsg = "  " + succUserInfo + ",    ,        :" +
                                (10 - Integer.parseInt(results.get(0).toString())) +
                                ",        :" + Integer.parseInt(results.get(0).toString());
                        System.out.println(succMsg);
                        //             Redis。
                        jedis.setnx(succUserInfo, succMsg);
                    }
                }
            } else { //      0,      。
                String overUserInfo = "over---" + userId;
                String overMsg = "  " + overUserInfo + ",       ,      :" + leftGoodsNum;
                System.out.println(overMsg);
                //                        Redis。
                jedis.setnx(overUserInfo, overMsg);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            JedisUtil.returnResource(jedis);
        }

    }
}
public class RedisSecKiller {

    //            
    private static final int N_THREADS = 5;
    // jedis  watch    WATCH_KEY,      ,     。
    public static final String WATCH_KEY = "Goods";
    //     
    private static final int GOODS_NUM = 1000;
    //     
    private static final int USER_NUM = 100;

    public static void main(String[] args) {
        //      ,  N_THREADS          。
        ExecutorService executorService = Executors.newFixedThreadPool(N_THREADS);
        Jedis jedis = JedisUtil.getJedis();
        //        10
        jedis.set(WATCH_KEY, String.valueOf(GOODS_NUM));
        jedis.close();
        //   USER_NUM        
        for (int i = 0; i < USER_NUM; i++) {
            executorService.execute(new JedisRunnable(UUID.randomUUID().toString()));
//            System.out.println("==============     ===============");
        }
        executorService.shutdown();
    }
}

 
public class JedisUtil {

    private static final String ADDR = "192.168.222.130";
    private static final int PORT = 6379;
    private static final boolean TEST_ON_BORROW = true;
    private static final int MAX_IDLE = 200;
    private static JedisPool jedisPool = null;

    static {
        try {
            JedisPoolConfig config = new JedisPoolConfig();
            config.setMaxIdle(MAX_IDLE);
            config.setTestOnBorrow(TEST_ON_BORROW);
            jedisPool = new JedisPool(config, ADDR, PORT);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    public synchronized static Jedis getJedis() {
        try {
            if (jedisPool != null) {
                Jedis resource = jedisPool.getResource();
                return resource;
            }
            return null;
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return null;
    }

    public static void returnResource(final Jedis jedis) {
        if (jedis != null) {
            jedis.close();
        }
    }

}