资讯专栏INFORMATION COLUMN

并发减库存 redis vs mysql

aikin / 1516人阅读

摘要:业务商品有库存,如每买一个商品库存就减一减库存可以通过来实现如也可以使用来实现如面对这种场景都说要使用因为并发性能更好想实际验证一下是否这样思路设置较大的并发数去更新库存执行次比较和花费的时间代码减库存任务减库存任务分别统计次休

业务

商品有库存, 如10000 每买一个商品 库存就减一

减库存可以通过mysql来实现 如

update product_stock set stock = stock - 1 where product_id = 1 and stock > 0; 

也可以使用redis来实现 如

decr 1_stock
(integer) 99

面对这种场景都说要使用redis 因为redis并发性能更好 想实际验证一下是否这样
思路

设置较大的并发数去更新库存 执行10次 比较redis和mysql花费的时间

代码

@SpringBootApplication
public class CocurrentUpdateStockApplication implements CommandLineRunner {
    @Autowired
    private JdbcTemplate jdbcTemplate;
    
    @Bean
    JedisConnectionFactory jedisConnectionFactory() {
        return new JedisConnectionFactory();
    }

    @Bean
    RedisTemplate redisTemplate() {
        final RedisTemplate template = new RedisTemplate();
        template.setConnectionFactory(jedisConnectionFactory());
        template.setKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new GenericToStringSerializer(Long.class));
        template.setValueSerializer(new GenericToStringSerializer(Long.class));
        return template;
    }

    public static void main(String[] args) {
        SpringApplication.run(CocurrentUpdateStockApplication.class, args);
    }
    //mysql减库存任务
    private Callable updateStockInMysqlTask = () -> {
        final String sql = "update product_stock set stock = stock-1 where product_id=1 and stock>0";
        jdbcTemplate.update(sql);
        return null;
    };
    //redis减库存任务
    private Callable updateStockInRedisTask = () -> {
        redisTemplate().execute(new RedisCallback() {
            public Long doInRedis(RedisConnection connection) throws DataAccessException {
                Long decr = connection.decr("1_stock".getBytes());
                return decr;
            }
        });
        return null;
    };

    @Override
    public void run(String... args) throws Exception {
        final String name = "mysql"; // or "redis"
        System.out.printf("start concurrent update stock in %s...%n", name);
        List timeList = new ArrayList<>();
        for (int i = 0; i < 10; i++) {//分别统计10次
            long start = System.currentTimeMillis();
            concurrentUpdateStock(name); //
            long end = System.currentTimeMillis();
            System.out.printf("Done. Take time: %d ms%n", end - start);
            timeList.add(end - start);
            Thread.sleep(1000); //休眠1秒
        }
        System.out.println(timeList.stream().collect(Collectors.summarizingLong(t -> t))); //输出统计结果

    }

    private void concurrentUpdateStock(String name) throws InterruptedException {
        // 模拟并发更新库存
        int nThreads = 500; //设置一个较大线程数
        ExecutorService pool = Executors.newFixedThreadPool(nThreads);
        List> tasks = new ArrayList<>();
        for (int i = 0; i < nThreads * 2; i++) { //2倍于线程数的减库存任务
            if ("mysql".equalsIgnoreCase(name))
                tasks.add(updateStockInMysqlTask);
            else if ("redis".equalsIgnoreCase(name))
                tasks.add(updateStockInRedisTask);
        }
        List> futureList = pool.invokeAll(tasks); //并发去执行这些任务

        while (futureList.stream().anyMatch(f -> !f.isDone())); //等待任务执行完
        pool.shutdown();

    }

}

输出结果

    mysql:
    LongSummaryStatistics{count=10, sum=11485, min=897, average=1148.500000, max=1458}
    
    redis:
    LongSummaryStatistics{count=10, sum=1706, min=95, average=170.600000, max=493}

结果
并发执行1000次减库存操作 mysql要比redis慢差不多7倍

完整代码见
https://github.com/zhugw/cocurrent_update_stock/blob/master/src/main/java/com/zhugw/CocurrentUpdateStockApplication.java

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/36170.html

相关文章

  • 并发库存 redis vs mysql

    摘要:业务商品有库存,如每买一个商品库存就减一减库存可以通过来实现如也可以使用来实现如面对这种场景都说要使用因为并发性能更好想实际验证一下是否这样思路设置较大的并发数去更新库存执行次比较和花费的时间代码减库存任务减库存任务分别统计次休 业务 商品有库存, 如10000 每买一个商品 库存就减一 减库存可以通过mysql来实现 如 update product_stock set stock ...

    FuisonDesign 评论0 收藏0
  • 秒杀系统优化方案之缓存、队列、锁设计思路

    摘要:一为什么难秒杀系统难做的原因库存只有一份,所有人会在集中的时间读和写这些数据。又例如抢票,亦与秒杀类似,瞬时流量更甚。 一、为什么难     秒杀系统难做的原因:库存只有一份,所有人会在集中的时间读和写这些数据。例如小米手机每周二的秒杀,可能手机只有1万部,但瞬时进入的流量可能是几百几千万。又例如12306抢票,亦与秒杀类似,瞬时流量更甚。 主要需要解决的问题有两个: 高并发对数据库...

    dinfer 评论0 收藏0
  • 秒杀系统优化方案之缓存、队列、锁设计思路

    摘要:一为什么难秒杀系统难做的原因库存只有一份,所有人会在集中的时间读和写这些数据。又例如抢票,亦与秒杀类似,瞬时流量更甚。 一、为什么难     秒杀系统难做的原因:库存只有一份,所有人会在集中的时间读和写这些数据。例如小米手机每周二的秒杀,可能手机只有1万部,但瞬时进入的流量可能是几百几千万。又例如12306抢票,亦与秒杀类似,瞬时流量更甚。 主要需要解决的问题有两个: 高并发对数据库...

    Meathill 评论0 收藏0
  • php和redis设计秒杀活动

    摘要:说明前段时间面试的时候,一直被问到如何设计一个秒杀活动,但是无奈没有此方面的实际经验,所以只好凭着自己的理解和一些资料去设计这么一个程序主要利用到了的和主要是利用它的结构去对库存进行处理,也可以用的数据结构来处理商品的库存,则用来确保用户 1 说明 前段时间面试的时候,一直被问到如何设计一个秒杀活动,但是无奈没有此方面的实际经验,所以只好凭着自己的理解和一些资料去设计这么一个程序主要利...

    kyanag 评论0 收藏0
  • 大话后端开发的奇淫技巧大集合

    摘要:,大家好,很荣幸有这个机会可以通过写博文的方式,把这些年在后端开发过程中总结沉淀下来的经验和设计思路分享出来模块化设计根据业务场景,将业务抽离成独立模块,对外通过接口提供服务,减少系统复杂度和耦合度,实现可复用,易维护,易拓展项目中实践例子 Hi,大家好,很荣幸有这个机会可以通过写博文的方式,把这些年在后端开发过程中总结沉淀下来的经验和设计思路分享出来 模块化设计 根据业务场景,将业务...

    CloudwiseAPM 评论0 收藏0

发表评论

0条评论

aikin

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<