浅谈分布式锁的几种使用方式(redis、zookeeper、数据库)
Q:一个业务服务器,一个数据库,操作:查询用户当前余额,扣除当前余额的3%作为手续费 synchronized lock dblock Q:两个业务服务器,一个数据库,操作:查询用户当前余额,扣除当前余额的3%作为手续费 分布式锁 我们需要怎么样的分布式锁? 可以保证在分布式部署的应用集群中,同一个方法在同一时间只能被一台机器上的一个线程执行。 这把锁要是一把可重入锁(避免死锁) 这把锁最好是一把阻塞锁(根据业务需求考虑要不要这条) 这把锁最好是一把公平锁(根据业务需求考虑要不要这条) 有高可用的获取锁和释放锁功能 获取锁和释放锁的性能要好 一、基于数据 分布式锁是解决多服务节点间共享资源访问控制的关键技术,主要应用于分布式系统中,确保同一时间只有一个客户端能够执行特定操作。在上述场景中,当业务从单服务器扩展到多服务器时,为了保证并发操作的正确性,需要引入分布式锁。 分布式锁应具备以下特性: 1. 可重入性:允许同一个线程多次获取锁,防止死锁。 2. 阻塞或非阻塞:根据业务需求选择,阻塞锁会一直等待直到获取锁,而非阻塞锁则在无法获取锁时立即返回。 3. 公平性:按照请求顺序分配锁,避免饥饿现象。 4. 高可用性:即使在部分节点故障时,锁服务仍能正常工作。 5. 锁的自动释放:确保在一定时间内未释放锁的情况下,系统能自动解锁,防止锁永久持有。 6. 性能:获取和释放锁的操作需要高效。 基于数据库实现的分布式锁: 1. 基于表实现:通过创建一个特殊表(如`methodLock`),使用`method_name`作为唯一键,当需要锁时尝试插入记录,成功插入即表示获取锁,执行完后删除记录释放锁。这种方法简单但存在几个问题: - 单点故障:依赖数据库,一旦数据库出现问题,锁服务也会受影响。 - 无失效时间:可能导致死锁。 - 非阻塞:插入失败会直接报错。 - 非重入:需要额外处理同一线程再次获取锁的情况。 - 非公平:线程获取锁的机会不均等。 - 解决方案:双库同步、定时清理超时锁、使用while循环重试、记录获取锁的线程信息、创建等待队列。 2. 基于排他锁实现:利用数据库的行级锁,如MySQL的InnoDB引擎的`SELECT ... FOR UPDATE`,查询时锁定对应记录,其他请求在释放锁之前无法操作。这种方法相对复杂,但能更好地控制锁的粒度。 除此之外,还有其他实现方式: 1. Redis分布式锁:Redis提供`SETNX`命令或`SET key value EX seconds NX`命令来原子地设置键并设置过期时间,实现分布式锁。Redis还支持`WATCH`命令用于观察键的变化,实现乐观锁。Redis的性能优秀,适合高并发场景,但同样需要处理锁的自动释放和续期问题。 2. ZooKeeper分布式锁:ZooKeeper是一个分布式协调服务,可以用来实现分布式锁。通过创建临时节点并监听节点变更,实现锁的获取和释放。ZooKeeper具有强一致性,适合需要高可用和一致性的场景。 选择哪种分布式锁实现方式取决于具体业务需求和系统环境。例如,对于对响应时间和性能敏感的系统,Redis可能是更好的选择;而对于更注重数据一致性和高可用性的系统,ZooKeeper可能更适合。无论选择哪种方式,都需要充分理解其工作原理和潜在问题,以确保在分布式环境下正确实现并发控制。
剩余6页未读,继续阅读
- 粉丝: 8
- 资源: 956
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助