📫作者简介:小明java问道之路,专注于研究 Java/ Liunx内核/ C++及汇编/计算机底层原理/源码,就职于大型金融公司后端高级工程师,擅长交易领域的高安全/可用/并发/性能的架构设计与演进、系统优化与稳定性建设。
📫 热衷分享,喜欢原创~ 关注我会给你带来一些不一样的认知和成长。
🏆 InfoQ签约作者、CSDN专家博主/后端领域优质创作者/内容合伙人、阿里云专家/签约博主、51CTO专家 🏆
🔥如果此文还不错的话,还请👍关注、点赞、收藏三连支持👍一下博主~
11、Bitmaps、Bitfields、Geospatial、HyperLogLog的底层
本文作为Redis的开篇,简单介绍Redis以及其数据类型、存储、事务、lua、集群等等特性,展开讲解Redis的10中数据类型,并给出源码中的7种数据类型的结构,
所以当回答的时候,建议先说10种,再说7种,并展开官网和源码中的注释进行回答。让面试官看到你的理解和你对基本逻辑的掌握更系统和专业。
Redis是一个日志类型的键值存储组件,使用ANSI C语言编写。它的所有数据结构都存储在内存中,可以用作缓存、数据库和消息中间件。
Redis(Remote dictionary server)是远程字典服务器的缩写。一个Redis实例可以有多个存储数据的字典,客户端 select 字典(即DB)来存储数据。
Redis有许多数据类型。它有10种核心数据类型,strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, geospatial indexes,bitfields, and streams.,每种类型都有一系列操作指令。Redis具有高性能,单线程压测可以达到 10~11w 的 QPS。
Redis中的所有数据读写操作都在内存中执行,但也可以下载所有数据进行持久化。Redis提供了两种持久性方法。一、快照模式,在某一时间将所有数据写入硬盘的RDB文件;二、追加文件模式,即所有写入命令都以追加模式写入硬盘的AOF文件。
Redis从2.6版开始就支持Lua,Lua是一种高效、简洁、可扩展的脚本语言,可以很容易地嵌入到其他语言中。通过在客户端支持定制的Lua脚本,Redis可以减少网络开销,提高处理性能,并整体操作脚本中的多个操作,以实现原子更新。
Redis支持事务。在多指令之后,指定多个操作,然后通过exec指令一次执行它们。如果在执行过程中发生异常,请不要执行所有命令操作。否则,一次按顺序执行所有操作,在执行过程中不会执行其他指令。
Redis还支持 Cluster 集群功能,所有 key 都可以通过哈希自动或手动分散到不同的节点。当容量不足时,一些 key 也可以通过 Redis 迁移指令迁移到其他节点。
Redis 需要使用 Linux 环境。如果使用Windows操作系统,可以考虑使用虚拟机。 如果不想安装也可以使用网页版Redis进行学习。
- # 拉取 Redis 镜像
- docker pull redis
-
- # 运行 Redis 容器,6379是Redis端口号
- docker run --name myredis -d -p6379:6379 redis
-
- # 执行容器中的 redis-cli,
- docker exec -it myredis redis-cli
- # Github 源码编译,下载源码
- git clone --branch 5.0 --depth 1 git@github.com:antirez/redis.git
- cd redis
-
- # 编译
- make
- cd src
-
- # 运行服务器,daemonize 表示在后台运行
- ./redis-server --daemonize yes
-
- # 运行命令行
- ./redis-cli
- # 直接安装方式
- # mac系统
- brew install redis
-
- # ubuntu操作系统
- apt-get install redis
-
- #运行客户端
- redis-cli
我们经常见到网络上的博客和书籍,资料有很多都比较老久了,很多新的资料也不负责任,这里博主基于官网给出的标准进行讲解。
Redis provides data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, geospatial indexes,bitfields, and streams.
Redis 字符串(String)存储字节序列,包括文本、序列化对象和二进制数组。因此,字符串是最基本的 Redis 数据类型。通常用于缓存,但它们支持额外的功能,也可以实现计数器和执行按位运算。默认情况下,单个 Redis 字符串最大为 512 MB。
- # 添加缓存:在 Redis 中存储然后检索字符串
- > SET user:1 salvatore
-
- # 查询缓存
- > GET user:1
-
- # 存储序列化的 JSON 字符串并将其设置为从现在起 100 秒后过期:
- > SET tuser:1 "\"{'username': 'priya', 'ticket_id': 321}\"" EX 100
-
- # 增加一个计数器
- > INCR tuser:1
- 1
- > INCRBY tuser:1 10
- 11
SET存储一个字符串值。
SETNX仅当键不存在时才存储字符串值。用于实现锁。
GET检索字符串值。
MGET在单个操作中检索多个字符串值。
大多数字符串操作的复杂度为 O(1),这意味着它们非常高效。但是 SUBSTR复杂GETRANGE度SETRANGE可能为 O(n)。这些随机访问字符串命令在处理大字符串时可能会导致性能问题。
如果将结构化数据存储为序列化字符串,可能还需要考虑Redis 哈希或RedisJSON。
Redis Hashes 是以字段值对集合的形式构造的记录类型。可以使用散列来表示基本对象和存储计数器分组等。大多数Redis哈希命令都是O(1)。
- # 将基本用户配置文件表示为散列:
- > HSET user:1 username
- (integer) 4
-
- > HGET user:1 username
- "martina"
-
- > HGETALL user:1
- 1) "username"
HSET设置哈希上一个或多个字段的值。
HGET返回给定字段的值。
HMGET返回一个或多个给定字段的值。
HINCRBY将给定字段的值增加提供的整数。
例如HKEYS、HVALS和HGETALL 是O(n),其中n是字段值对的数量。每个哈希可以存储多达4294967295(2^32-1)个字段值对,Redis 部署的VM上的总内存的限制。
Redis Lists 是字符串值的链接列表。Redis列表通常用于:实现堆栈和队列。为后台工作系统构建队列管理。
Redis 列表的最大长度为 2^32 - 1 (4,294,967,295) 个元素。
- # 将列表视为队列(先进先出):
- > LPUSH user:1 101
- (integer) 1
- > RPOP user:1
- "101"
-
- # 将列表视为堆栈(先进后出):
- > LPUSH user:1 101
- (integer) 1
- > LPOP user:1
- "101"
-
- # 检查列表的长度:
- > LLEN user:1
- (integer) 0
LPUSH添加一个新元素到列表的头部;RPUSH添加到尾巴。
LPOP从列表的头部移除并返回一个元素;RPOP做同样的事情,但从列表的尾部开始。
LLEN返回列表的长度。
LMOVE原子地将元素从一个列表移动到另一个列表。
LTRIM将列表减少到指定的元素范围。
Redis Set 是由字符串(成员)组成的无序集合。
可以使用 Redis set 来高效地:跟踪唯一项目(例如,跟踪访问给定博客文章的所有唯一 IP 地址)。表示关系(例如,具有给定角色的所有用户的集合)。执行常见的集合运算,例如交集、并集和差集。
Redis Set 的最大大小为 2^32 - 1 (4,294,967,295) 个成员。
- 存储用户 1
- > SADD user:1
- (integer) 1
-
- # 获取用户 1
- > SISMEMBER user:1:favorites 742
- (integer) 1
-
- # 用户 1 和 2 有没有共同的
- > SINTER user:1 user:2
- 1) "561"
-
- # 统计 user:1
- > SCARD user:1
- (integer) 3
SADD将新成员添加到集合中。
SREM从集合中删除指定的成员。
SISMEMBER测试集合成员的字符串。
SINTER返回两个或多个集合共有的成员集合(即交集)。
SCARD返回集合的大小(又名基数)。
大多数集合操作,包括添加、删除和检查项是否为集合成员,都是O(1)。这意味着他们的效率很高。但是,对于具有数十万或更多成员的大型集合,在运行SMEMBERS命令时应谨慎。此命令为O(n),并在单个响应中返回整个集合。作为替代方案,考虑SSCAN,它允许迭代检索集合的所有成员。
Redis Sorted sets是按关联分数排序的唯一字符串(成员)的集合。当多个字符串具有相同的分数时,这些字符串按字典顺序排列。
Sorted sets 的一些用例包括:排行榜。例如,可以使用 Sorted sets 轻松维护大型在线游戏中最高分数的有序列表。费率限制器。可以使用 Sorted sets 来构建滑动窗口速率限制器,以防止过多的API请求。
- # 随着玩家分数的变化更新实时排行榜:
- > ZADD leaderboard:455 100 user:1
- (integer) 1
-
- # 获取 user:1 的分数:
- > ZRANGE leaderboard:455 0 2 REV WITHSCORES
- 1) "user:1"
- 2) "100"
-
- # 返回用户1的排名,假设排序集按降序排列。
- > ZREVRANK leaderboard:455 user:2
- (integer) 0
ZADD将新成员和关联的分数添加到已排序的集合中。如果该成员已经存在,则更新分数。
ZRANGE返回在给定范围内排序的有序集合的成员。
ZRANK返回所提供成员的排名,假设排序是按升序排列。
ZREVRANK返回所提供成员的排名,假设 Sorted sets 按降序排列。
大多数有序集合操作的复杂度为 O(log(n)),其中n是成员数。ZRANGE运行具有较大返回值(例如,数万或更多)的命令时要小心。此命令的时间复杂度为 O(log(n) + m),其中m是返回的结果数。Redis Sorted sets 有时用于索引其他 Redis 数据结构。如果需要索引和查询数据,请考虑RediSearch和RedisJSON。
Redis 5.0 引入了 Stream 数据结构。Redis 流是一种数据结构,其作用类似于仅附加日志。可以使用流实时记录和同时联合事件。
Redis 流用例示例包括:事件溯源(例如,跟踪用户操作、点击等);传感器监控(例如,现场设备的读数);通知(例如,将每个用户的通知记录存储在单独的流中)
Redis 为每个流条目生成一个唯一的 ID。可以使用这些 ID 稍后检索它们的关联条目,或者读取和处理流中的所有后续条目。
Redis 流支持多种修剪策略(以防止流无限制地增长)和不止一种消费策略(请参阅XREAD、XREADGROUP和XRANGE)。
Bitmap 底层是 String 实现,赋值的每一个 bit 均对应 ASCII 码的二进制位。
Redis Bitmap 位图是字符串数据类型的扩展,可将字符串视为位向量。还可以对一个或多个字符串执行按位运算。
位图用例的一些示例包括:集合成员对应于整数 0-N 的情况的有效集合表示。对象权限,其中每一位代表一个特定的权限,类似于文件系统存储权限的方式。
Redis Bitfields 位域允许设置、递增和获取任意位长度的整数值。可以对从无符号 1 位整数到有符号 63 位整数的任何内容进行操作。
这些值使用二进制编码的 Redis 字符串存储。位域支持原子读、写和递增操作,使它们成为管理计数器和类似数值的不错选择。
Redis Geospatial indexes 地理空间索引让您可以存储坐标并进行搜索。此数据结构可用于查找给定半径或边界框内的附近点。
HyperLogLog 底层也是 String 实现,与其说 HyperLogLog 是一种单独的数据类型,倒不如说是对 String 数据类型做 API 封装的应用程序。HyperLogLog 是一种估计集合基数的数据结构。作为一种概率数据结构,HyperLogLog 以完美的准确性换取高效的空间利用。
高级数据类型 | 底层数据类型 |
Bitmap | String |
Bitfields | String |
Geospatialindexes | Sorted Set |
HyperLogLog | String |
源码内容中,define了7种类型:OBJ_ STRING 0、OBJ_ LIST 1、OBJ_ SET 2、OBJ_ ZSET 3、OBJ_ HASH 4、0BJ_ MODULE 5、OBJ_ STREAM 6。
这个0BJ_ MODULE,MODULE对象类型是一种特殊的类型,表示对象,由Redis模块直接管理。这其中就包括了 Bitmaps, Hyperloglogs, Geospatial indexes, Bitfields.
所以当回答的时候,建议先说10种,再说7种,并展开官网和源码中的注释进行回答。让面试官看到你的理解和你对基本逻辑的掌握更系统和专业。
本文作为Redis的开篇,简单介绍Redis以及其数据类型、存储、事务、lua、集群等等特性,展开讲解Redis的10中数据类型,并给出源码中的7种数据类型的结构,
所以当回答的时候,建议先说10种,再说7种,并展开官网和源码中的注释进行回答。让面试官看到你的理解和你对基本逻辑的掌握更系统和专业。