Learn Java design mode again: real battle sharing mode: provide activity and inventory information query scenarios based on Redis seckill

Author: little brother Fu
Blog: https://bugstack.cn

Precipitation, sharing, growth, so that they and others can have a harvest! 😄

1, Foreword

programmer 👨‍💻 What is the context?

In many cases, most of the programming and development personnel only focus on the implementation of the function, as long as they have written this part of the requirements, it's a bit like a passive job delivery. On the one hand, many new people don't understand the professional development of programmers, and on the other hand, they are not interested in the work of programming development. But in terms of the development of programmers, if we can't deal with the above (products) and the following (tests) well, we can't understand the business and product development well, and can't write very structured code. It's hard to cross the watershed of technology growth in one to three, three to five years.

Ability to accept and learn new knowledge

Have you ever felt that when you were a child, you had a strong ability to accept knowledge when nothing was possible, but as we began to grow up, our ability, way of doing things, character and conduct were often fixed. On the one hand, they have formed their own characteristics, on the other hand, the circle has been fixed. But because of this, they are seldom willing to listen to other people's opinions. For example, even if they see a whole piece of content, they will fall to 80% in the blind area of vision, and they can't see it right in front of them, which leads to their ability no longer being greatly improved.

How can programming ability grow fastest

Work content is often a little like in a factory 🏭 Screw in, most of the content is repetitive, and you can imagine how many innovations and new skills you have learned in the past year. Then, in order to learn more, I will buy some technical books, but! Technical books are different from other books. As long as they are not used, they are just understated and difficult to accept and understand. Just like the design pattern, although it may have been seen several times, it is still rarely used in the actual coding, most of the reasons are still not followed by the real operation. The best way to learn programming is to do it yourself.

2, Development environment

  1. JDK 1.8
  2. Idea + Maven
  3. Involving three projects, we can pay attention to the official account number: bugstack wormhole stack , reply to the source code download to obtain (open the obtained link and find the serial number 18)
engineering describe
itstack-demo-design-11-01 Use a bunch of code to realize business requirements
itstack-demo-design-11-02 Optimize code structure through design pattern, reduce memory usage and query time

3, Introduction to the enjoy model

The sharing element mode is mainly to share common objects, reduce the use of memory, and improve the access efficiency of the system. However, this part of shared objects usually consumes memory or needs to query a large number of interfaces or use database resources, so unified extraction is used as shared objects.

In addition, the sharing mode can be divided into the server and the client. In general, under the Internet H5 and Web scenarios, most of the data needs to be processed by the server, such as the use of the database connection pool and the use of the multi-threaded thread pool. In addition to these functions, some of the packaged processing needs to be distributed to the client, because the server needs to do the sharing processing. However, in some game scenarios, many clients need to render map effects, such as trees, flowers, fish and insects. By setting different elements to describe the use of shared element common objects, memory consumption is reduced, and the client's game is smoother.

In the implementation of the shareware model, we need to use the shareware factory to manage these independent objects and shared objects, so as to avoid thread safety problems.

4, Case scenario simulation

In this case, we simulate the query optimization using the sharing element mode in the commodity seckill scenario

Have you ever experienced a project with an average of more than ten orders per day in the first place to a project with an average of over 100000 orders per period of time in a month. In general, if there is no experience at the beginning, it is possible to use the row level lock of database to ensure the deduction operation of commodity inventory. However, with the rapid development of business, more and more users are killed. At this time, the database can no longer bear it. Generally, redis distributed lock is used to control commodity inventory.

At the same time, it is not necessary to get different activity queries from the database every time when querying, because other activity product information except inventory is fixed and unchangeable, so here you will cache it into memory.

Here we simulate the use of the factory structure of the sharing mode to provide the query of the active goods. The active goods are equivalent to the constant information, while the inventory part belongs to the changing information.

5, Using a pile of code to realize

The logic is very simple. I'm afraid you may write in disorder. A piece of fixed content and change content query combination, CV everywhere!

In fact, in general, many programmers query fixed information first, and use filtering or adding if judgment to supplement the changed information, that is, inventory. At first, I don't see any problems in this way, but as the method logic increases, more and more repetitive code will follow.

1. Engineering structure

itstack-demo-design-11-01
└── src
    └── main
        └── java
            └── org.itstack.demo.design
                └── ActivityController.java
  • The above engineering structure is relatively simple, and the next control class is used to query activity information.

2. Code implementation

/**
 * Blog: https://bugstack.cn -  Precipitation, sharing, growth, so that they and others can have a harvest!
 * Official account: bugstack wormhole stack
 * Create by Fustack @ 2020
 */
public class ActivityController {

