当前位置: 首页 > news >正文

高并发系统设计需要考虑哪些问题

高并发系统设计

针对高并发的系统,例如需要支持100万qps的下单系统,我们需要做什么样的设计?

我们需要有这样的思路,从一下几个角度考虑问题:

  1. 负载均衡:将用户请求分配到多个实例,避免出现单点瓶颈,可以使用Nginx实现。
  2. 网关层:解析HTTP/HTTPS协议,处理业务逻辑:鉴权、限流、路由、将HTTP转为gRPC或Dubbo协议等,可以使用Spring Cloud Gateway实现。
  3. 应用层:采用MQ异步处理、Redis缓存、本地缓存、线程池等优化。
  4. 存储层:分MySQL存储和Redis缓存,需要考虑Mysql的系统瓶颈,做对应的设计,例如分库分表、读写分离等。

一、负载均衡和网关层

这一块平时可能接触不太到,或者公司有框架组直接实现好,我们主要需要关注这些点:

  1. 负载均衡的策略:轮询、IP的Hash、随机、权重等等,需要选择合适的策略,例如选择动态权重调整,CPU高的机器就分配少的流量
  2. 限流:针对高并发的场景,一定要设置限流,来保护系统,例如服务的QPS最多是10w,超过10w拒绝服务。这里需要注意限流算法的选择,例如计数器、令牌桶、漏桶等
  3. 熔断:例如1分钟调用下游接口90%都是超时,那么触发熔断,直接返回默认值或者请求失败。

二、应用层

应用层的话,我们需要考虑这些场景:

  1. 流量削峰:可以通过MQ异步处理的方式,来进行流量削峰,防止短时间内有大量的QPS
  2. 缓存:可以增加多级缓存,例如Redis缓存、本地缓存等,来提高响应速度,降低下游的QPS压力
  3. 线程池:假如说接口里需要调用几十个下游接口,那我们需要考虑用线程池来并发的执行任务,提高响应速度。
假如下单服务需要调用70个下游接口,我需要怎么优化
  1. 区分核心和非核心接口:对于核心接口,例如库存扣减、支付预占,我们需要同步调用,保持强一致性。但是对于非核心接口,例如优惠券校验、风控等,我们可以做异步处理。
  2. 聚合下游接口:下游接口有70个,太多了,我们可以对接口进行聚合,例如建立BFF层,将多个接口合并为一个,减少调用;或者推动下游合并接口。
  3. 线程池优化:利用线程池去批量调用接口,需要合理的设置线程池参数,例如拒绝策略需要设置为不抛出异常,由调用线程执行。
  4. 静态数据放入缓存:对于查询类接口,如果不经常变化,可以将其放入缓存中,减少接口的调用。

三、存储层

存储层我们考虑两个:MySQL和Redis

1.MySQL

首先我们需要明白MySQL单机的性能,MySQL单机的qps大概是5000左右,具体要分读写

  1. 读(有索引时):5,000 ~ 50,000
  2. 写:1,000 ~ 10,000

生产的话就需要自己去做压测来找真正的性能瓶颈

那么这么点QPS肯定无法满足100万的QPS需求,因此我们需要有这样的一些优化措施:

  1. 分库分表:进行分库分表,例如分300个库,每个库QPS瓶颈是5000,就可以支持100万的QPS需求。
  2. 读写分离:写Master机器,读Slave机器,通过读写分离,降低压力,不过数据会有延迟。
假如我数据库只能分100个片怎么办?

100个分片无法满足qps的要求,我们可以:

  1. 做异步处理:对下单请求进行MQ异步处理,在3s内返回结果即可。
  2. 合并数据库操作:我们可以将多个写操作合并在一起执行,例如接收落库的MQ,批量拉取MQ,进行批量的数据库操作。
  3. 缓存/读写分离:通过增加缓存、读写分离,降低读的压力,提高写的QPS。
