企业项目管理、ORK、研发管理与敏捷开发工具平台

网站首页 > 精选文章 正文

Redis详细教程——从0开始认识Redis

wudianyun 2025-01-16 21:13:39 精选文章 7 ℃

文章目录

  • 前言
  • 一、Redis是什么?
  • 二、为什么要用Redis?Redis有哪些应用场景?1.为什么要用Redis2.Redis常见应用场景
  • 三、Linux安装Redis1.从源码安装Redis1.1 从Redis官网下载最新稳定版源码1.2 解压缩1.3 移动到/usr/local/redis文件夹1.4 编译1.4 安装2.从官方apt存储库安装Redis2.1 将存储库添加到apt索引2.2 安装
  • 四、Redis的基本使用1、启动redis服务2、使用redis-cli连接redis服务
  • 五、Redis的数据类型及其常用命令1、String类型2、List类型3、Set类型4、Hash类型5、Sorted Set类型6、HyperLogLog7、Geospatial in index8、Stream9、Pub/Sub
  • 六、Redis持久化策略及其内存淘汰策略1、Redis持久化RDB的优点RDB的缺点AOF 优点AOF 缺点如何选择使用哪种持久化方式?快照工作方式只追加操作的文件(Append-only file,AOF)日志重写AOF有多耐用?如果AOF文件损坏了怎么办?工作原理怎样从RDB方式切换为AOF方式AOF和RDB之间的相互作用备份redis数据容灾备份2、Redis的过期策略和内存淘汰机制
  • 七、Redis高可用(主从、哨兵、集群)
  • 八、缓存击穿、缓存穿透、缓存雪崩
  • 九、Java连接redis之jedis
  • 十、Spring Boot使用Redis作为缓存
  • 总结

前言

  本文将通过由浅入深的方式介绍Redis相关的知识。从0开始,一步步带您深入了解redis的相关特性,并最终应用到实践当中。

一、Redis是什么?

  Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
  Redis 可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
官网:https://redis.io/
官网的中文版:http://www.redis.cn/
下载地址:
https://download.redis.io/releases/redis-6.2.6.tar.gz

二、为什么要用Redis?Redis有哪些应用场景?

1.为什么要用Redis

  • 性能高完全基于内存,使用C语言编写,网络层使用epoll解决高并发问题,单线程模型避免了线程上下文切换及竞争条件。
  • 数据类型丰富五种基本类型String、List、Hash、Set、Sorted Set,还有几种特殊类型:Bitmap、HyperLogLog(基数统计)、Stream(流)、Geospatial index(地理位置索引)。
  • 功能丰富如发布订阅功能可实现简单的消息队列、Pipeline将多条命令放到一个管道里一块执行减少网络开销、可以使用Lua脚本创建具有原子性的命令集合、提供可选的内存过期策略、自动故障转移等。
  • 支持持久化Redis提供了两种持久化策略:RDB和AOF。RDB可以将内存中的快照每隔一段时间保存到磁盘当中,AOF可以将每条执行的命令依次追加到磁盘文件中。
  • 高可用和分布式Redis提供了主从复制、哨兵机制以及cluster模式来支持高可用。
  • 支持多种语言支持但不限于Java、PHP、Python、Ruby、Lua、Nodejs、C、C++、Go等等。Redis各语言下的客户端实现
  • 服务器足够简单不依赖外部库、单线程模型、代码优雅

2.Redis常见应用场景

1.缓存系统可以将热点数据存储在redis当中,并且结合expire过期时间可以进行缓存更新操作。
2.计数器、限流、全局id主要利用了incr和incrby命令的原子性递增的特性。计数器:比如网站播放量、转发数评论数;限流:比如限制用户的访问次数,接口的调用次数;全局id:分库分表的场景,可以从redis中拿到全局唯一的id。
3.消息队列系统 redis有三种方式实现消息队列:利用list的blpop/brpop实现阻塞队列;利用pub/sub实现发布订阅模型;利用stream实现可持久化的支持Ack机制的消息队列。
4.排行榜 使用sorted可以实现对数据的分值进行排序。
5.社交网络 比如实时聊天(pub/sub)、好友关系(set)等都可以借助redis来实现。
6.地理信息定位 redis的Geo可以做诸如“附近的人”,“城市距离计算”等。
7.活跃用户统计 可以使用bitmap相关的命令将指定时间段的用户活跃情况统计出来。
8.独立总数统计 使用hyperloglog可以用极小的空间以极高的效率估计出一个集合的总数。
9.分布式锁 利用redis的setnx命令实现,setnx:"set if not exists"只有不存在才能设置上值,使用的时候可以结合过期时间防止死锁。
10.抽奖 主要利用set集合相关的命令,srandmember key [count]随机取出一个或指定数量(count)的元素,如果count>0表示不放回的抽取,count<0表示放回的抽取(可以被重复抽取到)。也可使使用spop key [count]命令,删除并返回一个或指定数量的元素。

三、Linux安装Redis

这里我们介绍两种方式来安装Linux。由于apt安装后的文件较为分散,不利于管理和理解,所以建议使用源码方式安装。

1.从源码安装Redis

1.1 从Redis官网下载最新稳定版源码

wget https://download.redis.io/redis-stable.tar.gz

1.2 解压缩

tar -zxvf redis-stable.tar.gz

1.3 移动到/usr/local/redis文件夹

sudo mv redis-stable /usr/local/redis

1.4 编译

cd /usr/local/redis
make

编译需要一点时间,编译完成如下图所示。编译完成之后会在src文件夹下面生成一些可执行文件(redis-server,redis-cli等等。利用这些文件,我们可以完成服务的启动、连接等操作,但通常我们会进行下一步的安装操作)。

1.4 安装

make PREFIX=/usr/local/redis install

PREFIX的作用是让安装后的文件都放在/usr/local/redis文件夹下,方便卸载。如果不加这个参数的话,可执行文件会安装到/usr/loca/bin下,库文件会安装到/usr/local/lib下,公共文件会放到/usr/local/share下。安装完成后,在/usr/local/redis下面可以看到一个bin目录,里面放置着redis的可执行服务,后面我们会详细介绍里面的内容。

2.从官方apt存储库安装Redis

可以从官方 packages.redis.io APT 存储库安装 Redis 的最新稳定版本。将存储库添加到apt索引,更新它,然后安装:

2.1 将存储库添加到apt索引

curl -fsSL https://packages.redis.io/gpg | sudo gpg --dearmor -o /usr/share/keyrings/redis-archive-keyring.gpg
echo “deb [signed-by=/usr/share/keyrings/redis-archive-keyring.gpg] https://packages.redis.io/deb $(lsb_release -cs) main” | sudo tee /etc/apt/sources.list.d/redis.list

2.2 安装

sudo apt-get update
sudo apt-get install redis

这种方式安装的redis,各个文件分散在不同的文件夹。比如:

  • redis-server,redis-cli等命令放到了/usr/bin目录下
  • redis.conf默认配置文件放到了/etc/redis目录下
  • redis.log默认日志文件放到了/var/log/redis目录下
  • redis.pid进程id文件放在了/run/redis.pid
  • redis的主目录默认是/var/lib/redis文件夹

四、Redis的基本使用

1、启动redis服务

/usr/local/redis/bin/redis-server& /usr/local/redis/redis.conf

找到安装完成之后的redis-server可执行文件,以及要使用的redis.conf配置文件,在shell中使用如上命令即启动redis服务。redis-server后面的&符号表示以后台的守护进程的方式运行。也可以直接修改redis.conf中的daemonize no改成daemonize yes达到同样的目的。

