DEV Community

zhuyasen
zhuyasen

Posted on

Quickly and easily implement a high-performance e-commerce system by sponge+dtm

This article demonstrates how to use the Sponge framework to quickly build a simplified high-performance e-commerce system, implementing flash sale and order functionality, while ensuring data consistency through the Distributed Transaction Manager (DTM). The architecture of the e-commerce system is shown below:

flash-sale-order-cache

This is the source code example eshop, directory includes two identical code examples, but the code structure is slightly different, mainly to show that sponge supports the creation of microservices projects with different repository patterns, example-1-multi-repo is suitable for microservices multi-repo (multi-repo), example-2-mono-repo is suitable for microservices single repository (mono-repo).

Environment Setup

To build this e-commerce system, you need the following tools and dependencies:

Additionally, the following services are required:

  • DTM: A distributed transaction manager for ensuring data consistency across multiple service calls.
  • Redis: Used in conjunction with DTM to handle flash sale caching.
  • Kafka: A message queue system for asynchronous order processing.
  • MySQL: Database for storing service data.

All services will be running on a virtual machine with the IP address 192.168.3.37.

Launching DTM Services

DTM is a core component of this system, responsible for managing distributed transactions in the flash sale and order processes. Two DTM service instances are required—one for MySQL and one for Redis storage.

You can download DTM from the following link: https://github.com/dtm-labs/dtm/releases/tag/v1.18.0

Service Name Port Configuration
DTM-MySQL HTTP: 36789, gRPC: 36790
DTM-Redis HTTP: 35789, gRPC: 35790

1. Launching DTM-MySQL Service

   Store: # specify which engine to store trans status
     Driver: 'mysql'
     Host: '192.168.3.37'
     User: 'root'
     Password: '123456'
     Port: 3306
     Db: 'dtm'
Enter fullscreen mode Exit fullscreen mode
  • Start the DTM service:
   ./dtm -c conf.yml
Enter fullscreen mode Exit fullscreen mode

2. Launching DTM-Redis Service

   Store: # specify which engine to store trans status
       Driver: 'redis'
       Host: '192.168.3.37'
       User: 'default'
       Password: '123456'
       Port: 6379
Enter fullscreen mode Exit fullscreen mode
  • Start the DTM service:
   ./dtm -c conf.yml
Enter fullscreen mode Exit fullscreen mode

Rapid Development of an E-Commerce System Using Sponge

The simplified e-commerce system consists of the following eight microservices:

  • eshop_gw: API gateway service
  • user: User service
  • product: Product service
  • order: Order service
  • stock: Stock service
  • coupon: Coupon service
  • pay: Payment service
  • flashSale: Flash sale service

1. Prepare MySQL Databases and Tables for Each Service

Import the corresponding database tables for each service into MySQL:

2. Prepare Protobuf Files for Each Service

These protobuf files allow Sponge to quickly create services:

3. Generate gRPC+HTTP Hybrid Service Code Based on Protobuf

Open the sponge UI page, switch to the menu Protobuf --> Create grpc+http service, fill in the parameters, and generate 7 hybrid service codes that support both grpc and http: user, product, order, stock, coupon, pay, flashSale, as shown below:

eshop-grpc-http-pb

After downloading the code, unzip each service code into the eshop directory.

Note: If the large repository option is enabled on the code generation page, it means that the created service is suitable for a microservice mono-repo mode.

4. Generate CRUD Code Based on MySQL Tables

Open the sponge UI page, switch to the menu Public --> Generate service+handler CRUD code, fill in the parameters, and generate CRUD codes for the user, product, order, stock, coupon, and pay services, as shown below:

eshop-service-handler

After downloading the code, unzip the CRUD code and move the CRUD code (the api and internal directories) into the corresponding service code (if prompted with duplicate proto files, just ignore it).

Note: If the large repository option is enabled on the code generation page, it means that the created service is suitable for a microservice mono-repo mode.

5. Generate API Gateway Service Code Based on Protobuf

Open the sponge UI page, switch to the menu Protobuf --> Create grpc gateway service, fill in the parameters, and generate the API gateway service code for eshop_gw, as shown below:

eshop-grpc-gw-pb

After downloading the code, unzip the service code into the eshop directory.

To allow the eshop_gw service to connect to the various services, you need to generate the connection code. Open the sponge UI page, switch to the menu Public --> Generate grpc connection code, fill in the parameters, and generate the connection code for eshop_gw to connect to various grpc services, as shown below:

eshop-grpc-conn

After downloading the code, unzip it, and move the connection code (the internal directory) into the eshop_gw service code.

Note: If the large repository option is enabled on the code generation page, it means that the created service is suitable for a microservice mono-repo mode.

6. Write Business Logic Code

At this point, the service framework is basically set up. Next, write the actual business logic code in the internal/service directory of each service.

7. Start the Services

