Redis系统缓存使用经验总结

Redis系统缓存使用经验总结

1、接口请求缓存,车机获取天气数据接口校验,licence为唯一标识

①请求到达去缓存获取以licence加前缀为key的车机信息 ② 车机信息为空查询数据库,将查询结果缓存起来,设置过期时间③查询结果为空时,以licence加前缀为key,在缓存中存储空对象,设置过期时间。防止相同不合法licence频繁访问(缓存中没有时要查询数据库)数据库(穿透现象),造成服务器压力。④请求到达时去缓存查询不为空时,设置licence对应key的过期时间

防止redis穿透,雪崩现象

Count count = RedisUtil.get(ApiConstant.PRE_LICENCE_KEY + "{" + requestParam.getLicence() + "}", Count.class);

if ( ApiUtil.isEmpty(count) ) {
    count = this.countDao.viewCountByLicence(requestParam.getLicence());
    RedisUtil.set(ApiConstant.PRE_LICENCE_KEY + "{" + requestParam.getLicence() + "}", JSON.toJSONString(count));
    RedisUtil.expire(ApiConstant.PRE_LICENCE_KEY + "{" + requestParam.getLicence() + "}", 2 * 24 * 60 * 60);
}
if ( ApiUtil.isEmpty(count) ) {
    //设置访问licence 空对象
    count.allProperties2Null();
    RedisUtil.set(ApiConstant.PRE_LICENCE_KEY + "{" + requestParam.getLicence() + "}", JSON.toJSONString(count));
    RedisUtil.expire(ApiConstant.PRE_LICENCE_KEY + "{" + requestParam.getLicence() + "}", 2 * 24 * 60 * 60);

    S6Base s6Base = new S6Base();
    s6Base.allProperties2Null();
    s6Base.setStatus(ApiConstant.ReturnCode.PERMISSION_DENIED.getCode());
    list.add(s6Base);
    return buildFinalJSON(JSON.toJSONString(list));
}
//用户与licence不对应
if ( !ApiUtil.isEmpty(count) && !ApiUtil.isEmpty(count.getUserId()) && !count.getUserId().equals(user.getId()) ) {
    //设置访问licence 空对象
    count.allProperties2Null();
    RedisUtil.set(ApiConstant.PRE_LICENCE_KEY + "{" + requestParam.getLicence() + "}", JSON.toJSONString(count));
    RedisUtil.expire(ApiConstant.PRE_LICENCE_KEY + "{" + requestParam.getLicence() + "}", 2 * 24 * 60 * 60);

    S6Base s6Base = new S6Base();
    s6Base.allProperties2Null();
    s6Base.setStatus(ApiConstant.ReturnCode.PERMISSION_DENIED.getCode());
    list.add(s6Base);
    return buildFinalJSON(JSON.toJSONString(list));
}

2、redis管道,批量操作数据

        map.put("{" + TqwConstant.RedisKeyPrefix.GRID_HOURLY + key + "}", sb.toString());

        //todo 以后删除,3*3 造出 1*1 的数据, 用中心点填充周围
        BigDecimal lonBigdecimal = new BigDecimal(hewlon);
        BigDecimal latBigdecimal = new BigDecimal(hewlat);
        BigDecimal lonIncr       = lonBigdecimal.add(new BigDecimal("0.01"));
        BigDecimal latIncr       = latBigdecimal.add(new BigDecimal("0.01"));
        BigDecimal lonDecr       = lonBigdecimal.subtract(new BigDecimal("0.01"));
        BigDecimal latDecr       = latBigdecimal.subtract(new BigDecimal("0.01"));

        map.put("{" + TqwConstant.RedisKeyPrefix.GRID_HOURLY + DataUtil.formatLonLatString(hewlon, latIncr.toString()) + "_" + (DataUtil.object2Int(hourArr[0]) >= 24 ? (DataUtil.object2Int(hourArr[0]) >= 48 ? 72 : 48) : "24") + "}", sb.toString());
        map.put("{" + TqwConstant.RedisKeyPrefix.GRID_HOURLY + DataUtil.formatLonLatString(hewlon, latDecr.toString()) + "_" + (DataUtil.object2Int(hourArr[0]) >= 24 ? (DataUtil.object2Int(hourArr[0]) >= 48 ? 72 : 48) : "24") + "}", sb.toString());
        map.put("{" + TqwConstant.RedisKeyPrefix.GRID_HOURLY + DataUtil.formatLonLatString(lonIncr.toString(), hewlat) + "_" + (DataUtil.object2Int(hourArr[0]) >= 24 ? (DataUtil.object2Int(hourArr[0]) >= 48 ? 72 : 48) : "24") + "}", sb.toString());
        map.put("{" + TqwConstant.RedisKeyPrefix.GRID_HOURLY + DataUtil.formatLonLatString(lonDecr.toString(), hewlat) + "_" + (DataUtil.object2Int(hourArr[0]) >= 24 ? (DataUtil.object2Int(hourArr[0]) >= 48 ? 72 : 48) : "24") + "}", sb.toString());
        map.put("{" + TqwConstant.RedisKeyPrefix.GRID_HOURLY + DataUtil.formatLonLatString(lonIncr.toString(), latIncr.toString()) + "_" + (DataUtil.object2Int(hourArr[0]) >= 24 ? (DataUtil.object2Int(hourArr[0]) >= 48 ? 72 : 48) : "24") + "}", sb.toString());
        map.put("{" + TqwConstant.RedisKeyPrefix.GRID_HOURLY + DataUtil.formatLonLatString(lonIncr.toString(), latDecr.toString()) + "_" + (DataUtil.object2Int(hourArr[0]) >= 24 ? (DataUtil.object2Int(hourArr[0]) >= 48 ? 72 : 48) : "24") + "}", sb.toString());
        map.put("{" + TqwConstant.RedisKeyPrefix.GRID_HOURLY + DataUtil.formatLonLatString(lonDecr.toString(), latIncr.toString()) + "_" + (DataUtil.object2Int(hourArr[0]) >= 24 ? (DataUtil.object2Int(hourArr[0]) >= 48 ? 72 : 48) : "24") + "}", sb.toString());
        map.put("{" + TqwConstant.RedisKeyPrefix.GRID_HOURLY + DataUtil.formatLonLatString(lonDecr.toString(), latDecr.toString()) + "_" + (DataUtil.object2Int(hourArr[0]) >= 24 ? (DataUtil.object2Int(hourArr[0]) >= 48 ? 72 : 48) : "24") + "}", sb.toString());

        //存储
        if ( map.size() >= DataUtil.object2Int(Constant.PROPERTIES.get("pipeline.count")) ) {
            //设置新值
            RedisUtil.setByPipeline(map);
            map.clear();
        }
    } catch ( Exception ignored ) {
        logger.error(" grid hourly line info error [ " + lines[1] + " ] ", ignored);
    }
}
//执行集合剩余数据
if ( map.size() > 0 ) {
    //设置新值
    RedisUtil.setByPipeline(map);
}

