Redis是一个使用ANSI C编写的开源、支持网络、基于内存、可选持久性的键值对(key-value)存储数据库,从2015年6月开始,Redis的开发由Redis Labs赞助,而2013年5月至2015年6月期间,其开发由Pivotal赞助。在2013年5月之前,其开发由VMware赞助。根据月度排行网站DB-Engines.com的数据显示,Redis是最流行的健值对存储数据库。
? 数据来源:https://db-engines.com/en/ranking
? Redis采用内存(ln-Memory)数据集(DataSet)。
? 支持多种数超类型,支持字符串(string)、列表(list)、集合set)、散列(hash)、有序集合(zset)五种数据类型。
? 运行于大多数POSIX系统,如Linux、*BSD、OS X等。
? Redist作者:Salvatore Sanfilippo
? 作者GitHUB:http://github.com/antirez/redis
? 官方网站:https://redis.io
? 官方各版本下载地址:http://download.redis.io/releases/
? Redis中文命令参考:http://redisdoc.com
? 中文网站1:http://redis.cn
? 中文网站2:http://www.redis.net.cn
? 高速读写,数据类型丰富(数据读取的速度最高可达到 110000 次/s,数据写入速度最高可达到 81000 次/s)
? 支持持久化,多种内存分配及回收策略
? 支持弱事务,消息队列、消息订阅
? 支持高可用,支持分布式分片集群
Memcached
优点:高性能读写、单一数据类型、支持客户端式分布式集群、一致性haSh多核结构、多线程读写性能高。
缺点:无持久化、节点故障可能出现缓存穿透、分布式需要客户端实现、跨房数据同步困难、架构扩容复余度高。
Redis
优点:高性能读写、多数据类型支持、数据持久高可用架构、支持自定义虚拟内存、支特分布式分片集群、单线程读写性能极高。
缺点:多线程读写较Memcached慢
Tair
官方网站:http://air.taobao.org
优点:高性能读写、支持三种存储引擎(ddb、rdb、ldb)、支持高可用、支持分布式分片集群、支撑了几乎所有淘宝业务的缓存。
缺点:单机情况下,读写性能较其他两种产品较慢。
? 数据高速缓存,web会话缓存(Session Cache)
? 排行榜应用
? 消息队列发布订阅
? 附录·Redis的企业应用
#编译安装redis
[root@redis opt]# wget http://download.redis.io/releases/redis-5.0.7.tar.gz
[root@redis opt]# tar -zxvf redis-5.0.7.tar.gz -C /usr/local
[root@redis opt]# yum install gcc -y #gcc-v直看,如果没有需要安装
[root@redis opt]# cd /usr/local/redis-5.0.7
[root@redis redis-5.0.7]# make MALLOC=lib
[root@redis redis-5.0.7]# cd src && make all
[root@redis src]# make install
#启动redis实例
[root@redis src]# ./redis-server
#出现以上界面说明安装成功
#查询redis版本
[root@redis src]# ./redis-cli --version
redis-cli 5.0.7
[root@redis src]# ./redis-server --version
Redis server v=5.0.7 sha=00000000:0 malloc=libc bits=64 build=88e3df177d75c095
#开启redis服务守护进程。
#以./redis-server启动方式,需要一直打开窗口,不能进行其他操作,不太方便,以后台进程方式启动redis
[root@redis src]# vim /usr/local/redis-5.0.7/redis.conf #yum安装好的配置文件并不在这个目录下
#--136行-- daemonize no 改为yes
#因为刚才修改了配置文件所以要指定配置文件去启动一下,因为是编译安装的,所以redis自己也不知道配置文件在哪儿
[root@redis src]# ./redis-server /usr/local/redis-5.0.7/redis.conf
[root@redis redis-5.0.7]# ps -ef|grep redis
root 60719 1 0 16:41 ? 00:00:01 ./src/redis-server 127.0.0.1:6379
root 60936 4870 0 17:02 pts/1 00:00:00 grep --color=auto redis
[root@redis redis-5.0.7]# kill -9 60719
#此方法启动关闭较为麻烦,且不能设置开机自启动
#编辑redis配置文件
[root@redis redis-5.0.7]# vim /usr/local/redis-5.0.7/redis.conf
#bind127.0.0.1 #将bind127.0,0,1注释掉,否则数据库只有本机能够使用或者改为0.0.0.0
daemonize yes #136行,将no改为yes,使数据库能够以后台守护进程运行
protected-mode no #88行,把保护模式的yes改为no,否则会阻止远程访阿
requirepass redis #507行,修改并打开注释,设置密码
#添加redis系统自启动
#开机自启动,将redis的启动脚本复制一份放到/etc/init.d目录下
[root@redis redis-5.0.7]# cp /usr/local/redis-5.0.7/utils/redis_init_script /etc/init.d/redis
[root@redis redis-5.0.7]# vim /etc/init.d/redis
CONF="/usr/local/redis-5.0.7/redis.conf" #将conf的变量修改下,否则读不到配置文件
[root@redis redis-5.0.7]# cd /etc/init.d
[root@redis init.d]# chkconfig redis on #开启redis服务
#通过systemctl管理redis
[root@redis init.d]# systemctl start redis #启动redis服务
[root@redis init.d]# systemctl status redis #查看redis状态
● redis.service - LSB: Redis data structure server
Loaded: loaded (/etc/rc.d/init.d/redis; bad; vendor preset: disabled)
Active: active (exited) since 一 2022-08-22 17:47:47 CST; 1s ago
Docs: man:systemd-sysv-generator(8)
Process: 61405 ExecStart=/etc/rc.d/init.d/redis start (code=exited, status=0/SUCCESS)
8月 22 17:47:47 redis systemd[1]: Starting LSB: Redis data structure server...
8月 22 17:47:47 redis redis[61405]: /var/run/redis_6379.pid exists, process is alre...hed
8月 22 17:47:47 redis systemd[1]: Started LSB: Redis data structure server.
Hint: Some lines were ellipsized, use -l to show in full.
多实例配置需基于单实例配置完成后
[root@redis ~]# mkdir -p /mnt/redis
[root@redis ~]# cd /mnt/redis
[root@redis ~]# vim install_redis.sh
#!/bin/bash
#部署实例脚本
for i in 0 1 2 3
do
#创建多实例(端口命名)目录
mkdir -p /mnt/redis/638$i
#复制启动程序到各实例
cp /usr/local/redis-5.0.7/src/redis-server /mnt/redis/638$i
#复制配置文件。注意:此处基于单实例配置完成
cp /usr/local/redis-5.0.7/redis.conf /mnt/redis/638$i/
#修改程序存储日录
sed -i '/dir/s#.*#dir /mnt/redis/638'$i'/#g' /mnt/redis/638$i/redis.conf
#修改其他端口信息
sed -i 's/6379/638'$i'/g' /mnt/redis/638$i/redis.conf
#允许远程连接redis
sed -i '/protected-mode/s#yes#no#g' /mnt/redis/638$i/redis.conf
done
[root@redis ~]# vim start_redis.sh
#!/bin/bash
#启动实例脚本
for i in 0 1 2 3
do
/mnt/redis/638$i/redis-server /mnt/redis/638$i/redis.conf
done
以上redis版本为5.0.7。需要多少个redis服务可自定义在脚本中修改。
字段 | 含义 |
---|---|
daemonize no/yes | 是否后台运行 |
port 6379 | 默认端口 |
appendonly no/yes | AOF日志开关是否打开 |
logfile /var/log/redis.log | 日志文件位置 |
dbfilename dump.rdb | RDB持久化数据文件 |
bind 0.0.0.0 ip2 ip3 ip3 | 指定IP进行监听 |
protected-mode yes/no(保护模式。是否只允许本地访问) | 禁止protected-mode |
requirepass root | 增加requirepass (password) |
auth {password}进行认证 | 在redis-cli中使用 |
#获取当前配置
comfig get *
#变更运行配置
config set loglevel "notice"
#修改密码为空
config set requirepass ""
exit
config get dir
1) "dir"
2) "/usr/local/redis/data"
redis提供了两种不同级别的持久化方式:一种是RDB,另一种是AOF
RDB持久化可以在指定的时间间隔内生成数据集的时间点快照(point-in-time snapshot)。
RDB的优点
? RDB是一个非常紧凑(compact)的文件,它保存了Redis在某个时间点上的数据集。这种文件非常适合用于进行备份:比如说,你可以在最近的24小时内,每小时备份一次RDB文件,并且在每个月的每一天,也备份一个RDB文件。这样的话,即使遇上问题,也可以随时将数据集还原到不同的版本。
? RDB非常适用于灾难恢复(disaster recovery):它只有一个文件,并且内容都非常紧凑,可以(在加密后)将它传送到别的数据中心,或者亚马逊S3中。
? RDB可以最大化Redis的性能:父进程在保存RDB文件时唯一要做的就是fork出一个子进程,然后这个子进程就会处理接下来的所有保存工作,父进程无须执行任何磁盘I/O操作。
RDB的缺点
? 如果你需要尽量避免在服务器故障时丢失数据,那么RDB不适合你。
? 虽然Redis允许你设置不同的保存点(save point)来控制保存RDB文件的频率,但是,因为RDB文件需要保存整个数据集的状态,所以它并不是一个轻松的操作。因此你可能会至少5分钟才保存一次RDB文件。在这种情况下,一旦发生故障停机,你就可能会丢失好几分钟的数据。
? 每次保存RDB的时候,Rdis都要fork()出一个子进程,并由子进程来进行实际的持久作,在数据集比较庞大时,fork()可能会非常耗时,适成服务器在某某毫秒内停止处理客户端:如果数据集非常巨大,并且CPU时间非常紧张的话,那么这种停止时间甚至可能会长达整整一秒。虽然AOF重写也需要进行fork(),但无论AOF重写的执行间隔有多长,数据的耐久性都不会有任何损失。
AOF持久化记录服务器执行的所有写操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集。AOF文件中的命令全部以Redis协议的格式来保存,新命令会被追加到文件的末尾。
Redis还可以在后台对AOF文件进行重写(rewrite),使得AOF文件的体积不会超出保存数据集状态所需的实际大小,Redis还可以同时使用AOF持久化和RDB持久化,在这种情况下,当Redis重启时,它会优先使用AOF文件来还原数据集,因为AOF文件保存的数据集通常比RDB文件所保存的数据集更完整。
你甚至可以关闭持久化功能,让数据只在服务器运行时存在。
AOF的优点
? 使用AOF会让你的Redis更加耐久:你可以使用不同的fsync策略:无fsync,每秒fsync,每次写的时候fsync.使用默认的每秒fsync策略,Redis的性能依然很好(fsync是由后台线程进行处理的,主线程会尽力处理客户端请求)一旦出现故障,你最多丢失1秒的数据。
? Redis可以在AOF文件体积变得过大时,自动地在后台对AOF进行重写:重写后的新AOF文件包含了恢复当前数据集所需的最小命令集合。整个重写操作是绝对安全的,因为Redis在创建新AOF文件的过程中,会继续将命令追加到现有的AOF文件里面,即使重写过程中发生停机,现有的AOF文件也不会丢失。
? 一旦新AOF文件创建完毕,Redis就会从旧AOF文件切换到新AOF文件,并开始对所AOF文件进行追加操作。
? AOF文件有序地保存了对数据库执行的所有写入操作,这些写入操作以Redis协议的格式保存,因此AOF文件的内容非常容易被人读懂,对文件进行分析(parse)也很轻松。导出(export)AOF文件也非常简单:举个例子,如果你不小心执行了FLUSHALL命令,但只要AOF文件未被重写,那么只要停止服务器移除AOF文件末尾的FLUSHALL命令,并重启Redis,就可以将数据集恢复到FLUSHALL执行之前的状态。
AOF缺点
? 对于相同的数据集来说,AOF文件的体积通常要大于RDB文件的体积,根据所使用的fsync策略,AOF的速度可能会慢于RDB。
? 在一般情况下,每秒fsync的性能依然非常高,而关闭fsync可以让AOF的速度和RDB一样快,即使在高负荷之下也是如此。不过在处理巨大的写入载入时,RDB可以提供更有保证的最大延迟时间(latency)。
? AOF在过去曾经发生过这样的bug:因为个别命令的原因,导致AOF文件在重新载入时,无法将数据集恢复成保存时的原样,(举个例子,阻塞命令BRPOPLPUSH就曾经引起过这样的bug,测试套件里为这种情况添加了测试:它们会自动生成随机的、复杂的数据集,并通过重新载入这些数据来确保一切正常。虽然这种bug在AOF文件中并不常见,但是对比来说,RDB几乎是不可能出现这种bug的。
①一般来说,如果想达到足以境美PostgreSQL的数据安全性,你应该同时使用两种持久化功能。
②如果你非常关心你的数据,但仍然可以承受数分钟以内的数据丢失,那么你可以只使用RDB持久化。
③有很多用户都只使用AOF持久化,但我们并不推荐这种方式:因为定时生成RDB快照(snapshot)非常便于进行数据库备份,并且RDB恢复数据集的速度也要比AOF恢复的速度要快,除此之外,使用RDB还可以道免之前提到的AOF程序的bug。
④Note:因为以上提到的种种原因,未来redis可能会将AOF和RDB整合成单个持久化模型(这是一个长期计划)。
在默认情况下,Redis将数据库快照保存在名字为dump.rdb的二进制文件中。你可以对Redis进行设置,让它在“N秒内数据集至少有M个改动”这一条件被满足时,自动保存一次数据集。
你也可以通过调用SAVE或者BGSAVE,手动让Redis进行数据集保存操作。
比如说,以下设置会让Redis在满足“60秒内有至少有1000个键被改动”这一条件时,自动保存一次数据集:
save 60 1000
这种持久化方式被称为快照snapshotting。
当Redis需要保存dump.rdb文件时,服务器执行以下操作:
1、Redis调用forks,同时拥有父进程和子进程。
2、子进程将数据集写入到一个临时RDB文件中。
3、当子进程完成对新RDB文件的写入时,Redis用新RDB文件替换原来的RDB文件,并删除旧的RDB文件。
这种工作方式使得Redis可以从写时复制(copy-on-write)机制中获益。
只进行追加操作的文件(append-only file,AOF)
快照功能并不是非常耐久:如果Redis因为某些原因而造成故障停机,那么服务器将丢失最近写入、且仍未保存到快照中的那些数据。尽管对于某些程序来说,数据的耐久性并不是最重要的考虑因素,但是对于那些追求完全耐久能力的程序员来说,快照功能就不太适用了,
从1.1版本开始,Redis增加了一种完全耐久的持久化方式:AOF持久化。
你可以通过修改配置文件来打开AOF功能:appendonly yes。
从现在开始,每当Redis执行一个改变数据集的命令式(比如SET),这个命令就会被追加到AOF文件的末尾。这样的话,当redis重新启动时,程序就可以通过重新执行AOF文件中的命令来达到重建数据集的目的。
因为AOF的运作方式是不断地将命令追加到文件的末尾,所以随着写入命令的不断增加,AOF文件的体积也会变得越来越大。
举个例子,如果你对一个计数器调用了100次INCR,那么仅仅是为了保存这个计数器的当前值,AOF文件就需要使用100条记录(ety)。然而在实际上,只使用一条SET命令已经足以保存计数器的当前值了,其余99条记录实际上都是多余的。
为了处理这种情况,Redis支持一种有趣的特性:可以在不打断服务客户端的情况下,对AOF文件进行重沿(rebuild),执行BGREWRITEAOF命令,Redis将生成一个新的AOF文件,这个文件包含重建当前数据集所需的最少命令,Redis2.2需要自己手动执行BGREWRITEAOF命令。
你可以配置Redis多久才将数据fsync到磁盘一次。有几种方式:
1、每次有新命令追加到AOF文件时就执行一次fsync非常慢,也非常安全
2、每秒fsync一次:足够快(和使用RDB持久化差不多),并且在故障时只会丢失1秒钟的数据。
3、从不fsync:将数据交给操作系统来处理。更快,也更不安全的选择。
4、推荐(并且也是默认)的指施为每秒fsync一次,这种fsync策路可以兼顾速度和安全性。
服务器可能在程序正在对AOF文件进行写入时停机,如果停机造成了AOF文件出错(corrupt),那么Redis在重启时会拒绝载入这个AOF文件,从而确保数据的一致性不会被破坏。当发生这种情况时,可以用以下方法来修复出错的AOF文件:
● 为现有的AOF文件创建一个备份。
● 使用Redis附带的redis-check-aof程序,对原来的AOF文件进行修复:$redis-check-aof -fix
● 使用diff -u对比修复后的AOF文件和原始AOF文件的备份,查看两个文件之间的不同之处。(可选)
● 重启Redis服务器,等待服务器载入修复后的AOF文件,并进行数据恢复。
● 在版本号大于等于2.4的Redis中,BGSAVE执行的过程中,不可以执行BGREWRITEAOF。
● 反过来说,在BGREWRITEAOF执行的过程中,也不可以执行BGSAVE,这可以防止两个Redis后台进程同时对磁盘进行大量的I/O操作。
● 如果BGSAVE正在执行,并且用户显示地调用BGREWRITEAOF命令,那么服务器将向用户回复一个OK状态,并告知用户,BGREWRITEAOF已经被预定执行:一旦BGSAVE执行完华,BGREWRITEAOF就会正式开始。
● 当Redis启动时,如果RDB持久化和AOF持久化都被打开了,那么程序会优先使用AOF文件来恢复数据集,因为AOF文件所保存的数据通常是最完整的。
Redis对于数据备份是非常友好的,因为你可以在服务器运行的时候对RDB文件进行复制:
RDB文件一旦被创建,就不会进行任何修改。当服务器要创建一个新的RDB文件的,它先将文件的内容保存在一个临时文件里面,当临时文件写入完毕的,程序才使用rename(2)原子地用临时文件替换原来的RDB文件。
这也就是说,无论何时,复制RDB文件都是绝对安全的,
● 创建一个定期任务(cron job),每小时将一个RDB文件备份到一个文件夹,并且每天将一个RDB文件备份到另一个文件夹。
● 确保快照的备份都带有相应的日期和时间信息,每次执行定期任务脚本时,使用命令来删除过期的快照:比如说,你可以保留最近48小时内的每小时快照,还可以保留最近一两个月的每日快照。
● 至少每天一次,将RDB备份到你的数据中心之外,或者至少是备份到你运行Redis服务器的物理机器之外。
修改配置文件:
save 900 1
save 300 10
save 60 10000
以上配置分别表示:
·900秒(15分钟)内有1个更改
·300秒(5分钟)内有10个更改
·60秒内有10000个更改
·当达到以上定义的配置时间时,就将内存数据持久化到磁盘
RDB持久化高级配置:
stop-writes-on-bgsave-error yes
rdbcompeission yes
rdbchecksum yes
dbfilename dump.rdb
dir ./usr/local/redis/data/6379
以上配置分别表示:
·后台备份进程出错时,主进程停不停止写入?主进程不停止容易造成数据不一致
·导出的rdb文件是否压缩,如果rdb的大小很大的话建议这么做
·导入rdb恢复数据时,要不要检验rdb的完整性,验证版本是不是一致
·导出来的rdb文件名
·rdb的存放路径
AOF持久化基本配置:
appendonly yes/no
appendfsync always
appendfsync everysec
appendfsync no
以上配置分别表示:
·是否打开aof日志功能
·每1个命令,都立即同步到aof
·每秒写1次
·写入工作交给操作系统由操作系统判断履冲区大小,统一写入到aof
AOF持久化高级配置:
no-appendfsync-on-rewrite yes/no
auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb
以上配置分别表示:
·正在导出rdb快照的过程中,要不要停止同步aof
·aof文件大小比起上次重写时的大小,增长率100%时重写,缺点:业务开始的时候,会重复重写多次。
·aof文件,至少超过64M时,重写
在Reds2.2或以上版本,可以在不重启的情况下,从RDB切换到AOF:
1、为最新的dump.rdb文件创建一个备份。
2、将备份放到一个安全的地方。
3、执行以下两条命令:
redis-cli config set appendonly yes
redis-cli config set ""
4、确保写命令会被正确地追加到AOF文件的末尾。
执行说明:
● 执行的第一条命令开启了AOF功能:Redis会阻塞直到初始AOF文件创建完成为止,之后Redis会继续处理命令请求,并开始将写入命令追加到AOF文件末尾。
● 执行的第二条命令用于关闭RDB功能。这一步是可选的,如果你愿意的话,也可以同时使用RDB和AOF这两种持久化功能。
注意:别忘了在redis.conf中打开AOF功能!否则的话,服务器重启之后,之前通过CONFIG SET设置的配置不会生效,程序会按原来的配置来启动服务器。
类型 | 说明 |
---|---|
String 字符串 | redis字符串数据类型的相关命令用于管理redis字符串值 |
Hash 哈希 | redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。redis中每个hash可以存储232-1键值对(40多亿) |
List 列表 | redis列表是简单的字符串列表,按照插入顺序排序。可以添加一个元素到列表的头部(左边)或者尾部(右边)一个列表最多可以包含232-1个元素(≈43亿每个列表超过40亿个元素) |
set 集合 | redis的set是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据 |
sorted set 有序集合 | redis有序集合和集合一样也是string类型元素的集合,切不允许重复的成员 |
命令 | 含义 |
---|---|
keys * | 查看KEY支持通配符 |
del | 删除给定的一个或多个key |
exists | 检查是否存在 |
rename | 变更key名 |
sort | 键值排序,有非数字时报错 |
type | 返回值所存储值的类型 |
dump restore | 序列化与反序列化 |
expire\pexpire | 以秒\毫秒设定生存时间 |
ttl\pttl | 以秒\毫秒为单位返回生存时间 |
persist | 取消生存实现设置 |
randomkey | 返回数据库中的任意键 |
string是redis是最基本的类型,一个key对应一个value。一个键最大能存储512MB。
命令 | 描述 |
---|---|
set key value | 设置指定key的值 |
get key | 获取指定key的值 |
getrange key start end | 返回key中字符串值的子字符 |
getset key value | 将给定key的值设为value,并返回key的旧值(old value) |
getbit key offset | 所存储的字符串值,获取指定偏移量上的位(bit) |
mget key1[key2…] | 获取所有(一个或多个)给定key的值 |
setbit key offset value | 对key所存储的字符串值,设置或清除指定偏移量上的位(bit) |
setex key seconds value | 将值value 关联到key,并将key的过期时间设为seconds(以秒为单位) |
setnx key value | 只有在key不存在时设置key的值 |
setrange key offset value | 用value参数覆写给定key所存储的字符串值,从偏移量offset开始 |
strlen key | 返回key所存储的字符串值的长度 |
mset key value [key value …] | 同时设置一个或多个key-value对 |
msetnx key value [key value …] | 同时设置一个或多个key-value对,当且仅当所有给定key都不存在 |
psetex key milliseconds value | 这个命令和setex命令相似,但它以毫秒为单位设置key的生存时间,而不是像setex命令那样,以秒为单位 |
incr key | 将key中存储的数字值增1 |
incrby key increment | 将key所存储的值加上给定的增量值(increment) |
incrbyfloat key increment | 将key所存储的值加上给定的浮点增量值(increment) |
decr key | 将key中存储的数字值减1 |
decrby key decrementkey | 所存储的值减去给定的减量值(decrement) |
append key value | 如果key已经存在并且是一个字符串,append命令将指定value追加到改key原来的值(value)的末尾 |
应用场景:常规计数:微博数,粉丝数等。
我们可以将Redis中的Hashes类型看成具有String Key和String Value的map容器。
所以该类型非常适合于存储值对象的信息,如Username、Password和Age等,如果Hash中包含很少的字段,那么该类型的数据也将仅占用很少的磁盘空间。每一个Hash可以存储995701749个键值对。
命令 | 描述 |
---|---|
hdel key field1 [field2] | 删除一个或多个哈希表字段 |
hexists key field | 查看哈希表key中,指定的字段是否存在。 |
hget key field | 获取存储在哈希表中指定字段的值, |
hgetall key | 获取在哈希表中指定key的所有字段和值 |
hincrby key field increment | 为哈希表key中的指定字段的整数值加上增量increment. |
hincrbyfloat key field increment | 为哈希表key中的指定字段的浮点数值加上增量increment. |
hkeys key | 获取所有哈希表中的字段 |
hlen key | 获取哈希表中字段的数量 |
hmget key field1[field2] | 获取所有给定字段的值 |
hmset key field1 value1[field2 value2] | 同时将多个field-value(域-值)对设置到哈希表key中 |
hset keyfield value | 将哈希表key中的字段field的值设为value |
hsetnx key field value | 只有在字段field不存在时,设置哈希表字段的值 |
hvals key | 获取哈希表中所有值 |
hscan key cursor [MATCH pattern] [COUNT count] | 选代哈希表中的键值对 |
应用场景:存储部分变更的数据,如用户信息等。
List类型是按照插入顺序排序的字符串链表。和数据结构中的普通链表一样。我门可以在其头部(left)和尾部(right)添加新的元素。
在插入时,如果该健并不存在,Redis将为该键创建一个新的链表。与此相反,如果链表中所有的元素均被移除那么该键也将会被从数据库中删除。List中可以包含最大的元素数量是4294967295.
命令 | 描述 |
---|---|
blpop key1[key2] timeout | 移出并获取列表的第一个元素,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。 |
brpop key1[key2] timeout | 移出并获取列表的最后一个元素,如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。 |
brpoplpush source desination timeout | 从列表中弹出一个值。将弹出的元素插入到另外一个列表中并返回它:如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。 |
LINDEX key index | 通过索引获取列表中的元素 |
linsert key before|after pivot value | 在列表的元素前或者后插入元素 |
llen key | 获取列表长度 |
lpop key | 移出并获取列表的第一个元素 |
lpush key value1 [value2] | 将一个或多个值插入到列表头部 |
lpushx key value | 将一个值插入到已存在的列表头部 |
lrange key start stop | 获取列表指定范围内的元素 |
lrem key count value | 移除列表元素 |
lset key index value | 通过索引设置列表元素的值 |
ltrim key start stop | 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。 |
rpop key | 移除并获取列表最后一个元素 |
rpoplpush source destination | 移除列表的最后一个元素,并将该元素添加到另一个列表并返回 |
rpush key value1 [value2] | 在列表中添加一个或多个值 |
rpushhx key value | 为已存在的列表添加值 |
应用场景:消息队列系统,比如sina微博。
在Redis中我们的最新微博ID使用了常驻缓存,这是一直更新的。但是做了限制不能超过5000个ID,因此获取ID的函数会一直询问Redis。只有在start/count参数超出了这个范围的时候,才需要去访问数据库。
系统不会像传统方式那样刷新缓存,Redis实例中的信息永远是一致的。SQL数据库(或是硬盘上的其他类型数据库)只是在用户需要获取“很远”的数据时才会被触发,而主页或第一个评论页是不会麻烦到硬盘上的数据库了。
Set类型看作为没有排序的字符集合。Set可包含的最大元素数量是4294967295。如果多次添加相同元素,Set中将仅保留该元素的一份拷贝。
命令 | 描述 |
---|---|
sadd key member1[member2] | 向集合添加一个或多个成员 |
scard key | 获取集合的成员数 |
sdiff key1 [key2] | 返回给定所有集合的差集 |
sdiffstore destination key1 [key2] | 返回给定所有集合的差集并存储在destination中 |
sinter key1 [key2] | 返回给定所有集合的交集 |
sinterstore destination key1 [key2] | 返回给定所有集合的交集并存储在destination中 |
sismember key member | 判断member元素是否是集合key的成员 |
smembers key | 返回集合中的所有成员 |
smove source destination member | 将member元素从source集合移动到destination集合 |
spop key | 移除并返回集合中的一个随机元素 |
srandmember key [count] | 返回集合中一个或多个随机数 |
srem key member1 [member2] | 移除集合中一个或多个成员 |
sunion key1 [key2] | 返回所有给定集合的并集 |
sunionstore destination key1 [key2] | 所有给定集合的并集存储在destination集合中 |
sscan key cursor [MATCH pattern] [COUNT count] | 迭代集合中的元素 |
应用场景:在微博应用中,可以将一个用户所有的关注的人存在一个集合中,将其所有粉丝存在一个集合。
Redis还未集合提供了求交集、并集、差集等操作,可以非常方便的实现如共同关注、共同喜好、二度好友等功能,对上面的所有集合操作。
Sorted-Sets中的每一个成员都会有一个分数(score)与之关联,Redis正是通过分数来为集合中的成员进行从小到大的排序。成员是维一的,但是分数(score)却是可以重复的。
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。集合中最大的成员数为232-1(4294967295,每个集合可存储40多亿个成员)。
命令 | 描述 |
---|---|
zadd key score1 member1[score 2member2] | 向有序集合添加一个或多个成员,或者更新已存在成员的分数 |
zcard key | 获取有序集合的成员数 |
zcount key min max | 计算在有序集合中指定区间分数的成员数 |
zincrby key increment member | 有序集合中对指定成员的分数加上增量increment |
zinterstore destination numkeys key [key…] | 计算给定的一个或多个有序集的交集并将结果集存储在新的有序集合key中 |
zlexcount key min max | 在有序集合中计算指定字典区间内成员数量 |
zrange key start stop [WITHSCORES] | 通过索引区间返回有序集合成指定区间内的成员 |
zrangebylex key min max [limit offset count] | 通过字典区间返回有序集合的成员 |
zrangebyscore key min max [WITHSCORES] [LIMIT] | 通过分数返回有序集合指定区间内的成员 |
zrank key member | 返回有序集合中指定成员的索引 |
zram key member [member…] | 移除有序集合中的一个或多个成员 |
ZREMRANGEBYLEX key min max | 移除有序集合中给定的字典区间的所有成员 |
ZREMRANGEBYRANK key start stop | 移除有序集合中给定的排名区间的所有成员 |
zremrangebyscore key min max | 移除有序集合中给定的分数区间的所有成员 |
zrevrange key start stop [WITHSCORES] | 返回有序集中指定区间内的成员,通过索引,分数从高到底 |
zrevrangebyscorekey min max [WITHSCORES] | 返回有序集中指定分数区问内的成员,分数从高到低排序 |
zrevrank key member | 返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序 |
zscore key member | 返回有序集中,成员的分数值 |
ZUNIONSTORE destination numkeys key [key] | 计算给定的一个或多个有序集的并集,并存储在新的key中 |
zscan key cursor [MATCH pattern] [COUNT count] | 迭代有序集合中的元素(包括元素成员和元素分值) |
应用场景:排行榜应用,取TOP N操作这个需求与上面需求的不同之处在于,前面操作以时间为权重,这个是以某个条件为权重,比如按顶的次数排序,这时候就需要我们的sorted set出马了,将你要排序的值设置成sorted set的score,将具体的数据设置成相应的value,每次只需要执行一条ZADD命令即可。
Redis发布消息通常有两种模式:
● 队列模式(queuing)
● 发布-订阅模式(publish-subscribe)
任务队列
顾名思义,就是“传递消息的队列时”。与任务队列进行交互的实体有两类,一类是生产者(producer),另一类则是消费者(consumer),生产者将需要处理的任务放入任务队列中,而消费者则不断地从任务独立中读入任务信息并执行。
任务队列的好处:
①松耦合
生产者和消费者只需按照约定的任务描述格式,进行编写代码。
②易于扩展
多消费者模式下,消费者可以分布在多个不同的服务器中,由此降低单台服务器的负载。
其实从Pub/Sub的机制来看,它更像是一个广播系统,多个Subscriberi可以订阅多个Channel,多个Publisher可以往多个Channele中发布消息。可以这么简单的理解:
● Subscriber:收音机,可以收到多个须道,并以队列方式显示
● Publisher:电台,可以往不同的FM频道中发消息
● Channel:不同频率的FM频道
①一个Publisher,多个Subscriber模型
如下图所示,可以作为消息队列或者消息管道。主要应用:通知、公告。
②多个Publisher,一个Subscriber模型
可以将PubSub做成独立的HTTP接口,各应用程序作为Publisher向Channel中发送消息,Subscriber端收到消息后执行相应的业务逻辑,比如写致据库,显示等等。主要应用:排行榜、投票、计数。
③多个Publisher,多个Subscriber模型
故名思议,就是可以向不同的Channel中发送消息,由不同的Subscriber接收。主要应用:群聊,聊天。
发布订阅实践命令
命令 | 描述 |
---|---|
PUBLISH channel msg | 将信息message发送到指定的频道channel |
SUBSCRIBE channel [channel …] | 订阅频道,可以同时订阅多个频道 |
UNSUBSCRIBE [channel …] | 取消订阅指定的频道,如果不指定频道。则会取消订阅所有频道 |
PSUBSCRIBE pattern [pattern …] | 订阅一个或多个符合给定模式的频道,每个模式以* 作为匹配符,比如it* 匹配所有以 it开头的频道(it.news、it.blog 、it.tweets等等),news.*匹配所有以news.开头的频道(news.it、news.global.today等等),诸如此类 |
PUNSUBSCRIBE [pattern [pattern …]] | 退订指定的规则,如果没有参数则会退订所有规则 |
PUBSUB subcommand [argument [argument …]] | 查看订阅与发布系统状态 |
注意:使用发布订阅模式实现的消息队列,当有客户端订阅channel后只能收到后续发布到该频道的消息,之前发送的不会缓存,必须Provider和Concumer同时在线。
客户端在执行订阅命令之后进入了订阅状态,只能接收subscribe、psubscribe、unsunbscribe、punsubscribe四个命令。
开启的订阅客户端,无法收到该频道之前的消息,因为Redis不会对发布的消息进行持久化。
和很多专业的消息队列系统(例如Kafka、RocketMQ)相比,Redis的发布订阅略显粗糙,例如无法实现消息堆积和回溯。但胜在足够简单,如果当前场景可以容忍的这些缺点,也不失为一个不错的选择。
● redis中的事务跟关系型数据库中的事务是一个相似的概念,但是有不同之处。
● 关系型数据库事务执行失败后面的sql语句不再执行,而redis中的一条命令执行失败,其余的命令照常执行。
● redis中开启一个事务是使用multi,相当于begin\start transaction,exec提交事务,discard取消队列命令 (非回滚操作)。
mysql | Redis | |
---|---|---|
开启 | start transaction/begin | multi |
语句 | 普通SQL | 普通命令 |
失败 | rollback回滚 | discard取消(不叫回滚,是队列里面的命令不执行,且队列里面的任务根本就没有执行。而不是执行了也可以撤回来。) |
成功 | commit | exec |
命令 | 描述 |
---|---|
discard | 取消实物,放弃执行事务块内的所有命令 |
exec | 执行所有事务块内的命令 |
multi | 标记一个事务块的开始 |
unwatch | 取消watch命令对所有key的监视 |
watch key [key…] | 监视一个(或多个)key,如果在事务执行之前这些个key被其他命令所改动,那么事务将被打断 |
举例:我正在买票 Ticket-1,money-100
而票只有1张如果在我multi之后,和exec之前,票被别人买了,即ticket变成0了。我该如何观察这种情景并不再提交?
● 悲观的想法:世界充满危险,肯定有人和我抢,给ticket上锁,只有我能操作[悲观锁]
● 乐观的想法:没有那么多人和我抢,因此我只需要注意,有没有人更改ticket的值就可以了[乐观锁]
Redis的事务中,启用的是乐观锁,只负责监测key没有被改动。
命令 | 描述 |
---|---|
bgrewriteaof | 异步执行一个AOF (AppendOnly File) 文件重写操作 |
bgsave | 在后台异步保存当前数据库的数据到磁盘 |
client kill [ip:prot] [ID client-id] | 关闭客户端连接 |
client list | 获取连接到服务器的客户端连接列表 |
client getname | 获取连接的名称 |
client pause timeout | 在指定时间内终止运行来自客户端的命令 |
client setname connection-name | 设置当前连接的名称 |
cluster slots | 获取集群节点的映射数组 |
command | 获取Redis命令详情数组 |
command count | 获取Redis命令总数 |
command getkeys | 获取给定命令的所有键 |
time | 返回当前服务器时间 |
command info command-name [command-name …] | 获取指定Redis 命令描述的数组 |
config get parameter | 获取指定配置参数的值 |
config rewrite | 对启动Redis服务器时所指定的 redis.conf配置文件进行改写 |
config set parameter value | 修改redis配置参数,无需重启 |
config resetstat | 重置INFO命令中的某些统计数据 |
dbsize | 返回当前数据库的key的数量 |
debug object key | 获取key的调试信息 |
debug segfault | 让Redis 服务崩渍 |
flushall | 删除所有数据库的所有key |
flushdb | 删除当前数据库的所有key |
info [section] | 获取Redis服务器的各种信息和统计数值 |
lastsave | 返回最近一次 Redis 成功将数据保存到磁盘上的时间,以 UNIX 时间戳格式展示 |
monitor | 实时打印出Redis服务器接收到的命令,调试用 |
role | 返回主从实例所属的角色 |
save | 异步保存数据到硬盘 |
shutdown [nosave] [save] | 异步保存数据到硬盘,并关闭服务器 |
slaveof host port | 将当前服务器转变为指定服务器的从属服务器(slave server) |
slowlog subcommand [argument] | 管理redis的慢日志 |
sync | 用于复制功能(replication)的内部命令 |
● Slow log是redis用来记录查询执行时间的日志系统。
● Slow log保存在内存里面,读写速度非常快
可以通过改写redis.conf文件或者使用config get和config set命令对它们动态地进行修改。
slowlog-log-slower-than 10000 #超过多少微秒
CONFIG SET alowlog-log-slower-than 100
CONFIG SET slowlog-max-1en 1000 #保存多少条慢日志
CONFIG GET slow*
SLOWLOG GET
SLOWLOG RESET
END