微服务实践:分布式锁
分布式锁
单体应用下,使用锁机制可以解决多线程同步问题。而在,集群环境下,单个服务有多个实例,每个实例都在自身JVM内做了同步,却不能保证整体服务的同步,这个服务依然是紊乱的。
分布式与集群
下图来自知乎作者(大闲人柴毛毛),
单机处理到达瓶颈的时候,你就把单机复制几份,这样就构成了一个“集群”。集群中每台服务器就叫做这个集群的一个“节点”,所有节点构成了一个集群。每个节点都提供相同的服务,那么这样系统的处理能力就相当于提升了好几倍(有几个节点就相当于提升了这么多倍)。
但问题是用户的请求究竟由哪个节点来处理呢?最好能够让此时此刻负载较小的节点来处理,这样使得每个节点的压力都比较平均。要实现这个功能,就需要在所有节点之前增加一个“调度者”的角色,用户的所有请求都先交给它,然后它根据当前所有节点的负载情况,决定将这个请求交给哪个节点处理。这个“调度者”有个牛逼了名字——负载均衡服务器。
分布式结构就是将一个完整的系统,按照业务功能,拆分成一个个独立的子系统,在分布式结构中,每个子系统就被称为“服务”。这些子系统能够独立运行在web容器中,它们之间通过RPC方式通信。
可重入锁
举例说明可重入锁:
public class UnReentrant{ Lock lock = new Lock(); public void outer(){ lock.lock(); inner(); lock.unlock(); } public void inner(){ lock.lock(); //do something lock.unlock(); }}
outer中调用了inner,outer先锁住了lock,这样inner就不能再获取lock。其实调用outer的线程已经获取了lock锁,但是不能在inner中重复利用已经获取的锁资源,这种锁即称之为 不可重入 。通常也称为 自旋锁 。相对来说,可重入就意味着:在同一线程中,外层函数获取了锁之后,内层函数依然可以获得相同的锁。
重入意味着获取锁的操作的粒度是“线程”,而不是“调用”。
重入的一种实现方式是为每个锁关联一个计数值和一个所有者线程。当技术器为0时,这个锁就被认为是没有被任何线程所持有的。当现场请求一个未被持有的锁时,JVM就会记下锁的持有者,并且将获取计数值置为1。如果同一个线程再次获得这个锁,计数值将递增,而当线程退出同步代码块时,技术器会相应的递减。当计数值为0时,这个锁将被释放。
基于数据库方式
基于Redis缓存