Sanno限时秒杀抢票系统
亮点:在高并发情况下的秒杀优化,我们知道当并发数达到一定量的时候,会对数据库服务器带来很大的压力,那么如何缓解这些压力以及提高并发的QPS就是整个项目的重点。(不断的提高QPS)。
亮点3个:
1.利用缓存减少数据库的压力,以及读取缓存的速度远远快于数据库(网络时延+IO)
2.页面静态化技术加快用户访问速度,提高QPS,异步下单增强用户体验,以及内存标记减少Redis的访问。
3.安全性优化:双重md5密码校验,秒杀接口地址的隐藏,接口限流防刷,数学公式验证码。
整个的提升了系统的安全性能,
在高并发量的前提下,一台服务器都是无法承担如此大的并发访问的。我们知道淘宝双11QPS能达到上千万,所以一台服务器的访问量最少都需要上万,所以需要集群服务器才能实现一项高并发业务。
缓解数据库压力:
1.本项目大量的利用了缓存技术,包括用户信息缓存(分布式session),商品信息的缓存,商品库存缓存,订单的缓存,减少了对数据库服务器的访问。
用户信息缓存引出:分布式session.
2.分布式session
我们知道当服务器集群的时候,若用户第一个请求在第一台服务器上,第二个请求在其他服务器上,会出现session的丢失的情况,丢失用户信息。而且在这种高并发场景下,一定是很多服务器同步工作,所以如何解决session分布式的问题是一个重点。
本项目采用:利用redis缓存的方法,另外布置一个Redis服务器专门用于存放用户的session信息。这样就不会出现用户session丢失的情况。(每次需要session,从缓存中取即可)
这种方式的优点:相对其他的分布式方式,
1.服务器文件同步(不建议使用,这样会造成文件重复,资源浪费)
2.session存数据库(不建议用,会加大数据库压力)
3.使用cookie(不建议用,cookie不太安全)
对于集群中机器数多、网络环境复杂的情况有很好的处理效果。
大量的缓存引用也出现了一个问题,如何识别不同模块中的缓存(key值重复,如何辨别是不同模块的key)。 引出:通用缓存key封装
3.通用缓存key封装
利用一个抽象类,定义BaseKey(前缀),定义了缓存的String prefix(前缀) 以及缓存的过期时间。让不同模块继承它。
这样每次存入一个模块的缓存的时候,加上这个缓存特定的前缀,以及可以统一制定不同的过期时间。
4.页面静态化以及前后端分离
页面静态化的主要目的是为了加快页面的加载速度。做法:将订票的详情页面做成静态HTML,放在CDN(减少了服务端的压力)上做为静态数据发送给用户端,而数据信息通过前端ajax 异步发送请求来获取。只获取动态数据信息部分,加载速度可以达到全部渲染的2倍。
难点:
1.大量的使用了缓存,那么就存在缓存的过期时间控制以及缓存击穿以及缓存雪崩等问题?
解决:首先针对不同的缓存设置不同的过期时间,比如session缓存,在userKey这个前缀中,设置是30分钟过期,并且加入一层再登陆增加缓存时间的机制。这样每次取session,都会延长30分钟,相对来说,就减少了缓存过期的几率。
针对热点数据,比如演唱会票这种票详情信息,热点商品由于考虑到是一般抢票10分钟内几乎抢完,于是就设置为10分钟的缓存。
针对热点数据的缓存击穿问题,万一一波一波的抢票,(火车票)这种,某个时间点万一大量并发,刚好我的这个票缓存时间过了,去访问数据库。对于这种热点数据,我将过期时间一起存入缓存中,取出来的时候,比对一下过期时间和当前时间,少于1分钟,我就更新一下缓存,防止他过期。
2.大量的使用缓存,对于缓存服务器,也有很大的压力,有时候Redis 压力比mysql还要大很多,思考如何减少Redis的访问?
一般抢票,票的数量也少,大概1000张左右,但是并发量可能在几万。
在Redis预减库存的时候,内存中维护一个isOvermap作为一个标记,当没有库存的时候,将其置为true。每次抢票业务 访问Redis之前,查一下map,true说明没有库存,就直接返回No_stock。
3.高并发的时候,业务来不及同步处理,Redis压力,数据库有时候会有大量的insert 和update 操作,甚至请求堆积过多的时候,to many connections?
想到了消息队列,用来异步处理请求。每次请求过来,先不去处理请求,而是放入消息队列,然后在后台布置一个监听器,分别监听不同业务的消息队列,有消息来的时候,在进行秒杀抢票操作。这样防止多个请求同时操作的时候,数据库连接过多的异常。
4.为了在前端就限制同一时间的高并发,我也想到了一些前端就限制掉一些用户的做法。
数学公式验证码
转载自原文链接, 如需删除请联系管理员。
原文链接:项目的亮点和难点,转载请注明来源!