Abstract:

This blog is “Java seconds kill system of actual combat series” the twelfth article, with the tools of stress testing in this post we will Jmeter again kill scenes (high concurrency scenario) under various typical problems, one of the most classic is the “” inventory oversold” problem, in this article we repeat this problem, and analyzes problems!

Content:

A proper system that claims to be able to handle high concurrent requests has some hidden experiences behind it, and so does a seckill system. Generally, these experiences are quite brutal, and we will recreate them in this article! That is, pressure testing tool Jmeter is used to pressure the “kill interface” of this kill system!

Before the second kill test, we copied the “controller method corresponding to receiving the front end user’s second kill request” to be used in the JMeter pressure test, that is, a new method of “executing the second kill request” was reproduced in the KillController, with the code as follows:

@requestMapping (value = prefix+"/execute/lock",method = RequestMethod.POST,consumes = MediaType.APPLICATION_JSON_UTF8_VALUE)
@ResponseBody
public BaseResponse executeLock(@RequestBody @Validated KillDto dto, BindingResult result){
  if (result.hasErrors() || dto.getKillId()<=0){
      returnnew BaseResponse(StatusCode.InvalidParams); } BaseResponse response=new BaseResponse(StatusCode.Success); Try {// No distributed lock prerequisite Boolean res=killService.killItem(dto.getKillId(),dto.getUserId());
      if(! res){return new BaseResponse(StatusCode.Fail.getCode(),"No distributed lock - ha ha ~ the item has been snapped up or is not snapped up in time!");
      }
  }catch (Exception e){
      response=new BaseResponse(StatusCode.Fail.getCode(),e.getMessage());
  }
  return response;
}Copy the code


After that, we can happily enter the play session.

(1) Double-click JMeter startup script jmeter.sh, enter the main interface of JMeter, create a test plan, and then create a thread group under the test plan (set 1000 threads per second, you can adjust the number of threads later). This is followed by new HTTP request items and CSV data file reading configuration, as shown below:



Where, userId parameter is used to simulate users participating in seckilling ~ snapping, and its value will be derived from the “CSV data file setting” option in the figure above, where Debug sets 10 users, as shown below:



It is worth mentioning that the “HTTP Header Manager” option is required to specify the data format of the submitted data, That is, the content-type is Application /json (because the back-end interface is setting Consumes = MediaType.APPLICATION_JSON_UTF8_VALUE).

Before the start, we set the goods with killId=3 as the objects of seckill ~ snap up, and set the total value of “available purchase quantity/inventory” as 6 in the data table, as shown in the figure below:



(2) everything is ready. Click the start of JMeter’s main interface to initiate the request of “1000 threads in 1 second”. The userId corresponding to these 1000 threads, namely userId, will be read randomly from the above CSV file. Before we get the result, let’s start from a theoretical point of view: 10 users snapping up a book with only 6 items in stock, the theoretical result should be “stock goes to 0, all books are snapped up, then there are 6 items in the item_kill_success table, and there should be only 6 seconds of successful orders”! However, theory is theory, reality is very cruel!

(3) Click the start button of JMeter, then you can observe the output information of the console and the database tables ITEM_kill and Item_KILL_SUCCESS, and you will find a series of “horrible” data records, as shown below:



For the first time to encounter the “high concurrency second kill business scenario” children may feel surprised, “clearly through Postman test ah, why still appear this situation!” , a little puzzled!

Debug: If something happens for a reason, you need to analyze it from the source.

(4) Let’s review the core logic of the written “seckill interface” again, as shown in the figure below:




(1) When the user frantically clicks the “Buy” button in the front interface, the interface above will receive the “surging tide” of user seconds kill requests. For the first time, many users will kill the product in seconds for the first time, so most users in process A will pass the assessment;

(2) At the same time, since the logic of process B is to judge whether the product can be robbed or not, it is obvious that everyone is the first time to rob the product, and the product will not be robbed so quickly, so everyone in process B will also pass the assessment;

(3) In the C process, it is necessary to deduct the inventory. Since the deduction of inventory is only a simple operation of “minus one”, many people can successfully deduct one in the C process.

(4) In the end, we rushed to process D, which is used to “generate successful orders in seconds” to record the traces of products that users have killed in seconds, but also to serve process A; At this point, D no longer makes any judgment (as you can see, the core judgment actually lies in process A, which is the fatal source of the problem), so we directly insert A successful record.

Therefore, in the end, there are “oversold inventory”, “the same user can grab many times” and other puzzling problems;

Through the above analysis, in fact, Debug has pointed out that the root cause of the problem is that the processing of D process does not win enough time for the processing of A process under the condition of high concurrency. That is, “generate a second kill successful order record” is not timely for “judge whether the user has seconds kill ~ whether there is a corresponding order record” process is very good service!

Then in the following chapter, we will optimize from different perspectives, including the database Sql optimization, the optimization of code logic level, the introduction of the distributed lock, etc. (of course, these from the level of development, there are also can optimize operational level, such as load balancing, Nginx middleware cluster deployment for improvement of the high availability, etc.).

Supplement:

1, at present, the overall construction of the second kill system and code combat has been completed, the complete source code database address can be downloaded here: gitee.com/steadyjack/… Remember Fork and Star!!

2. Finally, don’t forget to pay attention to Debug’s wechat official account: