高并发和大流量解决方案考点:
PHP如何解决网站大流程与高并发的问题
高并发架构相关的概念
高并发解决方案
并发:在某个时间点有多少个访问同时到来。
QPS:每秒钟请求或访问的数量。指每秒响应请求数(HTTP请求)
吞吐量:单位时间内处理的请求数
响应时间:从请求发出到收到响应花费的时间。
测试工具: ab wrk http_load 等
ab是apache的一款工具 观察使用 top 命令来查看的。
如果QPS 50 那么此站点属于小型网站
流量优化:
防盗链处理:
什么是盗链?
盗链是指在自己的页面上展示一些并不在自己服务器上的内容。
什么是防盗链?
就是通过一些技术手段,让其他访问的url地址,不能正确的显示这个内容。
工作原理:
通过referer 或签名,网站可以检测到目标网页访问的来源网页,如果是资源文件,则可以跟踪到显示它的网页地址。
一旦检测到来源不是本站即进行阻止或者返回指定的页面。
Referer 请求目标文件的来源 是哪里?
那么我们通过nginx 来进行一些解读:
1、通过referer
nginx模块: nginx_http_referer_module 用于阻挡来源非法的域名请求
nginx指令 valid_referers 全局变量 $invalid_referer 可以使用这个变量,这个配置 放在nginx的配置文件中
valid_referers none|blocked|server_names|string...
referers none 来源为空的情况
referers blocked referer 来源头部不为空,但里面的值被代理或防火墙删除了,这些值都不以http://或者https://开头
server_names
location ~.*\.(gif|jpg|png|flv|swf|rar|zip)${
valid_referers none blocked xiaosong.com *.xiaosongit.com;
if($invalid_referer){ //如果为真,返回403 就可以了。
#return 403;
rewrite ^/ http://www.xiaosongit.com/403.jpg;
}
}
这是配置文件,这样就会显示 不允许显示此图。
上图可以通过伪装referer 来进行访问。
再次看看签名是怎么做的?
2、通过签名
httpAccessKeyModule 实现nginx防盗链 accesskey on|off
location ~.*\.(gif|jpg|png|flv|swf|rar|zip)${
accesskey on;
accesskey_hashmethod md5;
accesskey_arg "sign"; #参数的键名 可以随便起名
accesskey_signature "xiaosong$remote_addr";
}
$sign=md5('xiaosong'.$_SERVER['REMOTE_ADDR']); echo '<img src="image/logo.jpg?sign='.$sign.'">';
前段优化:
减少http请求 合并css文件 合并js文件
添加异步请求:按需请求,需要加载的时候,去服务器请求加载数据。
启用浏览器缓存和文件压缩
本地缓存
如果本地还能使用,那么就不会去请求浏览器,这样的话,请求最快
expires 服务器时间
expires 客户端时间
浏览器与服务器的时间无法保持一致,如果时间差距大,就会影响缓存。
Cache-Control 针对expires返回的是一个时间
no-store 禁止浏览器缓存响应
no-cache 不允许直接使用本地缓存,先发起请求和服务器协商
max-age=3600 告知浏览器该响应本地缓存有效的最长期限,以秒为单位
就是缓存1个小时
缓存优先级
pragma>Cache-Control>Expires
协商缓存:
相关header
Last-modified:通知浏览器资源最后的修改时间,如果没有修改的话就直接返回304 让其直接只用本地缓存。
if-modified-since:把Last-modified这个时间带服务器并做检测,如果有变化,就重新缓存,如果没有变化的话就是用本地缓存。
ETAG 文件指纹标识符 如果文件内容修改、指纹就换改变
都是判断文件是否发生了修改
适合缓存的内容:
不变的图像,如果 logo 图标
css、js
下载文件
适合使用协商缓存:
html文件、经常更换的图片、或js、css
不建议缓存的内容:用户、api 等
本地缓存配置 expires 指令 过期时间。
如果 expires为负值 那么就等于 Cache-Control :no-Cache
看看 expires 的过期时间 是如何设置的,h代表小时 d 代表天数
在nginx中开启 expires 来设置一下缓存。
http://tool.css-js.com
图片压缩:
tinypng
jpegMini
ImageOptim
这是三个网站,可以压缩图片
gZIp 是否开启压缩 nginx
那么我怎么知道有没有开启压缩呢?
浏览器缓存
CDN加速 解决带宽不够用
内容分发网络
CDN工作原理:
适用cdn
什么是CDN?
CDN的优势是什么?
CDN的适用场景
例如CSS/JS图片、大文件下载、直播网站
CDN 真实服务器的一个镜像,cdn系统能够将连接、负载、以及用户距离找到距离近的最快的
cdn跨运营商的网络加速、保证不同网络的用户都得到良好的访问质量
CDN的实现:
BAT等都有提供cdn服务
阿里云、腾讯云
可以用LVS做4层负载均衡
也可用Nginx、varnish、squid、apache做7层负载均衡和cache
建立独立图片服务器
独立的必要性
分担web服务器的IO负载,将耗费资源的图片服务分离出来,提高服务器性能和稳定性。
减少带宽、减少cpu、增加硬盘转数,提高图片响应能力。
青牛云
独立域名
同一域名浏览器的并发连接数有限制,突破浏览器连接数的限制。
一个浏览器同一个域名一般是2-6个并发
就会多了并发的请求。
独立后的问题
如何进行图片上传和图片同步
NFS共享方式:
利用FTP同步:
青牛云的接口 :
动态语言静态化
fpm 反向代理
什么是动态语言静态化
将现有PHP动态语言的逻辑静态生成静态html文件,让用户访问动态脚本重定向到静态html文件的过程
为什么要静态化
节省cpu资源、访问速度更快、不和mysql数据库打交道
静态化的实现方式
模板引擎
display() 方法 动态的生成一个静态文件。
利用ob系列函数:
下一次 直接判断 是否过期 是否存在,如果都为真 那么就直接返回这个模板文件
filectime()
直接生成一个对应的html文件,下一次直接判断是否过期、是否存在,直接显示:
通过这样的方式进行缓存文件的缓存。
对实时性要求不高的页面:保存一个长期不变的页面
动态语言的并发处理
什么是进程、线程、协程
是计算机中的程序,进程是一个执行中过的程序。
运行
阻塞
线程是进程中的一个实体,是被系统独立调度和分派的基本单元,线程自己不拥有系统资源
一个进程可以拥有多个线程。 线程是协程中一个
在单个程序中同时运行多个线程完成不同的工作,成为多线程。
每一个进程都有一个线程,如果进程只有一个线程,那就是进程本身了。
线程是进程内的一个执行单元,进程内至少有一个线程,他们共享进程地址空间,而进程有自己的独立的地址空间。
线程是处理器调度的基本单位,但进程不是。
二者都可以并发执行。
有进程进行控制线程。
协程:由用户进行控制 异步处理 协程能保留上一次调用的状态
进程间通讯不方便。
线程就是把一个进程分为很多片
$sockserv=stream_socket_server("tcp://0.0.0.0:8000",$errno,$errstr);
严重依赖进程,这就缺陷。
创建进程的数量是有限的,
现在高并发异步IO的服务器程序都是基于epoll实现的
Reactor模型
Nginx多线程的Reactor
swoole 名字叫斯沃 多线程的Reactor+多线程的worker
什么是多进程、多线程
同步阻塞模型
异步非阻塞模型
PHP并发变成实践
PHP的Swoole扩展
异步多线程服务器、消息队列、毫秒定时器、异步文件读写
除了异步IO的支持之外,Swoole为PHP多进程的模式设计了多个并发数据结构和IPC通讯机制,可以大大简化多进程并发编程的工作。 就不在用 socker 和Reactor 了。
是一种异步模型,不用等待。可以是PHP的一个框架。
需要打一个扩展。
消息队列
场景说明:用户注册后,需要发送注册邮件和注册短信
串行方式:将注册信息写入数据库成功后,发送注册邮件,发送注册短信
并行方式:将注册信息写入数据库成功后,发送注册邮件,同时发送短信
应用解耦:
场景说明:用户下单后,订单系统需要通知库存系统
流量削峰
接口的并发请求
数据库缓存
什么是数据库缓存
为什么要使用缓存
极大解决数据库服务器的压力
提高应用数据的响应速度
常见的缓存形式:内存缓存、文件缓存
为了节俭IO的开销,因此我们使用的是内存缓存。
高并发下,能最大成都地降低对数据库服务器的访问压力。
最大可能的降低IO的访问,这个比较慢,
放在内存中的数据访问速度最快。
缓存方式的选择:
缓存场景的选择:
缓存数据的实时性:缓存一个时间长度,过了一段时间后就销毁,重新访问缓存
缓存数据的稳定性:
使用mysql查询缓存:
mysql自带的查询缓存:
query_cache_type:0 1 2
0 不使用缓存
1 始终使用缓存
2 按需使用缓存
为1:
select sql_no_cache * from web_aa where id>100;
为2:
select sql_cache * from web_aa where id>100;
query_cache_size=0 默认情况下query_cache_size为0 表示为查询缓存预留的内存是0 ,则无法使用查询缓存。
这个可以在php.ini 配置项中配置
也可以使用 sql语句设置:
set GLOBAL query_cache_size=13421555;
清理缓存:
flush query cache
flush tables
作为一个了解,知道即可。
极大降低CPU的使用率
使用memcache缓存
是一套分布式的高速缓存系统 内存 对象 维护一个庞大hash表
需要PHP安装memcache 或 memcached的扩展
使用redis缓存
redis与memcache的区别
性能相差不大
持久化 redis
redis,依赖客户端来实现分布式读写
redis支持快照进行持久化,aof增强了可靠性的同时,对性能有所影响。
字符串、队列、hash、集合、
session_set_save_handler 来设置session 保存在哪里
mysql数据库底层优化
数据表数据类型优化
这个怎么优化呢?优化两个点
字段使用什么样的数据类型更加合适
字段使用什么速度会更快
tinyint smallint int bigint
0-255
考虑空间的问题,考虑范围的问题
unsingd 正
char 和 varchar
手机号 char 11位
md5 char 32位
varchar 用户名
字符串长度是否固定
enum
内部采用整形的方式存储
效率更快 确定的东西可以采用enum来存储
IP地址的存储
可以采用整形来存 ip2long long2ip
可以采用整形来存储IP地址 ,使用PHP函数
索引
索引并不是越多越好,在合适的字段上创建合适的索引
符合索引 前缀原则 如果a b c
like查询% 不使用索引
全表索引优化
字符串类型索引失效的问题 如果字符串中存储的是一个整形,如果没有加单引号 那么索引会失效
使用Limit
切分查询 删除1000万 那么 我们可以采用拆分 每次删除100万
优化特定类型
count(*) 没有where 的查询 是最快的
优化关联查询 特定的关联查询
优化自查询 尽量不适用子查询 要是用联合联合查询 left join
优化group by 和 distinct
优化limit 和 union 联合
存储引擎的优化
myISAM Innodb
使用行级锁
分区操作
通过特定的策略对数据表进行物理拆分
根据热点数据一个区、冷数据一个区
对用户透明
partition by 使用分区
分库分表
分库分表 拆分成多张表格
水平拆分
垂直拆分
join
union
数据库架构的优化
主从复制
读写分离
双主热备
负载均衡 LVS MyCat 中间件
web服务器的负载均衡
实现两种负载均衡
实现七层均衡的实现 nginx
nginx 负载均衡
内置策略 扩展策略
内置策略 IP Hash 、加权轮询
扩展策略 fair策略 通用hash 一致性hash
加权轮询:
首先将请求都分给高权重的机器,知道该机器的权值降到了比其他机器低,才开始将请求分给下一个高权重的机器
当所有后端机器都挂掉了,nginx会立即将所有机器的标志位清成初始状态,以避免造成所有的额机器都处在timeout的状态。
IP Hash :
变相的一种轮询
fair策略
判断响应时间最快的,选择一个负载最轻的
nginx负载均衡配置
add header cache-control max-age=3600;
add_header REAL_SERVER 8082;
按照 weight 从大到小
实现四层均衡的实现 LVS实现服务器集群 nat dr tun
create index indexname
索引优化
sql语句的优化
存储引擎的优化
数据表结构设计的优化
数据库服务器架构的优化
服务器端优化:
页面静态化
并发处理
数据库优化:
数据库缓存
分库分表 操作
读写分离
web服务器优化:
负载均衡 LVS