高并发优化方案

高并发

QPS

每秒处理请求数

  • QPS 达到50
    一般服务器就能应付,不需要优化

  • QPS 达到100
    假设关系型数据库在0.01秒完成查询。
    数据库缓存,数据库的负载均衡

  • QPS 达到800
    假设使用百兆带宽,出口带宽为8m,假设每个页面10k。百兆带宽已被吃完
    CDN加速,负载均衡

  • QPS 达到1000
    缓存层已无法应对
    做静态化

  • QPS 达到2000
    文件系统的访问锁都成为灾难
    做业务分离,分布式存储


优化方案

流量优化

防盗链处理

盗链是指在自己的页面上展示一些并不在自己服务器上的内容。如图片、音乐、视频、软件
防止别人通过技术手段绕过本站的资源展示页,盗用本站资源,使资源连接失效

根据referer或者签名,网站可以检测目标网页访问的来源,如果是资源文件则可以跟踪到显示它的网页地址。
nginx 模块ngx_http_referer_module用于阻挡来源非法的域名请求
nginx 指令valid_referers,全局变量$invalid_referer

//nginx 防盗链配置
location ~* \.(gif|jpg|png|bmp)$ {
        valid_referers none blocked *.domain.com;
//    valid_referers none blocked server_name 
        if ($invalid_referer) {//如果不在白名单
                 return 403;
                #rewrite ^/ http://www.ttlsa.com/403.jpg;
        }
    }
// none :表示referer来源为空的情况
// blocked:referer来源不为空的情况,但是里面的值被代理或者防火墙删除了
// server_name:白名单

php curl伪造referer绕过上述防盗链

使用nginx 的 ngx_http_secure_link_module 模块进行防盗链

nginx 配置如下

location /img/ {
                # 两个arg参数由请求获得
                secure_link $arg_md5,$arg_expires;
                # secret 为加密字符串 uri为访问的路由
                secure_link_md5 secret$arg_expires$uri;


                if ($secure_link = "") {
                        return 403;
                }

                if ($secure_link = "0") {
                        return 410;
                }
        }

php代码如下

//加密字符串 和nginx一致
$secret = "secret";
$uri = "/img/a.txt";
$expire = time();
//加密顺序要和nginx的配置一致
$md5 = base64_encode(md5($secret.$expire.$uri,true));
$md5 = strtr($md5, '+/', '-_');
$md5 = str_replace('=', '', $md5);
$url = "http://bd.test.com/img/a.txt?md5={$md5}&expires={$expire}";

前端优化

减少http请求

  • 使用图片地图 //变多次请求为一次
  • 使用css 精灵 贴图定位 //变多次请求为一次
  • 合并多个css和js //变多次请求为一次
  • 使用base64图片 //将图片请求省去
    代码示例
$src = 'https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/bd_logo1_31bdc765.png';
$img_info = getimagesize($src);
$base = base64_encode(file_get_contents($src)); //该base64 也可以用于css
$img_src = "data:{$img_info['mime']};base64," . $base;
exit("![]({$img_src})");

启用浏览器缓存和文件压缩

http缓存机制

缓存分类

  • 200 from cache:直接从本地缓存中获取响应 //最快
  • 304 not modified:协商缓存,浏览器在本地缓存没有命中的情况下,请求头中发送一定的校验数据到服务端,如果服务端没有改变,则从本地缓存中获取,返回304 //快速 不发送响应体
  • 200 ok:以上两种缓存失败,直接从服务器请求回来 //最慢

相关header
优先级 pragma > cache-control > expires

  • pragma:http1.0,设置为no-cache时,会禁用本地缓存
  • expires:http1.0,expires对应一个时间戳,表示到期时间
  • cache-control:http1.1 针对expires 时间不一致,运用时间间隔。
    no-store:禁止浏览器缓存响应
    no-cache:不允许直接使用本地缓存,先发起协商请求
    max-age=delta-seconds:告知浏览器该响应本地缓存有效的最长期限,以秒为单位