Before starting the services, modify the configuration files of each service, including the port numbers, database connections, etc. The default HTTP port for each service is 8080, and the grpc port is 8282. Since they are running locally on the same machine (local test IP is 192.168.3.90), to avoid port conflicts, the ports of each service have been modified (ports can be found and modified in the configs/xxx.yml directory and api/xxx/v1/xxx.proto). Below are the modified ports:

Service Protocol HTTP Port gRPC Port
eshop_gw HTTP 8080 -
user HTTP, gRPC 30080 30082
product HTTP, gRPC 30180 30182
order HTTP, gRPC 30280 30282
stock HTTP, gRPC 30380 30382
coupon HTTP, gRPC 30480 30482
pay HTTP, gRPC 30580 30582
flashSale HTTP, gRPC 30680 30682

Note: If running in containers or on different machines, you don’t need to modify the default ports, just change the mapped ports.

Testing and Verification

Single Service Testing

After all services have successfully started, verify that each service is functioning properly by testing the APIs of the following 7 services: user, product, order, stock, coupon, pay, and flashSale.

Open your browser and navigate to http://localhost:<service_port>/apis/swagger/index.html to check if the APIs of each service are working correctly. Besides testing the APIs on the Swagger page, you can also run gRPC API tests by filling in parameters in the internal/service/xxx_client_test.go file under each service.

Integration Testing

Once individual services pass the tests, use the API gateway service of eshop_gw to test the entire system. In your browser, visit the Swagger page of the API gateway service at http://localhost:8080/apis/swagger/index.html, as shown in the figure below:

eshop-gw-swagger

Testing the Submit Order API

  • The submit order process uses DTM's distributed transaction model saga, mainly to verify the consistency of creating orders, deducting stock, creating payment orders, and coupon data.

  • To avoid order failure due to insufficient stock, set the stock before testing. In the Swagger page, find the API for setting product stock, and fill in the parameters. For example, set product ID to 1 and stock to 10:

   {
     "productID": 1,
     "stock": 10
   }
Enter fullscreen mode Exit fullscreen mode
  • Test the submit order API by requesting both the non-buffered queue and buffered queue APIs. In the Swagger page, find the respective API and fill in the parameters, such as user ID = 1, product ID = 1, product quantity = 1, and order amount = 100:
   {
     "userID": 1,
     "productID": 1,
     "productCount": 1,
     "amount": 100,
     "couponID": 0
   }
Enter fullscreen mode Exit fullscreen mode

Note: If couponID is not set to 0, it means a coupon will be used. If the coupon is invalid or expired, the order will fail. To ensure the order succeeds, find the API for creating a new coupon on the Swagger page, create a new coupon, get the coupon ID, and fill it into the couponID field of the submit order API.

Testing the Flash Sale API

  • The flash sale process uses Kafka's message queue, DTM+Redis's two-phase message, and DTM+MySQL's saga distributed transaction models to verify consistency in flash sales, stock deduction, order creation, and payment order creation.

  • To avoid order failure due to insufficient stock, set the stock before testing. In the Swagger page, find the API for setting product stock and fill in the parameters. For example, set product ID to 1 and stock to 10:

   {
     "productID": 1,
     "stock": 10
   }
Enter fullscreen mode Exit fullscreen mode
  • Test the flash sale API to verify data consistency. In the Swagger page, find the flash sale API and fill in the parameters, such as user ID = 1 and product ID = 1:
   {
     "userID": 1,
     "productID": 1,
     "amount": 100
   }
Enter fullscreen mode Exit fullscreen mode

Stress Testing

To perform stress testing on the eshop_gw API gateway service and verify the system's performance under high concurrency, use the stress testing tool k6. Before conducting the stress test, ensure that enough stock is set to avoid order failure.

  1. For stress testing the Submit Order API scenario, use the k6 script submitOrder.js and run the following command:

    # 1000 virtual users, running for 10 seconds
    k6 run --vus 1000 --duration 10s test/k6/submitOrder.js
    
    # Alternatively, specify the number of virtual users and the number of request iterations, for example, 1000 virtual users performing 100,000 request iterations
    k6 run -u 1000 -i 100000 submit_order.js
    
  2. For stress testing the Flash Sale API scenario, use the k6 script flashSale.js and run the following command:

   # 10,000 virtual users, running for 1 second
   k6 run --vus 10000 --duration 1s test/k6/flashSale.js
Enter fullscreen mode Exit fullscreen mode

Note: The results of stress testing depend on factors such as machine configuration, network environment, and database setup. Adjust accordingly based on actual conditions.

Summary

This example shows how to quickly build a high-performance e-commerce system. The system architecture is divided into user, product, order, inventory, payment, flash sale and other services, each service code (excluding business logic code) can be generated by Sponge, using DTM to ensure data consistency under high concurrency flash sale, order scenarios. By integrating Redis and Kafka, the system also has efficient caching and message queuing support, improving overall performance and scalability.

Top comments (0)