1、Redis常用命令

官方命令大全网址:http://www.redis.cn/commands.html

1.1 keys

  1. 返回满足给定pattern 的所有key

语法:

  1. keys pattern

示例:

  1. redis 127.0.0.1:6379> keys list*
  2. 1) "list"
  3. 2) "list5"
  4. 3) "list6"
  5. 4) "list7"
  6. 5) "list8"

1.2 del

语法

  1. del key

实例

  1. 127.0.0.1:6379> del test
  2. (integer) 1

1.3 exists

  1. 确认一个key 是否存在

语法

  1. exists key

示例:从结果来看,数据库中不存在HongWan 这个key,但是age 这个key 是存在的

  1. redis 127.0.0.1:6379> exists HongWan
  2. (integer) 0
  3. redis 127.0.0.1:6379> exists age
  4. (integer) 1
  5. redis 127.0.0.1:6379>

1.4 expire

  1. Redis在实际使用过程中更多的用作缓存,然而缓存的数据一般都是需要设置生存时间的,即:到期后数据销毁。

语法

  1. EXPIRE key seconds 设置key的生存时间(单位:秒)key在多少秒后会自动删除
  2. TTL key 查看key剩余的生存时间
  3. PERSIST key 清除生存时间
  4. PEXPIRE key milliseconds 生存时间设置单位为:毫秒

示例

  1. redis 127.0.0.1:6379> set test 1 #设置test的值为1
  2. OK
  3. redis 127.0.0.1:6379> get test
  4. "1"
  5. redis 127.0.0.1:6379> EXPIRE test 5 #设置test的生存时间为5秒
  6. (integer) 1
  7. redis 127.0.0.1:6379> TTL test #查看test的生于生成时间还有1秒删除
  8. (integer) 1
  9. redis 127.0.0.1:6379> TTL test
  10. (integer) -2
  11. redis 127.0.0.1:6379> get test #获取test的值,已经删除
  12. (nil)

1.5 rename

  1. 重命名key

语法

  1. rename oldkey newkey

示例:age 成功的被我们改名为age_new了

  1. redis 127.0.0.1:6379> keys *
  2. 1) "age"
  3. redis 127.0.0.1:6379> rename age age_new
  4. OK
  5. redis 127.0.0.1:6379> keys *
  6. 1) "age_new"
  7. redis 127.0.0.1:6379>

1.6 type

  1. 显示指定key的数据类型

语法:

  1. type key

示例:这个方法可以非常简单的判断出值的类型

  1. redis 127.0.0.1:6379> type addr
  2. string
  3. redis 127.0.0.1:6379> type myzset2
  4. zset
  5. redis 127.0.0.1:6379> type mylist
  6. list

2、Redis的Java客户端—Jedis

1、关闭RedisServer端的防火墙

  1. systemctl stop firewalld(默认)
  2. systemctl disable firewalld.service(设置开启不启动)

2、新建maven项目后导入Jedis包
pom.xml

  1. <dependency>
  2. <groupId>redis.clients</groupId>
  3. <artifactId>jedis</artifactId>
  4. <version>2.9.0</version>
  5. </dependency>

3、写程序

@Test
public void testConn(){
    //与Redis建立连接 IP+port
    Jedis redis = new Jedis("192.168.127.128", 6379);
    //在Redis中写字符串 key value
    redis.set("jedis:name:1","jd-zhangfei");
    //获得Redis中字符串的值
    System.out.println(redis.get("jedis:name:1"));
    //在Redis中写list
    redis.lpush("jedis:list:1","1","2","3","4","5");
    //获得list的长度
    System.out.println(redis.llen("jedis:list:1"));
}

2、缓存过期和淘汰策略

Redis缓存淘汰策略与Redis键的过期删除策略并不完全相同,前者是在Redis内存使用超过一定值的时候(一般这个值可以配置)使用的淘汰策略;而后者是通过定期删除+惰性删除两者结合的方式进行内存淘汰的。缓存,不是存储,无法保证以前设置的缓存绝对存在。因为缓存容量是有上限的,即使set值的时候不设置过期时间,在内存不够的时候,会根据内存淘汰策略删除一些缓存。设置过期时间的key是如何删除的?过期后会立即释放内存吗?
Redis数据库结构体定义:

typedef struct redisDb {
    dict *dict;  -- key Value
    dict *expires; -- key ttl
    dict *blocking_keys;
    dict *ready_keys;
    dict *watched_keys;
    int id;
} redisDb;