协商缓存header

  • Last-modified :通知浏览器资源的最后修改时间,时间戳
  • Etag:http1.1 文件指纹标示,如果文件发送修改,则指纹会变。
  • if-none-match:浏览器在本地缓存没有命中的情况下,请求头中发送一定的校验数据到服务端,如果服务端没有改变,则从本地缓存中获取,返回304
// php 模拟nginx 的304
$since = $_SERVER['HTTP_IF_MODIFIED_SINCE'];
$lefttime = 3600;
if (strtotime($since) + $lefttime > time()) {
    header('HTTP/1.1 304 Not Modified');
    exit;
}
header('Last-Modified: ' . gmdate('D,d M Y H:i:s', time() . ' GMT'));
echo time();
nginx配置缓存策略

add_header指令:添加状态码为2xx和3xx的响应头信息
add_header name value [always];
可以设置 pragma/expires/cache-control 可以继承
expires指令:通知浏览器过期时长
expires time;
为负值时,表示cache-control:no-cache
为正值时,表示cache-control:max-age=指定时间

location ~* \.(gif|jpg|png|bmp)$ {
  expires 30d;# 表示遇到上述图片时,告诉浏览器缓存30天
  expires 12h;# 缓存12小时
  etag off;#关闭etag
  add_header cache-control max-age=3600;#缓存3600
}
前端代码和资源压缩
  • js代码压缩
    一般是去掉多余空格、回车、替换长变量名、简化一些代码的写法
    js代码压缩工具有在线工具、应用程序、编辑器插件;常见uglifyjs、yui composer、closure compiler
  • css压缩
    去除空白、注释;常见css compressor
  • html压缩
    不建议使用,有时会破坏代码结构。一般采用gzip
  • 图片压缩
    对图片压缩是有必要的。jpegmini,imageoptim,tinypng
  • gzip压缩
    配置nginx服务 传送门
    gzip on|off 是否开启服务
    gzip_buffers 32 4K| 16 8K 缓冲
    gzip_comp_level [1-9] 推荐6,压缩级别,级别越高,压得越小,越耗cpu
    gzip_disable # 正则匹配ua 什么样的uri不尽兴gzip
    gzip_min_length 200 # 开始压缩的最小长度
    gzip_http_version 1.0|1.1 开始压缩的http协议版本
    gzip_proxied 设置请求代理服务器,该如何缓存内容

cdn加速

相关概念
什么是cdn:content dilivery network,内容分发网络。可以根据情况,将用户请求导向最近的节点。
使用cdn的优势:本地cache加速,提高站点访问速度,分担网络流量,节省带宽

  • cdn工作原理:
    传统访问:输入域名->解析ip->找到服务器->服务器返回
    cdn:请求->智能dns解析->换回缓存服务器ip->内容返回(如命中缓存)->向源站点请求->结果返回给用户->结果缓存到缓存服务器
  • cdn适用场景
    站点中有大量静态资源,如css js
    html和图片
    大文件
    直播网站
  • cdn实现方式
    lvs4层负载均衡
    nginx 7层负载均衡和cache
    反向代理

建立独立图片服务器

分担web服务器的io负载,提高性能和稳定性
能够专门对图片服务器进行优化,减少带宽成本,提高访问时间
提高可扩展,提高图片吞吐
采用独立域名,突破浏览器同一域名并发连接数限制。要处理,如何进行上传图片和图片同步


服务端优化

动态语言静态化

  • 什么是动态语言静态化
    将现有php等动态语言的逻辑代码生成为静态html文件,用户访问动态脚本重定向到静态html文件的过程,对于实时性要求不高的页面
  • 为什么要静态化
    动态脚本通常会做逻辑计算和数据查询,访问量大时,服务器压力越大
    访问量大时会造成cpu负载过高,数据库压力过大,
    静态化可以减低逻辑处理压力,降低数据库服务器查询压力
  • 静态化实现方式
    使用模版引擎
    利用ob系列函数
    ob_start 打开输出控制缓冲
    ob_get_contents 返回输出缓冲区内容
    ob_clean 清空输出缓冲
    ob_end_flush 冲刷到缓冲区,并关闭
 time()) {
    include $cache_name;
    exit;
}
ob_start();//开启缓存
?>
    

