10-redis

2018-06-04  本文已影响14人  01010100

Redis:

1、数据结构:string, hash, list, set, sorted set

2、memcache对比:

1)数据类型更丰富

2)可以持久化

问题:单线程性能优势(IO多路复用)

1)直接操作内存

2)单线程,无需上下文切换及锁开销

3)基于IO多路复用

3、持久化与性能

1)Master最好不要做任何持久化工作,如RDB内存快照和AOF日志文件

2)如果数据比较重要,某个Slave开启AOF备份数据,策略设置为Always

3)为了主从复制的速度和连接的稳定性,Master和Slave最好在同一个局域网内

4)尽量避免在压力很大的主库上增加从库

5)主从复制不要用图状结构,用单向链表结构更为稳定,即:Master <- Slave1 <- Slave2 <- Slave3...

  这样的结构方便解决单点故障问题,实现Slave对Master的替换。如果Master挂了,可以立刻启用Slave1做Master,其他不变。

4、集群方案

Redis 集群的键空间被分割为 16384 个槽(slot), 集群的最大节点数量也是 16384 个

主从方案

哨兵方案

集群方案

5、场景问题

5.1 缓存与数据库一致性

https://tech.imdada.cn/2017/06/30/daojia-redis/

http://ifeve.com/concurrency-cache-cross/

更新顺序:失效:从缓存中读取,没得到则从数据库取数据,成功后放到缓存;

命中:从缓存中读取,取到直接返回;

更新:先将数据保存至数据库,再让缓存失效

同步:单独同步服务,分析读取mysql binLog + 消息队列 + 处理后更新到缓存

强一致性:缓存一般不应用于强一致性场景,如金融业务

5.2 缓存穿透

1、若缓存不存在,查询数据库使用分布式锁,获取锁时再次判断缓存中是否存在

2、查询数据库,数据库中若不存在该数据,则将NULL放入缓存中(失效时间短)

3、将缓存失效时间分散开,可以在原有的失效时间基础上增加一个随机值

5.3 如果有大量的key需要设置同一时间过期,一般需要注意什么

    将缓存失效时间分散开,比如我们可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,

    这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件

5.4 如何保证redis都是热点数据(考察缓存失效策略)

    LRU:从已设置过期时间和从所有数据中,选择最近最少使用淘汰

    Random:从已设置过期时间和从所有数据中,随机选择淘汰

    即将过期:从已设置过期时间的数据中,选择将要过期的淘汰

6、应用场景

分布式session,分布式锁,队列、排行榜、计数器

7、分布式锁:

使用jedis.setnx()命令实现加锁,其中key是锁,value是锁的过期时间。

执行过程:

1. 通过setnx()方法尝试加锁,如果当前锁不存在,返回加锁成功。

2. 如果锁已经存在则获取锁的过期时间,和当前时间比较,如果锁已经过期,则设置新的过期时间,返回加锁成功。代码如下:

publicstaticbooleanwrongGetLock2(Jedis jedis, String lockKey, intexpireTime) {

    longexpires = System.currentTimeMillis() + expireTime;

    String expiresStr = String.valueOf(expires);

    // 如果当前锁不存在,返回加锁成功

    if(jedis.setnx(lockKey, expiresStr) == 1) {

        returntrue;

    }

    // 如果锁存在,获取锁的过期时间

    String currentValueStr = jedis.get(lockKey);

    if(currentValueStr != null&& Long.parseLong(currentValueStr) < System.currentTimeMillis()) {

        // 锁已过期,获取上一个锁的过期时间,并设置现在锁的过期时间

        String oldValueStr = jedis.getSet(lockKey, expiresStr);

        if(oldValueStr != null&& oldValueStr.equals(currentValueStr)) {

            // 考虑多线程并发的情况,只有一个线程的设置值和当前值相同,它才有权利加锁

            return true;

        }

    }

    // 其他情况,一律返回加锁失败

    return false;

}

那么这段代码问题在哪里?

1. 由于是客户端自己生成过期时间,所以需要强制要求分布式下每个客户端的时间必须同步。 2. 当锁过期的时候,如果多个客户端同时执行jedis.getSet()方法,那么虽然最终只有一个客户端可以加锁,但是这个客户端的锁的过期时间可能被其他客户端覆盖。3. 锁不具备拥有者标识,即任何客户端都可以解锁。

http://www.importnew.com/27477.html

上一篇下一篇

猜你喜欢

热点阅读