一句话说清分布式锁,进程锁,线程锁

本文涉及的产品
云数据库 Redis 版,社区版 2GB
推荐场景:
搭建游戏排行榜
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: 在分布式集群系统的开发中,线程锁往往并不能支持全部场景的使用,必须引入新的技术方案分布式锁。线程锁,进程锁,分布式锁线程锁:大家都不陌生,主要用来给方法、代码块加锁。当某个方法或者代码块使用锁时,那么在同一时刻至多仅有有一个线程在执行该段代码。

在分布式集群系统的开发中,线程锁往往并不能支持全部场景的使用,必须引入新的技术方案分布式锁。

线程锁,进程锁,分布式锁

线程锁:大家都不陌生,主要用来给方法、代码块加锁。当某个方法或者代码块使用锁时,那么在同一时刻至多仅有有一个线程在执行该段代码。当有多个线程访问同一对象的加锁方法/代码块时,同一时间只有一个线程在执行,其余线程必须要等待当前线程执行完之后才能执行该代码段。但是,其余线程是可以访问该对象中的非加锁代码块的。

进程锁:也是为了控制同一操作系统中多个进程访问一个共享资源,只是因为程序的独立性,各个进程是无法控制其他进程对资源的访问的,但是可以使用本地系统的信号量控制(操作系统基本知识)。

分布式锁:当多个进程不在同一个系统之中时,使用分布式锁控制多个进程对资源的访问。

分布式锁到底是什么,怎么实现?

intsmaze说简单点,实现分布式锁必须要依靠第三方存储介质来存储锁的元数据等信息比如分布式集群要操作某一行数据时,这个数据的流水号是唯一的,那么我们就把这个流水号作为一把锁的id,当某进程要操作该数据时,先去第三方存储介质中看该锁id是否存在,如果不存在,则将该锁id写入,然后执对该数据的操作;当其他进程要访问这个数据时,会先到第三方存储介质中查看有没有这个数据的锁id,有的话就认为这行数据目前已经有其他进程在使用了,就会不断地轮询第三方存储介质看其他进程是否释放掉该锁;当进程操作完该数据后,该进程就到第三方存储介质中把该锁id删除掉,这样其他轮询的进程就能得到对该锁的控制。

Redis中当然不能通过get,set操作判断,get,set操作不是一个原子的,可以使用redis的jedis.set(String key, String value, String nxxx, String expx, int time)命令来保证原子性。

具体实现方案:
https://www.cnblogs.com/linjiqin/p/8003838.html

说了这么多,再补充一点,线程锁,进程锁,分布式锁的作用都是一样的,只是作用的范围大小不同范围大小:分布式锁——大于——进程锁——大于——线程锁。能用线程锁,进程锁情况下使用分布式锁也是可以的,能用线程锁的情况下使用进程锁也是可以的。只是范围越大技术复杂度就越大。

多年j2EE开发生涯从未感觉到分布式锁的痛点!!!

关于分布式锁,有过javaEE开发经验的就会说了,系统为了应对高并发,会搭建一个比如tomcat集群,集群内服务都是访问的同一台数据库,有多台服务器同时修改同一条数据库数据的操作,但是我们并没有在服务器中使用分布式锁?按照上面对分布式锁的解释,两个不同系统上的JVM进程同时访问数据库的同一个资源,这个时候我们应该使用分布式锁进行控制。

这说的没有错,但是我们忘记了数据库的特性了。如果两台服务器仅仅是直接访问(通过url)并操作某台服务器硬盘中某个文件同一行数据,这个时候我们必须用分布式锁。

但是因为这两台服务器访问的数据是存储在数据库中的(数据库本身就是一个服务程序,多线程的接收外部系统发来的请求),两台服务器的请求通过网络IO发送到数据库服务器后,然后把请求交给数据库服务的进程处理,数据库服务器是多线程接收请求并处理的,这个时候关于某表某一行数据的多线程访问控制是由数据库服务进行控制的(就是数据库服务的代码中进行了线程上的加锁处理),这就是数据库服务器的行锁等特性,因为数据库那一端已经对外部多个系统的请求进行了一个锁操作,所以不需要我们在应用服务端进行分布式锁的开发。 

