互联网协议按照功能不同分为tcp/ip四层或tcp/ip五层或osi七层。
物理层:主要是基于电器特性发送高低电压(电信号),高电压对应数字1,低电压对应数字0。
数据链路层:定义了电信号的分组方式。
网络层:引入一套新的地址用来区分不同的广播域/子网,这套地址即网络地址。
传输层:建立端口到端口的通信。
会话层:建立、管理、终止进程之间的会话。
表示层:对上层数据或信息进行变换以保证一个主机应用层信息可以被另一个主机的应用程序理解。
应用层:为操作系统或网络应用程序提供访问网络服务的接口。
C/S架构是第一种比较早的软件架构,主要用于局域网内。
它可以分为客户机和服务器两层:
第一层: 在客户机系统上结合了界面显示与业务逻辑;
第二层: 通过网络结合了数据库服务器。
B/S架构的全称为Browser/Server,即浏览器/服务器结构。
Browser指的是Web浏览器,极少数事务逻辑在前端实现,但主要事务逻辑在服务器端实现。
B/S架构的系统无须特别安装,只要有Web浏览器即可。
B/S架构的分层:
B/S架构有三层,分别为:
第一层表现层:主要完成用户和后台的交互及最终查询结果的输出功能。
第二层逻辑层:主要是利用服务器完成客户端的应用逻辑功能。
第三层数据层:主要是接受客户端请求后独立进行各种运算。
建立双工通信,确保双方都能收到对方的信息,所以需要3次握手。
第1次握手:建立连接时,客户端发送syn包(syn=x)到服务器,并进入同步已发送状态,等待服务器确认;SYN:同步序列编号。
第2次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(syn=y),即SYN+ACK包,此时服务器进入同步已接受状态。
第3次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。
全双工关闭需要客户端和服务器发送和接受都关闭,但是关闭连接时,当Server端收到FIN报文时,很可能并不会立即关闭SOCKET,只能先回复一个ACK报文,所以需要4次挥手
第1次挥手:客户端进程发出连接释放报文,并且停止发送数据。此时,客户端进入FIN-WAIT-1(终止等待1)状态。
第2次挥手:服务器收到连接释放报文,发出确认报文。服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。
客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
第3次挥手:服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
第4次挥手:客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。
服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。
ARP协议,全称“Address Resolution Protocol”,中文名是地址解析协议,使用ARP协议可实现通过IP地址获得对应主机的物理地址(MAC地址)。
在TCP/IP的网络环境下,每个联网的主机都会被分配一个32位的IP地址,这种互联网地址是在网际范围标识主机的一种逻辑地址。
为了让报文在物理网路上传输,还必须要知道对方目的主机的物理地址(MAC)才行,这样就存在把IP地址变换成物理地址的地址转换的问题,需要有一个服务或功能将IP地址转换为相应的物理地址(MAC地址),这个服务或者功能就是ARP协议。
所谓的“地址解析”,就是主机在发送帧之前将目标IP地址转换成目标MAC地址的过程。
ARP协议的基本功能就是通过目标设备的IP地址,查询目标设备的MAC地址,以保证主机间相互通信的顺利进行。
ARP 协议和DNS有点相像之处,不同点是:DNS是在域名和IP之间的解析,另外,ARP协议不需要配置服务,而DNS要配置服务才行。
ARP协议要求通信的主机双方必须在同一个物理网段(即局域网环境)!
客户和服务器交换数据前,必须现在双方之间建立一个TCP连接,之后才能传输数据。
并提供超时重发、丢弃重复数据,检验数据,流量控制等功能,保证数据能完整地从一端传到另一端。
简单说就是必须要建立连接后才能传输数据,确保传输完整性,类比现实当中的打电话。
不可靠传输,”报头”部分一共只有8个字节,总长度不超过65,535字节,正好放进一个IP数据包。
它不提供可靠性,只是把应用程序传给IP层的数据报发送出去,但是不能保证它们能到达目的地。
由于UDP在传输数据报前不用再客户和服务器之间建立一个连接,且没有超时重发等机制,所以传输速度很快。
简单说就是单向把程序中的信息发送了,但也不知道对方收到没有,类比现实当中的寄信。
局域网,LAN(Local Area Network)是指在某一区域内(如一个学校、工厂和机关内)由多台计算机互联成的计算机组。一般是方圆几千米以内。将各种计算机,外部设备和数据库等互相联接起来组成的计算机通信网。它可以通过数据通信网或专用数据电路,与远方的局域网、数据库或处理中心相连接,构成一个较大范围的信息处理系统。
局域网可以实现文件管理、应用软件共享、打印机共享、工作组内的日程安排、电子邮件和传真通信服务等功能。局域网严格意义上是封闭型的,可以由办公室内的两台计算机组成,也可以由一个公司内的上千台计算机组成。
广域网,WAN(Wide Area Network)也称远程网。通常跨接很大的物理范围,所覆盖的范围从几十公里到几千公里,它能连接多个城市或国家,或横跨几个洲并能提供远距离通信,形成国际性的远程网络。
广域网的通信子网主要使用分组交换技术。广域网的通信子网可以利用公用分组交换网、卫星通信网和无线分组交换网,它将分布在不同地区的局域网或计算机系统互连起来,达到资源共享的目的。如因特网(Internet)是世界范围内最大的广域网。
广域网是由许多交换机组成的,交换机之间采用点到点线路连接,几乎所有的点到点通信方式都可以用来建立广域网,包括租用线路、光纤、微波、卫星信道。而广域网交换机实际上就是一台计算机,有处理器和输入/输出设备进行数据包的收发处理。
tcp协议一定是先建好双向链接,发一个数据包要得到确认才算发送完成,没有收到就一直给你重发;udp协议没有链接存在,udp直接丢数据,不管你有没有收到。
TCP的可靠保证,是它的三次握手双向机制,这一机制保证校验了数据,保证了他的可靠性。而UDP就没有了,udp信息发出后,不验证是否到达对方,所以不可靠。
不过UDP的速度是TCP比不了的,而且UDP的反应速度更快,QQ就是用UDP协议传输的,HTTP是用TCP协议传输的。
Socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。
在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。
基于tcp 协议的套接字通信流程:
粘包:在接收数据时,一次性多接收了其它请求发送来的数据(即多包接收)。
如,对方第一次发送hello,第二次发送world,在接收时,应该收两次,一次是hello,一次是world,但事实上是一次收到helloworld,一次收到空,这种现象叫粘包。
原因:粘包问题主要还是因为接收方不知道消息之间的界限,不知道一次性提取多少字节的数据所造成的。
什么情况会发生:
1、发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据很小,会合到一起,产生粘包)
2、接收方不及时接收缓冲区的包,造成多个包接收(客户端发送了一段数据,服务端只收了一小部分,服务端下次再收的时候还是从缓冲区拿上次遗留的数据,产生粘包)
解决方案:
发送之前告诉对方自己要发送的字节长度,这样对方可以根据长度判断什么时候终止接受。
阻塞IO
举个简单的例子,我们要买网络编程一本书,来到书店问老板,老板的回复是等待一下,他去找书,这个时候我们就只能静静的等,直到老板找到这本书。
非阻塞IO
还是上面的例子,我们要买网络编程这本书,来到书店问老板,老板的回复是他去找书,这个时候情况就不同了,我们出去买一根雪糕,回来之后再问老板找到了没有 ,如果老板回复没有找到,我们再出去买包辣条再回来,直到老板回复找到了。
阻塞IO存在的问题是,当数据没有到来时,程序会一直阻塞,什么事情也做不了。非阻塞IO虽然会及时返回一个结果,但是需要不停地轮询IO请求的状态。
IO多路复用
假设你跟这个书店老板很熟了,我们问完有没有网络编程这本书之后,书店老板去找找,你说,找到之后放我家门口收件箱里吧,在这个收件箱里有我们所有请求的信息,只需要监听这个收件箱就可以了。
I/O多路复用是用于提升效率,单个进程可以同时监听多个网络连接IO。
举例:通过一种机制,可以监视多个文件描述符,一旦描述符就绪(读就绪和写就绪),能通知程序进行相应的读写操作,I/O多路复用避免阻塞在io上,原本为多进程或多线程来接收多个连接的消息变为单进程或单线程保存多个socket的状态后轮询处理。
防火墙的基本概念
古时候,人们常在寓所之间砌起一道砖墙,一旦火灾发生,它能够防止火势蔓延到别的寓所。
现在,如果一个网络接到了Internet上面,它的用户就可以访问外部世界并与之通信。但同时,外部世界也同样可以访问该网络并与之交互。
为安全起见,可以在该网络和Internet之间插入一个中介系统,竖起一道安全屏障。
这道屏障的作用是阻断来自外部通过网络对本网络的威胁和入侵,提供扼守本网络的安全和审计的唯一关卡,它的作用与古时候的防火砖墙有类似之处,因此我们把这个屏障就叫做“防火墙”。
在电脑中,防火墙是一种装置,它是由软件或硬件设备组合而成,通常处于企业的内部局域网与Internet之间,限制Internet用户对内部网络的访问以及管理内部用户访问外界的权限。
换言之,防火墙是一个位于被认为是安全和可信的内部网络与一个被认为是不那么安全和可信的外部网络(通常是Internet)之间的一个封锁工具。
防火墙是一种被动的技术,因为它假设了网络边界的存在,它对内部的非法访问难以有效地控制。因此防火墙只适合于相对独立的网络,例如企业内部的局域网络等。
作用:
基于这个准则,防火墙应封锁所有信息流,然后对希望提供的安全服务逐项开放,对不安全的服务或可能有安全隐患的服务一律扼杀在萌芽之中。
这是一种非常有效实用的方法,可以造成一种十分安全的环境,因为只有经过仔细挑选的服务才能允许用户使用。
基于这个准则,防火墙应先允许所有的用户和站点对内部网络的访问,然后网络管理员按照IP地址对未授权的用户或不信任的站点进行逐项屏蔽。
这种方法构成了一种更为灵活的应用环境,网络管理员可以针对不同的服务面向不同的用户开放,也就是能自由地设置各个用户的不同访问权限。
select
优点:单进程下支持高并发,可以跨平台
缺点:
多次从内核到应用,应用到内核的数组拷贝;
每次内核都会重置填写的数据
最大支持1024客户端,原因在于fd_set定义使用了FD_SETSIZE,大小为1024;
POLL模型:
POLL的原理与select相同,比select改进的地方:
1,请求和返回分离,避免每次都要重设数组
2,可以突破1024限制,poll是由打开文件的上限决定,可以使用ulimit命令查看上限
3,不能跨平台
EPOLL:
不管是select,还是poll,都需要遍历数组轮询,而且select仅支持1024个客户端,在大量并发,少量活跃的情况下效率较低,也就滋生了epoll模型。
1,可以突破1024限制,不跨平台
2,无须遍历整个文件描述符集,只需遍历被内核IO事件异步唤醒,而加入ready队列的文件描述符。
3,除了select/poll的IO事件水平触发(level triggered)外,还提供边沿触发(edge Triggered),可以缓存IO状态,减少epoll_wait调用,提高效率
1.进程是计算器最小资源分配单位 .
2.线程是CPU调度的最小单位 .
3.进程切换需要的资源很最大,效率很低 .
4.线程切换需要的资源一般,效率一般(当然了在不考虑GIL的情况下) .
5.协程切换任务资源很小,效率高(协程本身并不存在,是程序员通过控制IO操作完成) .
6.多进程、多线程根据cpu核数不一样可能是并行的,但是协程是在一个线程中所以是并发.
进程:
一个运行的程序(代码)就是一个进程,没有运行的代码叫程序,进程是系统资源分配的最小单位,进程拥有自己独立的内存空间,所以进程间数据不共享,开销大。
线程:
调度执行的最小单位,也叫执行路径,不能独立存在,依赖进程存在一个进程至少有一个线程,叫主线程,而多个线程共享内存(数据共享,共享全局变量),从而极大地提高了程序的运行效率。
协程:
是一种用户态的轻量级线程,协程的调度完全由用户控制。
协程拥有自己的寄存器上下文和栈。
协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,
可以不加锁的访问全局变量,所以上下文的切换非常快。
在CPython中,全局解释器锁(global interpreter lock,GIL)是一个互斥锁,它防止多个本机线程同时执行Python字节码。
这个锁是必要的,主要是因为CPython的内存管理不是线程安全的。
然而,由于GIL存在,其他特征已经发展成依赖于它所实施的保证。
首先需要明确的一点是GIL并不是Python的特性,它是在实现Python解析器(CPython)时所引入的一个概念。
就好比C++是一套语言(语法)标准,但是可以用不同的编译器来编译成可执行代码。
有名的编译器例如GCC,INTEL C++,Visual C++等。
Python也一样,同样一段代码可以通过CPython,PyPy,Psyco等不同的Python执行环境来执行。
像其中的JPython就没有GIL。
然而因为CPython是大部分环境下默认的Python执行环境,所以在很多人的概念里CPython就是Python,也就想当然的把GIL归结为Python语言的缺陷。
所以这里要先明确一点:GIL并不是Python的特性,Python完全可以不依赖于GIL。
每次执行python程序,都会产生一个独立的进程。在一个python的进程内,不仅有该进程的主线程和由该主线程开启的其他线程,还有解释器开启的垃圾回收等解释器级别的线程。
总之,所有线程都运行在这一个进程内,所有数据都是共享的,这其中,代码作为一种数据也是被所有线程共享的(主进程的所有代码以及Cpython解释器的所有代码)。
所有线程的任务,都需要将任务的代码当做参数传给解释器的代码去执行,即所有的线程要想运行自己的任务,首先要能够访问到解释器的代码。
解释器的代码是所有线程共享的,所以垃圾回收线程也可能访问到解释器的代码而去执行,这就导致了一个问题:对于同一个数据100,可能线程1执行x=100的同时,而垃圾回收执行的是回收100的操作,解决这种问题没有什么高明的方法,就是加锁处理,如下图的GIL,保证python解释器同一时间只能执行一个任务的代码。
锁的目的是为了保护共享的数据,同一时间只能有一个线程来修改共享的数据。
然后,我们可以得出结论:保护不同的数据就应该加不同的锁。
GIL 是解释器级别的,当然保护的就是解释器级别的数据,比如垃圾回收的数据。
有了GIL的存在,同一时刻同一个进程中只有一个线程被执行。
ProcessPoolExecutor类是一个Executor子类,它使用进程池异步执行调用。
ProcessPoolExecutor使用多处理模块,这允许它绕过全局解释器锁,但也意味着只能执行和返回可选择的对象。
import os
import time
import random
from concurrent.futures import ProcessPoolExecutor
def task(n):
print("n =", n, "on", os.getpid(), "is running.")
time.sleep(random.randint(1, 3))
return n ** 2
if __name__ == '__main__':
executor = ProcessPoolExecutor(max_workers=3)
futures = []
for i in range(10):
future = executor.submit(task, i)
futures.append(future)
executor.shutdown(True)
for future in futures:
print(future.result())
ThreadPoolExecutor是一个Executor子类,它使用线程池异步执行调用。
import time
import random
import threading
from concurrent.futures import ThreadPoolExecutor
def task(n):
print("n =", n, "on", threading.currentThread().getName(), "is running.")
time.sleep(random.randint(1, 3))
return n ** 2
if __name__ == '__main__':
executor = ThreadPoolExecutor(max_workers=3)
futures = []
for i in range(10):
future = executor.submit(task, i)
futures.append(future)
executor.shutdown(True)
for future in futures:
print(future.result())
threading.local()这个方法的特点用来保存一个全局变量,但是这个全局变量只有在当前线程才能访问,如果在开发多线程应用的时候 需要每个线程保存一个单独的数据供当前线程操作,可以考虑使用这个方法,简单有效。
举例:每个子线程使用全局对象a,但每个线程定义的属性a.xx是该线程独有的,Python提供了 threading.local 类,将这个类实例化得到一个全局对象,但是不同的线程使用这个对象存储的数据其它线程不可见(本质上就是不同的线程使用这个对象时为其创建一个独立的字典)。
管道:速度慢,容量有限,只有父子进程能通讯
FIFO:任何进程间都能通讯,但速度慢
消息队列:容量受到系统限制,且要注意第一次读的时候,要考虑上一次没有读完数据的问题
信号量:不能传递复杂消息,只能用来同步
共享内存区:能够很容易控制容量,速度快,但要保持同步,比如一个进程在写的时候,另一个进程要注意读写的问题,相当于线程中的线程安全
在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行。
并行(Parallel),当系统有一个以上CPU时,当一个CPU执行一个进程时,另一个CPU可以执行另一个进程,两个进程互不抢占CPU资源,可以同时进行,这种方式我们称之为并行(Parallel)。
线程锁:
多线程可以同时运行多个任务但是当多个线程同时访问共享数据时,可能导致数据不同步,甚至错误! so,不使用线程锁, 可能导致错误
进程锁:
也是为了控制同一操作系统中多个进程访问一个共享资源,只是因为程序的独立性,各个进程是无法控制其他进程对资源的访问的,但是可以使用本地系统的信号量控制(操作系统基本知识)。
同步和异步是针对应用程序和内核的交互而言的,同步指的是用户进程触发 IO 操作并等待或者轮询的去查看IO 操作是否就绪,而异步是指用户进程触发IO 操作以后便开始做自己的事情,而当IO 操作已经完成的时候会得到IO 完成的通知。
同步异步是针对调用者来说的,调用者发起一个请求后,一直干等被调用者的反馈就是同步,不必等去做别的事就是异步。
阻塞和非阻塞是针对于进程在访问数据的时候,根据IO操作的就绪状态来采取的不同方式,说白了是一种读取或者写入操作方法的实现方式,阻塞方式下读取或者写入函数将一直等待,而非阻塞方式下,读取或者写入方法会立即返回一个状态值。
阻塞非阻塞是针对被调用者来说的,被调用者收到一个请求后,做完请求任务后才给出反馈就是阻塞,收到请求直接给出反馈再去做任务就是非阻塞。
工作层次不同:
交换机主要工作在数据链路层(第二层)
路由器工作在网络层(第三层)。
转发依据不同:
交换机转发所依据的对象时:MAC地址。(物理地址)
路由转发所依据的对象是:IP地址。(网络地址)
主要功能不同:
交换机主要用于组建局域网
路由主要功能是将由交换机组好的局域网相互连接起来,或者接入Internet。
交换机能做的,路由都能做。
交换机不能分割广播域,路由可以。
路由还可以提供防火墙的功能。
路由配置比交换机复杂。
域名解析是将域名转换为其对应的IP地址的任务。
在使用Internet的应用程序中输入域名时,应用程序将发出命令让操作系统将域名转换为其IP地址,然后连接到该IP地址以执行它尝试执行的任何操作。
Windows操作胸膛hosts文件路径:C:\Windows\System32\drivers\etc
Linux及其他类Unix操作系统hosts文件路径:/etc
以管理员或超级用户的身份打开并编辑。
产生数据的模块,就形象地称为生产者;而处理数据的模块,就称为消费者。
在生产者与消费者之间在加个缓冲区,我们形象的称之为仓库,生产者负责往仓库了进商品,而消费者负责从仓库里拿商品,这就构成了生产者消费者模型。
结构图如下:
1、解耦
假设生产者和消费者分别是两个类。
如果让生产者直接调用消费者的某个方法,那么生产者对于消费者就会产生依赖(也就是耦合)。
将来如果消费者的代码发生变化, 可能会影响到生产者。而如果两者都依赖于某个缓冲区,两者之间不直接依赖,耦合也就相应降低了。
2、支持并发
由于生产者与消费者是两个独立的并发体,他们之间是用缓冲区作为桥梁连接,生产者只需要往缓冲区里丢数据,
就可以继续生产下一个数据,而消费者只需要从缓冲区了拿数据即可,这样就不会因为彼此的处理速度而发生阻塞。
3、支持忙闲不均
缓冲区还有另一个好处。如果制造数据的速度时快时慢,缓冲区的好处就体现出来了。
当数据制造快的时候,消费者来不及处理,未处理的数据可以暂时存在缓冲区中。 等生产者的制造速度慢下来,消费者再慢慢处理掉。
应用场景:
使用多线程,在做爬虫的时候,生产者用着产生url链接,消费者用于获取url数据,在队列的帮助下可以使用多线程加快爬虫速度。
CDN全称是Content Delivery Network,即内容分发网络,比如我们客户端向服务器请求一个数据,当这个数据很大,请求频繁,而且服务器距离客户端很远,这样很浪费资源,浪费大量的带宽,严重时候还会造成网络阻塞,而且这样响应时间非常慢。
CDN主要由负载均衡,和高速缓存服务器组成。其中分为中心部分和边缘部分。中心部分就是负责全局负载均衡,当客户端发送请求,首先会访问中心CDN,经过全局负载均衡,根据用户请求的ip 地址,一定的算法,然后算出距离用户最近,用户接入量最少得CDN缓存服务器,这样是不是相当于走了捷径。
因为cdn是介于客户端和请求服务器之间的一个缓存服务器,有一点点像redis缓存。当然第一次请求的时候,cdn没有缓存的话,cdn也会请求一次服务器,然后根据服务器返回的数据一方面留给自己缓存作为备用,另一方面也返回给客户端,好像现在像腾讯网,阿里云都有提供cdn服务器。而且域名配置服务器时候,就可以配到cdn。
一.LVS是什么?
LVS的英文全称是Linux Virtual Server,即Linux虚拟服务器。它是我们国家的章文嵩博士的一个开源项目。在linux内存2.6中,它已经成为内核的一部分,在此之前的内核版本则需要重新编译内核。
二.LVS能干什么?
LVS主要用于多服务器的负载均衡。它工作在网络层,可以实现高性能,高可用的服务器集群技术。它廉价,可把许多低性能的服务器组合在一起形成一个超级服务器。它易用,配置非常简单,且有多种负载均衡的方法。它稳定可靠,即使在集群的服务器中某台服务器无法正常工作,也不影响整体效果。另外可扩展性也非常好。
nginx是一个高性能的HTTP和反向代理服务器,其特点是占用内存少,并发能力强.
作为 Web 服务器:相比 Apache,Nginx 使用更少的资源,支持更多的并发连接,体现更高的效率,这点使 Nginx 尤其受到虚拟主机提供商的欢迎。能够支持高达 50,000 个并发连接数的响应,感谢 Nginx 为我们选择了 epoll and kqueue 作为开发模型.
作为负载均衡服务器:Nginx 既可以在内部直接支持 Rails 和 PHP,也可以支持作为 HTTP代理服务器 对外进行服务。Nginx 用 C 编写, 不论是系统资源开销还是 CPU 使用效率都比 Perlbal 要好的多。
作为邮件代理服务器: Nginx 同时也是一个非常优秀的邮件代理服务器(最早开发这个产品的目的之一也是作为邮件代理服务器),Last.fm 描述了成功并且美妙的使用经验。
Nginx 安装非常的简单,配置文件 非常简洁(还能够支持perl语法),Bugs非常少的服务器: Nginx 启动特别容易,并且几乎可以做到7*24不间断运行,即使运行数个月也不需要重新启动。你还能够在不间断服务的情况下进行软件版本的升级。
Keepalived是Linux下一个轻量级别的高可用解决方案。
Keepalived起初是为LVS设计的,专门用来监控集群系统中各个服务节点的状态,它根据TCP/IP参考模型的第三、第四层、第五层交换机制检测每个服务节点的状态,如果某个服务器节点出现异常,或者工作出现故障,Keepalived将检测到,并将出现的故障的服务器节点从集群系统中剔除,这些工作全部是自动完成的,不需要人工干涉,需要人工完成的只是修复出现故障的服务节点。
HAProxy 是一款提供高可用性、负载均衡以及基于TCP(第四层)和HTTP(第七层)应用的代理软件,支持虚拟主机,它是免费、快速并且可靠的一种解决方案。
HAProxy特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或七层处理。
HAProxy运行在时下的硬件上,完全可以支持数以万计的 并发连接。
并且它的运行模式使得它可以很简单安全的整合进您当前的架构中, 同时可以保护你的web服务器不被暴露到网络上。
作用: 高可用性,负载平衡和用于TCP和基于http的应用程序的代理
负载均衡(Load Balance),意思是将负载(工作任务,访问请求)进行平衡、分摊到多个操作单元(服务器,组件)上进行执行。是解决高性能,单点故障(高可用),扩展性(水平伸缩)的终极解决方案。
RPC(Remote Procedure Call,即远程过程调用)是建立在Socket之上的,在一台机器上运行的主程序,可以调用另一台机器上准备好的子程序,就像LPC(本地过程调用)。
也就是说两台服务器A,B,一个应用部署在A服务器上,想要调用B服务器上应用提供的函数/方法,由于不在一个内存空间,不能直接调用,需要通过网络来表达调用的语义和传达调用的数据。
对于RPC架构来说,应用越底层,代码越复杂、灵活性越高、效率越高;应用越上层,抽象封装的越好、代码越简单、效率越差。
在网络通信中,不管是TCP 还是UDP,我们都要在传输层上设计自己的应用层协议,使得前后端的数据可以相互通信传输一个可以识别的内容。
后来,人们期望能够更方便一点地让前后端进行交互,于是提出了RPC,就像调用函数一样来让前后端来进行通信,屏蔽掉复杂的应用层协议。
asyncio是Python 3.4版本引入的标准库,直接内置了对异步IO的支持。
asyncio的编程模型就是一个消息循环,我们从asyncio模块中直接获取一个EventLoop的引用,然后把需要执行的协程扔到EventLoop中执行,就实现了异步IO。
当一个greenlet遇到IO操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。
由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO。
由于切换是在IO操作时自动完成,所以gevent需要修改Python自带的一些标准库,这一过程在启动时通过monkey patch完成:
Twisted 是用 Python 实现的基于事件驱动的网络引擎框架,提供了允许阻塞行为但不会阻塞代码执行的方法,比较适合异步的程序。
事件驱动编程是一种编程范式,这里程序的执行流由外部事件来决定。它的特点是包含一个事件循环,当外部事件发生时使用回调机制来触发相应的处理。另外两种常见的编程范式是(单线程)同步以及多线程编程。
让我们用例子来比较和对比一下单线程、多线程以及事件驱动编程模型。
下图展示了随着时间的推移,这三种模式下程序所做的工作。
这个程序有3个任务需要完成,每个任务都在等待I/O操作时阻塞自身。阻塞在I/O操作上所花费的时间已经用灰色框标示出来了。
在单线程同步模型中,任务按照顺序执行。如果某个任务因为I/O而阻塞,其他所有的任务都必须等待,直到它完成之后它们才能依次执行。这种明确的执行顺序和串行化处理的行为是很容易推断得出的。如果任务之间并没有互相依赖的关系,但仍然需要互相等待的话这就使得程序不必要的降低了运行速度。
在多线程版本中,这3个任务分别在独立的线程中执行。这些线程由操作系统来管理,在多处理器系统上可以并行处理,或者在单处理器系统上交错执行。这使得当某个线程阻塞在某个资源的同时其他线程得以继续执行。与完成类似功能的同步程序相比,这种方式更有效率,但程序员必须写代码来保护共享资源,防止其被多个线程同时访问。多线程程序更加难以推断,因为这类程序不得不通过线程同步机制如锁、可重入函数、线程局部存储或者其他机制来处理线程安全问题,如果实现不当就会导致出现微妙且令人痛不欲生的bug。
在事件驱动版本的程序中,3个任务交错执行,但仍然在一个单独的线程控制中。当处理I/O或者其他昂贵的操作时,注册一个回调到事件循环中,然后当I/O操作完成时继续执行。回调描述了该如何处理某个事件。事件循环轮询所有的事件,当事件到来时将它们分配给等待处理事件的回调函数。这种方式让程序尽可能的得以执行而不需要用到额外的线程。事件驱动型程序比多线程程序更容易推断出行为,因为程序员不需要关心线程安全问题。