《构建高性能Web站点》笔记一(第1章到第6章)

看完《构建高性能Web站点》这本书,收获很多,书中很多经典方案都是用php来代码讲解,很值得phper认真品读,最主要是实践

第1章 绪论
等待什么
   首先让我们看一下从输入一个url到页面呈现到我们眼前,我们在等待什么?
    从一个网址输入,不只是页面的一个请求,还有图片、样式、脚本等这些文件请求,每个请求又会经历一些相同的历程:数据在网络的传输(传出和传入)、服务器对请求的处理返回数据、还有本地对返回数据的渲染。虽然这些请求是并发的,但是一个网页的一个完整过程总是取决于那个最后处理完的请求。
等待的时间:
数据在网络上的传输时间
站点服务器处理请求并生成回应数据的时间
浏览器本地计算和渲染的时间
怎么做
    如果你是一个网站的构架者,你能在这三个方面做些什么??
    你能让用户都在电信或联通的网络里吗,你能让用户都10M、20M的接入吗??很显然不能,但是我们可以在布置不同的服务器在电信和联通的网络和不同的区域,让不同网络和区域的用户都能以最优访问,我们可以让我们服务器的以更高的宽带接入,来减少我们这段数据的出入时间;精简页面内容和对页面、文本、图片等数据的必要的压缩,也会对减少网络的传输时间,但是如gzip等的压缩会增加两端的处理的时间,这个要根据实际情况选择了

web常用的优化方案:
1、增加带宽:
    当网页或组件下载速度变慢的话,一些架构师可能会采取增加带宽,因为他们认为是服务器带宽不够用了,这是最省事的一种方法,但是这对于提供下载服务为主的站点来说也许是这样的,对于其他服务的站点未必是好的解决方案 
2、减少HTTP请求:
    我们知道几乎每一个页面都包含了多个组件,每个组件都需要计算,下载,渲染,这些都是需要时间的,如果我们减少这些行为,那么就可以加快网页的执行速度,但是我们往往需要在优雅的网页以及网页的表现性能之间进行取舍,常见的优化方法是:
1.设计简单的网页,里面包含较少的图片和脚本,但是这可能牺牲了美观和用户交互
2.将多个图片文件合成一个图片文件,利用CSS偏移技术来呈现网页,这样可以避免多个图片下载
3.合并js脚本和css样式表
4.利用浏览器缓存策略,避免重复下载
可见这一块属于网页的前端优化
3、加快服务器的脚本执行计算速度
4、使用动态内容缓存
5、使用数据缓存
6、动态内容静态化
在动态网页的内容中虽然避免了可观的重复计算,但是需要每次调用动态脚本解释器判定缓存是否过期以及读取缓存,这似乎有点多余,关键是消耗了不少时间,直接让浏览器访问缓存不是更好么?这种情况下缓存直接暴漏给HTML页,我们普遍称之为静态化。
7、更换web服务器软件
8、页面组件分离
9、合理的部署web服务器
    我们知道访问的主机离我们的站点服务器距离越远,那么经过的路由节点越多,如果不在同一个互联网运营商的互联网中,还要经过运行商的顶级节点和骨干网络,可想而知这样要经过多少次存储转发,而且还要受不同运行商的出口带宽限制,显然我们希望我们的用户和站点服务器位于同一个互联网运营商的网络内,怎样实现呢?
10、使用负载均衡
如果我们已经最大程度上的发挥了单台服务器的处理能力,还不能满足现实需要,那么就需要更多的服务器一起分摊工作,为此我们需要想各种不同的办法实现web负载均衡,可能是简单的HTTP重定向,或是基于DNS的轮回解析,或者通过反向代理服务器来实现负载均衡调度,还可以通过LVS组件服务器集群等方法.
11、优化数据库
    如果我们忽略了数据库的优化,如果我们的表结构一塌糊涂,那么可以说前面的工作白干了,web服务器与数据库服务器交互通信一般是基于TCP协议,即便他们是在同一台主机上也是如此,在数据库设计的时候你需要考虑:
1.你是否合理的运用这种类型的索引?
    2.你了解数据库存储引擎的特性么?
12、考虑可扩展性
    可扩展性对于我们来说是我们山穷水尽的时候被指引得一条星光大道,一旦扩展无法进行,那就是死路一条
13、减少视觉等待
    有时候用户的要求的是你不要不理我,实在不行的话给用户一些提示吧

第2章 数据的网络传输
数据如何发送
1、应用程序通过系统函数库接口(如send)向内核发出系统调用
2、系统内核将数据从用户态内存区复制到由内核维护的内核缓冲区(这块地址空间的大小有限,需要发送的数据以队列的形式进入)
3、内核通知网卡来取数据,网卡将数据复制到网卡缓冲区
4、网卡缓冲区的数据完成从字节到位的转换,网卡通过特定的物理装置产生不同的电信号(铜线)或是光信号(光纤)
一般说的比如 100M 带宽,全称应该是100Mbit/s,或者l00Mbps,后边的bit/s经常省略
电磁波速度:铜线中电信号2.3*10^8,光纤约2*10^8(全反射增加了传输距离)
响应时间= 发送时间+传播时间+处理时间
等于
响应时间=(数据量比特数/带宽)+(传播距离/传播速度 )+处理时间
下载速度=数据量字节数/响应时间
约定:为了方便计算将lkb = 1000b