this is ob_cache

动态语言并发处理

概念理解

进程

进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调用的基本单位,是操作系统的基础。一个执行中的程序
进程的三态模型:多道程序系统中,进程在处理器上交替运行,状态不断发生变化;主要有运行、就绪、阻塞三种状态。

  • 运行:当一个进程在处理机上运行时,则称该进程处于运行状态。处于此状态的进程数目小于处理器数目,对于单处理器系统处于运行的进程只能有一个,在没有其他进程执行时,通常会自动执行系统的空闲进程
  • 就绪:当一个进程获得了处理机意外以外的一切资源,一旦得到处理机即可运行,则成为就绪状态。就绪状态可以按优先级来划分队列。例如,当一个进程由于时间片用完而进入就绪状态时,排入低优先级队列;当进程有io操作完成而进入就绪状态时,排入优先级高的队列
  • 阻塞:也称为等待或者睡眠,一个进程正在等待某一事件发生(例如请求i o而等待io操作)而暂时停止运行,这时即使把处理机分配给进程也无法运行,故称为阻塞。
  • 进程的五态模型:对于一个实际的系统,进程的状态及其转换更为复杂。包括新建态、活跃态/静止就绪、运行、活跃阻塞/静止阻塞、终止态
线程

由于用户的并发请求,为每一个请求都创建一个进程显然是不合理的。从系统资源开销的方面和效率上,引入线程的概念。
线程,有时被称为轻量级进程,是程序执行流的最小单元。线程是进程中的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源。线程可与同属一个进程的其他线程共享进程所拥有的全部资源。一个线程可以创建或撤销另
线程的三种状态:就绪,阻塞和运行

  • 就绪 线程具备运行的所有条件,逻辑上可以运行,在等待处理机
  • 阻塞 线程在等待一个事件,逻辑上不可执行
  • 运行 线程占有处理机,正在运行
线程和进程的区别
  • 线程是进程内的一个执行单元,进程内至少有一个线程,他们共享进程的地址空间,而进程拥有自己的地址空间。若程序只有一个线程,那就是程序本身了。
  • 进程是资源分配和拥有的单元,同一个进程内的线程共享进程的资源
  • 线程是处理器调度的基本单元,但进程不是
  • 两者均可并发执行
  • 每个独立线程有一个程序运行的入口,顺序执行序列和程序出口,但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制
协程

协程是一种用户态的轻量级的线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文切换非常快。

线程和协程的区别
  • 一个线程可以多个协程,一个进程也可以单独拥有多个协程
  • 线程进程都是同步机制,而协程是异步
  • 协程能保存上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态。
多进程

同一时间里,同一计算机系统中如果允许两个或两个以上的进程处于允许状态,就是多进程。

多线程

线程就是把一个进程分成很多片,每一片可以是一个独立的流程
与多进程的区别是只会使用一个进程的资源,线程间可以直接通信

同步阻塞模型

最早的服务器程序都是通过多进程,多线程来解决并发io问题,一个请求创建一个进程,然后子进程进入循环同步阻塞与客户端进行交互,收发数据。

异步非阻塞

现在各种高并发异步io的服务器程序都是基于epoll实现的。
io复用异步阻塞程序使用经典reactor模型,reactor本身不处理任何数据收发,只是可以监听一个socket句柄的时间变化

php并发编程
  • swoole扩展
  • 消息队列
    应用解耦,流量削峰,日志处理,消息通讯,kafka rabbitmq,redis
  • 接口的并发请求

数据库优化

数据库缓存

缓存需要考虑的问题:缓存方式的选择,缓存场景的选择,缓存数据的实时性,缓存数据的稳定性

