Redis HashTable 结构

结构 typedef struct dict { dictEntry **table; unsigned long size; unsigned long sizemask; unsigned long used; } dict; typedef struct dictEntry { void *key; union { void *val; uint64_t u64; int64_t s64; } v; struct dictEntry *next; } dictEntry; key: 键 val: 值,值可以是一个指针,也可以是 uint64_t 或 int64_t 类型的整数 next: 指向下一个节点,形成链表 哈希算法 // 使用字典设置的哈希函数,计算键 key 的哈希值 hash = dict->type->hashFunction(key); // 使用哈希表的 sizemask 属性和第一步得到的哈希值,计算索引值 index = hash & dict->ht[x].sizemask; 关注点 解决哈希冲突:拉链表,使用 *next 指向下一个具有相同索引值的哈希表节点 扩容和缩容:根据原哈希表已使用的空间扩大一倍或缩小一半 扩容条件: 没有执行 BGSAVE 或 BGREWRITEAOF 命令,且负载因子大于 1 在执行 BGSAVE 或 BGREWRITEAOF 命令,负载因子大于 5 渐进式 rehash:在 rehash 的过程中,新哈希表和旧哈希表同时存在,查询时先查询新哈希表,再查询旧哈希表,写入时只写入新哈希表

March 12, 2024

Redis QuickList 结构

结构 双向链表,每一个节点都是一个 ziplist /* Node, quicklist, and Iterator are the only data structures used currently. */ /* quicklistNode is a 32 byte struct describing a ziplist for a quicklist. * We use bit fields keep the quicklistNode at 32 bytes. * count: 16 bits, max 65536 (max zl bytes is 65k, so max count actually < 32k). * encoding: 2 bits, RAW=1, LZF=2. * container: 2 bits, NONE=1, ZIPLIST=2. * recompress: 1 bit, bool, true if node is temporarry decompressed for usage....

March 12, 2024

HTTPS

连接建立过程 基本流程如下: 客户端向服务器索要并验证服务器的公钥 双方协商产生对称密钥 双方采用对称密钥进行加密通信 TLS 的握手阶段涉及四次通信,使用不同的密钥交换算法,流程也会有所不同。下面以 RSA 密钥交换算法为例,介绍 HTTPS 连接建立过程。 Client Hello 客户端向服务器发送一个 Client Hello 消息,包含以下信息: 客户端支持的 TLS 版本 客户端生成的一个随机数(Client Random) 客户端支持的加密算法,如 RSA、DH、ECDH 等 Server Hello 服务器收到 Client Hello 消息后,向客户端发送一个 Server Hello 消息,包含以下信息: 服务器选择的 TLS 版本 服务器生成的一个随机数(Server Random) 服务器选择的加密算法 服务器的数字证书 客户端回应 客户端收到 Server Hello 消息后,会执行以下操作: 通过浏览器或者 OS 中的 CA 公钥验证服务器的数字证书 从服务器的数字证书中提取公钥,用于后续的通信 生成一个随机数(Pre-Master Secret),并使用服务器的公钥加密该随机数 向服务器发送消息,包含以下信息 加密后的 Pre-Master Secret 加密算法改变通知,表示后续的通信将使用对称密钥加密 客户端的 Finished 消息,包含一个验证数据,用于验证双方是否使用相同的密钥 服务器回应 服务器收到客户端的 Pre-Master Secret 后,会执行以下操作: 使用私钥解密 Pre-Master Secret 使用 Client Random、Server Random 和 Pre-Master Secret 生成对称密钥(Master Secret) 向客户端发送消息,包含以下信息 加密算法改变通知,表示后续的通信将使用对称密钥加密 服务器的 Finished 消息,包含一个验证数据,用于验证双方是否使用相同的密钥

March 1, 2024

HTTP 状态码

权威文档:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status 以下为补充的一些状态码 499 Client Closed Request 由 Nginx 定义的非标准状态码,表示客户端主动关闭了请求,导致服务器无法完成请求

March 1, 2024

Redis SDS 结构

介绍 SDS 全称为 Simple Dynamic String,用于存储二进制数据的一种结构,具有动态扩容、空间预分配、二进制安全等特性。Redis 中的字符串对象就是使用 SDS 结构实现的。 总体结构 struct __attribute__ ((__packed__)) sdshdr8 { uint8_t len; /* used */ uint8_t alloc; /* excluding the header and null terminator */ unsigned char flags; /* 3 lsb of type, 5 unused bits */ char buf[]; }; struct __attribute__ ((__packed__)) sdshdr16 { uint16_t len; /* used */ uint16_t alloc; /* excluding the header and null terminator */ unsigned char flags; /* 3 lsb of type, 5 unused bits */ char buf[]; }; struct __attribute__ ((__packed__)) sdshdr32 { uint32_t len; /* used */ uint32_t alloc; /* excluding the header and null terminator */ unsigned char flags; /* 3 lsb of type, 5 unused bits */ char buf[]; }; struct __attribute__ ((__packed__)) sdshdr64 { uint64_t len; /* used */ uint64_t alloc; /* excluding the header and null terminator */ unsigned char flags; /* 3 lsb of type, 5 unused bits */ char buf[]; }; len:记录 buf 中已使用的字节数 alloc:记录 buf 中已分配的字节数 flags:记录 buf 的类型,低 3 位表示类型,高 5 位未使用 buf:存储字符串的字节数组 优势 常数复杂度获取字符串长度:读取 len 字段即可,不需要遍历整个字符串 不存在缓冲区溢出问题:根据 len 和 alloc 字段,判断是否需要扩容 空间预分配,减少内存重分配次数:每次扩容都会多分配一些内存,减少内存重分配次数 二进制安全,可以存储任意二进制数据:以 len 字段的长度来判断字符串的结束,而不是以空字符 \0 来判断 兼容部分 C 字符串函数:遵从每个字符串的最后一个字节是空字符 \0 的惯例,可以使用部分 C 字符串函数 空间预分配 当执行字符串拼接操作时,如果字符串的长度超过了已分配的内存,Redis 会对字符串进行扩容。扩容的规则如下:...

February 29, 2024