第3章 服务器并发处理能力
1、吞吐率
服务器并发处理能力:单位时间内处理的请求数,吞吐率,reqs/s
apache的mod_status,显示的 requests/sec,从启动开始的平均计算值。
lighttpd的mod_status显示最近5S的吞吐率。

并发用户数:多少个用户同时向服务器发送请求
总请求数
请求资源描述

100个用户同时发送请求,服务器网卡缓冲区最多有100个等待处理的请求。

Httpwatch可以看到浏览器的并发连接

实际并发用户数位Web服务器当前维护的代表不同用户的文件描述符总数,即并发连接数。Web会限制同时服务的最多用户数,如apache的MaxClients参数。
多出来的用户请求,会在服务器内核的数据接收缓冲区中等待处理。

最大并发用户数稍稍大于最大并发连接数,如果请求的性质决定了处理每个请求花费的时间少,如1KB的静态网页,那么每个请求都可以快速处理然后释放文件描述符。这时,最大并发用户数可以大于最大并发连接数。

WEB服务器的本质是:以最快的速度将内核缓冲区中的用户请求数据拿回来,然后最快的处理完这些请求,将响应数据放到内核的发送数据缓冲区。

请求等待时间,用户等待时间:
1 用户平均请求等待时间:在一定并发用户数的情况下,对于单个用户的服务质量;
2 服务器平均请求处理时间:服务器的整体服务器质量,是吞吐率的倒数。

2、apache ab 压力测试
ab - nl000 - cl0 http://localho9t/te9t.htm
-n1000 总请求数为1000
-c10 并发用户数为10
重点关注:
Requests pec second 吞吐率 Complete requests/Time taken for tests
Time per request 用户平均请求等待时间 Time taken for test/(Complete requests/Concurrency Level)

吞吐率随并发用户数先增高,到达一定数量就会下降
服务器平均请求处理时间和并发用户数成正比

在总 CPU 的机器上,虽然我们感觉到很多任务在同时运行,但是从微现意义上讲,任何时刻只有一个进程处于运行状态,而其他的进程有的处于挂起状态并等待就绪,有的已经就绪但等待 CPU 时间片还有的处于其他状态
进程的优先级会动态改变

查看系统负载:
cat   /proc/loadavg
top
iostat 是指cpu空闲并且等待io操作完成的时间比例

#cat /proc/loadavg
8.71 8.06 7.41 2/389 9057
2/389 中,2为此时运行队列中的进程个数,389为此时的进程总数。
最右的9057为最新创建的进程ID

8.71 8.06 7.41表示最近1,5,15分钟计算出的系统负载。在单位时间内运行队列中就绪等待(CPU时间)的进程数平均值。
要提高系统,可以编写一个占用长时间CPU的脚本,比如一个循环累加器。

进程切换
调度器挂起正在运行的进程,恢复以前挂起的某个进程。即“上下文切换”。上下文表示进程运行到何种程度。
挂起进程:将进程在CPU寄存器中的数据拿出来暂存在内核堆栈中;
进程恢复:将数据重新装入CPU寄存器。
这段装入和移出的数据称为“硬件上下文”,进程上下文还包含了进程运行需要的一切状态信息。
nmon工具可以监视服务器每秒上下文切换次数。
nmon -s 300 -c 288 -f -m /tmp

-s 300:表示每300秒采集一次数据,
-c 288 :表示采集288次,300*288=86400秒,刚好是1天的数据,这样运行一次这个程序就会生成一个一天的数据文件,
-m /tmp: 表示生成的数据文件的路径
-f :表示生成的数据文件名中有时间

RunQueue    1    Load    Average
ContextSwitch    28.4    1 mins    0.01
Forks        0.0    5 mins    0.03
Interrupts    253.0    15 mins    0.00

28.4次/秒 是系统不提供其WEB服务器的上下文切换。

我们查看某时刻的 httpd 进程数
ps afx | grep httpd | wc -1
锁竞争:当一个任务占用资源的时候,我们锁住资源,这时候其他任务都在等待锁的释放

3、系统调用的减少对于降低请求处理时间有着不可忽视的作用
进程有用户态和内核态两种运行模式,进程可以在两种模式之间切挟,这也需要一定的开销 ,进程通常运行在用户态
strace可跟踪一个进程的系统调用
4、内存分配
    Apache使用了基于内存池策略的内存管理方案,在运行开始便一次性申请大片内存作为内存池,随后需要的时候在内存池中直接获取,不需要再次分配