上面的代码是Redis 中关于数据库的结构体定义,这个结构体定义中除了 id 以外都是指向字典的指针, 其中我们只看 dict 和 expires。
dict 用来维护一个 Redis 数据库中包含的所有 Key-Value 键值对,expires则用于维护一个 Redis 数据库中设置了失效时间的键(即key与失效时间的映射)。
当我们使用 expire命令设置一个key的失效时间时,Redis 首先到 dict 这个字典表中查找要设置的key是否存在,如果存在就将这个key和失效时间添加到 expires 这个字典表。
当我们使用 setex命令向系统插入数据时,Redis 首先将 Key 和 Value 添加到 dict 这个字典表中,然后将 Key 和失效时间添加到 expires 这个字典表中。
简单地总结来说就是,设置了失效时间的key和具体的失效时间全部都维护在 expires 这个字典表中。

2.1 过期删除策略

  • 定时删除

在设置key的过期时间的同时,为该key创建一个定时器,让定时器在key的过期时间来临时对key进行删除。
优点:保证内存被尽快释放
缺点:若过期key很多,删除这些key会占用很多的CPU时间,在CPU时间紧张的情况下,CPU不能把所有的时间用来做要紧的事儿,还需要去花时间删除这些key,定时器的创建耗时,若为每一个设置过期时间的key创建一个定时器(将会有大量的定时器产生),性能影响严重。
结论:此方法基本上没人用

  • 惰性删除

过期的key并不一定会马上删除,还会占用着内存。 当你真正查询这个key时,redis会检查一下,这个设置了过期时间的key是否过期了? 如果过期了就会删除,返回空。这就是惰性删除。
优点:删除操作只发生在从数据库取出key的时候发生,而且只删除当前key,所以对CPU时间的占用是比较少的,而且此时的删除是已经到了非做不可的地步(如果此时还不删除的话,我们就会获取到了已经过期的key了)
缺点:若大量的key在超出超时时间后,很久一段时间内,都没有被获取过,那么可能发生内存泄露(无用的垃圾占用了大量的内存)

  • 主动删除

在redis.conf文件中可以配置主动删除策略,默认是no-enviction(不删除)
Redis采用的过期策略:惰性删除+主动删除

持久化对过期key的处理

RDB对过期key的处理
过期key对RDB没有任何影响
1)从内存数据库持久化数据到RDB文件,持久化key之前,会检查是否过期,过期的key不进入RDB文件
2)从RDB文件恢复数据到内存数据库,数据载入数据库之前,会对key先进行过期检查,如果过期,不导入数据库(主库情况)
AOF对过期key的处理
过期key对AOF没有任何影响
1)从内存数据库持久化数据到AOF文件:当key过期后,还没有被删除,此时进行执行持久化操作(该key是不会进入aof文件的,因为没有发生修改命令)当key过期后,在发生删除操作时,程序会向aof文件追加一条del命令(在将来的以aof文件恢复数据的时候该过期的键就会被删掉)
2)AOF重写:重写时,会先判断key是否过期,已过期的key不会重写到aof文件

内存淘汰策略

当redis内存超出物理内存限制时,会和磁盘产生swap,这种情况性能极差,一般是不允许的。通过设置 maxmemory 限制最大使用内存。超出限制时,根据redis提供的几种内存淘汰机制让用户自己决定如何腾出新空间以提供正常的读写服务。

  • noeviction:当内存使用超过配置的时候会返回错误,不会驱逐任何键(默认策略,不建议使用)
  • allkeys-lru:加入键的时候,如果过限,首先通过LRU算法驱逐最久没有使用的键
  • volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
  • allkeys-random:加入键的时候如果过限,从所有key随机删除
  • volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
  • volatile-ttl:从配置了过期时间的键中驱逐马上就要过期的键
  • volatile-lfu:从所有配置了过期时间的键中驱逐使用频率最少的键
  • allkeys-lfu:从数据集(server.db[i].dict)中任意选择数据淘汰

设置maxmemory时,必须设置maxmemory-policy。在配置文件redis.conf中设置内存淘汰策略

maxmemory-policy allkeys-lru

LRU

LRU (Least recently used) 最近最少使用,算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”。
LRU 数据淘汰机制是这样的:在数据集中随机挑选几个键值对,取出其中 lru 最大的键值对淘汰。
最常见的实现是使用一个链表保存缓存数据,详细算法实现如下:
1. 新数据插入到链表头部;
2. 每当缓存命中(即缓存数据被访问),则将数据移到链表头部;
3. 当链表满的时候,将链表尾部的数据丢弃。
4. 在Java中可以使用LinkHashMap(哈希链表)去实现LRU

缓存淘汰策略的选择

  • allkeys-lru : 在不确定时一般采用策略。 冷热数据交换
  • volatile-lru : 比allkeys-lru性能差
  • allkeys-random : 希望请求符合平均分布(每个元素以相同的概率被访问) 自己控制:volatile-ttl 缓存穿透