最近学习尚硅谷的分布锁。
业务背景
虚拟机部署nginx和Redis,Windows运行7777和8888两个服务,通过nginx进行轮询卖1000张票。使用了分布锁,抢不到锁的线程休眠20毫秒后,继续抢。
问题
本地jmeter设置1秒1000个请求,总是卖不完票,报错问题下面贴出来。如果是1秒500个请求,卖500张票,就可以完全卖完。
是因为并发太高了?还是我的nginx设置不对吗?或者是因为休眠20毫秒?
//////////分割线//////////
虚拟机配置
虚拟机的配置是内存1G,处理器2个,NAT
nginx配置

业务代码
// V6.0,使用lua脚本来解锁。但是V6.0版本不满足可重入性,需要改为V7.0版本
public String sale() {
String retMessage = "";
String key = "zzyyRedisLock";
String uuidValue = IdUtil.simpleUUID() + ":" + Thread.currentThread().getId();
// 不用递归了,高并发下容易出错,我们用自旋替代递归方法重试调用;也不用if了,用while来替代
while (!stringRedisTemplate.opsForValue().setIfAbsent(key, uuidValue, 30L, TimeUnit.SECONDS)) {
// 暂停20毫秒
try { TimeUnit.MILLISECONDS.sleep(20L); } catch (InterruptedException e) { e.printStackTrace(); }
}
// 抢锁成功的线程,进行正常的业务逻辑操作,扣减库存
try {
//1 查询库存信息
String result = stringRedisTemplate.opsForValue().get("inventory001");
//2 判断库存是否足够
Integer inventoryNumber = result == null ? 0 : Integer.parseInt(result);
//3 扣减库存
if (inventoryNumber > 0) {
stringRedisTemplate.opsForValue().set("inventory001", String.valueOf(--inventoryNumber));
retMessage = "成功卖出一个商品,库存剩余: " + inventoryNumber + "\t" + "服务端口号:" + port;
System.out.println(retMessage);
} else {
retMessage = "商品卖完了,o(╥﹏╥)o";
}
} finally {
// 改进点,将判断+删除自己的合并为lua脚本保证原子性
String luaScript =
"if (redis.call('get',KEYS[1]) == ARGV[1]) then " +
"return redis.call('del',KEYS[1]) " +
"else " +
"return 0 " +
"end";
stringRedisTemplate.execute(new DefaultRedisScript<>(luaScript, Boolean.class), Arrays.asList(key), uuidValue);
}
return retMessage + "\t" + "服务端口号" + port;
}
jmeter显示的错误
jmeter的结果中有3种错误
图1:

图2:

图3:

nginx的error.log
我查看nginx的error.log,有出现过socket() failed (24: Too many open files) while connecting to upstream