Detailed use Redis + LUA to solve the problem of high concurrency of robbery of red envelopes _redis

Source: Internet
Author: User
Tags lua redis money back

The demand analysis of the red envelope robbery

The scene of the robbery is a bit like a second kill, but more simple than the second kill.

Because the second kill is usually related to inventory. And Rob Red envelopes can allow some red envelopes have not been robbed, because the people who send red envelopes will not have to lose, not to rob the money back to send a red envelope people can.

In addition, such as Millet to buy more simple than Taobao, but also because such as Millet is a company, if a small number did not Rob, the next time to rob, manual repair of the data is very simple. And like Taobao so many goods, if each has the risk of repairing data, then if the fault is very troublesome.

The scheme of red envelopes based on Redis

Here is a scheme based on Redis to rob red envelopes.

The original red envelopes are called Big Red envelopes, and the red envelopes after the split are called small red envelopes.

1. Small red envelopes are generated beforehand, inserted into the database, the red envelopes corresponding to the user ID is null. Build algorithm See another article: http://www.jb51.net/article/98620.htm

2. Each big red envelope corresponds to two redis queues, one is the unpaid red envelope queue, the other is the red envelope. At the beginning, put all the little red envelopes that were not robbed into a queue of unpaid red envelopes.

The unused red envelopes are JSON strings, such as {userId: ' 789 ', Money: ' 300 '}.

3. Use a map in the Redis to filter the users who have robbed the red envelopes.

4. Rob Red Envelopes, the first judge whether the user robbed red envelopes, if not, then never a red envelope to take out a small red envelope, and then push to another consumption queue, and finally put the user ID into the heavy map.

5. Use a single thread batch to take out the red envelopes in the consumption queue, and then batch update the user ID of the red envelopes into the database.

The above process is very clear, but in the 4th step, if the user quickly ordered two times, or opened two browser to rob Red envelopes, will it be possible for users to grab two red envelopes?

To solve this problem, the Lua script was adopted, allowing the entire process of step 4th to be executed atomically.

The following is a LUA script executed on the Redis:

--function: Try to get a red envelope, if successful, return the JSON string, if unsuccessful, return null 
--parameter: Red envelope queue name, consumed queue name, go to heavy map name, user ID 
--return value: Nil or JSON string, Contains user Id:userid, red envelope id:id, red envelope amount: Money 
 
-If the user has robbed a red envelope, return nil if 
rediscall (' hexists ', keys[3], keys[4]) ~= 0 Then 
 return nil 
Else 
 --First take out a small red envelope local 
 Hongbao = Rediscall (' Rpop ', keys[1]); 
 If Hongbao then local 
  x = Cjsondecode (Hongbao); 
  --Adding User ID information 
  x[' userId ' = keys[4]; 
  local re = Cjsonencode (x); 
  --Put the user ID in the heavy set 
  rediscall (' Hset ', keys[3], keys[4], keys[4); 
  --Put the red envelopes in the consumption queue 
  rediscall (' Lpush ', keys[2], re); 
  return re; 
 End End 
 

Here is the test code:

public class Testeval {static String host = ' localhost '; 
   
  static int honbaocount = 1_0_0000; 
   
  static int threadcount = 20; 
  static String hongbaolist = "Hongbaolist"; 
  static String hongbaoconsumedlist = "Hongbaoconsumedlist"; 
   
  static String Hongbaoconsumedmap = "Hongbaoconsumedmap"; 
   
static Random Random = new Random (); --function: Try to get a red envelope, if successful, returns the JSON string, if unsuccessful, returns the null//--parameter: Red envelope queue name, consumed queue name, go to heavy map name, User ID//-return value: Nil or JSON string containing user Id:userid, red Packet Id:id, red envelope amount: money static String Trygethongbaoscript =//"Local bconsumed = Rediscall (' hexists ', keys[3], keys[4] 
      \ n "//+" print (' bconsumed: ', bconsumed); \ n "" If Rediscall (' hexists ', keys[3], keys[4]) ~= 0 then\n " + "return nil\n" + "else\n" + "local Hongbao = Rediscall (' Rpop ', keys[1]) \ n"//+ "print (' Hongbao: ', h 
      Ongbao); \ n "+" if Hongbao then\n "+" local x = Cjsondecode (hongbao); \ n "+" x[' userId '] = keys[4];\n " + "Local re = Cjsonencode (x); \ n "+" Rediscall (' Hset ', keys[3], keys[4], keys[4]) \ n "+" Rediscall (' Lpush ', keys[2], re); \ n "+" 
  return re;\n "+" end\n "+" end\n "+" return nil "; 
   
  Static Stopwatch watch = new stopwatch (); 
    public static void Main (string[] args) throws Interruptedexception {//Testeval (); 
    Generatetestdata (); 
  Testtrygethongbao (); 
    The static public void Generatetestdata () throws interruptedexception {Jedis Jedis = new Jedis (host); 
    Jedisflushall (); 
    Final Countdownlatch latch = new Countdownlatch (threadcount); 
      for (int i = 0; i < ThreadCount ++i) {Final int temp = i; 
          Thread thread = new Thread () {public void run () {Jedis Jedis = new Jedis (host); 
          int per = Honbaocount/threadcount; 
          Jsonobject object = new Jsonobject (); 
            for (int j = Temp */J < (temp+1) * per; J + +) {objectput ("id", j); Objectput ("Money", j);
            Jedislpush (Hongbaolist, objecttojsonstring ()); 
        } latchcountdown (); 
      } 
      }; 
    ThreadStart (); 
  } latchawait (); static public void Testtrygethongbao () throws interruptedexception {final Countdownlatch latch = new COUNTD 
    Ownlatch (ThreadCount); 
    Systemerrprintln ("Start:" + Systemcurrenttimemillis ()/1000); 
    Watchstart (); 
      for (int i = 0; i < ThreadCount ++i) {Final int temp = i; 
          Thread thread = new Thread () {public void run () {Jedis Jedis = new Jedis (host); 
          String sha = Jedisscriptload (Trygethongbaoscript); 
          Int j = Honbaocount/threadcount * TEMP; while (true) {object = Jediseval (Trygethongbaoscript, 4, Hongbaolist, Hongbaoconsumedlist, hongbaocons 
            Umedmap, "" + j); 
            j + +; 
            if (object!= null) {//Systemoutprintln ("Get Hongbao:" + object); }else {//has finished the IF (Jedisllen (hongbaolist) = = 0) break; 
        } latchcountdown (); 
      } 
      }; 
    ThreadStart (); 
    } latchawait (); 
     
    Watchstop (); 
    Systemerrprintln ("Time:" + watchgettotaltimeseconds ()); 
    Systemerrprintln ("Speed:" + honbaocount/watchgettotaltimeseconds ()); 
  Systemerrprintln ("End:" + Systemcurrenttimemillis ()/1000); 
 } 
}

Test results of 20 threads, can rob 25,000 per second, enough to deal with most of the red envelopes scene.

If it is really unable to cope, split into a few redis clusters, or to bulk rob red envelopes, but also enough to deal with.

Summarize:

Redis's scheme, although in extreme cases (that is, Redis hang out) will lose a second of data, but it is a strong enough to cope with the high concurrent Robbery scheme.

The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.