构建高性能WEB站点

2.数据的网络传输
带宽
数据如何发送
    1.数据首先先入用户内存地址空间
    2.调用系统库接口比如send(),将用户内存数据复制到系统核心维护的内核缓冲区中
    3.内核缓冲区将复制到网卡缓冲区中
    4.网卡将缓冲区中的数据发送到线路中
    5.发送时,网卡会使用内部特定的物理装置产生各种信号,如使用铜线时发送0和1的电信号
        使用光纤时发送光信号

    光的传播速度为 30万公里/秒
    铜线中的电信号为2.3万公里/秒
    光纤中的光信号为2.0万公里/秒

数据发送速度
    1.数据发送速度取决于接受速度,数据链路层对于数据帧的传输的控制机制完全是按照接收方
    的接收能力来确定发送速度的
    2.数据传播介质的并行度,这里也可以成为"带宽",比如可以将若干条光纤并行组成光缆,
    类似于32位计算机总线中可以同时传输32位数据

如何计算响应时间
    响应时间 = 发送时间 + 传播时间 + 处理时间
    响应时间 = (数据量比特数 / 带宽) + (传播距离 / 传播速度) + 处理时间
    下载速度 = 数据量字节数 / 响应时间

假设下载100MB 的文件:
    换算成比特也就是 800Mb
假设Web服务器使用了10M独享带宽,所以发送时间为:
    800Mbit / (10Mbit/s) = 80s
假设用户接入方式为1M带宽,所以发送时间为:
    800Mbit / (1Mbit/s) = 800s
假设web服务器连接到骨干网上,带宽为40G,所以发送时间为:
    800Mbit / (40Gbit/s) = 0.02s
假设发送的距离为1000公里,按照20万公里/秒,所以传播时间为:
    1000km / (2.0*10^8m/s) = 0.005s
如果忽略处理时间,响应时间便为:
    80s + 800s + 0.02s + 0.005s = 880.025s
所以下载速度便为:
    100MByte / 800.025s = 113.63KB/s

互联互通
    电信网的用户数据如果要到联通,则需要经过各个IDC,然后进入到电信的骨干网络核心节点
    再到联通的骨干网络核心节点,再到联通的各个IDC,最后才到最终的联通用户那里
    而电信和联通这样的互联网运营商



3.服务器的并发处理能力
吞吐率
    是指在一定并非用户数的情况下,服务器处理请求能力的量化体现

用户平均请求等待时间
    主要用于衡量服务器再一定并发用户数量的情况下,对于单个用户的服务质量
服务器平均请求处理时间
    与前者对比,则用于衡量服务器的整体服务质量,它其实就是吞吐率的倒数s


CPU并发计算
    进程、
    轻量级进程
    线程
    进程调度器    Scheduler维护者各种状态的进程队列,进程调度器维护着一个包括所有可
            运行进程的队列,成为"运行队列(Run Queue)",以及包括所有休眠进程和
            僵尸进程的列表,进程调度器的工作就是决定下一个运行的进程
    系统负载
进程切换
    进程切换也是有很大开销的,apache的进程切换开销很大,而Lighttpd进行切换开销就很小,
        所以性能优于apache
    apche采用prefork模式,使用父进程预先创建一定的子进程,所有的子进程都竞争accept
        用户请求
系统负载可以用 top 、w 命令查看,本质获取的来源都是/proc/loadavg
top命令查看出来的进程包括 PR NI 这些类型,PR表示进程的优先级Priority
    优先级动态调整用NI表示

系统调用
    当需要操作硬件的时候是由 用户进程切换到内核进程,用户进程切换到内核进程也就是上下文
    切换,会有一定的开销,减少系统调用也能提升性能

持久连接
    也就是长连接,HTTP/1.1支持

I/O模型
    PIO: 是由CPU控制内存到硬盘的数据交换,CPU必须等待数据转发

    DMA: 直接内存访问(Direct Memory Access),不经过CPU,只是CPU发一个指令,让DMA控制器
        完成由内存到硬盘的数据交换
同步阻塞I/O
    使用O_SYNC标志打开文件
    对磁盘的read()会阻塞,一直到数据被复制到了用户进程空间
    对磁盘的write()不会阻塞,但如果使用O_SYNC打开文件,write()也会阻塞
    accept()、send()、recv()

同步非阻塞I/O
    在socket中设置O_NONBLOCK,对于socket的send()或者recv()便采用非阻塞方式
    非阻塞方式对于磁盘I/O并不产生效果

