当前位置: 首页 > 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当做权重,计算每个桶的权重,权重大的就移动其他桶的库存给这个桶。

相关文章:

  • DIFY教程第七弹:Echarts可视化助手生成图表
  • 【Axure视频教程】中继器表格间批量控制和传值
  • 榕壹云搭子系统技术解析:基于Spring Boot+MySQL+UniApp的同城社交平台开发实践
  • NumPy 2.x 完全指南【九】常量
  • git经验
  • 基于Qt的app开发第八天
  • 聊一聊Electron中Chromium多进程架构
  • 如何优化 Linux 服务器的磁盘 I/O 性能
  • 自动化测试基础知识详解
  • 蓝桥杯12届国B 纯质数
  • (七)深度学习---神经网络原理与实现
  • vue 中绑定样式 【style样式绑定】
  • 3d关键点 可视化
  • 阳光学院【2020下】计算机网络原理-A卷-试卷-期末考试试卷
  • 北斗如何赋能雨水情监测?
  • 南方科技大学Science! 自由基不对称催化新突破 | 乐研试剂
  • 性能优化--无分支编程的实际应用场景
  • 佰力博科技准静态d33测试的注意事项
  • SAP汽配解决方案:无锡哲讯科技助力企业数字化转型
  • amd架构主机构建arm架构kkfileview
  • 第十届影像上海博览会落幕后,留给中国摄影收藏的三个问题
  • “11+2”复式票,宝山购彩者领走大乐透1170万头奖
  • 吉林:消纳绿电,“氢”装上阵
  • 人民网评:守护健康证的“健康”,才有舌尖上的安全
  • 被流量绑架人生,《人生开门红》能戳破网络时代的幻象吗
  • 泽连斯基表示将在土耳其“等候”普京