高并发业务下的无损技术方案设计

news/2024/9/13 22:49:37/ 标签: java

0 前言

秒杀,既有需求真实且迫切的用户,也有试图牟利的黄牛。系统挑战,就是相较于以往千倍万倍的用户规模,可能是真人可能是机器人,在同一瞬间对系统发起冲击,需要海量的计算资源才能支撑。

秒杀系统的设计套路往往适用于其他高并发场景,具有较高的借鉴价值。同时,其特殊的挑战和需求,需要架构师在设计中权衡考量,这也有助于培养个人在权衡取舍方面的能力。

1 无损技术方案

好比治水:

  • 分流,让支流分摊压力,隔离风险。软件设计就是系统隔离,分割流量

  • 建水库存储洪水,再缓慢排出,削峰填谷。软件设计就是无损消峰

  • 拓宽河道,清除淤沙提高水流流速。软件设计就是性能优化,如多级缓存,特定场景的高性能库存扣减

一个请求打到服务器的基本链路:

DNS->网关->前端/后端

流量峰值也应该逐层减少:

1.1 系统隔离

秒杀活动因其高峰值特性,一般把它隔离出来成一个独立的秒杀系统(常规服务都是按领域特性做纵切,但这里按品类做横切,带有秒杀活动标的商品将会分流到独立的秒杀系统集群)。

考虑到交易系统体量很大,若为秒杀品类把整个交易系统复制一份,成本过大。所以把隔离区分为物理隔离和逻辑隔离:

  • 需定制化逻辑的能力和有特殊非功能性要求的能力剥离出来做物理隔离
  • 标准化且没有特殊非功能要求的能力采用逻辑隔离
部署架构图

先采用独立的秒杀域名和nginx集群(物理隔离)。这样:

  • 可以隔离流量大头,防止峰值冲击交易系统(非功能性需求)

  • 灵活扩展,针对不同时段的流量预估扩展nginx及后边服务的规模(非功能性需求)

  • 灵活增减私有的防控逻辑,而不影响原交易系统(定制化逻辑)

接着,将商详页和下单页独立部署(前端+BFF,物理隔离)。基于秒杀活动的玩法特征,海量用户在活动快开始时会反复刷新商详页,在活动开始时又会瞬时并发到访问下单页,所以这俩页面都是承受流量冲击的大头,需隔离开(非功能性需求)。同时因秒杀活动特性,商品属极端供不应求的场景,卖家占优势,所以可做服务降级,以降低计算资源消耗、提高性能(定制化逻辑)。如:

  • 商详页可将履约时效拿掉,不再计算预计多久能到货。还可拿掉评价信息,不再展示评价
  • 下单页可不再计算优惠金额分摊,秒杀商品不参与任何叠加优惠活动。仅保留必要信息,如商品信息,商品主图,购买按钮,下单按钮等
  • 结算页、收银台,则看情况,若流量压力不大,可不用物理隔离:
    • 支付扣减库存下单的压力会直接传递到结算
    • 但下单扣减就不需要并发支付,仅抢到的用户需结算,压力就很小
    • 为降低流量影响面积,这里假设下单扣减,毕竟秒杀商品也不怕客户下单后不支付

秒杀商品不怕客户不支付的原因

  • 商品吸引力:秒杀商品往往是极具吸引力的折扣商品,抢购用户通常都会完成支付,未支付的比例较低
  • 多次释放机制:即使有用户不支付,库存会在短时间内释放出来,其他用户可以继续抢购,这个过程在秒杀活动的激烈程度下通常很快完成。

最后,商品购买成功还需要依赖,订单系统创建订单,库存系统扣减商品库存,结算系统确认支付等等步骤。到达这里,流量相对已较平稳,且逻辑上没啥定制化诉求(压力小,没必要围绕性能做定制化),所以采用逻辑隔离复用原交易系统的集群。逻辑隔离两种实现思路:

  • 依赖限流框架,如在订单系统设置来源是秒杀系统BFF的创建订单请求,TPS不超100,并发连接数不能超过20
  • 依赖RPC框架,RPC框架可设置分组,只把订单系统集群里面部分服务节点设置成“秒杀组”,再把秒杀服务BFF的客户端也设置为“秒杀组”,那么秒杀系统的流量就只会打到订单系统集群里面属于“秒杀组”的节点上。这种隔离方式分割了集群,集群节点少了,出现故障发生过载的可能就提高了,可能会导致秒杀系统不可用

Q:为啥集群节点少了,出现故障发生过载的可能就提高?

A:好比公里原本4条道能并行4辆车,现在给按车辆类型分成了机动车和公交车专用,机动车道2条。如果其中1条机动车道发生车祸,原本分散在2条道上的车流就要汇聚在1条道,原本顺畅的通行可能立马就开始堵车了。

