Redis概述

什么是Redis

  Redis是用C语言开发的一个开源的高性能键值对(key-value)非关系性数据库,官方提供测试数据,50个并发执行100000个请求,读的速度是110000次/s,写的速度是81000次/s,且Redis通过提供多种键值数据类型来适应不同场景下的存储需求,目前为止Redis支持的键值数据类型如下:

  1. 字符串类型 string
  2. 散列类型 hash
  3. 列表类型 list
  4. 集合类型 set
  5. 有序集合类型 sortedset

Redis的应用场景

  1. 缓存(数据查询、短连接、新闻内容、商品内容等等)
  2. 聊天室的在线好友列表
  3. 任务队列。(秒杀、抢购、12306等等)
  4. 应用排行榜
  5. 网站访问统计
  6. 数据过期处理(可以精确到毫秒
  7. 分布式集群架构中的session分离

  总结,只要希望查询快就可以使用redis,但是mysql中的数据如果频繁的更新,就不建议使用redis了,否则redis会频繁的从mysql不断更新数据,会导致redis慢了。redis适合存储经常查询又不经常更新的数据。 (更新的频率不要太高。)   

Window版Redis安装

从GitHub上下载window版的Redis(本文使用Redis-x64-3.2.100版本),下载地址:

https://github.com/MSOpenTech/redis/tags

Redis 单机版

Redis的安装

window版的安装及其简单,解压Redis压缩包即可

Redis的目录结构

解压Redis压缩包后,见到如下目录机构:

Redis的启动与关闭

双击Redis目录中redis-server.exe可以启动redis服务,Redis服务占用的端口是6379

14.png

关闭Redis的控制台窗口就可以关闭Redis服务

Redis的使用

双击Redis目录中redis-cli.exe可以启动redis客户端

15.png

注意事项:redis所在的硬盘位置的盘符,硬盘空间必须有20G以上。redis解压到非中文目录里面,目录结构不要太深。  

Redis 集群版

环境准备

使用redis-trib.rb工具创建Redis集群,由于该文件是用ruby语言写的,所以需要安装Ruby开发环境,以及驱动redis-xxxx.gem,所以除了Redis安装文件外,还需要下载如上所述三个文件:

1、脚本文件redis-trib.rb,下载地址:

https://github.com/beebol/redis-trib.rb

2、开发环境Ruby(本文使用rubyinstaller-2.2.4-x64.exe安装版),下载地址:

http://dl.bintray.com/oneclick/rubyinstaller/

3、驱动redis-xxxx.gem(本文使用3.2.2版本),下载地址:

https://rubygems.org/gems/redis/versions

准备6个实例

配置文件

在Redis安装根目录下,创建编码格式为utf-8的配置文件:redis.6380.conf、redis.6381.conf、redis.6382.conf、redis.6383.conf、redis.6384.conf、redis.6385.conf。(Redis默认端口为6379,这里使用6380-6385六个端口)

以redis.6380.conf为例:

port 6380      
loglevel notice
logfile "E:/Redis-Cluster/Redis-x64-3.2.100/Logs/redis6380_log.txt"
appendonly yes
appendfilename "appendonly.6380.aof"
cluster-enabled yes
cluster-config-file nodes.6380.conf
cluster-node-timeout 15000
cluster-slave-validity-factor 10
cluster-migration-barrier 1
cluster-require-full-coverage yes

备注:
1、其他配置文件只需将port、logfile、appendfilename、cluster-config-file中的6380修改为相应的端口号即可
2、loglevel:日志的记录级别,notice是适合生产环境的
3、logfile:指定log的保存路径(默认是创建在Redis安装目录下),此处手动创建Logs目录
4、appendonly:持久化模式为aof格式
5、appendfilename:持久化文件
6、cluster-config-file:节点配置文件
7、cluster-enabled:是否开启集群
 

安装redis服务

使用完整路径,避免集群出现问题 

E:/Redis-Cluster/Redis-x64-3.2.100/redis-server.exe --service-install E:/Redis-Cluster/Redis-x64-3.2.100/redis.6380.conf --service-name redis6380
E:/Redis-Cluster/Redis-x64-3.2.100/redis-server.exe --service-install E:/Redis-Cluster/Redis-x64-3.2.100/redis.6381.conf --service-name redis6381
E:/Redis-Cluster/Redis-x64-3.2.100/redis-server.exe --service-install E:/Redis-Cluster/Redis-x64-3.2.100/redis.6382.conf --service-name redis6382
E:/Redis-Cluster/Redis-x64-3.2.100/redis-server.exe --service-install E:/Redis-Cluster/Redis-x64-3.2.100/redis.6383.conf --service-name redis6383
E:/Redis-Cluster/Redis-x64-3.2.100/redis-server.exe --service-install E:/Redis-Cluster/Redis-x64-3.2.100/redis.6384.conf --service-name redis6384
E:/Redis-Cluster/Redis-x64-3.2.100/redis-server.exe --service-install E:/Redis-Cluster/Redis-x64-3.2.100/redis.6385.conf --service-name redis6385
卸载redis服务

只需把安装命令中的–service-install修改为–service-uninstall即可,如下

E:/Redis-Cluster/Redis-x64-3.2.100/redis-server.exe --service-uninstall E:/Redis-Cluster/Redis-x64-3.2.100/redis.6380.conf --service-name redis6380
启动redis服务

使用完整路径,避免集群出现问题 

E:/Redis-Cluster/Redis-x64-3.2.100/redis-server.exe --service-start --service-name redis6380
E:/Redis-Cluster/Redis-x64-3.2.100/redis-server.exe --service-start --service-name redis6381
E:/Redis-Cluster/Redis-x64-3.2.100/redis-server.exe --service-start --service-name redis6382
E:/Redis-Cluster/Redis-x64-3.2.100/redis-server.exe --service-start --service-name redis6383
E:/Redis-Cluster/Redis-x64-3.2.100/redis-server.exe --service-start --service-name redis6384
E:/Redis-Cluster/Redis-x64-3.2.100/redis-server.exe --service-start --service-name redis6385

注:如果服务状态在正在运行时执行了卸载命令,这时服务窗口的Redis服务还是会显示,只有当服务停止后才不会再显示

停止redis服务

只需把安装命令中的–service-start修改为–service-stop即可,如下

E:/Redis-Cluster/Redis-x64-3.2.100/redis-server.exe --service-stop --service-name redis6380

安装ruby开发环境

双击rubyinstaller-2.2.4-x64.exe,选中如图两个选项(意义为将ruby添加到系统环境变量中,在cmd命令中能直接使用ruby命令),之后就是傻瓜式安装啦

安装驱动redis-xxxx.gem

将驱动redis-xxxx.gem拷贝到Ruby安装根目录下,在此目录执行cmd命令安装

gem install --local path_to_gem/filename.gem

使用redis-trib.rb创建集群

将redis-trib.rb文件拷贝到Redis安装目录下,在此目录执行cmd命令创建集群

D:/Redis-Cluster/Redis-x64-3.2.100/redis-trib.rb create --replicas 1 127.0.0.1:6380 127.0.0.1:6381 127.0.0.1:6382 127.0.0.1:6383 127.0.0.1:6384 127.0.0.1:6385

启动信息(中间会提示是否设置配置,输入yes),每个主节点分配的哈希槽信息和主从分配信息在此都可查看

>>> Creating cluster
Connecting to node 127.0.0.1:6380: OK
Connecting to node 127.0.0.1:6381: OK
Connecting to node 127.0.0.1:6382: OK
Connecting to node 127.0.0.1:6383: OK
Connecting to node 127.0.0.1:6384: OK
Connecting to node 127.0.0.1:6385: OK
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
127.0.0.1:6380
127.0.0.1:6381
127.0.0.1:6382
Adding replica 127.0.0.1:6383 to 127.0.0.1:6380
Adding replica 127.0.0.1:6384 to 127.0.0.1:6381
Adding replica 127.0.0.1:6385 to 127.0.0.1:6382
M: bb6ef615bb0ae13275943caec0db9d30b9f35c5e 127.0.0.1:6380 slots:0-5460 (5461 slots) master
M: b4d120f2983ad683f7b68992e1ba414722238db7 127.0.0.1:6381 slots:5461-10922 (5462 slots) master
M: 837779b3965e2c9d4dd4385750aaaaf9a9039fb0 127.0.0.1:6382 slots:10923-16383 (5461 slots) master
S: 5d154137180284d926ef51a91fc75f9438249ef8 127.0.0.1:6383 replicates bb6ef615bb0ae13275943caec0db9d30b9f35c5e
S: ad151680a3e36cf2083ef822be0bdb075a7d36de 127.0.0.1:6384 replicates b4d120f2983ad683f7b68992e1ba414722238db7
S: 9a2260a5a6a2add84b622a453a6a7b86a29d180d 127.0.0.1:6385 replicates 837779b3965e2c9d4dd4385750aaaaf9a9039fb0
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join...
>>> Performing Cluster Check (using node 127.0.0.1:6380)M: bb6ef615bb0ae13275943caec0db9d30b9f35c5e 127.0.0.1:6380 slots:0-5460 (5461 slots) master
M: b4d120f2983ad683f7b68992e1ba414722238db7 127.0.0.1:6381 slots:5461-10922 (5462 slots) master
M: 837779b3965e2c9d4dd4385750aaaaf9a9039fb0 127.0.0.1:6382 slots:10923-16383 (5461 slots) master
M: 5d154137180284d926ef51a91fc75f9438249ef8 127.0.0.1:6383 slots: (0 slots) master replicates bb6ef615bb0ae13275943caec0db9d30b9f35c5e
M: ad151680a3e36cf2083ef822be0bdb075a7d36de 127.0.0.1:6384 slots: (0 slots) master replicates b4d120f2983ad683f7b68992e1ba414722238db7
M: 9a2260a5a6a2add84b622a453a6a7b86a29d180d 127.0.0.1:6385 slots: (0 slots) master replicates 837779b3965e2c9d4dd4385750aaaaf9a9039fb0
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.
备注:

1、./redis-trib.rb create –replicas X

X:指定集群中每个主节点配备几个从节点,这里设置为1。

2、redis-trib.rb工具的使用

create:创建集群
check:检查集群
info:查看集群信息
fix:修复集群
reshard:在线迁移slot
rebalance:平衡集群节点slot数量
add-node:将新节点加入集群
del-node:从集群中删除节点
set-timeout:设置集群节点间心跳连接的超时时间
call:在集群全部节点上执行命令
import:将外部redis数据导入集群

Linux版Redis安装

官网提供了Linux版的Redis下载,官网下载地址:

http://redis.io/download

Redis 单机版

环境准备

Linux:CentOS7
Jdk:1.7以上版本

Redis安装在Linux上,redis是c语言开发的,需要gcc-c++环境。

yum -y install cpp binutils glibc glibc-kernheaders glibc-common glibc-devel gcc make gcc-c++ libstdc++-devel tcl

如果安装过则不会执行(没有规则可以创建目标“gcc-c++”。 停止)

make gcc-c++ libstdc++-devel tcl

安装

在安装之前可以先查看是否已经启动了redis,ps –ef | grep redis,再使用kill关闭redis

删除已经安装的redis

cd /usr/local/redis && rm –rf bin

进入root目录,上传压缩包

cd /root/software

使用工具上传“redis-3.2.4.tar.gz”

解压安装包并进入解压的文件夹

tar -zxvf redis-3.2.4.tar.gz && cd redis-3.2.4

1.png

执行安装,指定安装路径

make install PREFIX=/usr/local/redis

2.png

查看安装目录

cd /usr/local/redis/bin/

【说明】常用的是客户端和服务端;redis-cli 是客户端;redis-server 是服务端

启动

前端启动(不推荐)

前端启动

./redis-server

确认redis安装正常,效果:
3.png

后台启动

从安装包中复制redis.conf文件到/usr/local/redis/bin中

cp /root/software/redis-3.2.4/redis.conf ./

修改redis.conf配置文件

vi redis.conf

设置后台启动redis,修改如下,默认为no

daemonize yes

设置不仅限制本地访问:
注释掉 bind 127.0.0.1

禁用保护模式:
把 protected-mode yes 改为 protected-mode no

【提示】vim打开文件中查找内容的方式为底行模式按 /,然后输入要查找的内容即可(shift + n下一个)。如果被选中了后不想被选中则可以随意输入查找来消除选中效果

启动

./redis-server redis.conf

查看启动

ps -ef | grep redis

连接

使用redis-cli客户端连接
./redis-cli

如:输入ping ,返回pong
4.png

图形化界面连接

使用图形化界面测试访问192.168.12.168,redis默认端口为6379;示例图工具是Redis Desktop Manager

5.png

Redis 集群版

Redis 集群原理

Redis-cluster 架构图

6.png

  1. 所有的 redis 节点彼此互联(PING-PONG 机制),内部使用二进制协议优化传输速度和带宽。
  2. 节点的 fail 是通过集群中超过半数的节点检测失效时才生效。
  3. 客户端与 redis 节点直连,不需要中间 proxy 层。客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。
  4. redis-cluster 把所有的物理节点映射到[0-16383]slot 上,cluster 负责维护node<->slot<->value

Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value 时, redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽, redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。

7.png

Redis-cluster 投票&容错

8.png
投票过程是集群中所有 master 参与,如果半数以上 master 节点与 master 节点通信超时(cluster-node-timeout),认为当前 master 节点挂掉.

什么时候整个集群不可用(cluster_state:fail)?

  1. 如果集群任意 master 挂掉,且当前 master 没有 slave.集群进入 fail 状态,也可以理解成集群的 slot 映射[0-16383]不完整时进入 fail 状态. ps : redis-3.0.0.rc1 加入 cluster-require-full-coverage 参数,默认关闭,打开集群兼容部分失败.
  2. 如果集群超过半数以上 master 挂掉,无论是否有 slave,集群进入 fail 状态.

Redis 集群搭建

准备6个实例

为了保证可以进行投票,至少需要3个主节点。每个主节点都需要至少一个从节点,所以需要至少3个从节点。
一共需要6台redis服务器;可以使用6个redis实例。6个redis实例的端口号:7001~7006

复制实例

如果有安装过单机版,那么先停止单机版redis;如果有安装过集群版,那么先停止集群版redis;使用命令找出当前的所有redis进程,然后kill

./redis-cli shutdown
ps -ef | grep redis
kill 进程号 进程号 ...

把bin目录里面的rdb,和aof文件删除,准备干净的redis

cd /usr/local/redis/bin
rm -rf appendonly.aof
rm -f dump.rdb

把bin复制6份

cd ..

删除原有的redis-cluster

rm –rf redis-cluster

创建redis-cluster目录

mkdir redis-cluster
cp -r bin redis-cluster/redis1 && cp -r bin redis-cluster/redis2 && cp -r bin redis-cluster/redis3
cp -r bin redis-cluster/redis4 && cp -r bin redis-cluster/redis5 && cp -r bin redis-cluster/redis6

9.png

修改端口号

依次修改端口号为7001~7006

cd redis1
vi redis.conf

修改第84行,端口6379为7001,其它5个一样修改
10.png

同时启动6个实例
cd /usr/local/redis/redis-cluster

编写启动脚本

vi start-all.sh

在文件中输入如下内容:

cd redis1
./redis-server redis.conf
cd ..
cd redis2
./redis-server redis.conf
cd ..
cd redis3
./redis-server redis.conf
cd ..
cd redis4
./redis-server redis.conf
cd ..
cd redis5
./redis-server redis.conf
cd ..
cd redis6
./redis-server redis.conf
cd ..

设置脚本启动权限

chmod u+x start-all.sh

执行脚本;启动6个实例

./start-all.sh

查看

ps -ef | grep redis

11.png

停止6个redis

ps -ef | grep redis
kill 进程号 进程号 ...
安装环境

redis集群的管理工具使用的是ruby脚本语言,安装集群需要ruby环境。
安装ruby环境

yum install ruby

安装Ruby的打包系统

yum install rubygems

上传redis的ruby接口库

cd /root/software

使用工具上传“redis-3.2.1.gem”到“/root/software”

安装redis的ruby接口库

gem install redis-3.2.1.gem

12.png

创建redis集群
配置集群节点

需要修改每个实例的redis.conf配置文件,开启redis-cluster

cd /usr/local/redis/redis-cluster/
vi redis1/redis.conf

反注释第721行,同样需要修改6个节点;

cluster-enabled yes

重启redis实例

./start-all.sh
集群启动

集群管理工具redis-trib.rb在redis解压文件夹的src的文件夹中;使用redis-cluster的集群管理工具启动集群。
先进入集群管理工具所在的路径

cd /root/software/redis-3.2.4/src/

再启动命令(注意如下连接中的ip最好不用127.0.0.1和默认端口)

./redis-trib.rb create --replicas 1 192.168.12.168:7001 192.168.12.168:7002 192.168.12.168:7003 192.168.12.168:7004 192.168.12.168:7005 192.168.12.168:7006
备注:

1、./redis-trib.rb create –replicas X

X:指定集群中每个主节点配备几个从节点,这里设置为1。

2、redis-trib.rb工具的使用

create:创建集群
check:检查集群
info:查看集群信息
fix:修复集群
reshard:在线迁移slot
rebalance:平衡集群节点slot数量
add-node:将新节点加入集群
del-node:从集群中删除节点
set-timeout:设置集群节点间心跳连接的超时时间
call:在集群全部节点上执行命令
import:将外部redis数据导入集群

启动信息(中间会提示是否设置配置,输入yes),每个主节点分配的哈希槽信息和主从分配信息在此都可查看

>>> Creating cluster
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
192.168.12.168:7001
192.168.12.168:7002
192.168.12.168:7003
Adding replica 192.168.12.168:7004 to 192.168.12.168:7001
Adding replica 192.168.12.168:7005 to 192.168.12.168:7002
Adding replica 192.168.12.168:7006 to 192.168.12.168:7003
M: 28b8be6f285e363a957a275143dc6c5a16640d27 192.168.12.168:7001
slots:0-5460 (5461 slots) master
M: b1157115d9b1f5b15939d13cd01f447423acd3e6 192.168.12.168:7002
slots:5461-10922 (5462 slots) master
M: 1826fa69c51853431725f156dbe902958e96a564 192.168.12.168:7003
slots:10923-16383 (5461 slots) master
S: 201c1643327b7cf07039f14e95383edade027316 192.168.12.168:7004
replicates 28b8be6f285e363a957a275143dc6c5a16640d27
S: a49bb2d84beb4d531345f6b92561454458908a41 192.168.12.168:7005
replicates b1157115d9b1f5b15939d13cd01f447423acd3e6
S: 9dad6428a9f199c0ffd5a0a9b3de1853dec1ca1a 192.168.12.168:7006
replicates 1826fa69c51853431725f156dbe902958e96a564
Can I set the above configuration? (type 'yes' to accept): yes
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join...
>>> Performing Cluster Check (using node 192.168.12.168:7001)
M: 28b8be6f285e363a957a275143dc6c5a16640d27 192.168.12.168:7001
slots:0-5460 (5461 slots) master
1 additional replica(s)
M: 1826fa69c51853431725f156dbe902958e96a564 192.168.12.168:7003
slots:10923-16383 (5461 slots) master
1 additional replica(s)
M: b1157115d9b1f5b15939d13cd01f447423acd3e6 192.168.12.168:7002
slots:5461-10922 (5462 slots) master
1 additional replica(s)
S: 9dad6428a9f199c0ffd5a0a9b3de1853dec1ca1a 192.168.12.168:7006
slots: (0 slots) slave
replicates 1826fa69c51853431725f156dbe902958e96a564
S: a49bb2d84beb4d531345f6b92561454458908a41 192.168.12.168:7005
slots: (0 slots) slave
replicates b1157115d9b1f5b15939d13cd01f447423acd3e6
S: 201c1643327b7cf07039f14e95383edade027316 192.168.12.168:7004
slots: (0 slots) slave
replicates 28b8be6f285e363a957a275143dc6c5a16640d27
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

Redis集群连接

工具连接

redis的单机版,默认是16个数据库,但是redis-Cluster集群版,有多少个主节点,就有多少个数据库(整个集群才是一个完整的数据库)。
1、使用redis命令行客户端连接

cd /usr/local/redis/bin
./redis-cli -h 192.168.12.168 -p 7006 -c

13.png

【注意】一定要加-c参数,节点之间则可以互相跳转

2、使用图形客户端连接
因为有3台主redis数据库,所以需要连接3台。

代码连接
public class JedisClusterTest {

@Test
public void test() throws IOException {
// 设置集群节点
Set<HostAndPort> nodes = new HashSet<>();
nodes.add(new HostAndPort("192.168.12.168", 7001));
nodes.add(new HostAndPort("192.168.12.168", 7002));
nodes.add(new HostAndPort("192.168.12.168", 7003));
nodes.add(new HostAndPort("192.168.12.168", 7004));
nodes.add(new HostAndPort("192.168.12.168", 7005));
nodes.add(new HostAndPort("192.168.12.168", 7006));

// 创建jedis集群对象
JedisCluster jedisCluster = new JedisCluster(nodes);

// 设置值
jedisCluster.set("jedisCluster_msg", "redis-集群");

// 获取键值
String msg = jedisCluster.get("jedisCluster_msg");
System.out.println(msg);

// 关闭jedisCluster连接(在程序执行完之后,才能关闭,他的内部已经封装了连接池)
jedisCluster.close();
}

}

Redis的通用命令

在Resid安装目录下,使用redis-cli客户端连接Redis数据库

连接远程Redis服务器

redis-cli -h [ip] -p [host] -a [密码]

# 如果Redis设置了密码,则需要使用密码连接

密码设置

  • 配置文件设置

找到# requirepass foobared,去掉#注释,配置密码(或者干脆另起一行,照着写就是),需要重启Redis服务

  • 命令设置

密码信息保存在服务器内存中,不需要重启Redis服务,但服务器重启后将失效

config set requirepass 密码 #设置密码
config get requirepass #查看密码

keys pattern

获取所有与pattern匹配的key,返回所有与该key匹配的keys。
Patterm参数解析:

127.0.0.1:6379> keys *
1) "company"
2) "mylist"
3) "myhash"
4) "myset"

