作者简介:丛磊
白山合伙人兼工程副总裁
丛磊先生2016年加入白山,主要负责云链体系的设计与落实等工作。
丛磊先生2006年至2015年就职于新浪,原SAE(SinaAppEngine)创始人,曾任总负责人兼首席架构师,2010年起,带领新浪云计算团队从事云相关领域的技术研发工作。(注:SAE是国内最大的公有云PaaS平台,拥有70万用户。)
丛磊先生拥有两项发明专利,现任工信部可信云服务认证评委。
一天清晨,我被一个客户电话惊醒,客户异常焦急,寻问CDN能不能帮助他们解决“秒杀”的问题,他们昨天刚刚进行了“整点秒杀活动”,结果并发量过大,导致服务宕机,用户投诉。
为了理清思路,我问了对方三个问题:
(1)服务宕机的表现是什么?
(2)业务的基本架构什么样?
(3)秒杀的峰值并发到多少?
顺着这些线索,我们先一起还原了应用场景:
某电商业务架构图
该公司是一家P2P理财网站,常有用户在整点抢购高利率理财产品的“整点秒杀活动”。如上图所示,终端用户请求先通过前端负载均衡,然后到达运行实际电商逻辑的Web Server;再下层是运行在VM上的8台Redis,负责存储与业务相关的Cache数据,如用户Profile、理财产品信息、用户账单信息等。实际落地数据存储在MySQL中,该MySQL只进行了简单的分库分表及读写分离。
进行“秒杀”时,先由风控和运营人员选好理财产品,然后标记到数据库中;活动开始由产品人员放开,终端用户抢购。
该公司的业务主要来自移动端,平时流量较少,但“秒杀”活动时会瞬间产生大量流量,峰值并发达到10万以上(其中可能包括bot),如此大的并发主要是集中在以下两类接口:
(1)对于理财产品的刷新接口,类似GET /get_fprod.php?uid={$1}&pid={$2}&sid={$3},此类接口的请求量最多,占比90%。
(2)对于理财产品的下单接口,类似 GET /order_fprod?uid={$1}&pid={$2}&oid={$3}&sid={$4},此类接口的请求量较少,占比不到1%,但存在大量504超时。
其中uid是用户ID,pid是理财产品ID,oid是订单号,sid是随着客户端用户变化的随机token标识。
场景解读
根据与客户沟通得到的场景,初步得到了以下结论:
(1)客户以移动业务为主,产品通过API在客户端渲染UI,产品中几乎没有静态资源,带宽流量不高,传统CDN无法达到卸载压力的作用;
(2)秒杀时,产生大量502/504超时请求,说明此时用户请求已超过服务端的业务承载能力,急需扩容。
基于以上两点,我没有建议该公司采购CDN服务,而是推荐服务扩容,但随着我方对于业务更深层次的分析,逐渐发现了一些诡异的事情。
“诡异”现象
(1)数据库主从负载极不均衡,通过MySQL管理工具,发现主库的Query量高达80%;
(2)Redis Cache节点负载极不均衡,通过查看redis info发现,秒杀时,其中一台Redis请求量极大,占比达90%以上,其他Redis请求量却很低。
上述反常现象激起了双方技术人员的兴趣,这也许就是问题的关键!随着分析深入,第一个现象 浮出水面:该公司在使用数据库时,并未如某些大型电商平台一样使用数据库中间件层进行MySQL请求的路由分发,而是在业务代码端,使用语言层面的框架完成读写分离工作。这带来了两个弊端:
(1)程序员绕过语言层框架开发,并未真正实施读写分离;
(2) 产品人员要求展现效果实时,倒逼开发人员修改业务逻辑,会牺牲读写分离,使数据都在主库读写。
Cache穿透示意图
接着,第二个现象的原因也逐渐清晰:秒杀时,大量用户访问极少数理财产品,当这几个产品的pid恰好被hash到同一个Redis上,就会导致Cache节点热点失衡,所有请求最终集中在一个Redis,而这个Redis就是业务的瓶颈!
对症下药
1.使用数据库中间件进行读写分离以及横向扩展控制
使用数据库中间件可以带来诸多好处,其中最重要的是可对业务层隐藏部分数据库细节,更好地控制业务。当然,引入数据库中间层也存在明显缺点,在业务整体架构中增加一层组件,违反了“简单有效”的设计原则。对于很多互联网公司,在早期甚至中期没有数据库中间层也很正常。 但当业务发展到一定阶段,引入数据库中间层是利大于弊的。
基于经验,我方推荐客户使用MySQL Route,基本可以满足简单需求,如:连接复用;负载均衡;读写分离。
MySQL Route架构图
上图是MySQL Router官方架构图,可以看到,MySQL Router优势在于插件化设计,官方提供了一系列插件供使用。
除MySQL Router,国内还有很多开源数据库中间件可以采用,如阿里、美团等。
使用数据库中间层,不仅可以解决性能问题,还能在安全方面起到作用,如审计、流量限制等,甚至拦截SQL注入、劣质SQL语句等。
2.使用API加速服务缓解服务端压力
Cache服务失衡是比较棘手的问题。“秒杀”时,用户高频访问少数几个理财产品信息,当其Cache数据恰巧分配在同一节点,大量请求会瞬间集中到一台或少数几台节点,这就是Cache服务失衡的本质原因。不仅在电商“秒杀”场景中,其他有瞬间热点访问的业务类型也会存在这个问题。以微博为例,曾因明星热点事件导致接口缓慢甚至服务宕机,归根到底也是这个原因。“爆料”的瞬间,一个微博会在短时间内海量传播,该微博ID被同时打开,所有流量会集中到一个Redis节点。
这个问题如何解决?首先,Cache通常以某个数据结构的key为维度进行hash存储,大量用户只访问一个或几个key时,将导致Redis Cache节点负载不均衡,这是否一定对服务产生影响,则视并发情况而定,但这是一个巨大隐患。针对这个问题,客户提出了一种解决方案:把一个理财产品的Cache数据再拆散,1个key变成多个,降低key被分配到同一Cache节点的概率。但这种方法存在很大弊端:
(1)需要修改代码,原本一条get请求就可以完成的逻辑,要换成多条才能拼成;
(2)日常所有get/set操作的时间消耗都将成倍增加,因为1%的热点事件增加99%常规操作的时间,严重违背二八法则。
基于以上问题,我们推荐客户使用白山云聚合CLN-X的“API加速”来解决这个问题。
API加速
API加速完全不同于传统CDN的链路加速,通过缓存API返回内容并结合TCP广域网优化技术,对API请求进行优化。白山API加速将每个API的response数据毫秒级缓存在全网边缘节点,节点内存中的response数据以LRU(Least Recently Used)算法交换。在“热点事件”时,最热的信息持续保存在边缘节点,当客户端访问该API时,边缘节点可直接返回结果,不必返回源站。整个架构如下:
API加速架构图
API加速服务在网络边缘节点提供对API的加速能力,包括:API返回结果缓存能力、API请求回源网络加速能力。
传统观点认为,动态资源(API)无法缓存,但白山提出“任何资源都可以被缓存,只是过期时间不同”。对于常见的静态资源,缓存过期时间较长;而API并非不能被缓存,只是过期时间很短。如一个查询股价的API,可设定过期时间为50毫秒;百米运动员起跑反应时间为100-200毫秒,50毫秒对于PC端或移动端的用户体验并不会造成影响。
没有缓存时,1秒内如有10000个用户同时访问,后端承受10000个并发;如果设置50毫秒的缓存时间,理论上可将后端并发降低到20个(1秒/50毫秒=20),后端负载降低至五百分之一,其他请求由缓存服务器直接返回给用户。
综上所述,白山API加速为客户提供毫秒级缓存,在不影响用户体验的前提下提高终端用户响应速度,同时降低服务端的业务负载压力。
API加速还支持自定义缓存规则,使其更贴近业务,包括QueryString、Header、Path三种类型,针对场景,设定如下规则:
GET /get_fprod.php?uid={$1}&pid={$2}&sid={$3},每个理财产品都有独立ID,产品信息不随用户ID和客户端随机信息变化,因此Cache key可忽略URI中参数的{$1}和{$3},/get_fprod.php?pid={$2}就是在边缘节点存储毫秒级的Cache key。
缓存的过期时间如何确定呢?与业务相关,这需要对客户提供的脱敏日志进行分析,可初步设定过期时间为500毫秒,最后还需考虑RTT修正值,以适应广域网环境;RTT则由API加速服务自动捕捉并实时更新。
实际效果
通过为客户主要的瓶颈接口配置API加速服务,并在峰值时间,从以下两个维度对比API加速服务开启与关闭时的效果:
(1)终端用户请求平均响应时间和响应码200比例
(2)服务集群平均负载
最终效果如下:
图A
图B
图C
如图A所示,峰值期间终端用户请求平均响应时间,从3秒左右压缩至40毫秒以内;如图B所示,峰值期间所有请求响应码200的比例从70%左右提升至100%;图C表示,峰值期间,后端CPU Idle从10%左右提高至97%左右。实测对比数据表明,API加速对降低平均响应时间、提升用户体验效果十分显著,在降低后端服务器负载方面效果更加明显,使用API加速的后端CPU Idle可保持在91%以上。
后续建议
数据库失衡和缓存Redis失衡问题已经解决,但除上述问题,还有很多环节可以改善:
1.队列服务异步化请求
目前客户最终落地数据库请求直接请求到MySQL,未经队列缓冲,建议使用队列服务排队处理峰值请求,其好处在于能在大访问量时对请求进行调度,并可控制实际到达数据库的并发,从而有效保护数据库后端。
2.API防火墙屏蔽恶意Bot
用户日志中含有大量明显且规律的扫描软件痕迹,如sqlmap、fimap等,虽然尚未对业务造成较大影响,但却使服务端资源被占用。建议在负载均衡最前端对扫描行为予以屏蔽,以提高安全性,同时提升服务效率。除恶意Bot,抢单、刷单等行为也会对服务产生影响,建议使用API防护服务识别与拦截。
3.产品层考虑服务降级设计
该客户在整体业务上,没有服务降级设计,产品功能优先级未做划分,导致重要的数据库、Cache等众多基础服务混杂。一旦“秒杀”导致数据库穿透等严重问题时,整体服务将不可用。这种情况应重新梳理业务单元,按照优先级切分基础服务,首屏、产品列表、购买、订单等信息优先级最高;其次是非重要功能,如评论、账单等;如果后端负载较大,必要时可直接舍弃次要功能,从而降低后端负载,保证服务稳定。
总结
解决类似“整点秒杀活动”的情景,是一个系统复杂的工程,就文中客户暴露出来的数据库负载不均匀、Cache缓存负载不均匀等问题,可通过采用数据库中间层和API加速等技术解决,最终可取得理想效果。
上述“秒杀”案例,只是API加速的一个典型应用场景,接下来我还会撰文对API加速问题进行更为系统的剖析。也欢迎业界同仁通过微信后台(baishancloud)与我们取得联系,一起探讨API相关话题。
相关推荐
在IT行业中,尤其是在Java开发领域,高并发秒杀API的设计是相当重要的一项技术。它涉及到如何在短时间内处理大量用户请求,保证系统稳定性和性能。在这个主题下,我们主要讨论两个关键部分:业务分析和DAO(Data ...
在本课程中,我们将深入探讨Java高并发秒杀API的设计与实现,重点在于业务分析以及DAO(Data Access Object)层的构建。秒杀系统在电商、票务等场景中广泛应用,其核心挑战在于如何处理短时间内大量用户同时请求的高...
- **Netty**:高性能的网络通信框架,用于构建秒杀API的服务器端。 8. **重难点回顾**: - **幂等性**:确保同一操作无论执行多少次,结果始终一致,防止用户重复点击导致异常。 - **最终一致性**:在分布式环境...
Java高并发秒杀API是一个典型的企业级应用场景,主要用于处理大量用户在同一时间抢购限量商品的情况。在设计这样的系统时,我们需要关注多个关键知识点,包括但不限于数据库操作、并发控制、性能优化以及分布式协调...
这个项目专注于高并发场景下的秒杀API实现,涵盖了如何在大量用户同时请求时保持系统的稳定性和高效性。以下是这个项目中涉及的一些核心知识点: 1. **Spring框架**:Spring作为Java应用的核心框架,提供了依赖注入...
【SSM实战项目——Java高并发秒杀API详解】 在这个Java实战项目中,我们主要探讨的是如何使用Spring、Spring MVC和MyBatis(SSM)框架来构建一个高并发的秒杀系统。这个项目旨在帮助开发者理解在处理大量并发请求时...
在秒杀API的实现中,SpringMVC通过控制器(Controller)接收用户请求,调用业务逻辑,并返回响应结果。它的模型-视图-控制器架构使得业务逻辑和视图层分离,易于维护。 3. **MyBatis**:MyBatis是一个轻量级的持久...
总的来说,利用.NET Core、Mvc、WebApi、Console和Redis,我们可以构建出一个高效、可靠的秒杀系统,既能应对高并发挑战,又能保证业务逻辑的正确性。在实际开发中,还需要结合具体情况,对每个环节进行细致的优化和...
《IT学习资料》-SSM实战项目-Java高并发秒杀API是一份全面的教程,旨在帮助学习者掌握如何在Java环境下使用Spring、SpringMVC和MyBatis(简称SSM)框架构建高并发的秒杀系统。这个项目涵盖了从项目初始化到实现完整...
【标题】"秒杀神器,亲测可用"所提及的是一个专门为购物爱好者设计的软件工具,主要用于参与电商平台如淘宝的秒杀活动。秒杀活动通常指的是商家在特定时间以极低价格销售商品,吸引大量消费者同时抢购。这款秒杀器...
在Java中,构建一个高效的秒杀系统需要深入理解业务逻辑、并发控制、数据库优化以及分布式技术等多个方面。这里我们将围绕"java秒杀项目源码-seckill"这个项目进行详细的分析和讨论。 首先,`seckill`项目源码是...
2. **代码编写**:实现秒杀接口,处理秒杀逻辑,如库存检查、订单创建等。 3. **数据库配置**:使用提供的SQL文件初始化数据库,填充测试数据。 4. **性能优化**:引入缓存机制,如Redis,优化数据库操作,提升系统...
《IT学习资料2》是一个专为Java开发者设计的实践项目,主要聚焦于SSM(Spring、SpringMVC、MyBatis)框架的整合应用以及在高并发环境下的秒杀API实现。这个项目不仅包含了详细的操作流程,还有学习笔记,帮助开发者...
2. **Spring MVC**:作为Spring的一部分,Spring MVC负责处理HTTP请求,它将请求分发到控制器,控制器再调用业务逻辑,最终返回响应给客户端。Spring MVC的模型-视图-控制器架构模式使应用程序结构清晰,易于维护。 ...
- 倒计时逻辑:利用JavaScript的`setInterval`或`setTimeout`函数来定时更新倒计时显示,直到时间到达零。 - 服务器同步:为了确保所有用户看到的时间一致,需要与服务器进行时间同步,防止因客户端时间不准确导致...
标题中的".netcore秒杀活动,模拟"指出我们要探讨的是使用.NET Core框架构建的一个秒杀系统,这是一种在短时间内处理大量用户请求的高并发场景。在电商或其他促销活动中,秒杀功能常常被用来吸引用户,因此系统的...
【标题】:“java开发学习项目:商城秒杀项目”揭示了这是一个基于Java技术栈的电商系统开发实践,特别关注的是秒杀功能的实现。在Java开发中,商城系统是常见的项目类型,它涉及到用户交互、商品管理、订单处理等多...
- 接口层:提供秒杀API,处理用户请求,通常由SpringBoot的Controller实现。 - 业务逻辑层:处理秒杀逻辑,如验证用户资格、扣除库存等,这可能涉及到与数据库的交互。 - 缓存层:Redis用于存储临时数据和实现...
- **JavaScript API**:小程序的业务逻辑通过JavaScript处理,包括数据操作、页面路由、网络请求等,微信提供了丰富的API供开发者调用。 2. **后端开发**: - **语言选择**:通常后端开发可能使用Java、Python、...
2. **业务逻辑层**:实现具体业务逻辑,如验证用户资格、检查库存、扣除库存等。 3. **数据访问层**:通过Spring Data JPA与数据库交互,进行CRUD操作。 4. **服务治理**:可能包含Spring Cloud相关组件,如Eureka...