注:了解一下redis.conf中几个简单的配置
bind 127.0.0.1表示只有本机才能连这个redis服务
protected-mode yes表示开启保护模式,配合bind选项可以设置只允许指定的外部ip地址访问这个服务。
port 6379表示这个服务使用的端口号是6379
daemonize yes表示以后台守护进程的方式运行服务

2、使用redis-cli连接redis服务

/usr/local/redis-cli -h localhost -p 6379

启动redis-cli默认连接 本机的6379端口,也可以指定要连接的主机和端口以便远程连接redis服务。连接成功之后输入ping命令,服务端会返回PONG。

五、Redis的数据类型及其常用命令

通过上面的介绍我们已经了解到,redis并不是简单的String类型的key-value存储,还包含着丰富的数据结构,接下来我们就挨个介绍一下这几种数据结构以及它们所包含的常用命令。

1、String类型

字符串类型是redis最基本的值类型,其实现是二进制安全的,可以包含任意类型的数据,比如:图片类型或者序列化对象。一个字符串值类型最多能存储512MB字节的内容。String类型有三种内部编码:int,embstr,raw。Redis会自动根据值类型选择合适的编码。

  • SET key value [EX seconds] [PX milliseconds] [NX|XX]
    解释:设置key的值为value
    EX:过期时间,单位秒。PX:毫秒级过期时间。NX:值不存在才能设置。XX:值存在才能设置。
  • GET key
    解释:获取字符串类型key的值
  • SETEX key seconds value
    解释:设置key的值为value,并在seconds秒后过期
  • SETNX key value
    解释:如果key不存在,则设置key的值为value
  • MSET key value [key value ...]
    解释:原子的一次性设置多个key-value值,如果存在则更新
  • MGET key [key ...]
    解释:返回所有指定的key的value,如果不存在返回nil。
  • MSETNX key value [key value ...]
    解释:原子性的设置多个key-value值,只要有一个key存在,则都不执行。
  • SETRANGE key offset value
    解释:从key对应的原字符串的offset处开始覆盖value字符串。
  • GETRANGE key start end
    解释:返回key对应值从start到end位置的子串。负的位移表示从尾部开始的下标,比如-1表示最后一个字符,-2表示倒数第二个,以此类推。
  • STRLEN key
    解释:返回key的String类型value的长度。
  • GETSET key value
    解释:设置key的值为value,并返回原来的值。
  • APPEND key value
    解释:追加value值到key对应的原来的value值的尾部。

以下是bitmap类型的命令,因为实际类型也是String类型,只不过把每个字符按照实际的8位二进制位进行操作,所以放在一块介绍一下。

  • SETBIT key offset value
    解释:设置key对应offset处的值位value,value可以是0或者1.
  • GETBIT key offset
    解释:获取key对应string在offset处的bit值,当offset超出长度或者key不存在时总返回0.
  • BITPOS key bit [start] [end]
    **解释:获取字符串里面第一个被设置成1或者0的bit位。参数bit可以时1或者0,start和end表示要从第start字节开始,到第end字节结束。
  • BITCOUNT key [start end]
    **解释:统计字符串被设置成1的bit数。start和end仍然表示的是字节。
  • BITOP operation destkey key [key ...]
    **解释:对一个或多个保存二进制位的字符串key进行位元操作,并把计算结果保存到destkey上。operation代表的操作可以是AND、OR、NOT、XOR。

数值类型的操作。

  • INCR key
    解释:对存储在指定key的数值执行原子的加1操作。
  • DECR key
    解释:对存储在指定key的数值执行原子的减1操作。
  • INCRBY key increment
    解释:将key对应的数字加increment。
  • DECRBY key decrement
    解释:将key对应的数字减decrement。
  • INCRBYFLOAT key increment
    解释:将key对应的浮点数增加浮点数increment。

127.0.0.1:6379> set name genie EX 20 NX #设置key=name,value=genie,过期时间20秒,不存在才能设置成功

OK127.0.0.1:6379> set name genie EX 20 XX #由于key=name的键已存在,所以参数XX执行不成功(nil)127.0.0.1:6379> ttl name #查看key=name的键还有多长时间过期 (integer) 15127.0.0.1:6379> setex name2 60 weizhuang

OK127.0.0.1:6379> ttl name2(integer) 45127.0.0.1:6379> setnx name2 tianming(integer) 0127.0.0.1:6379> flushdb #清楚数据库中所有的key

OK127.0.0.1:6379> keys * #查看数据库中的所有key(empty array)127.0.0.1:6379> mset key1 value1 key2 value2 key3 value3

OK127.0.0.1:6379> keys *1) "key2"2) "key3"3) "key1"127.0.0.1:6379> mget key1 key2 key31) "value1"2) "value2"3) "value3"127.0.0.1:6379> setrange key3 2 new(integer) 6127.0.0.1:6379> get key3"vanew3"127.0.0.1:6379> getrange key3 2 -1"new3"127.0.0.1:6379> strlen key3(integer) 6127.0.0.1:6379> getset key3 hello"vanew3"127.0.0.1:6379> append key3 " world"(integer) 11127.0.0.1:6379> get key3"hello world"127.0.0.1:6379> setbit bitkey 1 1(integer) 0127.0.0.1:6379> getbit bitkey 1(integer) 1127.0.0.1:6379> bitpos bitkey 1(integer) 1127.0.0.1:6379> bitcount bitkey(integer) 1127.0.0.1:6379> setbit bitkey2 0 1(integer) 0127.0.0.1:6379> bitop and bitkey3 bitkey bitkey2(integer) 1127.0.0.1:6379> getbit bitkey3 0(integer) 0127.0.0.1:6379> set number 0

OK127.0.0.1:6379> incr number(integer) 1127.0.0.1:6379> get number"1"127.0.0.1:6379> decr number(integer) 0127.0.0.1:6379> get number"0"127.0.0.1:6379> incrby number 10(integer) 10127.0.0.1:6379> decrby number 2(integer) 8

2、List类型

Redis列表是通过Linked List实现的双向线性链表,元素按照插入顺序排序,向链表的头部和尾部添加新元素的时间复杂度是常量级的,缺点是查询的时间复杂度是O(N)。

  • LPUSH key value [value ...]
    解释:将所有给定的值依次插入到链表的头部。
  • LPOP key
    解释:移除并返回key对应的list的第一个元素。
  • RPUSH key value [value ...]
    解释:将所有给定的值依次添加到链表的尾部。
  • RPOP key
    解释:移除并返回key对应的list的最后一个元素。
  • LPUSHX key value [value ...]
    解释:如果key对应list存在,则向链表的头部插入元素。
  • RPUSHX key value [value ...]
    解释:如果key对应的list存在,则向链表的尾部插入元素。
  • RPOPLPUSH source destination
    解释:从source列表的尾部弹出一个元素放到destination列表的头部。
    应用:可以用来做安全的消息队列防止消息丢失;如果source和destination相同的话可以实现循环链表。
  • LRANGE key start stop
    解释:返回存储在key的列表中start到stop范围内的元素。偏移量从0开始计算,如果是负数表示从尾部开始计数,最后一个预算是-1。
  • LLEN key
    解释:返回存储在key的列表的长度。
  • LINDEX key index
    解释:返回存储在key的列表中下标为index(从0开始)位置的元素。
  • LSET key index value
    解释:设置存储在key的列表中下标为index位置的值为value.
  • LINSERT key BEFORE|AFTER pivot value
    解释:把value插入存于key的列表中在基准值pivot的前面或后面。
  • LREM key count value
    解释:从存于key的列表里移除前count次出现的值为value的元素。count>0从头往尾移除;count<0从尾往头移除;count=0移除所有。
  • LTRIM key start stop
    解释:修剪key存储的列表,保证列表只包含start到stop之间的元素。
  • BLPOP key [key ...] timeout
    解释:在超时时间内阻塞式从左边弹出列表元素。
  • BRPOP key [key ...] timeout
    解释:在超时时间内阻塞式从右边弹出列表元素。
  • BRPOPLPUSH source destination timeout
    解释:BRPOPLPUSH 是RPOPLPUSH的阻塞版本。

