【分布式】02-分布式锁原理和选型

本文探讨了分布式锁的基本条件,包括存储空间、唯一标识和两种状态,并分析了基于数据库实现分布式锁可能存在的问题,如加锁非原子操作和锁的释放。文章还列举了四种典型实现:MySQL、ZK、Redis和etcd,分析了它们的优缺点以及适用场景,强调了分布式锁在高并发和数据一致性方面的考量。
摘要由CSDN通过智能技术生成

在讨论分布式锁原理的时候,我们带着如下思考进入今天的主题:

  • 根据业务场景如何选择分布式锁模型:CP还是AP?
  • 读锁、加锁是否是原子操作?
  • 锁能否正常释放,避免死锁(如添加过期时间)
  • 保证分布式锁高可用:如何保证锁资源不丢失(保存锁的机器可能宕机)

锁的本质就是对共享资源的串行化处理。在单进程环境中,Java JDK提供了两种互斥锁实现:Lock和Synchronized。这两种锁对共享资源的操作前后加解锁,保证不同线程可以互斥有序的操作共享资源。

在分布式环境下,由于不同主机之间无法直接访问共享资源,所以就需要我们自己来实现分布式锁,保证不同JVM、不同主机之间不会出现资源抢占。

一、分布式锁基本条件

实现分布式锁有以下基本条件:

  • 存储空间:锁的实现需要有一个可以存储锁的空间。在多线程中可以使用内存保存锁;多进程中可以用共享的内存或者磁盘中的文件当做锁;分布式环境中,不同主机无法访问对方的内存或磁盘文件,所以要使用外部存储空间来存储锁。常见的有数据库、缓存如Redis、MongoDB、ZK等;
  • 唯一标识:分布式环境中要保证锁的名称是全局唯一的;
  • 两种状态:锁需要有两种不同的状态,如加锁、解锁;存在、不存在等;

最简单的实现可以用数据库实现一个简单的分布式锁:

建表:

CREATE TABLE `tb_lock` (
	`id` BIGINT NOT NULL AUTO_INCREMENT,
	`resource` bigint(64) NOT NULL COMMENT '锁定的资源',
  `status` tinyint(2) NOT NULL DEFAULT '0' COMMENT '锁资源状态:(0:解锁,1:加锁)',
	`desc` varchar(120) NOT NULL DEFAULT "" COMMENT '描述',
	`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  `update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
	PRIMARY KEY (`id`),
	UNIQUE KEY `uk_idx_resource` (`resource`) 
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='数据库分布式锁表';

伪代码:

// 1、读锁 (resourceId对应数据库resource字段,可以为用户编号、订单编号等其他场景)
lock = mysql.getByResourceId(resourceId);
// 2、判断锁状态(lock.status = 1是否为加锁状态 ,是表示锁被占用, sleep后再尝试)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值