3、redis存储二进制文件数据

private void backFile2Redis() {
    long begin = System.currentTimeMillis();
    logger.info("back up grid-hourly file to redis start !");
    String[] array = readPointFromFile(TqwConstant.PointLonLat.GRID_HOURLY_POINTS);
    logger.info("grid-hourly array size is " + array.length);
    File zipFile = this.backFileGenerator.getGridHourlyFile(array);
    try {
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        FileUtils.copyFile(zipFile, byteArrayOutputStream);
        TqwRedisUtil.set("{" + TqwConstant.FileBytesKey.HOURLY_BYTES + "}", byteArrayOutputStream.toByteArray());
        IOUtils.closeQuietly(byteArrayOutputStream);
    } catch ( Exception e ) {
        logger.info("Grid-hourly zip写入缓存失败", e);
    } finally {
        try {
            zipFile.delete();
        } catch ( Exception ignored ) {}
    }
    logger.info("back up Grid-hourly file to redis end ! cost time " + (System.currentTimeMillis() - begin));
}

redisUtil中工具方法如下:

public static void set(String key, byte[] values) {
    if ( FLAG ) {
        Jedis jedis = null;
        try {
            jedis = getJedis();
            jedis.set(key.getBytes(), values);
        } catch ( Exception var7 ) {
            logger.error(" redis set error, key is [ " + key + " ]  ", var7);
        } finally {
            if ( jedis != null ) {
                jedis.close();
            }

        }
    }
}

4、redis执行lua脚本程序(原子操作)

需求:qpm校验,统计每分钟访问量

①准备evalsha(sha,keys[],argv[]) sha为scriptload(script)返回值 参数key[]数组用于替换lua中key值参数,argv[]存放普通参数

/**
 * qpm 每分钟访问次数
 */
public static final String  QPM_SCRIPT      = "local qpm = tonumber(redis.call('get', KEYS[1]));\n" + "if qpm == nil then\n" + "    redis.call('incr', KEYS[1]);\n" + "    redis.call('expire', KEYS[1], 90);\n" + "    return true;\n" + "elseif qpm < tonumber(ARGV[1]) then\n" + "    redis.call('incr', KEYS[1]);\n" + "    return true;\n" + "else \n" + "    redis.call('incr', KEYS[1]);\n" + "    return false; \n" + "end";
public static       String  QPM_SCRIPT_SHA1 = "958ed8594556dd2c343e8fbf9ac53401337b56a4";//通过scriptload方法获得
②evalsha()执行时必须先执行scriptload()加载脚本进缓存

if ( !QPM_SCRIPT_EXISTS && !RedisUtil.scriptExists(ApiConstant.QPM_SCRIPT_SHA1) ) {
    ApiConstant.QPM_SCRIPT_SHA1 = RedisUtil.scriptLoad(ApiConstant.QPM_SCRIPT);
    QPM_SCRIPT_EXISTS = true;
}
if ( ApiConstant.ServiceNode.FREE.equalsIgnoreCase(Constant.PROPERTIES.get(ApiConstant.Properties.NODE_ID)) ) {
    Object value;
    if ( ApiUtil.containsRole(user.getAllRoleList(), ApiConstant.Role.DEVELOPER) ) {
        value = RedisUtil.evalsha(ApiConstant.QPM_SCRIPT_SHA1, "{" + user.getSsoId() + "}" + ApiUtil.getCurrentDateTime("yyyyMMddHHmm"), ApiConstant.QPM_DEVELOPER.toString());
    } else {
        value = RedisUtil.evalsha(ApiConstant.QPM_SCRIPT_SHA1, "{" + user.getSsoId() + "}" + ApiUtil.getCurrentDateTime("yyyyMMddHHmm"), ApiConstant.QPM_FREE.toString());
    }
    if ( value == null ) {
        return true;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值