开发者社区> 牧小农> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

掌握Redis分布式锁的正确姿势

简介: 掌握Redis分布式锁的正确姿势
+关注继续查看

本文中案例都会在上传到git上,请放心浏览

git地址:https://github.com/muxiaonong/Spring-Cloud/tree/master/order-lock

本文会使用到 三台 redis 独立服务器,可以自行提前搭建好


前言


在Java中,我们对于锁会比较熟悉,常用的有 synchronized、Lock锁,在java并发编程中,我们通过锁,来实现当多个线程竞争同一个共享资源或者变量而造成的数据不一致的问题,但是JVM锁只能针对于单个应用服务,随着我们业务的发展需要,单体单机部署的系统早已演化成分布式系统,由于分布式系统的多线程、多进程而且分布在不同的机器上,这个时候JVM锁的并发控制就没有效果了,为了解决跨JVM锁并且能够控制共享资源的访问,于是有了分布式锁的诞生。


屏幕快照 2022-05-11 上午10.41.43.png

什么是分布式锁

分布式锁是控制分布式系统之间同步访问共享资源的一种方式。在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁


为什么JVM锁在分布式下不可以呢?


我们通过代码来看一下就知道,为什么集群下jvm锁是不可靠的呢?我们模拟一下商品抢购的场景,A服务有十个用户去抢购这个商品,B服务有十个用户去抢购这个商品,当有其中一个用户抢购成功后,其他用户不可以在对这个商品进行下单操作,那么到底是A服务会抢到还是B服务会抢到这个商品呢,我们来看一下


当其中有一个用户抢购成功后,status会变成1

image.png


GrabService:


public interface GrabService {
    /**
     * 商品抢单
     * @param orderId
     * @param driverId
     * @return
     */
    public ResponseResult grabOrder(int orderId, int driverId);
}


GrabJvmLockServiceImpl:

@Service("grabJvmLockService")
public class GrabJvmLockServiceImpl implements GrabService {
    
    @Autowired
    OrderService orderService;
    
    @Override
    public ResponseResult grabOrder(int orderId, int driverId) {
        String lock = (orderId+"");
        
        synchronized (lock.intern()) {
            try {
                System.out.println("用户:"+driverId+" 执行下单逻辑");
                
                boolean b = orderService.grab(orderId, driverId);
                if(b) {
                    System.out.println("用户:"+driverId+" 下单成功");
                }else {
                    System.out.println("用户:"+driverId+" 下单失败");
                }
            } finally {
                
            }
        }
        return null;
    }
}

OrderService :

public interface OrderService {
    
    public boolean grab(int orderId, int driverId);
    
}

OrderServiceImpl :

@Service
public class OrderServiceImpl implements OrderService {
    
    @Autowired
    private OrderMapper mapper;
    
    public boolean grab(int orderId, int driverId) {
        Order order = mapper.selectByPrimaryKey(orderId);
         try {
             Thread.sleep(1000);
         } catch (InterruptedException e) {
             e.printStackTrace();
         }
        if(order.getStatus().intValue() == 0) {
            order.setStatus(1);
            mapper.updateByPrimaryKeySelective(order);
            
            return true;
        }
        return false;
        
    }
}

这里我们模拟集群环境,启动两个端口,8004和8005进行访问

这里我们用jmeter进行测试

如果不会jmeter的可以看我之前对tomcat进行压测的文章:tomcat优化


项目启动顺序:先启动 Server-eureka注册中心、在启动 8004和8005端口

image.png


测试结果:

image.png

这里我们可以看到 8004 服务和 8005 服务 同时都有一个用户去下单成功这个商品,但是这个商品只能有一个用户能够去抢到,因此jvm锁如果是在集群或分布式下,是无法保证访问共享变量的数据同时只有一个线程访问的,无法解决分布式,集群环境的问题。所以需要使用到分布锁。


分布式锁三种实现方式


分布式锁的实现方式总共有三种:


基于数据库实现分布式锁

基于缓存(Redis)实现分布式锁

基于Zookeeper实现分布式锁


版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
Redis 分布式锁(上)
本文主要是讲述分布式锁的实现和代码解析。
26 0
Redis 分布式锁(中)
问题:你知道 redis 分布式锁吗?有哪些实现方案?你谈谈对 redis 分布式锁的理解, 删除key 的时候有什么问题?
23 0
Redis分布式锁抽丝剥茧
本文从基础的线程安全、线程同步,认识到分布式锁是跨主机的资源线程/进程同步方案, 以步步为营的风格 演示了RedisSET命令做分布式锁的设计考量,好记性不如烂笔头。
23 0
别再纠结Redis/zookeeper,告诉你分布式锁的正确解决方案(下)
别再纠结Redis/zookeeper,告诉你分布式锁的正确解决方案(下)
29 0
redis系列:分布式锁
1 介绍 这篇博文讲介绍如何一步步构建一个基于Redis的分布式锁。会从最原始的版本开始,然后根据问题进行调整,最后完成一个较为合理的分布式锁。 本篇文章会将分布式锁的实现分为两部分,一个是单机环境,另一个是集群环境下的Redis锁实现。
2620 0
redis系列:分布式锁
1 介绍 这篇博文讲介绍如何一步步构建一个基于Redis的分布式锁。会从最原始的版本开始,然后根据问题进行调整,最后完成一个较为合理的分布式锁。 本篇文章会将分布式锁的实现分为两部分,一个是单机环境,另一个是集群环境下的Redis锁实现。
1007 0
探索Redis设计与实现15:Redis分布式锁进化史
Redis分布式锁进化史 近两年来微服务变得越来越热门,越来越多的应用部署在分布式环境中,在分布式环境中,数据一致性是一直以来需要关注并且去解决的问题,分布式锁也就成为了一种广泛使用的技术,常用的分布式实现方式为Redis,Zookeeper,其中基于Redis的分布式锁的使用更加广泛。
1964 0
+关注
牧小农
业精于勤荒于嬉,行成于思毁于随。
134
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载