del key1 key2…

删除一个或多个指定的key,返回值是删除key的个数

127.0.0.1:6379> del company
(integer) 1

exists key

判断该key是否存在,1代表存在,0代表不存在

127.0.0.1:6379> exists compnay
(integer) 0
127.0.0.1:6379> exists mylist
(integer) 1
127.0.0.1:6379>

type key

获取指定key的类型。该命令将以字符串的格式返回。 返回的字符串为string、list、set、hash,如果key不存在返回none

127.0.0.1:6379> type company
string
127.0.0.1:6379> type mylist
list
127.0.0.1:6379> type myset
set
127.0.0.1:6379> type myhash
hash
127.0.0.1:6379>

select 切换数据库

一个Redis服务器可以包括多个数据库,客户端可以指定连接Redis中的哪个数据库,就好比一个mysql服务器中创建多个数据库,客户端连接时指定连接到哪个数据库。一个Redis实例最多可提供16个数据库,下标为0到15,客户端默认连接第0个数据库,也可以通过select命令选择哪个数据库。

move移key到其他数据库

将key移到某个数据库;
move key 15 : 将当前数据库中的key移到15号数据库中

info 获取 redis 服务器的统计信息

127.0.0.1:6379> info
# Server
redis_version:3.2.100
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:1fe181ad2447fe38
redis_mode:standalone
os:Windows
arch_bits:64
multiplexing_api:winsock_IOCP
gcc_version:0.0.0
process_id:13028
run_id:180f539248b89f5359be251550b4b28d0171805f
tcp_port:6379
uptime_in_seconds:1795
uptime_in_days:0
hz:10
lru_clock:4401579
config_file:

# Clients
connected_clients:1
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:0

# Memory
used_memory:4360680
used_memory_human:4.16M
used_memory_rss:4327104
used_memory_peak:4360680
used_memory_peak_human:4.16M
used_memory_lua:33792
mem_fragmentation_ratio:0.99
mem_allocator:dlmalloc-2.8

# Persistence
loading:0
rdb_changes_since_last_save:0
rdb_bgsave_in_progress:0
rdb_last_save_time:1598235304
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:-1
rdb_current_bgsave_time_sec:-1
aof_enabled:0
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok

# Stats
total_connections_received:4
total_commands_processed:5
instantaneous_ops_per_sec:0
rejected_connections:0
sync_full:0
sync_partial_ok:0
sync_partial_err:0
expired_keys:0
evicted_keys:0
keyspace_hits:0
keyspace_misses:0
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:0

# Replication
role:master
connected_slaves:0
master_repl_offset:0
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

# CPU
used_cpu_sys:0.05
used_cpu_user:0.03
used_cpu_sys_children:0.00
used_cpu_user_children:0.00

# Keyspace
db0:keys=1,expires=1,avg_ttl=425280

Help

HELP命令可以查看redis的一些命令的用法;当忘记某个命令的使用时很有用。

Redis的数据类型

Redis的5种数据类型

