浅谈高并发解决方案

您所在的位置:网站首页 阿里高并发解决方案 浅谈高并发解决方案

浅谈高并发解决方案

2024-07-08 05:39| 来源: 网络整理| 查看: 265

浅谈常见高并发解决方案

文章目录 浅谈常见高并发解决方案高并发的处理指标 解决方案1 硬件1.1 概述1.2 单体应用垂直扩容方案 2 缓存2.1 概述2.2 http 缓存2.2.1 浏览器缓存2.2.2 Nginx2.2.3 CDN 缓存阿里云CDN加速原理 2.3 应用缓存2.3.1 内存缓存2.3.2 磁盘缓存 2.4 多级缓存2.5 缓存的使用场景 3 集群4 拆分4.1 应用拆分4.2 数据库拆分 5 静态化6 动静分离7 队列8 池化8.1 对象池8.2 数据库池8.3 Redis 连接池8.4 HttpCLient 连接池8.5 线程池 9 性能调优9.1 JVM优化设置 JVM 参数官方参考 9.2 Tomcat优化**参考:** 9.3 Java 程序优化9.4 数据库优化9.4.1 数据库服务器优化9.4.2 数据库架构优化9.4.3 数据库索引优化9.4.4 SQL 优化9.4.5 采用数据搜索引擎 9.5 Nginx 优化9.5.1 调整配置文件参数 9.6 Linux 优化9.7 网络优化9.8 前端优化9.8.1 Js优化9.8.2 CSS优化9.8.3 html 页面优化 10 压力测试11 总结

什么是高并发?

高并发(High Concurrency)通常是指通过设计保证系统能够同时并行处理很多请求。 通俗来讲,高并发是指在同一个时间点,有很多用户同时的访问同一 API 接口或者 Url 地址。它经常会发生在有大活跃用户量,用户高聚集的业务场景中。

高并发是互联网应用的一大特点,也是互联网应用不可避免的一个问题;比如 淘宝双11 购物狂欢节,京东 618 购物促销节,12306 春节火车票,促销,秒杀等。

解决高并发问题是一个系统工程,需要站在全局高度统筹谋划,从多个角度进行架构设计。

解决高并发问题,不是一个或两个方案就能解决的,需要从各个维度综合施策才能完成 。

高并发的处理指标

高并发相关常用的一些指标有:

响应时间(Response Time)

响应时间:系统对请求做出响应的时间。例如系统处理一个HTTP请求需要200ms,这个200ms就是系统的响应时间

吞吐量(Throughput)

吞吐量:单位时间内处理的请求数量。

每秒查询率QPS(Query Per Second)

QPS:每秒响应请求数。在互联网领域,这个指标和吞吐量区分的没有这么明显。

并发用户数

并发用户数:同时承载正常使用系统功能的用户数量。例如一个即时通讯系统,同时在线量一定程度上代表了系统的并发用户数。

在实践中,我们总结和提炼出来了很多应对高并发的方案或者说手段,接下来会给大家介绍不同维度的解决方案。

解决方案 1 硬件 1.1 概述

系统访问用户增多,流量增大,导致服务器压力增大,出现性能瓶颈,我们可以采用一个简单粗暴的策略:提升服务器硬件配置,提升服务器硬件配置的策略,也称为:单体应用 垂直扩容

比如:产品或者网站初期,通常功能较少,用户量也不多,一般就采用一个项目工程来 完成,这就是单体应用,也叫集中式应用。

按照经典的 MVC 三层架构设计,部署单台服务器,使用单台数据库,应用系统和数据 库部署在同一台服务器上,随着应用系统功能的增加,访问用户的增多,单台服务器已无法承受那么多的访问流量。

此时,我们可以直接采用简单粗暴的办法:提升硬件配置来解决

1.2 单体应用垂直扩容方案

CPU 从 32 位提升为 64 位

内存从 64GB 提升为 256GB(比如缓存服务器)

磁盘从 HDD(Hard Disk Drive)提升为 SSD(固态硬盘(Solid State Drives)),有大量读写的 应用

磁盘扩容,1TB 扩展到 2TB,比如文件系统

千兆网卡提升为万兆网卡

但是不管怎么提升硬件性能,硬件性能的提升不可能永无止尽,所以最终还是要靠分布式解决

2 缓存 2.1 概述

缓存可以说是解决大流量高并发,优化系统性能非常重要的一个策略

它是解决性能问题的利器,就像一把瑞士军刀,锋利强大

缓存在高并发系统中无处不在(到处都是)

2.2 http 缓存 2.2.1 浏览器缓存

​ 浏览器缓存是指当我们使用浏览器访问一些网站页面或者 HTTP 服务时,根据服务器端 返回的缓存设置响应头将响应内容缓存到浏览器,下次可以直接使用缓存内容或者仅需要去 服务器端验证内容是否过期即可,这样可以减少浏览器和服务器之间来回传输的数据量,节省带宽,提升性能;