Nginx使用多线程来处理请求,这使得多个线程之间可以共享内存资源,从而是内存总体使用量大大减少
5、持久连接
    在一次TCP连接中持续发送多份数据而不断开连接,与其相反的是短连接,也就是建立连接后发送一份数据便断开,然后再次建立连接发送下一份数据。建立TCP连接的操作开销较大,所以连接次数越少,越有利于性能的提升。主流Web服务器都支持长连接,Apache中默认长连接是打开的,配置文件httpd.conf中 KeepAliveTimeout 5。浏览器和服务器各自超时时间不同,以最短时间为准。
6、I/O模型
I/O模型分为很多种类型,比如内存I/O,网络I/O,磁盘I/O,这里讲的是网络I/O。
同步阻塞I/O:默认情况下socket都是阻塞的,进程调用某些涉及I/O操作的函数时,如:connect、accept、recv/recvfrom、send/sendto、closesocket,I/O操作完成后再继续运行
同步非阻塞I/O:在socket选项中设置O_NONBLOCK可以实现非阻塞I/O,非阻塞I/O通过反复轮询来尝试数据是否就绪,防止进程被阻塞,最大的好处是可以在一个进程中同时处理多个I/O事件
多路I/O就绪通知:可以同时处理多个connection,允许进程通过同一种方法同时监视所有文件描述符,并可以快速获得所有就绪的文件描述符。当数据就绪后,一般选择非阻塞方式。比如select和linux下的epoll
异步I/O:主动请求数据后便可以继续处理其他任务,随后等待I/O操作完毕的通知


第4章 动态内容缓存
缓存的目的就是把需要话费昂贵开销的计算结果保存起来,这里指动态内容自行实现缓存机制。

缓存和缓冲相似之处是都需要一块存储区,他们本质都于速度不一致有关,但缓存更加注重策略,也就是说缓存命中率。
实例操作php smarty缓存
《构建高性能Web站点》笔记一(第1章到第6章)_第1张图片
缓存持久化与查找 :可使用多级目录解决缓存文件过多引起的性能问题

过期检查
1、根据缓存过期时间和当前时间比对,简单
2、根据缓存创建时间、过期时间、当前时间比对

把缓存放到内存申
实例讲解使用php的apc扩展将数据缓存到内存中,类似的扩展还有xcache

局部无缓存

静态化页面

访问动态程序返回缓存文件如果能改成直接访问缓存文件,那又是性能的提升

静态化页面更新策略
1、在数据更新时重新生成静态化内容 .
2、定时更新静态内容
一般都是配套cms使用

局部静态化


第5章 动态脚本缓存
opcode 缓存

解释器如zend Engine
编译器如c的gcc
解释和编译类似:词法分析、语法分析、语义分析等
php的opcode中间码相当于java的class字节码

php的apc扩展可打开opcode 缓存,加速php执行速度
《构建高性能Web站点》笔记一(第1章到第6章)_第2张图片

php调用java方法
《构建高性能Web站点》笔记一(第1章到第6章)_第3张图片

扩展尽量少加载,有的扩展做得不好,初始化化会消耗大量时间

php的Xdebug是个调试利器:代码跟踪、覆盖、上下文信息收集、函数跟踪、瓶颈分析



第6章 浏览器缓存

Firefox 地址栏输入about:cache查看缓存,采用二进制文件的方式来存储和管理缓存文件
chrome浏览器查看缓存目录:chrome://version/个人资料目录下有个cache文件夹
C:\Users\Administrator\AppData\Local\Google\Chrome\User Data\Default\Cache

缓存协商:浏览器向Web服务器请求内容,服务器告诉浏览器哪些可以缓存。下次请求这个内容时,询问服务器是否可以使用本地的缓存,服务器收到浏览器询问后需要做出果断回应,到底是允许浏览器使用本地缓存还是将最新内容传回浏览器


php控制浏览器缓存
//定义一个合理缓存时间。合理值屈居于页面本身、访问者的数量和页面的更新频率,此处为3600秒(1小时)。 
$time = 60 * 60;
//发送Last-Modified头标,设置文档的最后的更新日期。 
header ("Last-Modified: " .gmdate("D, d M Y H:i:s", time() )." GMT"); 
//发送Expires头标,设置当前缓存的文档过期时间,GMT格式。 
header ("Expires: " .gmdate("D, d M Y H:i:s", time()+$time )." GMT"); 
//发送Cache_Control头标,设置xx秒以后文档过时,可以代替Expires,如果同时出现,max-age优先。 
header ("Cache-Control: max-age=$time"); 
?>
 
完整实例:
$cache_time = 3600; 
$modified_time = @$_SERVER['HTTP_IF_MODIFIED_SINCE']; 
if( strtotime($modified_time)+$cache_time > time() ){ 
    header("HTTP/1.1 304"); 
    exit; 

header("Last-Modified: ".gmdate("D, d M Y H:i:s", time() )." GMT");  
echo time(); 
?>
 
浏览器不想缓存 Ctrl + F5强制刷新


你可能感兴趣的:(系统架构)