分布式场景下的一些思考

最近在研究Redission在分布式场景下的一些应用,系统的梳理了一下分布式场景下的一些知识点;

一、多线程

在分布式场景下,离不开不同服务器不同进程之间的通信;进程之间通信交换数据要么通过在堆内存共享数据方式,要么通过消息通知的方式;说到进程,在多核CPU处理器,实际上是通过多线程轮流切换,竞争CPU资源的方式来工作。这种通过分配时间片的方式,协调多线程处理。回溯到线程的生命周期,线程生命周期有6种状态:
这里写图片描述
这里写图片描述

在阻塞状态,有看到一个synchronized关键字,这个想必大家都清楚,这是为了能够在多线程环境下让同一时刻只有一个线程共享资源的一种悲观加锁方式,讲到这里,必须梳理一下多线程环境下锁的一些知识

Java中的锁

锁是用来控制多个线程访问共享资源的方式,一般来说,一个锁能防止多个线程同时访问共享资源,当然也有些锁可以允许多个线程并发访问共享资源,比如读写锁。在Java中,一般常用的是Lock接口锁,相比java5之前的synchronized关键字只能隐式的获取和释放锁,Lock更加灵活,它提供的synchronized关键字不具备的特性如下:
这里写图片描述
后面我们会谈到实现Lock接口的具体锁,比如重入锁、分布式锁、读写锁等,其实这些锁都离不开一个基础组件同步器AbstractQueuedSynchronizer,下面先聊一下AQS的一些原理:
AQS提供模板的方式,继承者只需要实现同步状态的管理就可以了,AQS大致分为3类,独占式的获取和释放锁、共享式的获取和释放锁和查询同步队列中的等待线程情况。同步器对于状态的修饰是volatile,根据JMM内存模型的happen-before原则,写happen-before读,保证线程的安全

重入锁

ReentrantLock,支持重进入的锁,表示该锁支持一个线程对资源的重复加锁,重进入是指任意线程在获取到锁之后能够再次获取到该锁而不会被锁阻塞

该特性实际上解决2个问题:(1) 线程再次获取锁:通过判断当前线程是否为获取锁的线程来
决定获取操作是否成功,如果是获取锁的线程再次请求,则将同步状态值进行增加并返回
true (2) 锁的最终释放:如果该锁被获取了n次,那么前(n-1)次tryRelease(int releases)方法必须返回false,而只有同步状态完全释放了,才能返回true

重入锁存在获取锁的公平和非公平性,对于非公平锁,只要CAS设置同步状态成功,就表示当前线程获取了锁,而公平锁不同,增加了同步队列当前节点是否有前驱节点的判断;公平性锁保证了锁的获取按照FIFO原则,而代价是进行大量的线程切换。非公平性锁虽然可能造成线程“饥饿”,但极少的线程切换,保证了其更大的吞吐量

读写锁

读写锁和其他排他锁不同,它允许同一时刻多个读线程访问,但是在写线程访问时,所有的读线程和其他线程均被阻塞。读写锁维护了一对锁,一个读锁一个写锁,通过分离读锁和写锁,使得并发性比一般的排他锁性能要高;Java并发包提供读写锁的实现是ReentrantReadWriteLock

读写锁实际上在维护同步状态时,需要在同步状态上维护多个读线程和多个写线程的状态,在一个整型变量上维护多种状态,实际上是按位进行切割,高16为表示读状态,低16位表示写状态

在分布式场景下,我们不得不提到分布式锁

分布式锁

分布式锁是为了解决在分布式场景下,多个线程对共享资源的互斥访问,从而保证线程能够正确的返回结果;常见的分布式锁的实现方式通过redis来实现

对于分布式锁的实现思路,只要算法具备3个特性就可以满足最低保障的分布式锁

  • 安全属性(Safety property): 独享(相互排斥)。在任意一个时刻,只有一个客户端持有锁
  • 活性A(Liveness property A): 无死锁。即便持有锁的客户端崩溃(crashed)或者网络被分裂(gets partitioned),锁仍然可以被获取
  • 活性B(Liveness property B): 容错。 只要大部分Redis节点都活着,客户端就可以获取和释放锁

在redis命令中setnx,当key不存在,才设置成功,返回1,如果存在,则失败返回0,可以满足特性1,通过expire命令,设置key的TTL的时间,可以满足特性2,释放锁的时候,通过del命令删除key;对于特性3往往在实现过程中没有解决这个问题;这里不得不谈到redis的部署方式,redis部署方式由单节点部署、主从方式、哨兵方式、以及集群方式;在生产环境,容灾部署方式比较多的是哨兵部署方式,通过转移故障节点,从节点竞升为master节点。这种方式存在一个安全问题:

客户端A从master获取到锁 ;在master将锁同步到slave之前,master宕掉了。 slave节点被晋级为master节点;客户端B取得了同一个资源被客户端A已经获取到的另外一个锁。安全失效!

所以更加安全的分布式算法一般通过红锁算法RedLock来实现,在Redis的高级应用Redission来实现,具体请看http://redis.cn/topics/distlock.html

更多分布式场景下锁的一些分类可以参考:https://github.com/redisson/redisson/wiki/8.-%E5%88%86%E5%B8%83%E5%BC%8F%E9%94%81%E5%92%8C%E5%90%8C%E6%AD%A5%E5%99%A8#81-%E5%8F%AF%E9%87%8D%E5%85%A5%E9%94%81reentrant-lock

二、Redis的部署方式

猜你喜欢

转载自blog.csdn.net/hfy15352/article/details/80001156
今日推荐