文章目录
1、什么是Redis
Redis 是一种基于键值对(key-value)的 NoSQL 数据库,它的全称是(Remote Dictionary Service)远程字典服务。
Redis 中的值支持 字符串(string)、哈希(hash)、列表(list)、集合(set)、有序集合(zset)、位图(Bitmaps)、HyperLogLog、GEO(地理信息定位)等多种数据结构,因此 Redis 可以满足很多应用场景。
Redis 可以将所有数据存放在内存中,因此它的读写性能非常惊人。不仅如此,Redis 还可以将内存的数据利用快照和日志的形式保存在硬盘上,这样在服务器发生故障时,只要硬盘可以使用,那么其存储的数据就不会丢失。除了以上功能,Redis 还提供了键过期、发布订阅、事务、Lua 脚本等功能。
从 Redis 的官方统计来看,国内外很多大型互联网公司都在使用Redis,如国外的 Twitter、Stack Overflow、GitHub 等;国内的 新浪微博、阿里巴巴、腾讯、百度、搜狐、优酷土豆、美团、小米、唯品会等公司。因此,对 Redis 的了解与应用已经成为当下开发者必备的技能。
2、Redis 可以用来做什么
Redis的业务应用范围非常广泛,以下介绍几种常用的场景
2.1、缓存
Redis 提供了键值过期特性,同时也提供了灵活控制最大内存合内存溢出的淘汰策略。因此合理的使用Redis 缓存数据不仅可以加快数据的访问速度,而且可以有效的降低后端的压力。
2.2、排行榜
对数据进行排行的需求几乎存在与所有的系统或网站,例如:按照热度排行,按照时间排行,按照各种复杂维度计算出的排行。Redis 提供了列表和有序集合数据结构,合理的使用这些数据结构可以很轻松的实现各种维度的排行。
2.3、计数器
Redis 天然支持计数功能,而且计数的性能也非常好,因此经常用于对 视频播放计数、网页浏览计数、或用来做分布式自增ID等。
2.4、社交网络
点赞、踩、粉丝、共同好友或喜好、推送、下拉刷新等都是社交网站必备的功能,由于社交网站访问量通常比较大,而且传统的关系听数据库不太适合保存这种类型的数据,Redis 提供的数据结构可以比较轻松的实现这些功能。
2.5、消息队列
Redis 提供了发布订阅和阻塞队列的功能,虽然与专业的消息队列相比还不够强大,但是对于一般的消息队列功能基本都可以满足。
3、常用全局命令
Redis 的命令有上百个,如果靠死记硬背是很困难的,但是如果理解了 Redis 的一些机制,便会发现这些命令有很强的规律性和通用性。
另外 Redis 不是万能的,有些数据结构和命令必须在特定场景下使用,如果使用不当可能对 Redis 服务或应用本身造成不可知的后果。
3.1、查看所有键
keys *
该命令会将所有键输出
127.0.0.1:6379> keys *
1) "java"
2) "hello"
keys 命令会遍历所有键,所以它的时间复杂度是 O(n),如果 Redis 中有大量键时,不建议使用该命令。
3.2、键总数
dbsize
dbsize 命令会返回当前数据库中键的总数
127.0.0.1:6379> dbsize
(integer) 2
dbsize 命令在计算键总数时不会遍历所有键,而是直接获取 Redis 内置的键总数变量,所以该命令的时间复杂度为 O(1).
3.3、检查键是否存在
exists key
如果键存在返回 1,否则返回 0
127.0.0.1:6379> exists hello
(integer) 1
127.0.0.1:6379> exists hello1
(integer) 0
3.4、删除键
del 是一个通用命令,无论值是什么数据结构类型,del 命令都可以将其删除
del key [key ...]
返回结果是成功删除键的个数,如果删除一个不存在的键,就会返回 0
127.0.0.1:6379> del hello
(integer) 1
127.0.0.1:6379> exists hello
(integer) 0
127.0.0.1:6379> del hello
(integer) 0
3.5、键过期
Redis 支持对键添加过期时间,当超过过期时间后,会自动删除键
expire key seconds
ttl 命令会返回键剩余时间,它有3种返回值:
- 大于等于0:键剩余的过期时间
- -1:未设置过期时间
- -2:键不存在
127.0.0.1:6379> set hello world
OK
127.0.0.1:6379> expire hello 10
(integer) 1
127.0.0.1:6379> ttl hello
(integer) 2
127.0.0.1:6379> ttl hello
(integer) -2
127.0.0.1:6379> exists hello
(integer) 0
3.6、键的数据结构类型
type key
如果键不存在,则返回 none
127.0.0.1:6379> set today monday
OK
127.0.0.1:6379> rpush weeks monday sunday
(integer) 2
127.0.0.1:6379> type today
string
127.0.0.1:6379> type weeks
list
127.0.0.1:6379> type week
none
4、Redis 基本数据结构简介
Redis不是普通的键值存储,它实际上是一个数据结构服务器,支持不同类型的值。 这意味着,在传统的键值存储中,您将字符串键与字符串值相关联,在Redis中,值不仅限于简单的字符串,还可以包含更复杂的数据结构。 以下是Redis支持的所有数据结构的列表,本教程将单独介绍它们:
4.1、String 字符串
string 是redis最基本的类型,一个键最大能存储512MB。string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。
4.2、Hash 哈希
Redis hash 是一个键值(key=>value)对集合。
Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。
Redis Hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。
每个 hash 可以存储 232 - 1 键值对(40多亿)。
4.3、List 列表
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素导列表的头部(左边)或者尾部(右边)。
列表最多可存储 232 - 1 元素 (4294967295, 每个列表可存储40多亿)。
4.4、Set 集合
Redis的Set是string类型的无序集合。
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)
集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。
4.5、ZSet 有序集合
Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
zset的成员是唯一的,但分数(score)却可以重复。
5、Redis 高级数据结构简介
5.1、Bitmaps 位图
Bitmaps 本身不是一种数据结构,实际上它就是字符串(key 对应的 value 就是上图中最后的一串二进制),但是它可以对字符串的位进行操作。
Bitmaps 单独提供了一套命令,所以在 Redis 中使用 Bitmaps 和使用字符串的方法不太相同。可以把 Bitmaps 想象成一个以 位 为单位的数组,数组的每个单元只能存储 0 和 1,数组的下标在Bitmaps中叫做偏移量。
5.2、HyperLogLogs
Redis 在 2.8.9 版本添加了 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。 基数估计就是在误差可接受的范围内,快速计算基数。
5.3、Streams
Stream是Redis 5.0引入的一种新数据类型,允许消费者等待生产者发送的新数据,还引入了消费者组概念,组之间数据是相同的(前提是设置的偏移量一样),组内的消费者不会拿到相同数据。这种概念和kafka很雷同,kafka消费的时候就是在移动offset,数据依然在。
在某些特定场景可以使用redis的stream代替kafka等消息队列,减少系统复杂性,增强系统的稳定性
官方说他们这个stream是对日志数据结构(log data structure)的高度抽象。stream首先是一个append only日志数据结构,但实现更加的复杂,要比一般的日志文件更强大。
5.4、GEO
Redis 的 GEO 是 3.2 版本的新特性。这个功能可以将用户给定的地理位置信息储存起来, 并对这些信息进行操作。比如:获取某个地理位置的坐标、获取两个地理位置的距离、根据给定地理位置坐标获取指定范围内的地理位置集合等等。
6、Redis 数据结构和内部编码
type 命令返回的是当前键的数据结构类型,分别是:string(字符串)、hash(哈希)、 list(列表)、set(集合)、zset(有序集合),这些是 Redis 对外的数据结构。
实际上每种数据结构都有自己的底层内部编码实现,而且是多种实现,这样 Redis 就会在合适的场景使用合适的内部编码。
Redis 这样设计有两个好处:
第一,可以改进内部编码,而对外的数据结构和命令不受影响,比如 Redis 3.2 提供了 quicklist ,结合了 ziplist 和 linkedlist 的优势,为列表类型提供了一种更为优秀的内部编码实现,而对外来说是无感知不受影响的。
第二,多种内部编码实现可以在不同场景下发挥各自的优势,例如 ziplist 比较节省内存,但是在元素比较多的情况下,性能会有所下降,这时 Redis 会根据配置项将列表类型的内部编码转换为 linedlist.
7、Redis 单线程为何性能如此高
1、Redis 将所有数据放在内存中,实现纯内存访问,内存的响应时长大约为100纳秒,这也是 Redis 能达到每秒万级别访问的重点所在。
2、Redis 使用 epoll 作为 I/O 多路复用计数的实现,再配合 Redis 自身的事件处理模型将 epoll 中的连接、读写、关闭都转换为事件,避免了在网络 I/O 上浪费太多的时间。
3、单线程避免了线程切换和竞态产生的消耗。
8、Redis 5.x 新特性
1、新的流数据类型(Stream data type) https://redis.io/topics/streams-intro
2、新的 Redis 模块 API:定时器、集群和字典 API(Timers, Cluster and Dictionary APIs)
3、RDB 现在可存储 LFU 和 LRU 信息
4、redis-cli 中的集群管理器从 Ruby (redis-trib.rb) 移植到了 C 语言代码。执行 redis-cli –cluster help
命令以了解更多信息
5、新的有序集合(sorted set)命令:ZPOPMIN/MAX 和阻塞变体(blocking variants)
6、升级 Active defragmentation 至 v2 版本
7、增强 HyperLogLog 的实现
8、更好的内存统计报告
9、许多包含子命令的命令现在都有一个 HELP 子命令
10、客户端频繁连接和断开连接时,性能表现更好
11、许多错误修复和其他方面的改进
12、升级 Jemalloc 至 5.1 版本
13、引入 CLIENT UNBLOCK 和 CLIENT ID
14、新增 LOLWUT 命令 http://antirez.com/news/123
15、在不存在需要保持向后兼容性的地方,弃用 “slave” 术语
16、网络层中的差异优化
17、Lua 相关的改进:
- 将 Lua 脚本更好地传播到 replicas / AOF
- Lua 脚本现在可以超时并在副本中进入 -BUSY 状态
18、引入动态的 HZ(Dynamic HZ) 以平衡空闲 CPU 使用率和响应性
19、对 Redis 核心代码进行了重构并在许多方面进行了改进
参考资料:
Redis 5.0 release notes
Introduction to Redis Streams
《Redis 开发与运维》
《Redis 设计与实现》