In previous articles, I first did the FunTester framework Redis test prep and then shared the -FunTester test framework Redis performance testing practices that tested common key-value type Redis operations.

The FunTester test framework provides performance tests for Redis database key-list operations, including add, delete, and combine tests.

scenario

The line is divided into three test scenarios:

  1. Add a batch to Rediskey-listThe data is then sent to eachkey-listAdd elements to.
  2. Based on the data in 1, the concurrency goes fromkey-valuGets and deletes the element.
  3. Think of Redis at the same timekey-listAdd and remove elements from data. This includes adding and removing elements from the head and tail of the list.

Train of thought

Due to the poor performance of the Redis service test, QPS of 100 ~ 150 were measured in the previous paper. This time, the same key is not tested concurrently, and each thread has a unique key. This test plan a little bit complicated, USES Java. Util. Concurrent. Atomic. AtomicInteger thread-safe classes. In each multi-threaded tasks com. Funtester. Base. Constaint. FixedThread implementation class one more attribute com. Funtest. Redis. RedisList01. FunTester# listName.

The general idea is multi-threaded +Redis connection pooling, where each thread has a unique key that does not repeat itself, and then continuously performs the actions in the three test scenarios.

For the third test scenario, it is necessary to describe the test case: first, there are some keys and corresponding List values in the database. Then I’m going to add an element A from the head of the list, then I’m going to add an element B from the tail of the list, then I’m going to get and delete an element C from the head of the list, and I’m going to get and delete an element D from the tail of the list, and finally I’m going to verify that a==c and b==d.

The following are concrete implementations of the three test scenarios. I will focus on the implementation of the third test scenario and the results of the test because of the repetitive functionality. The first two scenarios just share the test scripts and data.

Scenario 1

Use cases

class RedisList01 extends RedisBase {

    static AtomicInteger num = new AtomicInteger(0)

    static RedisBase drive

    public static void main(String[] args) {
        String host = "FunTester"
        int port = 6379
        drive = new RedisBase(host, port)
        int times = 400
        int thread = 20
        Constant.RUNUP_TIME = 0
        def tester = new FunTester(times)

        def task = new Concurrent(tester, thread, "Redis testing practices, List adding tests")
        task.start()
        drive.close()
    }

    private static class FunTester extends FixedThread {

        String listName = DEFAULT_STRING + num.getAndIncrement()

        FunTester(int limit) {
            super(null, limit, true)}@Override
        protected void doing(a) throws Exception {
            drive.lpush(listName, StringUtil.getString(10), StringUtil.getString(10), StringUtil.getString(10), StringUtil.getString(10), StringUtil.getString(10))}@Override
        ThreadBase clone(a) {
            return new FunTester(this.limit)
        }
    }

}

Copy the code

The test results

The progress bar display and graphical statistical test data are omitted and only test results are shared. Table using Base64 decoding is the graphical test results, interested can turn to see the distribution map.

~ ☢ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ~ JSON ~ ☢ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ~ > {> (1)."rt":165> 1)."failRate":0.0> 1)."threads":20> 1)."deviation":"0.44%"> 1)."errorRate":0.0> 1)."executeTotal":7899> 1)."qps2":120.67464136761538> 1)."total":7899> 1)."qps":121.21212121212122> 1)."startTime":"The 2021-09-16 16:05:22"> 1)."endTime":"The 2021-09-16 16:06:28"> 1)."mark":"Redis test practice,list add test 161605"> 1)."table":"eJztkzsKwkAQhnshd5gDRIjBKscQLxBwwQU3SlZBS18oWptSPIFWYuFtAorHcESND8SNRt0gs/wwIcX830c2RgaUx2clLrfL8W4x2cynu9XSrHBZ367Wm9H s+BpsC+pln7kl9TYjYzzvLDBZq3qSQZEL5kAzK5nP3Qp4DWFCKyuQxvVUHWoOwT047nJyeQuENIXbdGzLxscPWCQ9YTDExDJJd0sYdDDfbQqDNgZHH3Ou+lR jtLyLwdHDXKoGmMu4Ln44XqSJ1a0sfXmoKCOs06f9Edab5BHtLeaDu5KmcTa5vwIpx45l9ux//YdxMEwBBhmSIRnqxyBDMiRD/RhkSIZkqB+DDMmQDPVjkCE ZkqF+DDJMZLgHx9E+BA==">} ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ~ JSON ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~Copy the code

Scenario 2

Use cases

class RedisList02 extends RedisBase {

    static AtomicInteger num = new AtomicInteger(0)

    static RedisBase drive

    public static void main(String[] args) {
        String host = "FunTester"
        int port = 6379
        drive = new RedisBase(host, port)
        int times = 400
        int thread = 20
        Constant.RUNUP_TIME = 0
        def tester = new FunTester(times)

        def task = new Concurrent(tester, thread, "Redis testing practices, List retrieves and deletes tests from scratch")
        task.start()
        drive.close()
    }

    private static class FunTester extends FixedThread {

        String listName = DEFAULT_STRING + num.getAndIncrement()

        FunTester(int limit) {
            super(null, limit, true)}@Override
        protected void doing(a) throws Exception {
            drive.lpop(listName)
        }

        @Override
        ThreadBase clone(a) {
            return new FunTester(this.limit)
        }
    }

}

Copy the code

The test results

~ ☢ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ~ JSON ~ ☢ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ~ > {> (1)."rt":172> 1)."failRate":0.0> 1)."threads":20> 1)."deviation":"0.25%"> 1)."errorRate":0.0> 1)."executeTotal":7912> 1)."qps2":115.98962074677847> 1)."total":7912> 1)."qps":116.27906976744185> 1)."startTime":"The 2021-09-16 16:08:43"> 1)."endTime":"The 2021-09-16 16:09:51"> 1)."mark":"Redis test practice,list retrieves and deletes test 161608 from scratch"> 1)."table":"eJzj5VLAD4pSUzKLn23tfrF+6tN1815s36qTk1lc8mR339MlW170bX/aP+3pzm1POxa8nLkEokrByEChJKMoNTGFgMkKvFy8+G0PSi0uyM8rTlUIycxNtVK o0C1OLcpMzFHIK83VUajUzQU6LTGPkB2EXKGgkJuZpwAxy8rQxFght1gnN7HCysjMAsgkrJugLygFj6Z1ABFRPhm1ZdSWkW3Lo2ntQERzmx5NawYimDVUt+3 RtEYgAlJNQISgWoAIzYcUuQDdGqifoNa0AhGCglqK227iKbyuhLsJn2Mosp56rh/0biXRV0SksKFJ8XINCmeM+nDUh6M+HHhnjPpw1IejPhx4Z4z6cNSHoz4 ceGeM+nDUh6M+HHhn0NSHAKoNkl0=">} ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ~ JSON ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~Copy the code

Scenario 3

class RedisList03 extends RedisBase {

    static AtomicInteger num = new AtomicInteger(0)

    static RedisBase drive

    public static void main(String[] args) {
        String host = "FunTester"
        int port = 6379
        drive = new RedisBase(host, port)
        int times = 100
        int thread = 20
        Constant.RUNUP_TIME = 0
        def tester = new FunTester(times)

        def task = new Concurrent(tester, thread, "Redis test practice,list gets and deletes tests from tail")
        task.start()

        drive.close()
    }

    private static class FunTester extends FixedThread {

        String listName = DEFAULT_STRING + num.getAndIncrement()

        FunTester(int limit) {
            super(null, limit, true)}@Override
        protected void doing(a) throws Exception {
            def a = Time.getTimeStamp() + StringUtil.getString(10)
            def b = Time.getTimeStamp() + StringUtil.getString(10)
            drive.lpush(listName, a)
            drive.rpush(listName, b)
            def c = drive.lpop(listName)
            def d = drive.rpop(listName)
            if(a ! = c || b ! = d) com.funtester.base.exception.FailException.fail(this.threadName + "Verification failed!")}@Override
        ThreadBase clone(a) {
            return new FunTester(this.limit)
        }
    }

}
Copy the code

The test results

Progress bar interception:

INFO-> Redis test practice,list from the end to get and delete test progress: Man man5%, current QPS:33INFO-> Redis test practice,list from the end to obtain and delete the test progress: Man man Man10%, current QPS:30INFO-> Redis test practice,list from the end to obtain and delete the test progress: Man man man man15%, current QPS:32INFO-> Redis test practice,list from the end to obtain and delete the test progress: All this all this all this all this19%, current QPS:31INFO-> Redis test practice,list from the end to obtain and delete the test progress: All this all this all this all this all this24%, current QPS:31The INFO - > redis test practice, the list and delete test schedule was obtained from the tail: ▍ ▍ ▍ ▍ ▍ ▍ ▍ ▍ ▍ ▍ ▍ ▍ ▍ ▍ ▍ ▍ ▍ ▍28%, current QPS:30
Copy the code

It can be seen that QPS is about 1/4 of the test result of single operation, which is relatively in line with expectations.

QPS change curve:

Test results:

~ ☢ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ~ JSON ~ ☢ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ~ > {> (1). "rt" : 673, > 1). The "failRate" : 0.0, "Deviation ":"0.55%", > ①. "errorRate":0.0, > ①. "executeTotal":1981 > ①. "qps2":29.55481291400609, > ①. "total":1981, > > 1). "startTime" : "the 2021-09-16 16:23:31" > (1). The "endTime" : "the 2021-09-16 16:24:38", > < span style = "max-width: 100%; clear: both; min-height: 1em; > 1). "table":"eJzj5VLAD4pSUzKLn23tfrF+6tN1815s36qTk1lc8mR339MN+170bX/aP+3pzm1POxa8nLkEokrByEChJKMoNTGFgMkKvFy8+G0PSi0uyM8rTlU IycxNtVKo0C1OLcpMzFHIK83VUajUzQU6LTGPkB2EXKGgkJuZpwAxy8rU3Ewht1gnN7HCysLUGMgkrJugLygFj6Z1ABFRPhm1ZYjb8mhaIxABqSYgQlDNQAS kWoAIZi0ltqPbAjW3FYgQVDsQoVlGMkXIdXCHoHqQ+g6h0OX43TkgDiTPR3CPoPpgEDiPYt9hzR7DiAL5cBA4Y9SHoz4c9eHAO2PUh6M+HPXhwDtj1IejPhz 14 ca7y9shoz4c9ehao2puh6m + HPXhwDuDpj4EAOQLudM = ">} ~ ☢ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ~ JSON ~ ☢ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~ ~ ☢ ☢ ~ ~ ~Copy the code

Response time distribution diagram:

conclusion

In writing the FunTester test framework to perform performance tests on Redis in this series. There are some fans. To talk to me is to ask what is the actual application scenario? This is because during the testing process, there are very few cases where Redis performance is quiet or needs to be tuned. It is generally considered that the ready performance is very fast, only to the CPU, memory, bandwidth will become ready calm. However, some extreme cases, such as Redis key distribution and Redis data store design, can lead to system performance calm. I personally don’t have much experience with ready’s type of blending either. The main reason for writing this tutorial is that there are several alternatives to the Redis storage design, and performance testing engineers are needed to help validate the performance metrics of these alternatives in different scenarios.

Have Fun ~ Tester!

  • FunTester test framework architecture diagram
  • JMeter Chinese Operation Manual with a sense of time
  • 140 interview questions (UI, Linux, MySQL, API, security)
  • FunTester Framework Tutorial
  • HTTP Interface Testing Basics
  • Tease the interface documentation together
  • Client encapsulation based on WebSocket
  • Pressure test results were corrected using microreference tests
  • Selenium4 Alpha-7 Upgrade experience
  • In manometry, the delay of asynchronous write interfaces is measured
  • LT browser – responsive web testing tool
  • Format the JSON data for output to the console
  • Java NIO is used in interface automation
  • Android APP test knowledge 【 interview reserve 】
  • Unit testing frameworks spock and Mockito applications