> **"Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache and message broker."** —— Redis是一个开放源代码(BSD许可)的内存中数据结构存储,用作数据库,缓存和消息代理。 *(摘自官网)*
/* Note: sdshdr5 is never used, we just access the flags byte directly.
* However is here to document the layout of type 5 SDS strings. */
struct__attribute__((__packed__))sdshdr5{
unsignedcharflags;/* 3 lsb of type, and 5 msb of string length */
charbuf[];
};
struct__attribute__((__packed__))sdshdr8{
uint8_tlen;/* used */
uint8_talloc;/* excluding the header and null terminator */
unsignedcharflags;/* 3 lsb of type, 5 unused bits */
charbuf[];
};
struct__attribute__((__packed__))sdshdr16{
uint16_tlen;/* used */
uint16_talloc;/* excluding the header and null terminator */
unsignedcharflags;/* 3 lsb of type, 5 unused bits */
charbuf[];
};
struct__attribute__((__packed__))sdshdr32{
uint32_tlen;/* used */
uint32_talloc;/* excluding the header and null terminator */
unsignedcharflags;/* 3 lsb of type, 5 unused bits */
charbuf[];
};
struct__attribute__((__packed__))sdshdr64{
uint64_tlen;/* used */
uint64_talloc;/* excluding the header and null terminator */
unsignedcharflags;/* 3 lsb of type, 5 unused bits */
charbuf[];
};
```
你会发现同样一组结构 Redis 使用泛型定义了好多次,**为什么不直接使用 int 类型呢?**
因为当字符串比较短的时候,len 和 alloc 可以使用 byte 和 short 来表示,**Redis 为了对内存做极致的优化,不同长度的字符串使用不同的结构体来表示。**
### SDS 与 C 字符串的区别
为什么不考虑直接使用 C 语言的字符串呢?因为 C 语言这种简单的字符串表示方式 **不符合 Redis 对字符串在安全性、效率以及功能方面的要求**。我们知道,C 语言使用了一个长度为 N+1 的字符数组来表示长度为 N 的字符串,并且字符数组最后一个元素总是 `'\0'`。*(下图就展示了 C 语言中值为 "Redis" 的一个字符数组)*
跳跃表(skiplist)是一种随机化的数据结构,由 **William Pugh** 在论文[《Skip lists: a probabilistic alternative to balanced trees》](https://www.cl.cam.ac.uk/teaching/0506/Algorithms/skiplists.pdf)中提出,是一种可以于平衡树媲美的层次化链表结构——查找、删除、添加等操作都可以在对数期望时间下完成,以下是一个典型的跳跃表例子:
在客户端消费者读取 Stream 消息时,Redis 服务器将消息回复给客户端的过程中,客户端突然断开了连接,消息就丢失了。但是 PEL 里已经保存了发出去的消息 ID,待客户端重新连上之后,可以再次收到 PEL 中的消息 ID 列表。不过此时 `xreadgroup` 的起始消息 ID 不能为参数 `>` ,而必须是任意有效的消息 ID,一般将参数设为 `0-0`,表示读取所有的 PEL 消息以及自 `last_delivered_id` 之后的新消息。
**B 树最大的优势就是插入和查找效率很高**,如果用 B 树存储要统计的数据,可以快速判断新来的数据是否存在,并快速将元素插入 B 树。要计算基础值,只需要计算 B 树的节点个数就行了。
不过将 B 树结构维护到内存中,能够解决统计和计算的问题,但是 **并没有节省内存**。
### 第二种:bitmap
**bitmap** 可以理解为通过一个 bit 数组来存储特定数据的一种数据结构,**每一个 bit 位都能独立包含信息**,bit 是数据的最小存储单位,因此能大量节省空间,也可以将整个 bit 数据一次性 load 到内存计算。如果定义一个很大的 bit 数组,基础统计中 **每一个元素对应到 bit 数组中的一位**,例如: