zhou zhou
昨天 464116335cba47ddce55ee3a4ddc87af7fee5d15
#redis降级
1个文件已修改
674 ■■■■■ 已修改文件
rsf-server/src/main/java/com/vincent/rsf/server/common/service/RedisService.java 674 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
rsf-server/src/main/java/com/vincent/rsf/server/common/service/RedisService.java
@@ -20,473 +20,303 @@
@Service
public class RedisService {
    private static final String LINK = ".";
    private static final String LINK = ".";
    private static final long MIN_DEGRADE_WINDOW_MS = 30000L;
    protected JedisPool pool;
    protected volatile JedisPool pool;
    Integer index = 0;
    Integer index = 0;
    public Boolean initialize = true;
    public volatile Boolean initialize = true;
    @Autowired
    private RedisProperties redisProperties;
    private volatile long degradedUntilMillis = 0L;
    public JedisPool getPool() {
        if (null == this.pool) {
            JedisPoolConfig config = new JedisPoolConfig();
            config.setTestOnBorrow(false);
            this.index = redisProperties.getIndex();
            this.pool = new JedisPool(config
                    , redisProperties.getHost()
                    , redisProperties.getPort()
                    , redisProperties.getTimeout()
                    , redisProperties.getPassword()
            );
        }
        return this.pool;
    }
    @Autowired
    private RedisProperties redisProperties;
    public Jedis getJedis(){
        try{
            Jedis jedis = this.getPool().getResource();
    public synchronized JedisPool getPool() {
        if (this.pool == null) {
            JedisPoolConfig config = new JedisPoolConfig();
            config.setTestOnBorrow(false);
            this.index = redisProperties.getIndex();
            this.pool = new JedisPool(config,
                    redisProperties.getHost(),
                    redisProperties.getPort(),
                    redisProperties.getTimeout(),
                    redisProperties.getPassword()
            );
        }
        return this.pool;
    }
            if(this.index != jedis.getDB()) {
                jedis.select(this.index);
            }
            return jedis;
        } catch (Exception e){
            log.error(this.getClass().getSimpleName(), e);
        }
        return null;
    }
    public Jedis getJedis() {
        if (isDegradedNow()) {
            return null;
        }
        try {
            Jedis jedis = this.getPool().getResource();
            if (this.index != jedis.getDB()) {
                jedis.select(this.index);
            }
            markRecovered();
            return jedis;
        } catch (Exception e) {
            markUnavailable(e);
        }
        return null;
    }
    // key - object ----------------------------------------------------------------------------------------------------------
    // key - object ----------------------------------------------------------------------------------------------------------
    public String set(String flag, String key, Object value) {
        if(!this.initialize) {
            return null;
        }
        if(null == value) {
            this.delete(flag, key);
            return null;
        }
        Jedis jedis = this.getJedis();
        try{
            return jedis.set((flag + LINK + key).getBytes(), Serialize.serialize(value));
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
        }
        return null;
    }
    public String set(String flag, String key, Object value) {
        if (value == null) {
            this.delete(flag, key);
            return null;
        }
        return execute(null, jedis -> jedis.set((flag + LINK + key).getBytes(), Serialize.serialize(value)));
    }
    public String set(String flag, String key, Object value, Integer seconds) {
        if(!this.initialize) {
            return null;
        }
        if (null == value) {
            this.delete(flag, key);
            return null;
        }
        Jedis jedis = this.getJedis();
        try{
            return jedis.setex((flag + LINK + key).getBytes(), seconds, Serialize.serialize(value));
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
        }
        return null;
    }
    public String set(String flag, String key, Object value, Integer seconds) {
        if (value == null) {
            this.delete(flag, key);
            return null;
        }
        return execute(null, jedis -> jedis.setex((flag + LINK + key).getBytes(), seconds, Serialize.serialize(value)));
    }
    public <T> T get(String flag, String key) {
        if(!this.initialize) {
            return null;
        }
        Jedis jedis = this.getJedis();
        try{
            byte[] bytes = jedis.get((flag + LINK + key).getBytes());
            if(bytes == null || bytes.length == 0 ) {
                return null;
            }
            return (T) Serialize.unSerialize(bytes);
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
        }
        return null;
    }
    public <T> T get(String flag, String key) {
        return execute(null, jedis -> {
            byte[] bytes = jedis.get((flag + LINK + key).getBytes());
            if (bytes == null || bytes.length == 0) {
                return null;
            }
            return (T) Serialize.unSerialize(bytes);
        });
    }
    public Long delete(String flag, String key) {
        if(!this.initialize) {
            return null;
        }
        Jedis jedis = this.getJedis();
        try{
            return jedis.del((flag + LINK + key).getBytes());
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
        }
        return null;
    }
    public Long delete(String flag, String key) {
        return execute(null, jedis -> jedis.del((flag + LINK + key).getBytes()));
    }
    public Long clear(String flag) {
        if(!this.initialize) {
            return null;
        }
        Jedis jedis = this.getJedis();
        this.setValue(flag, "CLEARING", "true");
        try{
            Object returnValue = jedis.eval("local keys = redis.call('keys', ARGV[1]) for i=1,#keys,1000 do redis.call('del', unpack(keys, i, math.min(i+4999, #keys))) end return #keys",0,flag + LINK + "*");
            return Long.parseLong(String.valueOf(returnValue));
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
        }
        return null;
    }
    public Long clear(String flag) {
        this.setValue(flag, "CLEARING", "true");
        return execute(null, jedis -> {
            Object returnValue = jedis.eval("local keys = redis.call('keys', ARGV[1]) for i=1,#keys,1000 do redis.call('del', unpack(keys, i, math.min(i+4999, #keys))) end return #keys", 0, flag + LINK + "*");
            return Long.parseLong(String.valueOf(returnValue));
        });
    }
    // 为已存在的key设置过期时间 - 秒
    public void setExpire(String flag, String key, int seconds){
        if(!this.initialize) {
            return;
        }
        Jedis jedis = this.getJedis();
        try{
            jedis.expire((flag + LINK + key).getBytes(), seconds);
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
        }
    }
    // 为已存在的key设置过期时间 - 秒
    public void setExpire(String flag, String key, int seconds) {
        executeVoid(jedis -> jedis.expire((flag + LINK + key).getBytes(), seconds));
    }
    // 为已存在的key设置过期时间 - 具体到时间戳 (秒)
    public void setExpireAt(String flag, String key, Date toTime){
        if(!this.initialize) {
            return;
        }
        Jedis jedis = this.getJedis();
        try{
            jedis.expireAt((flag + LINK + key).getBytes(), toTime.getTime()/1000);
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
        }
    }
    // 为已存在的key设置过期时间 - 具体到时间戳 (秒)
    public void setExpireAt(String flag, String key, Date toTime) {
        executeVoid(jedis -> jedis.expireAt((flag + LINK + key).getBytes(), toTime.getTime() / 1000));
    }
    // 获取过期剩余时间(秒) ttl == -1 没有设置过期时间; ttl == -2 key不存在
    public Long getExpire(String flag, String key) {
        if(!this.initialize) {
            return null;
        }
        Jedis jedis = this.getJedis();
        try{
            return jedis.ttl((flag + LINK + key).getBytes());
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
        }
        return null;
    }
    // 获取过期剩余时间(秒) ttl == -1 没有设置过期时间; ttl == -2 key不存在
    public Long getExpire(String flag, String key) {
        return execute(null, jedis -> jedis.ttl((flag + LINK + key).getBytes()));
    }
    // key - string ----------------------------------------------------------------------------------------------------------
    // key - string ----------------------------------------------------------------------------------------------------------
    public String setValue(String flag, String key, String value) {
        if(!this.initialize) {
            return null;
        }
        Jedis jedis = this.getJedis();
        try{
            return jedis.set(flag + LINK + key, value);
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
        }
        return null;
    }
    public String setValue(String flag, String key, String value) {
        return execute(null, jedis -> jedis.set(flag + LINK + key, value));
    }
    public String setValue(String flag, String key, String value, Integer seconds) {
        if(!this.initialize) {
            return null;
        }
        Jedis jedis = this.getJedis();
        try{
            return jedis.setex(flag + LINK + key, seconds , value);
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
        }
        return null;
    }
    public String setValue(String flag, String key, String value, Integer seconds) {
        return execute(null, jedis -> jedis.setex(flag + LINK + key, seconds, value));
    }
    public String getValue(String flag, String key) {
        if(!this.initialize) {
            return null;
        }
        Jedis jedis = this.getJedis();
        try{
            return jedis.get(flag + LINK + key);
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
        }
        return null;
    }
    public String getValue(String flag, String key) {
        return execute(null, jedis -> jedis.get(flag + LINK + key));
    }
    public Long deleteValue(String flag, String... key) {
        if(!this.initialize) {
            return null;
        }
    public Long deleteValue(String flag, String... key) {
        return execute(null, jedis -> {
            String[] keys = new String[key.length];
            for (int i = 0; i < key.length; i++) {
                keys[i] = flag + LINK + key[i];
            }
            return jedis.del(keys);
        });
    }
        Jedis jedis = this.getJedis();
        try{
            String[] keys = new String[key.length];
            for(int i=0;i<key.length;i++){
                keys[i] = flag + LINK + key[i];
            }
            return jedis.del(keys);
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
        }
        return null;
    }
    public Long clearValue(String flag) {
        this.setValue(flag, "CLEARING", "true");
        return execute(null, jedis -> {
            Object returnValue = jedis.eval("return redis.call('del', unpack(redis.call('keys', ARGV[1])))", 0, flag + LINK + "*");
            return Long.parseLong(String.valueOf(returnValue));
        });
    }
    public Long clearValue(String flag) {
        if(!this.initialize) {
            return null;
        }
    public void setValueExpire(String flag, String key, int seconds) {
        executeVoid(jedis -> jedis.expire((flag + LINK + key).getBytes(), seconds));
    }
        this.setValue(flag, "CLEARING", "true");
        Jedis jedis = this.getJedis();
        try{
            Object returnValue = jedis.eval("return redis.call('del', unpack(redis.call('keys', ARGV[1])))",0,flag + LINK + "*");
            return Long.parseLong(String.valueOf(returnValue));
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
        }
        return null;
    }
    public void setValueExpire(String flag, String key,int seconds){
        if(!this.initialize) {
            return;
        }
        Jedis jedis = this.getJedis();
        try{
            jedis.expire((flag + LINK + key).getBytes(), seconds);
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
        }
    }
    public void setValueExpireAt(String flag, String key,Date atTime){
        if(!this.initialize) {
            return;
        }
        Jedis jedis = this.getJedis();
        try{
            jedis.expireAt((flag + LINK + key).getBytes(), atTime.getTime()/1000);
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
        }
    }
    public void setValueExpireAt(String flag, String key, Date atTime) {
        executeVoid(jedis -> jedis.expireAt((flag + LINK + key).getBytes(), atTime.getTime() / 1000));
    }
    // hash ----------------------------------------------------------------------------------------------------------
    // hash ----------------------------------------------------------------------------------------------------------
    public Long setMap(String name, String key, Object value) {
        if(!this.initialize) {
            return null;
        }
        if(value == null){
            deleteMap(name,key);
            return null;
        }
        Jedis jedis = this.getJedis();
        try {
            return jedis.hset(name.getBytes(), key.getBytes(), Serialize.serialize(value));
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
        }
        return null;
    }
    public Long setMap(String name, String key, Object value) {
        if (value == null) {
            deleteMap(name, key);
            return null;
        }
        return execute(null, jedis -> jedis.hset(name.getBytes(), key.getBytes(), Serialize.serialize(value)));
    }
    public <T> T getMap(String name, String key) {
        if(!this.initialize) {
            return null;
        }
        Jedis jedis = this.getJedis();
        try{
            byte[] bytes = jedis.hget(name.getBytes(), key.getBytes());
            if (bytes == null || bytes.length == 0) {
                return null;
            }
            return (T) Serialize.unSerialize(bytes);
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
        }
        return null;
    }
    public <T> T getMap(String name, String key) {
        return execute(null, jedis -> {
            byte[] bytes = jedis.hget(name.getBytes(), key.getBytes());
            if (bytes == null || bytes.length == 0) {
                return null;
            }
            return (T) Serialize.unSerialize(bytes);
        });
    }
    public Set<String> getMapKeys(String name) {
        if(!this.initialize) {
            return null;
        }
        Jedis jedis = this.getJedis();
        try{
            return jedis.hkeys(name);
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
        }
        return null;
    }
    public Set<String> getMapKeys(String name) {
        return execute(null, jedis -> jedis.hkeys(name));
    }
    public Long deleteMap(String name, String... key) {
        if(!this.initialize) {
            return null;
        }
        Jedis jedis = this.getJedis();
        try{
            String[] keys = new String[key.length];
    public Long deleteMap(String name, String... key) {
        return execute(null, jedis -> {
            String[] keys = new String[key.length];
            System.arraycopy(key, 0, keys, 0, key.length);
            return jedis.hdel(name, keys);
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
        }
        return null;
    }
        });
    }
    public Long clearMap(String name) {
        if(!this.initialize) {
            return null;
        }
        Jedis jedis = this.getJedis();
        try{
            return jedis.del(name);
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
        }
        return null;
    }
    public Long clearMap(String name) {
        return execute(null, jedis -> jedis.del(name));
    }
    public void setMapExpire(String name,int seconds){
        if(!this.initialize) {
            return;
        }
        Jedis jedis = this.getJedis();
        try{
            jedis.expire(name.getBytes(), seconds);
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
        }
    }
    public void setMapExpire(String name, int seconds) {
        executeVoid(jedis -> jedis.expire(name.getBytes(), seconds));
    }
    public void setMapExpireAt(String name,Date atTime){
        if(!this.initialize) {
            return;
        }
        Jedis jedis = this.getJedis();
        try{
            jedis.expireAt(name.getBytes(), atTime.getTime()/1000);
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
        }
    }
    public void setMapExpireAt(String name, Date atTime) {
        executeVoid(jedis -> jedis.expireAt(name.getBytes(), atTime.getTime() / 1000));
    }
    // mq ----------------------------------------------------------------------------------------------------------
    // mq ----------------------------------------------------------------------------------------------------------
    // 列表末尾添加元素
    public Long push(String name, Object value) {
        if(!this.initialize) {
            return null;
        }
        if(value == null){
            return null;
        }
        Jedis jedis = this.getJedis();
        try{
            return jedis.rpush(name.getBytes(), Serialize.serialize(value));
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
        }
        return null;
    }
    // 列表末尾添加元素
    public Long push(String name, Object value) {
        if (value == null) {
            return null;
        }
        return execute(null, jedis -> jedis.rpush(name.getBytes(), Serialize.serialize(value)));
    }
    // 获取列表头部元素 && 删除
    public <T> T pop(String name) {
        if(!this.initialize){
            return null;
        }
        Jedis jedis = this.getJedis();
        try{
            byte[] bytes = jedis.lpop(name.getBytes());
            if(bytes == null || bytes.length == 0) {
                return null;
            }
            return (T) Serialize.unSerialize(bytes);
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
        }
        return null;
    }
    // 获取列表头部元素 && 删除
    public <T> T pop(String name) {
        return execute(null, jedis -> {
            byte[] bytes = jedis.lpop(name.getBytes());
            if (bytes == null || bytes.length == 0) {
                return null;
            }
            return (T) Serialize.unSerialize(bytes);
        });
    }
    // 删除
    public Long deleteList(String name) {
        if(!this.initialize) {
            return null;
        }
        Jedis jedis = this.getJedis();
        try{
            return jedis.del(name);
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
        }
        return null;
    }
    // 删除
    public Long deleteList(String name) {
        return execute(null, jedis -> jedis.del(name));
    }
    public void setListExpire(String name, int seconds){
        if(!this.initialize) {
            return;
        }
        Jedis jedis = this.getJedis();
        try{
            jedis.expire(name.getBytes(), seconds);
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
        }
    }
    public void setListExpire(String name, int seconds) {
        executeVoid(jedis -> jedis.expire(name.getBytes(), seconds));
    }
    public void setListExpireAt(String name, Date atTime){
        if(!this.initialize) {
            return;
        }
        Jedis jedis = this.getJedis();
        try{
            jedis.expireAt(name.getBytes(), atTime.getTime()/1000);
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
        }
    }
    public void setListExpireAt(String name, Date atTime) {
        executeVoid(jedis -> jedis.expireAt(name.getBytes(), atTime.getTime() / 1000));
    }
    // count ----------------------------------------------------------------------------------------------------------
    // count ----------------------------------------------------------------------------------------------------------
    public Long incr(String key) {
        if(!this.initialize) {
            return null;
        }
        Jedis jedis = this.getJedis();
        try{
            return jedis.incr("COUNT." + key);
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
        }
        return null;
    }
    public Long incr(String key) {
        return execute(null, jedis -> jedis.incr("COUNT." + key));
    }
    public Long decr(String key) {
        if(!this.initialize) {
            return null;
        }
        Jedis jedis = this.getJedis();
        try{
            return jedis.decr("COUNT." + key);
        } catch (Exception e) {
            log.error(this.getClass().getSimpleName(), e);
        }
        return null;
    }
    public Long decr(String key) {
        return execute(null, jedis -> jedis.decr("COUNT." + key));
    }
    private boolean isDegradedNow() {
        return !Boolean.TRUE.equals(this.initialize) && System.currentTimeMillis() < this.degradedUntilMillis;
    }
    private void markRecovered() {
        if (Boolean.TRUE.equals(this.initialize)) {
            return;
        }
        synchronized (this) {
            if (Boolean.TRUE.equals(this.initialize)) {
                return;
            }
            this.initialize = true;
            this.degradedUntilMillis = 0L;
            log.info("Redis recovered, degrade mode cleared.");
        }
    }
    private void markUnavailable(Exception e) {
        long now = System.currentTimeMillis();
        long nextRetryAt = now + getDegradeWindowMillis();
        boolean shouldLog = Boolean.TRUE.equals(this.initialize) || now >= this.degradedUntilMillis;
        synchronized (this) {
            this.initialize = false;
            this.degradedUntilMillis = nextRetryAt;
        }
        if (shouldLog) {
            log.warn("Redis unavailable, degrade mode enabled until {}. message={}", new Date(nextRetryAt), e.getMessage());
        }
    }
    private long getDegradeWindowMillis() {
        return Math.max((long) redisProperties.getTimeout() * 2L, MIN_DEGRADE_WINDOW_MS);
    }
    private <T> T execute(T fallbackValue, RedisCallback<T> callback) {
        if (isDegradedNow()) {
            return fallbackValue;
        }
        Jedis jedis = getJedis();
        if (jedis == null) {
            return fallbackValue;
        }
        try (jedis) {
            return callback.doWithJedis(jedis);
        } catch (Exception e) {
            markUnavailable(e);
            return fallbackValue;
        }
    }
    private void executeVoid(RedisVoidCallback callback) {
        execute(null, jedis -> {
            callback.doWithJedis(jedis);
            return null;
        });
    }
    @FunctionalInterface
    private interface RedisCallback<T> {
        T doWithJedis(Jedis jedis) throws Exception;
    }
    @FunctionalInterface
    private interface RedisVoidCallback {
        void doWithJedis(Jedis jedis) throws Exception;
    }
}