多路I/O就绪通知
    非阻塞I/O需要定式轮询每个socket是否有可接受的数据,会浪费很多CPU时间
    多路I/O就绪 允许进程通过一种方法来同时监视所有的文件描述符,这样就可以快速的获得
        所有的就绪文件描述符
    select()  目前所有平台都支持,缺点是只能维持1024个连接(可以重编译内核),另外
        select()会对所有socket进行一次线性扫描,所以也浪费了一些开销
    poll()      没有文件符上限限制,和select()类似不论socket是否就绪都会扫描

    select()和poll()不会丢失就绪的信息,所以称为水平触发
    
    SIGIO 告诉我们哪些文件刚刚变为就绪,如果没有采取行动,那么之后就不会再次通知了,
        这被称为边缘触发
    /dev/poll 类似SIGIO
    /dev/epoll 只是在Linux2.4上的一个补丁

    epoll 可以同时支持水平触发和边缘触发
        epoll实现通过epoll_ctl()注册每一个文件描述符,当某个文件就绪时,内核采用
        callback的回调机制,激活这个文件描述符,将进程调用epoll_wait()的时候就会
        得到通知
        当调用epoll_wait()返回的是一个就绪描述符的数量,只需去epoll指定的一个数组
        中依次取得相应的文件描述符即可,这里也使用了内存映射(mmap)技术

    kqueue 可以像epoll一样支持边缘触发或者水平触发,和epoll性能接近,但是很多平台
        不支持,只有FreeBSD支持

内存映射
    对于小文件,无需调用read()或者write(),而是通过访问mmap()系统调用来建立内存和磁盘
    的关联,然后像访问内存一样自由地访问文件

直接I/O
    打开文件时候,增加O_DIRECT,可以绕过内核缓冲区直接访问
sendfile
    可以将数据直接复制给socket,省去了系统核心的切换
使用sendfile()系统调用
    发送一个文件由硬盘-->系统buffer-->用户buffer-->系统buffer-->socket的buffer
    sendfile(): 硬盘-->系统buffer-->socket的buffer
异步I/O
    用户进程调用库函数访问文件时,进行必要的快速注册,如读写操作队列,然后函数
    马上返回,这时真正的I/O传输还没开始,所以这种机制才是真正的异步I/O,并且是
    非阻塞的
    目前Linux的 AIO只能通过O_DIRECT打开

服务器并发策略
    1.一个进程处理一个连接,非阻塞I/O
    apache采用:prefork()模式,父进程预先开启若干子进程,所有子进程使用阻塞accept()
    来竞争接受连接,一旦一个子进程建立连接后,它将继续进行处理
    
    2.一个线程处理一个连接,非阻塞I/O
    apache的worker多路处理模块,根据MPM配置,开启的进程不多,每个进程有若干线程,
    但实际上是轻量级进程,所以开销还是很大
    
    3.一个进程处理多个连接,非阻塞I/O
    nginx和Lighttpd采用的方式
    epoll在很小的静态文件下性能和select(),poll()差不多,但是文件大了就比他们强很多

    4.一个线程处理多个连接,异步I/O
    目前很少有web服务器支持这种真正意义的异步I/O,Lighttpd 1.5开始支持Linux的AIO



4.动态内容缓存
将数据动态的缓存起来,放到内存或者硬盘上,然后程序动态判断是否过期,再从硬盘后者内存中读取这
个缓存数据写给客户端
动态局部无缓存
缓存服务器,利用memcache

页面静态化
局部静态化 SSI
也就是shtml文件,它的效率比纯静态的要低,如果shtml文件里没有包含任何指令,和纯的html文件内容
一样,其执行效率也会低于纯html的,因为需要一些解析



5.动态脚本加速



6.浏览器缓存    
Last-Modified    
ETag
前面两种响应头使得浏览器会询问服务器此文件是否改动过,所以产生的流量非常小
apache使用SSI的时候如果用了last-modified效率只有以前的1/3,但是Lighttpd差不多
    
Expires
Cache-Control
这两种可以彻底让浏览器不发送请求,Expires有过期时间,但是如果服务器时间和浏览器时间不同步任



7.Web服务器缓存
缓存响应内存
    apache分别提供了mod_disk_cache和mod_mem_cache
    由于mod_disk_cache使用了内存映射作用,所以访问速度甚至比mod_mem_cache还要快
    可以缓存动态内容和静态内容

缓存文件描述符
    对于小文件,可以考虑将打开后的文件描述符直接缓存到本机内存中
    apache提供了相应的扩展mod_file_cache