127.0.0.1:6379> lpush userlist user1 user2 user3(integer) 3127.0.0.1:6379> lrange userlist 0 -11) "user3"2) "user2"3) "user1"127.0.0.1:6379> lpop userlist"user3"127.0.0.1:6379> lrange userlist 0 -11) "user2"2) "user1"127.0.0.1:6379> rpush userlist user0(integer) 3127.0.0.1:6379> lrange userlist 0 -11) "user2"2) "user1"3) "user0"127.0.0.1:6379> rpop userlist"user0"127.0.0.1:6379> lpushx userlist user3(integer) 3127.0.0.1:6379> rpushx otherlist other1(integer) 0127.0.0.1:6379> rpoplpush userlist otherlist"user1"127.0.0.1:6379> lrange otherlist 0 -11) "user1"127.0.0.1:6379> llen userlist(integer) 2127.0.0.1:6379> lset userlist 0 user0

OK127.0.0.1:6379> lindex userlist 0"user0"127.0.0.1:6379> linsert userlist before user0 user-1(integer) 3127.0.0.1:6379> lrange userlist 0 -11) "user-1"2) "user0"3) "user2"127.0.0.1:6379> lrem userlist 1 user-1(integer) 1127.0.0.1:6379> lrange userlist 0 -11) "user0"2) "user2"127.0.0.1:6379> rpush userlist user3 user4 user5 user6(integer) 6127.0.0.1:6379> ltrim userlist 0 5

OK127.0.0.1:6379> lrange userlist 0 -11) "user0"2) "user2"3) "user3"4) "user4"5) "user5"6) "user6"127.0.0.1:6379> ltrim userlist 0 3

OK127.0.0.1:6379> lrange userlist 0 -11) "user0"2) "user2"3) "user3"4) "user4"127.0.0.1:6379> blpop otherlist 01) "otherlist"2) "user1"127.0.0.1:6379> brpop otherlist 5(nil)(5.05s)

3、Set类型

