【场景】高并发解决方案

news2025/4/17 16:44:55

文章目录

  • 1. 硬件
  • 2. 缓存
    • 2.1 HTTP缓存
      • 2.1.1 浏览器缓存
      • 2.1.2 Nginx缓存
      • 2.1.3 CDN缓存
    • 2.2 应用缓存
  • 3 集群
  • 4. 拆分
    • 4.1 应用拆分(分布式、微服务)
    • 4.2 数据库拆分
  • 5. 静态化
  • 6. 动静分离
  • 7. 消息队列
  • 8. 池化
    • 8.1 对象池
    • 8.2 数据库连接池
    • 8.3 线程池
  • 9. 数据库优化
    • 9.1 配置优化
    • 9.2 索引优化
    • 9.3 执行计划

1. 硬件

  • CPU从32位提升为64位
  • 内存从64GB提升为256GB(比如缓存服务器);
  • 磁盘扩容,1TB扩展到2TB,比如文件系统
  • 磁盘从 HDD(Hard Disk Drive)提升为 SSD(固态硬盘(Solid State Drives)),有大量读写的应用
  • 千兆网卡提升为万兆网卡

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

2. 缓存

2.1 HTTP缓存

2.1.1 浏览器缓存

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

比如淘宝:http://www.taobao.com/

第一次访问返回200,第二次刷新访问,返回响应码为304,表示页面内容没有修改过,浏览器缓存的内容还是最新的,不需要从服务器获取,直接读取浏览器缓存即可

在这里插入图片描述

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

# web static
spring.web.resources.add-mappings=true
spring.web.resources.chain.cache=true
spring.web.resources.chain.enabled=true
# 静态资源在浏览器缓存3600s
spring.web.resources.cache.period=3600
spring.web.resources.static-locations=classpath:/static/

2.1.2 Nginx缓存

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

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

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

2.1.3 CDN缓存

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

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

2.2 应用缓存

浏览器 -> CDN -> Nginx -> Redis -> DB

需要缓存的数据:经常需要读取的数据、热点数据(销量高的商品、热搜榜单、网红直播间)、IO瓶颈数据(文件、电影)、计算昂贵的数据、无需实时更新的数据(js/css/html/img),缓存的目的是减少对后端服务的访问,降低后端服务的压力

3 集群

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

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

应用服务器集群、redis集群、MySQL集群(主从复制、读写分离)

4. 拆分

4.1 应用拆分(分布式、微服务)

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

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

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

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

4.2 数据库拆分

读写分离、分库分表(水平/垂直)

5. 静态化

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

常用静态化的技术: freemaker、velocity