缓存过期策略
然有问题,Cache-control使用一个相对时间就没问题了



8.反向代理缓存
在反向代理服务器上创建缓存



9.Web组件分离
是否使用epoll模型
是否使用sendfile()系统
是否使用异步I/O
是否支持HTTP持久连接(HTTP Keep-alive)
是否需要opcode缓存
是否使用动态内容缓存以及有效期为多长
是否使用web服务器缓存以及有效期为多长
是否使用浏览器缓存以及有效期为多长
是否使用反向代理缓存以及有效期为多长
是否使用负载均衡策略

web组件分离
为图片,JS,用户上传的文件,静态网页申请不同的域名
好处是浏览器针对同一个域名会维持一个并发队列(每个浏览器并发数不同),并发的去获取数据,这样就

能很好的提升性能

静态页面站点的优化
支持epoll
非阻塞I/O
异步I/O
使用sendfile()系统调用
    发送一个文件由硬盘-->系统buffer-->用户buffer-->系统buffer-->socket的buffer
    sendfile(): 硬盘-->系统buffer-->socket的buffer
单进程
使用高速磁盘
使用RAID分区
购买足够的带宽



10.分布式缓存
数据库的前端缓存区
    这块内核缓冲区也成为页面高速缓存(Page Cache)包括:
    1.读写缓存区
    2.写缓存区

使用memcached
    memcached基于key-value的方式来存储数据
    数据过期时间采用LRU(Least Recently Used)算法
线程安全和锁竞争
    memcached提供了原子递增操作
监控状态
    memcached提供了很多被监控的状态值,包括:
    1.空间使用率
    2.缓存命中率
    3.I/O流量
缓存扩展
    如果10台机器都不能满足要求,那么可以继续增加机器
    但是10台机器上工作量可能不是完全均衡的
    可以通过hash的方式,将key散列到不同的机器上,或者通过取余数的
        方式将数据放到不同的机器上



11.数据库优化
show status
show innodb status
    mysqlreport 一个第三方的mysql状态报告工具
正确使用索引
使用explain分析sql语句,不过只能分析查询语句
通过type类型分析,有const(常数时间,通过索引就找到了),ALL(全表扫描)
    还有ref,index,
Extra类型有: Using index,Using where, Using filesort, Using temporary

组合索引,注意(key1,kye2)和(kye2,key1)是两个不同的组合索引
组合索引可能会有副作用

在my.cnf中记录超过 一秒 的查询
long_query_time=1
long-slow-queries=/data/var/mysql_slow.log

    mysqlsla 第三方日志分析工具

索引缓存
    frm    存储了表的结果信息
    MYD    存储了表中的数据
    MYI    存储了表中的索引
缓存的大小通过key_buffer设置
MyISAM由于缓存索引机制,所以写操作存在延迟,可能会有隐患
Innodb采用预写日志方式(Write-Ahead Logging WAL)来实现事务,只有当事务日志写入磁盘后才
    更新数据和索引

    另外在加入索引后,更新和删除的时间可能会变长
    需要综合考虑查询,更新,删除的时间比列,如果查询的比列很高的话,牺牲一些更新和删除
的时间也是值得的

MyISAM 采用表锁定,排斥锁(update,delete)比共享锁(select)拥有更高优先级,所以只有等所有的
    更新锁执行完后,共享锁才能执行
Innodb 采用行锁定
    行锁定的效果不一定就比表锁定的效率高,需要综合考虑

Innodb支持事务,MySql提供的三个配置:
1.innodb_flush_log_at_trx_commit=1
    表示事务提交后立即写入磁盘,同时数据和索引也立即更新
2.innodb_flush_log_at_trx_commit=0
    事务提交后不是立即写入磁盘,而是每过1秒后 刷新 到磁盘文件 同时更新数据和索引
3.innodb_flush_log_at_trx_commit=2
    事务提交后不是立即写入磁盘,而是每过1秒后 刷新 到磁盘 同时更新数据和索引

    注:刷新到 磁盘文件 是将数据写入到内核缓冲区
        刷新到 磁盘 是真正的写入磁盘

使用查询缓存,对于MyISAM和Innodb都有效果
query_cache_size=268435456    表示起开256M空间缓存查询结果
query_cache_type=1
query_cache_limit=1048576

对于缓存的过期策略是,当一个数据表有更新操作时,那么设计这个表的所有查询缓存都会失效
对于读多写少的情况,查询缓存比较合适

    临时表,在查询时出现 Using temporary的状态