1.2 多级缓存

在系统的多个层级进行数据缓存,以提高响应效率,高并发架构中最常用方案之一。

1.2.1 DNS层

一般将静态资源挂到CDN上,借助CDN来分流和提高响应效率。以秒杀系统为例,就是将秒杀前端系统的商详页和下单页缓存到CDN网络上。

借助CDN的用户请求链路:

如果用户终端有页面缓存就走终端本地缓存,没有就请求远端CDN的域名(静态资源走CDN域名),请求来到DNS调度的节点,调度一个最近的CDN节点,如果该CDN节点有页面缓存则返回,没有则向缘站发起溯源,请求就会走普通链路过秒杀系统ng到秒杀系统前端。

1.2.2 网关层

网关这个有多种组合情况,最简单的就是一个接入层网关加一个应用层网关,比如:ISV(四层)-> Nginx(七层)。以这个为例,这里的缓存优化主要看接入层的负载均衡算法和应用层的本地缓存和集中内存缓存。

缓存还要提LB算法,是因为节点的本地缓存的有效性和LB算法强绑定。常用LB算法有轮询(也叫取模)和一致性哈希:

  • 轮询可以让请求分发更均衡,但同个缓存key的请求不一定会路由到同个应用层Nginx上,Nginx的本地缓存命中率低
  • 一致性哈希可让同个缓存key路由到同个应用层Nginx上,Nginx的本地缓存命中率高,但其请求分发不均衡容易出现单机热点问题。有种做法是设置一个阈值,当单节点请求超过阈值时改为轮询,可以算是自适应性负载均衡的变种。但这种基于阈值判断的做法在应对真正的高并发时效果并不理想。

所以想运用本地缓存强依赖业务运营,需对每个热点商品key有较为准确的流量预估,并人为的组合这些商品key,进而控制流量均匀的落到每个应用层Nginx上(其实就是数据分片,然后每片数据流量一致)。这非常困难,所以笔者认为,还是采用轮询加集中内存缓存比较简单有效。

从接入层开始带有本地缓存和集中内存缓存的请求链路:

1.2.3 服务层
应用层ngnix->秒杀系统BFF->订单服务

其实两两组合和网关层是一样的场景。应用层ngnix基于ngnix的负载均衡转发请求到秒杀系统BFF,秒杀系统BFF基于RPC框架的负载均衡转发请求到订单服务。都面临着负载均衡策略选择和是否启用本地缓存的问题。不一样的点只是缓存的粒度和启用缓存的技术栈选择。

1.2.4 多级缓存失效

因为缓存分散到多层,很难用单一技术栈应对缓存失效问题,但都等到缓存过期,这种更新时延较长又不一定能被业务接受。

有个做法是基于DB的binlog监听,各层监听自己相关的binlog信息,在发生缓存被变更的情况时,及时让集成内存的缓存失效。

本地缓存在这里还有个缺陷,就是缓存失效时需要广播到所有节点,让每个节点都失效,对于频繁变更的热key就可能产生消息风暴。

1.3 无损消峰

为流量峰值准备对应的服务集群,首先成本太高,接着单纯的水平扩展也不一定能做到(分布式架构存在量变引起质变的问题,资源扩展到一定量级,原先的技术方案整个就不适用了。

如当集群节点太多,服务注册发现可能会有消息风暴;出入口的带宽出现瓶颈,需要在部署上分流)。更别说这个峰值也不受控制,想要高枕无忧就会有很高的冗余浪费。

所以一般采用消峰:

  • 直接断头,把超出负荷的流量直接都丢弃掉,也就是我们常见的限流,也称为有损消峰(如果这是大促的订单,砍掉的可能都是钱,这个有损是真的资损)
  • 分流,也叫消峰填谷,通过技术或者业务手段将请求错开,铺到更长的时间线上,从而降低峰值,常见的有MQ异步消费和验证码问答题。先谈无损消峰
1.3.1 MQ异步消费

MQ依赖三个特性可以做到平滑的最终一致,分别是:

  • 有消息堆积才能起到蓄水池的效果,在出水口流速恒定的情况下能接住入水口瞬时的大流量
  • 有匀速消费才能让下游集群的流量压力恒定,不会被冲击
  • 有至少成功一次,才能保证事物最终一致

以秒杀系统BFF下单操作向订单服务创建订单为例。如果没有消息队列(MQ),同时有100W个创建请求,订单系统就必须承担100W个并行连接的压力。但是,如果使用了MQ,那么100W个创建请求的压力将全部转移到MQ服务端,订单系统只需要维持64个并行连接,以稳定地消费MQ服务端的消息。