Redis Set是字符串的无序集合,集合中的元素不会重复。可以在O(1)的时间复杂度内完成添加、删除和判断元素是否存在的操作。可以在很短的时间内在服务端进行集合的交集、并集、差集操作。

  • SADD key member [member ...]
    解释:添加一个或多个指定的member元素到集合的 key中。
  • SCARD key
    解释:返回key对应集合存储的元素个数。
  • SMEMBERS key
    解释:返回key对应集合的所有元素。建议使用SSCAN以游标方式迭代,避免阻塞和占用带宽。
  • SISMEMBER key element
    解释:返回element是否是集合key中的元素。
  • SMOVE source destination member
    解释:将元素member从source集合移动到destination结合。
  • SPOP key [count]
    解释:从集合key中弹出一个多个元素。
  • SRANDMEMBER key [count]
    解释:随即返回集合中的一个或多个元素,不删除集合中的元素。
  • SREM key member [member ...]
    解释:移除集合中指定的元素。
  • SSCAN key cursor [MATCH pattern] [COUNT count]
    解释:使用游标迭代集合中的元素。初始cursor是0,返回值的第一项是下一次迭代的cursor,直到返回值为0代表迭代完成。Match表示可对返回结果进行模式匹配,COUNT表示返回元素个数的参考值。
  • SINTER key [key ...]
    解释:返回指定所有的集合的成员的交集。
  • SINTERSTORE destination key [key ...]
    解释:将集合的交集存储到目标集合destination中。
  • `SUNION key [key …]
    解释:返回给定的多个集合的并集中的所有成员。
  • SUNIONSTORE destination key [key ...]
    解释:将集合的并集存储到目标集合destination中。
  • SDIFF key [key ...]
    解释:返回一个集合与给定集合的差集的元素。
  • SDIFFSTORE destination key [key ...]
    解释:将一个集合和给定集合的差集放到目标集合destination中。

127.0.0.1:6379> sadd myset user0 user1 user2(integer) 3127.0.0.1:6379> scard myset(integer) 3127.0.0.1:6379> smembers myset1) "user2"2) "user1"3) "user0"127.0.0.1:6379> sismember myset user3(integer) 0127.0.0.1:6379> smove myset myset2 user2(integer) 1127.0.0.1:6379> smembers myset21) "user2"127.0.0.1:6379> spop myset2"user2"127.0.0.1:6379> smembers myset2(empty array)127.0.0.1:6379> srandmember myset "user0"127.0.0.1:6379> sscan myset 01) "0"2) 1) "user1"

2) "user0"127.0.0.1:6379> srem myset user1(integer) 1127.0.0.1:6379> smembers myset1) "user0"127.0.0.1:6379> sadd myset user1 user2 user3(integer) 3127.0.0.1:6379> sadd myset2 user2 user3 user4(integer) 3127.0.0.1:6379> sinter myset myset21) "user2"2) "user3"127.0.0.1:6379> sdiff myset myset21) "user0"2) "user1"127.0.0.1:6379> sunion myset myset21) "user1"2) "user3"3) "user2"4) "user0"5) "user4"

4、Hash类型

Redis Hash是字符串字段和字符串值之间的映射,也就是说Hash类型的值实际上也是一个个的键值对,因此可以很好的表示对象类型。

  • HSET key field value
    解释:设置key指定的哈希集中指定字段的值。
  • HGET key field
    解释:返回key指定的哈希集中该字段所关联的值。
  • HMSET key fied value [field value ...]
    解释:一次设置key指定的哈希集中多个字段的值。
  • HMGET key field [field ...]
    解释:一次获取key指定的哈希集中多个字段的值。
  • HGETALL key
    解释:返回key指定的哈希集中所有的字段和值。
  • HSETNX key field value
    解释:只在key指定的哈希集中不存在指定的字段时,设置字段的值。
  • HDEL key field [field ...]
    解释:从key指定的哈希集中移除指定的域。
  • HEXISTS key field
    解释:返回hash里面的field是否存在。
  • HLEN key
    解释:返回key指定的哈希集中包含的字段的数量。
  • HKEYS key
    解释:返回key指定的哈希集中所有字段的名字。
  • HVALS key
    解释:返回key指定的哈希集中所有字段的值。
  • HSCAN key cursor [MATCH pattern] [COUNT count]
    解释:使用游标遍历哈希集中所有的键值对。
  • HSTRLEN key field
    解释:返回key指定的哈希集中指定字段对应的值的长度。
  • HINCRBY key field increment
    解释:让key指定的filed的值增加increment。
  • HINCRBYFLOAT key field increment
    解释:让key指定的field的值增加float类型的increment。

127.0.0.1:6379> hset user:001 name zhangsan age 25(integer) 2127.0.0.1:6379> hget user:001 name"zhangsan"127.0.0.1:6379> hmget user:001 name age1) "zhangsan"2) "25"127.0.0.1:6379> hgetall user:0011) "name"2) "zhangsan"3) "age"4) "25"127.0.0.1:6379> hsetnx user:001 sex male(integer) 1127.0.0.1:6379> hdel user:001 sex(integer) 1127.0.0.1:6379> hexists user:001 sex(integer) 0127.0.0.1:6379> hlen user:001(integer) 2127.0.0.1:6379> hkeys user:0011) "name"2) "age"127.0.0.1:6379> hvals user:0011) "zhangsan"2) "25"127.0.0.1:6379> hscan user:001 01) "0"2) 1) "name"

2) "zhangsan"

3) "age"

4) "25"127.0.0.1:6379> hstrlen user:001 name(integer) 8127.0.0.1:6379> hincrby user:001 age 1(integer) 26127.0.0.1:6379> hincrbyfloat user:001 age 0.5"26.5"

5、Sorted Set类型

Redis Sorted Sets 与Redis Sets类似,是字符串的非重复集合。不同之处在于,Sorted Set的每个成员都与一个分数相关联,用于保持Soreted Set的顺序,从最小到最大的分数。虽然成员是唯一的,但是分数可以重复。插入、删除、更新元素的时间复杂度都是O(log n)级别。

  • ZADD key [NX|XX] [CH] [INCR] score member [score member ...]
    解释:将所有指定的成员添加到键为key的有序集合里面。
    [NX]:只添加新成员。[XX]:只更新存在的成员的分数。
    [CH]:返回更新了分数的成员个数。[INCR]:对成员分数进行递增。
  • ZCARD key
    解释:返回key的有序集合中元素的个数。
  • ZCOUNT key min max
    解释:返回score值在min和max(包括min和max)之间的元素的个数。
  • ZLEXCOUNT key min max
    **解释:返回名称在min和max(包括min和max)之间的元素个数。
  • ZRANGE key start stop [WITHSCORE]
    解释:返回有序集合中第start到stop位置的元素,位置从0开始,可以是使用负向索引,最后一个元素的位置可以表示为-1。WITHCSCORE表示返回值带上分数。
  • ZRANGEBYLEX key min max [LIMIT offset count]
    解释:返回指定成员区间内的成员,按成员字典正序排列,分数必须相同。min的最小值可以用’-‘表示,max的最大值可以用’+‘表示。如果用其他值,min和max之前应用’['或者’('开头。
  • ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
    解释:返回有序集合中分数在min和max之间的元素。默认包括min和max分值的元素,如果想使用开区间可以加上’('符合。-inf和+inf表示负无穷和正无穷。默认是按照分数从低到高排序的。
  • ZREVRANGE key start stop [WITHSCORES]
    解释:返回有序集中,指定区间内的成员,成员按照score值递减排列。
  • ZREVRANGEBYLEX key max min [LIMIT offset count]
    解释:返回指定成员区间内的成员,按成员字典序倒叙排序,其余细节参考zrangebylex命令。不要在分数不同的有序集合中使用这个命令。
  • ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]
    解释:返回指定分数区间内的成员,按照分数值逆序排序。
  • ZRANK key member
    解释:返回按照分数从低到高排序的有序集合中member的位置,从0开始。
  • ZREVRANK key member
    解释:返回按照分数从高到低排序的有序集合中member的位置,从0开始。
  • ZSCORE key member
    解释:返回有序集合key中,成员member的分值。
  • ZMSCORE key member [member ...]
    解释:一次返回多个成员的分值。
  • ZREM key member [member ...]
    解释:移除有序集合中指定的成员。
  • ZREMRANGEBYLEX key min max
    解释:删除名称按照字典由低到高排序的成员之间的成员,不要在成员分数不同的有序集合上使用此命令。
  • ZREMRANGEBYRANK key start stop
    解释:移除集合中位置从start到stop的元素。
  • ZREMRANGEBYSCORE key min max
    解释:移除集合中score值在min和max之间的成员。
  • ZSCAN key cursor [MATCH pattern] [COUNT count]
    解释:使用游标遍历有序集合中的元素。
  • ZPOPMAX key [count]
    解释:删除并返回有序集合key中按照分数从高到低排序的count个成员。
  • ZPOPMIN key [count]
    解释:删除并返回有序集合key中按照分数从低到高排序的count个成员。
  • BZPOPMAX key [key ...] timeout
    解释:阻塞删除有序集合中分数值最大的成员。
  • BZPOPMIN key [key ...] timeout
    解释:阻塞删除有序集合中分数值最小的成员。
  • ZINCRBY key increment member
    解释:将有序集合中指定的成员的分数增加increment。
  • ZDIFF numkeys key [key ...] [WITHSCORES]
    解释:返回集合的差集。
  • ZDIFFSTORE destination numkeys key [key ...]
    解释:将集合的差集存储到目标集合destination中。
  • ZINTER numkeys key [key ...] [WEIGHTS weight [weight ...] [AGGREGATE SUM|MIN|MAX] [WITHSCORES]
    解释:计算并返回集合的交集。WEIGHTS:每个集合的权重,用于计算交集元素的分数,默认都是1。AGGREGATE:聚合方式:取和|取最小值|取最大值。
  • ZINTERCARD numkeys key [key ...] [LIMIT limit]
    解释:返回集合中交集的元素个数。limit表示最大限制,如果计算交集的时候交集元素个数达到limit,则不再继续计算,直接返回limit。
  • ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM | MIN | MAX]
    解释:将集合交集存储到目标集合中。
  • ZUNION numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM | MIN | MAX] [WITHSCORES]
    解释:返回集合的并集。
  • ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM | MIN | MAX]
    解释:将集合的并集存储到指定的集合中。

127.0.0.1:6379> zadd zset 0 user0 1 user1 2 user2(integer) 3127.0.0.1:6379> zcard zset(integer) 3127.0.0.1:6379> zcount zset 0 1(integer) 2127.0.0.1:6379> zlexcount zset [user0 [user1(integer) 2127.0.0.1:6379> zrange zset 0 -11) "user0"2) "user1"3) "user2"127.0.0.1:6379> zrangebyscore zset 0 11) "user0"2) "user1"127.0.0.1:6379> zrangebyscore zset 0 1 withscores1) "user0"2) "0"3) "user1"4) "1"127.0.0.1:6379> zrank zset user2(integer) 2127.0.0.1:6379> zrevrank zset user2(integer) 0127.0.0.1:6379> zscore zset user2"2"127.0.0.1:6379> zmscore zset user0 user2 user31) "0"2) "2"3) (nil)127.0.0.1:6379> zrem zset user2(integer) 1127.0.0.1:6379> zremrangebylex zset [user2 [user3(integer) 0127.0.0.1:6379> zremrangebyscore zset 3 5(integer) 0127.0.0.1:6379> zscan zset 01) "0"2) 1) "user0"

2) "0"

3) "user1"

4) "1"127.0.0.1:6379> zpopmax zset1) "user1"2) "1"127.0.0.1:6379> zpopmin zset1) "user0"2) "0"127.0.0.1:6379> zrange zset 0 -1(empty array)127.0.0.1:6379> zadd zset 0 user0 1 user1 2 user2 3 user3(integer) 4127.0.0.1:6379> zincrby zset 1 user3"4"127.0.0.1:6379> zscore zset user3"4"127.0.0.1:6379> zadd zset2 12 user2 13 user3 14 user4(integer) 3127.0.0.1:6379> zdiff 2 zset zset2 withscores1) "user0"2) "0"3) "user1"4) "1"127.0.0.1:6379> zinter 2 zset zset2 weights 2 1 aggregate max withscores1) "user2"2) "12"3) "user3"4) "13"127.0.0.1:6379> zunion 2 zset zset weights 1 1 aggregate sum withscores1) "user0"2) "0"3) "user1"4) "2"5) "user2"6) "4"7) "user3"8) "8"127.0.0.1:6379> zunion 2 zset zset2 weights 1 1 aggregate sum withscores

1) "user0"

2) "0"

3) "user1"

4) "1"

5) "user2"

6) "14"

7) "user4"

8) "14"

9) "user3"10) "17"

6、HyperLogLog

HyperLogLog是一个概率性的数据结构,用于统计集合中不重复的元素个数。HyperLoLog是一种空间换取精确度的思想,并不实际存储元素,最多只需要12k的空间即可以误差率低于1%的精确度估计集合的基数。

  • PFADD key element [element ...]
    解释:将元素加入HyperLogLog结构中。
  • PFCOUNT key [key ...]
    解释:如果只有一个参数key,则返回这个key代表的HyperLogLog结构的近似基数。如果有多个key,则合并所有key的HyperLoglog结构到一个临时的HyperLogLog结构,然后返回计算得到的基数。
  • PFMERGE destkey sourcekey [sourcekey ...]
    解释:将多个HyperLogLog合并为一个HyperLogLog,合并后的HyperLogLog的基数接近于所有输入HyperLogLog的可见集合的并集。

127.0.0.1:6379> pfadd myhll user1 user2 user3 user4 user5 user5 user4(integer) 1127.0.0.1:6379> pfcount myhll(integer) 5127.0.0.1:6379> pfadd myhll2 user1 user3 user6 user9(integer) 1127.0.0.1:6379> pfcount myhll myhll2(integer) 7127.0.0.1:6379> pfmerge myhll3 myhll myhll2

OK127.0.0.1:6379> pfcount myhll3(integer) 7127.0.0.1:6379> get myhll"HYLL\x01\x00\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00WR\x80F\x19\x80K\xff\x84N\x92\x80@\xfc\x80F\xfd"127.0.0.1:6379> type myhll #HyperLogLog基于String类型。

string

7、Geospatial in index

Geo是一种用于地理位置计算的数据结构,本质上是基于soreted set。每一个位置都需要经度和纬度来定位,从而基于Haversine距离公式假设地球是个完美的球形来计算两个地点的距离。

  • 有效的精度从-180度到180度。
  • 有效的维度从-85.05112878度到85.05112878度。
  • GEOADD key longitudu latitude member [longitude latitude member ...]
    解释:将指定的地理空间位置(经度、维度、名称)添加到指定的key中。
  • GEODIST key member1 member2 [unit]
    解释:返回集合中两个给定位置的距离。unit默认是米,可以指定下面这些单位:m米、km千米、mi英里、ft英尺。
  • GEOHASH key member [member ...]
    解释:返回一个或多个位置元素的Geohash表示。
  • GEOPOS key member [member ...]
    解释:从key里返回所有给定位置元素的位置(精度和维度)。
  • GEORADIUS key longitude latitude radius M|KM|FT|MI [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count [ANY]] [ASC|DESC] [STORE key] [STOREDIST key]
    解释:一给定的经纬度为中心,返回键包含的位置元素当中,与中心的距离不超过给定最大距离的所有位置元素。已过时,可使用GEOSEARCH代替。
  • GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]
    解释:同GEORADIUS命令一样,都可以找出位于指定范围内的元素,但是是以指定位置元素为中心的。
    GEOSEARCH key FROMMEMBER member | FROMLONLAT longitude latitude BYRADIUS radius M|KM|FT|MI | BYBOX width height M|KM|FT|MI [ASC|DESC] [COUNT count [ANY]] [WITHCOORD] [WITHDIST] [WITHHASH]
    解释:返回使用GEOADD填充的地理空间信息排序集中的成员,这些成员位于给定形状指定的区域的边界内。
    GEOSEARCHSTORE destination source FROMMEMBER member | FROMLONLAT longitude latitude BYRADIUS radius M | KM | FT | MI | BYBOX width height M | KM | FT | MI [ ASC | DESC] [ COUNT count [ANY]] [STOREDIST]
    解释:同GEOSEARCH,但是将结果存储到另一个GEO里面。

127.0.0.1:6379> GEOADD cities 116.28 39.54 beijing 120.19 36.04 qingdao 113.42 34.44 zhengzhou(integer) 3127.0.0.1:6379> GEOADD cities 118.46 32.03 nanjing 121.26 31.12 shanghai 113.18 23.10 guangzhou(integer) 3127.0.0.1:6379> GEODISt cities shanghai beijing km"1039.3868"127.0.0.1:6379> zrange cities 0 -1 withscores

1) "guangzhou"

2) "4046510568184210"

3) "shanghai"

4) "4054748594239096"

5) "zhengzhou"

6) "4064196885461489"

7) "nanjing"

8) "4065998211365636"

9) "qingdao"10) "4067518574201342"11) "beijing"12) "4069140601296155"127.0.0.1:6379> geohash cities shanghai1) "wtw1p34z4u0"127.0.0.1:6379> geopos cities guangzhou shanghai beijing1) 1) "113.18000167608261108"

2) "23.10000005307264104"2) 1) "121.26000076532363892"

2) "31.1199997456060018"3) 1) "116.28000229597091675"

2) "39.54000124957348561"127.0.0.1:6379> georadius cities 110 25 1000 km withcoord withdist1) 1) "guangzhou"

2) "385.9618"

3) 1) "113.18000167608261108"

2) "23.10000005307264104"127.0.0.1:6379> georadiusbymember cities shanghai 1000 km withcoord withdist1) 1) "shanghai"

2) "0.0000"

3) 1) "121.26000076532363892"

2) "31.1199997456060018"2) 1) "zhengzhou"

2) "820.5412"

3) 1) "113.42000037431716919"

2) "34.4400003325985935"3) 1) "nanjing"

2) "283.9656"

3) 1) "118.45999985933303833"

2) "32.03000012790491979"4) 1) "qingdao"

2) "556.1306"

3) 1) "120.18999785184860229"

2) "36.03999997417160017"127.0.0.1:6379> geosearch cities frommember shanghai bybox 800 1000 km asc withcoord withdist1) 1) "shanghai"

2) "0.0000"

3) 1) "121.26000076532363892"

2) "31.1199997456060018"2) 1) "nanjing"

2) "283.9656"

3) 1) "118.45999985933303833"

2) "32.03000012790491979"

8、Stream

Stream是Redis5.0版本引入的一个新的数据类型,它以更抽象的方式模拟日志数据结构,但欸之仍然是完整的:就像日志文件,通常实现为只附加模式打开的文件,Redis流主要是一个仅附加数据结构。

  • XADD key ID field string [field string ...]
    解释:将指定的流条目追加到指定的key的流中。一个条目由一组键值对组成。
  • XDEL key ID [ID ...]
    解释:从指定流中将指定id 的条目标记为删除。
  • XLEN key
    解释:返回流中的条目数。
  • XRANGE key start end [COUNT count]
    解释:返回流中满足给定id范围[start,end]的条目。
  • XREVRANGE key end start [COUNT count]
    解释:同XRANGE,但是以相反的顺序返回给定区间的条目。
  • XREAD [COUNT count] [BLOCK milliseconds]STREAMS key [key ...] ID [ID ...]
    解释:从一个或者多个流中返回id大于指定id的条目。$表示当前流中最大的id。
  • XTRIM key MAXLEN [~] count
    解释:将流裁剪为指定数量的条目,达到数目后会删除id较小的条目。
  • XGROUP [CREATE key groupname id-or-$] [SETID key groupname id-or-$] [DESTROY key groupname] [DELCONSUMER key groupname consumername]
    解释:XGROUP CREATE key groupname id-or-:创建与流关联的新消费者组;�������������������������−��−:创建与流关联的新消费者组;XGROUPSETIDkeygroupnameid−or−:将消费者组的最后交付ID设置为其他内容;XGROUP DESTROY key groupname:销魂一个消费者组;XGROUP DELCONSUMER key groupname consumer:从消费者组中移除指定消费者。
  • XREADGROUP GROUP group consumer [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] ID [ID ...]
    解释:从消费者组中读取消息。消费者组中的消息只会被一个消费者消费。
  • XACK key group ID [ID ...]
    解释:从流的消费者组的待处理条目列表中删除一条或多条消息。
  • XPENDING key group [start end count] [consumer]
    解释:查看消费者组中没有被XACK命令确认的消息。
  • XCLAIM key group consumer min-idle-time ID [ID ...] [IDLE ms] [TIME ms-unix-time] [TETRYCOUNT count] [FORCE] [JUSTID]
    解释:在流的消费者组上下文中,此命令改变待处理消息的所有权。
  • XINFO [CONSUMERS key groupname] key key [HELP]
    解释:查看流和关联的消费者组的信息。有三种形式:XINFO STREAM [key]:返回有关存储在特定键的流的一般信息;XINFO GROUP :获取流关联的消费者组的相关信息;XINFO CONSUMERS :获取指定流的消费者组中的消费者列别。XINFO HELP:查看帮助。

127.0.0.1:6379> XADD mystream MAXLEN ~ 10 * name zhangsan age 25"1651650194291-0"127.0.0.1:6379> XLEN mystream(integer) 1127.0.0.1:6379> XADD mystream * name lisi age 24"1651650248387-0"127.0.0.1:6379> XADD mystream * name wangwu age 25"1651650260460-0"127.0.0.1:6379> xdel mystream 1651650260460-0(integer) 1127.0.0.1:6379> xrange mystream - + 1) 1) "1651650194291-0"

2) 1) "name"

2) "zhangsan"

3) "age"

4) "25"2) 1) "1651650248387-0"

2) 1) "name"

2) "lisi"

3) "age"

4) "24"127.0.0.1:6379> xrevrange mystream + -1) 1) "1651650248387-0"

2) 1) "name"

2) "lisi"

3) "age"

4) "24"2) 1) "1651650194291-0"

2) 1) "name"

2) "zhangsan"

3) "age"

4) "25"127.0.0.1:6379> xread Streams mystream 01) 1) "mystream"

2) 1) 1) "1651650194291-0"

2) 1) "name"

2) "zhangsan"

3) "age"

4) "25"

2) 1) "1651650248387-0"

2) 1) "name"

2) "lisi"

3) "age"

4) "24"127.0.0.1:6379> xadd mystream * name wangwu age 26"1651650481385-0"127.0.0.1:6379> xtrim mystream maxlen ~ 2(integer) 0127.0.0.1:6379> xrange mystream - + #可以看到使用`~`不一定会精确的固定长度1) 1) "1651650194291-0"

2) 1) "name"

2) "zhangsan"

3) "age"

4) "25"2) 1) "1651650248387-0"

2) 1) "name"

2) "lisi"

3) "age"

4) "24"3) 1) "1651650481385-0"

2) 1) "name"

2) "wangwu"

3) "age"

4) "26"127.0.0.1:6379> xtrim mystream maxlen 2(integer) 1127.0.0.1:6379> xrange mystream - +1) 1) "1651650248387-0"

2) 1) "name"

2) "lisi"

3) "age"

4) "24"2) 1) "1651650481385-0"

2) 1) "name"

2) "wangwu"

3) "age"

4) "26"127.0.0.1:6379> xgroup create mystream mygroup $

OK127.0.0.1:6379> xpending mystream mygroup1) (integer) 02) (nil)3) (nil)4) (nil)127.0.0.1:6379> xadd mystream * name zhangsan age 25"1651650646406-0"127.0.0.1:6379> xpending mystream mygroup1) (integer) 02) (nil)3) (nil)4) (nil)127.0.0.1:6379> xreadgroup group mygroup liyanan streams mystream >1) 1) "mystream"

2) 1) 1) "1651650646406-0"

2) 1) "name"

2) "zhangsan"

3) "age"

4) "25"127.0.0.1:6379> xreadgroup group mygroup liyanan2 streams mystream >(nil)127.0.0.1:6379> xadd mystream * name laoliu age 26"1651650806288-0"127.0.0.1:6379> xreadgroup group mygroup liyanan2 streams mystream >1) 1) "mystream"

2) 1) 1) "1651650806288-0"

2) 1) "name"

2) "laoliu"

3) "age"

4) "26"127.0.0.1:6379> xpending mystream mygroup1) (integer) 22) "1651650646406-0"3) "1651650806288-0"4) 1) 1) "liyanan"

2) "1"

2) 1) "liyanan2"

2) "1"127.0.0.1:6379> xack mystream mygroup 1651650646406-0(integer) 1127.0.0.1:6379> xpending mystream mygroup1) (integer) 12) "1651650806288-0"3) "1651650806288-0"4) 1) 1) "liyanan2"

2) "1"127.0.0.1:6379> xclaim mystream mygroup liyanan3 10000 1651650806288-01) 1) "1651650806288-0"

2) 1) "name"

2) "laoliu"

3) "age"

4) "26"127.0.0.1:6379> xinfo stream mystream

1) "length"

2) (integer) 4

3) "radix-tree-keys"

4) (integer) 1

5) "radix-tree-nodes"

6) (integer) 2

7) "last-generated-id"

8) "1651650806288-0"

9) "groups"10) (integer) 111) "first-entry"12) 1) "1651650248387-0"

2) 1) "name"

2) "lisi"

3) "age"

4) "24"13) "last-entry"14) 1) "1651650806288-0"

2) 1) "name"

2) "laoliu"

3) "age"

4) "26"127.0.0.1:6379> xinfo groups mystream1) 1) "name"

2) "mygroup"

3) "consumers"

4) (integer) 3

5) "pending"

6) (integer) 1

7) "last-delivered-id"

8) "1651650806288-0"127.0.0.1:6379> xinfo consumers mystream mygroup1) 1) "name"

2) "liyanan"

3) "pending"

4) (integer) 0

5) "idle"

6) (integer) 3064792) 1) "name"

2) "liyanan2"

3) "pending"

4) (integer) 0

5) "idle"

6) (integer) 2393693) 1) "name"

2) "liyanan3"

3) "pending"

4) (integer) 1

5) "idle"

6) (integer) 108716

9、Pub/Sub

Pub/Sub实现了发布/订阅消息范式。发布者只需要将消息发送到指定的频道,不需要知道什么样的订阅者订阅。订阅者只需要对自己感兴趣的频道进行订阅,不需要知道消息是什么样的发布者发布的。实现了发布者和订阅者的解耦。

  • SUBSCRIBE channel [channel ...]
    解释:订阅一个或多个频道。
  • PSUBSCRIBE pattern [pattern]
    解释:订阅给定的模式。如:h?llo 可以订阅到hello,hallo …
  • PUBLISH channel message
    解释:将消息message发送到指定的频道channel。
  • UNSUBSCRIBE [channel [channel ...]]
    解释:退订指定的频道,如果没有指定频道,则退订所有频道。
  • PUNSUBSCRIBE [pattern [pattern ...]]
    解释:退订指定模式的频道,如果没有指定模式,则退订所有。
  • PUBSUB subcommand [argument [argument ...]]
    解释:自省命令,能够检测到PUB/SUB子系统的状态。如 pubsub channels可以检测活跃的信道。

#客户端1:消息发布者127.0.0.1:6379> publish CCTV-1 "welcome to watching CCTV-1"(integer) 2127.0.0.1:6379> publish CCTV-2 "welcome to watching CCTV-2"(integer) 1127.0.0.1:6379> pubsub channels1) "CCTV-2"2) "CCTV-1"127.0.0.1:6379>

#客户端二:订阅CCTV-1频道127.0.0.1:6379> subscribe CCTV-1

Reading messages... (press Ctrl-C to quit)1) "subscribe"2) "CCTV-1"3) (integer) 11) "message"2) "CCTV-1"3) "welcome to watching CCTV-1"

#客户端三:订阅CCTV-1和CCTV-2频道127.0.0.1:6379> subscribe CCTV-1 CCTV-2

Reading messages... (press Ctrl-C to quit)1) "subscribe"2) "CCTV-1"3) (integer) 11) "subscribe"2) "CCTV-2"3) (integer) 21) "message"2) "CCTV-1"3) "welcome to watching CCTV-1"1) "message"2) "CCTV-2"3) "welcome to watching CCTV-2"

六、Redis持久化策略及其内存淘汰策略

1、Redis持久化

Redis支持两种持久化方式:RDB和AOF。RDB持久化方式的思想是每隔一段时间对内存中的数据进行快照存储;AOF持久化方式是记录每次对服务器的写操作,然后追加到AOF文件的末尾,为防止文件过大,Redis支持对AOF文件的重写。

RDB的优点

  • RDB是一个非常紧凑的文件,它保存了某个时间点得数据集,非常适用于数据集的备份,比如你可以在每个小时报保存一下过去24小时内的数据,同时每天保存过去30天的数据,这样即使出了问题你也可以根据需求恢复到不同版本的数据集.
  • RDB是一个紧凑的单一文件,很方便传送到另一个远端数据中心或者亚马逊的S3(可能加密),非常适用于灾难恢复.
  • RDB在保存RDB文件时父进程唯一需要做的就是fork出一个子进程,接下来的工作全部由子进程来做,父进程不需要再做其他IO操作,所以RDB持久化方式可以最大化redis的性能.
  • 与AOF相比,在恢复大的数据集的时候,RDB方式会更快一些.

RDB的缺点

  • 如果你希望在redis意外停止工作(例如电源中断)的情况下丢失的数据最少的话,那么RDB不适合你.虽然你可以配置不同的save时间点(例如每隔5分钟并且对数据集有100个写的操作),是Redis要完整的保存整个数据集是一个比较繁重的工作,你通常会每隔5分钟或者更久做一次完整的保存,万一在Redis意外宕机,你可能会丢失几分钟的数据.
  • RDB 需要经常fork子进程来保存数据集到硬盘上,当数据集比较大的时候,fork的过程是非常耗时的,可能会导致Redis在一些毫秒级内不能响应客户端的请求.如果数据集巨大并且CPU性能不是很好的情况下,这种情况会持续1秒,AOF也需要fork,但是你可以调节重写日志文件的频率来提高数据集的耐久度.

AOF 优点

  • 使用AOF 会让你的Redis更加耐久: 你可以使用不同的fsync策略:无fsync,每秒fsync,每次写的时候fsync.使用默认的每秒fsync策略,Redis的性能依然很好(fsync是由后台线程进行处理的,主线程会尽力处理客户端请求),一旦出现故障,你最多丢失1秒的数据.
  • AOF文件是一个只进行追加的日志文件,所以不需要写入seek,即使由于某些原因(磁盘空间已满,写的过程中宕机等等)未执行完整的写入命令,你也也可使用redis-check-aof工具修复这些问题.
  • 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)。

如何选择使用哪种持久化方式?

  • 一般来说, 如果想达到足以媲美 PostgreSQL 的数据安全性, 你应该同时使用两种持久化功能。
    如果你非常关心你的数据, 但仍然可以承受数分钟以内的数据丢失, 那么你可以只使用 RDB 持久化。
    有很多用户都只使用 AOF 持久化, 但我们并不推荐这种方式: 因为定时生成 RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快, 除此之外, 使用 RDB 还可以避免之前提到的 AOF 程序的 bug 。
  • Note: 因为以上提到的种种原因, 未来我们可能会将 AOF 和 RDB 整合成单个持久化模型。 (这是一个长期计划。) 接下来的几个小节将介绍 RDB 和 AOF 的更多细节。

快照

  • 在默认情况下, Redis 将数据库快照保存在名字为 dump.rdb的二进制文件中。你可以对 Redis 进行设置, 让它在“ N 秒内数据集至少有 M 个改动”这一条件被满足时, 自动保存一次数据集。你也可以通过调用 SAVE或者 BGSAVE , 手动让 Redis 进行数据集保存操作。
    比如说, 以下设置会让 Redis 在满足“ 60 秒内有至少有 1000 个键被改动”这一条件时, 自动保存一次数据集:
    save 60 1000
    这种持久化方式被称为快照 snapshotting.

工作方式

当 Redis 需要保存 dump.rdb 文件时, 服务器执行以下操作:

  • Redis 调用forks. 同时拥有父进程和子进程。
  • 子进程将数据集写入到一个临时 RDB 文件中。
  • 当子进程完成对新 RDB 文件的写入时,Redis 用新 RDB 文件替换原来的 RDB 文件,并删除旧的 RDB 文件。
    这种工作方式使得 Redis 可以从写时复制(copy-on-write)机制中获益。

只追加操作的文件(Append-only file,AOF)

  快照功能并不是非常耐久(dura ble): 如果 Redis 因为某些原因而造成故障停机, 那么服务器将丢失最近写入、且仍未保存到快照中的那些数据。 从 1.1 版本开始, Redis 增加了一种完全耐久的持久化方式: AOF 持久化。
  你可以在配置文件中打开AOF方式:
  appendonly yes
  从现在开始, 每当 Redis 执行一个改变数据集的命令时(比如 SET), 这个命令就会被追加到 AOF 文件的末尾。这样的话, 当 Redis 重新启时, 程序就可以通过重新执行 AOF 文件中的命令来达到重建数据集的目的。

日志重写

  因为 AOF 的运作方式是不断地将命令追加到文件的末尾, 所以随着写入命令的不断增加, AOF 文件的体积也会变得越来越大。举个例子, 如果你对一个计数器调用了 100 次 INCR , 那么仅仅是为了保存这个计数器的当前值, AOF 文件就需要使用 100 条记录(entry)。然而在实际上, 只使用一条 SET 命令已经足以保存计数器的当前值了, 其余 99 条记录实际上都是多余的。
  为了处理这种情况, Redis 支持一种有趣的特性: 可以在不打断服务客户端的情况下, 对 AOF 文件进行重建(rebuild)。执行 BGREWRITEAOF 命令, Redis 将生成一个新的 AOF 文件, 这个文件包含重建当前数据集所需的最少命令。Redis 2.2 需要自己手动执行 BGREWRITEAOF 命令; Redis 2.4 则可以自动触发 AOF 重写, 具体信息请查看 2.4 的示例配置文件。

AOF有多耐用?

你可以配置 Redis 多久才将数据 fsync 到磁盘一次。有三种方式:

  • 每次有新命令追加到 AOF 文件时就执行一次 fsync :非常慢,也非常安全
  • 每秒 fsync 一次:足够快(和使用 RDB 持久化差不多),并且在故障时只会丢失 1 秒钟的数据。
  • 从不 fsync :将数据交给操作系统来处理。更快,也更不安全的选择。
  • 推荐(并且也是默认)的措施为每秒 fsync 一次, 这种 fsync 策略可以兼顾速度和安全性。

如果AOF文件损坏了怎么办?

服务器可能在程序正在对 AOF 文件进行写入时停机, 如果停机造成了 AOF 文件出错(corrupt), 那么 Redis 在重启时会拒绝载入这个 AOF 文件, 从而确保数据的一致性不会被破坏。当发生这种情况时, 可以用以下方法来修复出错的 AOF 文件:

  • 为现有的 AOF 文件创建一个备份。
  • 使用 Redis 附带的 redis-check-aof 程序,对原来的 AOF 文件进行修复:
    $ redis-check-aof –fix
  • (可选)使用 diff -u 对比修复后的 AOF 文件和原始 AOF 文件的备份,查看两个文件之间的不同之处。
  • 重启 Redis 服务器,等待服务器载入修复后的 AOF 文件,并进行数据恢复。

工作原理

AOF 重写和 RDB 创建快照一样,都巧妙地利用了写时复制机制:

  • Redis 执行 fork() ,现在同时拥有父进程和子进程。
  • 子进程开始将新 AOF 文件的内容写入到临时文件。
  • 对于所有新执行的写入命令,父进程一边将它们累积到一个内存缓存中,一边将这些改动追加到现有 AOF 文件的末尾,这样样即使在重写的中途发生停机,现有的 AOF 文件也还是安全的。
  • 当子进程完成重写工作时,它给父进程发送一个信号,父进程在接收到信号之后,将内存缓存中的所有数据追加到新 AOF 文件的末尾。
  • 搞定!现在 Redis 原子地用新文件替换旧文件,之后所有命令都会直接追加到新 AOF 文件的末尾。

怎样从RDB方式切换为AOF方式

在 Redis 2.2 或以上版本,可以在不重启的情况下,从 RDB 切换到 AOF :

  • 为最新的 dump.rdb 文件创建一个备份。
  • 将备份放到一个安全的地方。
  • 执行以下两条命令:
    redis-cli config set appendonly yes
    redis-cli config set save “”
  • 确保写命令会被正确地追加到 AOF 文件的末尾。
  • 执行的第一条命令开启了 AOF 功能: Redis 会阻塞直到初始 AOF 文件创建完成为止, 之后 Redis 会继续处理命令请求, 并开始将写入命令追加到 AOF 文件末尾。

执行的第二条命令用于关闭 RDB 功能。 这一步是可选的, 如果你愿意的话, 也可以同时使用 RDB 和 AOF 这两种持久化功能。
重要:别忘了在 redis.conf 中打开 AOF 功能! 否则的话, 服务器重启之后, 之前通过 CONFIG SET 设置的配置就会被遗忘, 程序会按原来的配置来启动服务器。

AOF和RDB之间的相互作用

  在版本号大于等于 2.4 的 Redis 中, BGSAVE 执行的过程中, 不可以执行 BGREWRITEAOF 。 反过来说, 在 BGREWRITEAOF 执行的过程中, 也不可以执行 BGSAVE。这可以防止两个 Redis 后台进程同时对磁盘进行大量的 I/O 操作。

  如果 BGSAVE 正在执行, 并且用户显示地调用 BGREWRITEAOF 命令, 那么服务器将向用户回复一个 OK 状态, 并告知用户, BGREWRITEAOF 已经被预定执行: 一旦 BGSAVE 执行完毕, BGREWRITEAOF 就会正式开始。 当 Redis 启动时, 如果 RDB 持久化和 AOF 持久化都被打开了, 那么程序会优先使用 AOF 文件来恢复数据集, 因为 AOF 文件所保存的数据通常是最完整的。

备份redis数据

  在阅读这个小节前, 请牢记下面这句话: 确保你的数据由完整的备份. 磁盘故障, 节点失效, 诸如此类的问题都可能让你的数据消失不见, 不进行备份是非常危险的。
  Redis 对于数据备份是非常友好的, 因为你可以在服务器运行的时候对 RDB 文件进行复制: RDB 文件一旦被创建, 就不会进行任何修改。 当服务器要创建一个新的 RDB 文件时, 它先将文件的内容保存在一个临时文件里面, 当临时文件写入完毕时, 程序才使用 rename(2) 原子地用临时文件替换原来的 RDB 文件。
  这也就是说, 无论何时, 复制 RDB 文件都是绝对安全的。

  • 创建一个定期任务(cron job), 每小时将一个 RDB 文件备份到一个文件夹, 并且每天将一个 RDB 文件备份到另一个文件夹。
  • 确保快照的备份都带有相应的日期和时间信息, 每次执行定期任务脚本时, 使用 find 命令来删除过期的快照: 比如说, 你可以保留最近 48 小时内的每小时快照, 还可以保留最近一两个月的每日快照。
  • 至少每天一次, 将 RDB 备份到你的数据中心之外, 或者至少是备份到你运行 Redis 服务器的物理机器之外。

容灾备份

Redis 的容灾备份基本上就是对数据进行备份, 并将这些备份传送到多个不同的外部数据中心。容灾备份可以在 Redis 运行并产生快照的主数据中心发生严重的问题时, 仍然让数据处于安全状态。
因为很多 Redis 用户都是创业者, 他们没有大把大把的钱可以浪费, 所以下面介绍的都是一些实用又便宜的容灾备份方法:

  • Amazon S3 ,以及其他类似 S3 的服务,是一个构建灾难备份系统的好地方。 最简单的方法就是将你的每小时或者每日 RDB 备份加密并传送到 S3 。 对数据的加密可以通过 gpg -c 命令来完成(对称加密模式)。 记得把你的密码放到几个不同的、安全的地方去(比如你可以把密码复制给你组织里最重要的人物)。 同时使用多个储存服务来保存数据文件,可以提升数据的安全性。
  • 传送快照可以使用 SCP 来完成(SSH 的组件)。 以下是简单并且安全的传送方法: 买一个离你的数据中心非常远的 VPS , 装上 SSH , 创建一个无口令的 SSH 客户端 key , 并将这个 key 添加到 VPS 的 authorized_keys 文件中, 这样就可以向这个 VPS 传送快照备份文件了。 为了达到最好的数据安全性,至少要从两个不同的提供商那里各购买一个 VPS 来进行数据容灾备份。
  • 需要注意的是, 这类容灾系统如果没有小心地进行处理的话, 是很容易失效的。最低限度下, 你应该在文件传送完毕之后, 检查所传送备份文件的体积和原始快照文件的体积是否相同。 如果你使用的是 VPS , 那么还可以通过比对文件的 SHA1 校验和来确认文件是否传送完整。

2、Redis的过期策略和内存淘汰机制

Redis的过期策略
Redis采用的是定期删除+过期删除策略。为什么不采用定时删除策略因为如果采用定时删除策略的话,需要用一个定时器来负责监视key,过期则自动删除。虽然内存及时释放,但是十分消耗CPU资源。在大并发请求下,CPU要将时间应用在处理请求,而不是删除key。定期删除+惰性删除是如何工作的 Redis每隔100ms随机抽取一部分key进行检查,如果过期则直接删除,这就是定期删除。如果定期删除没有检测到过期的key,就会采用惰性删除的策略,也就是说当访问一个key的时候,如果该key已经过期了,就会触发删除。这个时候如果部分过期的key定期删除没有删除掉,也没有及时访问,就会采用redis的内存淘汰策略进行删除。可以在redis.conf中进行配置:
maxmemory 4GB
maxmemory-policy allkeys-lru
当redis占用的内存达到maxmemory指定的内存的时候,redis就会根据maxmemory-policy指定的内存淘汰策略对内存进行删除。redis支持以下几种内存淘汰策略

  • valatile-lru 在设置了过期时间的键空间中选择最近最少使用的key进行删除。
  • allkeys-lru 在所有的键空间中选择最近最少使用的key进行删除。
  • volatile-lfu 在设置了过期时间的键空间中选择最近使用频率最少的key进行删除。
  • allkeys-lfu 在所有键空间中选择最近使用频率最少的key进行删除。
  • volatile-random 在设置了过期时间的键空间中随机进行删除。
  • allkeys-random 在所有键空间中随机进行删除。
  • volatile-ttl 在设置了过期时间的键空间中选择生命周期最短的key进行删除。
  • noevication 当达到最大内存的时候不进行删除,对于写命令直接返回错误。

七、Redis高可用(主从、哨兵、集群)

八、缓存击穿、缓存穿透、缓存雪崩

九、Java连接redis之jedis

十、Spring Boot使用Redis作为缓存

总结

提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

最近发表
标签列表