在上一篇文章中我们已经大致了解了 Redis 在并发场景下的工作流程,下面我们就来学习一下 Redis 的应用层面的东西
前面我们讲了 Redis 与 memcache 的最本质的区别就是 Redis 键值对数据 key–value 中的 value 有五种数据类型,基于这五种数据类型及 Redis 提供的对五种数据结构操作的 API 方法,我们能够很方便的对指定的属性进行查询,返回给用户请求指定的属性值,而不必返回全量的数据组成的 JSON 对象
如果使用 memcache 返回全部的数据组成的 JSON,还需要在 client 端编写代码解析,才能够获取指定的字段值;而使用 Redis 中的五种数据类型,就能够使服务器返回指定的字段值。
核心思想就是使计算向数据移动。memcache 计算流程在客户端完成,客户端要处理大量的逻辑,server 端只返回大量的数据;而 Redis 的计算发生在 Server 端,根据客户端请求返回指定的数据,客户端相对比较轻盈
Redis 中 value 值有五种数据类型,每种数据类型都有各自的方法,每种方法是和各自类型绑定的
除了 key-value 键值对中 value 有五种数据结构,在 key 中其实也有优化。key 中有一个 type 属性,会登记注册对应的 value 的类型,如果你非要用一个对 int 类型的方法来操作 string 类型的数据,就会直接报错——类型不匹配。除了 type 属性,key 中还有 encoding 类型,使用 object 命令可以观察 value 的 encoding 是 string 还是 int
Redis 开发者通过在 key 中内置的 type 和 encoding 两个小细节优化,大大减少了后续的数据类型判断,提高了 Redis 的响应能力。众所周知,Redis 最显著的特点就是快,其实 Redis 的快就是通过许多这样小小的细节优化,慢慢的把优势积累出来的。
Redis 进程里面是分为了 16 个独立的区域,即 16 个库,key 创建在不同的区域,其他的区域是看不到的、是隔离的
String 类型又分为字符串、数值、bitmap(位图)三种数据类型,面向每一种数据类型,都有各自的操作命令
面向字符串常见命令:
面向 string 类型数据,除了有针对字符串的指令之外,还有一些针对数值的操作:
我们通过这些命令可以像操作 int 类型数据一样,直接对 string 类型数据进行数值运算,它的底层实现可以归纳为二进制安全
应用场景:
二进制安全?
Redis 是支持多种语言连接的核心的中间件,不同的语言对于数据类型的理解是不一样的。有的语言认为 int 占两个字节,有的认为 int 占四个字节,如果用 int 存放一个占用 4 个字节的大整数,另外一种准备用 2 个字节接收的时候就会发现空间不够用,出现溢出错误
所以 Redis 在存放数据的时候,并不是使用字符流,而是使用字节流,一个字符占用一个字节,所以 9999 占用 4 个字节
说白了就是 Redis 底层存放数据的时候就是按照字节存放的,key 中的 encoding 只是在上层做了一些优化,如果没有 encoding 的话,每次进行运算的时候都要先进行类型判断,判断数据类型是否能够转换;而 key 中使用 encoding ,如果上次使用 int 类型做运算,解析成功了,那么这次的运算就不需要再进行判断,只需要直接进行运算即可
总结一下:所有使用 Redis 的用户,需要在用户端沟通好数据的编码和解码,Redis 里面是没有数据类型概念的
bitmap 即位图,是 Redis 中最值钱的,也是最难理解的,精力不够,暂时略过
二进制位的数据在操作系统中,CPU 的运算速度是最快的,所以 bitmap 应用于快速运算有很大的优势
面向 bitmap 常见命令:
位图的应用场景:
Redis 中 key-value 键值对中的 value 也可以是 list 结构,是双向队列
面向 list 结构常用命令:
使用不同的命令组合,可以使 list 结构表现出不同的数据结构的特性
Redis 中 key-value 键值对中的 value 也可以是 hash 键值对结构,相当于 hashmap 里面又放了一层 hashmap,这其实也是我们见到过的用法
面向 Set 的命令:
HDEL key field [field ...]
summary: Delete one or more hash fields
since: 2.0.0
HEXISTS key field
summary: Determine if a hash field exists
since: 2.0.0
HGET key field
summary: Get the value of a hash field
since: 2.0.0
HGETALL key
summary: Get all the fields and values in a hash
since: 2.0.0
HINCRBY key field increment
summary: Increment the integer value of a hash field by the given number
since: 2.0.0
HINCRBYFLOAT key field increment
summary: Increment the float value of a hash field by the given amount
since: 2.6.0
HKEYS key
summary: Get all the fields in a hash
since: 2.0.0
HLEN key
summary: Get the number of fields in a hash
since: 2.0.0
HMGET key field [field ...]
summary: Get the values of all the given hash fields
since: 2.0.0
HMSET key field value [field value ...]
summary: Set multiple hash fields to multiple values
since: 2.0.0
HSCAN key cursor [MATCH pattern] [COUNT count]
summary: Incrementally iterate hash fields and associated values
since: 2.8.0
HSET key field value
summary: Set the string value of a hash field
since: 2.0.0
HSETNX key field value
summary: Set the value of a hash field, only if the field does not exist
since: 2.0.0
HSTRLEN key field
summary: Get the length of the value of a hash field
since: 3.2.0
HVALS key
summary: Get all the values in a hash
since: 2.0.0
以上解释在 redis 进程中使用命令行 help @hash 获得,由于不会设置高亮,感觉不是很简洁明了,所以后面还是不使用了
如果不支持 hash 这种 key-value 键值对的存储格式,存储键值对格式的数据将会很麻烦,使用 hash 进行设置的话就会很方便:
//设置单个 kev-value:对 key 为 5170203 的人的 value 进行设置姓名
hset 5170203 name mjt
//设置多个key-value:对 key 为 5170203 的人的 value 进行设置姓名、年龄、性别
hmset 5170203 name mjt age 18 gender man
此时可以使用 hgetall 命令,得到一个 key 的所有 key-value 属性,类似于面向对象的操作,减少请求的 IO 次数
set 最需要记住的特点是元素唯一、适于集合操作、适合随机操作
面向 set 的命令:
SADD key member [member ...]
summary: Add one or more members to a set
since: 1.0.0
SCARD key
summary: Get the number of members in a set
since: 1.0.0
SDIFF key [key ...]
summary: Subtract multiple sets
since: 1.0.0
SDIFFSTORE destination key [key ...]
summary: Subtract multiple sets and store the resulting set in a key
since: 1.0.0
SINTER key [key ...]
summary: Intersect multiple sets
since: 1.0.0
SINTERSTORE destination key [key ...]
summary: Intersect multiple sets and store the resulting set in a key
since: 1.0.0
SISMEMBER key member
summary: Determine if a given value is a member of a set
since: 1.0.0
SMEMBERS key
summary: Get all the members in a set
since: 1.0.0
SMOVE source destination member
summary: Move a member from one set to another
since: 1.0.0
SPOP key [count]
summary: Remove and return one or multiple random members from a set
since: 1.0.0
SRANDMEMBER key [count]
summary: Get one or multiple random members from a set
since: 1.0.0
SREM key member [member ...]
summary: Remove one or more members from a set
since: 1.0.0
SSCAN key cursor [MATCH pattern] [COUNT count]
summary: Incrementally iterate Set elements
since: 2.8.0
SUNION key [key ...]
summary: Add multiple sets
since: 1.0.0
SUNIONSTORE destination key [key ...]
summary: Add multiple sets and store the resulting set in a key
since: 1.0.0
使用 set 的优势在于 set 中的元素唯一、不可重复
set 的另一个优势在于提供了许多对于集合的操作,支持集合的交集、并集和差集
同时基于 srandmember 命令,set 相当适合基于随机事件的场景
我们说 set 有很多好处,唯一不可重复,适用于集合操作和随机事件,不过 set 的缺点就是无序,有些需要顺序的情况下,就很难使用 set 结构。此时就可以使用 sorted_set
sorted_set 结构又称为有序集,是对 set 的优化,可以对数据去重还支持数据有序,这个顺序是对元素的排序
sorted_set 也是 Redis 中常用的东西,由排序可以引出如下概念:
sorted_set 也是 set,同样适合于集合的操作,不过关于 sorted_set 的操作要注意权重问题,交并差集的指令稍微复杂一点,所以要多熟悉相关指令的使用细节
关于 sorted_set 面试也会常问其排序是怎样实现的?增删改查的速度是怎样保证的?——其核心点就是基于跳跃表的实现
总结:五种数据结构总结
关联文章:
Redis入门–万字长文详解epoll