准备条件 作者只有一台电脑 通过nginx负载均衡进行测试
upstream backend {
server 127.0.0.1:8011 weight=1;
server 127.0.0.1:8012 weight=1;
}
server {
listen 8099;
server_name localhost;
#charset koi8-r;
#access_log logs/host.access.log main;
# 代理所有请求到上游服务器组
location / {
proxy_pass http://backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}创建一个Sprinngboot 测试demo 通过Jemter进行压测
package com.example.demo.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.Duration;
import java.util.Collections;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@RestController
@RequestMapping("/tickets")
@Slf4j
public class TicketController {
@Autowired
private RedisTemplate<String, Object> redisTemplate;
@RequestMapping("/")
public String getTickets() {
String randomId = UUID.randomUUID().toString();
String ticketKey = "apple";
String lockKey = ticketKey + ":lock"; // 使用单独的锁key
log.info("开始抢购商品:{}", ticketKey);
try {
Boolean getLock = redisTemplate.opsForValue().setIfAbsent(lockKey, randomId, Duration.ofSeconds(1));
if (!getLock) {
log.info("获取锁失败:{}", ticketKey);
return "系统繁忙,请重试";
}
Integer ticketStore = (Integer) redisTemplate.opsForValue().get(ticketKey);
if (ticketStore == null) {
log.info("抢购失败:{},库存不存在", ticketKey);
return "抢购失败";
}
if (ticketStore <= 0) {
log.info("抢购失败:{},库存不足", ticketKey);
return "抢购失败";
}
int remaining = ticketStore - 1;
log.info("抢购成功:{},剩余库存数:{}", ticketKey, remaining);
redisTemplate.opsForValue().set(ticketKey, remaining);
return "抢购成功";
} finally {
String luaScript =
"if redis.call('get', KEYS[1]) == ARGV[1] then " +
"return redis.call('del', KEYS[1]) " +
"else " +
"return 0 " +
"end";
redisTemplate.execute(new DefaultRedisScript<>(luaScript, Long.class),
Collections.singletonList(lockKey),
randomId);
}
}
}
简单测试 能实现相关的分布式锁 但是仍存在许多问题 如:无法进行 锁过期但是线程挂了 锁续期 可重入锁 redis如果挂了 怎么处理