Redis缓存

Redis

第一步,安装Redis,启动后,通过如下代码测试Redis

1. Redis java使用测试

Redis建立连接

Jedis jedis = new Jedis("127.0.0.1");
jedis.auth("youxin11");
//使用jedis操作redis
jedis.set("test123", "my first jedis test");
String string = jedis.get("test123");
System.out.println(string);
//关闭连接,每次使用完毕后关闭连接。连接池回收资源。
jedis.close();

Redis连接池

	JedisPoolConfig poolConfig = new JedisPoolConfig();
	poolConfig.setMaxIdle(redisConfig.getPoolMaxIdle());
	poolConfig.setMaxTotal(redisConfig.getPoolMaxTotal());
	poolConfig.setMaxWaitMillis(redisConfig.getPoolMaxWait() * 1000);
	JedisPool pool = new JedisPool(poolConfig, redisConfig.getHost(), redisConfig.getPort(),
				redisConfig.getTimeout()*1000, redisConfig.getPassword(), 0);
 	
 	Jedis jedis = pool.getResource();
    //使用jedis操作redis
    jedis.set("test123", "my first jedis test");
    String string = jedis.get("test123");
    System.out.println(string);
    //关闭连接,每次使用完毕后关闭连接。连接池回收资源。
    jedis.close();
    //关闭连接池。
    pool.close();

2. Redis缓存安全防范

分布式项目中,通过引入redis,极大的提升了应用程序的性能和效率,特别是数据查询方面。但同时也带来了一些问题。最要害的问题,就是数据的一致性问题。严格意义上来讲,这个问题是无解的,如果对数据一致性要求非常高,就不要使用缓存。另外的一些典型问题,就是缓存穿透、缓存雪崩和缓存击穿。

1. 缓存穿透

缓存穿透,是指查询一个数据库一定不存在的数据。
正常的使用缓存流程大致是,数据查询先进行缓存查询,如果key不存在或者key已经过期,再对数据库进行查询,并把查询到的对象,放进缓存。如果数据库查询对象为空,则不放进缓存。如果用户发起id为“-1”或id特别大不存在的数据。这时很可能是攻击者,攻击会导致数据库压力过大。

解决方案

1,接口层增加校验。对id做基础校验,id<=0的直接拦截;
2,从缓存取不到的数据,在数据库中也没有取到,这时也可以将key-value键值对写为key-null,缓存有效时间可以设置短点,如60秒(设置太长会导致正常情况也没法使用),这样可以防止攻击用户反复用同一个id暴力攻击。

	@Reference(version = "1.0.0")
    private GoodsService goodsService;
    
    @Autowired
    private CacheService cacheService;
    
    @RequestMapping(value = "detail", method = RequestMethod.POST)
    public Object detail(HttpServletRequest request) throws Exception{
        String requestStr = RequestStr.geRequestStr(request);
        JSONObject jsonObject = JSONObject.parseObject(RequestStr);
        
        if(StringUtils.isEmpty(jsonObject.getString("goodsId"))){
            throw new DescribeExceeption(ExcetpionEnum.PARAM_ERROR);
        }
        int goodsId = jsonObject.getInteger("goodsId");
        if(goodsId <= 0){
            //当id小于等于0时,我们认为是一场操作
            throw new DescribeExceeption(ExcetpionEnum.OPERATE_ERROR);
        }
        GoodsInfo goods = (GoodsInfo) cacheService.getCacheByKey("lyn_goods:" + goodsId);
        if(null == goods){
            goods = goodsService.findGoodsInfoByPrimary(goodsId);
            //非法数据也存入缓存,有效时间较短,防止同一ID,短时间,重复查询
            if(null != goods){
                cacheService.setCacheToRedis("lyn_goods:" + goodsId, goods, 18000);
            }else{
                cacheService.setCacheToRedis("lyn_goods:" + goodsId, goods, 60);
            }
        }
        return ResultUtils.success(goods);
    }

2. 缓存雪崩

缓存雪崩,是指在某一个时间段,缓存集中过期失效。产生雪崩的原因之一,比如马上就到618了,很快就会迎来一波抢购,这些要抢购的商品在同一时间点(17号23点放入)比较集中的放入了缓存,假设缓存两个小时。那么到了凌晨一点钟的时候,这批商品的缓存就都过期了。而此时对这批商品的访问查询,都落到了数据库身上,这时对于数据库而言,就会带来极大的压力。

解决方案:

1,在设置数据缓存有效期时,在时间后加上一个随机因子。

2,分散缓存过期时间,将热门类数据缓存时间长一点,冷门类的短一点。

3,设置热点数据永不过期。

	GoodsInfo goods = goodsService.findGoodsInfoByPrimary(goodsId);
    if(null != goods){
        Random random = new Random();
        //根据是否为热点数据,设置数据有效时间(有效时间,增加随机银子判断)
        long expire = goods.getIsHotSell() ? 3600 + random.nextInt() * 3600 : 600 + random.nextInt() * 600;
        cacheService.setCacheToRedis("lyn_goods:" + goodsId, goods, expire);
    }

3. 缓存击穿

缓存击穿,是指一个key非常热点,高并发集中对这个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像春运期间火车站售票大厅,本来那些设在门口和广场的自助机可以办理售票,结果自助机瞬间全部瘫痪,造成大量买票的人涌进售票大厅人工窗口。

解决方案:

1,设置热点数据永远不过期;

2,加互斥锁,互斥锁参考代码如下:

GoodsInfo goods = (GoodsInfo) cacheService.getCacheByKey("lyn_goods:" + goodsId);
        if(null != goods){
            String key = "lyn_goods_detail_lock";
            if(cacheService.lock(key, "0")){
                goods = this.getGoodsInfo(goodsId);
                cacheService.unLock(key);
            }else{
                Thread.sleep(100);
                goods = this.getGoodsInfo(goodsId);
            }
        }

4. 缓存数据持久化

Redis提供了将数据定期自动持久化至硬盘的能力,包括RDB和AOF两种方案,两种方案分别有其长处和短板,可以配合起来同时运行,确保数据的稳定性。

RDB

RDB方式是一种快照式的持久化方法,将某一时刻的数据持久化到磁盘中。并在启动时自动加载rdb文件,恢复之前保存的数据。可以在配置文件中配置Redis进行快照保存的时机:

save [60] [100]
//会让Redis每60秒检查一次数据变更情况,如果发生了100次或以上的数据变更,则进行RDB快照保存。可以配置多条save指令,让Redis执行多级的快照保存策略。Redis默认开启RDB快照。

AOF

采用AOF持久方式时,Redis会把每一个写请求都记录在一个日志文件里。在Redis重启时,会把AOF文件中记录的所有写操作顺序执行一遍,确保数据恢复到最新。AOF默认是关闭的,如要开启,进行如下配置:

appendonly yes

AOF提供了三种fsync配置,always/everysec/no,通过[appendfsync]指定:appendfsync no:不进行fsync,将flush文件的时机交给OS决定,速度最快;

appendfsync always:每写入一条日志就进行一次fsync操作,数据安全性最高,但速度最慢;

appendfsync everysec:折中的做法,交由后台线程每秒fsync一次;

博客原地址:

作者:Java开发者记录站
链接:https://www.jianshu.com/p/ebca78731137
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

你可能感兴趣的:(Redis缓存)