Redis官网:http://doc.redisfans.com/
Redis键(key)基础命令
key * | 查看当前库中所有的key |
---|---|
exists key | 判断某个key是否存在 |
type key | 查看你的key是什么类型 |
del key | 删除指定的key数据 |
unlink key | 据value删除非阻塞删除,仅仅将keys从keyspace元数据中删除,真正的删除会在后续异步中操作 |
expire key 10 | 为指定的key设置有效期10秒 |
ttl key | 查看指定的key还有多少秒过期,-1:表示永不过期,-2:表示已过期 |
select dbindex | 换数据库【0-15】,默认为0 |
dbsize | 查看当前数据库key的数量 |
flushdb | 清空当前库 |
flushall | 通杀全部库 |
Redis 中的 8 种常用数据类型
-
5 种基础数据类型:String(字符串)、List(列表)、Set(集合)、Hash(散列)、Zset(有序集合)。
-
3 种特殊数据类型:HyperLogLog(基数统计)、Bitmap(位图)、Geospatial(地理位置)。
5 种基础数据类型
数据类型 | 说明 |
---|---|
String(字符串) | 一种二进制安全的数据类型,可以用来存储任何类型的数据比如字符串、整数、浮点数、图片(图片的 base64 编码或者解码或者图片的路径)、序列化后的对象。 |
List(列表) | Redis 的 List 的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销。 |
Set(集合) | 无序集合,集合中的元素没有先后顺序但都唯一,有点类似于 Java 中的 HashSet 。 |
Zset(有序集合) | 和 Set 相比,Sorted Set 增加了一个权重参数 score ,使得集合中的元素能够按 score 进行有序排列,还可以通过 score 的范围来获取元素的列表。有点像是 Java 中 HashMap 和 TreeSet 的结合体。 |
Hash(散列) | 一个 String 类型的 field-value(键值对) 的映射表,特别适合用于存储对象,后续操作的时候,你可以直接修改这个对象中的某些字段的值。 |
String(字符串)
String是Redis最基本的类型,可以理解成与Memcached一模一样的类型,一个key对应一个value。String类型是二进制安全的。意味着Redis的string可以包含任何数据。比如jpg图片或者序列化的对象。String类型是Redis最基本的数据类型,一个Redis中字符串value最多可以是512M。
-
数据结构
-
常用命令
set <key> <value>
|
添加键值对
|
---|---|
get <key>
|
获取值
|
append <key> <value>
|
追价值
|
strlen <key>
|
获取值的长度
|
setnx <key> <value>
|
key不存在时,设置key的值
|
incr <key>
|
原子递增1
|
decr <key>
|
原子递减1
|
incrby/decrby <key> <步长>
|
递增或者递减指定的数字
|
mset <key1> <value1> <key2> <value2> ...
|
同时设置多个key-value
|
mget <key1> <key2> ...
|
获取多个key对应的值
|
msetnx <key1> <value1> <key2> <value2> ...
|
当多个key都不存在时,则设置成功
|
getrange key start end
|
获取值的范围,类似java中的substring
|
setrange <key> <起始位置> <value>
|
覆盖指定位置的值
|
setex <key> <过期时间(秒)> <value>
|
设置键值&过期时间(秒)
|
getset <key> <value>
|
以新换旧,设置新值同时返回旧值
|
-
应用场景
1、需要存储常规数据的场景
- 举例:缓存 Session、Token、图片地址、序列化后的对象(相比较于 Hash 存储更节省内存)。
- 相关命令:SET、GET。
2、需要计数的场景
- 举例:用户单位时间的请求数(简单限流可以用到)、页面单位时间的访问数。
- 相关命令:SET、GET、INCR、DECR。
3、分布式锁
利用SETNX key value命令可以实现一个最简易的分布式锁(存在一些缺陷,通常不建议这样实现分布式锁)。
List(列表)
-
数据结构
redis将链表和ziplist结合起来组成了quicklist。也就是将多个ziplist使用双向指针串起来使用,这样既满足了快速的插入删除性能,又不会出现太大的空间冗余。
-
常用命令
lpush/rpush <key1> <value1> <key2> <value2> ...
|
从左边或者右边插入一个或多个值
|
---|---|
lrange <key> <star> <stop>
|
从列表左边获取指定范围内的值
|
lpop/rpop <key> <count>
|
从左边或者右边弹出多个元素
|
rpoplpush source destination
|
从一个列表右边弹出一个元素放到另外一个列表中
|
lindex key index
|
获取指定索引位置的元素(从左到右)
|
llen key
|
获得列表长度
|
linsert <key> before|after <value> <newvalue>
|
在某个值的前或者后面插入一个值
|
LREM key count value
|
删除指定数量的某个元素
|
lset <key> <index> <value>
|
替换指定位置的值
|
-
应用场景
1、信息流展示
- 举例:最新文章、最新动态。
- 相关命令:LPUSH、LRANGE。
2、消息队列
List 可以用来做消息队列,只是功能过于简单且存在很多缺陷,不建议这样做。相对来说,Redis 5.0 新增加的一个数据结构 Stream 更适合做消息队列一些,只是功能依然非常简陋。和专业的消息队列相比,还是有很多欠缺的地方比如消息丢失和堆积问题不好解决。
Set(集合)
-
数据结构
set数据结构是字典,字典是用hash表实现的。
Java中的HashSet的内部实现使用HashMap,只不过所有的value都指向同一个对象。
Redis的set结构也是一样的,它的内部也使用hash结构,所有的value都指向同一个内部值。
-
常用命令
sadd <key> <value1> <value2> ...
|
添加一个或多个元素
|
---|---|
smembers <key>
|
取出所有元素
|
sismember <key> <value>
|
判断集合中是否有某个值
|
scard <key>
|
返回集合中元素的个数
|
srem key member [member ...]
|
删除多个元素
|
spop <key> <count>
|
随机弹出多个值
|
srandmember <key> <count>
|
随机获取多个元素,不会从集合中删除
|
smove <source> <destination> member
|
将某个原创从一个集合移动到另一个集合
|
sinter key [key ...]
|
取多个集合的交集
|
sinterstore destination key [key ...]
|
将多个集合的交集放到一个新的集合中
|
sunion key [key ...]
|
取多个集合的并集,自动去重
|
sinterstore destination key [key ...]
|
将多个集合的并集放到一个新的集合中
|
SDIFF key [key ...]
|
取多个集合的差集
|
sdiffstore destination key [key ...]
|
将多个集合的差集放到一个新的集合中
|
-
应用场景
1、需要存放的数据不能重复的场景
- 举例:网站 UV 统计(数据量巨大的场景还是 HyperLogLog更适合一些)、文章点赞、动态点赞等场景。
- 相关命令:SCARD(获取集合数量) 。
2、需要获取多个数据源交集、并集和差集的场景
- 举例:共同好友(交集)、共同粉丝(交集)、共同关注(交集)、好友推荐(差集)、音乐推荐(差集)、订阅号推荐(差集+交集) 等场景。
- 相关命令:SINTER(交集)、SINTERSTORE (交集)、SUNION (并集)、SUNIONSTORE(并集)、SDIFF(差集)、SDIFFSTORE (差集)。
3、需要随机获取数据源中的元素的场景、
- 举例:抽奖系统、随机点名等场景。
- 相关命令:SPOP(随机获取集合中的元素并移除,适合不允许重复中奖的场景)、SRANDMEMBER(随机获取集合中的元素,适合允许重复中奖的场景)。
ZSet(有序集合)
redis有序集合zset与普通集合set非常相似,是一个没有重复元素的字符串集合。 不同之处是有序集合的每个成员都关联了一个评分(score),这个评分(score)被用来按照从最低分到最高分的方式排序集合中的成员。
集合的成员是唯一的,但是评分是可以重复的。因为元素是有序的,所以你可以很快的根据评分(score)或者次序(position)来获取一个范围的元素。访问有序集合中的中间元素也是非常快的,因为你能够使用有序集合作为一个没有重复成员你的智能列表。
-
数据结构
SortedSet(zset)是redis提供的一个非常特别的数据结构,内部使用到了2种数据结构。
-
应用场景
1、需要随机获取数据源中的元素根据某个权重进行排序的场景
举例:各种排行榜比如直播间送礼物的排行榜、朋友圈的微信步数排行榜、王者荣耀中的段位排行榜、话题热度排行榜等等。
相关命令:ZRANGE (从小到大排序)、 ZREVRANGE (从大到小排序)、ZREVRANK (指定元素排名)。
2、需要存储的数据有优先级或者重要程度的场景 比如优先级任务队列。
举例:优先级任务队列。
相关命令:ZRANGE (从小到大排序)、 ZREVRANGE (从大到小排序)、ZREVRANK (指定元素排名)。
Hash(散列)
Redis hash是一个键值对集合。 Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。 类似于java里面的Map<String,Object>
-
数据结构
Hash类型对应的数据结构是2中:ziplist(压缩列表),hashtable(哈希表)。 当field-value长度较短个数较少时,使用ziplist,否则使用hashtable。
-
常用命令
hset key field value [field value ...]
|
设置多个
field
的值
|
---|---|
hget key field
|
获取指定
filed
的值
|
hgetall key
|
返回
hash
表所有的域和值
|
hmset key field value [field value ...]
|
和
hset
类似(已弃用)
|
hexists key field
|
判断给定的
field
是否存在,
1
:存在,
0
:不存在
|
hkeys key
|
列出所有的
filed
|
hvals key
|
列出所有的
value
|
HLEN key
|
返回
filed
的数量
|
hincrby key field increment
|
filed
的值加上指定的增量
|
hsetnx key field value
|
当
filed
不存在的时候,设置
filed
的值
|
-
应用场景
1、对象数据存储场景:
- 举例:用户信息、商品信息、文章信息、购物车信息。
- 相关命令:HSET (设置单个字段的值)、HMSET(设置多个字段的值)、HGET(获取单个字段的值)、HMGET(获取多个字段的值)。
3 种特殊数据类型
数据类型 | 说明 |
---|---|
HyperLogLog(基数统计) | 你可以将 Bitmap 看作是一个存储二进制数字(0 和 1)的数组,数组中每个元素的下标叫做 offset(偏移量)。通过 Bitmap, 只需要一个 bit 位来表示某个元素对应的值或者状态,key 就是对应元素本身 。我们知道 8 个 bit 可以组成一个 byte,所以 Bitmap 本身会极大的节省储存空间。 |
Bitmap(位图) | Redis 提供的 HyperLogLog 占用空间非常非常小,只需要 12k 的空间就能存储接近2^64 个不同元素。不过,HyperLogLog 的计数结果并不是一个精确值,存在一定的误差(标准误差为 0.81% )。 |
Geospatial(地理位置) | Geospatial index(地理空间索引,简称 GEO) 主要用于存储地理位置信息,基于 Sorted Set 实现。 |
HyperLogLog(基数统计)
在工作当中,我们经常会遇到与统计相关的功能需求,比如统计网站 PV(PageView 页面访问量),可以使用 Redis 的 incr、incrby 轻松实现。但像 UV(UniqueVisitor 独立访客)、独立 IP 数、搜索记录数等需要去重和计数的问题如何解决?这种求集合中不重复元素个数的问题称为基数问题。
解决基数问题有很多种方案:
数据存储在 MySQL 表中,使用 distinct count 计算不重复个数。
使用 Redis 提供的 hash、set、bitmaps 等数据结构来处理。
以上的方案结果精确,但随着数据不断增加,导致占用空间越来越大,对于非常大的数据集是不切实际的。能否能够降低一定的精度来平衡存储空间?Redis 推出了 HyperLogLog。
Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是:在输入元素的数量或者体积 非常非常大时,计算基数所需的空间总是固定的、并且是很小的。
在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。
但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以HyperLogLog 不能像集合那样,返回输入的各个元素。
什么是基数?比如数据集 {1, 3, 5, 7, 5, 7, 8},那么这个数据集的基数集为 {1, 3, 5 ,7, 8},基数 (不重复元素) 为 5。基数估计就是在误差可接受的范围内,快速计算基数。
-
常用命令
pfadd key element [element ...]
|
添加多个元素
|
---|---|
pfcount key1 key2 ...
|
获取多个HLL合并后元素的个数
|
pfmerge destkey sourcekey [sourcekey ...]
|
将多个HLL合并后元素放入另外一个HLL
|
-
应用场景
1、数量量巨大(百万、千万级别以上)的计数场景
- 举例:热门网站每日/每周/每月访问 ip 数统计、热门帖子 uv 统计、
- 相关命令:PFADD、PFCOUNT 。
Bitmap (位图)
现代计算机使用二进制(位)作为信息的基本单位,1个字节等于8位,例如“abc”字符串是有3个字节组成,但实际在计算机内存储时将其使用二进制表示,“abc”分别对应的ASCII码是:97、98、99,对应的二进制分别是01100001、01100010、01100011,如下图:
合理地使用位操作能够有效地提高内存使用率和开发效率。
Redis提供了Bitmaps这个“数据类型”可以实现对位的操作:
- Bitmaps本身不是一种数据类型, 实际上它就是字符串(key-value) , 但是它可以对字符串的位进行操作,字符串中每个字符对应1个字节,也就是8位,一个字符可以存储8个bit位信息。
- Bitmaps单独提供了一套命令, 所以在Redis中使用Bitmaps和使用字符串的方法不太相同。 可以把Bitmaps想象成一个以位为单位的数组, 数组的每个单元只能存储0和1, 数组的下标在 Bitmaps中叫做偏移量。
-
bitmaps与set比较
假设网站有 1 亿用户, 每天独立访问的用户有 5 千万, 如果每天用集合类型和 Bitmaps 分别存储活跃用户可以得到表:
数据类型 |
每个用户
id
占用空间
|
需要存储的用户量
|
全部内存量
|
---|---|---|---|
set
集合
|
64
位
|
50000000
|
64
位
* 50000000 = 400MB
|
Bitmaps
|
1
位
|
100000000
|
1
位
* 100000000 = 12.5MB
|
数据类型
| 一天 | 一月 | 一年 |
---|---|---|---|
set
集合
|
400MB
|
12GB
|
144GB
|
Bitmaps
|
12.5MB
|
375MB
|
4.5GB
|
但 Bitmaps 并不是万金油, 假如该网站每天的独立访问用户很少, 例如只有 10 万(大量的僵尸用户) , 那么两者的对比如下表所示, 很显然, 这时候使用 Bitmaps 就不太合适了, 因为基本上大部分位都 是 0。
数据类型
|
每个
userid
占用空间
|
需要存储的用户量
|
全部内存量
|
---|---|---|---|
set
集合
|
64
位
|
100000
|
64
位
* 100000 = 800KB
|
Bitmaps
|
1
位
|
100000000
|
1
位
* 100000000 = 12.5MB
|
-
常用命令
SETBIT key offset value
|
设置某个偏移量的值(
0
或
1
)
|
---|---|
GETBIT key offset
|
获取某个偏移位的值
|
BITCOUNT key [start] [end]
|
统计
bit
位都为
1
的数量
|
BITOP operation destkey key [key ...]
|
对一个多个
bitmaps
执行位操作
|
-
应用场景
1、需要保存状态信息(0/1 即可表示)的场景
- 举例:用户签到情况、活跃用户情况、用户行为统计(比如是否点赞过某个视频)。
- 相关命令:SETBIT、GETBIT、BITCOUNT、BITOP。
Geospatial (地理位置)
Reids3.2 中增加了对GEO类型的支持,GEO(Geographic),地理信息的缩写。该类型,就是元素的 2 维坐标,在地图上就是经纬度,redis基于该类型,提供了经纬度设置、查询、范围查询、距离查询,经纬度Hash等常见操作。
-
常用命令
geoadd key longitude latitude member [longitude latitude member ...]
|
添加多个位置的经纬度
|
---|---|
geopos key member [member ...]
|
获取多个位置的坐标值
|
geodist key member1 member2 [m|km|ft|mi]
|
获取两个位置的直线距离
|
georadius key longitude latitude radius m|km|ft|mi
|
以给定的经纬度为中心,找出某一半径内的元素
|
-
应用场景
1、需要管理使用地理空间数据的场景
- 举例:附近的人。
- 相关命令: GEOADD、GEORADIUS、GEORADIUSBYMEMBER 。