那如果想同时更新数据库的多行数据,这个时候数据库的行锁就无法保证了。这个时候我们就要使用分布式锁,是的这个时候就可以使用,注意我用的是可以。为什么说可以呢?因为数据库本身就提供了这个机制,事务以及他的隔离级别。当然你也可以不用数据库提供的事务,用分布式锁。

分布式锁的设计不需要考虑业务吗?

分布式锁的设计并不是完全美好的,只能针对某些业务场景下使用,如果要对所有业务使用,必须充分理解业务需求合理的设计,至于原因就和各位j2ee开发时mybatis的二级缓存以命名空间为单位所要注意的业务问题时一样的。  

intsmaze使用分布式锁,我们会把某表的第二第三行作为id来锁住,如果有相同的操作时更新该表第二第三行,我们才不让他修改,必须让他拿到锁才可以。但是如果有个操作仅仅是修改第二行,这个时候他就获得了对该行的操作,而且等数据库释放掉之前操作对该行的锁后。所以分布式锁并不是随处可用的,只是在某些场景下可以使用。比如业务系统不会存在单独修改第二行的操作。

分布式锁用于hbase存储系统

实际开发场景中,我们会对hbase操作进行分布式锁,hbase作为一款优秀的非内存数据库,传统数据库一样提供了事务的概念,只是HBase的事务是行级事务,可以保证行级数据的原子性、一致性、隔离性以及持久性,即通常所说的ACID特为了实现事务特性,HBase采用了各种并发控制策略,包括各种锁机制、MVCC机制等。因为hbase只支持行级事物,当业务需要并发操作两行甚至多行记录时,hbase本身就无法提供ACID的支持了。

数据库访问量过大除了主从还能如何负载压力?

数据库会为客户端的每一个请求创建一个线程,这些线程针对特定行数据修改必须获得该行的行锁,而其他客户端线程要想修改该数据的话,必须等待前面的线程释放锁后才被允许。如果客户端很多线程都要修改某行数据的话,没有拿到锁的线程都会在数据库端机器上不断轮询,增大数据库端的压力。

我们可以使用分布式锁,把对数据库行锁的等待获取的轮询放到每一个客户端机器上去实现,这样可以避免数据库端线程的不断轮询。比如,客户端在要发送对数据库的某行数据的操作请求前,在客户端机器上进行锁的争抢,没有获取到锁,就不会像数据库端发送操作请求,这样数据库端就没有了轮询的压力。当然分布式锁的引入一定要结合业务的需求来进行设计,不然会出现锁id的命名不全导致读取的数据不一致,数据过期失效等问题。

使用那种第三方介质存放分布式锁?

目前流行的是zookeeper和redis,两者各有好处,redis流行的内存缓存,且能进行水平扩容同时还能提高请求负载,面对高并分布式锁数据的读写请求能高速响应,同时有aof,哨兵机制可以防止某台宕机分布式锁数据丢失带来的问题。

zookeeper我是比较喜欢,因为他是分布式一致性算法paxos算法的实现,面对高负载请求毫无压力,同时某一台宕机毫不影响分布式锁数据一致性,且附带了监听机制,当某一程序释放某一个锁后,其他程序可以及时得到通知来获得对该分布式锁的控制权,这里的轮询实现不需要我们去开发了。

关于分布式锁与线程锁的介绍从一年前就在编辑中,一直没有时间以一种通俗明了的方式介绍给大家。本人在很多论坛中发现很多刚入大数据领域的新人都会提到分布式锁,但是并没有深刻明白分布式锁和线程锁的场景,以至于很多情况下明明线程锁就可以搞定的却引入了分布式锁,让整个系统设计的更加复杂了。

另外要说的,zookeeper笔者认为是很棒的技术,虽然在大数据领域只是作为某一个框架的一个协调者出现,导致很多开发者忽视了他的伟大性。但是我想说的,在当前火热的微服务中,其实会借助zookeeper实现很多功能,比如分布式锁,配置中心。

