[High concurrency solution] Jedis processes pipelines, transactions, and watches to cope with high concurrency. jediswatch
For an Internet platform, high concurrency is a common scenario. The most representative are seckilling and flash sales. High concurrency has three features:
1. High-concurrency reading
2. High-concurrency write (consistency)
3. An overselling problem occurs.
How should the front-end respond?
1. cache static data, examples, html pages, js, etc.
2. Build a Server Load balancer cluster. Currently, nginx is widely used.
3. restrict the number of requests initiated by the same ip address per unit time. Or create 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 backend respond?
1. mysql read/write splitting is adopted, but mysql performance will decrease when high concurrency occurs. In general, the processing performance of MySQL will increase with the increase of concurrent threads, but after a certain degree of concurrency, there will be a significant inflection point, and then all the way down, in the end, the performance may be worse than that of a single thread. For example, for operations on stock addition and subtraction, the usual method of low concurrency is: update xxx set count = count-xx where curcount> xx; in this way, mysql transaction locks can be fully utilized to avoid overselling. However, when the concurrency is reached, the performance will be greatly reduced due to exclusive lock wait.
2. Use the redis database and move it to mysql. The idea is as follows:
2.1 After the system is started, initialize the sku information to the redis database and record the available quantity and lock quantity.
2.2 Use optimistic locks and the redis watch mechanism. Logic:
1. Define the variable ticket number and set the initial value to 0. Watchkey
2. watch this variable, watch (watchkey );
3. Use the redis transaction to add or subtract inventory. First, compare the available quantity with the purchased quantity. If curcount> buycount, perform the inventory reduction and lock quantification operations normally:
Redis Usage Details
1. Pipeline
Using pipeline to Package Multiple commands from the client and send them together, you do not need to wait for the response of a single command to return, the Redis server will pack the processing results of multiple commands and return them to the client after processing multiple commands. Therefore, pipeline is suitable for batch processing jobs to improve efficiency, for example:
[Java]View plain copy print?
- Public static void testMget (){
- Jedis jedis = RedisCacheClient. getpolicance (). getClient ();
- Set <String> keys = jedis. keys ("cvfeedBackHandl _*");
- List <String> result = Lists. newArrayList ();
- Long t1 = System. currentTimeMillis ();
- For (String key: keys ){
- Result. add (jedis. get (key ));
- }
- For (String src: result ){
- System. out. println (src );
- }
- System. out. println (System. currentTimeMillis ()-t1 );
- }
- Public static void testPipline (){
- Jedis jedis = RedisCacheClient. getpolicance (). getClient ();
- Set <String> keys = jedis. keys ("cvfeedBackHandl _*");
- List <Object> result = Lists. newArrayList ();
- Pipeline pipelined = jedis. pipelined ();
- Long t1 = System. currentTimeMillis ();
- For (String key: keys ){
- Pipelined. <span style = "font-family: Arial;"> get </span> ("testabcd ");
- }
- Result = pipelined. syncAndReturnAll ();
- For (Object src: result ){
- System. out. println (src );
- }
- System. out. println (System. currentTimeMillis ()-t1 );
- }
For example, the execution time of the first method is 82 ms.
The execution time of the second method is 9 ms.
Note: Both pipeline and transactions return results asynchronously, that is, they do not wait for the result to be returned immediately after each command is executed, but return the result after all commands are executed. Pipelined. syncAndReturnAll () returns the results of each command involved in packaging and execution. If it is changed:
[Java]View plain copy print?
- For (String key: keys) {// The length of keys is 5
- Pipelined. get (key );
- Pipelined. del ("testabcd ");
- }
The returned result will be
[Java]View plain copy print?
- "Test1"
- 1
- "Test2"
- 0
- "Test2"
- 0
- "Test4"
- 0
- "Test5"
- 0
2. Transactions
Commit c () commits a transaction. If the execution is successful, the returned result is the same as that of pipeline, if there are two commands in the transaction, the exec return value of the transaction will combine the return values of the two commands and return them together. If the transaction is canceled, null is returned.
3. watch
It is generally used together with the transaction. After a key is watched, if other clients change the key, the transaction will be canceled and the exec of the transaction will return null. Jedis. watch (key) returns OK
Eg:
[Java]View plain copy print?
- Public static void testWach (){
- Jedis jedis = RedisCacheClient. getpolicance (). getClient ();
- String watch = jedis. watch ("testabcd ");
- System. out. println (Thread. currentThread (). getName () + "--" + watch );
- Transaction multi = jedis. multi ();
- Multi. set ("testabcd", "23432 ");
- Try {
- Thread. sleep (3000 );
- } Catch (InterruptedException e ){
- E. printStackTrace ();
- }
- List <Object> exec = multi.exe c ();
- System. out. println ("---" + exec );
- Jedis. unwatch ();
- }
- Public static void testWatch2 (){
- Jedis jedis = RedisCacheClient. getpolicance (). getClient ();
- String watch = jedis. watch ("testabcd2 ");
- System. out. println (Thread. currentThread (). getName () + "--" + watch );
- Transaction multi = jedis. multi ();
- Multi. set ("testabcd", "125 ");
- List <Object> exec = multi.exe c ();
- System. out. println ("--->" + exec );
- }
Thread-2 -- OK
Thread-0 -- OK
---> [OK]
--- Null // cancel the transaction
4. Transactions and Pipelines
When you watch a key, if another client changes the key, you can cancel the transaction, but the pipeline is not.