redis是一种高级的key-value的存储系统,其中value支持五种数据类型:

  1. 字符串(String)
  2. 哈希(hash)
  3. 字符串列表(list)
  4. 字符串集合(set)
  5. 有序字符串集合(sorted set)

在日常开发中主要使用比较多的有字符串、哈希、字符串列表、字符串集合四种类型,其中最为常用的是字符串类型。

关于key的定义,注意如下几点:

  1. key不要太长,最好不要超过1024个字节,这不仅会消耗内存还会降低查找效率
  2. key不要太短,如果太短会降低key的可读性
  3. 在项目中,key最好有一个统一的命名规范(见名知意)

字符串类型string

概述

字符串类型是Redis中最为基础的数据存储类型,它在Redis中是二进制安全的,这便意味着字符串类型存入和获取的数据相同。在Redis中字符串类型的Value最多可以容纳的数据长度是512M。

常用命令

  • set key value

设定key的value。指定字符串的value,如果该key存在则进行覆盖操作。总是返回”OK”

127.0.0.1:6379> set company "itcast"
OK
127.0.0.1:6379>
  • get key

获取key的value。如果与该key关联的value不是String类型,redis将返回错误信息,因为get命令只能用于获取String value;如果该key不存在,返回(nil)。

127.0.0.1:6379> set name "itcast"
OK
127.0.0.1:6379> get name
"itcast"
  • del key

删除指定key,返回影响的记录数

127.0.0.1:6379> del name
(integer) 1
127.0.0.1:6379> get name
(nil)

哈希类型hash

概述

Redis中的Hash类型可以看成具有String Key和String Value的map容器。所以Hash类型非常适合于存储键值对的信息。如Username、Password和Age等。如果Hash中包含很少的字段,那么该类型的数据也将仅占用很少的内存空间。每一个Hash可以存储4294967295个键值对。

常用命令

  • hset key field value

为指定的key设定field/value对(键值对)。返回影响的记录数

127.0.0.1:6379> hset myhash username haohao
(integer) 1
127.0.0.1:6379>
  • hget key field

获取指定的key中的field的值

127.0.0.1:6379> hset myhash username haohao
(integer) 1
127.0.0.1:6379> hget myhash username
"haohao"
  • hmset key field value [field1 value1 field2 value2…]

设置key中的多个filed/value

127.0.0.1:6379> hmset myhash username jack age 21
OK
  • hmget key fileds

获取key中的多个filed的值

127.0.0.1:6379> hmget myhash username age 
1)”jack”
2)”18”
  • hgetall key

获取key中所有map的key和value

127.0.0.1:6379> hset h_user id 1
(integer) 1
127.0.0.1:6379> hmset h_user age 12 name itcast gender 1
OK
127.0.0.1:6379> hgetall h_user
1) "id"
2) "1"
3) "age"
4) "12"
5) "name"
6) "itcast"
7) "gender"
8) "1"
  • hdel key field [field … ]

可以删除一个或多个字段,返回值是被删除的字段个数

127.0.0.1:6379> hdel myhash username age
(integer) 2
127.0.0.1:6379> hget myhash username
(nil)
127.0.0.1:6379>
  • HEXISTS key field

查看哈希表 key 中,判断域field 是否存在

127.0.0.1:6379> hexists myhash name
(integer) 1
127.0.0.1:6379> hexists myhash birthday
(integer) 0
  • HKEYS key和HVALS key

HKEYS key:获取哈希表Key的所有域field
HVALS key:获取哈希表key的所有域field对应的值

127.0.0.1:6379> hkeys h_user
1) "id"
2) "name"
127.0.0.1:6379> hvals h_user
1) "1"
2) "itcast"
  • HLEN key

返回哈希表 key 中域field的数量

127.0.0.1:6379> hlen h_user
(integer) 2

列表类型list

概述

在Redis中,List类型是按照插入顺序排序的字符串链表(java中的linkedlist)。和数据结构中的普通链表一样,我们可以在其头部(left)和尾部(right)添加新的元素。在插入时,如果该键并不存在,Redis将为该键创建一个新的链表。与此相反,如果链表中所有的元素均被移除,那么该键也将会被从数据库中删除。List中可以包含的最大元素数量是4294967295,list类型允许有重复元素

常用命令

  • lpush key value1 value2 …

在指定的key所关联的list的头部插入所有的values,如果该key不存在,该命令在插入的之前创建一个与该key关联的空链表,之后再向该链表的头部插入数据。插入成功,返回元素的个数。

127.0.0.1:6379> lpush mylist a b c
(integer) 3
127.0.0.1:6379>
  • rpush key value1 value2 …

在指定的key对应的list的尾部插入所有的value,如果该key不存在,该命令在插入之前创建一个与该key对应的空链表,再从尾部插入数据。插入成功,返回元素的个数。

127.0.0.1:6379> lpush l_users 1 2 3 a b
(integer) 5

注意:是左边添加,所以最终最左边的元素为b

127.0.0.1:6379> rpush l_users d e
(integer) 7

注意:是右边添加,所以最终最右边的元素为e

  • lrange key start end查看列表

获取链表中从start到end的元素的值,索引从0开始,如果为负数,-1表示倒数第一个元素,-2表示倒数第二个元素,以此类推。

127.0.0.1:6379> lrange l_users 0 -1
1) "b"
2) "a"
3) "3"
4) "2"
5) "1"
6) "d"
7) "e"
  • lpop key,从头部弹出元素(移除)

返回并弹出指定的key关联的链表中的第一个元素,即头部元素。如果该key不存在,返回nil;若key存在,则返回链表的头部元素。

127.0.0.1:6379> lpush mylist a b c
(integer) 3
127.0.0.1:6379> lpop mylist
"c"
127.0.0.1:6379> lpop mylist
"b"
  • rpop key,从尾部弹出元素(移除)

返回并弹出指定的key关联的链表中的最后一个元素,即尾部元素。如果该key不存在,返回nil;若key存在,则返回链表的尾部元素。

127.0.0.1:6379> lpush mylist a b c
(integer) 3
127.0.0.1:6379> rpop mylist
"a"
  • LLEN key

返回指定key对应链表中元素的个数

127.0.0.1:6379> lrange l_users 0 -1
1) "b"
2) "a"
3) "3"
4) "2"
5) "1"
6) "d"
7) "e"
127.0.0.1:6379> llen l_users
(integer) 7
  • LREM key count value

LREM命令会删除列表中前count个值为value的元素,返回实际删除的元素个数。根据count值的不同,该命令的执行方式会有所不同:

  1. 当count>0时, LREM会从列表左边(头部)开始删除。
  2. 当count<0时, LREM会从列表后边(尾部)开始删除。
  3. 当count=0时, LREM删除所有值为value的元素。
127.0.0.1:6379> lpush l_users 1 2 3
(integer) 10
127.0.0.1:6379> lrange l_users 0 -1
1) "3"
2) "2"
3) "1"
4) "b"
5) "a"
6) "3"
7) "2"
8) "1"
9) "d"
10) "e"

删除列表l_users中2个值为3的元素

127.0.0.1:6379> lrem l_users 2 3
(integer) 2
127.0.0.1:6379> lrange l_users 0 -1
1) "2"
2) "1"
3) "b"
4) "a"
5) "2"
6) "1"
7) "d"
8) "e"
  • LINDEX key index

获得指定索引的元素值

127.0.0.1:6379> lindex l_users 3
"b"

无序集合set

概述

在Redis中,我们可以将Set类型看作为没有排序的字符集合,和List类型一样,我们也可以在该类型的数据值上执行添加、删除或判断某一元素是否存在等操作。set集合类型可包含的最大元素数量是4294967295,和List类型不同的是,set集合类型中不允许出现重复的元素,且无序。 

常用命令

  • sadd key values[value1 value2 …]

向set中无序添加一个或多个数据,如果该key的值已有则不会重复添加

127.0.0.1:6379> sadd myset a b c
(integer) 3
  • smembers key

获取set中所有的成员

127.0.0.1:6379> smembers myset
1) "c"
2) "a"
3) "b"
  • srem key members[member1、member2…]

删除set中指定的成员

127.0.0.1:6379> srem myset a b
(integer) 2
127.0.0.1:6379> smembers myset
1) "c"
127.0.0.1:6379>
  • SISMEMBER key member

判断元素是否存在集合中

127.0.0.1:6379> sismember myset c
(integer) 1
  • SCARD key

获得集合中元素的个数

127.0.0.1:6379> scard myset
(integer) 1

有序集合sorted set

概述

在集合类型的基础上有序集合类型(sorted set)为集合中的每个元素都关联一个分数,这使得我们不仅可以完成插入、删除和判断元素是否存在在集合中,还能够获得分数最高或最低的前N个元素、获取指定分数范围内的元素等与分数有关的操作。

有序集合和列表类型区别:

  1. 相同点:

    1、二者都是有序的。
    2、二者都可以获得某一范围的元素。

  2. 不同点:

    1、列表类型是通过链表实现的,获取靠近两端的数据速度极快,而当元素增多后,访问中间数据的速度会变慢。
    2、有序集合类型使用散列表实现,所以即使读取位于中间部分的数据也很快。
    3、列表中不能简单的调整某个元素的位置,但是有序集合可以(通过更改分数实现)
    4、有序集合要比列表类型更耗内存。

常用命令

  • 增加元素:ZADD key score member [score member …]

向有序集合中加入一个元素和该元素的分数,如果该元素已经存在则会用新的分数替换原有的分数。返回值是新加入到集合中的元素个数,不包含之前已经存在的元素。 

127.0.0.1:6379> zadd z_users 10 a 20 b 30 c
(integer) 3
  • 获取指定区间元素:ZRANGE key start stop [WITHSCORES]

返回有序集合key 中,指定区间内的成员。其中成员的位置按 score 值递增 (从小到大) 来排序。start开始位置,stop结束位置(-1则为最后一个元素)

127.0.0.1:6379> zrange z_users 0 -1
1) "a"
2) "b"
3) "c"
127.0.0.1:6379> zrange z_users 0 -1 withscores
1) "a"
2) "10"
3) "b"
4) "20"
5) "c"
6) "30"
  • 按照排名范围删除元素:ZREMRANGEBYRANK key start stop

删除排名(按分数排)范围在第3的元素

127.0.0.1:6379> zremrangebyrank z_users 2 2
(integer) 1
127.0.0.1:6379> zrange z_users 0 -1
1) "a"
2) "b"
  • 按照分数范围删除元素:ZREMRANGEBYSCORE key min max

删除分数范围为5-10(包括端点值5和10)的元素

127.0.0.1:6379> zremrangebyscore z_users 5 10
(integer) 1
127.0.0.1:6379> zrange z_users 0 -1
1) "b"

总结

Redis的持久化

持久化概述

Redis的高性能是由于其将所有数据都存储在了内存中,为了使Redis在重启之后仍能保证数据不丢失,需要将数据从内存中同步到硬盘中,这一过程就是持久化。
Redis支持两种方式的持久化,一种是RDB方式,一种是AOF方式。可以单独使用其中一种或将二者结合使用。

  • RDB持久化(默认支持,无需配置)
    该机制是在指定的时间间隔内将内存中的数据集快照写入磁盘。
  • AOF持久化
    该机制将以日志的形式记录服务器所处理的每一个写操作,在Redis服务器启动之初会读取该文件来重新构建数据库,以保证启动后数据库中的数据是完整的。
  • 无持久化
    可以通过配置的方式禁用Redis服务器的持久化功能,这样可以将Redis视为一个功能加强版的memcached了。
  • redis可以同时使用RDB和AOF

RDB持久化机制

优点

  1. 一旦采用该方式,那么你的整个Redis数据库将只包含一个文件(rdb文件),这对于文件备份而言是非常完美的。比如,你可能打算每个小时归档一次最近24小时的数据,同时还要每天归档一次最近30天的数据。通过这样的备份策略,一旦系统出现灾难性故障,我们可以非常容易的进行恢复。
  2. 对于灾难恢复而言,RDB是非常不错的选择。因为我们可以非常轻松的将一个单独的文件压缩后再转移到其它存储介质上
  3. 性能最大化。对于Redis的服务进程而言,在开始持久化时,它唯一需要做的只是fork(分叉)出子进程,之后再由子进程完成这些持久化的工作,这样就可以极大的避免服务进程执行IO操作了。相比于AOF机制,如果数据集很大,RDB的启动效率会更高 

缺点

  1. 如果你想保证数据的高可用性(就是内存数据不丢失),即最大限度的避免数据丢失,那么RDB将不是一个很好的选择。因为系统一旦在定时持久化之前出现宕机现象,此前没有来得及写入磁盘的数据都将丢失。
  2. 由于RDB是通过fork子进程来协助完成数据持久化工作的,因此,如果当数据集较大时,可能会导致整个服务器停止服务几百毫秒,甚至是1秒钟

配置

在redis.windows.conf配置文件中有如下配置:

其中,上面配置的是RDB方式数据持久化时机,可以多个条件配合

AOF持久化机制

