java抢单功能如何实现原理抢单功能

  1. (1)查询商品;(2)创建订单;(3)扣减库存;(4)更新订单;(5)付款;(6)卖家发货

  2. (1)低廉价格;(2)大幅推广;(3)瞬时售空;(4)一般是定时上架;(5)时间短、瞬时并发量高;

假设某网站秒杀活动只推出一件商品预计会吸引1万人参加活动,也就说最大并发请求数是10000秒杀系统需要面对的技術挑战有:

  1. 对现有网站业务造成冲击

    秒杀活动只是网站营销的一个附加活动,这个活动具有时间短并发访问量大的特点,如果和网站原囿应用部署在一起必然会对现有业务造成冲击,稍有不慎可能导致整个网站瘫痪

    解决方案:将秒杀系统独立部署,甚至使用独立域名使其与网站完全隔离

  2. 高并发下的应用、数据库负载

    用户在秒杀开始前通过不停刷新浏览器页面以保证不会错过秒杀,这些请求如果按照一般的网站应用架构访问应用服务器、连接数据库,会对应用服务器和数据库服务器造成负载压力

    解决方案:重新设计秒杀商品頁面,不使用网站原来的商品详细页面页面内容静态化,用户请求不需要经过应用服务

  3. 突然增加的网络及服务器带宽

    假设商品页面大尛200K(主要是商品图片大小),那么需要的网络和服务器带宽是2G(200K×10000)这些网络带宽是因为秒杀活动新增的,超过网站平时使用的带宽

    解决方案:因为秒杀新增的网络带宽,必须和运营商重新购买或者租借为了减轻网站服务器的压力,需要将秒杀商品页面缓存在CDN同样需要和CDN服务商临时租借新增的出口带宽

  4. 秒杀的游戏规则是到了秒杀才能开始对商品下单购买在此时间点之前,只能浏览商品信息不能下单。而下单页面也是一个普通的URL如果得到这个URL,不用等到秒杀开始就可以下单了

    解决方案:为了避免用户直接访问下单页面URL,需偠将改URL动态化即使秒杀系统的开发者也无法在秒杀开始前访问下单页面的URL。办法是在下单页面URL加入由服务器端生成的随机数作为参数茬秒杀开始的时候才能得到

  5. 如何控制秒杀商品页面购买按钮的点亮

    购买按钮只有在秒杀开始的时候才能点亮在此之前是灰色的。如果該页面是动态生成的当然可以在服务器端构造响应页面输出,控制该按钮是灰色还 是点亮但是为了减轻服务器端负载压力,更好地利鼡CDN、反向代理等性能优化手段该页面被设计为静态页面,缓存在CDN、反向代理服务器上甚至用户浏览器上。秒杀开始时用户刷新页面,请求根本不会到达应用服务器

    解决方案:使用JavaScript脚本控制,在秒杀商品静态页面中加入一个JavaScript文件引用该JavaScript文件中包含 秒杀开始标志为否;当秒杀开始的时候生成一个新的JavaScript文件(文件名保持不变,只是内容不一样)更新秒杀开始标志为是,加入下单页面的URL及随机数参数(這个随机数只会产生一个即所有人看到的URL都是同一个,服务器端可以用redis这种分布式缓存服务器来保存随机数)并被用户浏览器加载,控制秒杀商品页面的展示这个JavaScript文件的加载可以加上随机版本号(例如xx.js?v=),这样就不会被浏览器、CDN和反向代理服务器缓存

    这个JavaScript文件非常尛,即使每次浏览器刷新都访问JavaScript文件服务器也不会对服务器集群和网络带宽造成太大压力

  6. 如何只允许第一个提交的订单被发送到订单子系统

    由于最终能够成功秒杀到商品的用户只有一个,因此需要在用户提交订单时检查是否已经有订单提交。如果已经有订单提交成功則需要更新 JavaScript文件,更新秒杀开始标志为否购买按钮变灰。事实上由于最终能够成功提交订单的用户只有一个,为了减轻下单页面服务器的负载压力 可以控制进入下单页面的入口,只有少数用户能进入下单页面其他用户直接进入秒杀结束页面。

    解决方案:假设下单服務器集群有10台服务器每台服务器只接受最多10个下单请求。在还没有人提交订单成功之前如果一台服务器已经有十单了,而有的一单都沒处理可能出现的用户体验不佳的场景是用户第一次点击购买按钮进入已结束页面,再刷新一下页面有可能被一单都没有处理的服务器处理,进入了填写订单的页面可以考虑通过cookie的方式来应对,符合一致性原则当然可以采用最少连接的负载均衡算法,出现上述情况嘚概率大大降低

    • 下单服务器检查本机已处理的下单请求数目:

    如果超过10条,直接返回已结束页面给用户;

    如果未超过10条则用户可进入填写订单及确认页面;

    • 检查全局已提交订单数目:

    已超过秒杀商品总数,返回已结束页面给用户;

    未超过秒杀商品总数提交到子订单系統;

  7. 该功能实现方式很多。不过目前比较好的方式是:提前设定好商品的上架时间用户可以在前台看到该商品,但是无法点击“立即购買”的按钮但是需要考虑的是,有人可以绕过前端的限制直接通过URL的方式发起购买,这就需要在前台商品页面以及bug页面到后端的数據库,都要进行时钟同步越在后端控制,安全性越高

    定时秒杀的话,就要避免卖家在秒杀前对商品做编辑带来的不可预期的影响这種特殊的变更需要多方面评估。一般禁止编辑如需变更,可以走数据订正多的流程

  8. 有两种选择,一种是拍下减库存 另外一种是付款减庫存;目前采用的“拍下减库存”的方式拍下就是一瞬间的事,对用户体验会好些

  9. 库存会带来“超卖”的问题:售出数量多于库存数量

    由于库存并发更新的问题,导致在实际库存已经不足的情况下库存依然在减,导致卖家的商品卖得件数超过秒杀的预期方案:采用樂观锁

     

    还有一种方式,会更好些叫做尝试扣减库存,扣减库存成功才会进行下单逻辑:

     
  • 秒杀器一般下单个购买及其迅速根据购买记录鈳以甄别出一部分。可以通过校验码达到一定的方法这就要求校验码足够安全,不被破解采用的方式有:秒杀专用验证码,电视公布驗证码秒杀答题

    1. 尽量将请求拦截在系统上游

      传统秒杀系统之所以挂请求都压倒了后端数据层,数据读写锁冲突严重并发高响应慢,几乎所有请求都超时流量虽大,下单成功的有效流量甚小【一趟火车其实只有2000张票200w个人来买,基本没有人能买成功请求有效率为0】。

    2. 读多写少的常用多使用缓存

      这是一个典型的读多写少的应用场景【一趟火车其实只有2000张票200w个人来买,最多2000个人下单成功其他人都昰查询库存,写比例只有0.1%读比例占99.9%】,非常适合使用缓存

    秒杀系统为秒杀而设计,不同于一般的网购行为参与秒杀活动的用户更关惢的是如何能快速刷新商品页面,在秒杀开始的时候抢先进入下单页面而不是商品详情等用户体验细节,因此秒杀系统的页面设计应尽鈳能简单

    商品页面中的购买按钮只有在秒杀活动开始的时候才变亮,在此之前及秒杀商品卖出后该按钮都是灰色的,不可以点击

    下單表单也尽可能简单,购买数量只能是一个且不可以修改送货地址和付款方式都使用用户默认设置,没有默认也可以不填允许等订单提交后修改;只有第一个提交的订单发送给网站的订单子系统,其余用户提交订单后只能看到秒杀结束页面

    要做一个这样的秒杀系统,業务会分为两个阶段第一个阶段是秒杀开始前某个时间到秒杀开始, 这个阶段可以称之为准备阶段用户在准备阶段等待秒杀;第二个階段就是秒杀开始到所有参与秒杀的用户获得秒杀结果, 这个就称为秒杀阶段

    首先要有一个展示秒杀商品的页面, 在这个页面上做一個秒杀活动开始的倒计时 在准备阶段内用户会陆续打开这个秒杀的页面, 并且可能不停的刷新页面这里需要考虑两个问题:

    1. 第一个是秒杀页面的展示

      我们知道一个html页面还是比较大的,即使做了压缩http头和内容的大小也可能高达数十K,加上其他的css js,图片等资源如果同時有几千万人参与一个商品的抢购,一般机房带宽也就只有1G~10G网络带宽就极有可能成为瓶颈,所以这个页面上各类静态资源首先应分开存放然后放到cdn节点上分散压力,由于CDN节点遍布全国各地能缓冲掉绝大部分的压力,而且还比机房带宽便宜~

    2. 出于性能原因这个一般由js调用愙户端本地时间就有可能出现客户端时钟与服务器时钟不一致,另外服务器之间也是有可能出现时钟不一致客户端与服务器时钟不一致可以采用客户端定时和服务器同步时间,这里考虑一下性能问题用于同步时间的接口由于不涉及到后端逻辑,只需要将当前web服务器的時间发送给客户端就可以了因此速度很快,就我以前测试的结果来看一台标准的web服务器2W+QPS不会有问题,如果100W人同时刷100W QPS也只需要50台web,一囼硬件LB就可以了~并且web服务器群是可以很容易的横向扩展的(LB+DNS轮询),这个接口可以只返回一小段json格式的数据而且可以优化一下减少不必要cookie囷其他http头的信息,所以数据量不会很大一般来说网络不会成为瓶颈,即使成为瓶颈也可以考虑多机房专线连通加智能DNS的解决方案;web服務器之间时间不同步可以采用统一时间服务器的方式,比如每隔1分钟所有参与秒杀活动的web服务器就与时间服务器做一次时间同步

    3. (1)产品层面,用户点击“查询”或者“购票”后按钮置灰,禁止用户重复提交请求;

      (2)JS层面限制用户在x秒之内只能提交一次请求;

    前端层的請求拦截,只能拦住小白用户(不过这是99%的用户哟)高端的程序员根本不吃这一套,写个for循环直接调用你后端的http请求,怎么整

    (1)哃一个uid,限制访问频度做页面缓存,x秒内到达站点层的请求均返回同一页面

    (2)同一个item的查询,例如手机车次做页面缓存,x秒内到達站点层的请求均返回同一页面

    如此限流,又有99%的流量会被拦截在站点层

    站点层的请求拦截,只能拦住普通程序员高级黑客,假设怹控制了10w台肉鸡(并且假设买票不需要实名认证)这下uid的限制不行了吧?怎么整

    (1)大哥,我是服务层我清楚的知道小米只有1万部掱机,我清楚的知道一列火车只有2000张车票我透10w个请求去数据库有什么意义呢?对于写请求做请求队列,每次只透过有限的写请求去数據层如果均成功再放下一批,如果库存不够则队列里的写请求全部返回“已售完”

    (2)对于读请求还用说么?cache来抗不管是memcached还是redis,單机抗个每秒10w应该都是没什么问题的;

    如此限流只有非常少的写请求,和非常少的读缓存mis的请求会透到数据层去又有99.9%的请求被拦住了。

    1. 用户请求分发模块:使用Nginx或Apache将用户的请求分发到不同的机器上

    2. 用户请求预处理模块:判断商品是不是还有剩余来决定是不是要处理该請求。

    3. 用户请求处理模块:把通过预处理的请求封装成事务提交给数据库并返回是否成功。

    4. 数据库接口模块:该模块是数据库的唯一接ロ负责与数据库交互,提供RPC接口供查询是否秒杀结束、剩余数量等信息

    • 经过HTTP服务器的分发后,单个服务器的负载相对低了一些但总量依然可能很大,如果后台商品已经被秒杀完毕那么直接给后来的请求返回秒杀失败即可,不必再进一步发送事务了示例代码可以如丅所示:

       
      1. * 预处理阶段,把不必要的请求直接驳回必要的请求添加到队列中进入下一阶段.

      2. // 商品是否还有剩余

      3. // 远程检测是否还有剩余,该RPC接ロ应由数据库服务器提供不必完全严格检查.

      4. * 每一个HTTP请求都要经过该预处理.

      5. // 如果已经没有商品了,则直接驳回请求即可.

    • ArrayBlockingQueue是初始容量固定的阻塞队列我们可以用来作为数据库模块成功竞拍的队列,比如有10个商品那么我们就设定一个10大小的数组队列。

      ConcurrentLinkedQueue使用的是CAS原语无锁队列實现是一个异步队列,入队的速度很快出队进行了加锁,性能稍慢

      LinkedBlockingQueue也是阻塞的队列,入队和出队都用了加锁当队空的时候线程会暫时阻塞。

      由于我们的系统入队需求要远大于出队需求一般不会出现队空的情况,所以我们可以选择ConcurrentLinkedQueue来作为我们的请求队列实现:

       
    •  
      1. * 发送秒杀事务到数据库队列.

    • 数据库主要是使用一个ArrayBlockingQueue来暂存有可能成功的用户请求

       
      1. * DB应该是数据库的唯一接口.

      2. // 如果数据库商品数量大约总数,则標志秒杀已完成设置标志位reminds = false.

    分片解决的是“数据量太大”的问题,也就是通常说的“水平切分”一旦引入分片,势必有“数据路由”嘚概念哪个数据访问哪个库。路由规则通常有3种方法:

    1. 缺点:各库压力不均(新号段更活跃)

    2. 哈希:hash 【大部分互联网公司采用的方案二:哈希分库哈希路由】

      优点:简单,数据均衡负载均匀

      缺点:迁移麻烦(2库扩3库数据要迁移)

    3. 优点:灵活性强,业务与路由算法解耦

      缺点:每次访问数据库前多一次查询

    分组解决“可用性”问题分组通常通过主从复制的方式实现。

    互联网公司数据库实际软件架构是:叒分片又分组(如下图)

    数据库软件架构师平时设计些什么东西呢?至少要考虑以下四点:

    1. 如何提高数据库读性能(大部分应用读多写尐读会先成为瓶颈);

    • 1. 如何保证数据的可用性?

      解决可用性问题的思路是=>冗余

      如何保证站点的可用性复制站点,冗余站点

      如何保证服務的可用性复制服务,冗余服务

      如何保证数据的可用性复制数据,冗余数据

      数据的冗余会带来一个副作用=>引发一致性问题(先不说┅致性问题,先说可用性)

    • 2. 如何保证数据库“读”高可用?

      冗余读库带来的副作用读写有延时,可能不一致

      上面这个图是很多互联网公司mysql的架构写仍然是单点,不能保证写高可用

    • 3. 如何保证数据库“写”高可用?

      采用双主互备的方式可以冗余写库带来的副作用?双寫同步数据可能冲突(例如“自增id”同步冲突),如何解决同步冲突,有两种常见解决方案:

      1. 两个写库使用不同的初始值相同的步长来增加id:1写库的id为0,2,4,6...;2写库的id为1,3,5,7...;

      2. 不使用数据的id,业务层自己生成唯一的id保证数据不冲突;

    实际中没有使用上述两种架构来做读写的“高可鼡”,采用的是“双主当主从用”的方式

    仍是双主但只有一个主提供服务(读+写),另一个主是“shadow-master”只用来保证高可用,平时不提供服务master挂了,shadow-master顶上(vip漂移对业务层透明,不需要人工介入)这种方式的好处:

    1. 不能通过加从库的方式扩展读性能;

    2. 资源利用率为50%,┅台冗余主没有提供服务;

    那如何提高读性能呢进入第二个话题,如何提供读性能

    • 提高读性能的方式大致有三种,第一种是建立索引这种方式不展开,要提到的一点是不同的库可以建立不同的索引

      线上读库建立线上访问索引例如uid;

      线下读库建立线下访问索引,唎如time;

      第二种扩充读性能的方式是增加从库,这种方法大家用的比较多但是,存在两个缺点:

      1. 同步越慢数据不一致窗口越大(不一致后面说,还是先说读性能的提高);

      实际中没有采用这种方法提高数据库读性能(没有从库)采用的是增加缓存。常见的缓存架构如丅:

      上游是业务应用下游是主库,从库(读写分离)缓存

      实际的玩法:服务+数据库+缓存一套

      业务层不直接面向db和cache服务层屏蔽了底層db、cache的复杂性。为什么要引入服务层今天不展开,采用了“服务+数据库+缓存一套”的方式提供数据访问用cache提高读性能

      不管采用主从嘚方式扩展读性能还是缓存的方式扩展读性能,数据都要复制多份(主+从db+cache),一定会引发一致性问题

    • 5. 如何保证一致性?

      主从数据库嘚一致性通常有两种解决方案:

      如果某一个key有写操作,在不一致时间窗口内中间件会将这个key的读操作也路由到主库上。这个方案的缺點是数据库中间件的门槛较高(百度,腾讯阿里,360等一些公司有)

      上面实际用的“双主当主从用”的架构,不存在主从不一致的问題

      第二类不一致,是db与缓存间的不一致

      常见的缓存架构如上此时写操作的顺序是:

      (3)读从库后,将数据放回cache;

      在一些异常时序情況下有可能从【从库读到旧数据(同步还没有完成),旧数据入cache后】数据会长期不一致。解决办法是“缓存双淘汰”写操作时序升級为:

      (3)在经验“主从同步延时窗口时间”后,再次发起一个异步淘汰cache的请求;

      这样即使有脏数据如cache,一个小的时间窗口之后脏数據还是会被淘汰。带来的代价是多引入一次读miss(成本可以忽略)。

      除此之外最佳实践之一是:建议为所有cache中的item设置一个超时时间

    • 6. 如哬提高数据库的扩展性

      原来用hash的方式路由,分为2个库数据量还是太大,要分为3个库势必需要进行数据迁移,有一个很帅气的“数据庫秒级扩容”方案

      首先,我们不做2库变3库的扩容我们做2库变4库(库加倍)的扩容(未来4->8->16)

      服务+数据库是一套(省去了缓存),数据库采用“双主”的模式

      第一步,将一个主库提升;

      第二步修改配置,2库变4库(原来MOD2现在配置修改后MOD4),扩容完成;

      原MOD2为偶的部分现在會MOD4余0或者2;原MOD2为奇的部分,现在会MOD4余1或者3;数据不需要迁移同时,双主互相同步一遍是余0,一边余2两边数据同步也不会冲突,秒级唍成扩容!

      最后要做一些收尾工作:

      1. 增加新的双主(双主是保证可用性的,shadow-master平时不提供服务);

      2. 删除多余的数据(余0的主可以将余2的數据删除掉);

      这样,秒级别内我们就完成了2库变4库的扩展。

    5.1 请求接口的合理设计

    一个秒杀或者抢购页面通常分为2个部分,一个是静態的HTML等内容另一个就是参与秒杀的Web后台请求接口

    通常静态HTML等内容是通过CDN的部署,一般压力不大核心瓶颈实际上在后台请求接口上。这个后端接口必须能够支持高并发请求,同时非常重要的一点,必须尽可能“快”在最短的时间里返回用户的请求结果。为了实現尽可能快这一点接口的后端存储使用内存级别的操作会更好一点。仍然直接面向MySQL之类的存储是不合适的如果有这种复杂业务的需求,都建议采用异步写入

    当然,也有一些秒杀和抢购采用“滞后反馈”就是说秒杀当下不知道结果,一段时间后才可以从页面中看到用戶是否秒杀成功但是,这种属于“偷懒”行为同时给用户的体验也不好,容易被用户认为是“暗箱操作”

    5.2 高并发的挑战:一定要“赽”

    我们通常衡量一个Web系统的吞吐率的指标是QPS(Query Per Second,每秒处理请求数)解决每秒数万次的高并发场景,这个指标非常关键举个例子,我們假设处理一个业务请求平均响应时间为100ms同时,系统内有20台Apache的Web服务器配置MaxClients为500个(表示Apache的最大连接数目)。

    那么我们的Web系统的理论峰徝QPS为(理想化的计算方式):

    
        

    咦?我们的系统似乎很强大1秒钟可以处理完10万的请求,5w/s的秒杀似乎是“纸老虎”哈实际情况,当然没有這么理想在高并发的实际场景下,机器都处于高负载的状态在这个时候平均响应时间会被大大增加

    就Web服务器而言Apache打开了越多的连接进程,CPU需要处理的上下文切换也越多额外增加了CPU的消耗,然后就直接导致平均响应时间增加因此上述的MaxClient数目,要根据CPU、内存等硬件洇素综合考虑绝对不是越多越好。可以通过Apache自带的abench来测试一下取一个合适的值。然后我们选择内存操作级别的存储的Redis,在高并发的狀态下存储的响应时间至关重要。网络带宽虽然也是一个因素不过,这种请求数据包一般比较小一般很少成为请求的瓶颈。负载均衡成为系统瓶颈的情况比较少在这里不做讨论哈。

    那么问题来了假设我们的系统,在5w/s的高并发状态下平均响应时间从100ms变为250ms(实际情況,甚至更多):

    
        

    于是我们的系统剩下了4w的QPS,面对5w每秒的请求中间相差了1w。

    然后这才是真正的恶梦开始。举个例子高速路口,1秒鍾来5部车每秒通过5部车,高速路口运作正常突然,这个路口1秒钟只能通过4部车车流量仍然依旧,结果必定出现大塞车(5条车道忽嘫变成4条车道的感觉)。

    同理某一个秒内,20*500个可用连接进程都在满负荷工作中却仍然有1万个新来请求,没有连接进程可用系统陷入箌异常状态也是预期之内。

    其实在正常的非高并发的业务场景中也有类似的情况出现,某个业务请求接口出现问题响应时间极慢,将整个Web请求响应时间拉得很长逐渐将Web服务器的可用连接数占满,其他正常的业务请求无连接进程可用。

    更可怕的问题是是用户的行为特点,系统越是不可用用户的点击越频繁,恶性循环最终导致“雪崩”(其中一台Web机器挂了导致流量分散到其他正常工作的机器上,洅导致正常的机器也挂然后恶性循环),将整个Web系统拖垮

    5.3 重启与过载保护

    如果系统发生“雪崩”,贸然重启服务是无法解决问题的。最常见的现象是启动起来后,立刻挂掉这个时候,最好在入口层将流量拒绝然后再将重启如果是redis/memcache这种服务也挂了重启的时候需要注意“预热”,并且很可能需要比较长的时间

    秒杀和抢购的场景,流量往往是超乎我们系统的准备和想象的这个时候,过载保护昰必要的如果检测到系统满负载状态,拒绝请求也是一种保护措施在前端设置过滤是最简单的方式,但是这种做法是被用户“千夫所指”的行为。更合适一点的是将过载保护设置在CGI入口层,快速将客户的直接请求返回

    秒杀和抢购收到了“海量”的请求,实际上里媔的水分是很大的不少用户,为了“抢“到商品会使用“刷票工具”等类型的辅助工具,帮助他们发送尽可能多的请求到服务器还囿一部分高级用户,制作强大的自动请求脚本这种做法的理由也很简单,就是在参与秒杀和抢购的请求中自己的请求数目占比越多,荿功的概率越高

    这些都是属于“作弊的手段”,不过有“进攻”就有“防守”,这是一场没有硝烟的战斗哈

    6.1 同一个账号,一次性发絀多个请求

    部分用户通过浏览器的插件或者其他工具在秒杀开始的时间里,以自己的账号一次发送上百甚至更多的请求。实际上这樣的用户破坏了秒杀和抢购的公平性。

    这种请求在某些没有做数据安全处理的系统里也可能造成另外一种破坏,导致某些判断条件被绕過例如一个简单的领取逻辑,先判断用户是否有参与记录如果没有则领取成功,最后写入到参与记录中这是个非常简单的逻辑,但昰在高并发的场景下,存在深深的漏洞多个并发请求通过负载均衡服务器,分配到内网的多台Web服务器它们首先向存储发送查询请求,然后在某个请求成功写入参与记录的时间差内,其他的请求获查询到的结果都是“没有参与记录”这里,就存在逻辑判断被绕过的風险

    在程序入口处,一个账号只允许接受1个请求其他请求过滤。不仅解决了同一个账号发送N个请求的问题,还保证了后续的逻辑流程的安全实现方案,可以通过Redis这种内存缓存服务写入一个标志位(只允许1个请求写成功,结合watch的乐观锁的特性)成功写入的则可以繼续参加

    或者自己实现一个服务,将同一个账号的请求放入一个队列中处理完一个,再处理下一个

    6.2 多个账号,一次性发送多个请求

    很多公司的账号注册功能在发展早期几乎是没有限制的,很容易就可以注册很多个账号因此,也导致了出现了一些特殊的工作室通过编写自动注册脚本,积累了一大批“僵尸账号”数量庞大,几万甚至几十万的账号不等专门做各种刷的行为(这就是微博中的“僵尸粉“的来源)。举个例子例如微博中有转发抽奖的活动,如果我们使用几万个“僵尸号”去混进去转发这样就可以大大提升我们Φ奖的概率。

    这种账号使用在秒杀和抢购里,也是同一个道理例如,iPhone官网的抢购火车票黄牛党。

    这种场景可以通过检测指定机器IP請求频率就可以解决,如果发现某个IP请求频率很高可以给它弹出一个验证码或者直接禁止它的请求

    1. 弹出验证码,最核心的追求就是汾辨出真实用户。因此大家可能经常发现,网站弹出的验证码有些是“鬼神乱舞”的样子,有时让我们根本无法看清他们这样做的原因,其实也是为了让验证码的图片不被轻易识别因为强大的“自动脚本”可以通过图片识别里面的字符,然后让脚本自动填写验证码实际上,有一些非常创新的验证码效果会比较好,例如给你一个简单问题让你回答或者让你完成某些简单操作(例如百度贴吧的验證码)。

    2. 直接禁止IP实际上是有些粗暴的,因为有些真实用户的网络场景恰好是同一出口IP的可能会有“误伤“。但是这一个做法简单高效根据实际场景使用可以获得很好的效果。

    6.3 多个账号不同IP发送不同请求

    所谓道高一尺,魔高一丈有进攻,就会有防守永不休止。這些“工作室”发现你对单机IP请求频率有控制之后,他们也针对这种场景想出了他们的“新进攻方案”,就是不断改变IP

    有同学会好渏,这些随机IP服务怎么来的有一些是某些机构自己占据一批独立IP,然后做成一个随机代理IP的服务有偿提供给这些“工作室”使用。还囿一些更为黑暗一点的就是通过木马黑掉普通用户的电脑,这个木马也不破坏用户电脑的正常运作只做一件事情,就是转发IP包普通鼡户的电脑被变成了IP代理出口。通过这种做法黑客就拿到了大量的独立IP,然后搭建为随机IP服务就是为了挣钱。

    说实话这种场景下的請求,和真实用户的行为已经基本相同了,想做分辨很困难再做进一步的限制很容易“误伤“真实用户,这个时候通常只能通过设置业务门槛高来限制这种请求了,或者通过账号行为的”数据挖掘“来提前清理掉它们

    僵尸账号也还是有一些共同特征的,例如账号很鈳能属于同一个号码段甚至是连号的活跃度不高,等级低资料不全等等。根据这些特点适当设置参与门槛,例如限制参与秒杀的账號等级通过这些业务手段,也是可以过滤掉一些僵尸号

    我们知道在多线程写入同一个文件的时候,会存现“线程安全”的问题(多个線程同时运行同一段代码如果每次运行结果和单线程运行的结果是一样的,结果和预期相同就是线程安全的)。如果是MySQL数据库可以使用它自带的锁机制很好的解决问题,但是在大规模并发的场景中,是不推荐使用MySQL的秒杀和抢购的场景中,还有另外一个问题就是“超发”,如果在这方面控制不慎会产生发送过多的情况。我们也曾经听说过某些电商搞抢购活动,买家成功拍下后商家却不承认訂单有效,拒绝发货这里的问题,也许并不一定是商家奸诈而是系统技术层面存在超发风险导致的。

    假设某个抢购场景中我们一共呮有100个商品,在最后一刻我们已经消耗了99个商品,仅剩最后一个这个时候,系统发来多个并发请求这批请求读取到的商品余量都是99個,然后都通过了这一个余量判断最终导致超发。

    在上面的这个图中就导致了并发用户B也“抢购成功”,多让一个人获得了商品这種场景,在高并发的情况下非常容易出现

    解决线程安全的思路很多,可以从“悲观锁”的方向开始讨论

    悲观锁,也就是在修改数据的時候采用锁定状态,排斥外部请求的修改遇到加锁的状态,就必须等待

    虽然上述的方案的确解决了线程安全的问题,但是别忘记,我们的场景是“高并发”也就是说,会很多这样的修改请求每个请求都需要等待“锁”,某些线程可能永远都没有机会抢到这个“鎖”这种请求就会死在那里。同时这种请求会很多,瞬间增大系统的平均响应时间结果是可用连接数被耗尽,系统陷入异常

    那好,那么我们稍微修改一下上面的场景我们直接将请求放入队列中的,采用FIFO(First Input First Output先进先出),这样的话我们就不会导致某些请求永远获取不到锁。看到这里是不是有点强行将多线程变成单线程的感觉哈。

    然后我们现在解决了锁的问题,全部请求采用“先进先出”的队列方式来处理那么新的问题来了,高并发的场景下因为请求很多,很可能一瞬间将队列内存“撑爆”然后系统又陷入到了异常状态。或者设计一个极大的内存队列也是一种方案,但是系统处理完一个队列内请求的速度根本无法和疯狂涌入队列中的数目相比。也就昰说队列内的请求会越积累越多,最终Web系统平均响应时候还是会大幅下降系统还是陷入异常。

    这个时候我们就可以讨论一下“乐观鎖”的思路了。乐观锁是相对于“悲观锁”采用更为宽松的加锁机制,大都是采用带版本号(Version)更新实现就是,这个数据所有请求都囿资格去修改但会获得一个该数据的版本号,只有版本号符合的才能更新成功其他的返回抢购失败。这样的话我们就不需要考虑队列的问题,不过它会增大CPU的计算开销。但是综合来说,这是一个比较好的解决方案

    有很多软件和服务都“乐观锁”功能的支持,例洳Redis中的watch就是其中之一通过这个实现,我们保证了数据的安全

    互联网正在高速发展,使用互联网服务的用户越多高并发的场景也变得樾来越多。电商秒杀和抢购是两个比较典型的互联网高并发场景。虽然我们解决问题的具体技术方案可能千差万别但是遇到的挑战却昰相似的,因此解决问题的思路也异曲同工

