高并发热点/单点数据_性能问题解决方案

来源:互联网 发布:快速排序的算法 编辑:程序博客网 时间:2024/05/01 05:25

热点单点数据问题由于其独有的高访问特性,在性能上一直都一大难题,IT界的大牛们也一直在寻求一种更为优化的解决方案!其中也不乏很多优秀的解决方案,但随着业务的不断攀升和互联网的高速发展,也就显得捉襟见肘,可见对此探索的重要性!

      最近项目中也遇到了此瓶颈,请容我将前因后果以及我自己设想的粗陋方案娓娓道来,欢迎大神们拍砖,在下感激不尽!

      前段时间接了一个双11的活动,业务逻辑:用户购买某一类商品后,活动期间的4个整点在活动页点击按钮领取支付宝红包,每个时段奖品数量有限,先到先得。听着很简单,可是活动开始时,异常火热,流量超过了我们的预估,本来是分时段领取奖品,结果演变为了秒杀。

      当时每个整点的QPS瞬间飙高,响应时间RT短时间内居高不下,但是整个Check下来应用全部机器的负载都非常正常,后来全面查找原因,才找到问题的根源,是由于每个时段更新数据库同一条奖品导致超时!

      整点开抢后瞬时巨量的请求同时涌入,即使我们Apache端做过初步限流,应用也做了信号量的控制,而且加上分布式缓存的使用,减缓了相当大的压力,整个业务逻辑校验阶段运作良好,但是系统的瓶颈就转移到其他环节:减奖品库存!因为我们每个时段只有一个奖品A,每次减库存都是update奖品A中的奖品余额字段!大量符合发奖要求的用户请求瞬时涌入数据库去更新此条记录,update锁行,导致后面的请求全部排队等待,等前面一个update完成释放行锁后才能处理下一个请求,大量请求等待,占用了数据库的连接!一旦数据库同一时间片内的连接数被打满,就会导致这个时间片内其他后来的全部请求因拿不到连接而超时,导致访问此数据库的其他环节也出现问题!所以RT就会异常飙高!

 

      根据木桶理论,我们后续肯定必须得优化这个最短板,将这个瓶颈解决!针对这样的情况,我们这边出了两套方案:1、强依赖分布式缓存达到减库存的目的;2、热点/单点数据拆分,弱依赖分布式缓存,采用分散热点的方式减库存.下面请允许我详细分解下这两套方案,也希望大家提各种建设性意见!

 

      一、强依赖分布式缓存

      应用中使用分布式缓存来存储当前时间段的奖品余额,有用户中奖则将此缓存中的余额减一,不需要查询和实时更新数据库,而是每隔自定义的一段时间将缓存中的余额异步更新至数据库中。

      优点:这种方式完全依赖于缓存,读写速度快,不需要实时更新数据库,降低了数据库相当大的压力;

      缺点:缓存不是100%稳定,很容易丢,即使采用持久化的缓存,在高并发下有时也会出问题;一旦丢失数据,这样

               就导致数据库记录的奖品余额比实际真实存在的奖品余额要多,这个时候读数据库,就会导致奖品多发,也就

               是所谓的超卖!

 

      二、热点/单点数据拆分,弱依赖分布式缓存

      某时段的一个奖品拆分为多条后,如何能保证先到先得的业务需求将奖品准确发完,这里就引入分布式缓存作为辅助,缓存不完全稳定没关系,只是借助其在多条奖品中进行准确分发,当数据库所有奖品都有余额的情况时,能减少查询操作!只有当某一条奖品余额为0时缓存中的数据才会失效,这时才需要查询一次数据库!

      步骤:

      1、 同个时段的奖品拆为多份(比如10份),加行号N区分(1~10),奖1~10的数值存入数组M中;

      2、 根据行号1~10 ,查询分布式缓存中是否存在各行奖品对应的记录(缓存中存放没余额的奖品行);

            是: 将存在的行号存入数组P;

            否: 数组P值为NULL;

      3、 数组M-数组P=数组R;

      4、 判断数组R是否为空 ;

            是: 没有奖品余额,返回未中奖!

            否: 在数组R中随机一个行号L;

      5、 更新数据库表,将L行奖品余额减一;

            更新成功: 减奖品库存成功,直接返回发奖成功!

            更新失败: 极大可能原因是由于没有奖品导致

                         5.1、 查询数据库中这10个奖品List(全量list);

                         5.2、 将List中没有奖品余额的行同步至对应的缓存(第2 步),并判断List中是否所有奖品行余额全为0;

                                 是: 无奖品,返回未中奖;

                                 否: List中选择一个有余额的奖品,最好是余额最多的,将行号存入L,执行第5 步;

 

           流程图:

 


           优点:此方案不会发生奖品多发的情况,将单行数据分拆为多行,分散了热点,同样可以减轻数据库更新时超负荷长链等待导致的连接被等待用户占用而后续请求超时,可以通过拆分为适量的行来解决单点热点数据带来的性能问题!

           缺点:此方案需要做业务拆解,增加了业务的复杂性!奖品拆分为多条,数据量太大时,不是很便捷,可能会带来数据库性能问题,但这个可以通过分库分表,旧数据迁移备份的方式解决!在奖品快被抽完的那么几微秒的用户可能存在误杀!

           这就是目前针对数据库的单点热点问题,我个人的一些见解,也只是初步构想,还没有进入完全的实践中,还希望各位大神多指点一二!

0 0
原创粉丝点击