1.网络IO实现方式

分布式系统间的通信的基础是网络IO,不同的技术都会有自己不同的实现,但是通信原理是基于下面三种通信方式:BIO,NIO,AIO。

首先BIO,NIO,AIO都是基于socket套接字来通信的,socket是传输层协议TCP/UDP的具体实现。

BIO:同步阻塞IO,每一个Socket使用一个线程来通信。阻塞表现在,主线程调用write()方法后,不能做其他事情,阻塞了,等待返回。

NIO:同步非阻塞IO,采用Reactor模式,使用一个线程来管理所有的Socket,简单来说,Channel注册到Selector,一个线程来遍历Selector通过Channel来通信。Channel通信是基于Socket. 有通信的时候会处理。非阻塞表现在,主线程不会阻塞,会有单独的一个线程来处理接受读操作。同步表现在,如果一个Socket通信有问题,会影响其它的Socket通信。

AIO:异步IO,采用Proactor模式,另外开线程来通信,通信完成会调用类似的回调函数来通知。我们不用单独建立线程来处理通信,Java自己会建立一个线程池处理通信,并回调对应的方法。多个通信之间不会互相影响。


2.CAP/BASE 理论

CAP理论:

C:Consistency(数据一致性)

A:Availability(可用性)

P:Partition-Tolerance(分区容忍性)

分布式系统的可用性都是需要保证的,一般在C和P直接做取舍,大部分系统会舍弃C保证AP,但也不是完全舍弃,不会保证数据的强一致性,但是会保证最终一致性。

BASE理论:

Basically Available:基本可用,允许分区失败

Soft state:软状态,接受一段时间的状态不同步

Eventually consistent:最终一致

具体实施过程中,可参考BASE理论,但主要看业务需要,做出取舍。


3.事务和分布式事务

事务:对数据一系列的增删改查操作。

事务的四个特征:

a.原子性:所有操作要么全部成功,要么全部失败。

b.一致性:保证数据的完整性和一致性。

c.隔离性:事物之间不相互影响。

d.持久性:事务执行成功,对数据库的改变是持久的。

事务的隔离级别:

a.读未提交 

b.读已提交 解决脏读  未提交的写事务将会禁止其他事务访问该行

c.可重复读 解决脏读,不可重复读

d.序列化,串行化,串行化 解决脏读,不可重复读,幻读

脏读,不可重复读,幻读区别:

脏读 读取了未提交的事务,事务A还没提交,事务B就读到了数据

不可重复读 事务A在读取数据,事务B就更新了数据(一个事务范围类)

幻读 事务A在读取数据,事务B就插入的数据(一个事务范围类)

不可重复读和幻读的区别在于,更新,删除和插入的区别,要解决问题,一个锁列,一个锁表

分布式事务:

简单的来说,在多个服务器之间保证事务。对于单台服务器,我们可以用数据库来保证事务,多台服务器,不同的数据库上的事务,就是分布式事务。


4.分布式锁的实现方式

讨论分布式锁之前,我们先来理解一下锁的概念。首先锁的目的是为了顺序的访问共享资源,比如文件,变量等。其次什么可以作为锁。对于单台服务器,我们可以用唯一对象,唯一的静态变量等,他们的共同点是唯一性。对于多台服务器,我们很难在服务器上找到唯一的东西来作为锁,因为多台服务器,肯定会有多个。这个时候,我们要寻求第三方的帮助,只要第三方能提供一个唯一的东西,我们就可以把它作为分布式的锁。

分布式锁需要能保证下面几点特性:

a.可用性:挂了一台还能不影响功能

b.可重入:同一个线程可以获得锁多次

c.阻塞:获取不到锁的线程应该等待

d.不能死锁:锁不能一直不释放

目前下面的几个可以实现分布式锁:

A.数据库

我们来简单的看一下实现逻辑,创建一个资源表,资源被使用就用一个字段标记一下,释放的时候就更新一下这个字段。可以乐观锁来处理并发的情况。看一下需要满足的四个特性:

a.可用性:可以做主从备份

b.可重入:数据库保存线程和主机信息

c.阻塞:其他线程获取不到锁可以维护while循环

d.不能死锁:写个定时器,定时释放锁

B.缓存(Redis,Memcahed)

Memcahed:

Memcached 可以使用 add 命令,该命令只有KEY不存在时,才进行添加,或者不会处理。Memcached 所有命令都是原子性的,并发下add 同一个KEY ,只会一个会成功。利用这个原理可以实现分布式锁。add成功的获得锁。

a.可用性:集群

b.可重入:与KEY相应的VALUE存放一个随机token,token相同可重入

c.阻塞:其他线程获取不到锁可以维护while循环,可以尝试5秒

d.不能死锁:设置过期时间

Redis:

Redis  没有add 命令,但有SETNX(SET if Not eXists)若给定的 key 已经存在,则 SETNX不做任何动作。设置成功,返回 1。设置失败,返回 0 。

a.可用性:集群

b.可重入:与KEY相应的VALUE存放一个随机token,token相同可重入

c.阻塞:其他线程获取不到锁可以维护while循环,可以尝试5秒

d.不能死锁:设置过期时间

C.Zookeeper

调用Create方法创建临时节点,创建成功的获得锁。处理完逻辑,删除临时节点。

a.可用性:集群

b.可重入:线程信息保存到临时节点下

c.阻塞:其他线程获取不到锁可以维护while循环,可以尝试5秒

d.不能死锁:服务器挂了,临时节点自动删除