mysql查询缓存

sql文本和查询结果的映射,sql必须完全一致(mysql内部使用hash码对应),才能使用缓存。
query_cache_type
查询缓存有0、1、2。0表示不使用查询缓存,1表示始终使用查询缓存,2表示按需使用查询缓存。

  • 为1 时,也可以关闭查询缓存;select SQL_NO_CACHE * from table where condition;
  • 为2 时,按需使用。select SQL_CACHE * from table where condition;
    query_cache_size 默认情况下为0。表示为查询缓存预留的内存为0,0则无法使用查询缓存。可在my.cnf中设置。
    清空缓存
  • flush query cache //清理查询缓存中内存碎片
  • reset query cache //从查询缓存中移出所有查询
  • flush tables //关闭所有的表,同时将清空缓存中的内容
    redis
    可固化,数据结构多,
mysql查询优化

数据库服务器架构优化
数据库表结构优化
索引优化
sql优化

web服务器优化

7层负载均衡

基于url应用层信息的均衡操作

优点
  • 功能强大,运行稳定,性能卓越
  • 配置简单灵活
  • 能够自动剔除工作不正常的后段服务器
  • 上传文件使用异步模式
  • 支持多种分配策略,可以权重分配,分配方式灵活
nginx负载均衡
内置策略
  • 加权策略:首先将请求分配给高权重的机器,直到该机器的权值降到比其他机器低时,才开始分配请求给下一个高权重机器。
  • ip hash:内置另外一个负载均衡,流程和轮询很类似,只是其中的算法和具体的策略有些变化。ip hash 算法是一种变相的轮询算法。
扩展策略:fair策略、通用hash、一致性hash
  • fair 策略:根据后段服务器响应时间判断负载情况,从中选择出负载最轻的机器进行分流。
  • 通用hash、一致性hash:通用hash比较简单,可以以nginx内置的变量为key进行hash,一致性hash采用了nginx内置的一致性hash环,支持memcache
http{
      upstream cluster{
            server srv1;
            server srv2;
      }
      server{
            listen 80;
            location / {
                    proxy_pass http://cluster;
            }
      }
}
//以下为示例
 upstream cluster{
                #ip_hash;#根据hash,因ip一致所以拿到同一个机器
                server 127.0.0.1:8080 weight=10;# 权重 轮询从大到小,顺序8081,8080,8082
                server 127.0.0.1:8081 weight=13;
                server 127.0.0.1:8082 weight=8;
        }
server {
    listen       8083;
    server_name  localhost;
    #charset koi8-r;
    #access_log  /var/log/nginx/log/host.access.log  main;
    location / {
        proxy_pass http://cluster;# 这里的cluster与上面的cluster一致
    }
}
# 服务器1
server {
    listen       8080;
    server_name  localhost;
    #charset koi8-r;
    #access_log  /var/log/nginx/log/host.access.log  main;
    location / {
        add_header REAL_SERVER 8080;#在响应头里查看,区别server
       root   /usr/share/nginx/html;
        index  index.html index.php index.htm;

    }
}
# 服务器2
server {
    listen       8081;
    server_name  localhost;
    #charset koi8-r;
    #access_log  /var/log/nginx/log/host.access.log  main;
    location / {
        add_header REAL_SERVER 8081;
       root   /usr/share/nginx/html;
        index  index.html index.php index.htm;

    }
}
# 服务器3
server {
    listen       8082;
    server_name  localhost;
    #charset koi8-r;
    #access_log  /var/log/nginx/log/host.access.log  main;
    location / {
        add_header REAL_SERVER 8082;
       root   /usr/share/nginx/html;
        index  index.html index.php index.htm;

    }
}

4层负载均衡

通过报文中的目标地址和端口,再加上负载均衡设备设置的服务器选择方式,决定最终的内部服务器
lvs实现服务器集群有三种方式NAT、DR和TUN模式

你可能感兴趣的:(高并发优化方案)