    public Activity queryActivityInfo(Long id) {
        // Simulate obtaining activity information from the interface from the actual business application
        Activity activity = new Activity();
        activity.setId(10001L);
        activity.setName("Books and music");
        activity.setDesc("Book coupon sharing incentive sharing activity phase II");
        activity.setStartTime(new Date());
        activity.setStopTime(new Date());
        activity.setStock(new Stock(1000,1));
        return activity;
    }

}
  • The simulation here is to query the activity information from the interface, which is basically to get all the product information and inventory from the database. It's a bit like the first commodity sales system, the database can resist the amount of shopping.
  • When the subsequent business development needs to extend the code to hand over the inventory to redis for processing, it will take a long time to obtain the active inventory from redis instead of from the database, otherwise the data will be inconsistent.

6, Enjoy element mode refactoring code

The next step is to use the shareware pattern for code optimization, which is also a small refactoring.

In general, the use of this structure in the sharing mode is not too much in the normal development. In addition to some thread pools and database connection pools, it is also the scene rendering in the game scene. In addition, the design pattern idea is to reduce the use of memory and improve efficiency. It is the same idea as the prototype pattern we used before to generate complex objects by cloning objects and reduce rpc calls.

1. Engineering structure

itstack-demo-design-11-02
└── src
    ├── main
    │   └── java
    │       └── org.itstack.demo.design
    │           ├── util
    │           │    └── RedisUtils.java    
    │           ├── Activity.java
    │           ├── ActivityController.java
    │           ├── ActivityFactory.java
    │           └── Stock.java
    └── test
        └── java
            └── org.itstack.demo.test
                └── ApiTest.java

Model structure of sharing mode

  • The above is the class diagram structure of our simulation query activity scenario. On the left side is the sharing factory, which provides fixed activity data query, and on the right side is the inventory data stored by Redis.
  • Finally, it is handed over to the activity control class to process the query operation and provide all the information and inventory of the activity. Because the inventory is variable, we set the scheduled task usage inventory in the RedisUtils simulation.

2. Code implementation

2.1 activity information

public class Activity {

    private Long id;        // Activity ID
    private String name;    // Activity name
    private String desc;    // Activity description
    private Date startTime; // start time
    private Date stopTime;  // End time
    private Stock stock;    // Active inventory
    
    // ...get/set
}
  • The object class here is simple, just the basic information of an activity; id, name, description, time and inventory.

2.2 inventory information

public class Stock {

    private int total; // Total inventory
    private int used;  // Stock used
    
    // ...get/set
}
  • Here is the inventory data. We provide a separate class to save the data.

2.3 Xiangyuan factory

public class ActivityFactory {

    static Map<Long, Activity> activityMap = new HashMap<Long, Activity>();

    public static Activity getActivity(Long id) {
        Activity activity = activityMap.get(id);
        if (null == activity) {
            // Simulate obtaining activity information from the interface from the actual business application
            activity = new Activity();
            activity.setId(10001L);
            activity.setName("Books and music");
            activity.setDesc("Book coupon sharing incentive sharing activity phase II");
            activity.setStartTime(new Date());
            activity.setStopTime(new Date());
            activityMap.put(id, activity);
        }
        return activity;
    }

}
  • Here is a Xiangyuan factory 🏭 , store the data that has been queried from the library table or interface through the map structure, and store it in memory for the next time you can get it directly.
  • Such a structure is generally common in our programming and development. Of course, sometimes for distributed access, data will be stored in redis, which can be selected on demand.

2.4 simulation Redis class

public class RedisUtils {

    private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);

    private AtomicInteger stock = new AtomicInteger(0);

    public RedisUtils() {
        scheduledExecutorService.scheduleAtFixedRate(() -> {
            // Simulate inventory consumption
            stock.addAndGet(1);
        }, 0, 100000, TimeUnit.MICROSECONDS);

    }

    public int getStockUsed() {
        return stock.get();
    }

}
  • In addition to the operation tool class for simulating redis, a timing task is provided to simulate the use of inventory. In this way, we can observe the change of inventory during the test.

2.4 activity control

public class ActivityController {

    private RedisUtils redisUtils = new RedisUtils();

    public Activity queryActivityInfo(Long id) {
        Activity activity = ActivityFactory.getActivity(id);
        // Simulate obtaining inventory change information from Redis
        Stock stock = new Stock(1000, redisUtils.getStockUsed());
        activity.setStock(stock);
        return activity;
    }

}
  • In the activity control class, we use the sharing factory to obtain the activity information, and replenish the inventory information after query. Because the inventory information is changing, while the activity information is fixed.
  • Finally, a unified control class can return the complete wrapped activity information to the caller.

3. Test verification

3.1 write test class