​ 比如新浪:http://www.sina.com.cn/。第一次访问返回 200,第二次刷新访问,返回响应码为 304,表示页面内容没有修改过, 浏览器缓存的内容还是最新的,不需要从服务器获取,直接读取浏览器缓存即可

​ 我们也可以在 Java 代码中通过设置响应头,告诉前端浏览器进行缓存:

DateFormat format = new SimpleDateFormat("EEE,MMM yyyy HH: mm: ss 'GMT'", Locale. US); //当前时间 long now = System.currentTimeMillis() * 1000 * 1000; response.addHeader( "Date", format.format(new Date())); //过期时间 http 1. 0 支持 response.addHeader("Expires", format.format (new Date(now+ 20 * 1000))); 2.2.2 Nginx

Nginx提供了 expires 指令来实现缓存控制,比如:

location /static { root /opt/static/; expires 1d;//全天 }

当用户访问时,Nginx 拦截到请求后先从 Nginx 本地缓存查询数据,如果有并且没有过期,则直接返回缓存内容

2.2.3 CDN 缓存

CDN 的全称是 Content Delivery Network,即内容分发网络。CDN 是构建在网络之上的内容分发网络,依靠部署在各地的边缘服务器,通过中心平台的负载均衡、内容分发、调度等功能模块,使用户就近获取所需内容,降低网络拥塞,提高用户访问响应速度和命中率。CDN的关键技术主要有内容存储和分发技术。

CDN 它本身也是一个缓存,它把后端应用的数据缓存起来,用户要访问的时候,直接从CDN 上获取,不需要走后端的 Nginx,以及具体应用服务器 Tomcat,它的作用主要是加速数据的传输,也提高稳定性,如果从 CDN 上没有获取到数据,再走后端的Nginx缓存,Nginx 上也没有,则走后端的应用服务器,CDN主要缓存静态资源

阿里云CDN加速原理

通过以下案例,您可以了解CDN的工作原理。

假设您的加速域名为 www.a.com,接入CDN开始加速服务后,当终端用户在北京发起HTTP请求时,处理流程如下图所示。

当终端用户向www.a.com下的指定资源发起请求时,首先向LDNS(本地DNS)发起域名解析请求。LDNS检查缓存中是否有www.a.com的IP地址记录。如果有,则直接返回给终端用户;如果没有,则向授权DNS查询。当授权DNS解析www.a.com时,返回域名CNAME www.a.tbcdn.com对应IP地址。域名解析请求发送至阿里云DNS调度系统,并为请求分配最佳节点IP地址。LDNS获取DNS返回的解析IP地址。用户获取解析IP地址。用户向获取的IP地址发起对该资源的访问请求。 如果该IP地址对应的节点已缓存该资源,则会将数据直接返回给用户,例如图中步骤7和8,此时请求结束。如果该IP地址对应的节点未缓存该资源,则节点向源站发起对该资源的请求。获取资源后结合用户自定义配置的缓存策略,将资源缓存到CDN节点并返回给用户,例如图中的北京节点,此时请求结束。 2.3 应用缓存 2.3.1 内存缓存

在内存中缓存数据,效率高,速度快,应用重启缓存丢失

2.3.2 磁盘缓存

在磁盘缓存数据,读取效率跟内存比较,磁盘缓存稍低,但应用重启缓存不会丢失

代码组件:

GuavaEhcache

服务器组件:

RedisMemCache 2.4 多级缓存

在整个应用系统的不同层级进行数据的缓存,多层次缓存,来提升访问效率; 比如:浏览器 -> CDN -> Nginx -> Redis -> DB (磁盘、文件系统)

2.5 缓存的使用场景

经常需要读取的数据

频繁访问的数据

热点数据缓存

IO 瓶颈数据

计算昂贵的数据

无需实时更新的数据

缓存的目的是减少对后端服务的访问,降低后端服务的压力

3 集群

有一个单体应用,当访问流量很大无法支撑,那么可以集群部署,也叫单体应用水平扩容,原来通过部署一台服务器提供服务,现在就多部署几台,那么服务的能力就会提升。

部署了多台服务器,但是用户访问入口只能是一个,比如 www.evanshare.com,所以就需要 负载均衡,负载均衡是应用集群扩容后的必须步骤,集群部署后,用户的会话 session 状态 要保持的话,就需要实现 session 共享。

4 拆分 4.1 应用拆分

​ 应用的拆分:分布式 (微服务)

​ 单体应用,随着业务的发展,应用功能的增加,单体应用就逐步变得非常庞大,很多人 维护这么一个系统,开发、测试、上线都会造成很大问题,比如代码冲突,代码重复,逻辑错综混乱,代码逻辑复杂度增加,响应新需求的速度降低,隐藏的风险增大,所以需要按照 业务维度进行应用拆分,采用分布式开发;

​ 应用拆分之后,就将原来在同一进程里的调用变成了远程方法调用,此时就需要使用到 一些远程调用技 httpClient、hessian、dubbo、webservice 等;

​ 随着业务复杂度增加,我们需要采用一些开源方案进行开发,提升开发和维护效率,比 如 Dubbo、SpringCloud;

​ 通过应用拆分之后,扩容就变得容易,如果此时系统处理能力跟不上,只需要增加服务 器即可(把拆分后的每一个服务再多做几个集群)

4.2 数据库拆分

​ 数据库拆分分为:垂直拆分和水平拆分 (分库分表)

​ 按照业务维度把相同类型的表放在一个数据库,另一些表放在另一个数据库,这种方式 的拆分叫垂直拆分,也就是在 不同库建不同表,把表分散到各个数据库

​ 比如产品、订单、用户三类数据以前在一个数据库中,现在可以用三个数据库,分别为 产品数据库、订单数据库、用户数据库,这样可以将不同的数据库部署在不同的服务器上,提升单机容量和性能问题,也解决多 个表之间的 IO 竞争问题

​ 根据数据行的特点和规则,将表中的某些行切分到一个数据库,而另外的某些行又切分 到另一个数据库,这种方式的拆分叫水平拆分

​ 单库单表在数据量和流量增大的过程中,大表往往会成为性能瓶颈,所以数据库要进行水平拆分

​ 数据库拆分,采用一些开源方案,降低开发难度,比如:MyCat、Sharding-Sphere

5 静态化

​ 对于一些访问量大,更新频率较低的数据,可直接定时生成静态 html 页面,供前端访问,而不是访问 jsp

​ 常用静态化的技术:freemaker、velocity 定时任务,每隔 2 分钟生成一次首页的静态化页面

​ 页面静态化首先可以大大提升访问速度,不需要去访问数据库或者缓存来获取数据,浏览器直接加载 html 页即可

​ 页面静态化可以提升网站稳定性,如果程序或数据库出了问题,静态页面依然可以正常 访问

6 动静分离

​ 采用比如 Nginx 实现动静分离,Nginx 负责代理静态资源,Tomcat 负责处理动态资源 Nginx 的效率极高,利用它处理静态资源,可以为后端服务器分担压力 动静分离架构示意图

redis 和 nginx 并发量 5w 左右,tomcat 和 mysql 700 左右,当然可以通过一些方式调整

7 队列

采用队列是解决高并发大流量的利器

队列的作用就是:异步处理/流量削峰/系统解耦

异步处理是使用队列的一个主要原因,比如注册成功了,发优惠券/送积分/送红包 /发短信/发邮件等操作都可以异步处理

使用队列流量削峰,比如并发下单、秒杀等,可以考虑使用队列将请求暂时入队, 通过队列的方式将流量削平,变成平缓请求进行处理,避免应用系统因瞬间的巨大 压力而压垮

使用队列实现系统解耦,比如支付成功了,发消息通知物流系统,发票系统,库存 系统等,而无需直接调用这些系统

队列应用场景

不是所有的处理都必须要实时处理不是所有的请求都必须要实时告诉用户结果不是所有的请求都必须 100% 一次性处理成功不知道哪个系统需要我的协助来实现它的业务处理,保证最终一致性,不需要强一 致性

常见的消息队列产品:ActiveMQ/RabbitMQ/RocketMQ/kafka

ActiveMQ 是 jms 规范下的一个老牌的成熟的消息中间件/消息服务器RabbitMQ/RocketMQ 数据可靠性极好,性能也非常优秀,在一些金融领域、电商 领域使用很广泛;RocketMQ 是阿里巴巴的;Kafka 主要运用在大数据领域,用于对数据的分析,日志的分析等处理,它有可能产生消息的丢失问题,它追求性能,性能极好,不追求数据的可靠性 8 池化

在实际开发中,我们经常会采用一些池化技术,减少资源消耗,提升系统性能

8.1 对象池

通过复用对象,减少对象创建和垃圾收集器回收对象的资源开销

可以采用 commons-pool2 实现

实际项目采用对象池并不常见,主要在开发框架或组件的时候会采用

8.2 数据库池

Druid

DBCP

C3P0

BoneCP

8.3 Redis 连接池

JedisPool(内部基于 commons-pool2 实现)

8.4 HttpCLient 连接池

核心实现类:PoolingHttpClientConnectionManager

参考:

public class TestMain { public static void main(String[] args) throws NSQException, TimeoutException { ExecutorService pool = Executors.newCachedThreadPool(); // http请求 PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(); cm.setDefaultMaxPerRoute(800);// 设置每个路由基础的连接 cm.setMaxTotal(1000);//设置最大连接数//cm.setMaxPerRoute(new HttpRoute(httpHost), maxRoute);// 设置目标主机的最大连接数 CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(cm).build(); for (int i = 0; i =’2005-11-30′ and createdate


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3