Redis优势、应用以及基本数据类型

Tags
Redis
内存管理
缓存设计
二进制编程
集合算法
字符串
数组
哈希算法
CreatedTime
Aug 24, 2022 02:37 PM
Slug
UpdatedTime
Last updated August 24, 2022

优势

实现模型:单线程模型
内部数据结构:
  • 支持字符串、散列、列表、集合等基础类型
  • 支持有序集合类型
  • API 使用方便
数据状态:
  • 基于内存高速读写
  • 支持硬盘持久化存储

应用

内存数据库

对比 memcached,功能更全面;支持持久化存储

中心化存储

给各种微服务提供公用状态,性能高

本地缓存设计

基于 redis 本身,可以设置缓存生效时间(TTL);
也可以设置最大内存空间,达到限制自动淘汰键;
基于队列实现一个优先级队列;
基于支持的“订阅发布模式”,构建消息推送。

数据库概念

如何理解:整个 redis 是一个大字典,数据库就是大字典下的最近的字段名,本质上更像命名空间。
例如,redis 数据库从 0 开始,一般到 16。其实换成 json 就是:
{ "0": {}, "1": {}, // ... "15": {} }
应用注意
  • 类似命名空间,但是数据不是强隔离,FLUSHALL 可以清空所有数据库数据
  • 不适合存储不同应用数据,但是可以存储同一应用不同环境(开发、测试)数据

键名

命令

获取键类型:TYPE key 。返回值包括:string、hash、list、set、zset(有序集合)
判断键是否存在:EXISTS key

整数

redis 没有整数类型(基础都是字符串),但是提供整数操作。
举例:INCR foo(将 foo 的值增加 1)
命令命名规则:多以 integer 开头(例如 INCR)

字符串

介绍

字符串类型是 Redis 中最基本的数据类型,它能存储任何形式的字符串,包括二进制数据
字符串类型是其他 4 种数据类型的基础,其他数据类型和字符串类型的差别从某种角度来说只是组织字符串的形式不同。例如,列表类型是以列表的形式组织字符串,而集合类型是以集合的形式组织字符串。

命令

递增数字:INCR num。如果 num 不存在,会将 num 默认设置为 0。能够避免出现“竞态条件”,整体是原子操作。

位操作

介绍

利用位操作命令可以非常紧凑地存储布尔值。由于 GETBIT 和 SETBIT 的时间复杂度都是 O(1),所以读取二进制位值性能很高。
注意:使用 SETBIT 命令时,如果当前键的键值长度小于要设置的二进制位的偏移量时,Redis 会自动分配内存并将键值的当前长度到指定的偏移量之间的二进制位都设置为 0。**如果要分配的内存过大,则很可能会造成服务器的暂时阻塞而无法接收同一时间的其他请求。

命令

GETBIT key offset:命令可以获得一个字符串类型键指定位置的二进制位的值(0 或 1),索引从 0 开始
SETBIT key offset value:命令可以设置字符串类型键指定位置的二进制位的值,返回值是该位置的旧值。
注意 ⚠️ 如果要设置的位置超过了键值的二进制位的长度,SETBIT 命令会自动将中间的二进制位设置为 0,同理设置一个不存在的键的指定二进制位的值会自动将其前面的位赋值为 0
BITCOUNT key [start] [end]:命令可以获得字符串类型键中值是 1 的二进制位个数
BITOP operation destkey key [key …]:BITOP 命令可以对多个字符串类型键进行位运算,并将结果存储在 destkey 参数指定的键中。BITOP 命令支持的运算操作有 AND、OR、XOR 和 NOT。
# BITOP命令支持的运算操作有AND、OR、XOR和NOT。如我们可以对bar和aar进行OR运算 redis> SET foo1 bar OK redis> SET foo2 aar OK redis> BITOP OR res foo1 foo2 (integer) 3 redis> GET res "car"

散列

命令

HSET key field1 value1:将 key 对象的 filed1 字段值设置为 value1
HGET key field:获取值
HEXISTS key field:判断 filed 字段是否存在
HSETNX key field value:当字段不存在时赋值。使用了 HSETNX 命令原子地实现了 HEXISTS 和 HSET 两个命令以避免竞态条件

列表

列表

列表类型内部是使用双向链表(double linked list)实现的。
这种特性使列表类型能非常快速地完成关系数据库难以应付的场景:如社交网站的新鲜事,我们关心的只是最新的内容,使用列表类型存储,即使新鲜事的总数达到几千万个,获取其中最新的 100 条数据也是极快的。同样因为在两端插入记录的时间复杂度是 O(1),列表类型也适合用来记录日志,可以保证加入新日志的速度不会受到已有日志数量的影响。总结来说,列表适合高频读取头部或者尾部数据的场景。

命令

1、向列表两端增加元素:
  • LPUSH key value [value …]
  • RPUSH key value [value …]
2、从列表两端弹出元素:
  • LPOP key
  • RPOP key
3、获取列表中元素的个数:
  • LLEN key
当键不存在时 LLEN 会返回 0
4、获得列表片段:
  • LRANGE key start stop

集合

介绍

集合类型的常用操作是向集合中加入或删除元素、判断某个元素是否存在等,由于集合类型在 Redis 内部是使用值为空的散列表(hash table)实现的,所以这些操作的时间复杂度都是 O(1)。
多个集合类型键之间还可以进行并集、交集和差集运算。

命令

1、增加/删除元素
  • SADD key member [member …]
  • SREM key member [member …]
2、获得集合中的所有元素
  • SMEMBERS key
  • SMEMBERS 命令会返回集合中的所有元素
3、判断元素是否在集合中
  • SISMEMBER key member
4、集合间运算
  • SDIFF key [key „]:对多个集合差集运算
  • SINTER key [key „]:对多个集合交集运算
  • SUNION key [key „]:对多个集合并集运算

有序集合

介绍

在集合类型的基础上有序集合类型为集合中的每个元素都关联了一个分数,能够获得分数最高(或最低)的前 N 个元素、获得指定分数范围内的元素等与分数有关的操作。
对比列表(共同):
  • 二者都是有序的
  • 二者都可以获得某一范围的元素
不同点:
列表
有序集合
通过链表实现的
使用散列表和跳跃表(Skip list)实现的
获取靠近两端的数据速度极快,它更加适合实现如“新鲜事”或“日志”这样很少访问中间元素的应用。
即使读取位于中间部分的数据速度也很快(时间复杂度是 O(log(N)))。
不能简单地调整某个元素的位置
有序集合可以(通过更改这个元素的分数)

命令

1、增加元素
ZADD key score member [score member …]
例如:zadd key1 100 a 120 b 其中,key1 是键名,a 的权重是 100,b 是 120
2、获得元素的分数:ZSCORE key member
3、获得排名在某个范围的元素列表:
ZRANGE key start stop [WITHSCORES]
ZREVRANGE key start stop [WITHSCORES]
4、增加某个元素的分数:ZINCRBY key increment member

常见问题

一:跨类型操作

在 Redis 中每个键都属于一个明确的数据类型,如通过 HSET 命令建立的键是散列类型,通过 SET 命令建立的键是字符串类型等等。
使用一种数据类型的命令操作另一种数据类型的键会提示错误:"ERR Operation against a key holding the wrong kind of value"

二:竞态条件

比如对于 INCR 命令。如果自己写的话,就要通过 api,来组装。思路是:get、plus、set。
假设多个客户端并发,同一时刻 get 读取到 num 为 0,client a 做 plus 1 操作,client b 做 plus 1 操作,那么最终 num 是 1,而不是 2。
利用 redis 内置的命令(例如 INCR),或者通过 redis 事务,可以避免这种情况