The activity can be seen everywhere on the Internet. From 12306 ticket snatching to Juhuasuan.com, it can be seen in every aspect of our life. The instantaneous architecture design is also a test of an architect’s architectural design ability. The purpose of this article is not to provide a design solution that can be directly implemented, but to provide a simple method, an idea, so that people can have a more emotional understanding of some of the design behind seckill, and you can do it yourself. All configuration and source code is available in GitHub Repository at the end of this article.

First, a brief introduction to some of the components covered in this article, as shown below:





JMeter: JMeter is used to simulate a large number of concurrent user requests during seckill activities

Seckill Service: A Seckill Service implemented using Express based on Nodejs. Steps 2, 3, and 4 in the figure are processed in this Service

Redis: A Redis Docker container that stores a data called counter to indicate the current remaining inventory size

Kafka: a Kafka docker container, in fact, there is a ZooKeeper Docker container. Kafka uses ZooKeeper to store some metadata, which is not covered in the program, so it is not listed as a separate container. After updating Redis, the Seckill service sends a message to Kafka indicating a successful Seckill

Seckill Kafka Consumer: Nodejs-based Kafka Consumer takes the Seckill success message from Kafka, processes it and stores it in MySQL

MySQL: a MySQL Docker container. The final successful request will correspond to a record in the database table

Environment set up

Download JMeter binary from the official website and run JMeter in the bin directory to start it. Then create a Thread Group named Seckill as shown in the following figure and set it to initiate 2000 concurrent requests within 5s.





Create an Http Request Sampler under the Thread Group and name it Seckill. Configure host name, port number, Http Request Method, and Request path as shown in the following figure





2. Install Redis, Kafka, Zookeeper, and MySQL. Docker Engine, Docker Machine and Docker Compose need to download and install Docker Engine, Docker Machine and Docker Compose before this. If it is on Windows or Mac, Docker official website provides Docker For Windows/Docker For Mac installation program, which can be very convenient to install these three components.

3. Write a Docker Compose file to create a Seckill project folder, create a Docker – Compose. Yml file, the content is as follows:





In the configuration file, four services are configured corresponding to four Docker Containers, namely ZooKeeper, Kafka, Redis and mysql. There are two places that need to be set to your actual environment. One is the KAFKA_ADVERTISED_HOST_NAME field under the Kafka configuration, which needs to set the IP of the local machine. The other is MYSQL_ROOT_PASSWORD under MYSQL configuration, which you can set to any value you want.

Once the file is created, you can go to the command line project root and execute docker-compose up. The Docker engine will start up all four components.

Note: After starting, we need to create a topic named CAR_NUMBER in the Kafka container, a counter named counter in the Redis container (set to 100, representing the initial inventory value of 100), Create a table named seckill (containing a self-growing id from segment and a date field in timestamp format).

Code snippet

1 . Seckill Service









  • Lines 1-8 introduce the objects needed by the program, nodeJS MVC framework Express, Redis, Kafka, etc

  • In line 10, a POST method with a path of /seckill is exposed using the method provided by Express

  • Line 12 defines a method that will be called on line 54

  • Lines 13-22 create a new Redis client and listen for error events

  • In line 23, this is a very important line of code. It tells Redis Cilent to monitor the value of counter in Redis, and then it starts a transaction. If another client changes the value of counter at the time the transaction is committed, it will abandon the transaction.

  • In line 24, we get the value of counter through the redis client’s asynchronous method. Because the Redis GET operation is atomic, there is no need to worry about concurrent reads and writes.

  • In line 25-28, determine whether the returned repository value is greater than 0. If so, start a transaction via client.multi(), decr() to decrease the value of counter by 1, and commit the transaction via exec(). If less than 0, line 47 is executed, the print is sold out and the Redis client is closed.

  • In lines 29-46, here we look at the callback method in multi-.exec (). Previously we have used watch to monitor counter. The replies in the callback method are null if another client modifies the value counter during the transaction, as you can see at lines 29-31, and the program prints “possible conflict” and calls the FN method again to try again. If the replies are not null, kafka’s producer sends a message to the CAR_NUMBER topic.

2 . seckill_kafka_consumer





It initializes a Kafka consumer to listen to the CAR_NUMBER topic, and inserts a record into the MySQL seckill table for new messages.

steps

  • Start the docker container
  • Start the Seckill_Service
  • Start the seckill_kafka_consumer
  • Start JMeter to send 2000 concurrent requests

The results of

JMeter request results




Redis counter field




MySQL seckill table




As you can see, in the end, counter in Redis becomes 0, and 100 records are inserted into the Seckill table, with no oversold or undersold. Of course, there are many other considerations that need to be taken into account in the actual production environment. I hope this article will serve as a reference to help you better understand the second kill scenario.

Project GitHub address: MockSecKill