[High Concurrency Solution] Jedis responds to high concurrency by operating pipelines, transactions, and watches

Keywords: Java Jedis Redis MySQL Database

For an Internet platform, high concurrency is a common scenario. The most representative ones are secondkill and snap-up. High concurrency has three characteristics:

1. High concurrent reading

2. High concurrent write (consistency)

3. Oversell

How does the front end respond?

1. Caching static data, such as pictures, html pages, js, etc.

2. Build load balancing cluster. At present, nginx is widely used.

3. Limit the number of requests initiated in the same ip unit time by restricting the number of ip requests. Or establish an ip blacklist to avoid malicious attacks

4. Consider system degradation. For example, when the system load is reached, a static processing page is returned.

How does the back end respond?

1. Use MySQL read-write separation, but when high concurrency, MySQL performance will be reduced. Generally speaking, the processing performance of MySQL will increase with concurrent threads, but after a certain degree of concurrency, there will be a significant inflection point, and then all the way down, eventually even worse than the performance of single threads. For example, the operation of adding or subtracting inventory usually has a low concurrency: update XXX set count = count-xx where curcount > xx; this can make full use of MySQL transaction locks to avoid oversold. However, when concurrency is increased, performance will be greatly degraded due to exclusive lock waiting.

2. Using redis database, pre-placed to mysql. The train of thought is as follows:

2.1 After the system is started, the sku information is initialized to redis database, and its usage and locking amount are recorded.

2.2 Optimistic lock and redis watch mechanism are used. The logic is:

1. Define the ticket number variable and set the initial value to 0. watchkey

2.watch the variable, watch(watchkey);

3. Use redis transaction to add or subtract inventory. Firstly, the availability and purchase volume are compared. If curcount > buycount, the inventory reduction and lock-in operations are normally performed.

 

Detailed description of Redis usage

1,Pipeline

pipeline is used to package multiple commands from client and issue them together without waiting for the response of a single command to return. Redis After processing many commands, the server packages the processing results of many commands together and returns them to the client. Therefore, pipeline is suitable for batch processing operations to improve efficiency, such as:

 

  1. public static void testMget() {  
  2.         Jedis jedis = RedisCacheClient.getInstrance().getClient();  
  3.         Set<String> keys = jedis.keys("cvfeedBackHandl_*");  
  4.         List<String> result = Lists.newArrayList();  
  5.         long t1 = System.currentTimeMillis();  
  6.         for (String key : keys) {  
  7.             result.add(jedis.get(key));  
  8.         }  
  9.         for (String src : result) {  
  10.             System.out.println(src);  
  11.         }  
  12.         System.out.println(System.currentTimeMillis() - t1);  
  13.     }  
  14.   
  15.     public static void testPipline() {  
  16.         Jedis jedis = RedisCacheClient.getInstrance().getClient();  
  17.         Set<String> keys = jedis.keys("cvfeedBackHandl_*");  
  18.         List<Object> result = Lists.newArrayList();  
  19.         Pipeline pipelined = jedis.pipelined();  
  20.         long t1 = System.currentTimeMillis();  
  21.         for (String key : keys) {  
  22.             pipelined.<span style="font-family: Arial;">get</span>("testabcd");  
  23.         }  
  24.         result = pipelined.syncAndReturnAll();  
  25.         for (Object src : result) {  
  26.             System.out.println(src);  
  27.         }  
  28.         System.out.println(System.currentTimeMillis() - t1);  
  29.     }  

For example, the execution time of the first method is 82ms

 

The second method takes 9 ms to execute

Note: Pipelines and transactions are asynchronous calls that return results, that is, they do not wait for each command to execute immediately, but wait for all commands to execute before returning results. pipelined.syncAndReturnAll() returns the result of each command that participates in the packaging execution. If the above is changed to:

 

  1. for (String key : keys) {//keys length is 5
  2.             pipelined.get(key);  
  3.             pipelined.del("testabcd");  
  4.  }  

The return result will be

 

 

  1. "test1"  
  2. 1  
  3. "test2"  
  4. 0  
  5. "test2"  
  6. 0  
  7. "test4"  
  8. 0  
  9. "test5"  
  10. 0  


2. Affairs

 

Transaction is to ensure that all commands in a transaction are atomic operations. Generally, it cooperates with watch. Transaction execution results are obtained asynchronously just like pipeline. multi.exec() submits a transaction. If successful execution, the result returned by multi.exec() is the return value of all commands as pipeline does. If there are two commands in a transaction, then the exec return value of the transaction will be two. The return values of the commands are combined to return. If the transaction is cancelled, return null.

3,watch

Usually used with transactions, when a key is watched, if other clients change the key, then the transaction will be cancelled, and the exec of the transaction will return null. jedis.watch(key) returns OK
eg:

 

  1. public static void testWach(){  
  2.        Jedis jedis = RedisCacheClient.getInstrance().getClient();  
  3.        String watch = jedis.watch("testabcd");  
  4.        System.out.println(Thread.currentThread().getName()+"--"+watch);  
  5.        Transaction multi = jedis.multi();  
  6.        multi.set("testabcd", "23432");  
  7.        try {  
  8.            Thread.sleep(3000);  
  9.        } catch (InterruptedException e) {  
  10.            e.printStackTrace();  
  11.        }  
  12.        List<Object> exec = multi.exec();  
  13.        System.out.println("---"+exec);  
  14.        jedis.unwatch();  
  15.    }  
  16.    public static void testWatch2(){  
  17.        Jedis jedis = RedisCacheClient.getInstrance().getClient();  
  18.        String watch = jedis.watch("testabcd2");  
  19.        System.out.println(Thread.currentThread().getName()+"--"+watch);  
  20.        Transaction multi = jedis.multi();  
  21.        multi.set("testabcd", "125");  
  22.        List<Object> exec = multi.exec();  
  23.        System.out.println("--->>"+exec);  
  24.    }  

Thread-2--OK
Thread-0--OK
--->>[OK]

- null// transaction cancellation

4. Transaction and Management

When watch ing a key, the transaction can be cancelled if other clients change the key, but the pipeline cannot.

Posted by pdpullmn612 on Sat, 20 Apr 2019 14:39:33 -0700