临时表可以创建在磁盘(Disk table),内存(Table),以及临时文件(File),磁盘的开销最大
通过设置 tmp_table_size 参数,表示存储临时表的内存空间大小

    线程池
从报告的Cache=0,表示没有复用的线程
可以在my.cnf中设置:  thread_cache_size=100

    反范式化设计
一些社交网站,如果完全采用范式设计,当某个用户更新好友状态的时候可能会很慢,但是代价是有很多
    额外的写开销,不过这些操作可以异步进行

    非关系型数据库
key-value数据库,MemcacheDB 基于Memcache传输协议,将BerkeleyDB作为持久化引擎



12.Web负载均衡
HTTP重定向
    镜像下载  将下载的文件通过URL重定向的形式告诉浏览器去一个就进的站点下载
    RR(Round Robin)做重定向性能方面有不如hash好:
        1.HTTP本身是无状态的,如果要实现按属性请求转移,必须要将最后一次转移到
        实际服务器的序列号进行持久化保存,以便在多次HTTP请求之间可以共享,比如
        将它存放到memcache中,所以会带来额外的开销
        2.要实现据对的按顺序转移,必然会使得主站点请求转移计算的并发性大打折扣,
        因为转移(最后一次转移至实际服务器的序列号)状态是互斥资源,需要锁来保证
        它的同步性
    主站点可以定时通过SNMP获得实际服务器的流量,相比下载开销,SNMP可以忽略,这样就
    可以做到更精确的各个实际服务器的下载流量均衡了

DNS负载均衡
    用户通过域名访问站点的时候,首先是查询DNS服务器,一个DNS服务器支持一个域名对应多个
    IP地址,可以使用站点域名 对应 IP   或者站点别名 对应 IP ,别名的扩展性更好
    
    因为DNS记录可以被用户浏览器或者互联网运营商的各级DNS服务器缓存,所以几乎不会遇到
    性能问题,通过DNS服务器一般采用RR的方式,通过这种方式,实际上就已经达到了负载均衡,
    因为可以将很多用户访问分散到十个IP上
    
    动态DNS(Standard Dynamic update DNS) DDNS,可以通过自动化远程修改DNS协议
    虽然我们更新了站点的DNS记录,但是运营商的DNS服务器可能会缓存我们的记录

反向代理负载均衡
    转移和转发
        对于HTTP请求体现在"转发"上
        对于DNS解析体现在"转移"上
    对于反向代理服务器的工作:
    1.任何对于实际服务器的HTTP请求都必须经过调度器
    2.调度器必须等待实际服务器的HTTP响应,并将它反馈给用户

    可以按照权重、hash地址、RR(Round Robin)、随即分配等方式转发
    对于大量的小型静态文件的请求,如果带宽有限制的话,反向代理可能会成为瓶颈
会话粘贴
    1.当某个后台服务器启用了Session本地化来保存用户的一些数据后,下次用户的请求如果
    转发给了其他后端服务器,将导致之前的session数据无法访问
    2.后端服务器实现了一定的动态内容缓存,而毫无规律的转发使得这些缓存的利用率下降

IP负载均衡
    之前的负载均衡是基于HTTP的,我们可以在数据链路层(第二层),IP层(第三层),还有
    传输层(第四层)来实现负载均衡,这些工具必须通过Linux的内核来完成,可以使用
    Netfilter 和 IPVS
    使用IP负载均衡的好处是,可以支持更多的高层协议,比如FTP,SMTP,DNS等,以及VoIP
DNAT
    类似于反向代理,我们将实际服务器放在内部网络,而作为网关的NAT服务器将来自用户的
    数据包转发给内外网络的实际服务器

    iptables、IPVS
IPVS/ipvsadm
    IPVS的管理工具ipvsadm,这里也称为LVS(Linux Virtual Server)
    LVS-NAT,其效率比传统的NAT服务器要高
    如果网关带宽是瓶颈的话,LVS-NAT性能还是会有问题
直接路由
    一个网卡可以配置多个IP
    LVS-DR,返回的数据就不经过代理服务器了,因为此时有了真实的IP,可以直接将数据
    返回给用户
    相比LVS-NAT,LVS-DR的优点是即使代理服务器到web服务器的带宽很小,但如果WAN交换机
    的带宽足够,一样可以提供很高的下载性能,比如对于视频网站,下载网站
IP隧道
    也称为LVS-TUN,和LVS-DR类似,但是实际服务器和反向代理可能不在同一个WAN网段上,这就
    必须通过LVS-TUN来实现,他们都非常适合响应和请求不对称的Web服务器



