怎么解决高并发大流量问题?下面本篇文章就来给大家分享下高并发大流量 web 解决思路及方案,希望对大家有所帮助!
高并发 web 架构相关概念
- QPS: 每秒钟请求或查询的数量,在互联网领域,指每秒相应请求数(http 请求)。
- 峰值每秒的 QPS:(总 PV 数 80%)/(6 小时秒数 20%),80% 的访问量集中在 20% 的时间
- 并发连接数:系统同时处理的请求数量
- 吞吐量:单位时间内处理的请求数量(通常由 QPS 与并发数决定)。
- 响应时间:从请求发出到收到响应花费的时间。例如系统处理一个 HTTP 请求需要 100ms,这个 100ms 就是系统的响应时间。
- PV:综合浏览量(Page View)即页面浏览量和点击量,一个访客在 24 小时内访问的页面数量。
- UV:独立访客(UniQue Visitor), 即一定时间范围内相同访客多次访问网站,只计算为 1 个独立访客。
- 带宽:计算带宽大小关注两个指标,峰值流量和平均页面大小。
- 日网站带宽 = PV / 统计时间(一天换算到秒)* 平均页面大小(单位 KB)*8。
- 压力测试:测试承受的最大并发,测试最大承受的 QPS,需要注意的测试并发测试机需要与被测试机器分开,不要对线上服务器进行并发测试,观察 ab 测试的所在机器,以及被测试机器的前端机的 CPU,内存,网络等都不超过最高限度的 75%。
- 并发量
- 响应速度
- 容错能力
- 常用的性能测试工具:ab,wrk,http_load,Web Bench,Siege,Apache JMeter。
高并发大流量 web 整体解决思路
- 流量优化
- web 资源防盗链防止第三方系统盗用图片,css,js 等占用服务器流量和服务器带宽
- 前端优化
- 减少 http 请求:图片合并,js 合并,css 合并压缩,虽然文件可能大点但请求会减少
- 添加异步请求:通过实际 ajax 调用接口获取数据
- 启动浏览器的缓存和文件压缩(也可以启用 nginx 的压缩模块)
- cdn 加速:解决带宽不够用的问题,数据缓存到 cdn 的节点,访问的时候选择就近的节点,减少带宽加快访问速度
- 建立独立的图片服务器:图片是很吃 io 的,可以将图片服务器与 web 服务器完全分离开,可以区分其它服务器单独搭建图片服务器不属于计算型的配置可以适当的调整,图片服务器还可以集群
- 服务端的优化
- 页面的静态化:动态的页面静态 html, 减少服务器的负载压力,页面静态化穿透,静态化有有效时间
- 动态语言并发处理:异步处理,多线程,队列的异步处理
- 数据库的优化:
- 数据库的缓存:memcache,redis 的缓存
- mysql 索引优化,mysql 分库分表,mysql 分区操作,mysql 主从复制读写分离,mysql 的负载均衡,mysql 的主从热备
- web 服务器的优化:
- 负载均衡:可以使用 ningx 的反向代理使用负载均衡,可以使用网络分层中的第四层 lvs 实现负载均衡
web 服务器负载均衡
负债均衡
- 四层负载均衡:所谓四层负载均衡就是基于 IP 端口的负载均衡
- 七层负载均衡:所谓七层的负载均衡就是基于(URL)信息的负载均衡
七层负载均衡实现:
基于 URL 等应用层信息的负债均衡 ningx 的 proxy 是它一个很强大的功能,实现了 7 层负载均衡,功能强大,性能卓越,运行稳定,配置简单灵活,能够自动剔除工作不正常的后端服务器,上传文件可以使用异步模式上传,支持多种分配策略,可以分配权重,分配方式灵活。
nginx 负载均衡策略
- IP Hash (内置)
- 加权轮询(内置)
- fair 策略(扩展)
- 通用 hash(扩展)
- 一致性 hash(扩展)
1、IP Hash 策略
nginx 内置的另一个负载均衡的策略,流程和轮询很相似,只是其中的算法和具体的策略有些变化,IP hash 算法是一种变相的轮询算法
2、加权轮训策略
首先将请求都分给高权重的机器,直到该机器的权值降到了比其他机器低,才开始将请求分给下一个高权重的机器,当所有后端机器都 down 掉时,nginx 会立即将所有机器的标志位清成初始状态,以避免造成所有的机器都处在 timeout 的状态
3、fair 策略
根据后端服务器的响应时间判断负载情况,从中选出负载最轻的机器进行分流
通用 hash、一致性 hash 策略,通用 hash 比较简单,可以以 nginx 内置的变量为 key 进行 hash,一致性 hash 采用了内置的一致性 hash 环,支持 memcache
四层负载均衡实现
通过报文中的目标地址和端口,再加上负载均衡设备设置的服务器选择方式,决定最终选择的内部服务器
lvs 相关术语:
- DS:director server 目标服务器,即负载均衡器
- RS:Real Server 真实服务器,即后端服务器
- VIP:直接面向用户的 IP 地址,通常为公网 IP 地址
- DIP:Director Server Ip 主要用于内部主机通信的 IP 地址
- RIP:Real Server IP 后端真实服务器的 IP 地址
- CIP:Client IP
lvs 负载均衡三种方式:
NAT:修改目标 IP 地址为后端的 RealServer 的 IP 地址
DR:修改目标 mac 地址为后端的 RealServer 的 mac 地址
TUNNEL:较少使用,常用于异地容灾
四七层负载均衡优缺点
四层比七层可以承载更大的并发量,使用大型站点小
七层可以实现更为复杂的负载均衡控制,比如 URL、基于 session、动静分离等
七层能够占用大量的 CPU 时间,承载的并发量
cdn 加速
什么是 cdn?
节点:可以理解为真实服务器的镜像。
全称是 Content Delivery Network,即内容分发网络尽可能避开互联网上有可能影响数据传输速度和稳定性的瓶颈和环节,使内容传输的更快、更稳定。
在网络各处放置节点服务器所构成的现有的互联网基础之上的一层智能虚拟网络。
cdn 系统能够实时地根据网络流量和各节点的连接,负载状况以及到用户的距离和响应时间等综合信息将用户的请求重新导向离用户最近的服务节点上。
cdn 的优势是什么?
- 1、本地的 cache 加速,提高企业站点(尤其含有大量图片和静态页面站点)的访问速度
- 2、跨运营商的网络加速,保证不同网络的用户得到良好的访问质量
- 3、远程访问用户根据 DNS 负载均衡技术智能自动选择 Cache 服务器
- 4、自动生成服务器的远程 Mirror(镜像)cache 服务器,远程用户访问时从 cache 服务器上读取数据,减少远程访问的带宽,分担网络流量,减轻愿站点 web 服务器负载等功能。
- 5、广泛分布的 cdn 节点加上节点之间的智能冗余机制,可以有效的预防黑客入侵
cdn 的工作原理是什么?
传统的访问:用户在浏览器输入域名发起请求,解析域名获取服务器 ip 地址,根据 ip 地址找到对应的服务器,服务器响应并返回数据。
使用 cdn 访问:用户发起请求,智能 dns 的解析(根据 ip 判断地理位置,接入网类型,选择路由最短和负载最轻的服务器),取得缓存服务器 ip,把内容返回给用户(如果缓存中有),向源站发起请求,将结果访问给用户,将结果存入缓存服务器。
cdn 的适用场景?
站点或者应用中大量静态资源的加速分发,例如:css,js,图片和 html
cdn 的实现方式?
- BAT 等实现的 CDN 服务
- 使用 LVS 的 4 层负载均衡
- 可用 nginx,varnish,squid,apache trafficServer 做七层负载均衡和 cache 使用 squid 做反向代理或者 nginx 做反向代理
建立独立的图片服务器
独立的必要性?
- 1、分担 web 服务器的 I/O 负载,将耗费资源的图片服务分离出来,提高服务器的性能和稳定性
- 2、能够专门对图片服务器进行优化,为图片服务设置针对性的缓存方案,减少带宽成本,提高访问速度
为啥采用独立的域名?
原因:同一域名下浏览器的并发连接数是有限制的,突破浏览器连接的限制,由于 cookie 的原因,对缓存不利,大部分 web cache 都只缓存不带 cookie 的请求,导致每次的图片请求都不能够命中 cache
独立后的问题?
- 如何进行图片上传和图片同步
- NPS 共享方式
- 利用 FTP 同步
动态页面静态化
相关概念:什么是动态语言静态化,为什么要静态化,静态化的实现方式。
动态语言的并发处理
什么是进程
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础
进程是一个 “执行中的程序”
进程的状态的三态模型
多道程序系统中,进程在处理器上交替运行,状态不断发生变化。
- 运行:当一个进程在处理机上运行时,则称该进程处于运行状态。处于此状态的进程的数目小于等于处理器的数目,对于单处理机系统,处于运行状态的进程只有一个。在没有其它进程可以执行时(如所有进程都在阻塞状态),通常会自动执行系统的空闲进程。
- 就绪:当一个进程获得了除处理机以外的一切所有资源,一旦得到处理机即可运行,则称此进程处于就绪状态。就绪状态可以按多个优先级来划分队列。例如,当一个进程由于时间片用完而进入就绪状态时,排入低优先级队列;当进程由 I/O 操作完成而进入就绪状态时,排入高优先级队列。
- 阻塞:也称为等待或睡眠状态,一个进程正在等待某一事件发生(例如请求 I/O 而等待 I/O 完成等)而暂时停止运行,这时即使把处理机分配给进程也无法运行,故称该进程处于阻塞状态。
什么是线程
由于用户的并发请求,为每一个请求都创建一个进程显然是行不通的,从系统资源开销方面或是响应用户请求的效率方面来看。因此操作系统中线程的概念便被引进了。
线程有时候被称为轻量级进程,是程序执行流的最小单元。
线程是进程中的一个实体,是被系统独立调度和分配的基本单位,线程自己不拥有系统资源,只拥有一点儿运行中必不可少的资源但它可与同属一个进程的其它线程共享进程所拥有的全部资源。
一个线程可以创建和撤销另一个线程,同一个进程中的多个线程之间可以并发执行。
线程是程序中一个单一的顺序控制流程。进程内一个相对独立的、可调度的执行单元,是系统独立调度和分派 cpu 的基本单位指运行中的程序的调度单位。
线程三状态
- 就绪状态:线程具备运行的所有条件,逻辑上可以运行,在等待处理机。
- 运行状态:线程占有处理机正在运行。
- 阻塞状态:线程在等待一个事件(如某个信号量),逻辑上不可执行。
什么是协程
协程是一种用户态的轻量级线程,协程的调度完全由用户控制。协程拥有自己的寄存器上下文和栈。协称调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切的开销,可以不要加锁的访问全局变量,所以上下文的切换非常快。
线程和进程的区别?
- 1、线程是进程内的一个执行单元,进程内至少有一个线程,它们共享进程的地址空间,而进程有自己独立的地址空间。
- 2、进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资源。
- 3、线程是处理器调度的基本单位,但进程不是
- 4、二者都可以并发的执行
- 5、每个独立的线程有一个程序运行的入口,顺序执行序列和程序的出口,但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
线程和协程的区别?
- 1、一个线程可以多个协程,一个进程也可以单独拥有多个协程
- 2、线程进程都是同步机制,而协程则是异步
- 3、协称能够保留上一次调用时的状态,每次过程重入的时,就相当于进入上一次调用的状态
什么是多进程?
同一个时间里,同一个计算机系统中如果允许两个或两个以上的进程处于运行状态,这就是多进程 多开一个进程,多分配一份资源,进程间通讯不方便
什么是多线程?
线程就是把一个进程分为很多片,每一片都可以是一个独立的流程,与多进程的区别是只会使用一个进程的资源,线程间可以通讯
多个概念之间的区别?
- 单进程单线程:一个人在一个桌上吃菜
- 单进程多线程:多个人在一个桌子上吃菜
- 多进程单线程:多个人每个人在自己桌子上吃菜
同步阻塞模型
多进程:最早的服务器端程序都是通过多进程,多线程来解决并发 IO 的问题一个请求创建一个进程,然后子进程进入循环同步堵塞地与客户端连接进行交互,收发处理数据。
步骤
- 创建一个 socket
- 进入 while 循环,阻塞在进程 accept 操作上,等待客户端连接进入主进程在多进程模型下通过 fork 创建子进程。
多线程模式下可以创建子线程
子线程 / 线程创建成功后进入 while 循环,阻塞在 recv 调用上,等待客户端向服务器发送数据
收到数据以后服务器程序进行处理然后使用 send 向客户端发送响应
当客户端连接关闭时,子进程 / 线程退出并销毁所有资源。主进程 / 线程会回收掉此子进程 / 线程。
这中模型严重的依赖进程的数量解决并发问题。
启动大量的进程会带来额外的进程调度消耗
异步非阻塞模型
现在各种高并发异步 IO 的服务器程序都是基于 epoll 实现的
IO 复用异步非阻塞程序使用经典的 Reactor 模型,Reactor 顾名思义就是反应堆的意思,它本身不处理任何数据收发。只是可以监视一个 socket 句柄的事件变化。
Reactor 模型:
1234 | - add:添加一个socket到reactor- set:修改socket对应的事件,如可读可写- del:从reactor中移除- callback:事件发生后回掉指定的函数 |
---|
nginx:多线程 Reactor
swoole:多线程 Reactor 多进程 worker
php 并发编程实战
- 1.php 的 swoole 扩展、并行、高性能网络通信引擎,使用纯 c 语言编写提供了 php 语言的异步多线程服务器,异步 tcp/udp 网络客户端,异步 mysql,异步 redis,数据库连接池,AsyncTask,消息队列,毫秒定时器,异步文件读写,异步 dns 查询。
- 2. 除了异步 IO 的支持之外,swoole 为 php 多进程的模式设计了多个并发数据结构和 IPC 通信机制,可以大大简化多线程并发编程的工作
- 3.swoole2.0 支持了类似 Go 语言的协程,可以使用完全同步的代码实现异步程序
- 4. 消息队列
- 5. 应用解耦
- 场景说明:用户下单后,订单系统需要通知库存系统。
- 假如库存系统无法访问,则订单减库存将失败,从而导致订单失败
- 订单系统跟库存系统解耦
- 引用队列
- 用户下单后,订单系统完成持久化处理,将消息写入消息队列,返回用户订单下单成功
- 订阅下单的消息,采用拉 / 推的方式,获取下单信息,库存系统根据下单信息,进行库存操作
- 6. 流量削峰 应用场景:秒杀活动,流量瞬间激增,服务器压力大 用户发起请求后,服务器接收后,先写入消息队列。假如消息队列长度超多最大值,则直接报错或提示用户 控制请求量,缓解高流量
- 7. 日志处理 应用场景:解决大量日志的传输 日志采集程序将程序写入消息队列,然后通过日志处理程序的订阅消费日志。
- 8. 消息通讯 聊天室
- 9. 常见消息队列产品 kafka,ActiveMQ,ZeroMQ,RabbitMQ,Redis 等 php 的异步 消息队列
- 10. 接口的并发请求 curl_multi_init
mysql 缓存层的优化
1. 什么是数据库缓存
mysql 等一些常见的关系型数据库的数据都存储在磁盘当中,在高并发场景下,业务应用对 mysql 产生的增删,改,查的操作造成巨大的 I/O 开销和查询压力,这无疑对数据库和服务器都是一种巨大的压力,为了解决此类问题,缓存数据的概念应运而生。
- 极大的解决数据库服务器的压力
- 提高应用数据的响应速度
常见的缓存形式:内存缓存和文件缓存
2. 为什么要使用数据库缓存
- 缓存数据是为了让客户端很少甚至不访问数据库服务器进行数据的查询,高并发下,能最大程序地降低对数据库服务器的访问压力。
- 用户请求 -》数据查询 -》连接数据库服务器并查询数据 -》将数据缓存起来(html,内存,json,序列化数据)-》显示给客户端
- 缓存方式的选择
- 缓存场景的选择
- 缓存数据的实时性
- 缓存数据的稳定性
3. 使用 mysql 查询缓存
- 启用 mysql 查询缓存
- 极大的降低 cpu 使用率
- query_cache_type 查询缓存类型,有 0,1,2 三个取值。0 则不适用查询缓存。1 表示始终使用查询缓存,2 表示按需使用查询缓存。
1 | query_cahce_type=1 select SQL_NO_CACHE * from my_table where condition; query_cache_type=2 select SQL_CACHE * from my_table where condition; 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;// 关闭所有打开的表,同时该操作将会清空查询缓存中的内容
4. 使用 Memcache 缓存
对于大型站点,如果没有中间缓存层,当流量打入数据库层时,即便有之前的几层为我们挡住一部分流量,但是在大并发的情况下,还是会有大量请求涌入数据库层,这样对于数据库服务器的压力冲击很大,响应速度也会下降,因此添加中间缓存层很有必要。
memcache 是一套分布式的高速缓存系统,由 liveJournal 的 BrandFitzpatrick 开发,但目前被许多网站使用以提升网站的访问速度,尤其对于一些大型的、需要频繁访问数据库的网站访问速度提升效果十分显著。 memcache 是一个高性能的分布式的内存对象缓存系统,通过在内存里维护一个统一的巨大的 hash 表,它能够用来存储各种格式的数据,包括图像,视频、文件以及数据库检索的结果等。简单的说就是将数据调用到内存,然后从内存中读取,从而大大提高读取速度。
工作流程:先检查客户端的请求数据是否在 memcache 中,如有,直接把请求数据返回,不再对数据库进行任何操作;如果请求的数据不在 memcache 中,就去查数据库,把从数据库中获取的数据返回给客户端,同时把数据缓存一份到 memcached 中。
通用缓存机制:用查询的方法名 参数作为查询时的 key,value 对中的 key 值
5. 使用 Redis 缓存
与 memcache 的区别:
- 性能相差不大
- redis 在 2.0 版本后增加了自己的 VM 特性,突破物理内存的限制,memcache 可以修改最大可用内存,采用 LRU 算法
- redis 依赖客户端来实现分布式读写
- memcache 本身没有数据冗余机制
- redis 支持(快照,aof)依赖快照进行持久化 aof 增强了可靠性的同时,对性能有所影响
- redis 用户数据量较小的高性能操作和运算上
- memcache 用于在动态系统中减少数据库负载,提升性能;适合做缓存提高性能。
- 可用于存储其他数据:session,session_set_save_handler
mysql 数据层的优化
- 数据表数据类型优化:int,smallint.,bigint,enum,ip 存储使用 int 类型 ip2long 转化存入
- 索引不是越多越好,在合适的字段上创建合适的索引
- 符合索引的前缀原则
- like 查询 % 的问题
- 全表扫描优化
- or 条件索引使用情况
- 字符串类型索引失效的问题
- 优化查询数据过程中的数据访问,使用 limit,尽量不要使用 *,变复杂为简单,切分查询,分解关联查询 *
- 优化特定类型查询语句,优化 count (),优化关联查询语句,优化子查询,优化 group by 和 distinct,优化 limit 和 union
- 存储引擎的优化:尽量使用 innodb
- 数据库表结构的优化:分区操作(对用户透明)partion,分库分表 (水平拆分,垂直拆分做副表)
- 数据库服务器架构的优化:主从复制,读写分离,双主热备,负载均衡 (lvs 实现负载均衡,MyCat 数据库中间件实现负载均衡)
源码附件已经打包好上传到百度云了,大家自行下载即可~
代码语言:javascript复制链接: https://pan.baidu.com/s/14G-bpVthImHD4eosZUNSFA?pwd=yu27
提取码: yu27
百度云链接不稳定,随时可能会失效,大家抓紧保存哈。
如果百度云链接失效了的话,请留言告诉我,我看到后会及时更新~
开源地址
码云地址: http://github.crmeb.net/u/defu
Github 地址: http://github.crmeb.net/u/defu