前言
Redis 是 Remote Dictionary Service 的简称,被称为远程字典服务;redis客户端和服务端是基于TCP建立网络通信的。
Redis 是内存数据库(保存在内存而不是磁盘),是目前市面上高性能的key-value数据库;底层的数据结构就是hash,因此查找数据的复杂度为O(1);
Redis属于非关系型数据库,用键值来存储。类似于哈希表数据结构。和MySQL这类关系型数据库是不一样的。
一、redis安装使用
安装
git clone https://gitee.com/mirrors/redis.git -b 6.2 cd redis make make test make install
默认安装在 /usr/local/bin
redis-server 是服务端程序
redis-cli 是客户端程序
启动
mkdir redis-data # 把redis文件夹下 redis.conf 拷贝到 redis-data # 修改 redis.conf # requirepass 修改密码 123456 # daemonize yes cd redis-data redis-server redis.conf # 通过 redis-cli 访问 redis-server redis-cli -h 127.0.0.1 -a 123456
二、redis结构
redis是key-value的结构
key是字符串
value有几种常用的数据结构,如string、list、hash、set、zset
字符串string: 是一个安全的二进制字符串;
双端队列 (链表)list:有序(插入有序);
散列表 hash:对顺序不关注,由(field,value)组成,其中field 是唯一的;
无序集合 set:对顺序不关注,里面的值都是唯一的;
有序集合 zset:对顺序是关注的,里面的值是唯一的;根据 member来确定唯一;根据 score 来确定有序;
字符串
字符串定义
redis中的字符串是一种动态字符串。在C语言中字符串是以’\0’结尾的字符串数组。但在redis中是自己构建一套简单动态字符串(simple dynamic string 简称SDS)。
sds优点:
- 降低获取字符串长度的时间
- 避免缓冲区溢出(增加字符串字符采用扩容再拼接。普通字符串增加字符串的字符由于地址连续会覆盖后面的字符串)
- 降低内存重分配次数(惰性空间释放和空间预分配) 二进制安全
redis源码中sds字符串数据结构:
struct __attribute__ ((__packed__)) sdshdr8 { uint8_t len; /* used */ uint8_t alloc; /* excluding the header and null terminator */ unsigned char flags; /* 3 lsb of type, 5 unused bits */ char buf[]; }; struct __attribute__ ((__packed__)) sdshdr16 { uint16_t len; /* used */ uint16_t alloc; /* excluding the header and null terminator */ unsigned char flags; /* 3 lsb of type, 5 unused bits */ char buf[]; }; struct __attribute__ ((__packed__)) sdshdr32 { uint32_t len; /* used */ uint32_t alloc; /* excluding the header and null terminator */ unsigned char flags; /* 3 lsb of type, 5 unused bits */ char buf[]; };
sds中字符串分割是以长度len进行分割,不像C语言中字符串用\0做分割符,这样可以保存更多形式的数据。如文本数据,图片、音频、压缩文件等任意格式的二进制数据。
char buf[];是一个柔性数组。使用柔性数组的好处有两个:
1.不需要另起free,结构体free了柔性数组的空间就会释放。
2.初始化不占用空间。
3.申请的内存可以减少内存碎片化。
柔性数组详细内容参考什么是柔性数组
字符串特点
字符串是动态字符串,字符串长度小于1M 时,加倍扩容;超过 1M 每次只多扩 1M;字符串最大长度为 512M;
redis字符串是二进制安全字符串;可以存储图片,二进制协议等二进制数据;
字符串基础命令
# 设置 key 的 value 值 SET key val # 获取 key 的 value GET key # 执行原子加一的操作 INCR key # 执行原子加一个整数的操作 INCRBY key increment # 执行原子减一的操作 DECR key # 执行原子减一个整数的操作 DECRBY key decrement # 如果key不存在,这种情况下等同SET命令。 当key存在时,什 么也不做 # SETNX 将key设置值为value,如果key不存在,这种情况下等同SET命令。 当key存在时,什么也不做。SETNX是”SET if Not eXists”的简写。 SETNX key value # 删除 key val 键值对 DEL key # 设置或者清空key的value(字符串)在offset处的bit值。 SETBIT key offset value # 返回key对应的string在offset处的bit值 GETBIT key offset # 统计字符串被设置为1的bit数. BITCOUNT key
存储结构
字符串长度小于等于 20 且能转成整数,则使用 int 存储;
字符串长度小于等于 44,则使用 embstr 存储;
字符串长度大于 44,则使用 raw 存储;
应用场景
对象存储 累加器 分布式锁 位运算
双端队列 (链表)list
双向链表实现,列表首尾操作(删除和增加)时间复杂度 O(1) ;查找中间元素时间复杂度为O(n) ;
基础命令
# 从队列的左侧入队一个或多个元素 LPUSH key value [value ...] # 从队列的左侧弹出一个元素 LPOP key # 从队列的右侧入队一个或多个元素 RPUSH key value [value ...] # 从队列的右侧弹出一个元素 RPOP key # 返回从队列的 start 和 end 之间的元素 0, 1 2 负索引 LRANGE key start end # 从存于 key 的列表里移除前 count 次出现的值为 value 的元素 # list 没有去重功能 hash set zset LREM key count value # 它是 RPOP 的阻塞版本,因为这个命令会在给定list无法弹出任何元素的时候阻塞连接 BRPOP key timeout # 超时时间 + 延时队列
应用场景
栈
队列
阻塞队列
异步消息队列
获取固定窗口记录
hash
散列表,unordered_map 通过 key 快速索引 value;
基础命令
# 获取 key 对应 hash 中的 field 对应的值 HGET key field # 设置 key 对应 hash 中的 field 对应的值 HSET key field value # 设置多个hash键值对 HMSET key field1 value1 field2 value2 ... fieldn valuen # 获取多个field的值 HMGET key field1 field2 ... fieldn # 给 key 对应 hash 中的 field 对应的值加一个整数值 HINCRBY key field increment # 获取 key 对应的 hash 有多少个键值对 HLEN key # 删除 key 对应的 hash 的键值对,该键为field HDEL key field
存储结构
节点数量大于 512(hash-max-ziplist-entries) 或所有字符串长度大于> 64(hash-max-ziplist-value),则使用 dict 实现;
节点数量小于等于 512 且有一个字符串长度小于 64,则使用ziplist 实现;
应用场景
存储对象
购物车
SET
集合;用来存储唯一性字段,不要求有序;
基础命令
# 添加一个或多个指定的member元素到集合的 key中 SADD key member [member ...] # 计算集合元素个数 SCARD key # SMEMBERS key SMEMBERS key # 返回成员 member 是否是存储的集合 key的成员 SISMEMBER key member # 随机返回key集合中的一个或者多个元素,不删除这些元素 SRANDMEMBER key [count] # 从存储在key的集合中移除并返回一个或多个随机元素 SPOP key [count] # 返回一个集合与给定集合的差集的元素 SDIFF key [key ...] # 返回指定所有的集合的成员的交集 SINTER key [key ...] # 返回给定的多个集合的并集中的所有成员 SUNION key [key ...]
存储结构
元素都为整数且节点数量小于等于 512(set-max-intsetentries),则使用整数数组存储;
元素当中有一个不是整数或者节点数量大于 512,则使用字典存储;
应用场景
抽奖
共同关注
推荐好友
zset
有序集合;用来实现排行榜;它是一个有序唯一;
基础命令
# 添加到键为key有序集合(sorted set)里面 ZADD key [NX|XX] [CH] [INCR] score member [score member ...] # 从键为key有序集合中删除 member 的键值对 ZREM key member [member ...] # 返回有序集key中,成员member的score值 ZSCORE key member # 为有序集key的成员member的score值加上增量increment ZINCRBY key increment member # 返回key的有序集元素个数 ZCARD key # 返回有序集key中成员member的排名 ZRANK key member # 返回存储在有序集合key中的指定范围的元素 order by id limit 1,100 ZRANGE key start stop [WITHSCORES] # 返回有序集key中,指定区间内的成员(逆序) ZREVRANGE key start stop [WITHSCORES]
存储结构
节点数量大于 128 或者有一个字符串长度大于 64,则使用跳表 (skiplist);
节点数量小于等于 128(zset-max-ziplist-entries)且所有字符串长度小于等于 64(zset-max-ziplist-value),则使用ziplist 存储;
数据少的时候,节省空间;O(n)
数量多的时候,提升访问性能;O(1)或者O(logn)
应用场景
百度热榜
延时队列
分布式定时器
时间窗口限流