计算机网站建设文献综述,网站建设公司石家庄,如何让广域网访问利用公网ip和本地服务器建设的网站,计算机科学与技术 开题报告 网站建设很多小伙伴反馈说#xff0c;高并发专题学了那么久#xff0c;但是#xff0c;在真正做项目时#xff0c;仍然不知道如何下手处理高并发业务场景!图片来自 Pexels甚至很多小伙伴仍然停留在只是简单的提供接口(CRUD)阶段#xff0c;不知道学习的并发知识如何运用到实际项目…很多小伙伴反馈说高并发专题学了那么久但是在真正做项目时仍然不知道如何下手处理高并发业务场景!图片来自 Pexels甚至很多小伙伴仍然停留在只是简单的提供接口(CRUD)阶段不知道学习的并发知识如何运用到实际项目中就更别提如何构建高并发系统了!究竟什么样的系统算是高并发系统?今天我们就一起解密高并发业务场景下典型的秒杀系统的架构结合高并发专题下的其他文章学以致用。电商系统架构在电商领域存在着典型的秒杀业务场景那何谓秒杀场景呢。简单的来说就是一件商品的购买人数远远大于这件商品的库存而且这件商品在很短的时间内就会被抢购一空。比如每年的 618、双 11 大促小米新品促销等业务场景就是典型的秒杀业务场景。我们可以将电商系统的架构简化成下图所示由图所示我们可以简单的将电商系统的核心层分为负载均衡层、应用层和持久层。接下来我们就预估下每一层的并发量假如负载均衡层使用的是高性能的 Nginx则我们可以预估 Nginx 最大的并发度为10W这里是以万为单位。假设应用层我们使用的是 Tomcat而 Tomcat 的最大并发度可以预估为 800 左右这里是以百为单位。假设持久层的缓存使用的是 Redis数据库使用的是 MySQLMySQL 的最大并发度可以预估为 1000 左右以千为单位。Redis 的最大并发度可以预估为 5W 左右以万为单位。所以负载均衡层、应用层和持久层各自的并发度是不同的那么为了提升系统的总体并发度和缓存我们通常可以采取哪些方案呢?①系统扩容系统扩容包括垂直扩容和水平扩容增加设备和机器配置绝大多数的场景有效。②缓存本地缓存或者集中式缓存减少网络 IO基于内存读取数据。大部分场景有效。③读写分离采用读写分离分而治之增加机器的并行处理能力。秒杀系统的特点对于秒杀系统来说我们可以从业务和技术两个角度来阐述其自身存在的一些特点。秒杀系统的业务特点这里我们可以使用 12306 网站来举例每年春运时12306 网站的访问量是非常大的但是网站平时的访问量却是比较平缓的也就是说每年春运时节12306 网站的访问量会出现瞬时突增的现象。再比如小米秒杀系统在上午 10 点开售商品10 点前的访问量比较平缓10 点时同样会出现并发量瞬时突增的现象。所以秒杀系统的流量和并发量我们可以使用下图来表示由图可以看出秒杀系统的并发量存在瞬时凸峰的特点也叫做流量突刺现象。我们可以将秒杀系统的特点总结如下①限时、限量、限价在规定的时间内进行;秒杀活动中商品的数量有限;商品的价格会远远低于原来的价格也就是说在秒杀活动中商品会以远远低于原来的价格出售。例如秒杀活动的时间仅限于某天上午 10 点到 10 点半商品数量只有 10 万件售完为止而且商品的价格非常低例如1 元购等业务场景。限时、限量和限价可以单独存在也可以组合存在。②活动预热需要提前配置活动;活动还未开始时用户可以查看活动的相关信息;秒杀活动开始前对活动进行大力宣传。③持续时间短购买的人数数量庞大;商品会迅速售完。在系统流量呈现上就会出现一个突刺现象此时的并发访问量是非常高的大部分秒杀场景下商品会在极短的时间内售完。秒杀系统的技术特点我们可以将秒杀系统的技术特点总结如下①瞬时并发量非常高大量用户会在同一时间抢购商品;瞬间并发峰值非常高。②读多写少系统中商品页的访问量巨大;商品的可购买数量非常少;库存的查询访问数量远远大于商品的购买数量。在商品页中往往会加入一些限流措施例如早期的秒杀系统商品页会加入验证码来平滑前端对系统的访问流量近期的秒杀系统商品详情页会在用户打开页面时提示用户登录系统。这都是对系统的访问进行限流的一些措施。③流程简单秒杀系统的业务流程一般比较简单;总体上来说秒杀系统的业务流程可以概括为下单减库存。针对这种短时间内大流量的系统来说就不太适合使用系统扩容了因为即使系统扩容了也就是在很短的时间内会使用到扩容后的系统大部分时间内系统无需扩容即可正常访问。那么我们可以采取哪些方案来提升系统的秒杀性能呢?秒杀系统方案针对秒杀系统的特点我们可以采取如下的措施来提升系统的性能。①异步解耦将整体流程进行拆解核心流程通过队列方式进行控制。②限流防刷控制网站整体流量提高请求的门槛避免系统资源耗尽。③资源控制将整体流程中的资源调度进行控制扬长避短。由于应用层能够承载的并发量比缓存的并发量少很多。所以在高并发系统中我们可以直接使用 OpenResty 由负载均衡层访问缓存避免了调用应用层的性能损耗。大家可以到 https://openresty.org/cn/ 来了解有关 OpenResty 更多的知识。同时由于秒杀系统中商品数量比较少我们也可以使用动态渲染技术CDN 技术来加速网站的访问性能。如果在秒杀活动开始时并发量太高时我们可以将用户的请求放入队列中进行处理并为用户弹出排队页面。秒杀系统时序图网上很多的秒杀系统和对秒杀系统的解决方案并不是真正的秒杀系统他们采用的只是同步处理请求的方案一旦并发量真的上来了他们所谓的秒杀系统的性能会急剧下降。我们先来看一下秒杀系统在同步下单时的时序图。同步下单流程①用户发起秒杀请求在同步下单流程中首先用户发起秒杀请求。商城服务需要依次执行如下流程来处理秒杀请求的业务。识别验证码是否正确商城服务判断用户发起秒杀请求时提交的验证码是否正确。判断活动是否已经结束验证当前秒杀活动是否已经结束。验证访问请求是否处于黑名单在电商领域中存在着很多的恶意竞争也就是说其他商家可能会通过不正当手段来恶意请求秒杀系统占用系统大量的带宽和其他系统资源。此时就需要使用风控系统等实现黑名单机制。为了简单也可以使用拦截器统计访问频次实现黑名单机制。验证真实库存是否足够系统需要验证商品的真实库存是否足够是否能够支持本次秒杀活动的商品库存量。扣减缓存中的库存在秒杀业务中往往会将商品库存等信息存放在缓存中此时还需要验证秒杀活动使用的商品库存是否足够并且需要扣减秒杀活动的商品库存数量。计算秒杀的价格由于在秒杀活动中商品的秒杀价格和商品的真实价格存在差异所以需要计算商品的秒杀价格。注意如果在秒杀场景中系统涉及的业务更加复杂的话会涉及更多的业务操作这里我只是列举出一些常见的业务操作。②提交订单订单入口将用户提交的订单信息保存到数据库中。扣减真实库存订单入库后需要在商品的真实库存中将本次成功下单的商品数量扣除。如果我们使用上述流程开发了一个秒杀系统当用户发起秒杀请求时由于系统每个业务流程都是串行执行的整体上系统的性能不会太高当并发量太高时我们会为用户弹出下面的排队页面来提示用户进行等待。此时的排队时间可能是 15 秒也可能是 30 秒甚至是更长时间。这就存在一个问题在用户发起秒杀请求到服务器返回结果的这段时间内客户端和服务器之间的连接不会被释放这就会占大量占用服务器的资源。网上很多介绍如何实现秒杀系统的文章都是采用的这种方式那么这种方式能做秒杀系统吗?答案是可以做但是这种方式支撑的并发量并不是太高。此时有些网友可能会问我们公司就是这样做的秒杀系统啊!上线后一直在用没啥问题啊!我想说的是使用同步下单方式确实可以做秒杀系统但是同步下单的性能不会太高。之所以你们公司采用同步下单的方式做秒杀系统没出现大的问题那是因为你们的秒杀系统的并发量没达到一定的量级也就是说你们的秒杀系统的并发量其实并不高。所以很多所谓的秒杀系统存在着秒杀的业务但是称不上真正的秒杀系统原因就在于他们使用的是同步的下单流程限制了系统的并发流量。之所以上线后没出现太大的问题是因为系统的并发量不高不足以压死整个系统。如果 12306、淘宝、天猫、京东、小米等大型商城的秒杀系统是这么玩的话那么他们的系统迟早会被玩死他们的系统工程师不被开除才怪!所以在秒杀系统中这种同步处理下单的业务流程的方案是不可取的。以上就是同步下单的整个流程操作如果下单流程更加复杂的话就会涉及到更多的业务操作。异步下单流程既然同步下单流程的秒杀系统称不上真正的秒杀系统那我们就需要采用异步的下单流程了。异步的下单流程不会限制系统的高并发流量。①用户发起秒杀请求用户发起秒杀请求后商城服务会经过如下业务流程。检测验证码是否正确用户发起秒杀请求时会将验证码一同发送过来系统会检验验证码是否有效并且是否正确。是否限流系统会对用户的请求进行是否限流的判断这里我们可以通过判断消息队列的长度来进行判断。因为我们将用户的请求放在了消息队列中消息队列中堆积的是用户的请求我们可以根据当前消息队列中存在的待处理的请求数量来判断是否需要对用户的请求进行限流处理。例如在秒杀活动中我们出售 1000 件商品此时在消息队列中存在 1000 个请求如果后续仍然有用户发起秒杀请求则后续的请求我们可以不再处理直接向用户返回商品已售完的提示。所以使用限流后我们可以更快的处理用户的请求和释放连接的资源。发送 MQ用户的秒杀请求通过前面的验证后我们就可以将用户的请求参数等信息发送到 MQ 中进行异步处理同时向用户响应结果信息。在商城服务中会有专门的异步任务处理模块来消费消息队列中的请求并处理后续的异步流程。在用户发起秒杀请求时异步下单流程比同步下单流程处理的业务操作更少它将后续的操作通过 MQ 发送给异步处理模块进行处理并迅速向用户返回响应结果释放请求连接。②异步处理我们可以将下单流程的如下操作进行异步处理判断活动是否已经结束判断本次请求是否处于系统黑名单为了防止电商领域同行的恶意竞争可以为系统增加黑名单机制将恶意的请求放入系统的黑名单中。可以使用拦截器统计访问频次来实现。扣减缓存中的秒杀商品的库存数量。生成秒杀 Token这个 Token 是绑定当前用户和当前秒杀活动的只有生成了秒杀 Token 的请求才有资格进行秒杀活动。这里我们引入了异步处理机制在异步处理中系统使用多少资源分配多少线程来处理相应的任务是可以进行控制的。③短轮询查询秒杀结果这里可以采取客户端短轮询查询是否获得秒杀资格的方案。例如客户端可以每隔 3 秒钟轮询请求服务器查询是否获得秒杀资格。这里我们在服务器的处理就是判断当前用户是否存在秒杀 Token如果服务器为当前用户生成了秒杀 Token则当前用户存在秒杀资格。否则继续轮询查询直到超时或者服务器返回商品已售完或者无秒杀资格等信息为止。采用短轮询查询秒杀结果时在页面上我们同样可以提示用户排队处理中但是此时客户端会每隔几秒轮询服务器查询秒杀资格的状态相比于同步下单流程来说无需长时间占用请求连接。此时可能会有网友会问采用短轮询查询的方式会不会存在直到超时也查询不到是否具有秒杀资格的状态呢?答案是有可能!这里我们试想一下秒杀的真实场景商家参加秒杀活动本质上不是为了赚钱而是提升商品的销量和商家的知名度吸引更多的用户来买自己的商品。所以我们不必保证用户能够 100% 的查询到是否具有秒杀资格的状态。④秒杀结算验证下单 Token客户端提交秒杀结算时会将秒杀 Token 一同提交到服务器商城服务会验证当前的秒杀 Token 是否有效。加入秒杀购物车商城服务在验证秒杀 Token 合法并有效后会将用户秒杀的商品添加到秒杀购物车。⑤提交订单订单入库将用户提交的订单信息保存到数据库中。删除 Token秒杀商品订单入库成功后删除秒杀 Token。这里大家可以思考一个问题我们为什么只在异步下单流程的粉色部分采用异步处理而没有在其他部分采取异步削峰和填谷的措施呢?这是因为在异步下单流程的设计中无论是在产品设计上还是在接口设计上我们在用户发起秒杀请求阶段对用户的请求进行了限流操作可以说系统的限流操作是非常前置的。在用户发起秒杀请求时进行了限流系统的高峰流量已经被平滑解决了再往后走其实系统的并发量和系统流量并不是非常高了。所以网上很多的文章和帖子中在介绍秒杀系统时说是在下单时使用异步削峰来进行一些限流操作那都是在扯淡!因为下单操作在整个秒杀系统的流程中属于比较靠后的操作了限流操作一定要前置处理在秒杀业务后面的流程中做限流操作是没啥卵用的。高并发“黑科技”与致胜奇招假设在秒杀系统中我们使用 Redis 实现缓存假设 Redis 的读写并发量在 5 万左右。我们的商城秒杀业务需要支持的并发量在 100 万左右。如果这 100 万的并发全部打入 Redis 中Redis 很可能就会挂掉那么我们如何解决这个问题呢?接下来我们就一起来探讨这个问题。在高并发的秒杀系统中如果采用 Redis 缓存数据则 Redis 缓存的并发处理能力是关键因为很多的前缀操作都需要访问 Redis。而异步削峰只是基本的操作关键还是要保证 Redis 的并发处理能力。解决这个问题的关键思想就是分而治之将商品库存分开放。暗度陈仓我们在 Redis 中存储秒杀商品的库存数量时可以将秒杀商品的库存进行“分割”存储来提升 Redis 的读写并发量。例如原来的秒杀商品的 id 为 10001库存为 1000 件在 Redis 中的存储为(10001, 1000)我们将原有的库存分割为 5 份则每份的库存为 200 件。此时我们在 Redis 中存储的信息为(10001_0, 200)(10001_1, 200)(10001_2, 200)(10001_3, 200)(10001_4, 200)。此时我们将库存进行分割后每个分割后的库存使用商品 id 加上一个数字标识来存储。这样在对存储商品库存的每个 Key 进行 Hash 运算时得出的 Hash 结果是不同的。这就说明存储商品库存的 Key 有很大概率不在 Redis 的同一个槽位中这就能够提升 Redis 处理请求的性能和并发量。分割库存后我们还需要在 Redis 中存储一份商品 id 和分割库存后的 Key 的映射关系此时映射关系的 Key 为商品的 id也就是 10001。Value 为分割库存后存储库存信息的 Key也就是 10001_010001_110001_210001_310001_4。在 Redis 中我们可以使用 List 来存储这些值。在真正处理库存信息时我们可以先从 Redis 中查询出秒杀商品对应的分割库存后的所有 Key同时使用 AtomicLong 来记录当前的请求数量。使用请求数量对从 Redis 中查询出的秒杀商品对应的分割库存后的所有 Key 的长度进行求模运算得出的结果为 01234。再在前面拼接上商品 id 就可以得出真正的库存缓存的 Key。此时就可以根据这个 Key 直接到 Redis 中获取相应的库存信息。移花接木在高并发业务场景中我们可以直接使用 Lua 脚本库(OpenResty)从负载均衡层直接访问缓存。这里我们思考一个场景如果在秒杀业务场景中秒杀的商品被瞬间抢购一空。此时用户再发起秒杀请求时如果系统由负载均衡层请求应用层的各个服务再由应用层的各个服务访问缓存和数据库。其实本质上已经没有任何意义了因为商品已经卖完了再通过系统的应用层进行层层校验已经没有太多意义了!!而应用层的并发访问量是以百为单位的这又在一定程度上会降低系统的并发度。为了解决这个问题此时我们可以在系统的负载均衡层取出用户发送请求时携带的用户 id商品 id 和秒杀活动 id 等信息直接通过 Lua 脚本等技术来访问缓存中的库存信息。如果秒杀商品的库存小于或者等于 0则直接返回用户商品已售完的提示信息而不用再经过应用层的层层校验了。针对这个架构我们可以参见本文中的电商系统的架构图(正文开始的第一张图)。写在最后最后附上并发编程需要掌握的核心技能知识图祝大家在学习并发编程时少走弯路。后记记住你比别人强的地方不是你做过多少年的 CRUD 工作而是你比别人掌握了更多深入的技能。不要总停留在 CRUD 的表面工作理解并掌握底层原理并熟悉源码实现并形成自己的抽象思维能力做到灵活运用才是你突破瓶颈脱颖而出的重要方向!你在刷抖音玩游戏的时候别人都在这里学习成长提升人与人最大的差距其实就是思维。你可能不信优秀的人总是在一起。。作者冰河技术