那么,咱们的Web系统的理论峰值QPS为(理想化的计算方式):php
20*500/0.1 = 100000 (10万QPS)html
咦?咱们的系统彷佛很强大,1秒钟能够处理完10万的请求,5w/s的秒杀彷佛是“纸老虎”哈。实际状况,固然没有这么理想。在高并发的实际场景下,机器都处于高负载的状态,在这个时候平均响应时间会被大大增长。前端
普通的一个p4的服务器天天最多能支持大约10万左右的IP,若是访问量超过10W那么须要专用的服务器才能解决,若是硬件不给力 软件怎么优化都是于事无补的。主要影响服务器的速度mysql
有:网络-硬盘读写速度-内存大小-cpu处理速度。nginx
就Web服务器而言,Apache打开了越多的链接进程,CPU须要处理的上下文切换也越多,额外增长了CPU的消耗,而后就直接致使平均响应时间增长。所以上述的MaxClient数目,要根据CPU、内存等硬件因素综合考虑,绝对不是越多越好。能够经过Apache自带的abench来测试一下,取一个合适的值。而后,咱们选择内存操做级别的存储的Redis,在高并发的状态下,存储的响应时间相当重要。网络带宽虽然也是一个因素,不过,这种请求数据包通常比较小,通常不多成为请求的瓶颈。负载均衡成为系统瓶颈的状况比较少,在这里不作讨论哈。web
那么问题来了,假设咱们的系统,在5w/s的高并发状态下,平均响应时间从100ms变为250ms(实际状况,甚至更多):redis
20*500/0.25 = 40000 (4万QPS)sql
因而,咱们的系统剩下了4w的QPS,面对5w每秒的请求,中间相差了1w。数据库
举个例子,高速路口,1秒钟来5部车,每秒经过5部车,高速路口运做正常。忽然,这个路口1秒钟只能经过4部车,车流量仍然依旧,结果一定出现大塞车。(5条车道突然变成4条车道的感受)apache
同理,某一个秒内,20*500个可用链接进程都在满负荷工做中,却仍然有1万个新来请求,没有链接进程可用,系统陷入到异常状态也是预期以内。
其实在正常的非高并发的业务场景中,也有相似的状况出现,某个业务请求接口出现问题,响应时间极慢,将整个Web请求响应时间拉得很长,逐渐将Web服务器的可用链接数占满,其余正常的业务请求,无链接进程可用。
更可怕的问题是,是用户的行为特色,系统越是不可用,用户的点击越频繁,恶性循环最终致使“雪崩”(其中一台Web机器挂了,致使流量分散到其余正常工做的机器上,再致使正常的机器也挂,而后恶性循环),将整个Web系统拖垮。
3. 重启与过载保护
若是系统发生“雪崩”,贸然重启服务,是没法解决问题的。最多见的现象是,启动起来后,马上挂掉。这个时候,最好在入口层将流量拒绝,而后再将重启。若是是redis/memcache这种服务也挂了,重启的时候须要注意“预热”,而且极可能须要比较长的时间。
秒杀和抢购的场景,流量每每是超乎咱们系统的准备和想象的。这个时候,过载保护是必要的。若是检测到系统满负载状态,拒绝请求也是一种保护措施。在前端设置过滤是最简单的方式,可是,这种作法是被用户“千夫所指”的行为。更合适一点的是,将过载保护设置在CGI入口层,快速将客户的直接请求返回
高并发下的数据安全
咱们知道在多线程写入同一个文件的时候,会存现“线程安全”的问题(多个线程同时运行同一段代码,若是每次运行结果和单线程运行的结果是同样的,结果和预期相同,就是线程安全的)。若是是MySQL数据库,可使用它自带的锁机制很好的解决问题,可是,在大规模并发的场景中,是不推荐使用MySQL的。秒杀和抢购的场景中,还有另一个问题,就是“超发”,若是在这方面控制不慎,会产生发送过多的状况。咱们也曾经据说过,某些电商搞抢购活动,买家成功拍下后,商家却不认可订单有效,拒绝发货。这里的问题,也许并不必定是商家奸诈,而是系统技术层面存在超发风险致使的。
1. 超发的缘由
假设某个抢购场景中,咱们一共只有100个商品,在最后一刻,咱们已经消耗了99个商品,仅剩最后一个。这个时候,系统发来多个并发请求,这批请求读取到的商品余量都是99个,而后都经过了这一个余量判断,最终致使超发。(同文章前面说的场景)
在上面的这个图中,就致使了并发用户B也“抢购成功”,多让一我的得到了商品。这种场景,在高并发的状况下很是容易出现。
优化方案1:将库存字段number字段设为unsigned,当库存为0时,由于字段不能为负数,将会返回false
1 <?php 2
3 //优化方案1:将库存字段number字段设为unsigned,当库存为0时,由于字段不能为负数,将会返回false
4
5 include('./mysql.php'); 6
7 $username = 'wang'.rand(0,1000); 8
9 //生成惟一订单
10
11 function build_order_no(){ 12
13 return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8); 14
15 } 16
17 //记录日志
18
19 function insertLog($event,$type=0,$username){ 20
21 global $conn; 22
23 $sql="insert into ih_log(event,type,usernma) 24
25 values('$event','$type','$username')"; 26
27 return mysqli_query($conn,$sql); 28
29 } 30
31 function insertOrder($order_sn,$user_id,$goods_id,$sku_id,$price,$username,$number) 32
33 { 34
35 global $conn; 36
37 $sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price,username,number) 38
39 values('$order_sn','$user_id','$goods_id','$sku_id','$price','$username','$number')"; 40
41 return mysqli_query($conn,$sql); 42
43 } 44
45 //模拟下单操做 46
47 //库存是否大于0
48
49 $sql="select number from ih_store where goods_id='$goods_id' and sku_id='$sku_id' "; 50
51 $rs=mysqli_query($conn,$sql); 52
53 $row = $rs->fetch_assoc(); 54
55 if($row['number']>0){//高并发下会致使超卖
56
57 if($row['number']<$number){ 58
59 return insertLog('库存不够',3,$username); 60
61 } 62
63 $order_sn=build_order_no(); 64
65 //库存减小
66
67 $sql="update ih_store set number=number-{$number} where sku_id='$sku_id' and number>0"; 68
69 $store_rs=mysqli_query($conn,$sql); 70
71 if($store_rs){ 72
73 //生成订单
74
75 insertOrder($order_sn,$user_id,$goods_id,$sku_id,$price,$username,$number); 76
77 insertLog('库存减小成功',1,$username); 78
79 }else{ 80
81 insertLog('库存减小失败',2,$username); 82
83 } 84
85 }else{ 86
87 insertLog('库存不够',3,$username); 88
89 } 90
91 ?>
解决线程安全的思路不少,能够从“悲观锁”的方向开始讨论。2. 悲观锁思路
悲观锁,也就是在修改数据的时候,采用锁定状态,排斥外部请求的修改。遇到加锁的状态,就必须等待。
虽然上述的方案的确解决了线程安全的问题,可是,别忘记,咱们的场景是“高并发”。也就是说,会不少这样的修改请求,每一个请求都须要等待“锁”,某些线程可能永远都没有机会抢到这个“锁”,这种请求就会死在那里。同时,这种请求会不少,瞬间增大系统的平均响应时间,结果是可用链接数被耗尽,系统陷入异常。
优化方案2:使用MySQL的事务,锁住操做的行
1 <?php 2
3 //优化方案2:使用MySQL的事务,锁住操做的行
4
5 include('./mysql.php'); 6
7 //生成惟一订单号
8
9 function build_order_no(){ 10
11 return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8); 12
13 } 14
15 //记录日志
16
17 function insertLog($event,$type=0){ 18
19 global $conn; 20
21 $sql="insert into ih_log(event,type) 22
23 values('$event','$type')"; 24
25 mysqli_query($conn,$sql); 26
27 } 28
29 //模拟下单操做 30
31 //库存是否大于0
32
33 mysqli_query($conn,"BEGIN"); //开始事务
34
35 $sql="select number from ih_store where goods_id='$goods_id' and sku_id='$sku_id' FOR UPDATE";//此时这条记录被锁住,其它事务必须等待这次事务提交后才能执行
36
37 $rs=mysqli_query($conn,$sql); 38
39 $row=$rs->fetch_assoc(); 40
41 if($row['number']>0){ 42
43 //生成订单
44
45 $order_sn=build_order_no(); 46
47 $sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price) 48
49 values('$order_sn','$user_id','$goods_id','$sku_id','$price')"; 50
51 $order_rs=mysqli_query($conn,$sql); 52
53 //库存减小
54
55 $sql="update ih_store set number=number-{$number} where sku_id='$sku_id'"; 56
57 $store_rs=mysqli_query($conn,$sql); 58
59 if($store_rs){ 60
61 echo '库存减小成功'; 62
63 insertLog('库存减小成功'); 64
65 mysqli_query($conn,"COMMIT");//事务提交即解锁
66
67 }else{ 68
69 echo '库存减小失败'; 70
71 insertLog('库存减小失败'); 72
73 } 74
75 }else{ 76
77 echo '库存不够'; 78
79 insertLog('库存不够'); 80
81 mysqli_query($conn,"ROLLBACK"); 82
83 }
那好,那么咱们稍微修改一下上面的场景,咱们直接将请求放入队列中的,采用FIFO(First Input First Output,先进先出),这样的话,咱们就不会致使某些请求永远获取不到锁。看到这里,是否是有点强行将多线程变成单线程的感受哈。3. FIFO队列思路
而后,咱们如今解决了锁的问题,所有请求采用“先进先出”的队列方式来处理。那么新的问题来了,高并发的场景下,由于请求不少,极可能一瞬间将队列内存“撑爆”,而后系统又陷入到了异常状态。或者设计一个极大的内存队列,也是一种方案,可是,系统处理完一个队列内请求的速度根本没法和疯狂涌入队列中的数目相比。也就是说,队列内的请求会越积累越多,最终Web系统平均响应时候仍是会大幅降低,系统仍是陷入异常。
4. 文件锁的思路
对于日IP不高或者说并发数不是很大的应用,通常不用考虑这些!用通常的文件操做方法彻底没有问题。但若是并发高,在咱们对文件进行读写操做时,颇有可能多个进程对进一文件进行操做,若是这时不对文件的访问进行相应的独占,就容易形成数据丢失
优化方案4:使用非阻塞的文件排他锁
1 <?php 2
3 //优化方案4:使用非阻塞的文件排他锁
4
5 include ('./mysql.php'); 6
7 //生成惟一订单号
8
9 function build_order_no(){ 10
11 return date('ymd').substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8); 12
13 } 14
15 //记录日志
16
17 function insertLog($event,$type=0){ 18
19 global $conn; 20
21 $sql="insert into ih_log(event,type) 22
23 values('$event','$type')"; 24
25 mysqli_query($conn,$sql); 26
27 } 28
29 $fp = fopen("lock.txt", "w+"); 30
31 if(!flock($fp,LOCK_EX | LOCK_NB)){ 32
33 echo "系统繁忙,请稍后再试"; 34
35 return; 36
37 } 38
39 //下单
40
41 $sql="select number from ih_store where goods_id='$goods_id' and sku_id='$sku_id'"; 42
43 $rs = mysqli_query($conn,$sql); 44
45 $row = $rs->fetch_assoc(); 46
47 if($row['number']>0){//库存是否大于0 48
49 //模拟下单操做
50
51 $order_sn=build_order_no(); 52
53 $sql="insert into ih_order(order_sn,user_id,goods_id,sku_id,price) 54
55 values('$order_sn','$user_id','$goods_id','$sku_id','$price')"; 56
57 $order_rs = mysqli_query($conn,$sql); 58
59 //库存减小
60
61 $sql="update ih_store set number=number-{$number} where sku_id='$sku_id'"; 62
63 $store_rs = mysqli_query($conn,$sql); 64
65 if($store_rs){ 66
67 echo '库存减小成功'; 68
69 insertLog('库存减小成功'); 70
71 flock($fp,LOCK_UN);//释放锁
72
73 }else{ 74
75 echo '库存减小失败'; 76
77 insertLog('库存减小失败'); 78
79 } 80
81 }else{ 82
83 echo '库存不够'; 84
85 insertLog('库存不够'); 86
87 } 88
89 fclose($fp); 90
91 ?>
这个时候,咱们就能够讨论一下“乐观锁”的思路了。乐观锁,是相对于“悲观锁”采用更为宽松的加锁机制,大都是采用带版本号(Version)更新。实现就是,这个数据全部请求都有资格去修改,但会得到一个该数据的版本号,只有版本号符合的才能更新成功,其余的返回抢购失败。这样的话,咱们就不须要考虑队列的问题,不过,它会增大CPU的计算开销。可是,综合来讲,这是一个比较好的解决方案。5. 乐观锁思路
有不少软件和服务都“乐观锁”功能的支持,例如Redis中的watch就是其中之一。经过这个实现,咱们保证了数据的安全。
优化方案5:Redis中的watch
1 <?php 2
3 $redis = new redis(); 4
5 $result = $redis->connect('127.0.0.1', 6379); 6
7 echo $mywatchkey = $redis->get("mywatchkey"); 8
9 /*
10
11 //插入抢购数据 12
13 if($mywatchkey>0) 14
15 { 16
17 $redis->watch("mywatchkey"); 18
19 //启动一个新的事务。 20
21 $redis->multi(); 22
23 $redis->set("mywatchkey",$mywatchkey-1); 24
25 $result = $redis->exec(); 26
27 if($result) { 28
29 $redis->hSet("watchkeylist","user_".mt_rand(1,99999),time()); 30
31 $watchkeylist = $redis->hGetAll("watchkeylist"); 32
33 echo "抢购成功!<br/>"; 34
35 $re = $mywatchkey - 1; 36
37 echo "剩余数量:".$re."<br/>"; 38
39 echo "用户列表:<pre>"; 40
41 print_r($watchkeylist); 42
43 }else{ 44
45 echo "手气很差,再抢购!";exit; 46
47 } 48
49 }else{ 50
51 // $redis->hSet("watchkeylist","user_".mt_rand(1,99999),"12"); 52
53 // $watchkeylist = $redis->hGetAll("watchkeylist"); 54
55 echo "fail!<br/>"; 56
57 echo ".no result<br/>"; 58
59 echo "用户列表:<pre>"; 60
61 // var_dump($watchkeylist); 62
63 }*/
64
65 $rob_total = 100; //抢购数量
66
67 if($mywatchkey<=$rob_total){ 68
69 $redis->watch("mywatchkey"); 70
71 $redis->multi(); //在当前链接上启动一个新的事务。 72
73 //插入抢购数据
74
75 $redis->set("mywatchkey",$mywatchkey+1); 76
77 $rob_result = $redis->exec(); 78
79 if($rob_result){ 80
81 $redis->hSet("watchkeylist","user_".mt_rand(1, 9999),$mywatchkey); 82
83 $mywatchlist = $redis->hGetAll("watchkeylist"); 84
85 echo "抢购成功!<br/>"; 86
87
88
89 echo "剩余数量:".($rob_total-$mywatchkey-1)."<br/>"; 90
91 echo "用户列表:<pre>"; 92
93 var_dump($mywatchlist); 94
95 }else{ 96
97 $redis->hSet("watchkeylist","user_".mt_rand(1, 9999),'meiqiangdao'); 98
99 echo "手气很差,再抢购!";exit; 100
101 } 102
103 } 104
105 ?>
第一个要说的就是数据库,首先要有一个很好的架构,查询尽可能不用* 避免相关子查询 给常常查询的添加索引 用排序来取代非顺序存取,若是条件容许 ,通常MySQL服务器最好安装在Linux操做系统中 。关于apache和nginx在高并发的状况下推荐使用nginx,ginx是Apache服务器不错的替代品。nginx内存消耗少 官方测试可以支撑5万并发链接,在实际生产环境中跑到2~3万并发链接数。php方面不须要的模块尽可能关闭,使用memcached,Memcached 是一个高性能的分布式内存对象缓存系统,不使用数据库直接从内存当中调数据,这样大大提高了速度,iiS或Apache启用GZIP压缩优化网站,压缩网站内容大大节省网站流量。PHP解决网站大数据大流量与高并发
第二,禁止外部的盗链。
外部网站的图片或者文件盗链每每会带来大量的负载压力,所以应该严格限制外部对
于自身的图片或者文件盗链,好在目前能够简单地经过refer来控制盗链,Apache自
己就能够经过配置来禁止盗链,IIS也有一些第三方的ISAPI能够实现一样的功能。当
然,伪造refer也能够经过代码来实现盗链,不过目前蓄意伪造refer盗链的还很少,
能够先不去考虑,或者使用非技术手段来解决,好比在图片上增长水印。
第三,控制大文件的下载。
大文件的下载会占用很大的流量,而且对于非SCSI硬盘来讲,大量文件下载会消耗
CPU,使得网站响应能力降低。所以,尽可能不要提供超过2M的大文件下载,若是须要
提供,建议将大文件放在另一台服务器上。
第四,使用不一样主机分流主要流量
将文件放在不一样的主机上,提供不一样的镜像供用户下载。好比若是以为RSS文件占用
流量大,那么使用FeedBurner或者FeedSky等服务将RSS输出放在其余主机上,这
样别人访问的流量压力就大多集中在FeedBurner的主机上,RSS就不占用太多资源了
第五,使用不一样主机分流主要流量
将文件放在不一样的主机上,提供不一样的镜像供用户下载。好比若是以为RSS文件占用流量大,那么使用FeedBurner或者FeedSky等服务将RSS输出放在其余主机上,这样别人访问的流量压力就大多集中在FeedBurner的主机上,RSS就不占用太多资源了。
第六,使用流量分析统计软件。
在网站上安装一个流量分析统计软件,能够即时知道哪些地方耗费了大量流量,哪些页面须要再进行优化,所以,解决流量问题还须要进行精确的统计分析才能够。好比:Google Analytics(Google分析)。
高并发和高负载的约束条件:硬件、部署、操做系统、Web 服务器、PHP、MySQL、测试
部署:服务器分离、数据库集群和库表散列、镜像、负载均衡
负载均衡分类: 1)、DNS轮循 2)代理服务器负载均衡 3)地址转换网关负载均衡 4)NAT负载均衡 5)反向代理负载均衡 6)混合型负载均衡
部署方案1:
适用范围:静态内容为主体的网站和应用系统;对系统安全要求较高的网站和应用系统。
Main Server:主服务器
承载程序的主体运行压力,处理网站或应用系统中的动态请求;
将静态页面推送至多个发布服务器;
将附件文件推送至文件服务器;
安全要求较高,以静态为主的网站,可将服务器置于内网屏蔽外网的访问。
DB Server:数据库服务器
承载数据库读写压力;
只与主服务器进行数据量交换,屏蔽外网访问。
File/Video Server:文件/视频服务器
承载系统中占用系统资源和带宽资源较大的数据流;
做为大附件的存储和读写仓库;
做为视频服务器将具有视频自动处理能力。
发布服务器组:
只负责静态页面的发布,承载绝大多数的Web请求;
经过Nginx进行负载均衡部署。
部署方案2:
适用范围:以动态交互内容为主体的网站或应用系统;负载压力较大,且预算比较充足的网站或应用系统;
Web服务器组:
Web服务无主从关系,属平行冗余设计;
经过前端负载均衡设备或Nginx反向代理实现负载均衡;
划分专用文件服务器/视频服务器有效分离轻/重总线;
每台Web服务器可经过DEC可实现链接全部数据库,同时划分主从。
数据库服务器组:
相对均衡的承载数据库读写压力;
经过数据库物理文件的映射实现多数据库的数据同步。
共享磁盘/磁盘阵列
将用于数据物理文件的统一读写
用于大型附件的存储仓库
经过自身物理磁盘的均衡和冗余,确保总体系统的IO效率和数据安全;
方案特性:
经过前端负载均衡,合理分配Web压力;
经过文件/视频服务器与常规Web服务器的分离,合理分配轻重数据流;
经过数据库服务器组,合理分配数据库IO压力;
每台Web服务器一般只链接一台数据库服务器,经过DEC的心跳检测,可在极短期内自动切换至冗余数据库服务器;
磁盘阵列的引入,大幅提高系统IO效率的同时,极大加强了数据安全性。
Web服务器:
Web服务器很大一部分资源占用来自于处理Web请求,一般状况下这也就是Apache产生的压力,在高并发链接的状况下,Nginx是Apache服务器不错的替代品。Nginx (“engine x”) 是俄罗斯人编写的一款高性能的 HTTP 和反向代理服务器。在国内,已经有新浪、搜狐通行证、网易新闻、网易博客、金山逍遥网、金山爱词霸、校内网、YUPOO相册、豆瓣、迅雷看看等多家网站、 频道使用 Nginx 服务器。
Nginx的优点:
高并发链接:官方测试可以支撑5万并发链接,在实际生产环境中跑到2~3万并发链接数。
内存消耗少:在3万并发链接下,开启的10个Nginx 进程才消耗150M内存(15M*10=150M)。
内置的健康检查功能:若是 Nginx Proxy 后端的某台 Web 服务器宕机了,不会影响前端访问。
策略:相对于老牌的Apache,咱们选择Lighttpd和Nginx这些具备更小的资源占用率和更高的负载能力的web服务器。
Mysql:
MySQL自己具有了很强的负载能力,MySQL优化是一项很复杂的工做,由于这最终须要对系统优化的很好理解。你们都知道数据库工做就是大量的、 短时的查询和读写,除了程序开发时须要注意创建索引、提升查询效率等软件开发技巧以外,从硬件设施的角度影响MySQL执行效率最主要来自于磁盘搜索、磁盘IO水平、CPU周期、内存带宽。
根据服务器上的硬件和软件条件进行MySQl优化。MySQL优化的核心在于系统资源的分配,这不等于无限制的给MySQL分配更多的资源。在MySQL配置文件中咱们介绍几个最值得关注的参数:
改变索引缓冲区长度(key_buffer)
改变表长(read_buffer_size)
设定打开表的数目的最大值(table_cache)
对缓长查询设定一个时间限制(long_query_time)
若是条件容许 ,通常MySQL服务器最好安装在Linux操做系统中,而不是安装在FreeBSD中。
策略: MySQL优化须要根据业务系统的数据库读写特性和服务器硬件配置,制定不一样的优化方案,而且能够根据须要部署MySQL的主从结构。
PHP:
一、加载尽量少的模块;
二、若是是在windows平台下,尽量使用IIS或者Nginx来替代咱们日常用的Apache;
三、安装加速器(都是经过缓存php代码预编译的结果和数据库结果来提升php代码的执行速度)
eAccelerator,eAccelerator是一个自由开放源码php加速器,优化和动态内容缓存,提升了性能php脚本的缓存性能,使得PHP脚本在编译的状态下,对服务器的开销几乎彻底消除。
Apc:Alternative PHP Cache(APC)是 PHP 的一个免费公开的优化代码缓存。它用来提供免费,公开而且强健的架构来缓存和优化 PHP 的中间代码。
memcache:memcache是由Danga Interactive开发的,高性能的,分布式的内存对象缓存系统,用于在动态应用中减小数据库负载,提高访问速度。主要机制是经过在内存里维护一个统 一的巨大的hash表,Memcache可以用来存储各类格式的数据,包括图像、视频、文件以及数据库检索的结果等
Xcache:国人开发的缓存器,
策略: 为PHP安装加速器。
代理服务器(缓存服务器):
Squid Cache(简称为Squid)是一个流行的自由软件(GNU通用公共许可证)的代理服务器和Web缓存服务器。Squid有普遍的用途,从做为网页服务器的前置cache服务器缓存相关请求来提升Web服务器的速度,到为一组人共享网络资源而缓存万维网,域名系统和其余网络搜索,到经过过滤流量帮助网络安全,到局域网经过代理网。Squid主要设计用于在Unix一类系统运行。
策略:安装Squid 反向代理服务器,可以大幅度提升服务器效率。
压力测试:压力测试是一种基本的质量保证行为,它是每一个重要软件测试工做的一部分。压力测试的基本思路很简单:不是在常规条件下运行手动或自动测试,而是在计算机数量较少或系统资源匮乏的条件下运行测试。一般要进行压力测试的资源包括内部内存、CPU 可用性、磁盘空间和网络带宽等。通常用并发来作压力测试。
压力测试工具:webbench,ApacheBench等
漏洞测试:在咱们的系统中漏洞主要包括:sql注入漏洞,xss跨站脚本攻击等。安全方面还包括系统软件,如操做系统漏洞,mysql、apache等的漏洞,通常能够经过升级来解决。
漏洞测试工具:Acunetix Web Vulnerability Scanner
博客来源:http://www.php.cn/php-weizijiaocheng-350323.html