public class ApiTest {

    private Logger logger = LoggerFactory.getLogger(ApiTest.class);

    private ActivityController activityController = new ActivityController();

    @Test
    public void test_queryActivityInfo() throws InterruptedException {
        for (int idx = 0; idx < 10; idx++) {
            Long req = 10001L;
            Activity activity = activityController.queryActivityInfo(req);
            logger.info("Test results:{} {}", req, JSON.toJSONString(activity));
            Thread.sleep(1200);
        }
    }

}
  • Here we use the activity query control class to query the activity information ten times under the operation of the for cycle. At the same time, in order to ensure the change of the inventory timing task, we add the sleep operation, and there will be no such sleep in the actual development.

3.2 test results

22:35:20.285 [main] INFO  org.i..t.ApiTest - Test result: 10001 {"desc":"Book coupon sharing incentive sharing activity phase II","id":10001,"name":"Books and music","startTime":1592130919931,"stock":{"total":1000,"used":1},"stopTime":1592130919931}
22:35:21.634 [main] INFO  org.i..t.ApiTest - Test result: 10001 {"desc":"Book coupon sharing incentive sharing activity phase II","id":10001,"name":"Books and music","startTime":1592130919931,"stock":{"total":1000,"used":18},"stopTime":1592130919931}
22:35:22.838 [main] INFO  org.i..t.ApiTest - Test result: 10001 {"desc":"Book coupon sharing incentive sharing activity phase II","id":10001,"name":"Books and music","startTime":1592130919931,"stock":{"total":1000,"used":30},"stopTime":1592130919931}
22:35:24.042 [main] INFO  org.i..t.ApiTest - Test result: 10001 {"desc":"Book coupon sharing incentive sharing activity phase II","id":10001,"name":"Books and music","startTime":1592130919931,"stock":{"total":1000,"used":42},"stopTime":1592130919931}
22:35:25.246 [main] INFO  org.i..t.ApiTest - Test result: 10001 {"desc":"Book coupon sharing incentive sharing activity phase II","id":10001,"name":"Books and music","startTime":1592130919931,"stock":{"total":1000,"used":54},"stopTime":1592130919931}
22:35:26.452 [main] INFO  org.i..t.ApiTest - Test result: 10001 {"desc":"Book coupon sharing incentive sharing activity phase II","id":10001,"name":"Books and music","startTime":1592130919931,"stock":{"total":1000,"used":66},"stopTime":1592130919931}
22:35:27.655 [main] INFO  org.i..t.ApiTest - Test result: 10001 {"desc":"Book coupon sharing incentive sharing activity phase II","id":10001,"name":"Books and music","startTime":1592130919931,"stock":{"total":1000,"used":78},"stopTime":1592130919931}
22:35:28.859 [main] INFO  org.i..t.ApiTest - Test result: 10001 {"desc":"Book coupon sharing incentive sharing activity phase II","id":10001,"name":"Books and music","startTime":1592130919931,"stock":{"total":1000,"used":90},"stopTime":1592130919931}
22:35:30.063 [main] INFO  org.i..t.ApiTest - Test result: 10001 {"desc":"Book coupon sharing incentive sharing activity phase II","id":10001,"name":"Books and music","startTime":1592130919931,"stock":{"total":1000,"used":102},"stopTime":1592130919931}
22:35:31.268 [main] INFO  org.i..t.ApiTest - Test result: 10001 {"desc":"Book coupon sharing incentive sharing activity phase II","id":10001,"name":"Books and music","startTime":1592130919931,"stock":{"total":1000,"used":114},"stopTime":1592130919931}

Process finished with exit code 0
  • It can be seen that the stock part has been changing all the time, and the other parts are the activity information, which is fixed. So we use the sharing element mode to split this structure.

7, Summary

  • For the design of sharing mode, we can focus on the design of sharing factory. In some scenarios with a large number of duplicate objects, we can use this scenario to reduce the interface calls at the server and the memory consumption at the client. Is the main application of this design pattern.
  • In addition, we can see from the use of map structure that using a fixed id to store and retrieve objects is a key point. In addition, it is not only used in the sharing mode, but also in some other factory mode, adapter mode and combination mode, the map structure can be used to store services for external acquisition to reduce the use of ifelse judgment.
  • Of course, in addition to the advantages of this design to reduce the use of memory, it also has its disadvantages. In some complex business processing scenarios, it is difficult to distinguish internal and external states, such as our activity information part and inventory change part. If it can't be split well, it will make the design of Xiangyuan factory very confusing and difficult to maintain.

8, Recommended reading

Tags: Java Database Redis Programming

Posted on Sun, 14 Jun 2020 22:21:04 -0400 by BPWheeler