Apache服务器访问过慢分析及解决

起因:线上的一台服务器,最近总是出现 访问 很慢的情况发生,点击一个链接要2秒钟以上才能打开,按照我们对于访问人数的估计,服务器应该不至于响应这么慢,从而需要针对这个问题进行分析,来解决网站访问过慢。

分析:

1、首先,在页面访问变慢情况发生时,使用 top 命令查看了服务器的负载情况,发现负载并不高,初步估计不是程序的问题。 
2、然后,查看了线程中的 httpd 的数量, ps -aux | grep httpd | wc -l 发现,线程数已经达到了 apache 设置的最大值。由此断定是网站访问人数过多造成了访问过慢。 
3、为了验证,查看了连接数和当前的连接数,分别是 

    netstat -ant | grep $ip:80 | wc -l 
    netstat -ant | grep $ip:80 | grep EST | wc -l 
    发现果然,连接数特别多,远远超过我们的估计值。 
4、刚开始的时候,对于服务器的 MPM 配置方式不是特别的熟悉,认为修改服务器配置可以解决问题。主要的配置部分包括 prefork 模式 或者 work 模式的配置,下面是一些简单的介绍。

    prefork 模式: 
    以 prefork 模式工作的 apache 的默认配置: 
   

 <IfModule mpm_prefork_module> 
       ServerLimit            2000    
       StartServers              5    #指定服务器启动时建立的子进程数量 
       MinSpareServers           5    #指定空闲子进程的最小数量 
       MaxSpareServers          10    #指定空闲子进程的最大数量 
       MaxClients              150    #指定同一时间客户端最大接入请求的数量(单个进程并发线程数),任何超过该限制的请求都将进入等候队列,一旦一个连接被释放,队列中的请求将得到服务 
       MaxRequestsPerChild       0    #指定每个子进程在其生存周期内允许伺服的最大请求数量,默认为10000,0表示子进程永远不结束 
    </IfModule> 


    prefork 控制进程在最初建立“StartServers”个子进程后,为了满足 MinSpareServers 设置的需要创建一个进程,等待一秒钟,继续创建两个,再等待一秒钟,继续创建四个……如此按指数级增加创建的进程数,最多达到每秒32个,直到满足MinSpareServers设置的值为止。这种模式可以不必在请求到来时再产生新的进程,从而减小了系统开销以增加性能。 
    MaxSpareServers 设置了最大的空闲进程数,如果空闲进程数大于这个值,Apache会自动kill掉一些多余进程。这个值不要设得过大,但如果设的值比 MinSpareServers小,Apache会自动把其调整为 MinSpareServers+1。如果站点负载较大,可考虑同时加大MinSpareServers和MaxSpareServers。 
    MaxClients是这些指令中最为重要的一个,设定的是 Apache可以同时处理的请求,是对Apache性能影响最大的参数。其缺省值150是远远不够的,如果请求总数已达到这个值(可通过ps -ef|grephttpd|wc -l来确认),那么后面的请求就要排队,直到某个已处理请求完毕。这就是系统资源还剩下很多而HTTP访问却很慢的主要原因。虽然理论上这个值越大,可以处理的请求就越多,但Apache默认的限制不能大于256。在 apache2 中通过ServerLimit指令无须重编译Apache就可以加大MaxClients。 
    虽然通过设置ServerLimit,我们可以把MaxClients加得很大,但是往往会适得其反,系统耗光所有内存。以一台服务器为例:内存2G,每个apache进程消耗大约0.5%(可通过ps aux来确认)的内存,也就是10M,这样,理论上这台服务器最多跑200个apache进程就会耗光系统所有内存,所以,设置MaxClients要慎重。 
    worker 模式: 
    以 worker 模式工作的 apache 的默认配置为: 

<IfModule mpm_worker_module> 
       StartServers              2 
       MaxClients              150 
        MinSpareThreads          25 
       MaxSpareThreads           75 
       ThreadsPerChild           25 
       MaxRequestsPerChild        0 
    </IfModule> 

    Worker 由主控制进程生成“StartServers”个子进程,每个子进程中包含固定的ThreadsPerChild线程数,各个线程独立地处理请求。同样,为了不在请求到来时再生成线程, 
    MinSpareThreads和MaxSpareThreads设置了最少和最多的空闲线程数;而MaxClients 设置了同时连入的clients最大总数。如果现有子进程中的线程总数不能满足负载,控制进程将派生新的子进程。 
    MinSpareThreads和 MaxSpareThreads的最大缺省值分别是75和250。这两个参数对Apache的性能影响并不大,可以按照实际情况相应调节。
    ThreadsPerChild是worker MPM中与性能相关最密切的指令。 
    ThreadsPerChild的最大缺省值是64,如果负载较大,64也是不够的。这时要显式使用 ThreadLimit指令,它的最大缺省值是20000。 
    Worker模式下所能同时处理的请求总数是由子进程总数乘以ThreadsPerChild 值决定的,应该大于等于MaxClients。如果负载很大,现有的子进程数不能满足时,控制进程会派生新的子进程。默认最大的子进程总数是16,加大时也需要显式声明ServerLimit(最大值是20000)。需要注意的是,如果显式声明了ServerLimit,那么它乘以 ThreadsPerChild的值必须大于等于MaxClients,而且MaxClients必须是ThreadsPerChild的整数倍,否则 Apache将会自动调节到一个相应值。

    服务器的apache采用的是 prefork 的工作模式,对 MaxClients 进行了相应的调整,发现服务启动后很短时间,连接数就能够达到最大。 