这样一来,订单系统的集群规模就可以大大减小,而且更重要的是,系统的稳定性得到了保障。由于并行连接数的减少,资源竞争也会降低,整体响应效率也会提高,就像在食堂排队打饭一样,有序排队比乱抢效率更高。但是,用户体验可能会受到影响,因为点击抢购后可能会收到排队提示(其实就是友好提示),需要延迟几十秒甚至几分钟才能收到抢购结果。

1.3.2 验证码问答题

两层好处:

  • 消峰,用户0.5秒内并发的下单事件,因为个人的手速差异,被平滑的分散到几秒甚至几十秒中
  • 防刷,提高机器作弊成本
验证码

基本实现步骤:

  • 请求到来时生成1串6位随机字符串 verification_code

  • 用特定前缀拼接用户ID作为key,verification_code做为value存redis,超时5s

  • 生成一个图片,将 verification_code 写到图片上,返回给用户

  • 用户输入图片中字符串

  • 从redis里面取出 verification_code 做比对,如果一致,执行下单操作

但这样其实是可以用暴力破解的,比如,用机器仿照一个用户发起10W个请求携带不同的6位随机字符。所以校验验证码时可以使用 GETDEL ,让验证码校验无论对错都让验证码失效。

问答题

基本实现思路和验证码几乎一样。差别在于,问答题的题库要提前生成,请求到来时从题库中拿到一组问题和答案。然后把答案存redis,问题塞到图片里返回给用户。

验证码和问答题具有很好的消峰效果。特别是问答题,想要提高消峰效果只要提高问题难度就行,例如,笔者曾经在12306上连续错了十几次问答题。但是这也是用户体验有损的,例如,虽然笔者当初未能成功抢到票而感到沮丧,但这魔性的题库依然把笔者成功逗笑。

无损消峰,无损了流量,但损失了用户体验。现如今技术水平在不断进步,解决方法在增多,这些有损用户体验的技术方案可能都会慢慢退出历史舞台,就像淘宝取消618预售。 关注我,紧跟本系列专栏文章,咱们下篇再续!

作者简介:魔都架构师,多家大厂后端一线研发经验,在分布式系统设计、数据平台架构和AI应用开发等领域都有丰富实践经验。

各大技术社区头部专家博主。具有丰富的引领团队经验,深厚业务架构和解决方案的积累。

负责:

  • 中央/分销预订系统性能优化

  • 活动&券等营销中台建设

  • 交易平台及数据中台等架构和开发设计

  • 车联网核心平台-物联网连接平台、大数据平台架构设计及优化

  • LLM Agent应用开发

  • 区块链应用开发

  • 大数据开发挖掘经验

  • 推荐系统项目

    目前主攻市级软件项目设计、构建服务全社会的应用系统。 本文由博客一文多发平台 OpenWrite 发布!


http://www.ppmy.cn/news/1515813.html

相关文章

MVC 参考手册

MVC 参考手册 1. 引言 MVC(Model-View-Controller)是一种广泛使用的软件架构模式,它将应用程序的逻辑分为三个相互关联的组件:模型(Model)、视图(View)和控制器(Controller)。这种模式最早在20世纪70年代被提出,用于Smalltalk编程语言中,后来被广泛采用于各种编程…

Elasticsearch安装 Kibana安装

安装Elasticsearch 一、拉取镜像或者上传 docker pull Elasticsearch 二、将上传的镜像导入(在仓库拉取的这一步跳过) docker load -i es.tar docker load -i 三、创建容器 1.Elasticsearch 注意修改到自己的网络(第八行) docker run -d \--nam…

【springboot系列】springboot的启动原理,springboot应用是如何启动的

【springboot系列】springboot的启动原理,springboot应用是如何启动的 Spring Boot的启动原理是一个复杂而精妙的流程,它负责加载配置、初始化应用上下文、自动配置和启动内嵌服务器等任务。以下是Spring Boot启动原理的详细解释: 1. 加载主…

一文入门:正则表达式基础

正则表达式简介 正则表达式(Regular Expression,简称regex或RE)是一种用于匹配字符串中字符组合的模式。它广泛应用于编程语言、文本编辑器和各种工具中,用于执行复杂的字符串搜索和替换任务。 为什么使用正则表达式&#xff1f…

G1处理器GC调优常用参数详解

mixGC触发机制: G1 垃圾收集器在执行垃圾收集时,会根据不同的情况选择不同的垃圾收集策略,其中 "Mixed GC" 是一种比较复杂的策略,用于回收整个堆内存中的垃圾。 G1 垃圾收集器执行 Mixed GC 的时机通常取决于以下几个…

GUI编程01:第一个Frame窗口

本节内容视频链接:3、第一个Frame窗口_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1DJ411B75F?p3&vd_sourceb5775c3a4ea16a5306db9c7c1c1486b5 1.GUI编程中用到的类 2.我的第一个Frame窗口代码 package com.yundait.www;import java.awt.*;public …