在下单接口中做异步处理,那用户在页面上如何及时感知呢?
  1. 前端建立webSocket流,感知服务端异步推送的结果。
  2. 前端轮询:1s轮询一次结果。
  3. SSE事件订阅:前端通过 EventSource 发起一个 HTTP 长连接请求,订阅后端推送过来的变化。
2.Redis

首先我们需要知道Redis单机的qps,大概是50,000 左右,也看具体场景

  1. GET/SET 操作,50,000 ~ 200,000 纯内存操作,单线程无锁
  2. 持久化开启时:10,000 ~ 50,000,RDB/AOF 持久化会占用磁盘 I/O

生产的话就需要自己去做压测

那么这么点QPS无法满足100万的QPS需求,因此我们需要有一些优化措施。

针对于读的场景,我们可以:

  1. 增加本地缓存,降低Redis缓存的压力。
  2. 读写分离:通过读Redis的slave机器,来降低Master的压力。

针对于写的场景,我们可以:

  1. 分桶:将一个key分成多个,例如针对库存字段,我们可以把100个库存分成5个桶,每个桶有20个库存,就可以满足QPS的压力了。

那么这里也会有一些问题。

分桶后,假如有多个桶都只剩下了1库存,但是用户的请求是扣2个,怎么处理
  1. 动态平衡桶库存,系统自动去调整每个桶里的剩余库存,例如用qps当做权重,计算每个桶的权重,权重大的就移动其他桶的库存给这个桶;或者是当库存不足时,触发平衡操作,将小库存聚合为大库存。
  2. 如果需要保持强一致性,可以使用原子化跨桶扣减:通过Lua语句合并扣减操作,从两个桶里扣库存
  3. 如果是追求QPS的话,可以采用本地优先扣减 + 异步调平的方式,即先扣本地,立即返回部分成功,并且异步的去扣其他桶。这里用户会感知到。
Redis热key分桶,数据倾斜问题怎么解决
  1. 选用随机的key作为路由的key,例如用订单号而不是用户id。
  2. 采用动态权重平衡库存的方式,例如用qps当做权重,计算每个桶的权重,权重大的就移动其他桶的库存给这个桶。
http://www.xdnf.cn/news/422515.html

相关文章:

  • 极限学习机进行电厂相关数据预测
  • 目标检测任务常用脚本1——将YOLO格式的数据集转换成VOC格式的数据集
  • 滑动窗口——水果成篮
  • 正则表达式常用验证(一)
  • vim,gcc/g++,makefile,cmake
  • 如何用URDF文件构建机械手模型并与MoveIt集成
  • 获取accesstoken时,提示证书解析有问题,导致无法正常获取token
  • do while
  • 从代码学习深度学习 - 全卷积神经网络 PyTorch版
  • 【网络编程】七、详解HTTP 搭建HTTP服务器
  • MySQL 5.7在CentOS 7.9系统下的安装(上)——以rpm包的形式下载mysql
  • 音频特征工具Librosa包的使用
  • Windows Java gRPC 示例
  • windowsC++操作ADB
  • archlinux中挂载macOS的硬盘
  • keepalived+lvs
  • S32DS删除历史安装的license code(Software Activation Code)
  • 什么是序列化与反序列化
  • CodeBuddy终极测评:中国版Cursor的开发革命(含安装指南+HTML游戏实战)
  • 计算机网络网络层(下)
  • 奇妙小博客
  • 虚拟仿真技术在康养休闲旅游服务实训室中的核心应用
  • tomcat搭建内网论坛
  • 利用比较预言机处理模糊的偏好数据
  • 问题及解决02-处理后的图像在坐标轴外显示
  • Spring Boot 项目中什么时候会抛出 FeignException?
  • Pattern and Match
  • 【Qwen3 + MCP】快速打造一个免费的Qwen AI图像生成助手
  • 【前缀和】和为 K 的子数组(medium)
  • 数据清洗案例