Java深入学习28:Redisson分布式锁的使用

情况1- 常规情况,没有任何同步锁,使用Jmeter模拟多线程

  问题:结果发现numTest会出现重复读写的情况(numTest = 6)

@RestController
public class RedissonController {
    static int numTest = 0;
    @GetMapping("/test")
    public String test(){
        System.out.println("num: " + ++numTest);
        return "success"+ Math.random()*100;
    }
}

numTest: 2
numTest: 3
numTest: 1
numTest: 4
numTest: 5
numTest: 6
numTest: 7
numTest: 6
numTest: 8
numTest: 9
numTest: 10

 

情况2- 我们使用Lock锁

  解决的问题:单服务的情况下,解决了数据重复读写的问题

  新的问题:很明显,如果是分布式服务,Lock锁是内存锁(synchronized也是),还是会出现重复读物数据的情况

@RestController
public class RedissonController {
    static int numLock = 0;

    @GetMapping("/lock")
    public String lock(){
        Lock lock = new ReentrantLock();
        lock.lock();
        try {
            System.out.println("numLock: " + ++numLock);
        } finally {
            lock.unlock();
        }

        return "success"+ Math.random()*100;
    }

}
numLock: 1
numLock: 2
numLock: 3
numLock: 4
numLock: 5
numLock: 6
numLock: 7
numLock: 9
numLock: 10
numLock: 11
numLock: 12
numLock: 8

 

情况3- 使用redisson分布式锁解决分布式下高并发下,数据重复读取

  模拟的先决条件

    1- 使用Redis保存公有数据(数据库也行);    

    2- 使用Ngnix负载均衡搭建分布式服务(见附录)

    3- 使用Jmeter模拟并发请求(见附录)

3-1- 当没有使用redisson锁时,结果如下,数据大量的重复读取

@RestController
public class RedissonController {
    @Autowired
    private RedisTemplate redisTemplate;

  //直接从redis读写数据 @GetMapping(
"/redisson") public String redisson(){ int num = (int)redisTemplate.opsForValue().get(key); System.out.println("numRedisson: " + ++num); redisTemplate.opsForValue().set(key,num); return "success"+ Math.random()*100; } }

 

 

 3-2- 当使用redisson锁时,结果如下,分布式下两台服务器,数据读写正常不会重复

@RestController
public class RedissonController {
    @Autowired
    private RedissonClient client;
    @Autowired
    private RedisTemplate redisTemplate;

  //使用redisson分布式锁从redis读写数据
    @GetMapping("/redisson/lock")
    public String redissonLockTest(){
        RLock testLock = client.getLock("testLock");
        testLock.lock();
        try {
            if(redisTemplate.hasKey(key)){
                int num = (int)redisTemplate.opsForValue().get(key);
                System.out.println("numRedissonLock: " + ++num);
                redisTemplate.opsForValue().set(key,num);
            }

        }finally {
            testLock.unlock();
        }
        return "success"+ Math.random()*100;
    }

}

 

附录 -使用Ngnix负载均衡搭建分布式服务 

1-下载并安装Nginx,参考博客,只要下载安装包,正常启动就好。  

  启动Ngnix指令:在安装目录下:nginx.exe

  关闭Ngnix指令:在安装目录下:taskkill /f /t /im nginx.exe

2- Ngnix负载均衡配置

    upstream upstream_name{
        server 127.0.0.1:8001 weight=1;#第一台服务器
        server 127.0.0.1:8002 weight=1;#第二台服务器
    }


    server {
        listen       80;
        server_name  localhost;
        location / {
            #这个至关重要,表示代理的时候设置主机名(IP)和端口,不设置会无法转发请求,这里其实就是代理Nginx本机IP以及监听端口
            proxy_set_header Host $host:8080;
            #这个是获取到请求客户端的真实IP而不是Nginx代理机器的IP
            proxy_set_header X-Real-IP $remote_addr;
            #这个是转发
            proxy_set_header X-Forwarded-For $Proxy_add_x_forwarded_for;
            #这个名字可以随便取,只要能匹配到upstream的名字即可
            proxy_pass http://upstream_name;
        }
    }

 

 附录-使用Jmeter模拟并发请求

  1-Jmeter的使用参考博客

  2-模拟部分截图

 

 

END

posted on 2020-05-06 10:51  我不吃番茄  阅读(1107)  评论(0编辑  收藏  举报