在网上购物秒抢某个商品,比如说小米手机,这对我们来说都不陌生。这些看似很简单的东西从技术的角度来说对于Web系统是一个巨大的考验,一个Web系统在很短时间内收到很多请求时,系统的优化和稳定至关重要。今天就由小编为大家详细解释一下这些问题。
1、大规模并发带来的挑战
比如说5w每秒的高并发秒杀功能,在这个过程中,整个Web系统遇到了很多的问题和挑战。如果Web系统不做针对性的优化,会轻而易举地陷入到异常状态。一起来讨论下优化的思路和方法。
1.1、请求接口的合理设计
一个抢购页面,通常分为2个部分,一个是静态的HTML等内容,另一个就是Web后台请求接口。通常静态HTML等内容,是通过CDN的部署,一般压力不大,核心瓶颈实际上在后台请求接口上。这个后端接口,必须能够支持高并发请求,同时必须尽可能“快”,在最短的时间里返回用户的请求结果。为了实现尽可能快这一点,接口的后端存储使用内存级别的操作会更好一点,仍然直接面向MySQL之类数据库的存储是不合适的,如果有这种复杂业务的需求,都建议采用异步写入。
1.2、高并发的挑战
衡量一个Web系统的吞吐率的指标是QPS(Query Per Second,每秒处理请求数),解决每秒数万次的高并发场景,这个指标非常关键。假设处理一个业务请求平均响应时间为100ms,同时系统内有20台Apache的Web服务器,配置MaxClients为500个(表示Apache的最大连接数目)。那么Web系统的理论峰值QPS为(理想化的计算方式):20*500/0.1 = 100000 (10万QPS) ,系统似乎很强大,1秒钟可以处理完10万的请求,实际情况当然没有这么理想。在高并发的实际场景下,机器都处于高负载的状态,在这个时候平均响应时间会被大大增加。就Web服务器而言,Apache打开了越多的连接进程,CPU需要处理的上下文切换也越多,额外增加了CPU的消耗,然后就直接导致平均响应时间增加。因此上述的MaxClient数目,要根据CPU、内存等硬件因素综合考虑,绝对不是越多越好。可以通过Apache自带的abench来测试一下,取一个合适的值。然后,我们选择内存操作级别的存储的Redis,在高并发的状态下,存储的响应时间至关重要,不考虑网络带宽和负载均衡问题。假设系统,在5w/s的高并发状态下,平均响应时间从100ms变为250ms(实际情况,甚至更多):20*500/0.25 = 40000 (4万QPS)于是系统剩下了4w的QPS,面对5w每秒的请求,中间相差了1w。 举个通俗例子说明,收费站1秒钟来5部车,每秒通过5部车,收费站运作正常。突然这个收费站1秒钟只能通过4部车,车流量仍然依旧,结果必定出现大塞车。(5条车道忽然变成4条车道的感觉)同理某一个秒内,20*500个可用连接进程都在满负荷工作中,却仍然有1万个新来请求,没有连接进程可用,系统陷入到异常状态也是预期之内。其实在正常的非高并发的业务场景中,也有类似的情况出现,某个业务请求接口出现问题,响应时间极慢,将整个Web请求响应时间拉得很长,逐渐将Web服务器的可用连接数占满,影响其他正常的业务请求,无连接进程可用。更严重的是用户的行为,系统越是不可用,用户的点击越频繁,恶性循环最终导致“雪崩”(其中一台Web机器挂了,导致流量分散到其他正常工作的机器上,再导致正常的机器也挂,然后恶性循环),将整个Web系统拖垮。
1.3、重启与过载保护
如果系统发生“雪崩”,贸然重启服务,是无法解决问题的。这种情况最好在入口层将流量拒绝,然后再将重启,如果是redis/memcache这种服务也挂了,重启的时候需要注意“预热”,并且很可能需要比较长的时间。秒杀和抢购的场景,流量往往是超乎系统的准备和想象的。这个时候过载保护是必要的。如果检测到系统满负载状态,拒绝请求也是一种保护措施。在前端设置过滤是最简单的方式,但是,这种做法是会被客户骂的,更合适的解决方案是将过载保护设置在CGI入口层,快速将客户的直接请求返回。