数据发送的过程(从主机到线路的过程)
- 应用程序首先将数据写到该进程的地址空间中。
- 应用程序通过系统函数库接口向内核发出系统调用,系统内核将这些数据从用户态内存复制到内核缓冲区中。(内核缓冲区大小有限,所有数据都以队列的方式进入这里)。
- 数据写入内核缓冲区后,内核通知网卡控制器来取数据,将数据复制到网卡的缓冲区中。
- 网卡缓冲区将要发送出去的数据进行字节到位的转换(二进制),然后依次发出。
网络数据传输的瓶颈
一般在带宽最低的交换点。
数据的响应时间和下载速度的公式
响应时间=发送时间(数据量比特数/带宽) + 传播时间(传播距离/传播速度) + 处理时间
下载速度=数据量字节数/响应时间。
吞吐率的概念
单位时间内服务器处理的请求数,单位是reqs/s。测试吞吐率三个重要的元素:并发用户数、总请求书、请求资源描述。比如请求一个13KB的静态页面,不考虑带宽的话,100个并发,1000次请求,可以达到11769reqs/s的吞吐率。但如果在100M独享宽带中,那么吞吐率=((100Mbit/8)*1000)/13KB=961.53reqs/s。所以优化的话,可以购买更高的独享带宽(如1GB带宽),然后为服务器安装千兆网卡,服务器所在网络也要使用千兆网卡交换机。
如何针对不同的请求性质来对服务器的吞吐率进行压测
对于有不同性质的请求(如获取静态资源、获取动态内容等)交错在一起的资源需求模型过于复杂,也就是对CPU处理和I/O操作的需求设计太多因素。所以我们一般都简化模型,对同一特定类型的有代表性的请求进行压力测试,然后根据需要,对多个请求的吞吐率按照比例计算加权平均值。
进程、轻量级进程、线程、协程的概念
- 进程:进程的调度由内核来进行,从内核的观点看,进程的目的就是担当分配系统资源的实体。同时,进程也可以理解为记录程序实例当前运行到什么程度的一组数据,多个进程通过不同的进程描述符与这些数据进行关联。每个进程都有自己独立的内存地址空间和生命周期。进程的创建使用fork()系统调用,其开销不很昂贵,但频繁创建,就对性能很大,对内存也消耗很大。每个进程都共享CPU寄存器,一个进程被挂起的本质就是将它在CPU寄存器中的数据拿出来暂存在内核态堆栈中,而一个进程恢复工作的本质就是将它的数据重新装入CPU寄存器。
- 轻量级进程:linux2.0之后,提供了对轻量级进程的支持,由使用clone()系统调用,并由内核直接管理,像普通进程一样独立存在。但这些进程允许共享一些资源,比如地址空间、打开的文件等。减少了内存的开销,并为多进程应用程序的数据共享提供了直接支持,但上下文开销还是避免不了。
- 线程:多线程一般只是一个普通的进程,在用户态通过一些库函数模拟实现的多执行流,上下文切换的开销最小,但不能利用到多CPU的优势。另外一种线程的实现是LinuxThreads,可以说是内核级线程,也是通过clone()来创建,由内核的进程调度器来管理,所以实现原理上是将线程和轻量级进程进行了一对一关联。
- 协程:一种用户态的轻量级线程,其实就是单线程,指定执行整个函数中到一部分然后就先出去执行别的,等条件满足时,协程下次更新帧到了再继续往下执行。优点是无需线程上下文切换的开销,充分开发了单CPU的能力,资源占用低,适合高并发I/O。缺点也很明显,就是没办法利用多CPU的优势。
怎么查看linux的系统负载
- cat /proc/loadavg 可以查看当前系统最近1分钟、5分钟和15分钟的系统负载。
- top 实时查看系统的负载统计和各个进程的消耗。
UNIX提供了5中I/O模型
- 阻塞I/O模型:在进程空间中调用recvfrom,其系统调用直到数据包到达且被复制到应用进程的缓冲区中或者发生错误时才返回,期间会一直阻塞等待。
- 非阻塞I/O模型:recvfrom从应用层到内核的时候,如果缓冲区没有数据,就返回一个EWOULDBLOCK错误,然后一直轮询检查这个状态,看内核是不是有数据到来。
- I/O复用模型:
- select/poll:进程通过将一个或多个fd传递给select或poll系统调用,它们会顺序扫描这些fd是否就绪,单支持的fd最多只能1024个,整个操作会阻塞在select操作上。
- epoll:同时支持水平触发和边缘触发,默认使用水平触发。但nginx默认使用的是边缘触发。epoll同样只告知那些就绪的文件描述符,当调用epoll_wait()获得就绪文件描述符时,返回的并不是实际的描述符,而是一个代表就绪描述符数量的值,只需去epoll指定的一个数组中依次获取相应数量的文件描述符即可,这里使用内存映射(mmap)技术,彻底省掉了描述符在系统调用时复制的开销。另一个本质的改进在于epoll采用基于事件的就绪通知方式,相当于一旦某个文件描述符就绪时,内核会采用类似callback的回调机制,迅速激活这个文件描述符,当进程调用epoll_wait()时便得到通知。epoll_wait()只会处理有效激活的连接,非激活或空闲的连接是对epoll没有影响的。
- 信号驱动I/O模型:首先开启套接口信号驱动IO功能,并通过系统调用sigaction执行一个信号处理函数(此系统调用立即返回,进程继续工作,它是非阻塞的)。当数据准备就绪时,就为该进程生成一个SIGIO信号,通过信号回调通知应用程序调用recvfrom来读取数据,并通知主循环函数处理数据。
- 异步I/O模型:告知内核启动某个操作,并让内核在整个操作完成后(包括将数据从内核复制到用户自己的缓冲区)通知我们。
- 异步IO模型和信号驱动IO模型的区别:信号驱动IO由内核通知我们何时可以开始一个IO操作;异步IO模型由核通知我们IO操作何时已经完成。
内存映射
将内存中某块地址空间跟指定的磁盘文件进行关联,从而把对这块内存的访问转换为对磁盘文件的访问。可以提高I/O性能。有两种类型的内存映射类型,共享型和私有型。共享型可以多个进程共享,但因为要同步,所以效率不如私有型。
静态化内容的管理
一般使用CMS(内容管理系统)来进行管理,同时CMS也可以再必要的时候帮助我们更新静态化内容。
静态化页面的更新策略
- 在数据更新时重新生成静态化内容。一般不会一有数据更新,就重新生成分发,而是会有一个静态化内容缓冲区,需要更新的内容会加入这个缓冲区中,当达到一定程度再批量进行处理。
- 根据不同内容的实时性要求,设定不同的时间间隔定时更新。
- 一般两者都会一起使用。
局部静态化
SSI技术能实现各个局部页面的独立更新,避免整个静态网页更新,可以大大节省重建整个网页时的计算开销和磁盘I/O开销,甚至包括分发时的网络I/O开销。
浏览器如何和服务器协商是否要对文件进行缓存
主要有两种协商方式:最后修改时间和ETab
1. 最后修改时间:第一次请求的response会加上Last-Modified的时间,后面再次发起请求,则会带上If-Modified-Since时间到服务器,判断这个时间跟要访问的文件的时间是不是不一致,一致则使用浏览器缓存,不一致则重新获取。但如果有做集群的话,很难保证同个文件在不同服务器上最后修改的时间一致。
2. ETag:不同的web服务器会有自己的算法实现ETag,但原则都一样,即如果一个页面的ETag没有变化,那么这个页面也一定没有更新。nginx的ETag=文件的最后修改时间(转成16进制)+文件的大小(转成16进制)。
3. 使用expire过期时间或者Cache-Control:max-age设置有效时长,都可以对文件进行缓存。但跟上面1、2点不同,这种不会去请求服务器,上面两种还需要发送请求到服务器判断是否需要获取缓存。
浏览器缓存的适用场景
- 缓存大文件。
- 节省带宽。对于小文件,并且不考虑带宽的时候,对系统的吞吐率提升并不大
浏览器请求资源的并发数限制
不同浏览器,对同一个域的资源的并发请求数是收到限制的。所以要加快浏览器并发请求页面中所有的资源,可以对不同的资源分配不同的域名。
TCP/IP网络分层模型
- TCP/IP模型分为5层:应用层(应用层、表示层、会话层)(第5层,里面又可以分为3层)、传输层(第4层)、网络层(第3层)、数据链路层(第2层)、物理层(第1层)。
- 应用层:主要是面向用户的交互,有常用的http协议、ftp协议等。
- 传输层:将应用层的数据进行传输转运。常用的有tcp(可靠的传输控制协议)、udp(用户数据报协议)。
- 网络层:处理网络中流动的数据包。常用的有ip协议、icmp协议、arp协议。通过分析ip地址得出物理mac地址。
- 数据链路层:用来处理连接硬件的部分,包括控制网卡、硬件相关的设备驱动等。
- 物理层:负责数据传输的硬件,常用的有双绞线电缆、无线、光纤等。
- 数据传递流程:首先应用层将数据报文按照协议封装格式压缩然后传递给传输层,传输层通过协议将数据报封装为数据报段然后传递给网络层,网络层将数据报段封装成数据包并传递给数据链路层,数据链路层收到数据包后封装为数据帧,然后将数据帧转成比特传递给物理层,物理层将比特通过光或电信号发送给目标。
七层负载均衡
七层负载均衡主要指目前主流的反向代理服务器。反向代理服务器的核心工作便是转发HTTP请求,因此它工作再HTTP层面,也就是TCP七层结构中的应用层(第七层),所以基于反向代理的负载均衡也称为七层负载均衡。
四层负载均衡
根据IP进行负载均衡。基于NAT技术的负载均衡,可以工作在传输层(第四层),对数据包中的IP地址和端口信息进行修改,所以也称为四层负载均衡。
1. LVS-NAT:用一台服务器作为NAT调度器(相当于网关),配合LVS对后台服务器进行负载均衡。请求和返回的响应都必须经过NAT调度器,所以NAT调度器的带宽可能会成为瓶颈。但是因为是在内核里面进行转发调度,所以性能比反向代理服务器优秀很多。
2. LVS-DR(直接路由):将后端服务器连入外网,设置相同的IP别名,配合LVS进行负载均衡,请求响应不用经过调度器直接返回给用户,所以相对于LVS-NAT的优点是没有网关瓶颈。有个前提是调度器和后端服务器必须在同一个WAN网段内。
3. LVS-TUN(IP隧道):跟LVS-DR的原理基本相同。不同的是实际服务器可以喝调度器不在同一个WAN网段,调度器通过IP隧道技术来转发请求到实际服务器。CDN服务便是基于IP隧道技术来实现的。
分布式计算框架
Map/Reduce框架,将一个大人物分解成多个小人物放到map中分别计算,然后再汇总到reduce。