-
高并发和大流量解决方案
- 高并发架构相关概念
- 并发
并发,在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机制上运行,但任一个时刻点上只有一个程序在处理机上运行。 - 通常如果一个系统的日PV在千万以上,有可能是一个高并发的系统。
- QPS:每秒钟请求或者查询的数量,在互联网领域,指每秒响应请求数(HTTP请求)。
- 吞吐量:单位时间内处理的请求数量(通常由QPS与并发数决定)。
- 响应时间:从请求发出到收到响应花费的时间。
- PV:综合浏览量(Page View),即页面浏览量或者点击量,一个访客在24小时内访问的页面数量。
- UV:独立访客(UniQue Visitor),即一定时间范围内相同访客多次访问网站,只计算为一个独立访客。
- 日网站带宽=PV / 统计时间(换算到秒)* 平均页面大小(单位kb)*8。
- QPS不等于 并发连接数
- QPS式每秒HTTP请求数量,并发连接数是系统同时处理的请求数量。
- 峰值每秒请求数QPS = (总PV数* 80%) / (6小时秒数 * 20%)
- 常用性能测试工具:ab、wrk、http_load、web bench、siege、apache jmeter
- 并发
- 高并发架构相关概念
-
web资源防盗链
- 通过Reterer或者签名,网站可以检测目标网页访问的来源网页,如果是资源文件,则可以跟踪到显示它的网站地址。一旦检测到来源不是本站即进行阻止或者返回制定地址。
- Referrer
- Nginx模块ngx_http_ referrer_module用于阻挡来源非法的域名请求
- Nginx指令valid_ referrers,全局变量$invalid_ referrer
- valid_ referrers none | blocked | server_names | string
location ~ .*\.(jpg|gif|png)$ { valid_referers none blocked server_names; if ($invalid_referer) { # return 403; rewrite ^/ 地址 } }
- 签名
- 使用第三方模块HttpAccessKeyModule实现Nginx
- accesskey on | off 模块开关
- accesskey_hashmethod md5 | sha-1 签名加密方式
- accesskey_arg GET 参数名称
- accesskey_signature 加密规则
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf|flv|mp4|ico)$ { accesskey on; accesskey_hashmethod md5; accesskey_arg sign; #参数键名 accesskey_signaurre "mytest$remote_addr"; #mytest字符串拼接客户端ip然后md5加密 expires 30d; }
- PHP端访问一个图片
<?php //自定义的秘钥串 $accesskey = "mytest"; //客户端IP $user_addr = $_SERVER['REMOTE_ADDR']; $urlkey = md5($accesskey .$user_addr ); //sign是Nginx配置中的参数 echo '<img src="./images/5.png?sing="'. $urlkey .'">'; //对比测试 echo '<img src="./images/5.png">';
-
减少HTTP请求
- 域名解析->TCP连接->发送请求->等待->下载资源->解析时间
- DNS缓存
- 查找DNS缓存也是需要时间,多个缓存就要查找多次有可能缓存会被清除
- HTTP1.1协议规定请求只能串行发送,也就是说一百个请求必须依次逐个发送,前面的一个请求完成才能开始下一个请求。
- 图片地图
- CSS Sprites
- CSS Sprites 即 CSS精灵,通过合并图片,通过指定css的background-image和background-position来显示元素
- 合并脚本和样式表
- 图片使用Base64编码,减少页面请求
-
浏览器缓存和压缩优化技术
- HTTP缓存机制
- 200 from cache:直接从本地缓存中获取响应,最快,最省流浪
- 304 Not Modified:协商缓存,浏览器在本地没有命中的情况下请求头发送一定的数据到服务端,如果服务端数据没有改变浏览器从本地缓存响应,返回304;快速,发送很少的数据,只返回一些基本的响应头信息,数据量很少,不发送实际响应体。
- 200 ok:以上两种缓存全都失败,服务器返回完整的响应。没有用到缓存,相对最慢。
- 相关Header
- Pragma(最优)
HTTP1.0 时代的遗留产物,该字段被设置为no-cache时,会告知浏览器禁用本地缓存,即每次都向服务器发送请求。 - Expires(最低)
HTTP1.0时代用来启用本地缓存字段,expires值对应一个形如Wed, 21 Oct 2015 07:28:00 GMT的格林威治时间,告诉浏览器缓存实现的时刻,如果还没到该时刻,表明缓存有效,无需发送请求。 - Cache-Control(次之)
- HTTP1.1针对Expires时间不一致的解决方案,运用Cache-Control告知浏览器缓存的时间间隔而不是时刻,即使具体时间不一致,也不影响缓存管理。
- no-store
禁止浏览器缓存响应 - no-cache
在释放缓存副本之前,强制高速缓存将请求提交给原始服务器进行验证。 - max-age=秒数
告知浏览器该响应本地缓存有效时间的最长期限。
- Last-Modified
通知浏览器资源的最后修改时间。 - If-Modified-Since
If-Modified-Since请求的HTTP标头发出请求的条件:服务器会发送回所请求的资源,用200状态,只有当它已经给定的日期之后被最后修改。如果请求没有被修改,那么响应将是304没有任何主体的;Last-Modified头将包含最后一次修改的日期。不同于If-Unmodified-Since,If-Modified-Since只能与GET或HEAD一起使用。 - ETag
所述ETag HTTP 响应报头为资源的特定版本的标识符。它允许缓存更高效,并节省带宽,因为如果内容没有改变,Web 服务器不需要发送完整的响应。另一方面,如果内容发生了变化,etags 有助于防止资源的同时更新互相覆盖(“空中冲突”)。如果给定 URL 处的资源发生更改,则Etag必须生成新值。因此,Etags 与指纹相似,也可能用于某些服务器的跟踪目的。它们的比较可以快速确定资源的两个表示是否相同,但它们也可能被设置为无限期地由跟踪服务器持续存在。 - If-None-Match
If-None-Match HTTP 请求报头使得所述请求为条件。对于GET和HEAD方法,200只有服务器没有ETag与给定资源匹配的情况下,服务器才会返回具有状态的请求资源。对于其他方法,仅当最终现有资源ETag不符合任何列出的值时才会处理该请求。条件GET和HEAD方法失败时,服务器必须返回 HTTP 状态码304(未修改)。对于应用服务器端更改的方法,将使用状态码412( Precondition Failed )。请注意,生成304响应的服务器必须生成以下头域中的任何一个头域,这些域头域应该发送到同一个请求的200(OK)响应中:Cache-Control,Content-Location,Date,ETag,Expires 和 Vary。与存储的比较ETag使用弱比较算法,这意味着不仅两个文件是相同的字节到字节,而且如果内容是等同的,则认为两个文件是相同的。例如,只有页脚生成日期不同的两页才会被视为相同。
当与其结合使用时If-Modified-Since,它具有优先权(如果服务器支持它)。
- Pragma(最优)
- Nginx配置缓存策略
- add_header指令
- 添加状态码为2xx和3xx的响应头信息
- add_header name value [always]
- 可以设置Pragma、Expires、Cache-Control,可以继承
- add_header指令
- 前端代码和资源的压缩
- JS、CSS、HTML、图片压缩
去除空白符、换行符等等 - Gzip压缩
#开启gzip gzip on; #缓冲(在内存中缓冲几块?每块多大?) gzip_buffers 32 4k | 16 8k; #压缩级别【1-9】,越大压缩率越高,同时消耗cpu资源也越多,建议设置在4左右。 gzip_comp_level 3; #低于1kb的资源不压缩 gzip_min_length 1k; #需要压缩哪些响应类型的资源,多个空格隔开。不建议压缩图片,下面会讲为什么。 gzip_types text/plain application/javascript application/x-javascript text/javascript text/xml text/css; #配置禁用gzip条件,支持正则。此处表示ie6及以下不启用gzip(因为ie低版本不支持) gzip_disable "MSIE [1-6]\."; #是否添加“Vary: Accept-Encoding”响应头 gzip_vary on;
- JS、CSS、HTML、图片压缩
- HTTP缓存机制
-
CDN加速
- CDN的全称是Content Delivery Network,即内容分发网络。其基本思路是尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定。通过在网络各处放置节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网络,CDN系统能够实时地根据网络流量和各节点的连接、负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上。其目的是使用户可就近取得所需内容,解决 Internet网络拥挤的状况,提高用户访问网站的响应速度。
- 优势
- 本地Cache加速,提高企业站点的访问速度
- 跨运营商的网络加速,保证不同网络的用户都得到良好的访问质量
- 远程访问用户根据DNS负载均衡技术智能自动选择Cache服务器
- 自动生成服务器的远程Mirror cache服务器,远程用户访问时从cache服务器上读取数据,减少远程访问的宽带、分担网络流量、减轻原站点WEB服务器负载均衡等功能。
- 广泛分布的CDN节点加上节点之间的智能冗余机制,可以有效的预防黑客入侵。
- CDN工作原理
- 用户发起请求
- 智能DNS的解析(根据IP判断地址位置,接入网类型,选择路由最短和负载均衡最轻的服务器)
- 取得缓存服务器IP
- 把内容返回给用户(如果缓存中有)
- 向源站发起请求
- 把内容返回给用户
-
将结果存入服务器
- 实现
- 可用LVS做四层负载均衡
- 可用Nginx、Varnish、Squid、Apache 做7层负载均衡和cache
- Nginx、Squid反向代理
-
建立独立的图片服务器
- 分担Web服务器的I/O负载
- 采用独立域名
- NFS共享方式
- 利用FTP同步
-
动态语言静态化
- 将现有PHP等动态语言的逻辑代码生成静态HTML文件,用户访问动态脚本重定向到静态HTML文件的过程。
- 实现方式
- 使用模版引擎
可以使用Smarty的缓存机制生成静态HTML缓存文件。 - 利用ob系列的函数
//打开缓冲区 ob_start(); //使用phpinfo函数 phpinfo(); //得到缓冲区的内容并且赋值给$info $info = ob_get_contents(); //打开文件info.txt $file = fopen('info.txt', 'w'); //写入信息到info.txt fwrite($file, $info); fclose($file);
- 使用模版引擎
-
动态语言层的并发处理
-
进程、线程、协程
-
进程
- 进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。
- 进程是一个执行中的程序。
- 进程的三态模型:多道程序系统中,进程在处理器上交替运行,状态不断的发生变化。
-
线程
- 线程是进城的一个实体,是被系统独立调度和分派的基本单位,线程自己不拥有系统资源,只拥有一点儿在运行中必不可少的资源但它可与同属一个进城的其他线程共享所拥有的全部资源。
- 一个线程可以创建和撤销另一个线程,同一进城中的多个线程之间可以并发执行。
-
协程
- 协程是一种用户态的轻量级线程,协程的调度完全由用户控制。从技术的角度来说,“协程就是你可以暂停执行的函数”。协程拥有自己的寄存器上下文和栈。协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。
-
线程与进程的区别
- 地址空间:线程是进程内的一个执行单元,进程内至少有一个线程,它们共享进程的地址空间,而进程有自己独立的地址空间
- 资源拥有:进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资源
- 线程是处理器调度的基本单位,但进程不是
- 二者均可并发执行
- 每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口,但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
-
协程与线程的区别
- 一个线程可以多个协程,一个进程也可以单独拥有多个协程。
- 线程进程都是同步机制,而协程则是异步。
- 协程能保留上一次调用时的状态,每次过程重入时,就相当于进入上一次调用的状态。
- 线程是抢占式,而协程是非抢占式的,所以需要用户自己释放使用权来切换到其他协程,因此同一时间其实只有一个协程拥有运行权,相当于单线程的能力。
- 协程并不是取代线程, 而且抽象于线程之上, 线程是被分割的CPU资源, 协程是组织好的代码流程, 协程需要线程来承载运行, 线程是协程的资源, 但协程不会直接使用线程, 协程直接利用的是执行器(Interceptor), 执行器可以关联任意线程或线程池, 可以使当前线程, UI线程, 或新建新程.。
- 线程是协程的资源。协程通过Interceptor来间接使用线程这个资源。
-
-
多进程、多线程
- 多进程
- 同一时间里,同一个计算机系统中如果允许两个或者两个以上的进程处于运行状态。
- 多进程
同步阻塞模型
-
异步非阻塞模型
- 现在各种高并发异步I/O的服务器程序都是基于epoll实现的。
- IO服用异步非阻塞程序使用经典的Reactor模型,它本身不处理任何数据收发。只是监听一个socket句柄的事件变化。
-
PHP并发编程实践
- PHP的Swoole扩展
- 消息队列
- 接口的并发请求
-
-
数据库缓存层的优化
- MySQL查询缓存
- 启用MySQL缓存
query_cache_type=参数 //可选项目以及说明如下: //0:那么可以说,你的缓存根本就没有用,相当于禁用了 //1:将会缓存所有的结果,除非你的select语句使用SQL_NO_CACHE禁用了查询缓存。 //2:则只缓存在select语句中通过SQL_CACHE指定需要缓存的查询。 query_cache_size //将query_cache_size设置为具体的大小,具体大小是多少取决于查询的实际情况,但最好设置为1024的倍数,参考值32M
- 启用MySQL缓存
- Memcache缓存
- Memcache是一个高性能的分布式的内存对象缓存系统,通过在内存里维护一个统一的巨大的hash表它能够用来存储各种格式的数据,包括图像、视频、文件以及数据库检索的结果等。简单的说就是将数据调用到内存中,然后从内存中读取,从而大大提高读取速度。
- 先检查客户端的请求数据是否在memcached中,如有,直接把请求数据返回,不再对数据库进行任何操作;如果请求的数据不在memcached中,就去查数据库,把从数据库中获取的数据返回给客户端,同时把数据缓存一份到memcached中。
- Redis缓存
- Redis、Memcache区别
- 性能相差不大
- Redis在2.0后增加了VM特性,突破了物理内存的限制
- Memcache可以修改最大可用内存,采用LRU算法
- Redis依赖客户端来实现分布式读写
- Memcache本身没有数据冗余机制
- Redis支持(快照、AOF),依赖快照进行持久化,aof增加了可靠性同时,对性能有所影响。
- Redis支持多种类的数据类型
- Redis用于数据量较小的高性能操作运算上
- Memcache不支持持久化,通常做缓存,提升性能
- Memcache在并发场景下,用cas保持一致性,Redis事务支持比较弱,只能保证事务中的每个操作连续执行。
- Memcache用于在动态系统中减少数据负载,提升性能;适合做缓存,提高性能。
- MySQL查询缓存
-
MySQL数据层的优化
- 数据表数据类型优化
- 索引优化
- SQL语句优化
- 存储引擎的优化
- 数据表结构设计的优化
- 数据库服务器架构的优化
-
Web服务器的负载均衡、请求分发
- 七层负载均衡的实现
- 基于URL等应用层信息的负载均衡
- Nginx和proxy是它一个很强大的功能
- 内置策略
- IP Hash
- 加权轮询
- 扩展策略
- fair策略
- 通用hash
- 一致性hash
- Nginx配置
http { upstream 名称 { server ser1; server ser2; server ser3; } server{ listen 80; location / { proxy_pass http://名称; } } }
- 四层负载均衡的实现
- 七层负载均衡的实现
高并发解决方案
最后编辑于 :
©著作权归作者所有,转载或内容合作请联系作者
- 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
- 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
- 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
推荐阅读更多精彩内容
- JAVA并发编程与高并发解决方案 - 并发编程 五 相关文章 JAVA并发编程与高并发解决方案 - 并发编程 一 ...
- 高并发解决方案--负载均衡 1,什么是负载均衡? 当一台服务器的性能达到极限时,我们可以使用服务器集群来提高网站的...