文档章节

利用redis的lua实现防止超买的一段小程序(和测试程序在一起)

 陆大侠
发布于 2015/11/12 13:40
字数 304
阅读 44
收藏 0

private static AtomicLong salesCount = new AtomicLong(100000);

 private final String updateStockHold = "local key = KEYS[1] \n"

 + "local count = ARGV[1] \n"

 + "redis.call('decrby', key, count) \n"

 + "local afterCount = redis.call('get', key) \n"

 + "if (tonumber(afterCount) < 0) then \n"

 + " redis.call('incrby', key, count) \n"

 + " return afterCount \n"

 + "else \n"

 + " return afterCount \n"

 + "end \n";


 @Test

 public void testRedisService() throws InterruptedException, BrokenBarrierException {

        Jedis jedis = setupSentinelPool();

 jedis.set("iphone_count", "100000");


 final CyclicBarrier cyclicBarrier =new CyclicBarrier(21);

 ExecutorService executorService = Executors.newFixedThreadPool(20);

 int times = 20;

 while (times > 0) {

            Thread.sleep(10);

 executorService.submit(new Runnable() {

                @Override

 public void run() {

                    Jedis jedis = setupSentinelPool();

 int runTimes = 3000;

 try {

                        cyclicBarrier.await();

 } catch (InterruptedException e) {

                        e.printStackTrace();

 } catch (BrokenBarrierException e) {

                        e.printStackTrace();

 }

                    while (runTimes > 0) {

                        int count = 1;

 String luaAcquireLockSHA = jedis.scriptLoad(updateStockHold);

 Object obj = jedis.evalsha(luaAcquireLockSHA, 1, "iphone_count", String.valueOf(count));

 System.out.println("After Update Count:" + obj);

// System.out.println("After Update Count : " + jedis.get("iphone_count"));

 runTimes--;

 if (Long.parseLong(obj.toString()) >= 0) {

                            salesCount.addAndGet(-1);

 }else {

                            break;

 }

                        if(Thread.currentThread().isInterrupted()){

                            break;

 }

                    }

                }

            });

 times--;

 }

        cyclicBarrier.await();

 System.out.println("Start Time Unit " + new Date());

 executorService.awaitTermination(1, TimeUnit.SECONDS);

 executorService.shutdownNow();

 System.out.println("End Time Unit " + new Date());


 Thread.sleep(100);

 System.out.println("Final Result : " + jedis.get("iphone_count"));

 System.out.println("Final Result Expected: " + salesCount.get());


 }


    private Jedis setupSentinelPool() {

        try {

            // 1.配置Apache-Commons连接池属性

 GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();

 poolConfig.setMaxTotal(1);

 poolConfig.setMaxIdle(1);

 poolConfig.setMinIdle(1);

 poolConfig.setBlockWhenExhausted(true);

 poolConfig.setMaxWaitMillis(500);

 poolConfig.setLifo(false);

 poolConfig.setTestOnBorrow(false);

 poolConfig.setTestOnReturn(false);

 poolConfig.setTestWhileIdle(true);

 poolConfig.setTimeBetweenEvictionRunsMillis(30000);

 poolConfig.setNumTestsPerEvictionRun(-1);

 poolConfig.setMinEvictableIdleTimeMillis(60);


 // 2.获取Sentinel地址

 String[] addrs = redisCacheConfig.getSentinels().split(";");

 Set<String> sentinelSet = new HashSet<String>();

 for (String addr : addrs) {

                sentinelSet.add("172.19.9.230:6601");

 }


            JedisSentinelPool pool = new JedisSentinelPool("mkt-cache", sentinelSet, poolConfig,

 2000, "redis1");

 logger.info("[CACHE]JedisSentinelPool init completed.");


 return pool.getResource();


 } catch (Throwable e) {

            // logger.error("[CACHE]init fail", e);

 throw new InitializationException("RedisClient init fail", e);

 } finally {


        }

    }


© 著作权归作者所有

粉丝 2
博文 54
码字总数 18787
作品 0
浦东
私信 提问
加载中

评论(1)

陆大侠 博主
REDIS在另外一台机器上。测试机I7 3770 上,开20线程测试,每秒可处理15000次以上订单,库存保持完全一致。
像调试java一样来调试Redis lua

高并发的系统中,redis的使用是非常频繁的,而lua脚本则更是锦上添花。因为lua脚本本身执行的时候是一个事务性的操作,不会掺杂其他外部的命令,所以很多关键的系统节点都会用redis+lua来实现...

java菜分享
2018/12/29
35
0
Redis进阶实践之七Redis和Lua初步整合使用

Redis进阶实践之七Redis和Lua初步整合使用 一、引言 Redis学了一段时间了,基本的东西都没问题了。从今天开始讲写一些redis和lua脚本的相关的东西,lua这个脚本是一个好东西,可以运行在任何...

morpheusWB
2018/09/13
31
2
再有人问你分布式锁,就把这个丢给他!

作者介绍 中华石杉,十余年BAT架构经验倾囊相授。个人微信公众号:石杉的架构笔记(ID:shishan100)。 现在面试都会聊聊分布式系统,通常面试官都会从服务框架(Spring Cloud、Dubbo),一路...

中华石杉
01/31
0
0
初学乍练:redis事务与脚本

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wzy0623/article/details/82350861 目录 一、事务 1. 概述 2. 错误处理 3. watch命令 二、redis脚本 1. 脚本介...

wzy0623
2018/09/03
0
0
如何优雅地在Redis中使用Lua

作者:可均可可 原文:http://www.cnblogs.com/PatrickLiu/p/8391829.html 一、引言 今天讲一些redis和lua脚本的相关的东西,lua这个脚本是一个好东西,可以运行在任何平台上,也可以嵌入到大...

程序员之家_
02/08
0
0

没有更多内容

加载失败,请刷新页面

加载更多

MongoDB系列-解决面试中可能遇到的MongoDB复制集(replica set)问题

关注我,可以获取最新知识、经典面试题以及微服务技术分享   MongoDB复制集(replica set):MongoDB复制集维护相同数据集的一组mongod进程,复制集是生产部署的基础,具有数据冗余以及高可用...

ccww_
22分钟前
2
0
SpringBoot系列:Spring Boot集成Spring Cache,使用RedisCache

前面的章节,讲解了Spring Boot集成Spring Cache,Spring Cache已经完成了多种Cache的实现,包括EhCache、RedisCache、ConcurrentMapCache等。 这一节我们来看看Spring Cache使用RedisCache。...

杨小格子
30分钟前
2
0
OpenJDK之CountDownLatch

OpenJDK8,本人看的是openJDK。以前就看过,只是经常忘记,所以记录下 图1 CountDownLatch是Doug Lea在JDK1.5中引入的,作用就不详细描述了, await()方法,如果还有线程在执行,那么当前线程...

克虏伯
37分钟前
2
0
简单编程

1.编写一个程序,提示用户输入名和姓,然后以“名,姓”的格式打印出来。 #include<stdio.h>int main(){char name[3];char family[3];printf("Please input your name and family:\n...

电子工程197沈志初
41分钟前
4
0
详解Mysql分布式事务XA(跨数据库事务)

在开发中,为了降低单点压力,通常会根据业务情况进行分表分库,将表分布在不同的库中(库可能分布在不同的机器上)。在这种场景下,事务的提交会变得相对复杂,因为多个节点(库)的存在,可...

slagga
46分钟前
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部