一、什么是分布式系统
1、分布式系统是:若干独立计算机的组合,这些计算机对于用户来说就像单个相关系统。
意思就是说硬件独立、软件统一。
硬件独立:
计算机机器本身是独立的,一个大型的分布式系统,会由若干台计算机来组成系统的基础设施。
软件统一:
对于用户来说就像是和单个系统打交道。
2、分布式系统设计需要注意的问题:
如何将系统拆分为子系统?
如何规划子系统间的通信?
如何考虑通信过程中的安全?
如何让子系统可以扩展?
如何保证子系统的可靠性?
如何实现数据的一致性?
3、分布式系统面临的挑战:
异构性:分布式系统由不同的网络、不同的操作系统、不同的编程语言、所以需要一种通用的通信协议来屏蔽差异性。
缺乏全球时钟:程序之间相互协作,对于时间会产生依赖,但是各个计算机之间没有全局时间的概念由于网络通信所导致的。
一致性:数据被分散或者复制到各个计算机上,如何保证一致性是个问题。
故障的独立性:任何计算机都可能产生故障,原因也很多,出现时机也随机,分布式系统要求允许部分故障但不影响整个系统的使用。
并发:分布式系统是为了更好地共享资源而设计的,那么系统中的每个资源都必须被设计成在并发环境中是安全的。
透明性:分布式系统中的任何故障对用户来讲都应该是透明不可见的。
开放性:分布式系统多人编写,最终集成为系统,对外发布的接口必须遵守一定的规范。
安全性: 加密用于给共享资源提供适当的保护。
可扩展性:系统要设计成随着业务量的增加、相应的系统也必须能扩展来提供对应的服务。
4、线程
5、通信:
OSI分层模型分为七层、TCP/IP 模型分为四层(应用层、网络层、传输层、链路层)。
OSI和TCP/IP模型的对比:
相同点:都有应用、传输、网络层;都是下层服务上层。
不同点:层数不同,模型与协议出现的次序不同,TCP/IP先有协议,后有模型(出现早),OSI先有模型后有协议(出现晚)。
6、网络I/O
同步和异步:描述的是用户线程与内核的交互方式。
同步:
指用户线程发起IO请求后需要等待或者轮询内核IO操作完成后才能继续执行。
异步:
指用户发起IO请求后扔继续执行,当内核IO操作完成后会通知用户线程,或者调用用户线程注册的回调函数。
阻塞和非阻塞:指的是用户线程调用内核IO操作的方式。
阻塞:
指IO操作需要彻底完成后才返回到用户空间。
非阻塞:
IO操作被调用后立即返回给用户一个状态值,无需等待IO操作彻底完成。
一个IO操作其实分成了两个步骤:发起IO请求和实际的IO操作。
阻塞IO和非阻塞IO的区别在于第一步,发起IO请求是否会被阻塞,如果阻塞直到完成那么就是传统的阻塞IO,如果不阻塞,那么就是非阻塞IO。
同步IO和异步IO的区别就在于第二个步骤是否阻塞,如果实际的IO读写阻塞请求进程,那么就是同步IO。
UNIX/IO模型类型:
阻塞IO;非阻塞IO;IO复用(select和poll);信号驱动IO(SIGIO);异步IO
前四种IO模型都是同步的IO。
阻塞IO模型:请求无法立即完成则保持阻塞。
阶段一:等待数据就绪。网络IO的情况就是等待远端数据陆续到达;磁盘IO的情况就是等待磁盘数据从磁盘上读取到内核态内存中。
阶段二:数据复制。考虑到系统安全,用户态的程序没有权限直接读取内核态内存,因此内核负责把内核态内存中的数据复制一份到用户态内存中。
非阻塞IO模型:
socket设置为NONBLOCK(非阻塞)就是告诉内核,当所请求的IO操作无法完成时,不要将进程休眠,而是立刻返回一个错误码,这样请求就不会阻塞。
IO操作函数将不断的测试数据是否已经准备好,如果没有准备好继续测试,直到数据准备好为止,整个IO请求的过程中,虽然用户线程每次发起IO请求后立即返回,但是为了等到数据扔需要不断的轮询、重复请求,这是对CPU时间的极大浪费。
数据准备好了,从内核复制到用户空间。这种模型很少使用。
IO复用模型:
使用select或者poll函数他们可以同时阻塞多个IO操作,而且可以同时对多个读操作、多个写操作的IO函数进行检测,直到有数据可读或者可写时才真正调用IO操作函数。使用他们的好处是:用户可以再一个线程内同时处理多个socket的IO请求,用户可以注册多个socket然后不断地的调用select来读取被激活的socket,也就是可以做到在一个线程内同时处理多个IO请求的目的。而在同步阻塞模型中,必须通过多线程的方式才可以达到这个目的。
7、Java常见IO模型:
阻塞IO模式:
就是常见的ServerSocket serverSocket = new ServerSocket(port);
Socket socket = serverSocket.accept();
这样的会阻塞住,我们需要使用多线程的方式让其支持多个客户端访问,但是每次收到新的连接都要新建一个线程,处理问候销毁线程,代价开销太大。我们可以使用线程池再次进行改进,这个在大量短连接的场景中性能会有提升,但是在大量长连接的场景中,并没有什么优势。该方法适用于小到中等规模的客户端的并发数,连接数超过100000或者更多,性能则不理想。
对于上面的方式我们可以再次改进为非阻塞IO模式,上面的模式在读写操作时都是同步阻塞的,面对大并发(持续大量连接请求)的场景,需要消耗大量的线程来维持连接,CPU在大量的线程之间频繁切换,性能损耗很大,一旦单机的连接达到1万,甚至达到几万,服务器性能急剧下降。
而NIO的selector可以解决这个问题,用主线程(一个线程或者是CPU个数的线程)保持住所有连接,管理和读取客户端连接的数据,将读取的数据交给后面的线程池处理,线程池处理完业务逻辑后,将结果交给主线程发送响应给客户端,少量的线程就可以处理大量连接的请求。
NIO组成:Channel、Buffer、Selector。
要使用Selector需要向Selector注册Channel然后调用他的select方法,这个方法会一直阻塞到某个注册的通道有事件就绪。一旦这个方法返回,线程就可以处理这些事件。
可以改为异步IO模式。
8、RPC
RPC是指:计算机A上的进程,调用另外一台计算机B上的进程,其中A上的调用进程被挂起,而B上的被调用进程开始执行,当值返回给A时,A进程继续执行。RPC背后的思想就是:尽量使远程过程调用具有与本地调用相同的形式。