做法

使用redis的lua脚本功能来限频
在redis中定时刷新系统时间来作为一个全局的时钟

限频脚本:

	/**
	 * 获取令牌的lua脚本
	 */
	public final static String SCRIPT = "local epoch = redis.call(\"hget\",KEYS[1],'Epoch');\n" +
			"local currentEpoch = tonumber(ARGV[1]);\n" +
			"if(epoch == false and currentEpoch ~= epoch) then\n" +
			"  redis.call('hset', KEYS[1], 'Epoch',currentEpoch);\n" +
			"  redis.call(\"hset\", KEYS[1],  'Count', tonumber(ARGV[2]));\n" +
			"  redis.call('pexpire', KEYS[1], 2000);\n" +
			"  return 1;\n" +
			"end;   \n" +
			"local currentCount = redis.call(\"HINCRBY\", KEYS[1],'Count', tonumber(ARGV[3]));\n" +
			"if(currentCount > 0) then  \n" +
			"  return 1;\n" +
			"else  \n" +
			"  return 2;\n" +
			"end;";

	/**
	 * 同步系统时间到redis 中的lua脚本
	 */
	public final static String SET_SYSTEM_TIME_SCRIPT = "local clientId = redis.call(\"hget\",KEYS[1],'Client'); \n" +
			"if (clientId == false or clientId == ARGV[1]) then \n" +
			"   redis.call('hset', KEYS[1], 'Client', ARGV[1]);\n" +
			"   redis.call('hset', KEYS[1], 'Time' ,ARGV[2]);\n" +
			"   redis.call('pexpire', KEYS[1], tonumber(ARGV[3]));\n" +
			"   return 1;\n" +
			"end;\n" +
			"return 2;";

java调用代码:

  List<String> keys = new ArrayList<String>();
  keys.add("JRateLimit-Key-" + source);
  
   List<String> args = new ArrayList<String>();
   args.add(currentEpoch + "");  //currentEpoch是通过获取全局时钟来做的
   args.add(permitsPerEpoch + "");
   args.add((0 - permits) + "");
  
  Object result = client.evalsha(LIMIT_LUA_SCRIPT_SHA, keys, args, false);  //result的类型即为lua脚本中的返回值类型,Long

策略

通过redis实现全局时钟
通过一次多取几个令牌放到内存中来解决超大调用频率导致的redis请求单机ops极限问题

posted on 2018-12-10 15:27  j.liu&nbsp;windliu  阅读(270)  评论(0编辑  收藏  举报