优点

  1. 该机制可以带来更高的数据安全性,即数据持久性。Redis中提供了3种同步策略,即每秒同步、每修改同步和不同步。事实上,每秒同步也是异步完成的,其效率也是非常高的,所差的是一旦系统出现宕机现象,那么这一秒钟之内修改的数据将会丢失。而每修改同步,我们可以将其视为同步持久化,即每次发生的数据变化都会被立即记录到磁盘中。可以预见,这种方式在效率上是最低的。至于无同步,无需多言,我想大家都能正确的理解它。
  2. 由于该机制对日志文件的写入操作采用的是append模式,因此在写入过程中即使出现宕机现象,也不会破坏日志文件中已经存在的内容。然而如果本次操作只是写入了一半数据就出现了系统崩溃问题,不用担心,在Redis下一次启动之前,我们可以通过redis-check-aof工具来帮助我们解决数据一致性的问题。
  3. 如果日志过大,Redis可以自动启用rewrite机制。即Redis以append模式不断的将修改数据写入到老的磁盘文件中,同时Redis还会创建一个新的文件用于记录此期间有哪些修改命令被执行。因此在进行rewrite切换时可以更好的保证数据安全性。
  4. AOF包含一个格式清晰、易于理解的日志文件用于记录所有的修改操作。事实上,我们也可以通过该文件完成数据的重建

缺点

  1. 对于相同数量的数据集而言,AOF文件通常要大于RDB文件
  2. 根据同步策略的不同,AOF在运行效率上往往会慢于RDB。

配置

开启AOF持久化

在redis.windows.conf配置文件中有如下配置:

将appendonly修改为yes,开启aof持久化机制,默认会在目录下产生一个appendonly.aof文件
启动需要指定配置文件

AOF持久化时机
#appendfsync always
appendfsync everysec
#appendfsync no

上述配置为aof持久化的时机,解释如下:

Jedis的基本使用

介绍

Redis不仅是使用命令来操作,现在基本上主流的语言都有客户端支持,比如java、C、C#、C++、php、Node.js、Go等。 在官方网站里列一些Java的客户端,有Jedis、Redisson、Jredis、JDBC-Redis、等其中官方推荐使用Jedis和Redisson。 在企业中用的最多的就是Jedis,Jedis同样也是托管在github上,地址:

https://github.com/xetorthio/jedis

Jedis基本上实现了所有的Redis命令,并且还支持连接池、集群等高级的用法,而且使用简单,使得在Java中使用Redis服务将变得非常的简单,Maven依赖:

<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.2.0</version>
<type>jar</type>
<scope>compile</scope>
</dependency>

基本操作

常用API

代码操作

package com.itheima.jedis;

import redis.clients.jedis.Jedis;
import java.util.List;

/**
* jedis的使用
*/
public class JedisTest1 {
public static void main(String[] args) {
/*
目的:使用jedis操作redis,进行存取数据
1.创建jedis对象,连接到redis服务器端
public Jedis(String host, int port)
host,指定redis服务器地址
port,指定redis使用的端口号
*/
Jedis jedis = new Jedis("localhost",6379);

/*
2.往redis里面写入数据
通过jedis操作redis,与使用redis客户端执行命令是一致的
客户端所有的命令都是jedis的方法,所有key和value都是方法的参数
*/
//存入字符串数据,jedis.set(key,value);
jedis.set("name","javaee87");

//存入list数据,jedis.lpush(key,value可变参数);
jedis.lpush("myList2","one","two","three");

//3.从redis里面读取数据
//取string数据,jedis.get(key)
String name = jedis.get("name");

//取list数据,List<String> myList2 = jedis.lrange(key,start,end);
List<String> myList2 = jedis.lrange("myList2",0,-1);

//打印
System.out.println("name="+name);
System.out.println("myList2="+myList2);

//4.关闭连接
jedis.close();
}
}

连接池的使用

基本概念

jedis连接资源的创建与销毁是很消耗程序性能,所以jedis为我们提供了jedis的池化技术,jedisPool在创建时初始化一些连接资源存储到连接池中,使用jedis连接资源时不需要创建,而是从连接池中获取一个资源进行redis的操作,使用完毕后,不需要销毁该jedis连接资源,而是将该资源归还给连接池,供其他请求使用。

常用API

代码操作

package com.itheima.jedis;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.util.List;

/**
* jedis的使用
*/
public class JedisTest2 {
public static void main(String[] args) {
//目的:使用连接池优化jedis操作redis,进行存取数据
//1.创建jedis连接池配置对象,并设置配置连接池的参数
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(100);//最大连接数
config.setMaxWaitMillis(3000);//用户等待连接超时事件,等待3秒

//2.根据配置对象创建jedis连接池对象
//public JedisPool(GenericObjectPoolConfig poolConfig, String host, int port)
JedisPool jedisPool = new JedisPool(config,"localhost",6379);

//3.根据连接池获取jedis连接对象
Jedis jedis = jedisPool.getResource();

//4.往redis里面写入数据
jedis.set("name","javaee87");

//存入list数据,jedis.lpush(key,value可变参数);
jedis.lpush("myList2","one","two","three");

//5.从redis里面读取数据
//取string数据,jedis.get(key)
String name = jedis.get("name");

//取list数据,List<String> myList2 = jedis.lrange(key,start,end);
List<String> myList2 = jedis.lrange("myList2",0,-1);

//打印
System.out.println("name="+name);
System.out.println("myList2="+myList2);

//6.关闭连接
jedis.close();

//7.关闭连接池
//jedisPool.close();,连接池不要关闭,关闭了连接池就不能用了
}
}

连接池工具类

配置文件

jedis.properties

maxTotal=100
maxWaitMillis=3000
host=localhost
port=6379

工具类

package com.itheima.util;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.util.ResourceBundle;

public class JedisUtils {

//jedis连接池对象
private static JedisPool jedisPool;

//通过静态代码块初始化
static{
//解析jedis.properties配置文件
//ResourceBundle专门用于解析properties文件,只需要提供文件名就可以解析
ResourceBundle resourceBundle = ResourceBundle.getBundle("jedis");
//获取里面的数据
int maxTotal = Integer.parseInt(resourceBundle.getString("maxTotal"));
int maxWaitMillis = Integer.parseInt(resourceBundle.getString("maxWaitMillis"));
String host = resourceBundle.getString("host");
int port = Integer.parseInt(resourceBundle.getString("port"));
//创建连接池配置对象
JedisPoolConfig config = new JedisPoolConfig();
config.setMaxTotal(maxTotal);
config.setMaxWaitMillis(maxWaitMillis);
//初始化连接池对象
jedisPool = new JedisPool(config,host,port);
}


//提供一个方便获取jedis连接的工具类方法
public static Jedis getJedis(){
return jedisPool.getResource();
}
}

测试代码

package com.itheima.jedis;

import com.itheima.util.JedisUtils;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

import java.util.List;