5、后来想到需要查看用户都是访问的那些页面,将配置中的 access_log 打开,发现85%以上的访问都是直接访问的资源文件,由此判定,用户可能使用了多线程的下载工具,或者这些资源遭受了盗链。 
6、找到了问题所在,进行解决也就比较好办了。想到了两个方法: 
    A、对单个IP进行连接的线程限制,不允许多线程连接资源。 
        对于IP限制,我采用了 mod_limitipconn 这个模块。这个模块的好处是比较简单,缺点是不能够针对单独的文件夹或者文件进行设置,而且不支持虚拟主机。 
        在 apache 中安装了这个模块后,在配置文件中添加如下几段就可以生效了:           

 ExtendedStatus On 
            <IfModule mod_limitipconn.c > 
               < Location / >   # 所有虚拟主机的/目录 
                   MaxConnPerIP 3     # 每IP只允许3个并发连接 
                   NoIPLimit image/*  # 对图片不做IP限制 
               < /Location > 
            <Location /mp3 >  # 所有主机的/mp3目录 
            MaxConnPerIP1         # 每IP只允许一个连接请求    
            OnlyIPLimitaudio/mpeg video    # 该限制只对视频和音频格式的文件 
               < /Location > 
            </IfModule > 


    B、添加URL重写,防止盗链。 
        防止盗链,一个重要的方法就是判断请求的 refer,但是如果使用一些浏览器发出请求的时候将 refer 去掉,或者伪装,这个办法就无能为力了。但是貌似还有更高级的方法,还是可以实现这个功能。 
        安装apache的 mod_rewrite 模块后,在apache配置文件中添加 
        

RewriteEngine On 
        RewriteCond %{HTTP_REFERER} !^http://abc.com/.*$ [NC] 
        RewriteCond %{HTTP_REFERER} !^http://abc.com$ [NC] 
        RewriteCond %{HTTP_REFERER} !^http://www.abc.com/.*$ [NC] 
        RewriteCond %{HTTP_REFERER} !^http://www.abc.com$ [NC] 
        RewriteRule .*\.(gif|jpg|swf)$ http://www.abc.com/about/nolink.png [R,NC] 


        这样盗链的请求会被重定向到一个错误页面,从而减少下载带给服务器的压力。

参考资料: 
1、部署Apache 的一些技巧。       

2、Apache Server 负载能力测试    
3、Apache AB                        
4、Apache的参数设置                
5、Ab的用法                        
6、Apache限制连接数和并发数        
7、Apache安装mod_rewrite模块        
8、Apache防盗链的简单实现           

 

 

 

Windows系统下如果优化Apache的性能主要是通过专门针对Windows NT优化的MPM(多路处理模块)-mpm_winnt.c来优化的,它使用一个单独的父进程产生一个单独的子进程,在这个子进程中轮流产生多个线程来处理请求。也就是说mpm_winnt只能启动父子两个进程, 不能像Linux下那样同时启动多个进程。 mpm_winnt主要通过ThreadsPerChild和MaxRequestsPerChild两个参数来优化Apache。 ThreadsPerChild 这个参数用于设置每个进程的线程数, 子进程在启动时建立这些线程后就不再建立新的线程了.一方面因为mpm_winnt不能启动多个进程, 所以这个数值要足够大,以便可以处理可能的请求高峰;另一方面该参数以服务器的响应速度为准的, 数目太大的反而会变慢。因此需要综合均衡一个合理的数值。mpm_winnt上的默认值是64, 最大值是1920. 这里建议设置为100-500之间,服务器性能高的话值大一些,反之值小一些。 MaxRequestsPerChild 该参数表示每个子进程能够处理的最大请求数, 即同时间内子进程数目.设置为零表示不限制, mpm_winnt上的默认值就是0. 官方参考手册中不建议设置为0, 主要基于两点考虑: (1) 可以防止(偶然的)内存泄漏无限进行,从而耗尽内存; (2) 给进程一个有限寿命,从而有助于当服务器负载减轻的时候减少活动进程的数量。 因此这个参数的值更大程度上取决于服务器的内存,如果内存比较大的话可以设置为0或很大的数字,否则设置一个小的数值。需要说明的是,如果这个值设置的太小的话会造成Apache频繁重启,在日志文件中会看到如下的文字:Processexiting because it reached MaxRequestsPerChild. Signaling the parent,这样一来降低了Apache的总体性能。 另外,可以通过查看Apache提供的server-status(状态报告)来验证当前所设置数值是否合理,在httpd.conf文件中做如下设置来打开它: # 首先需要加载mod_status模块 LoadModule status_module modules/mod_status.so  # 然后设置访问的地址 <Location /server-status> SetHandler server-status Orderdeny,allow Deny from all # 如果限制某个IP访问则设置为 Allow from 192.168.1.1 Allow from all </Location> 综合来说,因为Windows NT下Apache只能启动父子两个进程,因此只能通过增大单个进程的线程数以及单个进程能够处理的最大请求数来进行优化。其他优化的参数同Linux系统下是一样的,大家可以加以参考。下面针对上述两个参数给出一个建议的设置: <IfModule mpm_winnt.c> ThreadsPerChild 250MaxRequestsPerChild 5000 </IfModule> 用上面的方法优化了一下windows+apache+php后,发现响应速度快了很多,一般最多只延迟3秒左右,但对于美国的主机来说应该是个正常的状态吧!

 

 

大型网站HTTPS实践三:基于协议和配置的优化

 

1 前言

上文讲到 HTTPS对用户访问速度的影响

本文就为大家介绍HTTPS在访问速度,计算性能,安全等方面基于协议和配置的优化。

2 HTTPS 访问速度优化

2.1 Tcp fast open

HTTPS HTTP使用 TCP 协议进行传输,也就意味着必须通过三次握手建立 TCP连接,但一个 RTT 的时间内只传输一个 syn 包是不是太浪费?能不能在 syn 包发出的同时捎上应用层的数据?其实是可以的,这也是 tcp fast open的思路,简称TFO。具体原理可以参考rfc7413

遗憾的是TFO需要高版本内核的支持,linux 3.7以后支持TFO,但是目前的windows系统还不支持 TFO,所以只能在公司内部服务器之间发挥作用。

2.2 HSTS

前面提到过将用户HTTP请求 302 跳转到HTTPS,这会有两个影响:

1、不安全,302跳转不仅暴露了用户的访问站点,也很容易被中间者支持。

2、降低访问速度,302跳转不仅需要一个 RTT,浏览器执行跳转也需要执行时间。

由于 302跳转事实上是由浏览器触发的,服务器无法完全控制,这个需求导致了 HSTS的诞生:

HSTS(HTTP Strict Transport Security)。服务端返回一个HSTS httpheader,浏览器获取到HSTS头部之后,在一段时间内,不管用户输入www.baidu.com还是http://www.baidu.com,都会默认将请求内部跳转成https://www.baidu.com

Chrome, firefox, ie 都支持了HSTShttp://caniuse.com/#feat=stricttransportsecurity)。

2.3 Session resume

Session resume 顾名思义就是复用session,实现简化握手。复用session的好处有两个:

1、减少了 CPU消耗,因为不需要进行非对称密钥交换的计算。

2、提升访问速度,不需要进行完全握手阶段二,节省了一个 RTT和计算耗时。

TLS 协议目前提供两种机制实现 session resume,分别介绍一下。

2.3.1 Session cache

Session cache 的原理是使用client hello中的 session id查询服务端的 session cache,如果服务端有对应的缓存,则直接使用已有的 session信息提前完成握手,称为简化握手。

Session cache 有两个缺点:

1、需要消耗服务端内存来存储 session内容。

2、目前的开源软件包括 nginx,apache只支持单机多进程间共享缓存,不支持多机间分布式缓存,对于百度或者其他大型互联网公司而言,单机 session cache几乎没有作用。

Session cache 也有一个非常大的优点:

session id TLS 协议的标准字段,市面上的浏览器全部都支持 session cache

百度通过对TLS握手协议及服务器端实现的优化,已经支持全局的 session cache,能够明显提升用户的访问速度,节省服务器计算资源。

2.3.2 Session ticket

上节提到了session cache的两个缺点,session ticket能够弥补这些不足。

Session ticket 的原理参考RFC4507。简述如下:

server session 信息加密成 ticket 发送给浏览器,浏览器后续握手请求时会发送 ticketserver端如果能成功解密和处理 ticket,就能完成简化握手。

显然,sessionticket的优点是不需要服务端消耗大量资源来存储 session内容。

Session ticket 的缺点:

1session ticket只是 TLS 协议的一个扩展特性,目前的支持率不是很广泛,只有 60%左右。

2session ticket需要维护一个全局的key来加解密,需要考虑KEY的安全性和部署效率。

总体来讲,sessionticket的功能特性明显优于session cache。希望客户端实现优先支持 session ticket

2.4 Ocsp stapling

Ocsp 全称在线证书状态检查协议 (rfc6960),用来向 CA站点查询证书状态,比如是否撤销。通常情况下,浏览器使用 OCSP协议发起查询请求,CA返回证书状态内容,然后浏览器接受证书是否可信的状态。

这个过程非常消耗时间,因为CA站点有可能在国外,网络不稳定,RTT也比较大。那有没有办法不直接向CA站点请求OCSP 内容呢?ocspstapling 就能实现这个功能。

详细介绍参考RFC6066 8 节。简述原理就是浏览器发起 client hello时会携带一个certificate status request的扩展,服务端看到这个扩展后将 OCSP内容直接返回给浏览器,完成证书状态检查。

由于浏览器不需要直接向CA站点查询证书状态,这个功能对访问速度的提升非常明显。

Nginx 目前已经支持这个 ocsp stapling file,只需要配置ocsp stapling file的指令就能开启这个功能:

·  ssl_staplingon;ssl_stapling_file ocsp.staple;

2.5 False start

通常情况下,应用层数据必须等完全握手全部结束之后才能传输。这个其实比较浪费时间,那能不能类似 TFO一样,在完全握手的第二个阶段将应用数据一起发出来呢?google提出了 false start来实现这个功能。详细介绍参考https://tools.ietf.org/html/draft-bmoeller-tls-falsestart-00

简单概括False start的原理就是在 client_key_exchange发出时将应用层数据一起发出来,能够节省一个 RTT

False start 依赖于 PFSperfect forward secrecy完美前向加密),而PFS又依赖于DHE 密钥交换系列算法(DHE_RSA,ECDHE_RSA, DHE_DSS, ECDHE_ECDSA),所以尽量优先支持 ECDHE密钥交换算法实现 false start

2.6 使用SPDY或者 HTTP2

SPDY google推出的优化 HTTP 传输效率的协议(https://www.chromium.org/spdy),它基本上沿用了HTTP协议的语义, 但是通过使用帧控制实现了多个特性,显著提升了 HTTP协议的传输效率。

SPDY 最大的特性就是多路复用,能将多个 HTTP请求在同一个连接上一起发出去,不像目前的 HTTP协议一样,只能串行地逐个发送请求。Pipeline虽然支持多个请求一起发送,但是接收时依然得按照顺序接收,本质上无法解决并发的问题。

HTTP2 IETF 2015 2 月份通过的 HTTP 下一代协议,它以 SPDY 为原型,经过两年多的讨论和完善最终确定。

本文就不过多介绍SPDY HTTP2 的收益,需要说明两点:

1SPDY HTTP2 目前的实现默认使用 HTTPS 协议。

2SPDY HTTP2 都支持现有的 HTTP 语义和API,对 WEB应用几乎是透明的。

Google 宣布 chrome浏览器 2016 年将放弃 SPDY 协议,全面支持 HTTP2,但是目前国内部分浏览器厂商进度非常慢,不仅不支持 HTTP2,连 SPDY 都没有支持过。

百度服务端和百度手机浏览器现在都已经支持 SPDY3.1协议。

 

3 HTTPS 计算性能优化

3.1 优先使用ECC

ECC 椭圆加密算术相比普通的离散对数计算速度性能要强很多。下表是 NIST推荐的密钥长度对照表。

表格 2 NIST推荐使用的密钥长度

对于 RSA算法来讲,目前至少使用2048位以上的密钥长度才能保证安全性。ECC只需要使用224位长度的密钥就能实现RSA2048位长度的安全强度。在进行相同的模指数运算时速度显然要快很多。

3.2 使用最新版的 openssl

一般来讲,新版的openssl相比老版的计算速度和安全性都会有提升。比如 openssl1.0.2采用了intel 最新的优化成果,椭圆曲线p256 的计算性能提升了 4倍。(https://eprint.iacr.org/2013/816.pdf)

Openssl 2014 年就升级了 5次,基本都是为了修复实现上的 BUG或者算法上的漏洞而升级的。所以尽量使用最新版本,避免安全上的风险。

3.3 硬件加速方案

现在比较常用的TLS硬件加速方案主要有两种:

1SSL专用加速卡。

2GPU SSL加速。

上述两个方案的主流用法都是将硬件插入到服务器的 PCI插槽中,由硬件完成最消耗性能的计算。但这样的方案有如下缺点:

1、支持算法有限。比如不支持 ECC,不支持 GCM等。

2、升级成本高。

a) 出现新的加密算法或者协议时,硬件加速方案无法及时升级。

b) 出现比较大的安全漏洞时,部分硬件方案在无法在短期内升级解决。比如 2014年暴露的 heartbleed漏洞。

3、无法充分利用硬件加速性能。硬件加速程序一般都运行在内核态,计算结果传递到应用层需要 IO和内存拷贝开销,即使硬件计算性能非常好,上层的同步等待和 IO开销也会导致整体性能达不到预期,无法充分利用硬件加速卡的计算能力。

4、维护性差。硬件驱动及应用层 API大部分是由安全厂家提供,出现问题后还需要厂家跟进。用户无法掌握核心代码,比较被动。不像开源的 openssl,不管算法还是协议,用户都能掌握。

3.4 TLS 远程代理计算

也正是因为上述原因,百度实现了专用的 SSL硬件加速集群。基本思路是:

1、优化 TLS协议栈,剥离最消耗 CPU资源的计算,主要有如下部分:

a)  RSA中的加解密计算。

b)  ECC算法中的公私钥生成。

c)  ECC算法中的共享密钥生成。

2、优化硬件计算部分。硬件计算不涉及协议及状态交互,只需要处理大数运算。

3Web server TLS 计算集群之间的任务是异步的。即 web server将待计算内容发送给加速集群后,依然可以继续处理其他请求,整个过程是异步非阻塞的。

4 HTTPS 安全配置

4.1 协议版本选择

SSL2.0 早就被证明是不安全的协议了,统计发现目前已经没有客户端支持 SSL2.0,所以可以放心地在服务端禁用 SSL2.0协议。

2014 年爆发了 POODLE攻击,SSL3.0 因此被证明是不安全的。但是统计发现依然有 0.5%的流量只支持 SSL3.0。所以只能有选择地支持 SSL3.0

TLS1.1 1.2目前为止没有发现安全漏洞,建议优先支持。

4.2 加密套件选择

加密套件包含四个部分:

1、非对称密钥交换算法。建议优先使用 ECDHE,禁用 DHE,次优先选择 RSA

2、证书签名算法。由于部分浏览器及操作系统不支持 ECDSA签名,目前默认都是使用 RSA签名,其中 SHA1 签名已经不再安全,chrome 及微软 2016 年开始不再支持 SHA1签名的证书(http://googleonlinesecurity.blogspot.jp/2014/09/gradually-sunsetting-sha-1.html)

3、对称加解密算法。优先使用 AES-GCM算法,针对 1.0 以上协议禁用 RC4 rfc7465)。

4、内容一致性校验算法。Md5 sha1 都已经不安全,建议使用 sha2 以上的安全哈希函数。

4.3 HTTPS 防攻击

4.3.1 防止协议降级攻击

降级攻击一般包括两种:加密套件降级攻击 (cipher suite rollback)和协议降级攻击(version roll back)。降级攻击的原理就是攻击者伪造或者修改 client hello消息,使得客户端和服务器之间使用比较弱的加密套件或者协议完成通信。

为了应对降级攻击,现在server端和浏览器之间都实现了SCSV功能,原理参考https://tools.ietf.org/html/draft-ietf-tls-downgrade-scsv-00

一句话解释就是如果客户端想要降级,必须发送 TLS_SCSV的信号,服务器如果看到 TLS_SCSV,就不会接受比服务端最高协议版本低的协议。

4.3.2 防止重新协商攻击

重新协商(tlsrenegotiation)分为两种:加密套件重协商 (cipher suite renegotiation)和协议重协商(protocolrenegotiation)。

重新协商会有两个隐患:

1、重协商后使用弱的安全算法。这样的后果就是传输内容很容易泄露。

2、重协商过程中不断发起完全握手请求,触发服务端进行高强度计算并引发服务拒绝。

对于重协商,最直接的保护手段就是禁止客户端主动重协商,当然出于特殊场景的需求,应该允许服务端主动发起重协商。

5 结束语

HTTPS 的实践和优化涉及到了非常多的知识点,由于篇幅关系,本文对很多优化策略只是简单介绍了一下.如果想要了解协议背后的原理,还是需要详细阅读 TLS协议及 PKI 知识。对于大型站点来说,如果希望做到极致,HTTPS的部署需要结合产品和基础设施的架构来进行详细的考虑,比起部署支持 HTTPS的接入和对它的优化,在产品和运维层面上花费的功夫会更多。

 

大型网站的HTTPS实践一:HTTPS协议和原理

1 前言

百度已经于近日上线了全站HTTPS的安全搜索,默认会将HTTP请求跳转成HTTPS。本文重点介绍HTTPS协议, 并简单介绍部署全站HTTPS 的意义。

2 HTTPS 协议概述

HTTPS 可以认为是 HTTP + TLSHTTP协议大家耳熟能详了,目前大部分 WEB应用和网站都是使用 HTTP协议传输的。

TLS 是传输层加密协议,它的前身是 SSL协议,最早由 netscape公司于 1995 年发布,1999 年经过 IETF讨论和规范后,改名为 TLS。如果没有特别说明,SSL TLS 说的都是同一个协议。

HTTP TLS在协议层的位置以及 TLS协议的组成如下图:

1 TLS协议格式

TLS 协议主要有五部分:应用数据层协议,握手协议,报警协议,加密消息确认协议,心跳协议。

TLS 协议本身又是由 record协议传输的,record协议的格式如上图最右所示。

目前常用的HTTP协议是HTTP1.1,常用的TLS协议版本有如下几个:TLS1.2,TLS1.1, TLS1.0 SSL3.0。其中 SSL3.0由于 POODLE 攻击已经被证明不安全,但统计发现依然有不到 1%的浏览器使用 SSL3.0TLS1.0也存在部分安全漏洞,比如 RC4 BEAST 攻击。

TLS1.2 TLS1.1暂时没有已知的安全漏洞,比较安全,同时有大量扩展提升速度和性能,推荐大家使用。

需要关注一点的就是TLS1.3将会是TLS 协议一个非常重大的改革。不管是安全性还是用户访问速度都会有质的提升。不过目前没有明确的发布时间。

同时 HTTP2也已经正式定稿,这个由SPDY协议演化而来的协议相比HTTP1.1又是一个非常重大的变动,能够明显提升应用层数据的传输效率。

3 HTTPS 功能介绍

百度使用HTTPS协议主要是为了保护用户隐私,防止流量劫持。

HTTP 本身是明文传输的,没有经过任何安全处理。例如用户在百度搜索了一个关键字,比如苹果手机,中间者完全能够查看到这个信息,并且有可能打电话过来骚扰用户。也有一些用户投诉使用百度时,发现首页或者结果页面浮了一个很长很大的广告,这也肯定是中间者往页面插的广告内容。如果劫持技术比较低劣的话,用户甚至无法访问百度。

这里提到的中间者主要指一些网络节点,是用户数据在浏览器和百度服务器中间传输必须要经过的节点。比如 WIFI热点,路由器,防火墙,反向代理,缓存服务器等。

HTTP协议下,中间者可以随意嗅探用户搜索内容,窃取隐私甚至篡改网页。不过 HTTPS是这些劫持行为的克星,能够完全有效地防御。

总体来说,HTTPS协议提供了三个强大的功能来对抗上述的劫持行为:

1、内容加密。浏览器到百度服务器的内容都是以加密形式传输,中间者无法直接查看原始内容。

2、身份认证。保证用户访问的是百度服务,即使被 DNS劫持到了第三方站点,也会提醒用户没有访问百度服务,有可能被劫持

3、数据完整性。防止内容被第三方冒充或者篡改。

HTTPS是如何做到上述三点的呢?下面从原理角度介绍一下。

4 HTTPS 原理介绍

4.1 内容加密

加密算法一般分为两种,对称加密和非对称加密。所谓对称加密(也叫密钥加密)就是指加密和解密使用的是相同的密钥。而非对称加密(也叫公钥加密)就是指加密和解密使用了不同的密钥。

2对称加密

3非对称加密

对称内容加密强度非常高,一般破解不了。但存在一个很大的问题就是无法安全地生成和保管密钥。假如客户端软件和服务器之间每次会话都使用固定的,相同的密钥加密和解密,肯定存在很大的安全隐患。如果有人从客户端端获取到了对称密钥,整个内容就不存在安全性了,而且管理海量的客户端密钥也是一件很复杂的事情。

非对称加密主要用于密钥交换(也叫密钥协商),能够很好地解决这个问题。浏览器和服务器每次新建会话时都使用非对称密钥交换算法协商出对称密钥,使用这些对称密钥完成应用数据的加解密和验证,整个会话过程中的密钥只在内存中生成和保存,而且每个会话的对称密钥都不相同(除非会话复用),中间者无法窃取。

非对称密钥交换很安全,但同时也是HTTPS性能和速度严重降低的罪魁祸首。想要知道HTTPS为什么影响速度,为什么消耗资源,就一定要理解非对称密钥交换的整个过程。

下面重点介绍一下非对称密钥交换的数学原理及在 TLS握手过程中的应用。

4.1.1 非对称密钥交换

在非对称密钥交换算法出现以前,对称加密一个很大的问题就是不知道如何安全生成和保管密钥。非对称密钥交换过程主要就是为了解决这个问题,使得对称密钥的生成和使用更加安全。

密钥交换算法本身非常复杂,密钥交换过程涉及到随机数生成,模指数运算,空白补齐,加密,签名等操作。

常见的密钥交换算法有RSAECDHEDHDHE等算法。它们的特性如下:

·  RSA:算法实现简单,诞生于1977 年,历史悠久,经过了长时间的破解测试,安全性高。缺点就是需要比较大的素数(目前常用的是 2048 位)来保证安全强度,很消耗 CPU 运算资源。RSA 是目前唯一一个既能用于密钥交换又能用于证书签名的算法。

·  DH:diffie-hellman密钥交换算法,诞生时间比较早(1977年),但是1999 年才公开。缺点是比较消耗 CPU性能。

·  ECDHE:使用椭圆曲线(ECC)的 DH 算法,优点是能用较小的素数(256 位)实现 RSA相同的安全等级。缺点是算法实现复杂,用于密钥交换的历史不长,没有经过长时间的安全攻击测试。  

·  ECDH:不支持 PFS,安全性低,同时无法实现false start。  

·  DHE:不支持 ECC。非常消耗 CPU资源。

建议优先支持RSA ECDH_RSA密钥交换算法。原因是:

1ECDHE支持 ECC 加速,计算速度更快。支持 PFS,更加安全。支持 false start,用户访问速度更快。

2、目前还有至少 20%以上的客户端不支持 ECDHE,我们推荐使用 RSA而不是 DH 或者 DHE,因为 DH系列算法非常消耗 CPU(相当于要做两次 RSA计算)。

需要注意通常所说的ECDHE密钥交换默认都是指ECDHE_RSA,使用 ECDHE生成 DH 算法所需的公私钥,然后使用 RSA 算法进行签名最后再计算得出对称密钥。

非对称加密相比对称加密更加安全,但也存在两个明显缺点:

1CPU计算资源消耗非常大。一次完全 TLS握手,密钥交换时的非对称解密计算量占整个握手过程的 90%以上。而对称加密的计算量只相当于非对称加密的 0.1%,如果应用层数据也使用非对称加解密,性能开销太大,无法承受。

2、非对称加密算法对加密内容的长度有限制,不能超过公钥长度。比如现在常用的公钥长度是 2048位,意味着待加密内容不能超过 256个字节。

所以公钥加密目前只能用来作密钥交换或者内容签名,不适合用来做应用层传输内容的加解密。

非对称密钥交换算法是整个HTTPS得以安全的基石,充分理解非对称密钥交换算法是理解 HTTPS协议和功能的关键。

下面分别通俗地介绍一下RSA ECDHE 在密钥交换过程中的应用。

4.1.1.1 RSA 密钥协商

4.1.1.1.1 RSA 算法介绍

RSA 算法的安全性是建立在乘法不可逆或者大数因子很难分解的基础上。RSA的推导和实现涉及到了欧拉函数和费马定理及模反元素的概念,有兴趣的读者可以自行百度。

RSA 算法是统治世界的最重要算法之一,而且从目前来看,RSA也是 HTTPS 体系中最重要的算法,没有之一。

RSA 的计算步骤如下:

1、随机挑选两个质数 p, q,假设 p = 13, q = 19 n = p *q = 13 * 19 = 247;

2(n)表示与整数 n 互质数的个数。如果 n 等于两个质数的积,则(n)=(p-1)(q-1)挑选一个数 e,满足1< e <(n)并且 e 与互质,假设 e= 17;

3、计算 e关于 n 的模反元素, ed=1 mod (n) , e = 17 ,(n) =216  可得 d = 89;

4、求出了 e,和 d,假设明文 m = 135,密文用 c表示。

那么加解密计算如下:

实际应用中,(n,e)组成了公钥对,(n,d)组成了私钥对,其中 n d 都是一个接近22048的大数。即使现在性能很强的CPU,想要计算m≡c^d mod(n),也需要消耗比较大的计算资源和时间。

公钥对(n, e)一般都注册到了证书里,任何人都能直接查看,比如百度证书的公钥对如下图,其中最末 6个数字(010001)换算成 10进制就是 65537,也就是公钥对中的 ee取值比较小的好处有两个:

1、由 c=m^e mod(n)可知,e 较小,客户端CPU 计算消耗的资源较少。

2、加大 server端的破解难度。e 比较小,私钥对中的 d 必然会非常大。所以 d 的取值空间也就非常大,增加了破解难度。

那为什么(n,e)能做为公钥公开,甚至大家都能直接从证书中查看到,这样安全吗?分析如下:

由于 ed≡1 mod(n),知道了 e n,想要求出私钥 d,就必须知道(n)。而(n)=(p-1)*(q-1),必须计算出 p q 才能确定私钥 d。但是当 n大到一定程度时(比如接近2^2048),即使现在最快的CPU也无法进行这个因式分解,即无法知道 n是由哪个数 p q 乘出来的。所以就算知道了公钥,整个加解密过程还是非常安全的。

5百度 HTTPS 证书公钥

 

4.1.1.1.2 握手过程中的 RSA密钥协商

介绍完了RSA的原理,那最终会话所需要的对称密钥是如何生成的呢?跟 RSA有什么关系?

TLS1.2为例简单描述一下,省略跟密钥交换无关的握手消息。过程如下:

1、浏览器发送 client_hello,包含一个随机数 random1

2、服务端回复 server_hello,包含一个随机数 random2,同时回复 certificate,携带了证书公钥 P

3、浏览器接收到 random2之后就能够生成 premaster_secrect以及master_secrect。其中 premaster_secret长度为 48 个字节,前 2 个字节是协议版本号,剩下的 46个字节填充一个随机数。结构如下:

·  Struct{byte Version[2];bute random[46];}

master secrect 的生成算法简述如下:

Master_key = PRF(premaster_secret, “mastersecrect”, 随机数1+随机数2)其中 PRF 是一个随机函数,定义如下:PRF(secret, label, seed) = P_MD5(S1, label + seed)  XOR P_SHA-1(S2, label + seed)

从上式可以看出,把premaster_key赋值给 secret”master key”赋值给 label,浏览器和服务器端的两个随机数做种子就能确定地求出一个 48 位长的随机数。

mastersecrect包含了六部分内容,分别是用于校验内容一致性的密钥,用于对称内容加解密的密钥,以及初始化向量(用于 CBC模式),客户端和服务端各一份。

至此,浏览器侧的密钥已经完成协商。

4、浏览器使用证书公钥 P premaster_secrect加密后发送给服务器。

5、服务端使用私钥解密得到 premaster_secrect。又由于服务端之前就收到了随机数 1,所以服务端根据相同的生成算法,在相同的输入参数下,求出了相同的 master secrect

RSA 密钥协商握手过程图示如下:

6 RSA密钥协商过程

可以看出,密钥协商过程需要 2 RTT,这也是HTTPS慢的一个重要原因。而RSA发挥的关键作用就是对premaster_secrect进行了加密和解密。中间者不可能破解 RSA算法,也就不可能知道 premaster_secrect,从而保证了密钥协商过程的安全性。

4.1.1.2 ECDHE 密钥协商

4.1.1.2.1 DH ECC算法原理

ECDHE 算法实现要复杂很多,主要分为两部分:diffie-hellman算法(简称为DH)及 ECC(椭圆曲线算术)。他们的安全性都是建立在离散对数计算很困难的基础上。

简单介绍一下dh算法的实现,先介绍两个基本概念:

·  本原根:如果整数 a 是素数 p 的本原根,则 a, a^2, …, a^(p-1) 在 mod p 下都不相同。 

·  离散对数:对任意整数 b 和素数 p 的本原根 a,存在唯一的指数 i 满足:

b ≡ a^i mod p (0≤i≤p-1)

则称 i b 的以 a 为底的模 p的离散对数。

理解这两个概念,dh算法就非常简单了,示例如下:

假设 client server 需要协商密钥,p=2579,则本原根 a= 2

1Client选择随机数 Kc = 123做为自己的私钥,计算 Yc = a^Kc  mod p = 2^123 mod 2579 =2400,把 Yc作为公钥发送给server

2Server选择随机数 Ks = 293作为私钥,计算 Ys = a^Ks  mod p = s^293 mod 2579 = 968,把 Ys作为公钥发送给client

3Client计算共享密钥:secrect =  Ys^Kc mod (p) = 968^123 mod(2579) = 434

4Server计算共享密钥:secrect = Yc^Ks mod(p) =2400^293 mod(2579)=434

上述公式中的Ys,Yc,P, a,都是公开信息,可以被中间者查看,只有 Ks,Kc作为私钥没有公开,当私钥较小时,通过穷举攻击能够计算出共享密钥,但是当私钥非常大时,穷举攻击肯定是不可行的。

DH 算法有一个比较大的缺陷就是需要提供足够大的私钥来保证安全性,所以比较消耗 CPU计算资源。ECC 椭圆曲线算术能够很好的解决这个问题,224位的密钥长度就能达到 RSA2048位的安全强度。

ECC 的曲线公式描述的其实不是椭圆,只是跟椭圆曲线周长公式形似才叫椭圆曲线加密算术。ECC涉及到了有限域、群等近世代数的多个概念,就不做详细介绍了。

ECC 安全性依赖于这样一个事实:

P = kQ,已知 k, Q 求出 P 相对简单,但是已知 P Q 求出 k 却非常困难。

上式看起来非常简单,但有如下约束条件:

1Q是一个非常大的质数,p, k, q都是椭圆曲线有限域上的离散点。

2、有限域定义了自己的加法和乘法法则,即使 kQ的运算也非常复杂。

ECC 应用于 Diffie-Hellman密钥交换过程如下:

1、定义一个满足椭圆方程的有限域,即挑选 p, a, b满足如下方程:

y^2 mod p = (x^3+ax +b) mod p

2、挑选基点 G = (x, y)G的阶为 nn为满足 nG = 0 的最小正整数。

3Client选择私钥 Kc (0 <Kc

4server选择私钥 Ks 并产生公钥 Ys =Ks*G

5client计算共享密钥 K = Kc*Ys  server 端计算共享密钥Ks*Yc ,这两者的结果是一样的,因为:

 Kc*Ys = Kc*(Ks*G) = Ks*(Kc*G) = Ks*Yc

由上面描述可知,只要确定p, a, b就能确定一条有限域上的椭圆曲线,由于不是所有的椭圆曲线都能够用于加密,所以 p, a, b的选取非常讲究,直接关系曲线的安全性和计算速度。

Openssl 实现的,也是 FIPS推荐的 256 位素数域上的椭圆曲线参数定义如下:

质数 p =115792089210356248762697446949407573530086143415290314195533631308867097853951 n =115792089210356248762697446949407573529996955224135760342422259061068512044369SEED= c49d3608 86e70493 6a6678e1 139d26b7 819f7e90c = 7efba166 2985be94 03cb055c75d4f7e0 ce8d84a9 c5114abcaf317768 0104fa0d 椭圆曲线的系数 a = 0椭圆曲线的系统 b = 5ac635d8 aa3a93e7 b3ebbd55 769886bc651d06b0 cc53b0f63bce3c3e 27d2604b基点 G x = 6b17d1f2 e12c4247 f8bce6e5 63a440f277037d81 2deb33a0f4a13945 d898c296基点 G y = 4fe342e2 fe1a7f9b 8ee7eb4a 7c0f9e162bce3357 6b315ececbb64068 37bf51f5

4.1.1.2.2 握手过程中的 ECDHE密钥协商

简单介绍了ECC DH 算法的数学原理,我们看下ECDHE TLS 握手过程中的应用。

相比 RSAECDHE需要多发送一个server_key_exchange的握手消息才能完成密钥协商。

同样以TLS1.2为例,简单描述一下过程:

1、浏览器发送 client_hello,包含一个随机数 random1,同时需要有 2 个扩展:

a)    Elliptic_curves:客户端支持的曲线类型和有限域参数。现在使用最多的是 256位的素数域,参数定义如上节所述。

b)   Ec_point_formats:支持的曲线点格式,默认都是uncompressed

2、服务端回复 server_hello,包含一个随机数 random2 ECC 扩展。

3、服务端回复 certificate,携带了证书公钥。

4、服务端生成 ECDH临时公钥,同时回复 server_key_exchange,包含三部分重要内容:

a)    ECC相关的参数。

b)   ECDH临时公钥。

c)    ECC参数和公钥生成的签名值,用于客户端校验。

5、浏览器接收 server_key_exchange之后,使用证书公钥进行签名解密和校验,获取服务器端的 ECDH临时公钥,生成会话所需要的共享密钥。

至此,浏览器端完成了密钥协商。

6、浏览器生成 ECDH临时公钥和 client_key_exchange消息,跟RSA 密钥协商不同的是,这个消息不需要加密了。

7、服务器处理 client_key_exchang消息,获取客户端ECDH临时公钥。

8、服务器生成会话所需要的共享密钥。

9Server端密钥协商过程结束。

图示如下:

7 ECDHE密钥协商过程

 

4.1.2 对称内容加密

非对称密钥交换过程结束之后就得出了本次会话需要使用的对称密钥。对称加密又分为两种模式:流式加密和分组加密。流式加密现在常用的就是 RC4,不过 RC4已经不再安全,微软也建议网站尽量不要使用 RC4流式加密。

一种新的替代RC4的流式加密算法叫ChaCha20,它是 google推出的速度更快,更安全的加密算法。目前已经被 android chrome 采用,也编译进了 google 的开源 openssl 分支 —boring ssl,并且nginx 1.7.4也支持编译 boringssl

分组加密以前常用的模式是AES-CBC,但是CBC已经被证明容易遭受BEASTLUCKY13攻击。目前建议使用的分组加密模式是 AES-GCM,不过它的缺点是计算量大,性能和电量消耗都比较高,不适用于移动电话和平板电脑。

4.2 身份认证

身份认证主要涉及到PKI和数字证书。通常来讲 PKI(公钥基础设施)包含如下部分:

·  End entity:终端实体,可以是一个终端硬件或者网站。

·  CA:证书签发机构。

·  RA:证书注册及审核机构。比如审查申请网站或者公司的真实性。

·  CRL issuer:负责证书撤销列表的发布和维护。

·  Repository:负责数字证书及 CRL内容存储和分发。

申请一个受信任的数字证书通常有如下流程:

1、终端实体生成公私钥和证书请求。

2RA检查实体的合法性。如果个人或者小网站,这一步不是必须的。

3CA签发证书,发送给申请者。

4、证书更新到 repository,终端后续从 repository更新证书,查询证书状态等。

目前百度使用的证书是X509v3格式,由如下三个部分组成:

1tbsCertificate(to be signed certificate待签名证书内容),这部分包含了10个要素,分别是版本号,序列号,签名算法标识,发行者名称,有效期,证书主体名,证书主体公钥信息,发行商唯一标识,主体唯一标识,扩展等。

2signatureAlgorithm,签名算法标识,指定对tbsCertificate进行签名的算法。

3signaturValue(签名值),使用 signatureAlgorithmtbsCertificate进行计算得到签名值。

数字证书有两个作用:

1、身份授权。确保浏览器访问的网站是经过 CA验证的可信任的网站。

2、分发公钥。每个数字证书都包含了注册者生成的公钥。在 SSL握手时会通过 certificate消息传输给客户端。比如前文提到的 RSA证书公钥加密及 ECDHE的签名都是使用的这个公钥。

申请者拿到CA的证书并部署在网站服务器端,那浏览器发起握手接收到证书后,如何确认这个证书就是 CA签发的呢?怎样避免第三方伪造这个证书?

答案就是数字签名(digitalsignature)。数字签名是证书的防伪标签,目前使用最广泛的 SHA-RSA数字签名的制作和验证过程如下:

1、数字签名的签发。首先是使用哈希函数对待签名内容进行安全哈希,生成消息摘要,然后使用 CA自己的私钥对消息摘要进行加密。

2、数字签名的校验。使用 CA的公钥解密签名,然后使用相同的签名函数对待签名证书内容进行签名并和服务端数字签名里的签名内容进行比较,如果相同就认为校验成功。

8数字签名生成及校验

这里有几点需要说明:

数字签名签发和校验使用的密钥对是CA自己的公私密钥,跟证书申请者提交的公钥没有关系。数字签名的签发过程跟公钥加密的过程刚好相反,即是用私钥加密,公钥解密。现在大的 CA都会有证书链,证书链的好处一是安全,保持根 CA的私钥离线使用。第二个好处是方便部署和撤销,即如果证书出现问题,只需要撤销相应级别的证书,根证书依然安全。 CA证书都是自签名,即用自己的公钥和私钥完成了签名的制作和验证。而证书链上的证书签名都是使用上一级证书的密钥对完成签名和验证的。怎样获取根 CA和多级 CA 的密钥对?它们是否可信?当然可信,因为这些厂商跟浏览器和操作系统都有合作,它们的公钥都默认装到了浏览器或者操作系统环境里。比如firefox就自己维护了一个可信任的 CA列表,而chrome IE 使用的是操作系统的 CA列表。 4.3 数据完整性

这部分内容比较好理解,跟平时的md5签名类似,只不过安全要求要高很多。openssl现在使用的完整性校验算法有两种:MD5或者 SHA。由于 MD5在实际应用中存在冲突的可能性比较大,所以尽量别采用 MD5来验证内容一致性。SHA也不能使用 SHA0 SHA1,中国山东大学的王小云教授在 2005年就宣布破解了 SHA-1完整版算法。

微软和google都已经宣布16 年及 17 年之后不再支持sha1签名证书。

5 HTTPS 使用成本

HTTPS 目前唯一的问题就是它还没有得到大规模应用,受到的关注和研究都比较少。至于使用成本和额外开销,完全不用太过担心。

一般来讲,使用HTTPS前大家可能会非常关注如下问题:

1、证书费用以及更新维护。大家觉得申请证书很麻烦,证书也很贵,可是证书其实一点都不贵,便宜的一年几十块钱,最多也就几百。而且现在也有了免费的证书机构,比如著名的 mozilla发起的免费证书项目:let’s encrypthttps://letsencrypt.org/)就支持免费证书安装和自动更新。这个项目将于今年中旬投入正式使用。

数字证书的费用其实也不高,对于中小网站可以使用便宜甚至免费的数字证书服务(可能存在安全隐患),像著名的 verisign公司的证书一般也就几千到几万块一年不等。当然如果公司对证书的需求比较大,定制性要求高,可以建立自己的 CA站点,比如 google,能够随意签发 google相关证书。

2HTTPS降低用户访问速度。HTTPS对速度会有一定程度的降低,但是只要经过合理优化和部署,HTTPS对速度的影响完全可以接受。在很多场景下,HTTPS速度完全不逊于 HTTP,如果使用 SPDYHTTPS的速度甚至还要比 HTTP快。

大家现在使用百度HTTPS安全搜索,有感觉到慢吗?

3HTTPS消耗 CPU 资源,需要增加大量机器。前面介绍过非对称密钥交换,这是消耗 CPU计算资源的大户,此外,对称加解密,也需要 CPU的计算。

同样地,只要合理优化,HTTPS的机器成本也不会明显增加。对于中小网站,完全不需要增加机器也能满足性能需求。

6 后记

国外的大型互联网公司很多已经启用了全站 HTTPS,这也是未来互联网的趋势。国内的大型互联网并没有全站部署 HTTPS,只是在一些涉及账户或者交易的子页面 / 子请求上启用了 HTTPS。百度搜索首次全站部署 HTTPS,对国内互联网的全站 HTTPS进程必将有着巨大的推动作用。

目前互联网上关于HTTPS的中文资料比较少,本文就着重介绍了 HTTPS协议涉及到的重要知识点和平时不太容易理解的盲区,希望能对大家理解 HTTPS协议有帮助。百度 HTTPS性能优化涉及到大量内容,从前端页面、后端架构、协议特性、加密算法、流量调度、架构和运维、安全等方面都做了大量工作。本系列的文章将一一进行介绍。

 

HTTPS对网站性能SEO有哪些影响

1 前言

HTTPS在保护用户隐私,防止流量劫持方面发挥着非常关键的作用,但与此同时,HTTPS也会降低用户访问速度,增加网站服务器的计算资源消耗。

本文主要介绍https对用户体验的影响。

本文最早发表于百度运维部官方博客

2 HTTPS对访问速度的影响

在介绍速度优化策略之前,先来看下HTTPS对速度有什么影响。影响主要来自两方面:

1. 协议交互所增加的网络RTT(round trip time)

2. 加解密相关的计算耗时。

下面分别介绍一下。

2.1 网络耗时增加

由于 HTTPHTTPS都需要DNS解析,并且大部分情况下使用了DNS缓存,为了突出对比效果,忽略主域名的DNS解析时间。

用户使用HTTP协议访问http://www.baidu.com(或者www.baidu.com)时会有如下网络上的交互耗时:

可见,用户只需要完成TCP三次握手建立TCP连接就能够直接发送HTTP请求获取应用层数据,此外在整个访问过程中也没有需要消耗计算资源的地方。

接下来看HTTPS的访问过程,相比HTTP要复杂很多,在部分场景下,使用HTTPS访问有可能增加7RTT。如下图:

HTTPS首次请求需要的网络耗时解释如下:

1. 三次握手建立TCP连接。耗时一个RTT

2. 使用HTTP发起GET请求,服务端返回302跳转到https://www.baidu.com。需要一个RTT以及302跳转延时。

a) 大部分情况下用户不会手动输入https://www.baidu.com来访问HTTPS,服务端只能返回302强制浏览器跳转到https

b) 浏览器处理302跳转也需要耗时。

3. 三次握手重新建立TCP连接。耗时一个RTT

a) 302跳转到HTTPS服务器之后,由于端口和服务器不同,需要重新完成三次握手,建立TCP连接。

4. TLS完全握手阶段一。耗时至少一个RTT

a) 这个阶段主要是完成加密套件的协商和证书的身份认证。

b) 服务端和浏览器会协商出相同的密钥交换算法、对称加密算法、内容一致性校验算法、证书签名算法、椭圆曲线(ECC算法不需要)等。

c) 浏览器获取到证书后需要校验证书的有效性,比如是否过期,是否撤销。

5. 解析CA站点的DNS。耗时一个RTT

a) 浏览器获取到证书后,有可能需要发起OCSP或者CRL请求,查询证书状态。

b) 浏览器首先获取证书里的CA域名。

c) 如果没有命中缓存,浏览器需要解析CA域名的DNS

6. 三次握手建立CA站点的TCP连接。耗时一个RTT

a) DNS解析到IP后,需要完成三次握手建立TCP连接。

7. 发起OCSP请求,获取响应。耗时一个RTT

8. 完全握手阶段二,耗时一个RTT及计算时间。

a) 完全握手阶段二主要是密钥协商。

9. 完全握手结束后,浏览器和服务器之间进行应用层(也就是HTTP)数据传输。

当然不是每个请求都需要增加7RTT才能完成HTTPS首次请求交互。大概只有不到0.01%的请求才有可能需要经历上述步骤,它们需要满足如下条件:

1. 必须是首次请求。即建立TCP连接后发起的第一个请求,该连接上的后续请求都不需要再发生上述行为。

2. 必须要发生完全握手,而正常情况下80%的请求能实现简化握手。

3. 浏览器需要开启OCSP或者CRL功能。Chrome默认关闭了ocsp功能,firefoxIE都默认开启。

4. 浏览器没有命中OCSP缓存。Ocsp一般的更新周期是7天,firefox的查询周期也是7天,也就说是7天中才会发生一次ocsp的查询。

5. 浏览器没有命中CA站点的DNS缓存。只有没命中DNS缓存的情况下才会解析CADNS

2.2 计算耗时增加

上节还只是简单描述了HTTPS关键路径上必须消耗的纯网络耗时,没有包括非常消耗CPU资源的计算耗时,事实上计算耗时也不小(30ms以上),从浏览器和服务器的角度分别介绍一下:

1浏览器计算耗时

a) RSA证书签名校验,浏览器需要解密签名,计算证书哈希值。如果有多个证书链,浏览器需要校验多个证书。

b) RSA密钥交换时,需要使用证书公钥加密premaster。耗时比较小,但如果手机性能比较差,可能也需要1ms的时间。

c) ECC密钥交换时,需要计算椭圆曲线的公私钥。

d) ECC密钥交换时,需要使用证书公钥解密获取服务端发过来的ECC公钥。

e) ECC密钥交换时,需要根据服务端公钥计算master key

f) 应用层数据对称加解密。

g) 应用层数据一致性校验。

2服务端计算耗时

a) RSA密钥交换时需要使用证书私钥解密premaster。这个过程非常消耗性能。

b) ECC密钥交换时,需要计算椭圆曲线的公私钥。

c) ECC密钥交换时,需要使用证书私钥加密ECC的公钥。

d) ECC密钥交换时,需要根据浏览器公钥计算共享的master key

e) 应用层数据对称加解密。

f) 应用层数据一致性校验。

由于客户端的CPU和操作系统种类比较多,所以计算耗时不能一概而论。手机端的HTTPS计算会比较消耗性能,单纯计算增加的延迟至少在50ms以上。PC端也会增加至少10ms以上的计算延迟。

服务器的性能一般比较强,但由于RSA证书私钥长度远大于客户端,所以服务端的计算延迟也会在5ms以上。

 

 

站点采用HTTPS协议的利弊分析、及SEO建议

站长之家(Chinaz.com)注:本文作者为Moz网站专栏作家Cyrus Shepard,是一篇关于“HTTPS站点优化建议及技巧的分享型文章。文章写于谷歌宣布将“HTTPS协议作为搜索引擎排名参考因素后。

谷歌几乎没有明确对外公开过影响谷歌搜索引擎排名的因素具体有哪些,因而当其在去年8月份宣布采用“HTTPS加密协议有利于搜索引擎排名时,我的心情就两字儿:震惊!

HTTPS与其他的谷歌参考因素不同,实行起来比较复杂,有一定的风险性,而且还需一些额外的费用。但利益也是显而易见的,使用HTTPS协议的站点更安全、且在搜索排名上更具优势。

Moz网站20149月份的调查数据显示:17.24%的站长表示其网站已采用HTTPS协议;24.9%的站长表示正在搭建中;57.85%的站长表示目前仍无此项计划。

如下图:

虽然大部分站长仍无转向HTTPS阵营的打算,但相比之前的情况已有提升。看来,谷歌的算法更新对站长们还是很有震慑力的。

采用HTTPS协议对SEO有何好处?

除了安全性更高这一好处外,HTTPSSEO也是有一定益处的。

1、使用HTTPS协议有利于搜索引擎排名

去年8月份,谷歌曾发布公告表示将把是否使用安全加密协议(即HTTPS作为搜索引擎排名的一项参考因素。同等情况下,HTTPS站点能比HTTP站点获得更好的搜索排名。

不过得说明下,影响谷歌搜索引擎排名的因素已有逾200项,因而HTTPS协议的影响到底几何目前尚不清楚。

因而,与其他谷歌排名影响因素一样的是,HTTPS协议也并非独立存在的。

建议:

如果只是为了搜索引擎排名的话,那有很多因素的影响力比HTTPS协议大。

如下图(14个影响力大于HTTPS协议的影响因素):

更多影响因素可查看:影响谷歌搜索引擎排名的因素调查(完整版)

2、安全隐私

不少站长都认为,只有诸如电子商务、金融、社交网络等存在敏感信息安全问题的站点才有采用HTTPS协议的必要,其实不然。任何类型的站点都可以从中获益。

1)使用HTTPS协议可认证用户和服务器,确保数据发送到正确的客户机和服务器;

2HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全,可防止数据在传输过程中不被窃取、改变,确保数据的完整性。

3HTTPS是现行架构下最安全的解决方案,虽然不是绝对安全,但它大幅增加了中间人攻击的成本。

建议:

在成本费用允许情况下,还是建议站长采用HTTPS加密协议,毕竟网站安全也是用户体验的一个重要环节,而且还有利于搜索引擎排名,何乐而不为呢!

使用HTTPS协议有何挑战?

1、容易忽略的问题

将站点由HTTP转为HTTPS协议涉及到很多问题,有时候会忽略了一些重要的细节问题:

1robots.txt文件中是否屏蔽了重要的URL链接?

2Canonical标签指向的URL是否正确?

3)当用户访问你的网站时,是否会出现浏览器安全警告提示窗口?(出现安全警告提示可能会吓走用户)

虽然概率很小,但这几个问题还是可能出现的。

2、网站加载速度问题

HTTPS协议的握手过程比较费时,对网站的响应速度有负面影响。据ACM CoNEXT数据显示,使用HTTPS协议很可能会使页面的加载时间延长近50%。而网站加载速度也是影响搜索引擎排名的一个很重要的因素。

不过,还是可以通过一些技巧来减少这个问题的。比如,压缩文本内容可以降低解码耗用的CPU资源。实际上,建立HTTPS连接,要求额外的TCP往返,因此会新增一些发送和接收的字节,但这是第一次打开网页时的情况。

3、成本

据数据显示,很多站长每年花在SSL证书上的费用在100美元-200美元之间,这对于个人博客、或是小型站点来说是一笔不小的开支。不过,现在网上也有不少免费SSL证书,可查看:

WoSign沃通SSL证书免费申请及账户设置教程

CloudFlare SSLWosign沃通SSL申请开通和安装使用

2014美国主机网站域名 SSL证书使用的七点总结

如何购买廉价SSL证书

详解HTTPSSSL证书申请、站点搭建等

4HTTPS兼容性问题

这里所说得兼容性包括很多方面,比如现有的Web应用要尽可能无缝地迁移到HTTPS、浏览器对HTTPS的兼容性问题、HTTPS协议解析以及SSL证书管理等。

5、更多问题

如果你的网站依靠AdSense获得收入的话,那么转型HTTPS站点可能会使得收入大幅下降(谷歌对广告源采用SSL协议的站点有所限制)。

此外,即使是谷歌管理员工具也尚不支持HTTPS站点的迁移工作。要完成SSL加密的全球化,需要的不止是时间,还少不了各方的努力啊。

使用HTTPS协议的站点数量增长情况

如今,越来越多的站点采用了HTTPS协议,不过大多用于登陆页面、或是存在交易信息的页面,很少网站选择全站采用HTTPS协议。

Builtwith调查数据显示,在排名TOP10000的网站中,只有4.2%的站点默认使用HTTPS加密访问模式。再将范围放大到TOP100万个网站,这个百分比则降到了1.9%

如下图:

不过,随着谷歌和百度等搜索引擎对HTTPS协议的优待,这个百分比未来应该会有所上升。

HTTPS站点的SEO自检清单

1、确保网站的每个元素(包括插件、JSCSS文件、图片、内容分发网站等)都采用HTTPS协议;

2、使用301重定向将HTTP URL指向HTTPS版地址。记住别误用302跳转;

3、保证Canonical标签指向HTTPSURL

·  再谈Canonical标签:与301有何区别?

·  canonical标签介绍

4、采用HTTPS协议后,应确保网站内链指向的是HTTPSURL,而非旧版URL。这对用户体验以及网站优化而言,都是一个很重要的步骤。

5、在谷歌、必应等平台上的管理员工具中监控HTTPS版本站点;

6、使用谷歌管理员工具中Fetch&Render功能(http://googlewebmastercentral.blogspot.com/2014/05/rendering-pages-with-fetch-as-google.html),确保你的HTTPS站点能够正常的被谷歌抓取;

7、更新网站sitemaps,并在谷歌管理员工具中提交新版sitemaps

8、更新robots.txt文件,加入新版sitemaps内容,确保重要的HTTPS版页面不会被屏蔽;

9、如有必要,还应该更新网站的分析跟踪代码。现在已经有很多新的谷歌分析代码段都能够处理HTTPS站点了。

10、采用HSTS协议(HTTP严格传输安全协议),其作用是强制客户端(如浏览器)使用HTTPS与服务器建立连接。可在保证安全性的前提下,提高网站的响应速度。

 

 

Apache全局/局部https访问配置方法

一、全局https访问

1.找到apache安装目录的httpd.conf配置文件,进行一下操作:

2.#LoadModule rewrite_module modules/mod_rewrite.so(把代码前面的#号去掉,如果没有这个模块,请加上);

3.在httpd.conf加入代码:

RewriteEngine on

RewriteCond %{SERVER_PORT}!^443$

RewriteRule ^(.*)?$ https://%{SERVER_NAME}$1[L,R]

重启apache即可。

二、指定路径访问使用https访问

1.在httpd.conf加入代码:

RewriteEngineon
RewriteBase /test
RewriteCond %{SERVER_PORT} !^443$
RewriteRule ^.*$ https://%{SERVER_NAME}%{REQUEST_URI} [L,R]

2.重启apache即可。

 

 

 

性能测试简介

即压力测试,就是根据一定数量的VUVirtualUsers)我称为并发用户操作核心交易后,系统所能达到的最大瓶劲,以便于发现系统的极限、有没有Outofmemory这样的问题存在以及相关的系统设置、配置是否搭挡的合理的一种测试。

一般商业的比较好的用LoaderRunner,如果没钱的就用OpensourceJmeter来模拟这个VU的操作。

压力测试,存在几个误区,需要小心。

1  无限大的拼命增加VU的数量

系统再完美,硬件配置再高,也经不住没有经过合理运算的VU的压力呀。

2  偏执的用一定的数据量的VU,跑7*24小时

不是说这个没必要,很有必要,小日本的电视为什么寿命敢说比中国人生产的电视机寿命长?因为它用一个机械臂就对着电视机的按钮不断的点点点。

我们说的压力测试要测试多长时间,关键是要看经过科学计算的VU的数量以及核心交易数有多少,不是说我拿250VU24*7如果没有问题我这个系统就没有问题了,这样的说法是不对的,错误的。随便举个例子就能把你推倒。

假设我有250VU,同时跑上万笔交易,每个VU都有上万笔交易,250VU一次跑下来可能就要数个小时,你又怎么能断定250VU对于这样的系统我跑24*7小时就能真的达到上万笔交易在250VU的并发操作下能够真的跑完7天的全部交易?可能需要一周半或者两周呢?对吧?

我还看到过有人拿500VU对着一条交易反复跑24*7小时。。。这样的测试有意义吗?你系统就仅仅只有一条交易?你怎么能够判断这条交易涉及到的数据量最大?更不用说交易是彼此间有依赖的,可能a+b+c+d的交易的一个混合组织就能够超出你单笔交易所涉及到的数据量了呢!

2.2 合理的制定系统最大用户、并发用户

提供下面这个公式,以供大家在平时或者日常需要进行的性能测试中作为一个参考。

1        计算平均的并发用户数:C = nL/T

公式(1)中,C是平均的并发用户数;nlogin session的数量;Llogin session的平均长度;T指考察的时间段长度。

2        并发用户数峰值:C’ ≈ C+3根号C

公式(2)则给出了并发用户数峰值的计算方式中,其中,C’指并发用户数的峰值,C就是公式(1)中得到的平均的并发用户数。该公式的得出是假设用户的loginsession产生符合泊松分布而估算得到的。

实例:

假设有一个OA系统,该系统有3000个用户,平均每天大约有400个用户要访问该系统,对一个典型用户来说,一天之内用户从登录到退出该系统的平均时间为4小时,在一天的时间内,用户只在8小时内使用该系统。

则根据公式(1)和公式(2),可以得到:

C =400*4/8 = 200

C’≈200+3*根号200 = 242

F=VU * R / T

其中F为吞吐量,VU表示虚拟用户个数,R表示每个虚拟用户发出的请求数,T表示性能测试所用的时间

R = T /TS

2.3 影响和评估性能的几个关键指标

从上面的公式一节中我们还得到了一个名词吐吞量。和吞吐量相关的有下面这些概念,记录下来以供参考。

²  吞吐量

指在一次性能测试过程中网络上传输的数据量的总和。

对于交互式应用来说,吞吐量指标反映的是服务器承受的压力,在容量规划的测试中,吞吐量是一个重点关注的指标,因为它能够说明系统级别的负载能力,另外,在性能调优过程中,吞吐量指标也有重要的价值。

²  吞吐率

单位时间内网络上传输的数据量,也可以指单位时间内处理客户请求数量。它是衡量网络性能的重要指标,通常情况下,吞吐率用字节数/来衡量,当然,你可以用请求数/页面数/来衡量。其实,不管是一个请求还是一个页面,它的本质都是在网络上传输的数据,那么来表示数据的单位就是字节数。

²  事务

就是用户某一步或几步操作的集合。不过,我们要保证它有一个完整意义。比如用户对某一个页面的一次请求,用户对某系统的一次登录,淘宝用户对商品的一次确认支付过程。这些我们都可以看作一个事务。那么如何衡量服务器对事务的处理能力。又引出一个概念----TPS

²  TPS (Transaction Per second)

每秒钟系统能够处理事务或交易的数量,它是衡量系统处理能力的重要指标。

²  点击率(Hit PerSecond

点击率可以看做是TPS的一种特定情况。点击率更能体现用户端对服务器的压力。TPS更能体现服务器对客户请求的处理能力。

每秒钟用户向web服务器提交的HTTP请求数。这个指标是web应用特有的一个指标;web应用是请求-响应模式,用户发一个申请,服务器就要处理一次,所以点击是web应用能够处理的交易的最小单位。如果把每次点击定义为一个交易,点击率和TPS就是一个概念。容易看出,点击率越大。对服务器的压力也越大,点击率只是一个性能参考指标,重要的是分析点击时产生的影响。

需要注意的是,这里的点击不是指鼠标的一次单击操作,因为一次单击操作中,客户端可能向服务器发现多个HTTP请求。

²  吞吐量指标的作用:

ü  用户协助设计性能测试场景,以及衡量性能测试场景是否达到了预期的设计目标:在设计性能测试场景时,吞吐量可被用户协助设计性能测试场景,根据估算的吞吐量数据,可以对应到测试场景的事务发生频率,事务发生次数等;另外,在测试完成后,根据实际的吞吐量可以衡量测试是否达到了预期的目标。

ü  用于协助分析性能瓶颈:吞吐量的限制是性能瓶颈的一种重要表现形式,因此,有针对性地对吞吐量设计测试,可以协助尽快定位到性能冰晶所在位置。

²  平均相应时间

也称为系统响应时间,它一般指在指定数量的VU情况下,每笔交易从mouseclickIE的数据刷新与展示之间的间隔,比如说:250VU下每笔交易的响应时间不超过2秒。

当然,响应时间也不能一概而论,对于实时交易如果银行柜台操作、超市收银员(邪恶的笑。。。)的操作、证交所交易员的操作来说这些操作的响应时间当然是越快越好,而对于一些企业级的如:

与银行T+1交易间的数据跑批、延时交易、T+1报表等,你要求它在2秒内响应,它也做不到啊。就好比你有个1MB的带宽,你传的东西是超过4MB,你要它在2秒内跑完理论速度也做不到啊,对吧,所以有些报表或者数据,光前面传输时间就不止两秒了。。。一口咬死说我所有的交易平均相应时间要2秒,真的是不科学的!

2.4 合理的性能测试

²  VU数量的增加

一个合理的性能测试除了需要合理的计算VU的数量、合理的设置系统平均响应时间外还需要合理的在测试时去规划发起VU的时间,比如说,我看到有人喜欢这样做压力测试。

第一秒时间,500个并发用户全部发起了。。。结果导致系统没多久就崩了,然后说系统没有满足设计要求。

为什么说上述这样的做法是不对的?我们说不是完全不对,只能说这样的测试已经超过了500VU的并发的设计指标了。

合理的并发应该是如下这样的:

25-50VU开始起交易了,然后过一段时间又有25-50个用户,过一段时间又增加一些VU,当所有的设计VU都发起交易了,此时,再让压力测试跑一段时间比如说:24*7是比较合理的。所以VU数量不是一上手就500个在一秒内发起的,VU数量的增加应该如下面这张趋势图:



这是一个阶梯状的梯型图,可以看到VU的发起是逐渐逐渐增多的,以下两种情况如果发生需要检查你的系统是否在原有设置上存在问题:

ü  VU数量上升阶段时崩溃

有时仅仅在VU数量上升阶段,系统就会了现各种各样的错误,甚至有崩溃者,这时就有重新考虑你的系统是否有设置不合理的地方了。

ü  VU全部发起后没多久系统崩溃

VU在达到最高值时即所有的VU都已经发起了,此时它是以一条直的水平线随着系统运行而向前延伸着的,但过不了多久,比如说:运行24*7小时,运行了没一、两天,系统崩溃了,也需要做检查。

所以,理想的性能测试应该是VU数量上升到最终VU从发起开始到最后所有VU把交易做完后,VU数量落回零为止。

²  吐吞量的变化

2.3节我们可以知道,吞吐量是随着压力/性能测试的时间而逐渐增大的,因此你的吞吐量指示应该如下图所示:



肯定是这样,你的吞吐量因该是积累的,如果你的吞吐量在上升了一段时间后突然下落,而此时你的性能测试还在跑着,如下图所示:



那么,此时代表什么事情发生了?你可以查一下你的loaderrunner或者jmeter里对于这段吞吐量回落期间的交易的response的状态进行查看,你将会发现大量的error已经产生,因为产生了error,所以你的交易其实已经出错了,因此每次运行的数据量越来越小,这也就意味着你的压力测试没有过关,系统被你压崩了!

²  平均响应时间

平均响应时间如VU的数量增加趋势图一样,一定是一开始响应时间最短,然后一点点增高,当增高到一定的程度后,即所有的VU都发起交易时,你的响应时间应该维持在一个水平值,然后随着VU将交易都一笔笔做完后,这个响应时间就会落下来,这段时间内的平均值就是你的系统平均响应时间。看看它,有没有符合设计标准?

²  内存监控

我们就来说AppServer,我们这边用的是TomcatSUNJVM的内存变化,我们就用两张图例来讲解吧:

理想状态情况下的JVM内存使用趋势:



这是一个波浪型的(或者也可以说是锯齿型的)趋势图,随着VU数量的一点点增加,我们的内存使用数会不断的增加,但是JVM的垃圾回收是自动回收机制的,因此如果你的JVM如上述样的趋势,内存上涨一段时间,随即会一点点下落,然后再上涨一点,涨到快到头了又开始下落,直到最后你的VU数量全部下降下来时,你的JVM的内存使用也会一点点的下降。

非理想状态情况下的JVM内存使用趋势:



嘿嘿嘿,看到了吗?你的JVM随着VU数量的上升,而直线上升,然后到了一定的点后,即到了Java –Xmx后的那个值后,突然直线回落,而此时你的交易还在进行,压力测试也还在进行,可是内存突然回落了。。。因为你的JVM已经crash了,即OUT OF MEMORY鸟。

²  CPU Load

我们来看一份测试人员提交上来CPU得用率的报告:

Web Server

App Server

DB Server

60%

98%

=_=!(oh my god)

6%

同时平均响应时间好慢啊。

拿过来看了一下代码与设计。。。Struts+spring+JDBC的一个框架,没啥花头的,再仔细一看Service层。

大量的复杂业务逻辑甚至报表的产生全部用的是javaobject:List, Hashmap等操作,甚至还有在Service层进行排序、复杂查询等操作。

一看DB层的CPU利用率才6%,将一部分最复杂的业务拿出去做成StoreProcedure(存储过程后),再重新运行压力测试。

Web Server

App Server

DB Server

60%

57%

=_=!(oh my god)

26%

同时平均响应时间比原来快了15-16倍。

为什么??

看看第一份报告,我们当时还查看了数据库服务器的配置,和APPServer的配置是一个级别的,而利用率才6%。。。

数据库,至所以是大型的商用的关系型数据库,你只拿它做一个存储介质,你这不是浪费吗?人家里面设置的这个StoreProcedure的处理能力,索引效率,数据分块等功能都没有去利用,而用你的代码去实现那么多复杂业务比如说多表关联、嵌套等操作,用必要吗?那要数据库干什么用呢?

是啊,我承认,原有这样的代码,跨平台能力强一点,可付出的代价是什么呢?

用户在乎你所谓的跨平台的理论还是在乎的是你系统的效率?一个系统定好了用DB2或者是SQL SERVER,你觉得过一年它会换成ORACLE或者MySQL吗?如果1年一换,那你做的系统也只能让用户勉强使用一年,我劝你还是不要去做了。在中国,有人统计过5年左右会有一次系统的更换,而一些银行、保险、金融行业的系统一旦采用了哪个数据库,除非这个系统彻底出了问题,负责是不会轻意换数据库的,因此不要拿所谓的纯JAVA代码或者说我用的是hibernate,ejb实现可以跨数据库这套来说事,效率低下的系统可以否定你所做的一切,一切!

三、Apache服务器的优化

上面两节,讲了大量的理论与实际工作中碰到的相关案例,现在就来讲一下在我们第一天和第二天中的ApacheHttpServer + Tomcat这样的架构,怎么来做优化吧。

3.1 Linux/UnixLinux系统下Apache并发数的优化

ApacheHttp Server在刚安装完后是没有并发数的控制的,它采用一个默认的值,那么我们的Web Server硬件很好,允许我们撑到1000个并发即VU而因为我们没有去配置导致我们的WebServer300个并发都撑不到,你们认为,这是谁的责任?

ApacheHttp服务器采用prefork或者是worker两种并发控制模式。

² preforkMPM

使用多个子进程,每个子进程只有一个线程。每个进程在某个确定的时间只能维持一个连接。在大多数平台上,PreforkMPM在效率上要比Worker MPM要高,但是内存使用大得多。prefork的无线程设计在某些情况下将比worker更有优势:它可以使用那些没有处理好线程安全的第三方模块,并且对于那些线程调试困难的平台而言,它也更容易调试一些。

² workerMPM 使用多个子进程,每个子进程有多个线程。每个线程在某个确定的时间只能维持一个连接。通常来说,在一个高流量的HTTP服务器上,Worker MPM是个比较好的选择,因为Worker MPM的内存使用比PreforkMPM要低得多。但worker MPM也由不完善的地方,如果一个线程崩溃,整个进程就会连同其所有线程一起"死掉".由于线程共享内存空间,所以一个程序在运行时必须被系统识别为"每个线程都是安全的"

一般来说我们的ApacheHttp Server都是装在Unix/Linux下的,而且是采用源码编译的方式来安装的,我们能够指定在编译时Apache就采用哪种模式,为了明确我们目前的Apache采用的是哪种模式在工作,我们还可以使用httpd–l命令即在Apachebin目录下执行httpd –l,来确认我们使用的是哪种模式。

这边,我们使用Apache配置语言中的” IfModule”来自动选择模式的配置。

我们的ApacheHttp Server在配完后一般是没有这样的配置的,是需要你手动的添加如下这样的一块内容的,我们来看,在httpd.conf文件中定位到最后一行LoadModule,敲入回车,加入如下内容:

<IfModule prefork.c>

ServerLimit  20000

StartServers  5

MinSpareServers  5

MaxSpareServers  10

MaxClients  1000

MaxRequestsPerChild 0

</IfModule>

上述参数解释:

ü   ServerLimit    20000

默认的MaxClient最大是256个线程,如果想设置更大的值,就的加上ServerLimit这个参数。20000ServerLimit这个参数的最大值。如果需要更大,则必须编译apache,此前都是不需要重新编译Apache

生效前提:必须放在其他指令的前面

ü  StartServers  5

指定服务器启动时建立的子进程数量,prefork默认为5

 

ü  MinSpareServers  5

指定空闲子进程的最小数量,默认为5。如果当前空闲子进程数少于MinSpareServers,那么Apache将以最大每秒一个的速度产生新的子进程。此参数不要设的太大。

ü  MaxSpareServers  10

设置空闲子进程的最大数量,默认为10。如果当前有超过MaxSpareServers数量的空闲子进程,那么父进程将杀死多余的子进程。此参数不要设的太大。如果你将该指令的值设置为比MinSpareServers小,Apache将会自动将其修改成"MinSpareServers+1"

ü  MaxClients  256

限定同一时间客户端最大接入请求的数量(单个进程并发线程数),默认为256。任何超过MaxClients限制的请求都将进入等候队列,一旦一个链接被释放,队列中的请求将得到服务。要增大这个值,你必须同时增大ServerLimit

ü  MaxRequestsPerChild10000

每个子进程在其生存期内允许伺服的最大请求数量,默认为10000.到达MaxRequestsPerChild的限制后,子进程将会结束。如果MaxRequestsPerChild"0",子进程将永远不会结束。

MaxRequestsPerChild设置成非零值有两个好处:

1.可以防止(偶然的)内存泄漏无限进行,从而耗尽内存。

2.给进程一个有限寿命,从而有助于当服务器负载减轻的时候减少活动进程的数量。

Prefork.c的工作方式:

一个单独的控制进程(父进程)负责产生子进程,这些子进程用于监听请求并作出应答。Apache总是试图保持一些备用的(spare)或者是空闲的子进程用于迎接即将到来的请求。这样客户端就不需要在得到服务前等候子进程的产生。在Unix系统中,父进程通常以root身份运行以便邦定80端口,而Apache产生的子进程通常以一个低特权的用户运行。UserGroup指令用于设置子进程的低特权用户。运行子进程的用户必须要对它所服务的内容有读取的权限,但是对服务内容之外的其他资源必须拥有尽可能少的权限。

在上述的</IfModule>后再加入一个”<IfModule>”如下红色加粗(大又粗)内容:

<IfModule prefork.c>

ServerLimit  20000

StartServers  5

MinSpareServers  5

MaxSpareServers  10

MaxClients  1000

MaxRequestsPerChild 0

</IfModule>

<IfModule worker.c>

ServerLimit  50

ThreadLimit  200

StartServers  5

MaxClients  5000

MinSpareThreads  25

MaxSpareThreads  500

ThreadsPerChild  100

MaxRequestsPerChild 0

</IfModule>

上述参数解释:

ü  ServerLimit16

服务器允许配置的进程数上限。这个指令和ThreadLimit结合使用设置了MaxClients最大允许配置的数值。任何在重启期间对这个指令的改变都将被忽略,但对MaxClients的修改却会生效。

ü  ThreadLimit64

每个子进程可配置的线程数上限。这个指令设置了每个子进程可配置的线程数ThreadsPerChild上限。任何在重启期间对这个指令的改变都将被忽略,但对ThreadsPerChild的修改却会生效。默认值是"64".

ü  StartServers3

服务器启动时建立的子进程数,默认值是"3"

ü  MinSpareThreads75

最小空闲线程数,默认值是"75"。这个MPM将基于整个服务器监视空闲线程数。如果服务器中总的空闲线程数太少,子进程将产生新的空闲线程。

ü  MaxSpareThreads250

设置最大空闲线程数。默认值是"250"。这个MPM将基于整个服务器监视空闲线程数。如果服务器中总的空闲线程数太多,子进程将杀死多余的空闲线程。MaxSpareThreads的取值范围是有限制的。Apache将按照如下限制自动修正你设置的值:worker要求其大于等于MinSpareThreads加上ThreadsPerChild的和

ü  MaxClients400

允许同时伺服的最大接入请求数量(最大线程数量)。任何超过MaxClients限制的请求都将进入等候队列。默认值是"400",16(ServerLimit)乘以25(ThreadsPerChild)的结果。因此要增加MaxClients的时候,你必须同时增加ServerLimit的值。

ü  ThreadsPerChild25

每个子进程建立的常驻的执行线程数。默认值是25。子进程在启动时建立这些线程后就不再建立新的线程了。

ü  MaxRequestsPerChild  0

设置每个子进程在其生存期内允许伺服的最大请求数量。到达MaxRequestsPerChild的限制后,子进程将会结束。如果MaxRequestsPerChild"0",子进程将永远不会结束。

MaxRequestsPerChild设置成非零值有两个好处:

1.可以防止(偶然的)内存泄漏无限进行,从而耗尽内存。

2.给进程一个有限寿命,从而有助于当服务器负载减轻的时候减少活动进程的数量。

注意

对于KeepAlive链接,只有第一个请求会被计数。事实上,它改变了每个子进程限制最大链接数量的行为。

Worker.c的工作方式:

每个进程可以拥有的线程数量是固定的。服务器会根据负载情况增加或减少进程数量。一个单独的控制进程(父进程)负责子进程的建立。每个子进程可以建立ThreadsPerChild数量的服务线程和一个监听线程,该监听线程监听接入请求并将其传递给服务线程处理和应答。Apache总是试图维持一个备用(spare)或是空闲的服务线程池。这样,客户端无须等待新线程或新进程的建立即可得到处理。在Unix中,为了能够绑定80端口,父进程一般都是以root身份启动,随后,Apache以较低权限的用户建立子进程和线程。UserGroup指令用于设置Apache子进程的权限。虽然子进程必须对其提供的内容拥有读权限,但应该尽可能给予它较少的特权。另外,除非使用了suexec,否则,这些指令设置的权限将被CGI脚本所继承。

公式:

ThreadLimit>=ThreadsPerChild

MaxClients <= ServerLimit * ThreadsPerChild  必须是ThreadsPerChild的倍数

MaxSpareThreads>=MinSpareThreads+ThreadsPerChild

硬限制:

ServerLimiThreadLimit这两个指令决定了活动子进程数量和每个子进程中线程数量的硬限制。要想改变这个硬限制必须完全停止服务器然后再启动服务器(直接重启是不行的)

Apache在编译ServerLimit时内部有一个硬性的限制,你不能超越这个限制。

preforkMPM最大为"ServerLimit200000"

其它MPM(包括work MPM)最大为"ServerLimit 20000

Apache在编译ThreadLimit时内部有一个硬性的限制,你不能超越这个限制。

mpm_winnt"ThreadLimit 15000"

其它MPM(包括work prefork)"ThreadLimit 20000

注意

使用ServerLimitThreadLimit时要特别当心。如果将ServerLimitThreadLimit设置成一个高出实际需要许多的值,将会有过多的共享内存被分配。当设置成超过系统的处理能力,Apache可能无法启动,或者系统将变得不稳定。

3.2 WindowsWindows系统下Apache并发数的优化

以上是Linux/Unix下的Apache的并发数优化配置,如果我们打入了httpd–l如下显示:

怎么办?

ü  步骤一

先修改/path/apache/conf/httpd.conf文件。

httpd.conf

“#Includeconf/extra/httpd-mpm.conf”前面的 “#”去掉,保存。

ü  步骤二

再修改/apache安装目录/conf/extra/httpd-mpm.conf文件。

mpm_winnt模式下,Apache不使用prefork也不使用work工作模式,切记!

因此,我们只要找到原文件中:

<IfModule mpm_winnt_module>

    ThreadsPerChild      150

    MaxRequestsPerChild    0

</IfModule>

修改后

<IfModule mpm_winnt_module>

    ThreadsPerChild      500

    MaxRequestsPerChild    5000

</IfModule>

上述参数解释:

ü  ThreadsPerChild

是指一个进程最多拥有的线程数(Windows版本,貌似不可以开启多个进程),一般100-500就可以,根据服务器的具体性能来决定。

ü  MaxRequestsPerChild

是指一个线程最多可以接受的连接数,默认是0,就是不限制的意思,

0极有可能会导致内存泄露。所以,可以根据实际情况,配置一个比较大的值。Apache会在几个线程之间进行轮询,找到负载最轻的一个线程来接受新的连接。

注意:

修改后,一定不要apacherestart,而是先 apache stop然后再 apache start才可以。

3.3 启用服务端图片压缩

对于静态的html 文件,在apache 可加载mod_deflate.so 模块,把内容压缩后输出,可节约大量的传输带宽。

打开httpd.conf文件,找到:

#LoadModule deflate_module modules/mod_deflate.so

将前面的“#”去掉,变成:

LoadModule deflate_module modules/mod_deflate.so

然后在最后一行的LoadModule处,加入如下的几行:

<IfModule mod_deflate.c>

 DeflateCompressionLevel 7

 AddOutputFilterByType DEFLATE text/html text/plain text/xml application/x-httpd-PHP

 AddOutputFilter DEFLATE css js

</IfModule>

注意:

默认等级是6,而且9级需要更多的CPU时间,用默认的6级就可以了。

要注意的是,apache 2.2.15,我用httpd -l,居然发现mod_deflat已经内置了,所以其实就不用再在httpd.conf中增加loadmodule,否则会说出错的

3.4 Apache中将MS办公文档自动关联客户端的MS-Office

我们经常会在web页的一个超链接上点一个指向物理文件的文档,我们一般会得到保存,另存为,打开3个选项,当我们打开的如果是一个MS文档,在选打开选项时IE会自动启用客户端上装有的word或者是excel等相关MS办公工具去打开,这个怎么做呢?很简单。

打开httpd.conf,找到:

    AddType application/x-compress .Z

    AddType application/x-gzip .gz .tgz

在其后敲入一个回车,加入:

AddType application/vnd.openxmlformats  docx pptx xlsx doc xls ppt txt

重启Apache服务即可。

3.5 防止DDOS攻击

DDOS攻击即采用自动点击机器人或者连续点击工具不断的刷新某一个网址或者网页上的按钮,造成网站在一时间收到大量的HTTP请求,进而阻塞网站正常的HTTP通道甚至造成网站瘫痪。



为了防止这一形式的攻击,我们一般把在一个按钮或者是一个请求在一秒内连续执行如:100次,可以认为是一种攻击(比如说你打开一个网页,点一下提交按钮,然后按住F5键不松开)。

Linux下的Apache HttpServer安装后会提供一个mod_evasive20的模块,用于防止这一形式的攻击,它的做法是:

如果认为是一个DDOS攻击,它的防范手段采用如下两种形势:

ü  把这个请求相关联的IP,封锁30分钟

ü  直接把相关的IP踢入黑名单,让其永不翻身

设置:

在你的Apachehttpd.conf文件中的最后一行“LoadModule”加入如下这句:

LoadModule evasive20_module   /usr/lib/httpd/modules/mod_evasive20.so

然后加入下面这几行

<IfModule mod_evasive20.c>

DOSHashTableSize 3097

DOSPageCount 15

DOSSiteCount 100

DOSPageInterval 1

DOSSiteInterval 1

DOSBlockingPeriod 36000

DOSEmailNotify 网站超级管理员@xxx.com

DOSLogDir "logs/mod_evasive"

</IfModule>

核心参数解释:

ü  DOSHashTableSize3097 记录黑名单的尺寸

ü  DOSPageCount 每个页面被判断为dos攻击的读取次数

ü  DOSSiteCount 每个站点被判断为dos攻击的读取部件(object)的个数

ü  DOSPageInterval 读取页面间隔秒

ü  DOSSiteInterval 读取站点间隔秒

ü  DOSBlockingPeriod 被封时间间隔秒

注意:

上述设置是针对Linux/Unix下的Apache Server,相关的Windows下的Apache见如下设置:

Windows下的Apache加载mod_evasive模块

1. 下载附件中的压缩包,解压并拷贝mod_dosevasive22.dllApache安装目录下的modules目录(当然也可以是其他目录,需要自己修改路径)。

2. 修改Apache的配置文件http.conf

添加以下内容

LoadModule dosevasive22_module modules/mod_dosevasive22.dll

DOSHashTableSize 3097

DOSPageCount 3

DOSSiteCount 50

DOSPageInterval 1

DOSSiteInterval 1

DOSBlockingPeriod 10

3.6 Apache中设置URL含中文附件的下载/打开的方法(仅限Linux系统下)

这个话题很有趣,起因是我们在工程中碰到了客户这样的一个需求:

<ahref=”xxx.xxx.xx/xx/xxx/轮胎损坏情况2007-05-05.jpg”>损坏部件</a>

看看好像没啥问题,一点这个超链接,因该是在IE中打开一个叫轮胎损坏情况2007-05-05.jpg”,嘿嘿,大家自己动手放一个带有中文名的这样的一个图片,看看能否被解析,解析不了。

所以我们就说,真奇怪,我们上传图片都是上传时的图片名经上传组件解析过以后变成一个UUID或者是GUID一类的文件名如:gb19070122abcxd.jpg这样一种英文加数字组合的文件名,这样的文件名,Apache当然是可以解析的,客户坚持一定我上传的图片是中文名(连中文描述都不行),因为,客户说:我们是中国人,当然用中文图片名。。。

没办法,找了半天,找到一篇日文的教程,还好还好,N年前学过一点点日语,照着教程把它啃下来了。

这是一个日本人写的关于在Apache中支持以亚州文字命名文件名的一个补丁,叫“mod_encoding”

相关配置:

1.       下载完后是一个这样的压缩包:mod_encoding-20021209.tar.gz

2.       解压后使用:

configure

make

make install

make这一行时,编译出错,报“make: *** [mod_encoding.so]Error 1”这样的错

原因很明显,是regex.h未包含进来,解决办法也很简单:

ü  vi打开mod_encoding.c

ü  #include<httpd.h>那一段的前面加上如下一行:

#include<regex.h>然后:

          重新makemake install搞定,CALL!!!

3.       编译后得到一个:mod_encoding.so的文件,然后在httpd.conf文件中加入下面这几行:

LoadModule encoding_module modules/mod_encoding.so

Header add MS-Author-Via "DAV"

<IfModule mod_encoding.c>

  EncodingEngine    on

  NormalizeUsername on

  SetServerEncoding GBK

  DefaultClientEncoding UTF-8 GBK GB2312

  AddClientEncoding "(Microsoft .* DAV $)" UTF-8 GBK GB2312

  AddClientEncoding "Microsoft .* DAV" UTF-8 GBK GB2312

  AddClientEncoding "Microsoft-WebDAV*" UTF-8 GBK GB2312

</IfModule>

4.       重启Apache,搞定,在apache中我们的url可以是中文名的附件了。

3.7 不可忽视的keepalive选项

Apache 服务器中,KeepAlive是一个布尔值,On代表打开,Off 代表关闭,这个指令在其他众多的 HTTPD服务器中都是存在的。

KeepAlive 配置指令决定当处理完用户发起的 HTTP请求后是否立即关闭 TCP连接,如果 KeepAlive设置为On,那么用户完成一次访问后,不会立即断开连接,如果还有请求,那么会继续在这一次 TCP连接中完成,而不用重复建立新的 TCP连接和关闭TCP 连接,可以提高用户访问速度。

那么我们考虑3种情况:

1.用户浏览一个网页时,除了网页本身外,还引用了多个JavaScript 文件,多个css文件,多个图片文件,并且这些文件都在同一个HTTP服务器上。

2.用户浏览一个网页时,除了网页本身外,还引用一个javascript文件,一个图片文件。

3.用户浏览的是一个动态网页,由程序即时生成内容,并且不引用其他内容。

对于上面3中情况,我认为:1最适合打开 KeepAlive2 随意,3最适合关闭 KeepAlive

 下面我来分析一下原因。

 在Apache中,打开和关闭 KeepAlive功能,服务器端会有什么异同呢?

 先看看理论分析。

打开KeepAlive 后,意味着每次用户完成全部访问后,都要保持一定时间后才关闭会关闭TCP连接,那么在关闭连接之前,必然会有一个Apache进程对应于该用户而不能处理其他用户,假设KeepAlive的超时时间为10 秒种,服务器每秒处理 50个独立用户访问,那么系统中 Apache的总进程数就是 10 * 50 500 个,如果一个进程占用 4M 内存,那么总共会消耗 2G内存,所以可以看出,在这种配置中,相当消耗内存,但好处是系统只处理了 50 TCP的握手和关闭操作。

 

如果关闭KeepAlive,如果还是每秒50个用户访问,如果用户每次连续的请求数为3个,那么 Apache 的总进程数就是 50 * 3= 150个,如果还是每个进程占用 4M内存,那么总的内存消耗为 600M,这种配置能节省大量内存,但是,系统处理了 150 TCP的握手和关闭的操作,因此又会多消耗一些 CPU资源。

再看看实践的观察。

我在一组大量处理动态网页内容的服务器中,起初打开KeepAlive功能,经常观察到用户访问量大时Apache进程数也非常多,系统频繁使用交换内存,系统不稳定,有时负载会出现较大波动。关闭了KeepAlive功能后,看到明显的变化是:Apache的进程数减少了,空闲内存增加了,用于文件系统Cache的内存也增加了,CPU的开销增加了,但是服务更稳定了,系统负载也比较稳定,很少有负载大范围波动的情况,负载有一定程度的降低;变化不明显的是:访问量较少的时候,系统平均负载没有明显变化。

总结一下:

在内存非常充足的服务器上,不管是否关闭KeepAlive功能,服务器性能不会有明显变化;

如果服务器内存较少,或者服务器有非常大量的文件系统访问时,或者主要处理动态网页服务,关闭KeepAlive后可以节省很多内存,而节省出来的内存用于文件系统Cache,可以提高文件系统访问的性能,并且系统会更加稳定。

ü   补充1

关于是否应该关闭 KeepAlive选项,我觉得可以基于下面的一个公式来判断。

  在理想的网络连接状况下,系统的Apache进程数和内存使用可以用如下公式表达:

HttpdProcessNumber= KeepAliveTimeout *TotalRequestPerSecond / Average(KeepAliveRequests)

HttpdUsedMemory= HttpdProcessNumber *MemoryPerHttpdProcess

  换成中文意思:

Apache进程数 = KeepAliveTimeout *每秒种HTTP请求数 /平均KeepAlive请求

Apache占用内存 =Apache进程数 *平均每进程占用内存数

  需要特别说明的是:

[平均KeepAlive请求]数,是指每个用户连接上服务器后,持续发出的 HTTP请求数。当 KeepAliveTimeout 0或者 KeepAlive关闭时,KeepAliveTimeout不参与乘的运算从上面的公式看,如果 [每秒用户请求]多,[KeepAliveTimeout]的值大,[平均KeepAlive请求]的值小,都会造成 [Apache进程数]多和 [内存]多,但是当 [平均KeepAlive请求]的值越大时,[Apache进程数] [内存]都是趋向于减少的。

基于上面的公式,我们就可以推算出当平均KeepAlive请求 <= KeepAliveTimeout时,关闭 KeepAlive选项是划算的,否则就可以考虑打开。

ü   补充2

KeepAlive 该参数控制Apache是否允许在一个连接中有多个请求,默认打开。但对于大多数论坛类型站点来说,通常设置为off以关闭该支持。

ü   补充3

如果服务器前跑有应用squid服务,或者其它七层设备,KeepAlive On设定要开启持续长连接

实际在前端有squid的情况下,KeepAlive很关键。记得On

Keeyalive不能随心所欲设置,而是需要根据实际情况,我们来看一个真实的在我工作中发生的搞笑一次事件:

当时我已经离开该项目了,该项目的TeamLeader看到了keepalive的概念,他只看到了关闭keeyalive可以节省web服务器的内存,当时我们的web服务器只有4gb内存,而并发请求的量很大,因此他就把这个keepalive设成了off

然后直接导致脱机客户端(脱机客户端用的是.net然后webservice连接)的“login”每次都显示出错

一查代码才知道,由于这个脱机客户端使用的是webservice访问,.net开发团队在login功能中设了一个超时,30秒,30timeout后就认为服务器没有开启,结果呢由于原来的apache设的是keeyalivetimeout 15秒,现在被改成了off,好家伙,根本就没有了这个timeout概念,因此每次.net登录直接被apache弹回来,因为没有了这个timeout的接口了。

由此可见,学东西。。。不能一知半解,务必求全面了解哈。

3.8HostnameLookups设置为off

尽量较少DNS查询的次数。如果你使用了任何”Allowfromdomain””Denyfromdomain”指令(也就是domain使用的是主机名而不是IP地址),则代价是要进行两次DNS查询(一次正向和一次反向,以确认没有作假)。所以,为了得到最高的性能,应该避免使用这些指令(不用域名而用IP地址也是可以的)

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值