iOS 17.6.1版本重发,修复高级数据保护错误

今日,苹果没有带来iOS 17.6.2的更新,而是重新发布了iOS 17.6.1版本,本次升级版本号为21G101,高于第一版的21G93。距离初版发布相隔一周半时间。 在 iOS / iPadOS 17.6.1 的更新日志,苹果公司写道:“此更新包…

如何在分布式环境中实现高可靠性分布式锁

目录 一、简单了解分布式锁 (一)分布式锁:应对分布式环境的同步挑战 (二)分布式锁的实现方式 (三)分布式锁的使用场景 (四)分布式锁需满足的特点 二、Redis 实现分…

最近云计算领域有哪些重大进展?

在云计算领域,近期确实涌现出了一系列令人瞩目的重大进展。以下是一些关键点,为您概述了当前的科技动态: 中国云计算市场迅猛发展: 中国云计算市场正处于快速发展期,年复合增长率超过40%。公有云市场规模增长49.3%至32…

CISAW安全集成和别的类型有什么区别

信息安全人员认证(Certified Information Security Assurance Worker, CISAW)是由中国网络安全审查技术认证中心依据信息安全领域的不同专业、技术和应用方向以及安全岗位需求,按照ISO/IEC 17024标准建立的多层次认证体系。 CISAW分为三个主…

Win/Linux/Mac 安装Python 3.6

一.Win 1.下载Python 3.6 Windows 版本 方法一(访问速度慢): 官网地址 方法二(推荐): 各个Python版本下载 国内下载镜像1 国内下载镜像2 2.安装时注意选择" Add Python 3.6 to PATH "&…

CSS的font-stretch属性与字符胖瘦控制

font-stretch CSS 属性用于选择字体的一个更宽(expanded)或更窄(condensed)的版本,以控制字符的“胖瘦”。然而,需要注意的是,并非所有的字体都支持多种拉伸变体(stretch variants&a…

鸿蒙(API 12 Beta3版)【使用Image完成图片接收器】图片开发指导依赖JS对象

图像接收类,用于获取组件surface id,接收最新的图片和读取下一张图片,以及释放ImageReceiver实例。 开发步骤 添加依赖 在进行应用开发之前,开发者需要打开native工程的src/main/cpp/CMakeLists.txt,在target_link_…

一文入门mysql 数据库,小白看了都能学会

数据库 数据库分为关系型数据库和非关系型数据库。 一、关系型数据库 关系型数据库常见的有下面几种:oracle大型数据库;sqlserver企业级;sqlite文件数据库一个文件就是一个数据库,数据库下可以有表;当然最重要的还是mysql是一个…

巨省成本的电子版招生简章越来越流行,你知道是怎么制作的吗?

随着科技的不断发展,传统的纸质招生简章逐渐被电子版招生简章所取代。电子版招生简章不仅能够节省大量成本,还能够提高宣传效果,因此在市场上越来越流行。你知道它是怎么制作的吗? 1.要制作电子杂志,首先需要选择一款适合自己的软…

如何克服编程学习中的挫折感

学习编程的过程中,遇到挫折是再正常不过的事。每个人都有过卡在一个Bug上几天甚至几周,或者在理解复杂算法时感到迷茫的经历。下面是一些我在面对这些挑战时总结出来的经验,希望能对你有所帮助: 方向一:心态调整 接受…

JVM-Java的四种引用

引用分析 无论是通过引用计数算法判断对象的引用数量,还是通过可达性分析算法判断对象是否可达,判定对象是否可被回收都与引用有关,Java 提供了四种强度不同的引用类型 强引用: 被强引用关联的对象不会被回收,只有所…

Python网络编程:Web框架基础(Flask/Django)

Python作为一种功能强大且易于使用的编程语言,广泛应用于Web开发领域。Python的丰富生态系统中,有两个非常流行的Web框架:Flask和Django。本博文将详细介绍这两个框架的基础知识,并通过综合示例展示如何使用它们构建Web应用。 一…

智能温度监测与控制系统:基于冒泡、选择、快速和归并排序算法的实现(代码详解)

一、项目概述 目标和用途 智能温度监测和控制系统旨在实时监测环境温度,并根据收集到的数据进行分析和控制。该系统能够从多个温度传感器采集数据,对这些数据进行排序和分析,以便于控制加热或冷却设备,从而保持设定的温度范围。…

使用 Python 爬虫进行网站流量分析:Referer 头的利用

在互联网时代,网站流量分析是了解用户行为、优化网站结构和提升用户体验的重要手段。本文将介绍如何使用 Python 爬虫技术结合 HTTP Referer 头进行网站流量分析,以及如何实现这一过程。 什么是 HTTP Referer 头? HTTP Referer 头是一个请求…