lua+redsi

pull/38/head
qiurunze 2019-02-21 18:42:32 +08:00
parent c4fdecf1e9
commit 92f77fd8e4
4 changed files with 2035 additions and 0 deletions

View File

@ -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)

View File

@ -160,3 +160,13 @@
**Redis2.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 中可以 限制每秒钟的请求数实现限流!

View File

@ -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);
}
}
}
}

File diff suppressed because it is too large Load Diff