参照
Redis详解(一)------ redis的简介与安装
Redis详解(二)------ redis的配置文件介绍
Redis详解(三)------ redis的六大数据类型详细用法
Redis详解(四)------ redis的底层数据结构
Redis详解(五)------ redis的五大数据类型实现原理
Redis设计与实现
安装和启动
redis-server:Redis服务器
- /etc/redis/redis.conf
redis-cli:Redis命令行客户端
redis-benchmark:Redis性能测试工具
redis-check-aof:AOF文件修复工具
redis-check-rdb:RDB文件检查工具
配置文件redis.conf
INCLUDES
MODULES
- loadmodule 引入自定义模块
NETWORK
-
bind
-
port
-
timeout
- 客户端连接时的超时时间,单位为秒
-
tcp-keepalive
- 周期性的使用SO_KEEPALIVE检测客户端是否还处于健康状态,避免服务器一直阻塞
GENERAL
-
daemonize
-
pidfile
-
loglevel
- debug
- verbose
- notice
- warning
-
logfile
-
databases
- select 命令选择一个不同的数据库
SNAPSHOTTING
-
持久化操作
-
.save 300 10
- 表示300 秒内如果至少有 10 个 key 的值变化,则保存
-
stop-writes-on-bgsave-error
- 默认值为yes
-
rdbcompression
-
默认值是yes 压缩存储
- LZF算法进行压缩
-
-
rdbchecksum
- 默认值是yes 使用CRC64算法来进行数据校验
-
dbfilename
- 快照的文件名,默认是 dump.rdb
-
dir
REPLICATION
-
slave-serve-stale-data
-
当一个 slave 与 master 失去联系,
或者复制正在进行的时候,是否应答客户端请求 -
默认值为yes
- slave 仍然会应答客户端请求
- 返回的数据可能是过时,或者是空的
-
no
- info he salveof 操作之外
- 返回一个 “SYNC with master in progress” 的错误
-
-
slave-read-only
-
默认值为yes
- Slave是否为只读Redis
-
-
repl-diskless-sync
-
默认值为no
- 不使用无硬盘复制功能
-
-
repl-diskless-sync-delay
-
当启用无硬盘备份
-
服务器等待一段时间后才会通过套接字
向从站传送RDB文件 -
默认5秒
- 等待时间是可配置的
-
-
repl-disable-tcp-nodelay
-
默认值为no
- 同步之后是否禁用从站上的TCP_NODELAY
-
-
repl-ping-slave-period
- 节点超时时间
SECURITY
-
rename-command 命令重命名
-
flushdb
-
flushall
- rename-command FLUSHALL “”
-
config
-
keys
-
-
requirepass
CLIENTS
-
maxclients
-
客户端最大并发连接数,默认0无限制
-
当客户端连接数到达限制时
- redis会关闭新的连接并向客户端返回max number of clients reached错误
-
MEMORY MANAGEMENT
-
maxmemory
- Redis的最大内存,如果设置为0 。表示不作限制
-
maxmemory-policy
-
内存清除策略
-
volatile-lru 利用LRU算法移除设置过过期时间的key (LRU:最近使用 Least Recently Used )
-
allkeys-lru 利用LRU算法移除任何key
-
volatile-random 移除设置过过期时间的随机key
-
allkeys-random 移除随机key
-
volatile-ttl 移除即将过期的key(minor TTL)
-
noeviction noeviction 不移除任何key
- 默认
-
APPEND ONLY MODE
-
appendonly
-
默认no,使用rdb方式持久化
- redis如果中途宕机,会导致可能有几分钟的数据丢
-
Append Only File是另一种持久化方式
- 每次写入的数据在接收后都写入appendonly.aof文件
-
-
appendfilename
- aof文件名,默认是"appendonly.aof"
-
appendfsync
- aof持久化策略的配置
- no 表示不执行fsync,由操作系统保证数据同步到磁盘,速度最快
- always 表示每次写入都执行fsync,以保证数据同步到磁盘
- everysec 表示每秒执行一次fsync,可能会导致丢失这1s数据
-
no-appendfsync-on-rewrite
-
默认设置为no
- aof重写或者写入rdb文件的时候 执行fsync
- 对持久化特性来说这是更安全的选择
-
yes
- rewrite期间对新写操作不fsync,
暂时存在内存中,等rewrite完成后再写入 - Linux的默认fsync策略是30秒
可能丢失30秒数据
- rewrite期间对新写操作不fsync,
-
-
auto-aof-rewrite-percentage
-
即当aof文件增长到一定大小的时候,
Redis能够调用bgrewriteaof对日志文件进行重写 -
设置为100
- 二倍
-
-
auto-aof-rewrite-min-size
- 重写的最小aof文件大小
-
aof-load-truncated
-
redis宕机或者异常终止不会造成尾部不完整现象,可以选择让redis退出
-
默认值为 yes
- 当截断的aof文件被导入的时候,
会自动发布一个log给客户端然后load
- 当截断的aof文件被导入的时候,
-
no
- 用户必须手动redis-check-aof修复AOF文件才可以。默认值为 yes
-
LUA SCRIPTING
-
lua-time-limit
-
默认值为5000
- 一个lua脚本执行的最大时间,单位为ms
-
REDIS CLUSTE
-
cluster-enabled
- 集群开关,默认是不开启集群模式
-
cluster-config-file
-
集群配置文件的名称
-
这个配置文件有Redis生成并更新
- 默认配置为nodes-6379.conf
-
-
cluster-node-timeout
- 集群节点超时毫秒数 15000
-
cluster-slave-validity-factor
-
该参数用来判断slave节点与master断线的时间是否过长
-
故障转移的时候,全部slave都会请求申请为master
-
配置值为10
- 表示对于断开时间比较长的slave排除掉,
防止 数据过于陈旧
- 表示对于断开时间比较长的slave排除掉,
-
(node-timeout * slave-validity-factor) + repl-ping-slave-period
- 30*10+10
-
-
cluster-migration-barrier
-
配置值为1
- master的slave数量大于该值,slave才能迁移到其他孤立master上
-
-
cluster-require-full-coverage
-
默认为yes,集群全部的slot有节点负责,集群状态才为ok
-
no 不建议
- 可以在slot没有全部分配的时候提供服务
-
六大数据类型
string
-
介绍
-
string 类型是二进制安全的
- 可以包含任何数据,比如图片或者序列化的对象
-
一个 redis 中字符串 value 最多可以是 512M
-
-
命令
-
set
-
get
- set 如果已存在,覆盖,无视类型
-
-
mset
-
mget
- 能够极大的提高操作效率
-
-
setex
-
设置值和超时
- 原子操作
-
-
setnx
-
当key不存在时,成功
-
如果存在,不做任何操作
-
Redis单线程的特点
- 可以用于实现分布式锁
-
-
ttl
-
自增自减操作
-
incr
-
decr
- incr 如果不存在,先赋值0,再执行incr
-
-
incrby
- decrby
-
-
-
使用场景
-
计数
- 统计系统的在线人数
- 不用考虑并发造成计数不准的问题,
通过 incrby 命令,我们可以正确的得到我们想要的结果
-
限制次数
-
登录次数校验
- 错误超过三次5分钟内就不让登录了
- 每次登录设置key自增一次
- 并设置该key的过期时间为5分钟后
- 每次登录检查一下该key的值来进行限制登录
-
秒杀接口限流
-
-
hash
-
键值对集合
-
key /field
-
value
- (key-value)
-
类似Map<String,Map<String,Object>> 集合
-
-
命令
-
hset
-
hget
-
hdel
- hexits
-
-
-
hmget
- hmset
-
hincrby
-
hgetall
-
hkeys
-
hlen
- hvals
-
-
-
-
使用场景
- 查询的时间复杂度是O(1),用于缓存一些信息
list
-
是简单的字符串列表
- 添加一个元素到列表的头部(左边)或者尾部(右边)
- 底层实际上是个链表
-
特点
- 有序
- 可以重复
-
命令
-
lpush
- 插入到表头
- 如果不是列表类型,报错
- 要求列表key要存在
-
lpop
-
rpush
- rpop
-
-
rpoplpush
- 将source列表最后一个元素弹出 返回
- 将source弹出的元素插入到destinate列表的表头
- 原子
-
lindex
-
llen
-
lrange
- start stop区间
-
ltrim
- start stop区间
-
lset
- 依据index
-
lrem
-
依据count 查询
- 0 全部移除
-
0 从左依次移除指定数量
- <0 从右依次移除指定数量
-
-
-
使用场景
-
栈
- 通过命令 lpush+lpop
-
队列
- 命令 lpush+rpop
-
有限集合
- 命令 lpush+ltrim
-
消息队列
- 命令 lpush+brpop
-
set
-
set 是 string 类型的无序集合
-
特点
- 无序
- 不可重复
-
命令
-
sadd
- srem
-
scard
-
smenbers
- sismenber
-
-
创建set1 set2
- sadd s1 1 2 3
- sadd s2 4 5 6
-
sdiff
-
sdiff set1 set2
- 1 2 3
-
-
sinter
-
sinter set1 set2
- empty
-
-
sunion
-
sunion set1 set2
- 1 2 3 4 5 6
-
-
smove
-
smove set1 set2 1
- 把1从set1移到set2,set1中删除
-
smove set1 set2 8
- 8不在set1里面 不做任何事情 返回0
-
-
spop
-
spop set1
- 移除并返回set1里面随机元素
-
spop set1 5
- 3>set1个个数 全部返回
- 0<count<len 返回count个元素,元素不相同
- count <0 返回个数为count绝对值的元素 元素可能重复
-
-
srandmember
- 相比spop 返回一个随机元素 不移除
-
sunionstore
-
sdiffstore
-
sinterstore
-
-
场景
-
集合的交并集特性
社交领域的相关业务- 我们可以很方便的求出多个用户的共同好友,
共同感兴趣的领域等
- 我们可以很方便的求出多个用户的共同好友,
-
zset
-
sorted set 有序集合)
- 排序依据add时的 score
-
特点
- 有序
- 不可重复
-
命令
-
zadd
- zrem
-
zscard
-
zcount
- score>=min且score<=max
-
zrange
- 成员位置按照score从小到大排序
- -1 表示最后一个元素
-
zrank
-
返回元素在集合中的排名
- 按从小到大排序
-
-
zrevrank
-
返回元素在集合中的排名
- 按从大到小排序
-
-
zremrangebyrank
- rank>=start且rank<=end
-
zremrangebyscore
- score>=min且score<=max
-
-
使用场景
-
社交领域的相关业务
-
利用zset 的有序特性
- 排行榜
-
stream
-
介绍
-
Redis Stream 的内部,其实也是一个队列,每一个不同的key,对应的是不同的队列
-
每个队列的元素,也就是消息,都有一个msgid
- 需要保证msgid是严格递增的
-
消息是默认持久化的,即便是Redis重启,也能够读取到消息
-
stream可以做到多播的呢
-
消费者Group
- 不同的消费组,可以消费同一个消息
- 每个消费组,都维护一个Idx下标
- 每次进行消费,都会更新一下这个下标,
往后面一位进行偏移
-
-
系统相关命令
-
client list
- config get
-
debug object key
- dbsize
-
flushall
-
flushdb id
- select
-
-
info
-
lastsave
- minitor
-
-
BGSAVE
- BGREWRITEAOF
key相关命令
-
del
-
ttl
-
pttl
- type
-
-
-
exits
- randomkey
-
keys
-
expire
-
expireat
- persis
-
-
migtate
- move
-
rename
- 会覆盖
-
OBJECT ENCODING key
-
set k1 str
- 显示类型 embstr
-
set k2 123
- 显示类型 int
-
6种底层数据结构
Redis 是用 C 语言写的
SDS
-
简单动态字符串(simple dynamic string,SDS) 不是简单的C 字符串
-
结构
-
struct sdshdr
-
int len;
-
int free
-
char buf[];
- ‘\0’
-
-
-
特性
-
常数复杂度获取字符串长度
- 读取 len 属性,时间复杂度为 O(1)
-
杜绝缓冲区溢出
- 依据len空间扩展,不会出现缓冲区溢出
-
减少修改字符串的内存重新分配次数
-
空间预分配策略
- 对字符串进行空间扩展的时候
- 扩展的内存比实际需要的多
- 可以减少连续执行字符串增长操作所需的内存重分配次数
-
惰性空间释放策略
- 对字符串进行缩短操作时
- 不立即使用内存重新分配来回收缩短后多余的字节
- 使用 free 属性将这些字节的数量记录下来,等待后续使用
-
-
二进制安全
-
兼容部分 C 字符串函数
-
list
-
链表
-
结构
-
listNode
- struct listNode *prev;
- struct listNode *next;
- void *value;
-
list
-
listNode *head;
-
listNode *tail;
-
unsigned long len;
-
void (*free) (void *ptr);
- 节点值复制函数
-
void (*free) (void *ptr);
- 节点值释放函数
-
int (*match) (void *ptr,void *key);
- 节点值对比函数
-
-
-
特性
-
双端
- 链表具有前置节点和后置节点的引用,获取这两个节点时间复杂度都为O(1)
-
无环
- 表头节点的 prev 指针和表尾节点的 next 指针都指向 NULL,对链表的访问都是以 NULL 结束。
-
带链表长度计数器
- 通过 len 属性获取链表长度的时间复杂度为 O(1)
-
多态
- 链表节点使用 void* 指针来保存节点值,可以保存各种不同类型的值。
-
dictht
-
字典
- 符号表或者关联数组、或映射(map)
- 是一种用于保存键值对的抽象数据结构
- 字典中的每一个键 key 都是唯一的,通过 key 可以对值来进行查找或修改
- Redis 的字典使用哈希表作为底层实现
-
结构
-
dictht
-
dictEntry **table;
- 哈希表数组
-
unsigned long size;
- 哈希表大小
-
unsigned long sizemask;
- 哈希表大小掩码,用于计算索引值
-
unsigned long used;
-
哈希表已有节点的数量
- size 4,有2个节点dictEntry
-
-
-
dictEntry
-
void *key;
- 键
-
union{
void *val;
uint64_tu64;
int64_ts64;
}v-
值
- 值可以是一个指针,也可以是uint64_t整数,也可以是int64_t整数
-
-
struct dictEntry *next;
-
指向下一个哈希表节点,形成链表
-
hash冲突
- 开放地址法
- 这里用的是 链地址法
-
-
-
-
特性
-
哈希算法
-
解决哈希冲突
-
扩容和收缩
-
rerehash(重新散列)
-
扩展
- 基于原哈希表创建一个大小等于 ht[0].used*2n 的哈希表
- 已使用的空间扩大一倍创建另一个哈希表
-
收缩
- 每次收缩是根据已使用空间缩小一倍创建一个新的哈希表
-
-
触发扩容的条件
-
载因子 = 哈希表已保存节点数量 / 哈希表大小
-
没有执行 BGSAVE 命令或者 BGREWRITEAOF 命令
- 负载因子大于等于1
-
前正在执行 BGSAVE 命令或者 BGREWRITEAOF 命令
- 负载因子大于等于5
-
-
渐近式 rehash
- 扩容和收缩操作不是一次性、集中式完成的,而是分多次、渐进式完成的
- 字典的删除查找更新等操作可能会在两个哈希表上进行
- 增加操作,一定是在新的哈希表上进行的。
-
zskiplist
-
跳跃表
- 跳跃表(skiplist)是一种有序数据结构,
它通过在每个节点中维持多个指向其它节点的指针,
从而达到快速访问节点的目的
- 跳跃表(skiplist)是一种有序数据结构,
-
结构
-
zskiplistNode
-
跳跃表节点
-
zskiplistLevel{} level[]
-
struct zskiplistNode *forward;
- 前进指针
-
unsigned int span;
- 跨度
-
-
truct zskiplistNode *backward;
- 后退指针
-
double score;
- 分值
-
robj *obj;
- 成员对象
-
-
zskiplist
-
多个跳跃表节点构成一个跳跃表
-
structz skiplistNode *header, *tail;
- 表头节点和表尾节点
-
unsigned long length;
- 节点的数量
-
int level;
- //表中层数最大的节点的层数
-
-
-
性质
-
由很多层结构组成
-
每一层都是一个有序的链表,
排列顺序为由高层到底层- 都至少包含两个链表节点,
分别是前面的head节点和后面的nil节点
- 都至少包含两个链表节点,
-
最底层的链表包含了所有的元素
-
上一层的元素是当前层的元素的子集
-
链表中的每个节点都包含两个指针
- 一个指向同一层的下一个链表节点
- 另一个指向下一层的同一个链表节点
-
-
功能
-
搜索
- 从最高层的链表节点开始
-
插入
-
首先确定插入的层数
-
抛一枚硬币方法
- 正面就累加,直到遇见反面为止
-
-
则需要将新元素插入到从底层到k层
-
-
删除
- 各个层中找到包含指定值的节点,然后将节点从链表中删除即可
- 如果删除以后只剩下头尾两个节点,则删除这一层
-
intset
-
整数集合 保存整数值的集合抽象数据类型
- 可以保存类型为int16_t、int32_t 或者int64_t 的整数值
- 并且保证集合中不会出现重复元素
-
结构
-
uint32_t encoding;
-
uint32_t length;
-
int8_t contents[];
-
保存元素的数组
- 按照从小到大的顺序排列
- 并且不包含任何重复项
- 由真正类型有 encoding 来决定
-
-
-
特性
-
升级
- 当新增的元素类型比原集合元素类型的长度要大时
- 升级能极大地节省内存
-
降级
- 整数集合不支持降级操作
- 一旦对数组进行了升级,编码就会一直保持升级后的状态
-
ziplist
-
压缩列表(ziplist)是Redis为了节省内存而开发的
-
结构
-
压缩表
-
zlbytes
-
zltail
-
zllen
- 节点数量
-
entry1 entry2…
- 节点列表
-
zlend
- 0xFF
-
-
压缩表节点
-
previous_entry_ength
- 记录压缩列表前一个字节的长度
- 当前节点位置减去上一个节点的长度即得到上一个节点的起始位置
- 压缩列表可以从尾部向头部遍历。这么做很有效地减少了内存的浪费
-
encoding
-
类型一共有两种
- 一种字节数组
- 一种是整数
-
-
content
- 节点内容类型和长度由encoding决定
-
-
总结
-
简单字符串SDS
-
链表可以保存各种不同类型的值
- 除了用作列表键
- 还在发布与订阅、慢查询、监视器等方面发挥作用
-
字典底层使用哈希表实现
-
每个字典通常有两个哈希表
- 一个平时使用
- 另一个用于rehash时使用
-
使用链地址法解决哈希冲突
-
-
跳跃表通常是有序集合的底层实现之一,表中的节点按照分值大小进行排序
-
整数集合是集合键的底层实现之一,底层由数组构成,升级特性能尽可能的节省内存。
-
压缩列表是Redis为节省内存而开发的顺序型数据结构,通常作为列表键和哈希键的底层实现之一。
数据类型-数据结构
简介
-
Redis中,并没有直接使用这些数据结构来实现键值对数据库
-
而是基于这些数据结构创建了一个对象系统(五大数据类型)
-
每一种数据类型都至少用到了一种数据结构
-
通过这五种不同类型的对象
- Redis可以在执行命令之前,根据对象的类型判断一个对象是否可以执行给定的命令
- 而且可以针对不同的场景,为对象设置多种不同的数据结构,从而优化对象在不同场景下的使用效率。
redisObject
-
每次在Redis数据库中创建一个键值对时,至少会创建两个对象,一个是键对象,一个是值对象
-
而Redis中的每个对象都是由 redisObject 结构来表示
-
结构
-
unsigned type:4;
- 类型
-
unsigned encoding:4;
- 编码
-
void *ptr;
- 指向底层数据结构的指针
-
int refcount;
-
引用计数
-
内存回收
- 创建一个新对象,属性 refcount 初始化为1
- 对象被一个新程序使用,属性 refcount 加 1
- 对象不再被一个程序使用,属性 refcount 减 1
- 当对象的引用计数值变为 0 时,对象所占用的内存就会被释放。
-
内存共享
-
set k1 100,
- set k2 100,
-
目前只支持整数值的字符串对象
-
将数据库键的值指针指向一个现有值的对象
-
将被共享的值对象引用refcount 加 1
-
-
-
unsigned lru:22;
-
记录最后一次被程序访问的时间
-
对象的空转时长
- OBJECT IDLETIME 命令可以打印给定键的空转时长
- 通过将当前时间减去值对象的 lru 时间计算得到
-
可以配合前面内存回收配置使用
-
-
-
键总是一个字符串对象
-
而值可以是字符串、列表、集合等对象
-
我们说一个键为集合键时,表示的是这个键对应的值为集合对象。
type
-
type key
- 判断对象类型
-
string
- int
- embstr
- raw
-
list
-
ziplist(压缩列表)
-
编码转换
-
列表保存元素个数小于512个
- list-max-ziplist-entries
-
每个元素长度小于64字节
- list-max-ziplist-value
-
-
-
rpush numbers 1 “three” 5
-
linkedlist(双端链表)
-
-
hash
-
ziplist
-
新增的键值对是保存到压缩列表的表尾
-
编码转换
-
列表保存元素个数小于512个
- set-max-intset-entries
-
每个元素长度小于64字节
-
-
-
hset profile name “Tom”
- hset profile age 25
-
hashtable
- 底层使用字典数据结构
- 哈希对象中的每个键值对都使用一个字典键值对
-
-
set
-
intset
-
集合对象包含的所有元素都被保存在整数集合中
-
编码转换
-
集合对象中所有元素都是整数
-
集合对象所有元素数量不超过512
- set-max-intset-entries
-
-
-
SADD Dfruits “apple” “banana” “cherry”
-
hashtable
-
字典作为底层实现
- 字典的每个键都是一个字符串对象
- 字典的值则全部设置为 null
- 可以对比java HashSet 与HashTable
-
-
-
zset
-
有序集合对象是有序的
- 与列表使用索引下标作为排序依据不同,有序集合为每个元素设置一个分数(score)作为排序依据
-
ziplist
-
每个集合元素使用两个紧挨在一起的压缩列表节点来保存
-
压缩列表内的集合元素按分值从小到大的顺序进行排列
-
编码转换
-
保存的元素数量小于128
- zset-max-ziplist-entries
-
保存的所有元素长度都小于64字节
- zset-max-ziplist-value
-
-
-
ZADD price 8.5 apple 5.0 banana 6.0 cherry
-
skiplist+dict
-
一个 zset 结构同时包含一个字典和一个跳跃表
-
dict
- 字典的键保存元素的值
- 字典的值则保存元素的分值
-
skiplis
- 跳跃表节点的 object 属性保存元素的成员
- 跳跃表节点的 score 属性保存元素的分值
-
这两种数据结构会通过指针来共享相同元素的成员和分值
-
假如我们单独使用 字典
- 虽然能以 O(1) 的时间复杂度查找成员的分值
- 字典是以无序的方式来保存集合元素,
所以每次进行范围操作的时候都要进行排序
-
假如我们单独使用跳跃表来实现
- 虽然能执行范围操作
- 但是查找操作有 O(1)的复杂度变为了O(logN)。
-
-
encoding
-
OBJECT ENCODING key
- 查看值对象的编码:
-
int
- 整数类型
-
embstr
- embstr编码的简单字符串
-
raw
- 简单动态字符串
-
ht
- 字典
-
linkedlist
- 双端链表
-
ziplist
- 压缩列表
-
intset
- 整数集合
-
skiplist
- 跳跃表和字典
五大数据类型 应用场景
string
-
string 类型是二进制安全的,可以用来存放图片,视频等内容
-
另外由于Redis的高性能读写功能,而string类型的value也可以是数字,可以用作计数器(INCR,DECR)
- 比如分布式环境中统计系统的在线人数,秒杀等
- 登录时密码输入失败次数限制
hash
-
value 存放的是键值对 查询速度快
- 比如可以做单点登录存放用户信息
list
- 栈
- 队列
- 有限集合
- 可以实现简单的消息队列
- 另外可以利用lrange命令,做基于redis的分页功能
set
-
由于底层是字典实现的,查找元素特别快
-
另外set 数据类型不允许重复,
利用这两个特性我们可以进行全局去重- 比如在用户注册模块,判断用户名是否注册
-
另外就是利用交集、并集、差集等操作
- 可以计算共同喜好,全部的喜好,自己独有的喜好等 社交领域功能
zset
-
有序的集合,可以做范围查找
- 排行榜应用,取 TOP N 操作等
XMind - Trial Version