阅读:2929回复:0
javaweb 一次性返回页面太多数据造成页面卡顿 如何优化_阿里双十一结束了,程序员如何设计一个秒杀系统?
秒杀系统的关键点:
秒杀系统其实主要解决2个问题,一个是并发读,一个是并发写。整体概况为“稳、准、快” 1.高性能。 秒杀涉及大量的并发读和并发写,因此支持高并发访问这点非常关键。本文将从设计数据的动静分离方案、热点的发现与隔离、请求的削峰与分层过滤、服务端的极致优化这 4 个方面重点介绍。 2.一致性。 秒杀中商品减库存的实现方式同样关键。可想而知,有限数量的商品在同一时刻被很多倍的请求同时来减库存,减库存又分为“拍下减库存”“付款减库存”以及预扣等几种,在大并发更新的过程中都要保证数据的准确性,其难度可想而知。 3.高可用。 虽然介绍了很多极致的优化思路,但现实中总难免出现一些我们考虑不到的情况,所以要保证系统的高可用和正确性,我们还要设计一个 PlanB 来兜底,以便在最坏情况发生时仍然能够从容应对。 ———————————————— 1.设计秒杀系统时应该注意的5个架构原则 总结来说就是“4 要 1 不要” 数据要尽量少。 所谓“数据要尽量少”,请求的数据包括请求包体和返回包体,字段精简。不管是请求数据还是返回数据都需要服务器做处理,而服务器在写网络时通常都要做压缩和字符编码,这些都非常消耗 CPU,所以减少传输的数据量可以显著减少 CPU 的使用。数据库也容易成为一个瓶颈,所以和数据库打交道越少越好,数据越简单、越小则越好。 请求数要尽量少。 这里的请求数包括了页面依赖的 CSS/JavaScript、图片、加载这些文件都需要建立连接要做三次握手,另外,如果不同请求的域名不一样的话,还涉及这些域名的 DNS 解析,可能会耗时更久。所以,减少请求数可以显著减少以上这些因素导致的资源消耗。 路径要尽量短。 所谓“路径”,就是用户发出请求到返回数据这个过程中,需求经过的中间的节点数。所以缩短请求路径不仅可以增加可用性,同样可以有效提升性能(减少中间节点可以减少数据的序列化与反序列化),并减少延时(可以减少网络传输耗时)。要缩短访问路径有一种办法,就是多个相互强依赖的应用合并部署在一起,把远程过程调用(RPC)变成 JVM 内部之间的方法调用,也就是同一个服务同一个web容器。这里把应用合并部署在一起,是和分布式微服务并不是矛盾的,只是要从中取舍 依赖要尽量少。 所谓依赖,指的是要完成一次用户请求必须依赖的系统或者服务,这里的依赖指的是强依赖。比如说你要展示秒杀页面,而这个页面必须强依赖商品信息、用户信息,还有其他如优惠券、成交列表等这些对秒杀不是非要不可的信息(弱依赖),这些弱依赖在紧急情况下就可以去掉。防止强依赖被弱依赖拖垮,比如优惠券服务无法提供优惠券列表,导致拖垮支付服务是不行的 不要有单点。 单点是系统架构的大忌,单点意味着没有备份,风险不可控,设计分布式系统最重要的原则就是“消除单点”。避免单点关键点是避免将服务的状态和机器绑定,即服务无状态化,这样服务就可以在机器中随意移动。 ———————————————— 2.如何做好动静分离 URL 唯一化。 商品详情系统天然地就可以做到 URL 唯一化,每个商品都由 ID 来标识,那么 http://item.xxx.com/item.htm?id=xxxx 就可以作为唯一的 URL 标识。就以 URL 作为缓存的 Key。 分离浏览者相关的因素。 浏览者相关的因素包括是否已登录,以及登录身份等,这些相关因素我们可以单独拆分出来,通过动态请求来获取。 分离时间因素。 服务端输出的时间也通过动态请求获取。 异步化地域因素。 详情页面上与地域相关的因素做成异步方式获取,当然你也可以通过动态请求方式获取,只是这里通过异步获取更合适。 去掉 Cookie。 去掉 Cookie 并不是用户端收到的页面就不含 Cookie 了,而是说,在缓存的静态数据中不含有 Cookie。分离出动态内容之后,如何组织这些内容页就变得非常关键了。这里将这些信息 JSON 化(用 JSON 格式组织这些数据),以方便前端获取。 前面我们介绍里用缓存的方式来处理静态数据。而动态内容的处理通常有两种方案:ESI(Edge Side Includes)方案和 CSI(Client Side Include)方案。 ESI 方案(或者 SSI):即在 Web 代理服务器上做动态内容请求,并将请求插入到静态页面中,当用户拿到页面时已经是一个完整的页面了。这种方式对服务端性能有些影响,但是用户体验较好。 CSI 方案。即单独发起一个异步 JavaScript 请求,以向服务端获取动态内容。这种方式服务端性能更佳,但是用户端页面可能会延时,体验稍差。 动静分离的几种架构方案 前面我们通过改造把静态数据和动态数据做了分离,那么如何在系统架构上进一步对这些动态和静态数据重新组合,再完整地输出给用户根据架构上的复杂度,有 3 种方案可选: 实体机单机部署 虚拟机改为实体机,增大 Cache 容量,采用了一致性 Hash 分组的方式来提升命中率,将 Cache 分成若干组,是希望能达到命中率和访问热点的平衡。Hash 分组越少,缓存的命中率肯定就会越高,但短板是也会使单个商品集中在一个分组中,容易导致 Cache 被击穿。没有网络瓶颈,而且能使用大内存;既能提升命中率,又能减少 Gzip 压缩;优势很明显,但是一定程度上也造成了 CPU 的浪费,因为单个的 Java 进程很难用完整个实体机的 CPU。 统一 Cache 层 单独一个 Cache 层,减少应用接入时使用 Cache 的成本。统一 Cache 的方案易于维护,可以共享内存,最大化利用内存,不同系统之间的内存可以动态切换,从而能够有效应对各种攻击。但是也带来了其他一些问题,比如缓存更加集中,导致:Cache 层内部交换网络成为瓶颈;缓存服务器的网卡也会是瓶颈;机器少风险较大,挂掉一台就会影响很大一部分缓存数据。要解决上面这些问题,可以再对 Cache 做 Hash 分组,即一组 Cache 缓存的内容相同,这样能够避免热点数据过度集中导致新的瓶颈产生。 上 CDN 在将整个系统做动静分离后,我们自然会想到更进一步的方案,就是将 Cache 进一步前移到 CDN 上,因为 CDN 离用户最近,效果会更好。有以下几个问题需要解决。 靠近访问量比较集中的地区;离主站相对较远;节点到主站间的网络比较好,而且稳定;节点容量比较大,不会占用其他 CDN 太多的资源。节点不要太多。 除此之外,CDN 化部署方案还有以下几个特点: 把整个页面缓存在用户浏览器中; 如果强制刷新整个页面,也会请求 CDN; 实际有效请求,只是用户对“刷新抢宝”按钮的点击。 这样就把 90% 的静态数据缓存在了用户端或者 CDN 上,当真正秒杀时,用户只需要点击特殊的“刷新抢宝”按钮,而不需要刷新整个页面。这样,系统只是向服务端请求很少的有效数据,而不需要重复请求大量的静态数据。 ———————————————— 版权声明:本文为CSDN博主「寂夜迷心」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/weixin_33724428/article/details/112084773 |
|