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 DefaultRedisScriptUNLOCK_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());

你是否还在寻找稳定的海外服务器提供商?创新互联www.cdcxhl.cn海外机房具备T级流量清洗系统配攻击溯源,准确流量调度确保服务器高可用性,企业级服务器适合批量采购,新人活动首月15元起,快前往官网查看详情吧


当前名称:redis应用笔记-创新互联
文章链接:http://ybzwz.com/article/pjphh.html