13.共享文件系统
将静态文件放到单独的机器上,多个web服务器可以共享
NFS(Network File System)
    NFS 并没有设计自己传输协议,而是采用RPC(Remote Procedure Calls)
    具体配置方式请参看 Linux的NFS配置文档
文件共享的方式存在一定的延迟
另外如果web服务器多了,多个web服务器共享一个机器,也会造成瓶颈



14.内容分发和同步
SSH (Secure Shell) 它是建立在应用层和传输层上的安全协议,它属于主动分发的方式
    SCP、SFTP、多级分发
Web DAV
    利用HTTP的扩展协议WebDAV,可以进行远程文件操作

被动同步方式
    rsync 基于SSH
    利用rsync 和 crontab 可以实现定时被动获取文件的功能
分发还是同步
    1.文件分发需要依赖一定的应用程序逻辑,比如通过SCP扩展编写代码控制文件传输,或者
        自己开发专用的分发程序,而文件同步可以对应用完全透明,部分非常简单
    2.文件分发可以更好地控制触发条件,更加灵活,比如更容易实现多级复制,也就是前面
        介绍的多级分发
    3.文件同步(利用rsync)是一种天然的异步复制操作,不阻塞Web应用程序的运行,而在Web
        应用中药相对文件分发实现异步复制操作,必须得借助其他支持,比如异步计算等



15.分布式文件系统
文件分发和同步的缺点:
    1.需要维护大量的rsync同步脚本,或者需要配置大量的分发参数,尤其对于大规模的集群
    2.缺乏整体的管理和监控,我们需要能够一览无余地了解所有复制工作的状态,以及更多
        细节报告,这有助于我们更好地了解它们在运行中的状态
MogileFS
Hadoop

分布式文件系统帮助我们完成了更多的事情,它的意义在于:
    1.可以组建包括大量廉价服务器的海量存储系统,这是简单的文件分发和同步不容易做到的
    2.通过内部冗余复制,保证文件的可用性,特别是在上面提到的海量存储系统中,容错能力
        是至关重要的
    3.拥有非常好的可扩展性,增加存储节点和追踪器都非常容易
    4.实现多个文件副本之间负载均衡,完全可以通过扩展来保证性能



16.数据库扩展
主从复制
    开启主服务器上的二进制日志(log-bin)
    在主服务器和从服务器上分别进行简单的配置和授权
读写分离
    更新删除操作在主服务器上进行
    多个从服务器进行读操作
使用数据库反向代理
    由这个反向数据库反向代理服务器再访问主从服务器
垂直分区
    1.将不同的数据分布到不同的服务器上,比如博客表放到一个单独的数据库机器上,
    用户好友信息放到一个单独的数据库服务器上
    2.博客表的数据库还可以做成主从复制,即一个主博客数据库,多个从库
水平分区
    将某个很大的表,再拆分成多个表,然后再放到独立的数据库服务器上
如何分区
    哈希算法:通过取模来分表,比如%10,或者%100,缺点是当数据增长后想从10个分区扩展到
        20个分区,就需要重新分区了
    范围:将其中1--1000,1001--2000分别分区,这样就考虑到可扩展性了
    关系映射:需要一个独立的数据库维护分区后的映射关系,这样也能保证可扩展性
类似MySql Proxy的分区反向代理
    Spock Proxy    DAL(数据库访问层)??

很多大规模的站点基本上都经历了从简单的主从复制到垂直分区,再到水平分区的步骤



17.分布式计算
异步计算
    将一个很耗时的计算交给其他机器完成,比如邮件发送任务
    Gearman
    MemcacheQ 分布式消息队列服务,基于Memcache协议

分布式计算
    异步计算仅仅是将一个耗时的操作交给了其他机器完成,但是这个操作总花费时间并不会减少,
    分布式计算将任务拆分成多个交给多个机器,最后汇总。
Map/Reduce
    所有的计算任务都可以经历从拆分到汇总两个过程



18.性能监控
实时监控
    Nmon 一款工作在服务器本地的实时监控软件
监控代理
    很多监控工具都是基于SNMP来完成的
    有的web服务器并没有提供相应的SNMP如nginx,只提供了必要的HTTP监控接口
    MRGT,Cacti
响应时间监控
    从用户的角度去去访问站点的不同部分的响应时间,以上的监控工具就无能为力了
    可以使用 监控宝 ,基于Web界面的第三方工具

你可能感兴趣的:(Web)