相关实践学习
云数据库HBase版使用教程
  相关的阿里云产品:云数据库 HBase 版 面向大数据领域的一站式NoSQL服务,100%兼容开源HBase并深度扩展,支持海量数据下的实时存储、高并发吞吐、轻SQL分析、全文检索、时序时空查询等能力,是风控、推荐、广告、物联网、车联网、Feeds流、数据大屏等场景首选数据库,是为淘宝、支付宝、菜鸟等众多阿里核心业务提供关键支撑的数据库。 了解产品详情: https://cn.aliyun.com/product/hbase   ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库 ECS 实例和一台目标数据库 RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
8天前
|
安全 Java 数据处理
Python网络编程基础(Socket编程)多线程/多进程服务器编程
【4月更文挑战第11天】在网络编程中,随着客户端数量的增加,服务器的处理能力成为了一个重要的考量因素。为了处理多个客户端的并发请求,我们通常需要采用多线程或多进程的方式。在本章中,我们将探讨多线程/多进程服务器编程的概念,并通过一个多线程服务器的示例来演示其实现。
|
24天前
|
消息中间件 安全 Linux
线程同步与IPC:单进程多线程环境下的选择与权衡
线程同步与IPC:单进程多线程环境下的选择与权衡
57 0
|
25天前
|
消息中间件 存储 算法
【软件设计师备考 专题 】操作系统的内核(中断控制)、进程、线程概念
【软件设计师备考 专题 】操作系统的内核(中断控制)、进程、线程概念
68 0
|
1月前
|
安全 编译器 C#
C#学习相关系列之多线程---lock线程锁的用法
C#学习相关系列之多线程---lock线程锁的用法
|
26天前
|
安全 Python
Python中的并发编程:多线程与多进程技术探究
本文将深入探讨Python中的并发编程技术,重点介绍多线程和多进程两种并发处理方式的原理、应用场景及优缺点,并结合实例分析如何在Python中实现并发编程,以提高程序的性能和效率。
|
25天前
|
消息中间件 Linux 调度
【Linux 进程/线程状态 】深入理解Linux C++中的进程/线程状态:阻塞,休眠,僵死
【Linux 进程/线程状态 】深入理解Linux C++中的进程/线程状态:阻塞,休眠,僵死
65 0
|
1月前
|
资源调度 算法 Linux
Linux进程/线程的调度机制介绍:详细解析Linux系统中进程/线程的调度优先级规则
Linux进程/线程的调度机制介绍:详细解析Linux系统中进程/线程的调度优先级规则
51 0
|
1天前
|
安全 Java 调度
Java并发编程:深入理解线程与锁
【4月更文挑战第18天】本文探讨了Java中的线程和锁机制,包括线程的创建(通过Thread类、Runnable接口或Callable/Future)及其生命周期。Java提供多种锁机制,如`synchronized`关键字、ReentrantLock和ReadWriteLock,以确保并发访问共享资源的安全。此外,文章还介绍了高级并发工具,如Semaphore(控制并发线程数)、CountDownLatch(线程间等待)和CyclicBarrier(同步多个线程)。掌握这些知识对于编写高效、正确的并发程序至关重要。
|
2天前
|
调度 Python
Python多线程、多进程与协程面试题解析
【4月更文挑战第14天】Python并发编程涉及多线程、多进程和协程。面试中,对这些概念的理解和应用是评估候选人的重要标准。本文介绍了它们的基础知识、常见问题和应对策略。多线程在同一进程中并发执行,多进程通过进程间通信实现并发,协程则使用`asyncio`进行轻量级线程控制。面试常遇到的问题包括并发并行混淆、GIL影响多线程性能、进程间通信不当和协程异步IO理解不清。要掌握并发模型,需明确其适用场景,理解GIL、进程间通信和协程调度机制。
17 0
|
5天前
|
Java 程序员 编译器
Java中的线程同步与锁优化策略
【4月更文挑战第14天】在多线程编程中,线程同步是确保数据一致性和程序正确性的关键。Java提供了多种机制来实现线程同步,其中最常用的是synchronized关键字和Lock接口。本文将深入探讨Java中的线程同步问题,并分析如何通过锁优化策略提高程序性能。我们将首先介绍线程同步的基本概念,然后详细讨论synchronized和Lock的使用及优缺点,最后探讨一些锁优化技巧,如锁粗化、锁消除和读写锁等。

热门文章

最新文章

相关实验场景

更多