redis应用笔记

1.登录服务

        在登陆服务中,如果将数据全部存储到tomcat中,当存在多个tomcat的时候,数据是无法同步的,这就导致了数据的共享问题:

             1、每台服务器中都有完整的一份session数据,服务器压力过大。

             2、session拷贝数据时,可能会出现延迟

解决办法就是采用redis, redis完美的符合了以下的要求:

                1.同步性

                2.基于内存,高效率

                3.满足key-value结构

        同时注意,redis的string与hashset的区别

优化后的流程如下图

 首先我们很容易想到,将用户的登录手机号作为key,而后对于存储到redis中的用户的凭证,我们选择生成随机的token,使用token是为了不暴露用户的手机号(隐私处理).同时我们还要注意,session是能在tomcat中自动同步的,但是token是做不到的,我们需要手动同步token.而token是怎么做到帮助我们识别用户的登录状态的呢,答案就是在每次的服务器回传的过程中,都会在头部添加一个token字段.

2.商品缓存

 

 缓存穿透:

        指的是客户端在请求数据的过程中,缓存和数据库中都没有要请求的数据,这样缓存永远都不会生效,请求都会打到数据库.这样就导致数据库在频繁的查找数据.服务器性能大幅度下降.

        解决办法:

        1.缓存空对象: 对于同一个请求的资源,比如请求不存在的id= -1的资源,在缓存中添加id=-1的键,将其值设置为null,这样避免了同样的id导致的反复查找,下次查找id=-1的资源可以直接从缓存中查出来.

                优点: 实现简单,维护方便

                缺点: 一旦请求的资源变换,还是需要继续查找.

                        额外的内存消耗

                        可能造成短期的不一致(第一次请求的时候数据没有,缓存中设置为null,但是第二次请求时数据库中已经有了上次请求的id对应的数据,仍然会返回null)

        2.添加布隆过滤器:它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器可以用于检索一个元素是否在一个集合中。它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。

                优点: 内存占用少,没有多余的key

                缺点: 实现很复杂,并且存在误判的可能

        

3.redis加锁的办法: 在后面指定了锁的有效时间,是用锁的超时时间进行兜底的.

private boolean tryLock(String key){
        Boolean ifAbsent = stringRedisTemplate.opsForValue().setIfAbsent(key, "1", 2, TimeUnit.MINUTES);
        //如果直接返回的话会自动拆箱,可能导致出现空值
        return BooleanUtil.isTrue(ifAbsent);
    }

如果是redis中设置锁的语句就如下所示:

//给线程1设置锁
setnx lock thread1

//设置锁的时长
expire lock 5

//合并起来
//(nx指的是不存在的时候才可以设置)
set lock thread1 ex 5 nx


//删除锁
del lock 

4.redis将两个操作转换为原子操作(并行的情况下)

        使用lua脚本

        lua脚本数组是从下标为1开始的

java代码的改造:

改造之前:

    @Override
    public void deleteLock() {
        //判断redis中的锁和当前的锁是否是同一把
        //当前的锁
        String threadNameUUID = ID_NAME + Thread.currentThread().getId();
        //redis数据库里面的数据是否一致
        String redisLock = stringRedisTemplate.opsForValue().get(KEY_NAME + name);
        if(threadNameUUID.equals(redisLock)){
            stringRedisTemplate.delete(KEY_NAME + name);
        }
    }

 改造后:

        unlock.lua在resources目录下

//初始化lua脚本
    private static final DefaultRedisScript<Long> UNLOCK_LUA;
    
    //在static]块中初始化
    static{
        UNLOCK_LUA = new DefaultRedisScript<>();
        UNLOCK_LUA.setLocation(new ClassPathResource("unlock.lua"));
        UNLOCK_LUA.setResultType(Long.class);
    }

        unlock.lua

--比较线程标识与redis锁中的标识是否一致
if(redis.call('get', KEYS[1]) == ARGV[1])  then
    --释放锁
    return redis.call('del', KEYS[1])
end
return 0

        调用代码:

    @Override
    public void deleteLock() {
        //调用lua脚本
        stringRedisTemplate.execute(
                UNLOCK_LUA,
                Collections.singletonList(KEY_NAME + name),
                ID_NAME + Thread.currentThread().getId());
    }

lua传入空参,比如java调用lua脚本的时候key是空的这时不能传空对象,要传Collections.emptyList()

下面举例:

Long execute = stringRedisTemplate.execute(SECKILL_SCRIPT,
        Collections.emptyList(),
          voucherId.toString(), id.toString());

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值