前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用redis分布式锁高并发下QPS测试,单机一秒下1千个订单

使用redis分布式锁高并发下QPS测试,单机一秒下1千个订单

作者头像
天涯泪小武
发布2019-10-22 16:20:48
1.9K0
发布2019-10-22 16:20:48
举报
文章被收录于专栏:SpringCloud专栏SpringCloud专栏

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

代码语言:txt
复制
                 本文链接:[https://blog.csdn.net/tianyaleixiaowu/article/details/102571736](https://blog.csdn.net/tianyaleixiaowu/article/details/102571736) 

前面一篇讲过并发下单时进行优化的一些策略,后来我写了代码进行了实测。

关于redisson做分布式锁的代码在这篇文章。这里我来测试一下分布式锁的性能。

简单的controller

代码语言:javascript
复制
package com.tianyalei.redislock.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author wuweifeng wrote on 2019-10-15.
 */
@RequestMapping("/redisLock")
@RestController
public class IndexController {
    @Resource
    private IndexService indexService;

    private volatile AtomicInteger index = new AtomicInteger(Integer.MAX_VALUE);


    @RequestMapping("random")
    public String sellTwo(int count) {
        int i = index.getAndDecrement() % count;
        if (i == 0) {
            indexService.sell(0);
        } else if (i == 1) {
            indexService.sell(1);
        } else if (i == 2) {
            indexService.sell(2);
        } else if (i == 3) {
            indexService.sell(3);
        } else if (i == 4) {
            indexService.sell(4);
        }

        return "ok";
    }

    @RequestMapping("mm")
    public String sellmm(int count) {
        int i = index.getAndDecrement() % count;
        if (i == 0) {
            indexService.sellMemory(0);
        } else if (i == 1) {
            indexService.sellMemory(1);
        } else if (i == 2) {
            indexService.sellMemory(2);
        } else if (i == 3) {
            indexService.sellMemory(3);
        } else if (i == 4) {
            indexService.sellMemory(4);
        }

        return "ok";
    }
}

定义了2个接口,上面的是用redis分布式锁,下面的是走内存。

代码语言:javascript
复制
package com.tianyalei.redislock.controller;

import com.tianyalei.redislock.annotation.RedissonLock;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author wuweifeng wrote on 2019-10-15.
 */
@Service
public class IndexService {
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    private Logger logger = LoggerFactory.getLogger(getClass());

    private volatile AtomicInteger count1 = new AtomicInteger(500000);
    private volatile AtomicInteger count2 = new AtomicInteger(500000);
    private volatile AtomicInteger count3 = new AtomicInteger(500000);
    private volatile AtomicInteger count4 = new AtomicInteger(500000);
    private volatile AtomicInteger count5 = new AtomicInteger(500000);


    /**
     * 上分布式锁
     */
    @RedissonLock(lockIndex = 0)
    public void sell(Integer goodsId) {
        logger.info("goodId:" + goodsId);
        stringRedisTemplate.opsForValue().set(getRandomString(8), System.currentTimeMillis() + "abc");
        logger.info(System.currentTimeMillis() + "");
    }

    /**
     * 直接读内存
     */
    public void sellMemory(Integer goodsId) {
        logger.info("goodId:" + goodsId);
        switch (goodsId) {
            case 0:
                logger.info("count1:" + count1.getAndDecrement());
                break;
            case 2:
                logger.info("count2:" + count2.getAndDecrement());
                break;
            case 3:
                logger.info("count3:" + count3.getAndDecrement());
                break;
            case 4:
                logger.info("count4:" + count4.getAndDecrement());
                break;
            default:
                logger.info("count5:" + count5.getAndDecrement());
                break;
        }

        stringRedisTemplate.opsForValue().set(getRandomString(8), System.currentTimeMillis() + "abc");
        logger.info(System.currentTimeMillis() + "");
    }

    public static String getRandomString(int length) {
        String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(62);
            sb.append(str.charAt(number));
        }
        return sb.toString();
    }
}

关于RedissonLock注解在前面的文章里写了代码了。

sell方法就是针对goodsId进行加分布式锁,如果只有一个商品的话,就等于是完全在该商品的售卖上进行排队,性能就全靠redis的加锁解锁和业务耗时了。业务方面我采用直接将订单下到redis里的方式,不走数据库。正常情况下,业务耗时在10ms左右比较靠谱。

sellMemory方法就是完全在内存中进行商品数量的减少,摆脱掉redis的网络通信。业务上也是将订单下到redis中。

redis的一次加锁、解锁,我们可以计算它的耗时,加锁是一次通信,加锁失败后排队,然后等待redis的Channel监听回调,回调这又是一次通信,回调后再次去试图加锁并成功,这又是一次通信,业务上在redis里下一单,这又是一次通信。共计4次。

那么在业务耗时相同的情况下,在内存中直接扣减库存会比通过redis分布式锁,少4次网络IO。

结果如下:

通过redis分布式锁下单

200个线程并发,循环1次,购买1个商品,锁在同一个goodsId。共计600ms,200单下单完毕。

200个线程并发,循环2次,购买1个商品,锁在同一个goodsId。共计1100ms,400单下单完毕。

200个线程并发,循环2次,购买5个商品,锁在不同的goodsId,性能明显有所提升。共计600ms,400单下单完毕。

400个线程并发,循环1次,购买5个商品,锁在不同的goodsId。共计600ms,400单下单完毕。

400个线程并发,循环2次,购买5个商品,锁在不同的goodsId。共计1000ms,800单下单完毕。

在内存里下单

200个线程并发,循环1次,购买1个商品,锁在同一个goodsId。共计300ms,200单下单完毕。

200个线程并发,循环2次,购买1个商品,锁在同一个goodsId。共计400ms,400单下单完毕。

200个线程并发,循环1次,购买5个商品,锁在不同的goodsId。共计300ms,200单下单完毕。

200个线程并发,循环2次,购买5个商品,锁在不同的goodsId。共计400ms,400单下单完毕。

400个线程并发,循环1次,购买5个商品,锁在不同的goodsId。共计500ms,400单下单完毕。

400个线程并发,循环2次,购买5个商品,锁在不同的goodsId。共计700ms,800单下单完毕。

注意,这个测试是直接在HaProxy后面做的server,没有通过zuul网关。可以看到,在内存中下单,速度约是redis上锁的2倍。在并发高的情况下,差距会更大。

当业务耗时更大的情况下,redis分布式锁在同一个商品上加锁,每秒大概能完成100单。而基于内存的话,单实例能下到1千单。

基于内存,那么就需要通过分布式配置中心,在项目启动后,给商品数量count赋初值。譬如1万个商品,10个实例,则每个分配1千。

实例之间彼此不会发生锁的冲突,基于cas的减库存,性能优异。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2019-10-15 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档