浏览器只需要请求静态页面,暂时不需要去访问数据库或者缓存来获取数据,浏览器直接加载html页即可,局部使用ajax发起请求更新。先给用户返回静态页面,后续再利用ajax请求数据(比如用户请求电商首页时,先返回纯html,其他的图片、视频资源使用ajax更新,请求地址都写为互联网绝对路径

在这里插入图片描述

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

还可以延迟加载,根据滚动条的位置加载数据

6. 动静分离

采用比如Nginx实现动静分离,Nginx负责代理静态资源,Tomcat 负责处理动态资源

Nginx的效率极高,利用它处理静态资源,可以减轻后端服务器的压力,动静分离架构示意图:

在这里插入图片描述

Redis的并发量在7w,nginx的并发量在4w,tomcat的并发量在700左右,MySQL在600左右

7. 消息队列

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

  • 异步下单:收到用户下单请求,校验后即可给用户返回下单成功,将数据放入消息队列,访问数据库的操作可以后续再做
  • 削峰填谷:请求过多时,将请求数据放到MQ中,业务线程可以以稳定的速度消费,这就防止了高并发请求直接访问业务服务器
  • 定时发送邮件:将数据带上TTL放到MQ中,时间到后转移到死信队列,业务线程从死信队列获取数据,取消订单

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

使用队列实现系统解耦,比如最主要的支付操作成功了,发消息通知物流,发票等操作都不用保证实时,无需同步调用这些接口,可以让这些消息入队,使用线程池慢慢处理

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

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

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

8. 池化

8.1 对象池

通过复用对象,减少对象创建和垃圾收集器回收对象的资源开销,可以采用commons-pool2实现

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

8.2 数据库连接池

Druid、DBCP、C3P0、BoneCP

8.3 线程池

  • Executors.newFixedThreadPool:创建一个固定大小的线程池,可控制并发的线程数,超出的线程会在队列中等待;
  • Executors.newCachedThreadPool:创建一个可缓存的线程池,若线程数超过处理所需,缓存一段时间后会回收,若线程数不够,则新建线程;
  • Executors.newSingleThreadExecutor:创建单个线程数的线程池,它可以保证先进先出的执行顺序;
  • Executors.newScheduledThreadPool:创建一个可以执行延迟任务的线程池;
  • Executors.newSingleThreadScheduledExecutor:创建一个单线程的可以执行延迟任务的线程池;
  • Executors.newWorkStealingPool:创建一个抢占式执行的线程池(任务执行顺序不确定)【JDK 1.8 添加】。
  • ThreadPoolExecutor:最原始的创建线程池的方式,它包含了 7 个参数可供设置,会更加可控。

9. 数据库优化

9.1 配置优化

MySQL Server配置优化: mysqld启动时会加载my.cnf,配置其中的相关配置可以优化server

如果某个二级索引不断被使用,二级索引成为热数据,那么InnoDB会根据在二级索引树上的索引值在构建一个哈希索引来加速搜索(只适用于等值比较)。业务完成后,可以用show engine innodb status查看哈希索引使用频率,若不高可以关闭

  • 根据物理机的条件,合理设置InnoDB log buffer大小(redo log缓存的大小),Innodb_buffer_pool_size(缓存的大小),来减少磁盘I/O次数,因为缓存区大了,在缓冲区工作的时间就长了,redo log的效率就高了
  • 增大并发连接数量和保持连接超时时间
  • MySQL使用select + 线程池的模型,适当增加MySQL线程池中的线程thread_cache_size

9.2 索引优化

  • 选择合适的索引数据结构: 一般使用B+树,若等值查询较多,也可使用自适应哈希索引
  • 选择合适的索引列:选择对查询频率高且区分度高的列作为索引列。区分度越高,索引的效果越好。避免在索引中包含过多重复值或过长的列;
  • 尽量使用聚簇索引:聚簇索引的叶子节点存储了具体的数据,不用在像非聚簇索引一样进行回表查询,所以在查询时,尽量选择聚簇索引。此外对于聚簇索引,数据在索引结构中的位置和物理位置是一致的,访问效率更高
  • 避免过多的索引:索引会占用存储空间,并且在数据更新时需要维护索引,过多的索引会增加维护的开销。只创建必要的索引,避免创建过多的索引;
  • 联合索引符合要符合最左匹配原则、join的连接字段最好用到索引、where过滤字段的区分度是否大、过滤字段避免涉及聚合函数以及类型转换

索引失效的情况

  • 没用到索引导致全表扫描,加了表锁
  • 由于where的过滤字段做了类型转换、聚合函数,没用到索引
  • 索引不合适,导致外部排序
  • select的字段过多,导致回表
  • 联合索引没用到最左侧的字段

表数据量太大,导致查找慢:可以分库分表,或者将一些时间很久远的数据导出到专门的文件服务器中

log buffer和buffer pool太小,刷脏页频率过高

当只需要指定数量数据的时候,可以使用limit提前结束查找,无需扫描全表。limit m,n时最好先用主键id过滤掉前m个数据

9.3 执行计划

参考:【MySQL】分析SQL的几种方式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1215191.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

酷开系统 酷开科技,将家庭娱乐推向新高潮

在当今数字化时代,家庭娱乐已经成为人们日常生活中不可或缺的一部分。如果你厌倦了传统的家庭娱乐方式,想要一种全新的、充满惊喜的娱乐体验,那么,不妨进入到酷开科技的世界,作为智能电视行业领军企业,酷开…

Git常用操作-MD

文章目录 1. 本地创建分支,编写代码,提交本地分支到远程仓库2. 提交本地代码到本地仓库3. 提交本地代码到本地dev分支4. 提交本地dev分支到远程仓库5. 本地dev分支拉取远程master分支,并将master分支内容合并到本地dev6. 同义命令7. 撤销上次…

Codeforces Round 908 (Div 2——AB)

A. Secret Sport 题目 AB二人玩游戏,每一局(plays)游戏会有一个获胜者,首先获胜X局(play)的玩家得一分(赢得一轮sets)。率先获得Y分的玩家获得最终胜利。 给你整场游戏的每局&…

Spring Boot使用EhCache完成一个缓存集群

在上一篇在SpringBoot中使用EhCache缓存,我们完成了在Spring Boot中完成了对EhCaChe的使用,这篇,我们将对EhCache的进一步了解,也就是搭建一个EhCache的缓存集群。 集群 在搭建一个EhCache的时候,我们需要先了解&…

areadetector ADURL模块应用在面探测控制的初步应用

本章中讨论了使用ADURL控制面探测器Lambda的过程&#xff1a; ADURL的使用请见&#xff1a; EPICS -- areaDetector URL驱动程序-CSDN博客 需要启动一个ADURL的IOC程序&#xff0c;并且设置相关的插件中参数的值&#xff1a; # st.cm < envPaths < st_base.cmddbpf 1…

WorkPlus即时通讯app支持多种信创环境组合运行

在信息技术领域&#xff0c;国产信创技术的快速发展为企业带来了更多的选择和机会。在此背景下&#xff0c;WorkPlus作为一款全方位的移动数字化平台&#xff0c;全面支持国产信创操作系统、芯片和数据库&#xff0c;并且全面兼容鸿蒙操作系统。这一优势使得WorkPlus成为了企业…

企业数据备份应该怎么操作?应该知道的四种备份方法

​企业数据备份对于保护最重要的资产至关重要。在面对不断增加的安全威胁时&#xff0c;很多企业都感到无从下手&#xff0c;不知如何保护关键业务数据。通过采用正确的数据备份方法&#xff0c;可以成为确保企业数据安全的最有效手段。因此&#xff0c;不论您是个人还是在职人…

第二证券:今日投资前瞻:小米汽车引关注 全球风光有望持续高速发展

昨日&#xff0c;两市股指盘中轰动上扬&#xff0c;深成指、创业板指一度涨超1%。到收盘&#xff0c;沪指涨0.55%报3072.83点&#xff0c;深成指涨0.72%报10077.96点&#xff0c;创业板指涨0.53%报2015.36点&#xff0c;北证50指数涨2.64%&#xff1b;两市算计成交9900亿元&…

亚马逊云科技云存储服务指南

文章作者&#xff1a;Libai 高效的云存储服务对于现代软件开发中的数据管理至关重要。亚马逊云科技云存储服务提供了强大的工具&#xff0c;可以简化工作流程并增强数据管理能力。 亚马逊云科技开发者社区为开发者们提供全球的开发技术资源。这里有技术文档、开发案例、技术专栏…

Ubuntu 22.04 LTS ffmpeg mp4 gif 添加图片水印

ffmpeg编译安装6.0.1&#xff0c;参考 Ubuntu 20.04 LTS ffmpeg gif mp4 互转 许编译安装ffmpeg &#xff1b;解决gif转mp4转换后无法播放问题-CSDN博客 准备一个logo MP4添加水印 ffmpeg -i 2.mp4 -vf "movielogo.png[watermark];[in][watermark]overlayx10:y10[out]&…

torch_cluster、torch_scatter、torch_sparse三个包的安装

涉及到下面几个包安装的时候经常会出现问题&#xff0c;这里我使用先下载然后再安装的办法&#xff1a; pip install torch_cluster pip install torch_scatter pip install torch_sparse 1、选择你对应的torch版本&#xff1a;https://data.pyg.org/whl/ 2、点进去然后&…

PowerConsume功耗计算器

嵌入式低功耗产品开发&#xff0c;功耗计算器资源-CSDN文库 PowerConsume使用说明 安装说明 需要安装在无空格等特殊字符的路径&#xff0c;不推荐安装在C盘。 功能说明 已知条件 电池容量 各状态的电流和运行时间 自动计算出设备运行时间 启动界面如下 添加状态 在空白处…

【Python基础篇】运算符

博主&#xff1a;&#x1f44d;不许代码码上红 欢迎&#xff1a;&#x1f40b;点赞、收藏、关注、评论。 格言&#xff1a; 大鹏一日同风起&#xff0c;扶摇直上九万里。 文章目录 一 Python中的运算符二 算术运算符1 Python所有算术运算符的说明2 Python算术运算符的所有操作…

12.Oracle的索引

Oracle11g的索引 一、什么是索引二、索引的分类三、索引的语法四、分析索引四、索引的作用及使用场景 一、什么是索引 在Oracle数据库中&#xff0c;索引是一种特殊的数据结构&#xff0c;用于提高查询性能和加速数据检索。索引存储了表中某列的值和对应的行指针&#xff0c;这…

开源微信小程序源码/校园综合服务平台小程序源码+数据库/包括校园跑腿 快递代取 打印服务等功能

源码简介&#xff1a; 校园综合服务小程序源码&#xff0c;它是基于微信小程序开发&#xff0c;包括快递代取 打印服务 校园跑腿 代替服务 上门维修和其他帮助等功能。它是开源微信小程序源码。 校园综合服务小程序开源源码是一款功能强大的小程序&#xff0c;可用于搭建校园…

【uniapp/uview1.x】u-upload 在 v-for 中的使用时, before-upload 如何传参

引入&#xff1a; 是这样一种情况&#xff0c;在接口获取数据之后&#xff0c;是一个数组列表&#xff0c;循环展示后&#xff0c;需要在每条数据中都要有图片上传&#xff0c;互不干扰。 分析&#xff1a; uview 官网中有说明&#xff0c;before-upload 是不加括号的&#xff…

@Version乐观锁配置mybatis-plus使用(version)

1&#xff1a;首先在实体类的属性注解上使用Version import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.Versio…

番外 2 : LoadRunner 的安装以及配置

LoadRunner 的安装以及配置教程 一 . 配置 IE 浏览器二 . 安装 LoadRunner 工具三 . 修改默认浏览器的配置四 . 设置 LoadRunner 能够获取本地资源 Hello , 大家好 , 又给大家带来新的专栏喽 ~ 这个专栏是专门为零基础小白从 0 到 1 了解软件测试基础理论设计的 , 虽然还不足以…

《如何控制 LLM 的输出格式和解析其输出结果?》

内容来源&#xff1a;dotey 《如何控制 LLM 的输出格式和解析其输出结果&#xff1f;》 https://baoyu.io/blog/prompt-engineering/how-to-parse-the-output-from-llm 现在很多人对于如何使用像 ChatGPT 这样的 LLM 已经比较有经验了&#xff0c;可以使用各种不同的 Prompt …

RTLS 颠覆制造业的 方式之——跟踪

进行中工作跟踪 在制品 (WIP) 跟踪主要关注生产中的项目如何从一个步骤移动到另一步骤。因此&#xff0c;运动是此类流程管理的共同点&#xff0c;使得实时位置的洞察力几乎在每个时刻都很有用。 1. 传递时间和运动数据 制造几乎总是涉及许多同时移动的事物。无论是在同一条…