redis实现访问限制

来源:互联网 发布:淘宝开店要注册公司吗 编辑:程序博客网 时间:2024/05/29 19:05
package redis;import redis.clients.jedis.HostAndPort;import redis.clients.jedis.JedisCluster;import java.util.Arrays;import java.util.HashSet;import java.util.Set;public class RedisLimit {    private JedisCluster jedisCluster;    private String key;    /**     * 限制次数     */    private int limit;    /**     * 限制时间 毫秒     */    private long expire;    private static final String LUA_SIMPLE_CHECK = " local size = redis.call('get',KEYS[1]) " +            " if size and tonumber(size) >= tonumber(ARGV[1]) then " +            "    return 1 " +            " end " +            " local incr = redis.call('incr',KEYS[1]) " +            " if incr == 1 then " +            "    redis.call('pexpire',KEYS[1],ARGV[2]) " +            " end " +            " return 0 ";    private static String luaSimpleCheckSha;    private static final String LUA_PRECISE_CHECK = " local size = redis.call('llen',KEYS[1]) " +            " local timeNow = tonumber(ARGV[3])" +            " if size >= tonumber(ARGV[1]) then " +            "    local tiemOld = redis.call('lpop',KEYS[1]) " +            "    redis.call('rpush',KEYS[1],timeNow) " +            "    if timeNow - tonumber(tiemOld) < tonumber(ARGV[2]) then" +            "       return 1 " +            "    else " +            "       return 0" +            "    end " +            " end " +            " redis.call('rpush',KEYS[1],timeNow)" +            " return 0";    private static String luaPreciseCheckSha;    public RedisLimit(JedisCluster jedisCluster, String key, int limit, int expire) {        this.jedisCluster = jedisCluster;        this.key = key;        this.limit = limit;        this.expire = expire;    }    /**     * 在给定的时间内限制访问多少次。如果超过了则返回true     * 简单判断不够准确 优点存储数据量低     * 这些操作不是原子性的     */    public boolean simpleCheck() {        String sizeStr = jedisCluster.get(key);        if (sizeStr != null && Long.valueOf(sizeStr) >= limit) {            return true;        }        Long incr = jedisCluster.incr(key);        if (incr == 1) {            jedisCluster.pexpire(key, expire);        }        return false;    }    /**     * 在给定的时间内限制访问多少次。如果超过了则返回true     * 简单判断不够准确 优点存储数据量低     * 通过lua实现原子性操作     */    public boolean simpelCheckByLua() {        if (luaSimpleCheckSha == null) {            luaSimpleCheckSha = jedisCluster.scriptLoad(LUA_SIMPLE_CHECK, "luaSimpleCheck");        }        Long eval;        try {            eval = (Long) jedisCluster.evalsha(luaSimpleCheckSha, Arrays.asList(key),                    Arrays.asList(String.valueOf(limit), String.valueOf(expire)));        } catch (Exception e) {            //TODO 打印日志            e.printStackTrace();            eval = (Long) jedisCluster.eval(LUA_SIMPLE_CHECK, Arrays.asList(key),                    Arrays.asList(String.valueOf(limit), String.valueOf(expire)));        }        return eval == 1;    }    /**     * 精确判断 缺点是存储数据量多 依赖服务器时间戳     */    public boolean preciseCheck() {        Long card = jedisCluster.llen(key);        if (card >= limit) {            //移除最早访问时间            String timeOld = jedisCluster.lpop(key);            //当前访问时间            long timeNow = System.currentTimeMillis();            jedisCluster.rpush(key, String.valueOf(timeNow));            if (timeNow - Long.valueOf(timeOld) < expire) {                return true;            } else {                return false;            }        }        long timeNow = System.currentTimeMillis();        jedisCluster.rpush(key, String.valueOf(timeNow));        return false;    }    public boolean preciseCheckByLua() {        if (luaPreciseCheckSha == null) {            luaPreciseCheckSha = jedisCluster.scriptLoad(LUA_PRECISE_CHECK, "luaPreciseCheck");        }        Long eval;        try {            eval = (Long) jedisCluster.evalsha(luaPreciseCheckSha, Arrays.asList(key),                    Arrays.asList(String.valueOf(limit), String.valueOf(expire), String.valueOf(System.currentTimeMillis())));        } catch (Exception e) {            //TODO 打印日志            e.printStackTrace();            eval = (Long) jedisCluster.eval(LUA_PRECISE_CHECK, Arrays.asList(key),                    Arrays.asList(String.valueOf(limit), String.valueOf(expire), String.valueOf(System.currentTimeMillis())));        }        return eval == 1;    }    public static void main(String[] args) {        HostAndPort hostAndPort1 = new HostAndPort("ip", 20621);        HostAndPort hostAndPort2 = new HostAndPort("ip", 20622);        HostAndPort hostAndPort3 = new HostAndPort("ip", 20622);        Set<HostAndPort> set = new HashSet<>();        set.add(hostAndPort1);        set.add(hostAndPort2);        set.add(hostAndPort3);        JedisCluster jedisCluster = new JedisCluster(set);        RedisLimit redisLimit = new RedisLimit(jedisCluster, "localhostzhpincr", 10, 100);        for (int i = 0; i < 50; i++) {            if (redisLimit.simpelCheckByLua()) {                System.out.println("超过限制");            } else {                System.out.println("可以执行");            }        }    }}
原创粉丝点击