> For the complete documentation index, see [llms.txt](https://books.innohub.top/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://books.innohub.top/redis/info/01-overview.md).

# Redis 总览

Redis 是一个开源的K-V内存性数据库，是构建高性能可伸缩的应用的合适的解决方案。Redis以下三个特性使它与众不同：

* 完全的内存型存储，仅使用磁盘进行持久化
* 与其他内存型数据库相比又分为丰富的数据结构
* 支持数据主从备份 master-slave

## 1. Redis 优势

* **速度较快**： 可以进行110k op/s Sets 操作，81k op/s Gets 操作
* **丰富的数据结构**：*String, Hash, list, set, sorted set*, bit arrays, HyperLogLogs, Stream
* **原子操作**: 所有操作都是原子的，线程安全
* **多用途**： 可以用于很多案例，例如缓存、消息队列、应用中的任何短时数据

## 2. 数据类型

Redis 支持5种数据类型，String, Hash, List, Set, Sorted Set

| 类型          | 简介                                       | 特性                                                     | 场景                           |
| ----------- | ---------------------------------------- | ------------------------------------------------------ | ---------------------------- |
| String      | 二进制安全                                    | 可以包含任何数据，例如图片或者序列化对象。一个键值最大存储512M                      |                              |
| Hash        | 键值对集合                                    | 适合存储对象，可以一次只修改一个属性值（Memcached 中需要去除整个字符串，反序列化后，再次进行设置) | 存储。读取修改对象属性                  |
| List        | 双向链表                                     | 增删快，提供了操作某一段元素的API                                     | 消息队列，最新消息排行                  |
| Set         | 基于Hash表实现，不重复元素集合                        | <p>1. 添加，查找，删除元素的复杂度都是O(1) <br>2. 提供了交并补集的操作</p>       |                              |
| Sorted  Set | 有序集合，Set集合中的每一个元素添加一个Score参数，元素按照score排序 | 数据插入时已经进行了天然排序                                         | <p>1. 排行榜<br>2. 带权重的消息队列</p> |

### 2.1 String 相关用法

String 是最为基础的Redis数据类型，二进制安全，可以用于表示任意数据，最大容量512Mb，String常用操作如下:

* **GET**: 获取一个key对应的value
* **SET**： 设置或替换一个key对应的value，可以用`set K V nx`, 只有键值不存在时可以set成功，`set K V xx`只有键值存在时可以set成功。可以使用`EX`, `PX`设置键值过期时间，分别对应秒级以及毫秒级单位。
* **INCR/DECR/INCRBY/DECRBY**: 对于用String形式的数字，可以使用原子自增系列的命令，进行原子操作。*Redis没有专用的整数类型，所有的数字操作基于string进行*，存储在键值中的字符串被解释为以10为基的64为带符号数来执行操作，该系列命令不可以操作超出范围的值。
* **APPEND**: 在一个key对应的String的value上附加另外一个String, 如果该键值不存在，则直接设置key对应的值。返回追加后的字符串的长度。

  ```
  append 命令的一个典型应用场景是用于固定时间序列的存储。可以用于表示固定大小的样本列表，配合 STRLEN 获取字符串长度，使用 GETRANGE 对于字符串进行随机访问，其中左右标都是包含的，使用 SETRANGE key offset value ，将偏离下为offset的位置开始进行字符串替换。

  这种模式的主要问题在于，无法方便的把时间序列且分为固定长度的数据，可以使用加了时间戳的键值，使用多个key进行存储，避免处理较大的键值，同时方便分布式多实例操作。
  ```
* **GETBIT/SETBIT/BITCOUNT**: 进行bit位操作，获取或者设置一个offset对应的比特值。返回原来存储在offset的bit值

  ```
  需要注意的是如果设置最后一个位置的bit值时，该键值不存在或者字符串占用的空间小于512M，redis需要分配所有的中间空间，可能需要一定的时间。第一次分配后，之后再进行setbit不会进行内存分配操作。
  ```
* `GETRANGE/SETRANGE`:用于获取或者设置string值的子字符串，`getrange KEY start end`获取\[start, end]偏移量中的子字符串, 可以使用负值作为偏移量，-1代表最后一个位置，以此类推，但是start一定是位于前面的偏移量。`setrange KEY offset VALUE` 从offset开始重写KEY对应的值的子字符串，如果offset大于value 的长度，中间的位置使用0字节占位。
* `MSET/MSETNX/MGET`:设置或者获取多个键值，MSETNX对于存在的键值不进行设置

### 2.2 Lists

Lists是简单字符串的双向列表，按照插入顺序排列，可以使用`LPUSH`从列表头插入元素，使用`RPUSH`从列表尾插入元素，对于一个空的键值进行操作时，创建一个新的List，一个List的最大元素数是$2^{32} -1$。List的主要优势是对于链表头尾附近的元素可以有常数时间级的插入删除时间。但是对于列表中部的元素，复杂度为O(N)，常用操作：

* 构建一个基于时间线的数据存储链表，使用LRANGE获取最新时间戳的数据
* 使用LPUSH以及LTRIM创建一个固定长度的List，`LTRIM KEY start end`, 仅保留对应的List的start到end的元素, 如果start > end ，则返回一个空列表
* `RPOPLPUSH` : redis通常用作消息传递服务器，以实现对于后台作业或者其他类型消息传递任务的处理。通常会使用一种简单的队列形式，将值Push到生产者队列，然后消费者轮询(RPOP)进行消费。但是在消费过程中，由于网络原因或者消费者崩溃，很可能出现消息丢失。为了构建一个可信队列，可以使用`RPOPLPUSH`指令，消费生产者队列的同时将元素插入一个处理队列，当客户端消费完毕，从处理队列中删除该元素 (lrem KEY count value); 同时有一个额外客户端监控处理队列，将长时间停留的元素重新插入到生产者队列。

### 2.3 Sets

Set是string的无序集合，可以在O(1)的时间复杂度插入、删除、校验元素是否存在。

* 使用Set进行唯一性校验，对于一个网站独立IP的page view量，可以使用`SADD`将一个元素加入到set中
* 支持集合的所有操作，`SINTER` 进行交集操作，`SUNION`并集，`SDIFF` 进行多个集合差集操作；`SCARD` 获取集合元素数量，
* 随机获取元素，可以使用SPOP, SRANDMEMBER

### 2.4 Hash

Redis hash类型是string 到string的哈希表，用于表示对象具有天然优势。

```
HSET key field value
HMSET key f1 v1 f2 v2...
HGET key field
HMGET key f1 f2
HDEL key field ...
HLEN key
HKEYS key
HVALS key
```

### 2.5 Sorted sets

与Redis集合类似，有序集合也是不重复的string集合，但是每一个元素都与一个分数相关联。可以使用`ZADD key [NX|XX] [CH] [INCR] score member [score member...]` 添加元素，并且指定score。

### 2.1 redis 键值规范

* 避免使用过长的键值，查找键值需要较大的开销，占用较大内存、带宽。对于一定要使用较长的键值的场景，可以使用hash后的值（例如sha1）
* 避免使用过短的键值，提高可读性
* 定义键值需要根据一定的规范，不同字段使用冒号隔开
* 键值最大不超过512M
