1.简介
Redis是一个开源的,内存中的数据结构存储系统,它可以用做数据库,缓存和消息中间件。
支持多种类型的数据结构,支持每秒10w次查询请求
- 字符串 strings
- 散列 hashes
- 列表 lists
- 集合 sets
- 有序集合 sorted sets
- bitmaps
- hyperloglogs
- 地理空间 geospatial 索引半径查询
2. redis操作
2.1 原生操作
HSET hash field value — Redis 命令参考 (redisdoc.com)
2.2 python操作
pass
3.数据类型
介绍
官网有 8 种,前面 5 种为常用数据结构
- string 二进制安全的字符串
- Lists: 按插入顺序排序的字符串元素的集合。他们基本上就是链表(linked lists)。
- Sets: 不重复且无序的字符串元素的集合。
- Sorted sets,类似Sets,但是每个字符串元素都关联到一个叫score浮动数值(floating number value)。里面的元素总是通过score进行着排序,所以不同的是,它是可以检索的一系列元素。(例如你可能会问:给我前面10个或者后面10个元素)。
- Hashes,由field和关联的value组成的map。field和value都是字符串的。这和Ruby、Python的hashes很像。
- Bit arrays (或者说 simply bitmaps): 通过特殊的命令,你可以将 String 值当作一系列 bits 处理:可以设置和清除单独的 bits,数出所有设为 1 的 bits 的数量,找到最前的被设为 1 或 0 的 bit,等等。
- HyperLogLogs: 这是被用于估计一个 set 中元素数量的概率性的数据结构。
- Streams:5.0版本新增, append-only collections of map-like entries that provide an abstract log data type:可以用来做持久化的消息队列
String 字符串
存储原理
假设存储 key = hello vlaue = word
set hello word
String的三种编码
- int,存储8个字节的长整型(long,2^63-1)
- embstr,embstr格式的SDS(Simple Dynamic String)
- raw,SDS,存储大于44个字节的字符串
redis 为什么要自己写一个SDS的数据类型
主要是为了解决C语言 char[] 的四个问题:
- 字符数组必须先给目标变量分配足够的空间,否则可能会溢出
- 查询字符数组长度 时间复杂度O(n)
- 长度变化,需要重新分配内存
- 通过从字符串开始到结尾碰到的第一个\0来标记字符串的结束,因此不能保存图片、音频、视频、压缩文件等二进制(bytes)保存的内容,二进制不安全
redis SDS
- 不用担心内存溢出问题,如果需要会对 SDS 进行扩容
- 因为定义了 len 属性,查询数组长度时间复杂度O(1) 固定长度
- 空间预分配,惰性空间释放
- 根据长度
len
来判断是结束,而不是\0
embstr和raw
- 当 value 的值为整型时,编码为 int
- 当 value 值为字符时,存储的编码为 embstr,连续的内存空间,只需要分配一次
- 当 value 值字符长度超过 44 时,存储的编码为 raw,不是连续的内存空间,需要分配两次
- 如果 value 的值为 int 或者 embstr ,然后通过 append 添加字符的时候,也会转化为 raw 类型(因为 embstr 设计的是只读的,如果发生变化只能再开辟一块空间),而且这个过程是不可逆的。
应用场景
- 缓存,热点数据
- 分布式session
- set key value NX EX 分布式锁
- INCR计数器
- 文章的阅读量,微博点赞数,允许一定的延迟,先写入 Redis 再定时同步到数据库
- 全局ID
- INT 类型,INCRBY,利用原子性
- INCR 限流
- 以访问者的 IP 和其他信息作为 key,访问一次增加一次计数,超过次数则返回 false。
- setbit 位操作
Hash哈希
介绍
对于这种类似于数据库表的结构,redis中可以使用hash进行存储
结构
键key:{
域field:值value,域field:值value,
}
同样是存储字符串,Hash 与 String 的主要区别?
- 1、把所有相关的值聚集到一个 key 中,节省内存空间
- 2、只使用一个 key,减少 key 冲突
- 3、当需要批量获取值的时候,只需要使用一个命令,减少内存/IO/CPU 的消耗
Hash 不适合的场景:
- 1、Field 不能单独设置过期时间
- 2、没有 bit 操作
- 3、需要考虑数据量分布的问题(value 值非常大的时候,无法分布到多个节点)
hash表
有两种存储的数据编码
如果
Field
的个数超过512
个 或者Field
中任意一个 键或者值 的长度大于64
个字节,hash表
会用ht
来存储
redis配置文件
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
ht(hashtable) 哈希表
在 Redis 中,hashtable 被称为字典(dictionary),它是一个数组+链表的结构。
为什么有 ht[0] 和 ht[1] 两个hash表,是为了扩容。
应用场景
图解
对应操作
存储 | 命令 |
---|---|
用户id | key |
商品id | field1 |
商品数量 | value1 |
商品价格 | field2 |
商品价格值 | value2 |
操作 | 命令 |
---|---|
商品+1 | hincr |
商品-1 | hdecr |
删除 | hdel |
全选 | hgetall |
商品数量 | hlen |
List 列表
介绍
有序,左边是列表头,从左到右
存储有序的字符串(从左到右),元素可以重复。可以充当队列和栈的角色。
结构
{ user_id:[1,2] }
List 存储原理(quicklist)
内部是一个双向链表,*zl 指针指向的是 ziplist 压缩列表,数据真正还是存储在 ziplist 中。
应用场景
- 时间线
- 队列
- 栈
Set 集合
介绍
一个
set
集合可以存储2^63-1
个元素
结构
{ user_id:[1,2] }
应用场景
1.知乎点赞数
2.京东的商品筛选
ZSet 有序集合
介绍
每个元素有一个对应的分数,基于分数进行排序;如果分数相等,以
key
值的ascii
值进行排序。
结构
{ user_id:[1,2] }
数据结构对比
数据结构 | 是否允许重复元素 | 是否有序 | 有序实现方式 |
---|---|---|---|
list | 是 | 是 | 索引下标 |
set | 否 | 否 | 无 |
zset | 否 | 是 | 分值score |
存储结构
ziplist
skiplist+dict 跳表+字典
redis配置文件
zset-max-ziplist-entries 128
zset-max-ziplist-value 64
什么是 skiplist ?
上面的是普通的链表,下面的是跳表,level 是随机的
普通链表查找一个元素的时间复杂度为O(n)
跳表的时间复杂度为O(m*log2n)
假设我们找元素19
1.先从起始的 level3 指针中查找 26 大于 19
2.退回到起始的 level2 的指针,大于7 继续往后,找到19
3.通过三次就找到了19
应用场景
1.商品的评价标签,可以记录商品的标签,统计标签次数,增加标签次数,按标签的分值进行排序
2.百度搜索热点
BitMaps
介绍
Bitmaps 是在字符串类型上面定义的位操作。一个字节由 8 个二进制位组成。
应用场景
用户访问统计
在线用户统计
Hyperloglogs
介绍
Hyperloglogs:提供了一种不太准确的基数统计方法,比如统计网站的 UV,存在一定的误差。
Streams
介绍
5.0 推出的数据类型。支持多播的可持久化的消息队列,用于实现发布订阅功能,借鉴了 kafka 的设计。
5.其他
编码转换
对象 | 元素编码 | 升级编码 | 再次升级 |
---|---|---|---|
字符串 | INT 整数并且小于 log 2^63-1 | embstr 超过44字节被修改 | raw |
哈希 | ziplist 键和值的长度小于64字节,键值对个数不超过521个 | hashtable | |
列表 | quicklist |
集合 | intset 元素都是整数,元素个数小于512 | hashtable | |
有序集合 | ziplist 任何一个member长度小于64字节,元素个数不超过128个 | skiplist |
数据结构
对象 | 元素编码 | 升级编码 | 再次升级 |
---|---|---|---|
字符串 | INT 整数并且小于 log 2^63-1 | embstr 超过44字节被修改 | raw |
哈希 | ziplist 键和值的长度小于64字节,键值对个数不超过521个 | hashtable |
列表 | quicklist | ||
集合 | intset 元素都是整数,元素个数小于512 | hashtable | |
有序集合 | ziplist 任何一个member长度小于64字节,元素个数不超过128个 | skiplist |