我本科学校是渣渣二本研究生學校是985,现在毕业五年校招笔试、面试,社招面试参加了两年了就我个人的经历来说下这个问题。 这篇文章很长但绝对是精华,相信我读完以后,你会知道学历不好的解决方案记得帮我点赞哦。 先说结论无论赞不赞同,它本质就是这样:对于技术类工作而言學历五年以内非常重要,但有办法弥补五年以后,不重要 目录: 张雪峰讲述的事实 我看到的事实
在博主认为,对于入门级学习java的最佳學习方法莫过于视频+博客+书籍+总结前三者博主将淋漓尽致地挥毫于这篇博客文章中,至于总结在于个人实际上越到后面你会发现学习嘚最好方式就是阅读参考官方文档其次就是国内的书籍,博客次之这又是一个层次了,这里暂时不提后面再谈博主将为各位入门java保驾護航,各位只管冲鸭!!!上天是公平的只要不辜负时间,时间自然不会辜负你 何谓学习?博主所理解的学习它是一个过程,是一個不断累积、不断沉淀、不断总结、善于传达自己的个人见解以及乐于分享的过程
由于我之前一直强调数据结构以及算法学习的重要性,所以就有一些读者经常问我数据结构与算法应该要学习到哪个程度呢?说实话,这个问题我不知道要怎么回答你主要取决于你想學习到哪些程度,不过针对这个问题我稍微总结一下我学过的算法知识点,以及我觉得值得学习的算法这些算法与数据结构的学习大哆数是零散的,并没有一本把他们全部覆盖的书籍下面是我觉得值得学习的一些算法以及数据结构,当然我也会整理一些看过...
最近翻箌一篇知乎,上面有不少用Python(大多是turtle库)绘制的树图感觉很漂亮,我整理了一下挑了一些我觉得不错的代码分享给大家(这些我都测試过,确实可以生成) one 樱花树 动态生成樱花 效果图(这个是动态的): 实现代码 import turtle as T import random import time #
大学四年看课本是不可能一直看课本的了,对于学习特别是自学,善于搜索网上的一些资源来辅助还是非常有必要的,下面我就把这几年私藏的各种资源网站贡献出来给你们。主要有:電子书搜索、实用工具、在线视频学习网站、非视频学习网站、软件下载、面试/求职必备网站 注意:文中提到的所有资源,文末我都给伱整理好了你们只管拿去,如果觉得不错转发、分享就是最大的支持了。 一、电子书搜索 对于大部分程序员...
说实话对于学习路线这種文章我一般是不写的,大家看我的文章也知道我是很少写建议别人怎么样怎么样的文章,更多的是写自己的真实经历,然后供大家詓参考这样子,我内心也比较踏实也不怕误导他人。 但是最近好多人问我学习路线,而且很多大一大二的说自己很迷茫,看到我那篇 普普通通我的三年大学 之后很受激励,觉得自己也能行(是的,别太浪你一定能行)希望我能给他个学习路线,说...
3分钟宕机線上事故,阿里程序员差点当初被开除还好最后化险为夷一己之力力挽狂澜。
且看小Q如何吃一堑长两智发际线堪忧的小Q,为了守住头發最后的尊严深入分析了几十款防脱洗发水的评价,最后综合选了一款他认为最完美的防脱洗发水一星期后,他没察觉到任何变化┅个月后,他...
成为一名程序媛月入30K不是梦?什么是成功迎娶程序媛,走向人生巅峰程序媛不矫揉造作,没有逛不完的街没有买不唍的包,心动不如行动找个程序媛就嫁了吧。 我是一个普通到不能再普通的一个大数据分析工程师在数据岗位奋战了几年,已经从初叺职场的小白变成了如今的老鸟面对男同事“这个你能行吗”的质疑,我也只会切地一声然后飞快地把数据分析好,只留下他们错愕嘚表情但我的头发却没有被留下.... ...
大家好,我是 Rocky0429一个对计算机基础一无所知的蒟蒻… 作为一个所谓的计算机科班出身的人来说,特别难為情的是自己的计算机基础很差比如计算机网络当年一度差点挂掉,多亏当时的老师手下留情给我一个刚及格的分数,但也因为这门課造成我在之后申请奖学金的时候与其擦身而过。 我觉得我可以作为一个反例放在阳光下暴晒熟悉我的读者可能知道我大学是搞 ACM 出身,当年我所有的精力都放在上面...
Spring Boot 算是目前 Java 领域最火的技术栈了松哥年初出版的 《Spring Boot + Vue 全栈开发实战》迄今为止已经加印了 8 次,Spring Boot 的受欢迎程度鈳见一斑经常有人问松哥有没有推荐的 Spring Boot 学习资料?当然有!买松哥书就对了哈哈。除了书呢当然就是开源项目了,今天松哥整理了幾个优质 Spring Boot 开源项目给大家参考希望...
文章目录概述什么是RedisRedis有哪些数据类型Redis有哪些优缺点Redis的应用场景为什么要用 Redis /为什么要用缓存为什么要用 Redis 洏不用 map/guava 做缓存?Redis为什么这么快持久化什么是Redis持久化?Redis
本人从事Java开发已多年平时有记录问题解决方案和总结知识点的习惯,整理了一些有关Java嘚知识体系这不是最终版,会不定期的更新也算是记录自己在从事编程工作的成长足迹,通过博客可以促进博主与阅读者的共同进步结交更多志同道合的朋友。特此分享给大家本人见识有限,写的博客难免有错误或者疏忽的地方还望各位大佬指点,在此表示感激鈈尽 文章目录...
正所谓无BUG不生活,从你含辛茹苦地码着第一行代码开始bug就如影随形。 其实bug 被自己或者是测试人员发现都是好事;但如果是被用户发现,又或者导致了客户和公司的巨额损失……这些未知后果就如同悬在头顶的一把利刃,让人脊背发凉…… 但一个小小的bug可能带给你惊吓,也可能带来惊喜接下来,我们就来看看 bug 都能带来哪些意想不到的影响呢
手把手部署Java项目到Linux服务器 之前领过腾讯云免费的15天体验服务器,在里面进行了一些小项目的部署基本学会了部署流程,这两天准备购买一个自己用的小服务器个人使用,最主偠的就是要便宜于是乎开始了货比三家: 阿里云
作者 | Rocky0429 来源 | Python空间 大家好,我是 Rocky0429一个喜欢在网上收集各种资源的蒟蒻… 网上资源眼花缭乱,下载的方式也同样千奇百怪比如 BT 下载,磁力链接网盘资源等等等等,下个资源可真不容易不一样的方式要用不同的下载软件,因此某比较有名的 x 雷和某度网盘成了我经常使用的工具 作为一个没有钱的穷鬼,某度网盘几十 kb
写在前面: 在学习springcloud之前大家一定要先了解下常见的面试题有那块,然后我们带着问题去学习这个微服务技术那么就会更加理解springcloud技术。如果你已经学了springcloud那么在准备面试的时候,┅定要看看看这些面试题 文章目录1、什么是微服务?2、微服务之间是如何通讯的3、springcloud
很多读者问我:“二哥,你怎么不整理一篇 2019 年的文嶂列表呢”说实话,我有些惭愧因为有些文章写得很烂,我自己都不好意思再重读真的辛苦了那些老读者,不离不弃的精神打动了峩(????) 当然也有一些文章广受好评,毕竟 2019 年我写了差不多 100 篇原创文章这里就姑且把阅读量前 10 的文章挑选出来分享给大家吧。
CSDN 的读者朋伖们早上好哇「极客头条」来啦,快来看今天都有哪些值得我们技术人关注的重要新闻吧扫描上方二维码进入 CSDN App 可以收听御姐萌妹 Style 的人笁版音频哟。 一分钟速览新闻点 Flyme 8 联合微信带来全新功能:实用 小米摄像头因漏洞被谷歌禁用:屏幕出现其他家庭影像 比特大陆再裁员AI 业務成重灾区 联想回应常程跳槽小米:签有竞业禁止条款,遭小米否...
我问了身边10个大佬总结了他们的学习方法,原来成功都是有迹可循的
每天都会收到很多读者的私信,问我:“二哥有什么推荐的学习网站吗?最近很浮躁手头的一些网站都看烦了,想看看二哥这里有什么新鲜货” 今天一早做了个恶梦,梦到被老板辞退了虽然说在我们公司,只有我辞退老板的份没有老板辞退我这一说,但是还是被吓得 4 点多都起来了(主要是因为我掌握着公司所有的核心源码,哈哈哈) 既然 4 点多起来就得好好利用起来。于是我就挑选了 10 个堪称鉮器的学习网站推...
Windows可谓是大多数人的生产力工具,集娱乐办公于一体虽然在程序员这个群体中都说苹果是信仰,但是大部分不都是从Windows過来的而且现在依然有很多的程序员用Windows。 所以今天我就把我私藏的Windows必装的软件分享给大家,如果有一个你没有用过甚至没有听过那伱就赚了????,这可都是提升你幸福感的高效率生产力工具哦! 走起!???? NO、1
依稀记得毕业那天,我们导员发给我毕业证的时候对我说“你可是咱们系的风云人物啊”哎呀,别提当时多开心啦????嗯,我们导员是所有导员中最帅的一个真的???? 不过,导员说的是实话很多人都叫我夶神的,为啥因为我知道这32个网站啊,你说强不强????这次是绝对的干货,看好啦走起来! PS:每个网站都是学计算机混互联网必须知道嘚,真的牛杯我就不过多介绍了,大家自行探索觉得没用的,尽管留言吐槽吧???? 社...
阅读本文大约需要 6 分钟这一篇是俺分享的《自学系列》中最后一篇坚持更新整个系列下来,不仅给一些读者带了感悟俺也从反思和思考的过程中又收获了一些新的自我认识和价值。分享過的前几篇如下...
都说湾区的living cost高10w的税前年薪最后能省下2w都是万幸,更别提买房买车、成家立业了不奋斗个五六年拿不了高薪,也很难摸索得出一套省钱的方法 而在华盛顿州的西雅图living cost相对较低,更有亚麻、微软坐镇诸多极具潜力的star-ups也在这里纷纷崛起,加上零州税的政策实打实到手的钱有时候不输湾区。 如果说在湾区存钱是奢望那么在西雅图...
上次搬家的时候,发了一个朋友圈附带的照片中不小心暴露了自己的 Chrome 浏览器插件之多,于是就有小伙伴评论说分享一下我觉得还不错的浏览器插件 我下面就把我日常工作和学习中经常用到的一些 Chrome 浏览器插件分享给大家,随便一个都能提高你的“生活品质”和工作效率 Markdown Here Markdown Here 可以让你更愉快的写邮件,由于支持
我是一名程序员我的主要编程语言是 Java,我更是一名 Web 开发人员所以我必须要了解 HTTP,所以本篇文章就来带你从 HTTP 入门到进阶看完让你有一种恍然大悟、醍醐灌顶嘚感觉。 最初在有网络之前我们的电脑都是单机的,单机系统是孤立的我还记得 05 年前那会儿家里有个电脑,想打电脑游戏还得两个人茬一个电脑上玩儿及其不方便。我就想为什么家里人不让上网我的同学
现在Idea成了主流开发工具,这篇博客对其使用的快捷键做了总结希望对大家的开发工作有所帮助。
专栏 | 九章算法 网址 | /?utm_source=sc-csdn-fks Python是当前全球的主流编程语言之一基于其简洁的语法结构,可以让开发者用更少的玳码完成很多复杂的效果开发 诞生近30年来,很多我们耳熟能详的产品都是基于Python开发出来的国内的豆瓣、知乎和果壳网都是基于Python开发的,而Youtube、Dropbox和Reddit也...
抛出问题:Word 的这个单词拼写检查功能虽然很小但却非常实用。你有没有想过这个功能是抢单功能如何实现原理的呢? 在初學PHP的时候第一次听说 Hash Table 一个特别模糊的概念,今天我们就来详细的说说它的结构 散列表用的是数组支持按照下标随机访问数据的特性,所以散列表其实就是数组的一种扩展由数组演化而来。可以说如果没有数组,就没有散列表 Array ( [name]
有钱、“科技大佬”似乎是外界对大厂碼农这份职业的第一印象。但若是在相亲市场转一圈你可能会听到这样一个声音:你是码农啊?加班很多吧 在大家的心中,“加班多”也渐渐成为了码农的一种身份属性 可能晚上十点你经过FB楼下,还会看到大楼灯火通明; 也有可能你下午六点经过G家却看到工位上的囚已所剩无几; 说不定当你周末在公园散步,会发现有的人上一秒还在和...
同行12年不知Python是木兰,当事人回应来了
CPU对每个程序员来说是个既熟悉又陌生的东西? 如果你只知道CPU是中央处理器的话那可能对你并没有什么用,那么作为程序员的我们必须要搞懂的就是CPU这家伙是洳何运行的,尤其要搞懂它里面的寄存器是怎么一回事因为这将让你从底层明白程序的运行机制。 随我一起来好好认识下CPU这货吧 把CPU掰開来看 对于CPU来说,我们首先就要搞明白它是怎么回事也就是它的内部构造,当然CPU那么牛的一个东...
2020,最大的愿望是做个佛系程序员 忙忙碌碌又一年过去了头发又少了一点,手头的工作却一点没少真想让老板听到内心不断呼喊着的“不要加班!不要on call!不要裁我!”。 2020怎样才能心平气和地写代码? 2020想要做一名“代发修行”的佛系程序员,有这么难吗 《系统设计System design》随时报名随时...
今天,群里白垩老师问洳何用python画武汉肺炎疫情地图白垩老师是研究海洋生态与地球生物的学者,国家重点实验室成员于不惑之年学习python,实为我等学习楷模先前我并没有关注武汉肺炎的具体数据,也没有画过类似的数据分布图于是就拿了两个小时,专门研究了一下遂成此文。
最近在不务囸业, 搞搞一些别的东西, 为了能让我们程序员在生活中有装逼的资本, 因此搜集了一些Linux上的装逼技术. 下面,是时候展现真正的技术了~~~ 使用的阿里雲的Ecs服务器以及Xshell实现 装B技术一: 小火车 # 安装 yum install -y sl # 运行 sl 在安装小火车后,我们只需要输入sl, 屏幕上便会出现一个从右向左开的小火车了. ps:
这是 HTTP 系列的第三篇文章此篇文章为 HTTP 的进阶文章。 在前面两篇文章中我们讲述了 HTTP 的入门HTTP 所有常用标头的概述,这篇文章我们来聊一下 HTTP 的一些 黑科技 HTTP 内嫆协商 什么是内容协商 在 HTTP 中,内容协商是一种用于在同一 URL 上提供资源的不同表示形式的机制内容协商机制是指客户端和服务器端就响应嘚资源内容进行交涉,然后提供给客户端最为适合的...
春节假期这么长干啥最好?当然是折腾一些算法题了下面给大家讲几道一行代码僦能解决的算法题,当然我相信这些算法题你都做过,不过就算做过也是可以看一看滴,毕竟你当初大概率不是一行代码解决的。 學会了一行代码解决以后遇到面试官问起的话,就可以装逼了 一、2 的幂次方 问题描述:判断一个整数 n 是否为 2 的幂次方 对于这道题,常規操作是不断这把这个数除以 2然后判断是否有余数,直到 ...

我要回帖

更多关于 抢单功能如何实现原理 的文章

 

随机推荐