/**
* jedis的使用
*/
public class JedisTest3 {
public static void main(String[] args) {
//目的:使用连接池优化jedis操作redis,进行存取数据

//1.使用工具类获取jedis连接对象
Jedis jedis = JedisUtils.getJedis();
//2.往redis里面写入数据
jedis.set("name","javaee87黑马程序员");
//存入list数据,jedis.lpush(key,value可变参数);
jedis.lpush("myList2","one","two","three");
//3.从redis里面读取数据
//取string数据,jedis.get(key)
String name = jedis.get("name");
//取list数据,List<String> myList2 = jedis.lrange(key,start,end);
List<String> myList2 = jedis.lrange("myList2",0,-1);
//打印
System.out.println("name="+name);
System.out.println("myList2="+myList2);

//4.关闭连接
jedis.close();

}
}

过期与淘汰策略

长期将Redis作为缓存使用,难免会遇到内存空间存储瓶颈,当Redis内存超出物理内存限制时,Redis性能将急剧下降。此时如何淘汰无用数据释放空间,存储新数据就变得尤为重要了。

设置占用内存

  • 配置文件配置
    找到# maxmemory ,去掉#注释,设置maxmemory参数,maxmemory是bytes字节类型,注意转换,一般推荐Redis设置使用内存为最大物理内存的四分之三,Redis服务重启后不会失效

不会转换的,可到如下网址换算大小:

在线文件大小换算:https://www.bejson.com/convert/filesize/

  • 命令修改
    使用redis-cli客户端命令修改,Redis服务重启后将失效

如果不设置最大内存大小或者设置最大内存大小为0,在64位操作系统下不限制内存大小,在32位操作系统下最多使用3GB内存

过期策略

Redis采用的过期策略是:定期删除+惰性删除策略。

  • 为什么不用定时删除策略?

定时删除,用一个定时器来负责监视key,过期则自动删除。虽然内存及时释放,但是十分消耗CPU资源。在大并发请求下,CPU要将时间应用在处理请求,而不是删除key。因此没有采用这一策略.

  • 定期删除+惰性删除是如何工作的呢?

定期删除,redis默认每个100ms检查一次,随机抽取进行检查(如果每隔100ms,全部key进行检查,redis岂不是卡死)。因此,如果只采用定期删除策略,会导致很多key到时间没有删除。于是,惰性删除派上用场。也就是说在你获取某个key的时候,redis会检查一下,这个key如果设置了过期时间那么是否过期了?如果过期了此时就会删除。

  • 采用定期删除+惰性删除就没其他问题了么?

不是的,如果定期删除没删除key。然后你也没即时去请求key,也就是说惰性删除也没生效。这样,redis的内存会越来越高。那么就应该采用内存淘汰机制。

淘汰策略

Redis定义了六种策略用来处理这种情况:

  1. noeviction(默认策略):对于写请求不再提供服务,直接返回错误(DEL请求和部分特殊请求除外)
  2. allkeys-lru:从所有key中,使用LRU算法进行淘汰最近最少使用的数据
  3. allkeys-random:从所有key中,随机选择数据淘汰
  4. volatile-lru:从设置了过期时间的key中,使用LRU算法进行淘汰最近最少使用的数据
  5. volatile-random:从设置了过期时间的key中,随机选择数据淘汰
  6. volatile-ttl:在设置了过期时间的key中,根据key的过期时间进行淘汰,越早过期的越优先被淘汰

注:

  • 当使用volatile-lru、volatile-random、volatile-ttl这三种策略时,如果key没有设置 expire(过期时间),则和noeviction一样返回错误
  • 将key设置过期时间实际上会消耗更多的内存,因此建议使用allkeys-lru策略从而更有效率的使用内存

配置文件设置

找到# maxmemory-policy,去掉#注释,在maxmemory-policy后设置淘汰策略,Redis重启后不会失效

命令修改

使用redis-cli客户端命令修改,Redis服务重启后将失效

LRU算法

LRU(Least Recently Used),即最近最少使用,是一种缓存置换算法。在使用内存作为缓存的时候,缓存的大小一般是固定的。当缓存被占满,这个时候继续往缓存里面添加数据,就需要淘汰一部分老的数据,释放内存空间用来存储新的数据。这个时候就可以使用LRU算法了。
核心思想是:如果一个数据在最近一段时间没有被用到,那么将来被使用到的可能性也很小,所以就可以被淘汰掉。

在Redis中的实现
近似LRU算法

Redis使用的是近似LRU算法,它跟常规的LRU算法还不太一样。近似LRU算法通过随机采样法淘汰数据,每次随机出5(默认)个key,从里面淘汰掉最近最少使用的key。

可以通过maxmemory-samples参数修改采样数量:例:maxmemory-samples 10 maxmenory-samples配置的越大,淘汰的结果越接近于严格的LRU算法

Redis为了实现近似LRU算法,给每个key增加了一个额外增加了一个24bit的字段,用来存储该key最后一次被访问的时间。

Redis3.0的优化

Redis3.0对近似LRU算法进行了一些优化。新算法会维护一个候选池(大小为16),池中的数据根据访问时间进行排序,第一次随机选取的key都会放入池中,随后每次随机选取的key,只有在访问时间小于池中最小的时间才会放入池中,直到候选池被放满。当放满后,如果有新的key需要放入,则将池中最后访问时间最大(最近被访问)的移除。

当需要淘汰的时候,则直接从池中选取最近访问时间最小(最久没被访问)的key淘汰掉就行。

LFU算法

LFU算法是Redis4.0里面新加的一种淘汰策略。它的全称是Least Frequently Used,它的核心思想是根据key的最近被访问的频率进行淘汰,很少被访问的优先被淘汰,被访问的多的则被留下来。

LFU一共有两种策略:

  1. volatile-lfu:在设置了过期时间的key中,使用LFU算法淘汰key
  2. allkeys-lfu:在所有的key中,使用LFU算法淘汰数据

设置使用这两种淘汰策略跟前面讲的一样,不过要注意的一点是这两种策略只能在Redis4.0及以上设置,如果在Redis4.0以下设置会报错

LRU与LFU的区别

LFU算法能更好的表示一个key被访问的热度。假如你使用的是LRU算法,一个key很久没有被访问到,只刚刚是偶尔被访问了一次,那么它就被认为是热点数据,不会被淘汰,而有些key将来是很有可能被访问到的则被淘汰了(Redis不直接使用LRU算法的原因)。如果使用LFU算法则不会出现这种情况,因为使用一次并不会使一个key成为热点数据。