mirror of
https://github.com/qiurunze123/miaosha.git
synced 2023-11-19 22:41:03 +08:00
lua+redsi
This commit is contained in:
parent
c4fdecf1e9
commit
92f77fd8e4
|
@ -82,6 +82,7 @@
|
|||
| 028 |项目进行dubbo + zk 改造 (已完成dubbo嵌入--springboot 与dubbo结合xml版本)?|[解决思路](/docs/code-solve.md) |
|
||||
| 029 |dubbo客户端 dubbo-admin管理平台 搭建安装|[解决思路](/docs/dubbo-admin.md) |
|
||||
| 030 |如何利用dubbo 的mock 来进行服务降级本地伪装 ?? (有更好的方式进群@我)|[解决思路](/docs/dubbo-zk.md) |
|
||||
| 027 |*** 如何利用lua + redis 取代 nigix + lua 脚本进行分布式限流 ? *** |[解决思路](/docs/redis-good.md) |
|
||||
|
||||
|
||||
#### [分布式系统发展历程(已更新)](/docs/fenbushi.md)
|
||||
|
|
|
@ -160,3 +160,13 @@
|
|||
**Redis(2.6以后)--lua分布式锁**
|
||||
|
||||
![整体流程](https://raw.githubusercontent.com/qiurunze123/imageall/master/lualock.png)
|
||||
|
||||
**如何利用lua + redis 取代 nigix + lua 脚本进行分布式限流**
|
||||
|
||||
分布式限流的关键就是把限流做成具有原子性的功能,可以使用redis + lua 来进行技术实现,高并发和高性能,实现时间窗口内的流量控制
|
||||
操作在lua脚本中又因为redis是单线程的,因此线程安全!Redis 将整个脚本作为一个原子执行, 无需担心并发, 也就无需事务;
|
||||
|
||||
![整体流程](https://raw.githubusercontent.com/qiurunze123/imageall/master/lualimit1.png)
|
||||
|
||||
lua脚本一致存在于redis 中可以 限制每秒钟的请求数实现限流!
|
||||
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
package com.geekq.miaosha.redis.redismanager;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import com.geekq.miaosha.redis.redismanager.RedisUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import redis.clients.jedis.Jedis;
|
||||
import redis.clients.jedis.JedisPool;
|
||||
import redis.clients.jedis.Transaction;
|
||||
|
||||
/**
|
||||
* redis乐观锁实例
|
||||
* @author linbingwen
|
||||
*
|
||||
*/
|
||||
public class OptimisticLockTest {
|
||||
public static void main(String[] args) throws InterruptedException {
|
||||
long starTime=System.currentTimeMillis();
|
||||
|
||||
initPrduct();
|
||||
initClient();
|
||||
printResult();
|
||||
|
||||
long endTime=System.currentTimeMillis();
|
||||
long Time=endTime-starTime;
|
||||
System.out.println("程序运行时间: "+Time+"ms");
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 输出结果
|
||||
*/
|
||||
public static void printResult() {
|
||||
Jedis jedis = RedisUtil.getInstance().getJedis();
|
||||
Set<String> set = jedis.smembers("clientList");
|
||||
|
||||
int i = 1;
|
||||
for (String value : set) {
|
||||
System.out.println("第" + i++ + "个抢到商品,"+value + " ");
|
||||
}
|
||||
|
||||
RedisUtil.returnResource(jedis);
|
||||
}
|
||||
|
||||
/*
|
||||
* 初始化顾客开始抢商品
|
||||
*/
|
||||
public static void initClient() {
|
||||
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
|
||||
int clientNum = 10000;// 模拟客户数目
|
||||
for (int i = 0; i < clientNum; i++) {
|
||||
cachedThreadPool.execute(new ClientThread(i));
|
||||
}
|
||||
cachedThreadPool.shutdown();
|
||||
|
||||
while(true){
|
||||
if(cachedThreadPool.isTerminated()){
|
||||
System.out.println("所有的线程都结束了!");
|
||||
break;
|
||||
}
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化商品个数
|
||||
*/
|
||||
public static void initPrduct() {
|
||||
int prdNum = 100;// 商品个数
|
||||
String key = "prdNum";
|
||||
String clientList = "clientList";// 抢购到商品的顾客列表
|
||||
Jedis jedis = RedisUtil.getInstance().getJedis();
|
||||
|
||||
if (jedis.exists(key)) {
|
||||
jedis.del(key);
|
||||
}
|
||||
|
||||
if (jedis.exists(clientList)) {
|
||||
jedis.del(clientList);
|
||||
}
|
||||
|
||||
jedis.set(key, String.valueOf(prdNum));// 初始化
|
||||
RedisUtil.returnResource(jedis);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 顾客线程
|
||||
*
|
||||
* @author linbingwen
|
||||
*
|
||||
*/
|
||||
class ClientThread implements Runnable {
|
||||
Jedis jedis = null;
|
||||
String key = "prdNum";// 商品主键
|
||||
String clientList = "clientList";//// 抢购到商品的顾客列表主键
|
||||
String clientName;
|
||||
|
||||
public ClientThread(int num) {
|
||||
clientName = "编号=" + num;
|
||||
}
|
||||
|
||||
|
||||
public void run() {
|
||||
try {
|
||||
Thread.sleep((int)(Math.random()*5000));// 随机睡眠一下
|
||||
} catch (InterruptedException e1) {
|
||||
}
|
||||
while (true) {
|
||||
System.out.println("顾客:" + clientName + "开始抢商品");
|
||||
jedis = RedisUtil.getInstance().getJedis();
|
||||
try {
|
||||
jedis.watch(key);
|
||||
int prdNum = Integer.parseInt(jedis.get(key));// 当前商品个数
|
||||
if (prdNum > 0) {
|
||||
Transaction transaction = jedis.multi();
|
||||
transaction.set(key, String.valueOf(prdNum - 1));
|
||||
List<Object> result = transaction.exec();
|
||||
if (result == null || result.isEmpty()) {
|
||||
System.out.println("悲剧了,顾客:" + clientName + "没有抢到商品");// 可能是watch-key被外部修改,或者是数据操作被驳回
|
||||
} else {
|
||||
jedis.sadd(clientList, clientName);// 抢到商品记录一下
|
||||
System.out.println("好高兴,顾客:" + clientName + "抢到商品");
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
System.out.println("悲剧了,库存为0,顾客:" + clientName + "没有抢到商品");
|
||||
break;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
jedis.unwatch();
|
||||
RedisUtil.returnResource(jedis);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
1876
src/main/java/com/geekq/miaosha/redis/redismanager/RedisUtil.java
Normal file
1876
src/main/java/com/geekq/miaosha/redis/redismanager/RedisUtil.java
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user