Spike design architecture model

Original: spike architecture model design

Preface: I believe many people have seen spike system, such as Jingdong or Taobao spike, spike millet phone, then spike back system is how to achieve it? How do we design a system to spike it? For spike system what issues should be considered? How to design a robust system to spike? This issue we're going to explore this issue:

 

Blog directory

Spike system problem that should be considered: a

II: design and technical solutions spike system

Three: System Architecture

Four: summary

A: What issues should be considered spike

1.1: oversold issues

   Analysis spike business scenarios, the most important thing is oversold issues, if stocking only 100, but eventually oversold 200, in general, relatively low price spike system, if oversold will seriously affect the company's property interests therefore bear the brunt of the problem is to solve the oversold commodities.

1.2: high concurrency

Spike has a short time, a large amount of concurrency features, spike duration of only a few minutes, while the company usually to create a sensational effect, will be a very low price to attract users, user participation will be snapped up very much. A short time

There are a large number of requests rush to, how to prevent back-end cache concurrency caused by excessive breakdown or failure, defeat the database problems need to be considered.

1.3: Anti-brush Interface

Now most of them will come out for the spike spike corresponding software, such software will simulate constantly sends a request to the backend server, one second hundreds of times are very common, how to prevent invalid request repeat of such software, to prevent the continued requests initiated we also need to consider targeted

1.4: spike url

For the average user, see only a relatively simple spike page, does not meet the specified time, spike button is grayed out, once it reaches the specified time, the gray button becomes clickable. This section is for white users, if it is a little bit of knowledge of the user's computer, the browser will see the network see url spike through specific software to spike request can also be achieved through F12. Url spike or know in advance who direct a request to implement spike. We need to consider this issue resolved

1.5: Database Design

Spike risk of defeat our server, if it with our other businesses in the same database, coupled together, it is very likely implications and affect other businesses. How to prevent this problem from occurring, even if the spike occurs down, stuck a server problem, we should let him try not to affect the normal conduct of business online

1.6: a large number of requests issue

1.2 According to consider, even for a short time using the cache still not enough to cope with the impact of the flow of high concurrency. How to host such a huge amount of access, while providing service to ensure a stable low-latency, it is a big challenge to face. We come to an account balance, if using redis cache, a single server can withstand redis QPS probably about 4W, if a spike of users attracted more than enough, single QPS could reach hundreds of thousands, or monomer redis insufficient to support such a huge amount of requests. Cache will be breakdown, directly penetrate into the DB, thereby defeat mysql. Background will be a lot of error

II: design and technical solutions spike system

2.1: spike System Database Design

For questions raised by 1.5 database spike, spike should therefore be individually designed a database to prevent concurrent access because of the high spike of activity caused the collapse of the entire site. It should be only two tables, a spike Orders table, a spike goods table

  

In fact, there should be few tables, merchandise table: can be found in association goods_id specific product information, product image, name, usually the price, the price spike, etc., as well as user table: user_id user can query the user nickname, user phone number other additional information, such as shipping address, will not give specific examples of this.

2.2: url spike design

In order to avoid having to access experienced by people under a single page url directly to the back interface spike goods, we need to spike the url achieve dynamic, even the development of the entire system one can know the url spike spike before the start. Specific approach is through the md5 encrypted string of random characters as url spike, and then front-access backstage for specific url, can continue to spike after a background check through.

2.3: spike static pages

The product description, parameters, transaction records, images, evaluation, and all written into a static page, the user need not request by accessing the back-end server without going through a database generated directly in the front-end client, which can reduce the maximum possible pressure on the server. Specific methods can be used freemarker template technology, create pages template, fill data, and then render the page

2.4: upgrade to a cluster redis redis monomer

Spike is a reading and writing little scenes, very appropriate use redis do caching. But taking into account the breakdown cache problem, we should build redis clusters, using Sentinel mode, redis can improve performance and availability.

 2.5: Using nginx

nginx是一个高性能web服务器,它的并发能力可以达到几万,而tomcat只有几百。通过nginx映射客户端请求,再分发到后台tomcat服务器集群中可以大大提升并发能力。

2.6:精简sql

典型的一个场景是在进行扣减库存的时候,传统的做法是先查询库存,再去update。这样的话需要两个sql,而实际上一个sql我们就可以完成的。可以用这样的做法:update miaosha_goods  set stock =stock-1 where goos_id ={#goods_id} and  version = #{version} and sock>0;这样的话,就可以保证库存不会超卖并且一次更新库存,还有注意一点这里使用了版本号的乐观锁,相比较悲观锁,它的性能较好。

2.7:redis预减库存

很多请求进来,都需要后台查询库存,这是一个频繁读的场景。可以使用redis来预减库存,在秒杀开始前可以在redis设值,比如redis.set(goodsId,100),这里预放的库存为100可以设值为常量),每次下单成功之后,Integer stock = (Integer)redis.get(goosId); 然后判断sock的值,如果小于常量值就减去1;不过注意当取消的时候,需要增加库存,增加库存的时候也得注意不能大于之间设定的总库存数(查询库存和扣减库存需要原子操作,此时可以借助lua脚本)下次下单再获取库存的时候,直接从redis里面查就可以了。

2.8:接口限流

秒杀最终的本质是数据库的更新,但是有很多大量无效的请求,我们最终要做的就是如何把这些无效的请求过滤掉,防止渗透到数据库。限流的话,需要入手的方面很多:

2.9.1:前端限流

首先第一步就是通过前端限流,用户在秒杀按钮点击以后发起请求,那么在接下来的5秒是无法点击(通过设置按钮为disable)。这一小举措开发起来成本很小,但是很有效。

2.9.2:同一个用户xx秒内重复请求直接拒绝

具体多少秒需要根据实际业务和秒杀的人数而定,一般限定为10秒。具体的做法就是通过redis的键过期策略,首先对每个请求都从String value = redis.get(userId);如果获取到这个

value为空或者为null,表示它是有效的请求,然后放行这个请求。如果不为空表示它是重复性请求,直接丢掉这个请求。如果有效,采用redis.setexpire(userId,value,10).value可以是任意值,一般放业务属性比较好,这个是设置以userId为key,10秒的过期时间(10秒后,key对应的值自动为null)

2.7.3:令牌桶算法限流

接口限流的策略有很多,我们这里采用令牌桶算法。令牌桶算法的基本思路是每个请求尝试获取一个令牌,后端只处理持有令牌的请求,生产令牌的速度和效率我们都可以自己限定,guava提供了RateLimter的api供我们使用。以下做一个简单的例子,注意需要引入guava

public class TestRateLimiter {

    public static void main(String[] args) {
        //1秒产生1个令牌
        final RateLimiter rateLimiter = RateLimiter.create(1);
        for (int i = 0; i < 10; i++) {
            //该方法会阻塞线程,直到令牌桶中能取到令牌为止才继续向下执行。
            double waitTime= rateLimiter.acquire();
            System.out.println("任务执行" + i + "等待时间" + waitTime);
        }
        System.out.println("执行结束");
    }
}

   上面代码的思路就是通过RateLimiter来限定我们的令牌桶每秒产生1个令牌(生产的效率比较低),循环10次去执行任务。acquire会阻塞当前线程直到获取到令牌,也就是如果任务没有获取到令牌,会一直等待。那么请求就会卡在我们限定的时间内才可以继续往下走,这个方法返回的是线程具体等待的时间。执行如下;

可以看到任务执行的过程中,第1个是无需等待的,因为已经在开始的第1秒生产出了令牌。接下来的任务请求就必须等到令牌桶产生了令牌才可以继续往下执行。如果没有获取到就会阻塞(有一个停顿的过程)。不过这个方式不太好,因为用户如果在客户端请求,如果较多的话,直接后台在生产token就会卡顿(用户体验较差),它是不会抛弃任务的,我们需要一个更优秀的策略:如果超过某个时间没有获取到,直接拒绝该任务。接下来再来个案例:

public class TestRateLimiter2 {

    public static void main(String[] args) {
        final RateLimiter rateLimiter = RateLimiter.create(1);

        for (int i = 0; i < 10; i++) {
            long timeOut = (long) 0.5;
            boolean isValid = rateLimiter.tryAcquire(timeOut, TimeUnit.SECONDS);
            System.out.println("任务" + i + "执行是否有效:" + isValid);
            if (!isValid) {
                continue;
            }
            System.out.println("任务" + i + "在执行");
        }
        System.out.println("结束");
    }
}

其中用到了tryAcquire方法,这个方法的主要作用是设定一个超时的时间,如果在指定的时间内预估(注意是预估并不会真实的等待),如果能拿到令牌就返回true,如果拿不到就返回false.然后我们让无效的直接跳过,这里设定每秒生产1个令牌,让每个任务尝试在

0.5秒获取令牌,如果获取不到,就直接跳过这个任务(放在秒杀环境里就是直接抛弃这个请求);程序实际运行如下:

只有第1个获取到了令牌,顺利执行了,下面的基本都直接抛弃了,因为0.5秒内,令牌桶(1秒1个)来不及生产就肯定获取不到返回false了。

2.8:异步下单

为了提升下单的效率,并且防止下单服务的失败。需要将下单这一操作进行异步处理。最常采用的办法是使用队列,队列最显著的三个优点:异步、削峰、解耦。这里可以采用rabbitmq,在后台经过了限流、库存校验之后,流入到这一步骤的就是有效请求。然后发送到队列里,队列接受消息,异步下单。下完单,入库没有问题可以用短信通知用户秒杀成功。假如失败的话,可以采用补偿机制,重试。

2.9:服务降级

假如在秒杀过程中出现了某个服务器宕机,或者服务不可用,应该做好后备工作。之前的博客里有介绍通过Hystrix进行服务熔断和降级,可以开发一个备用服务,假如服务器真的宕机了,直接给用户一个友好的提示返回,而不是直接卡死,服务器错误等生硬的反馈。

三:总结

秒杀流程图:

      这就是我设计出来的秒杀流程图,当然不同的秒杀体量针对的技术选型都不一样,这个流程可以支撑起几十万的流量,如果是成千万破亿那就得重新设计了。比如数据库的分库分表、队列改成用kafka、redis增加集群数量等手段。通过本次设计主要是要表明的是我们如何应对高并发的处理,并开始尝试解决它,在工作中多思考、多动手能提升我们的能力水平,加油!如果本篇博客有任何错误,请麻烦指出来,不胜感激。

Guess you like

Origin www.cnblogs.com/lonelyxmas/p/11300668.html