一.高并发架构相关概念
- 并发
并发,在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任意时刻点只能有一个程序 在处理机上运行。
我们说的高并发是什么?
在互联网时代,高并发指的是并发访问。也就是在某个时间点,有多少个访问同时到来。
通常一个系统的日PV在千万以上,就可能是一个高并发系统
高并发问题,我们具体该关心什么?
QPS:每秒钟请求或者查询的数量,在互联网领域,指每秒响应请求数(指HTTP请求)
吞吐量:单位时间内处理的请求数量(通常由QPS与并发数决定)
响应时间:从请求发出到收到响应花费的时间。如系统处理一个HTTP请求需要100ms,100ms就是系统的响应时间
PV:综合浏览量(page view),即页面浏览量或者点击量,一个网站在24小时内访问的页面数量
UV:独立访客(UniQue Visitor),即一定时间范围内相同访客多次访问网站,只计算为1个独立访客
日网站带宽 = PV/统计时间(换算成秒)*平均页面大小(单位KB)*8
峰值一般是平均值的倍数,根据实际情况来定。
QPS不等于并发连接数
QPS是每秒HTTP请求数量,并发连接数是系统同时处理的请求数量
(总PV数80%)/(6小时秒数20%) = 峰值每秒请求数(QPS)
80%访问量集中在20%的时间
压力测试
测试能承受的最大并发
测试最大承受的QPS值
常用性能测试工具
ab、wrk 、 http_load、 Web Bench 、 Siege 、 Apache JMeter
ab
全程是apache benchmark,是apache官方推出的工具
创建多个并发访问线程,模拟多个访问者同时对某一URL地址进行访问。他的测试目标是基于URL的,因此,他既可以用来测试apache的负载压力,也可以测试nginx、lighthttp、tomact、IIS等其他web服务器的压力。
ab使用
模拟并发请求100次,总共请求5000次
ab -c 100 -n 5000 待测试网站
注意事项
测试机器与被测试机器分开
不要对线上服务做压力测试
观察测试工具ab所在机器,以及被测试的前端机的CPU,内存,网络等都不超过最高限度的75%
QPS达到极限
随着QPS的增长,每个阶段需要根据实际情况来进行优化,优化的方案也与硬件条件、网络带宽息息相关。
QPS达到50
可以称为小型网站,一般服务器就可以应付
QPS达到100
假设关系型数据库的每次请求在0.01秒完成
假设单页面只有一个SQL查询,那么100QPS意味着1秒钟完成100次请求,但是此时我们并不能保证数据库查询能完成100次
方案:数据库缓存层、数据库的负载均衡
QPS达到800
假设我们使用百兆带宽,意味着网站出口的实际带宽是8M左右
假设每个页面只有10K,在这个并发条件下,百兆带宽已经吃完
方案:CDN加速,负载均衡
QPS达到1000
假设我们使用Memcache缓存数据库查询数据,每个页面对Memcache的请求远大于直接对DB的请求
Memcache的悲观并发数在2W左右,但有可能在之前内网带宽已经吃光,表现出不稳定
方案:静态HTML缓存
QPS达到2000
达到这个级别,文件系统访问锁都成为灾难
方案:做业务分离,分布式存储
高并发解决方案案例
- 流量优化
防盗链 - 前端优化
减少HTTP请求
添加异步请求
启用浏览器缓存和文件压缩
CDN加速
建立独立的图片服务器 - 服务端优化
页面静态化
并发处理
队列处理 - 数据库优化
数据库缓存
分库分表、分区操作
读写分离
负载均衡 - Web服务器优化
负载均衡
二. 流量优化
防盗链处理
- 盗链概念
盗链是指在自己的页面上展示一些并不在自己服务器上的内容,获得他人服务器上的资源地址,绕过别人的资源展示页面,直接在自己的页面上向最终用户提供此内容
常见的是小站盗用大站的图片、音乐、视频、软件等资源
通过盗链的方法可以减轻自己服务器的负担,因为真实的空间和流量均来自别人的服务器 - 什么是防盗链
防止别人通过一些技术手段绕过本站的资源展示页面,盗用本站的资源,让绕开本站资源展示页面的资源链接失效
可以大大减轻服务器及带宽的压力 - 防盗链
防盗链的工作原理
通过Referer或者签名,网站可以检测目标网页访问的来源网页,如果是资源文件,则可以跟踪到显示他的网页地址。
一旦检测到来源不是本站即进行阻止或者返回指定的页面
通过计算签名的方式,判断请求是否合法,如果请求合法则显示,否则返回错误信息
防盗链的实现方法
Referer
Nginx模块ngx_http_referer_module用于阻挡来源非法的域名请求
Nginx指令valid_referers,全局变量$invalid_referer
Referer
valid_referers none | blocked |server_names |string …;
none : "Referer"来源头部为空
blocked : "Referer"来源头部不为空,但里面的值被代理或者防火墙删除了,这些值都不以http://或者https://开头
server_names : "Referer"来源头部包含当前的server_names
location ~ .*\.(gif|jpg|png|flv|swf|rar|zip)$
{
valid_referers none blocked ityhc.com *.ityhc.com;
if($invalid_referer)
{
return 403;
#rewrite ^/ http://www.ityhc.com/403.jpg;
}
}
以上仿盗链技术有缺陷,因为可以伪造Referer
所以还可以通过加密签名的方式实现防盗链
加密签名
使用第三方模块HttpAccessKeyModule实现Nginx仿盗链
accesskey on|off 模块开关
accesskey_hashmethod md5 |sha-1 签名加密方式
accesskey_arg GET参数名称
accesskey_signature 加密规则
location ~ .*\.(gif|jpg|png|flv|swf|rar|zip)$
{
accesskey on;
accesskey_hashmethod md5;
accesskey_arg "key";
accesskey_signature "mypass$remote_addr";
}
三. 前端优化
-
减少HTTP请求
为什么减少HTTP请求
性能黄金法则
只有10%-20%的用户响应时间花在接收请求的HTTP文档上,剩下的80%-90%的时间花在HTTP文档所引用的所有组件(图片、script、css、flash等等)进行的HTTP请求上 -
减少HTTP请求的方式
如何改善
(1)改善响应时间的最简单途径就是减少组件的数量,并由此减少HTTP请求的数量
HTTP连接产生的开销
域名解析—TCP连接—请求发送—等待—下载资源—解析时间
疑问?
DNS缓存
查找DNS缓存也需要时间,多个缓存就要查找多次有可能缓存会被清除
Keep-Alive
HTTP1.1协议规定请求只能串行发送,也就是说一百个请求必须依次逐个发送,前面的一个请求结束才能开始下一个请求
(2)图片地图
图片地图允许你在一个图片上关联多个URL。目标URL的选择取决于用户单击了图片上的哪个位置
使用:
(3) CSS Sprites
CSS精灵,通过使用合并图片,指定CSS的background-image和background-position来显示图片
图片地图和CSS精灵的响应时间基本相同,但比使用各自独立图片的方式要快50%以上
(4)合并脚本和样式表
使用外部JS和CSS文件引入的方式,因为这比直接写在页面中性能要更好一点
独立的一个JS比用多个JS文件组成的页面的载入要快38%
把多个脚本写在一个脚本,把多个样式文件写入一个样式文件
(5)图片使用Base64编码减少页面请求数
采用Base64编码方式将图片直接嵌入到网页中,而不是从外部载入
四. 启用浏览器缓存和文件压缩
HTTP缓存机制
-
缓存分类
HTTP缓存模型中,如果请求成功会有三种情况
200 from cache:直接从本地缓存中获取响应,最快速,最省流量,因为根本没向服务器发送请求
304 Not Modified:协商缓存,浏览器在本地没有命中的情况下请求头中发送一定的校验数据到服务端,如果服务端数据没有改变,浏览器从本地缓存响应,返回304
快速,发送的数据很少,只返回一些基本的响应头信息,数据量很小,不发送实际响应体
200 OK:以上两种缓存全都失败,服务器返回完整的响应。没有用到缓存,相对最慢。 -
本地缓存
相关Header
Pragma:HTTP1.0时代的遗留产物,该字段被设置为no-cache时,会告知浏览器禁用本地缓存,即每次都向服务器发送请求。
Expires:HTTP1.0时代用来启用本地缓存的字段,expires值对应一个形如 Thu,31 Dec 2037 23:55:55GMT的格林威治时间,告诉浏览器缓存实现的时刻,如果还没到该时刻,标明缓存有效,无需发送请求。
浏览器和服务器的时间无法保持一致,如果时间差距大,就会影响缓存结果
Cache-Control:HTTP1.1针对Expires时间不一致的解决方案,运用Cache-Control告知浏览器缓存过期的时间间隔而不是时刻,即使具体时间不一致,也不影响缓存的管理。
no-store :禁止浏览器缓存响应
no-cache:不允许直接使用本地缓存,先发起请求和服务器协商
max-age=delta-seconds:告知浏览器该响应本地缓存有效的最长期限,以秒为单位
优先级
Pragma>Cache-Control>Expires -
协商缓存
当浏览器没有命中本地缓存,如本地缓存过期或者响应中声明不允许直接使用本地缓存,那么浏览器肯定发起服务器端请求
服务端会验证数据是否修改,如果没有通知浏览器使用本地缓存
相关Header
Last-Modified:通知浏览器资源的最后修改时间
Last-Modified:Mon ,28 Sep 2015 08:06:43 GMT
If-Modified-Since:得到资源的最后修改时间后,会将这个信息通过If-Modified-Since提交到服务器做检查,如果没有修改,返回304状态码
If-Modified-Since:Mon ,28 Sep 2015 08:06:43 GMT
ETag:HTTP1.1推出,文件的指纹标识符,如果文件内容修改,指纹会改变
ETag:“782342342-2342”
If-None-Match:本地缓存失效,会携带此值取请求服务端,服务端判断该资源是否改变,如果没有改变,直接使用本地缓存,返回304
适合缓存的内容
不变的图像,如logo,图标等
js、css静态文件
可下载的内容,媒体文件
建议使用协商缓存
HTML文件
经常替换的图片
经常修改的JS、CSS文件
js、css文件的加载可以加入文件签名来拒绝缓存
index.css?签名
index.签名.js
不建议缓存的内容
用户隐私等敏感数据
经常改变的API数据接口
- Nginx配置缓存策略
本地缓存配置
add_header指令:添加状态码为2XX和3XX的响应头信息
add_header name value[always];
可以设置Pragma/Expires/Cache-Control,可以继承
expires指令:通知浏览器过期时长
expires time;
为负值时表示Cache-Control:no-cache;
为正值或0时,表示Cache-Control:max-age=指定的时间;
当为max时,会把Expires设置为"Mon ,28 Sep 2037 08:06:43 GMT",Cache-Control设置为10年
协商缓存相关配置
Etag指令:指定签名
etag on | off;默认为on
- 前端代码和资源的压缩
优势
让资源文件更小,加快文件在网络中的传输,让网页更快的展现,降低带宽和流量开销
压缩方式
JS CSS 图片 HTML代码的压缩
Gzip压缩
JS代码压缩
JS代码压缩的原理是去掉多余的空格和回车,替换长变量名、简化一些代码写法等
压缩工具有很多,有在线工具,有应用程序,有编辑器插件
压缩工具:UglifyJS、YUI Compressor、Closure Compiler
css代码压缩
常用工具:YUI Compressor、CSS Compressor、
HTML代码压缩
不建议使用代码压缩,有时会破坏代码结构,可以使用Gzip压缩,当然也可以使用htmlcompressor工具,不过转换后一定要检查代码结构。
图片压缩
压缩工具:tinypng JpegMini ImageOptim
Gzip压缩
配置Nginx
gzip on|off; #是否开启gzip
gzip_buffers 32 4K |16 8K #缓冲(在内存中缓冲几块?每块多大)
gzip_comp_level[1-9] #推荐6 压缩级别(级别越高,压的越小越浪费CPU计算资源)
gzip_disable #正则匹配UA 什么样的URL不进行gzip
gzip_min_length 200#开始压缩的最小长度
gzip_http_version 1.0|1.1 #开始压缩的HTTP协议版本
gzip_proxied #设置请求者代理服务器,该如何缓存内容
gzip_types text/plain application/xml #对哪些类型的文件进行压缩 如txt,html,css,xml
gzip_vary on|off # 是否传输gzip压缩标志
其他工具
自动化构建工具Grunt
五. CDN加速
- 相关概念
什么是CDN
CDN全称(Content Delivery Network内容分发网络)尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定
在网络各处放置节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网络
CDN系统能够实时根据网络流量和各节点的连接、负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上
使用CDN的优势
本地Cache加速,提高企业站点(尤其含有大量图片和静态页面站点)的访问速度
跨运营商的网络加速,保证不同网络的用户都得到良好的访问质量
远程访问用户根据DNS负载均衡技术智能自动选择Cache服务器
自动生成服务器的远程Mirror(镜像)cache服务器,远程用户访问时从cache服务器上读取数据,减少远程访问的带宽、分担网络流量、减轻原站点WEB服务器负载等功能
广泛分布的CDN节点机上节点间的只能冗余机制,可以有效的预防黑客入侵
CDN工作原理
传统访问
用户在浏览器中输入域名发起请求—》解析域名获取服务器的IP地址—》根据IP地址找到对应的服务器—》服务器响应并返回数据
使用CDN访问
用户发起请求—》智能DNS解析(根据IP判断地址位置、接入网类型、选择路由最短和负载最轻的服务器)—》取得缓存服务器IP---->把内容返回给用户(如果缓存中有)—》向源站发起请求—》将结果返回给用户—》将结果存入缓存服务器
CDN的适用场景
场景
站点或应用中大量静态资源的加速分发,例如:CSS,JS,图片和THML
大文件下载
直播网站
CDN的实现
BAT都有提供CDN服务
可用LVS做4层负载均衡
可用Nginx,Varnish,Squid,Apache TrafficServer做7层负载均衡和Cache
反向代理:使用squid反向代理或者使用Nginx反向代理
六. 建立独立的图片服务器
- 相关概念
独立的必要性
分担WEB服务器的I/O负载-将耗费资源的图片服务分离出来,提高服务器的性能和稳定性
能够专门对图片服务器进行优化–为图片服务设置有针对性的缓存方法,减少带宽成本,提高访问速度
提高网站的可扩展性–通过增加图片服务器,提高图片吞吐能力
采用独立域名
原因:同一域名下浏览器的并发连接数有限制,突破浏览器连接数的限制
由于cookie的原因,对缓存不利,大部分WEB cache都只缓存不带cookie的请求,导致每次的图片请求都不能命中cache
独立后的问题
如何进行图片上传和图片同步
NFS共享方式
利用FTP同步
服务端优化
七. 页面静态化
- 相关概念
什么是动态语言静态化
将现有PHP等动态语言的逻辑代码生成为静态HTML文件,用户访问动态脚本重定向到静态HTML文件的过程。
对实时性要求不高的页面
为什么要静态化
原因:动态脚本通常会做逻辑计算和数据查询,访问量越大,服务器压力越大
访问量大时,可能造成CPU负载过高,数据库服务器压力过大
静态化可以减低逻辑处理压力,降低数据库服务器查询压力
静态化的实现方式
(1)使用模板引擎
可以使用Smarty的缓存机制生成静态HTML缓存文件
$smarty->cache_dir = $ROOT."/cache";//缓存目录
$smarty->caching = true;//是否开启缓存
$smarty->cache_lifetime = “3600”;//缓存时间
$smarty->display(string template[,string cache_id,[,string compile_id]]);
$smarty->clear_all_cache();//清除所有缓存
$smarty->clear_cache(‘file.html’);//清除指定的缓存
s
m
a
r
t
y
−
>
c
l
e
a
r
c
a
c
h
e
(
′
a
r
t
i
c
l
e
.
h
t
m
l
′
,
smarty->clear_cache('article.html',
smarty−>clearcache(′article.html′,art_id);//清除同一个模板下的指定缓存号的缓存
(2)利用ob系列函数
ob_start():打开输出控制缓冲
ob_get_contents():返回输出缓冲区内容
ob_clean():清空输出缓冲区
ob_end_flush():冲刷出(送出)输出缓冲区内容并关闭缓冲
ob_start();
输出到页面的HTML代码
。。。。
ob_get_contents();
ob_end_flush();
fopen()写入
可以判断文件的inode修改时间,判断是否过期使用filectime函数
并发处理
1. 相关概念
什么是进程、线程、协程
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础
进程是一个执行的程序
进程的三态模型:多道程序系统中,进程在处理器上交替运行,状态不断地发生变化
运行、就绪、阻塞
运行:当一个进程在处理机上运行时,则称该进程处于运行状态。处于此状态的进程的数目小于等于处理器的数目,对于单处理机系统,处于运行状态的进行只有一个。在没有其他进程可以执行时(如所有的进程都在阻塞状态),通常会自动执行系统的空闲进程。
就绪:当一个进程获得了除处理机意外的一切所需资源,一旦得到处理机即可运行,则称此进程处于就绪状态。就绪进程可以按多个优先级来划分队列。例如,当一个进程由于时间片用完而进入就绪状态时,排入低优先级队列;当进程由I/O操作完成而进入就绪状态时,排入高优先级队列。
阻塞:也称为等待或睡眠状态,一个进程正在等待某一事件发生(例如请求I/O而等待I/O完成等)而暂时停止运行,这时即使把处理机分配给进程也无法运行,故称该进程处于阻塞状态。
进程的五态模型:对于一个实际的系统,进程的状态及其转换更为复杂
新建态、活跃就绪/静止就绪、运行、活跃阻塞/静止阻塞、终止态
新建态:对应于进程刚刚被创建时没有被提交的状态,并等待系统完成创建进程的所有必要信息。
终止态:进程已结束运行,回收除进程控制块之外的其他资源,并让其他进程从进程控制块中收集有关信息。
活跃就绪:指进程在主存并且可被调度的状态
静止就绪(挂起就绪):指进程被对换到辅存时的就绪状态,是不能被直接调度的状态,只有当主存中没有活跃就绪态进程,或者是挂起就绪态进程具有更高的优先级,系统将把挂起就绪态进程调回主存并转换为活跃就绪。
活跃阻塞:指进程已在主存,一旦等待的事件产生便进入活跃就绪状态。
静止阻塞:进程对换到辅存时的阻塞状态,一旦等待的事件产生便进入静止就绪状态。
由于用户的并发请求,为每一个请求都创建一个进程显然是行不通的,从系统资源开销方面或是响应用户请求的效率方面来看。因此操作系统中线程的概念便被引入了。
线程,有时候被称为轻量级进程(lightweight Process,LWP),是程序执行流的最小单元。
线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源但它可与同属于一个进程的其他线程共享进程所拥有的全部资源。
一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发执行。
线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派CPU的基本单位指运行中的程序调度单位。
在单个程序中同时运行多个线程完成不同的工作,称为多线程。
每个程序都至少有一个线程,若程序只有一个线程,那就是程序本身。
线程的状态:就绪、阻塞、运行
就绪状态:线程具备运行的所有条件,逻辑上可以运行,在等待处理机。
运行状态:线程占有处理机正在运行。
阻塞状态:线程在等待一个事件(如某个信号量),逻辑上不可执行。
协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。
进程、线程的区别
- 线程是进程内的一个执行单元,进程内至少有一个线程,他们共享进程的地址空间,而进程有自己独立的地址空间
- 进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资源
- 线程是处理器调度的基本单位,但进程不是
- 两者均可并发执行
- 每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口,但线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制
线程和协程的区别
- 一个线程可以多个协程,一个进程也可以单独拥有多个协程
- 线程进程都是同步机制,而协程则是异步
- 协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态
什么是多进程、多线程
多进程:同一个时间里,同一个计算机系统中如果允许两个或两个以上的进程处于运行状态,这就是多进程
边玩QQ,边浏览网页
多开一个进程,多分配一份资源,进程间通讯不方便
多线程:线程就是把一个进程分为很多片,每一片都可以是一个独立的流程
与多进程的区别是只会使用一个进程的资源,线程间可直接通信
多概念之间的区别
例子
单进程单线程:一个人在一个桌子上吃饭
单进程多线程:多个人在同一个桌子上一起吃饭
多进程单线程:多个人每个人在自己桌子上吃饭
同步阻塞模型
多进程
最早的服务器端程序都是通过多进程、多线程来解决并发IO的问题
一个请求创建一个进程,然后子进程进入循环同步阻塞地与客户端连接进行交互,收发处理数据
多线程
用多线程模式实现非常简单,线程中可以直接向某个客户端连接发送数据
步骤
创建一个socket
进入while循环,阻塞在进程accept操作上,等待客户端连接进入主进程在多进程模型下通过fork创建子进程
多线程模型下可以创建子进程
子进程/线程创建成功后进入while循环,阻塞在recv调用上,等待客户端向服务器发送数据
收到数据后服务器程序进行处理然后使用send向客户端发送响应
当客户端连接关闭,子进程/线程退出并销毁所有资源。主进程/线程会回收掉此子进程/线程。
缺点
这种模型严重依赖进程的数量解决并发问题
启动大量进程会带来额外的进程调度消耗
异步非阻塞模型
现在各种高并发异步IO服务器程序都是基于epoll实现的
IO复用异步非阻塞程序使用经典的Reactor模型,Reactor顾名思义就是反应堆的意思,它本身不处理任何数据收发。只是可以监视一个socket句柄的事件变化
reactor模型
add:添加一个socket到reactor
set:修改socket对应的事件,如可读可写
del:从reactor中移除,不再监听事件
callback:事件发生后回调指定的函数
Nginx:多线程Reactor
Swoole:多线程Reactor+多进程Worker
PHP并发编程实践
php的Swoole扩展
PHP的异步、并行、高性能网络通信引擎,使用纯C语言编写,提供了PHP语言的异步多线程服务器,异步TCP/UDP网络客户端,异步MySQL,异步Redis,数据库连接池,AsyncTask,消息队列,毫秒定时器,异步文件读写,异步DNS查询
除了异步IO支持外,Swoole为PHP多进程的模型设计了多个并发数据结构和IPC通信机制,可以大大简化多进程并发编程的工作
Swoole2.0支持类似Go语言的协程,可以使用完全同步的代码实现异步程序
消息队列
场景说明:用户注册后,需要发注册邮件和注册短信
串行方式:将注册信息写入数据库成功后,发送注册邮件,再发送注册短信
并行方式:将注册信息写入数据库成功后,发送注册邮件的同时,发送注册短信
消息队列方式:将注册信息写入数据库成功后,将成功信息写入队列,此时直接返回成功给用户,写入队列的时间非常短,可以忽略不计,然后异步发送邮件和短信
应用解耦
场景说明:用户下单后,订单系统需要通知库存系统
加入库存系统无法访问,则订单减库存将失败,从而导致订单失败
引用队列
用户下单后,订单系统完成持久化处理,将消息写入消息队列,返回用户订单下单成功
订阅下单的消息,采用拉/推的方式,获取下单信息,库存系统根据下单信息,进行库存操作
流量削峰
应用场景:秒杀活动,流量瞬时激增,服务器压力大。
用户发起请求,服务器接收后,先写入消息队列。假如消息队列长度超过最大值,则直接报错或者提示用户
后续程序读取消息队列再做处理
控制请求量
缓解高流量
日志处理
应用场景:解决大量日志的传输
日志采集程序将程序写入消息队列,然后通过日志处理程序的订阅消费日志
常见的消息队列产品
Kafka、ActiveMQ ZeroMQ RabbitMQ Redis等
接口的并发请求
curl_multi_init
八. 数据库优化
-
什么是数据库缓存
MySQL等关系型数据库的数据存储在磁盘上,在高并发场景,业务应用对MySQL产生的增删改查的操作造成巨大的I/O开销和查询压力,这无疑对数据库和服务器都是一种巨大的压力,为了解决此类问题,缓存数据的概念应运而生。
极大的解决数据库服务器的压力
提高应用数据的响应速度
常见的缓存形式:内存缓存,文件缓存 -
为什么要使用缓存
缓存数据是为了让客户端很少甚至不访问数据库服务器进行数据的查询,高并发下,能最大程序的降低对数据库服务器的访问压力
用户请求–》数据查询–》连接数据库服务器并查询数据–》将数据缓存起来(HTML,内存、JSON、序列化数据)—》显示给客户端
第二次请求时
用户再次请求或者新用户访问—》数据查询—》直接从缓存中获取数据—》显示给客户端
缓存方式的选择
缓存场景的选择
缓存数据的实时性
缓存数据的稳定性 -
使用MySQL查询缓存
启用MySQL查询缓存
query_cache_type
查询缓存类型,有0、1、2三个取值。0表示不使用查询缓存。1表示始终使用查询缓存。2表示按需使用查询缓存。
query_cache_type为1时,也可以关闭查询缓存
SELECT SQL_NO_CACHE * FROM my_table WHERE conditon;
极大降低CPU使用率
query_cache_type为2时,按需使用查询缓存
SELECT SQL_CACHE * FROM my_table WHERE conditon;
query_cache_size
默认情况下query_cache_size为0,表示为查询缓存预留的内容为0,无法使用查询缓存
SET GLOBAL query_cache_size = 134217728;
查询缓存可以看做是SQL文本和查询结果的映射
第二次查询的SQL和第一次查询的SQL完全相同,则会使用缓存
SHOW STATUS LIKE ‘Qcache_hits’;查看命中次数
表的结构或数据发生变化时,查询缓存中的数据不再有效
清理缓存
FLUSH QUERY CACHE;//清理查询缓存内存碎片
RESET QUERY CACHE;//从查询缓存中移出所有查询
FLUSH TABLES;//关闭所有打开的表,同时该操作会清空查询缓存中的内容
-
使用Memcache缓存
对于大型站点,如果没有中间缓存层,当流量打入数据库层时,即便有之前的几层为我们挡住一部分流量,但是在大并发的情况下,还是会有大量请求涌入数据库层,这样对于数据库服务器的压力冲击很大,响应速度也会下降,因此添加中间缓存层很有必要。
memcache是一套分布式的高速缓存系统,由liveJournal的 BradFitzpatrick开发,但目前被很多网站使用以提升网站的访问速度,尤其对于一些大型的、需要频繁访问数据库的网站访问速度提升效果十分显著
工作原理
memcache是一个高性能的分布式的内存对象缓存系统,通过在内存中维护一个统一的巨大的hash表,它能够用来存储各种格式的数据,包括图像、视频、文件以及数据库检索的结果等。简单的说就是将数据调用到内存,然后从内存中读取,从而大大提高读取速度
工作流程
先检查客户端的请求数据是否在memcached中,如果有,直接把请求数据返回,不再对数据库进行任何操作;如果请求的数据不在memcached中,就去查数据库,把从数据库中获取的数据返回给客户端,同时把数据缓存一份到memcached中
方法
获取:get(key)
设置:set(key,val,expire)
删除:delete(key)
通用缓存机制
用查询的方法名+参数作为查询时的key value对中的key值 -
使用Redis缓存
与Memcache的区别
(1)性能相差不大,使用场景不同
(2)Redis2.0增加了自己的VM特性,突破物理内存限制,Memcache可以修改最大可用内存,采用LRU算法
(3)Redis依赖客户端实现分布式读写
(4)Memcache本身没有数据冗余机制
(5)Redis支持(快照、AOF),依赖快照进行持久化,AOF增强了可靠性的同时,对性能有所影响
(6)Memcache不支持持久化,通常做缓存,提升性能
(7)Memcache在并发场景下,用cas保证一致性,redis事务支持比较弱,只能保证事务中的每个操作连续执行
(8)redis支持多种类型的数据类型
(9)redis用于数据量较小的高性能操作和运算上
(10)Memcache用于在动态系统中减少数据库负载,提升性能;适合做缓存,提高性能 -
缓存其他数据
其他数据
Session
session_set_save_handler
八. 数据库优化
-
数据表数据类型优化
tinyint smallint bigint
char varchar
enum 特定、固定的分类使用enum 男 女
IP地址存储 -
索引优化
索引创建原则
在合适的字段创建合适的索引
复合索引的前缀原则
索引注意事项
复合索引的前缀原则
like查询%
全表扫描优化
or条件索引使用情况
字符串类型索引失效问题
- SQL语句优化
(1)优化查询过程中的数据访问
使用limit
返回列不用*
(2)优化长难句的查询语句
变复杂为简单
切分查询
分解关联查询
(3)优化特定类型的查询语句
优化count()
优化关联查询
优化子查询
优化group by和distinct
优化limit和union
-
存储引擎优化
(1)尽量使用innoDB存储引擎 -
数据表结构设计优化
(1)分区操作
通过特定的策略对数据表进行物理拆分
对用户透明
partition by
(2)分库分表
水平拆分
垂直拆分 -
数据库服务器架构优化
(1)主从复制
(2)读写分离
(3)双主热备
(4)负载均衡
通过lvs的三种基本模式实现负载均衡
MyCAT数据库中间件实现负载均衡
九. WEB服务器负载均衡
-
七层负载均衡的实现
基于URL等应用层信息的负载均衡
Nginx的proxy是它一个很强大的功能,实现了7层负载均衡
功能强大,性能卓越,运行稳定
配置简单灵活
能够自动剔除工作不正常的后端服务器
上传文件使用异步模式
支持多种分配策略,可以分配权重,分配方式灵活 -
Nginx负载均衡
内置策略、扩展策略
内置策略:IP Hash,加权轮询
扩展策略:fair策略,通用hash,一致性hash -
加权轮询策略
首先将请求都分给高权重的机器,知道该机器的权重降到了比其他机器低,才开始讲请求分给下一个高权重的机器
当所有后端机器都down掉时,Nginx会立即将所有机器的标志位清成初试状态,以避免造成所有机器都处在timeout的状态 -
IP hash策略
是一种变相的轮询算法 -
fair策略
根据后端服务器的响应时间判断负载情况,从中选出负载最轻的机器进行分流 -
通用hash,一致性hash策略
通用hash比较简单,可以以Nginx内置的变量为key进行hash,一致性hash采用Nginx内置的一致性hash环,支持memcache
NGINX配置
http{
upstream cluster{
server srv1;
server srv2;
server srv3;
}
server{
listen 80;
location /{
proxy_pass http://cluster;
}
}
}
- 四层负载均衡的实现
通过报文中的目标地址和端口,再加上负载均衡设备设置的服务器选择方式,决定最终选择的内部服务器
LVS实现服务器集群负载均衡有三种方式,NAT,DR和TUN