[toc]
一、什么是高并发
高并发(High Concurrency)是互联网分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计保证系统能够同时并行处理很多请求。
高并发相关常用的一些指标有响应时间(Response Time),吞吐量(Throughput),每秒查询率QPS(Query Per Second),并发用户数等。
- 响应时间:系统对请求做出响应的时间。例如系统处理一个HTTP请求需要200ms,这个200ms就是系统的响应时间。
- 吞吐量:单位时间内处理的请求数量。
- QPS:每秒响应请求数。在互联网领域,这个指标和吞吐量区分的没有这么明显。
- 并发用户数:同时承载正常使用系统功能的用户数量。例如一个即时通讯系统,同时在线量一定程度上代表了系统的并发用户数。
二、如何提升系统的并发能力
加机器的方式就不说了,花钱就完事了
2.0 常见的互联网分层架构
常见互联网分布式架构如上,分为:
(1)客户端层:典型调用方是浏览器browser或者手机应用APP
(2)反向代理层:系统入口,反向代理
(3)站点应用层:实现核心应用逻辑,返回html或者json
(4)服务层:如果实现了服务化,就有这一层
(5)数据-缓存层:缓存加速访问存储
(6)数据-数据库层:数据库固化数据存储
2.1 客户端提升性能
- 资源静态化 - 使用服务端渲染
- 采用cdn , 加快动态资源加载
一些小点:
- 减少http请求
- 使用浏览器的缓存
- 减少单个请求的数据传输
2.2 代理层的水平扩展
反向代理层的水平扩展,是通过“DNS轮询”实现的:dns-server对于一个域名配置了多个解析ip,每次DNS解析请求来访问dns-server,会轮询返回这些ip。
当nginx成为瓶颈的时候,只要增加服务器数量,新增nginx服务的部署,增加一个外网ip,就能扩展反向代理层的性能,做到理论上的无限高并发。
(有多个NG的情况下)
优化ng的一些小细节,比如:
- 启用压缩
- 使用长链接
- 增加worker数
NG是七层模型中的第七层-应用层 , 所以又称它为七层负载, 因此性能会有一定的损耗
LVS(Linux Virtual Server: Linux虚拟服务器) 是七层模型中的第四层-网络层 , 所以又称它为四层负载, 因此性能会更高
LVS 是在网络栈的四层做请求包的转发,请求包转发之后,由客户端和后端服务直接建立连接,后续的响应包不会再经过 LVS 服务器,所以性能更高, LVS 缺陷是工作在四层,而请求的 URL 是七层的概念,不能针对 URL 做更细致地请求分发,而且 LVS 也没有提供探测后端服务是否存活的机制
如果你的 QPS 在十万以内,那么可以考虑不引入LVS 而直接使用 Nginx 作为唯一的负载均衡服务器
来源: 《阿里亿级高并发系统设计》
主流软件负载均衡器对比(LVS、Nginx、HAproxy) - 知乎 (zhihu.com)
LVS负载均衡(LVS简介、三种工作模式、十种调度算法)_chenhuyang的博客-CSDN博客_lvs负载均衡
2.3 站点层的水平扩展
站点层的水平扩展,是通过“nginx”实现的。通过修改nginx.conf,可以设置多个web后端。
当web后端成为瓶颈的时候,只要增加服务器数量,新增web服务的部署,在nginx配置中配置上新的web后端,就能扩展站点层的性能,做到理论上的无限高并发。
(单个NG或者分发到具体某个NG时)
2.4 服务层
服务层的水平扩展,是通过“服务连接池”实现的。
站点层通过RPC-client调用下游的服务层RPC-server时,RPC-client中的连接池会建立与下游服务多个连接,当服务成为瓶颈的时候,只要增加服务器数量,新增服务部署,在RPC-client处建立新的下游服务连接,就能扩展服务层性能,做到理论上的无限高并发。用上Eruka之类的服务注册发现功能,使用多节点容灾
除了水平扩展还有缓存和异步
缓存:
下个标题会讲解
异步:
- 引入消息队列从业务级别 解耦 耗时或并发高的功能
- 在代码中使用多线程到达异步能力
还有很多代码细节,比如
- 提升gateway的性能, 改用netty容器启动 , 并设定工作线程和 select(选择)线程数
- 增加tomcat连接数, 超时时间等
- fegin调用采用okhttp的方式,并使用长链接
- 优化jvm
- 代码中使用异步,线程池等, 代码质量良好
- 数据库的链接池
- 单sql执行, 不阻塞数据库, 提高据库的qps
- 避免数据库的长事务
2.5 数据层的水平扩展
在数据量很大的情况下,数据层(缓存,数据库)涉及数据的水平扩展,将原本存储在一台服务器上的数据(缓存,数据库)水平拆分到不同服务器上去,以达到扩充系统性能的目的。
2.5.1 缓存
使用redis之类的缓存数据库,减少与数据库的交互
一些优化细节,比如:
- 尽量避免大key
- 减少redis的访问次数, 使用mget和管道
- 使用netty链接池
2.5.2 数据库
使用读写分离 , 分库分表等操作提高数据库的效率
引入es, 将复杂查询或者全文类查询通过es来实现
数据库本身的优化,比如:
- 数据库自身的连接池
- 超时时间
- sql要命中索引
https://blog.csdn.net/weixin_42476601/article/details/82220027