一、Redis的一些特点
- 非关系型的键值对数据库,底层是hashtable,可以根据键以0(1)的时间复杂度取出或插入关联值
- Redis的数据基于内存存储的
- 键值对中键的类型可以是字符串,整型,浮点型等,且键是唯一的
- 键值对中的值类型可以是string, hash, list, set, sorted_set等
- Redis内置了复制,磁盘持久化,LUA脚本, 事务,SSL, ACLS,客户端缓存,客户端代理等功能
- 通过Redis哨兵和Redis Cluster模式提供高可用性
帮助命令查看详细使用说明:help @string
二、Redis k-v存储结构
源码解析
/* Redis database representation. There are multiple databases identified
* by integers from 0 (the default database) up to the max configured
* database. The database number is the 'id' field in the structure. */
typedef struct redisDb {
dict *dict; /* The keyspace for this DB */
dict *expires; /* Timeout of keys with a timeout set */
dict *blocking_keys; /* Keys with clients waiting for data (BLPOP)*/
dict *ready_keys; /* Blocked keys that received a PUSH */
dict *watched_keys; /* WATCHED keys for MULTI/EXEC CAS */
int id; /* Database ID */
long long avg_ttl; /* Average TTL, just for stats */
unsigned long expires_cursor; /* Cursor of the active expire cycle. */
list *defrag_later; /* List of key names to attempt to defrag one by one, gradually. */
} redisDb;
typedef struct dict {
dictType *type;
void *privdata;
dictht ht[2];
long rehashidx; /* rehashing not in progress if rehashidx == -1 */
unsigned long iterators; /* number of iterators currently running */
} dict;
typedef struct dictType {
uint64_t (*hashFunction)(const void *key);
void *(*keyDup)(void *privdata, const void *key);
void *(*valDup)(void *privdata, const void *obj);
int (*keyCompare)(void *privdata, const void *key1, const void *key2);
void (*keyDestructor)(void *privdata, void *key);
void (*valDestructor)(void *privdata, void *obj);
} dictType;
/* This is our hash table structure. Every dictionary has two of this as we
* implement incremental rehashing, for the old to the new table. */
typedef struct dictht {
dictEntry **table;
unsigned long size;
unsigned long sizemask;
unsigned long used;
} dictht;
typedef struct dictEntry {
void *key;
union {
void *val;
uint64_t u64;
int64_t s64;
double d;
} v;
struct dictEntry *next;
} dictEntry;
三、Redis Key的底层存储结构:SDS(Simple Dynamic String)
源码结构
// redis3.2之前数据结构:
struct sdshdr { // c语言struct结构体,相当于java的class
// buf中已使用长度,int是4byte 所以范围是 --> 0 ~ 2^32 - 1
unsigned int len;
// buf中未使用长度
unsigned int free;
// 保存字符串
char buf[];
}; // sds的扩容:新增后长度小于 1MB,新长度的2倍新增后长度大于 1MB ,新长度加上1MB源码
// Redis3.2之后共有五种类型的SDS(长度分别为小于5bit、1字节、2字节、4字节、8字节)。
struct __attribute__ ((__packed__)) sdshdr5 {
unsigned char flags; /* 低3位存储类型, 高5位存储长度 */
char buf[]; // len < 2^5
};
struct __attribute__ ((__packed__)) sdshdr8 {
uint8_t len; /* 已使用,1字节 */
uint8_t alloc; /* 总长度,用1字节存储 */
unsigned char flags; /* 低3位存储类型, 高5位预留 */
char buf[]; // len < 2^8
};
struct __attribute__ ((__packed__)) sdshdr16 {
uint16_t len; /* 已使用,2字节 */
uint16_t alloc; /* 总长度,用2字节存储 */
unsigned char flags; /* 低3位存储类型, 高5位预留 */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr32 {
uint32_t len; /* 已使用,4字节 */
uint32_t alloc; /* 总长度,用4字节存储 */
unsigned char flags; /* 低3位存储类型, 高5位预留 */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr64 {
uint64_t len; /* 已使用,8字节 */
uint64_t alloc; /* 总长度,用8字节存储 */
unsigned char flags; /* 低3位存储类型, 高5位预留 */
char buf[];
};
sdshdr5、sdshdr8数据结构图解
四、Redis value之string类型
查看value类型相关命令
# 1.查看value类型:
type [key]
# 2.查看value编码类型:
object encoding [key]
redis value 的存储结构源码
typedef struct redisObject {
unsigned type:4; // 4bit 类型:string、list、hash、set、zset
unsigned encoding:4; // 4bit 编码:int、embstr、raw、ziplist ...
unsigned lru:LRU_BITS; /* 24bit LRU time (relative to global lru_clock) or
* LFU data (least significant 8 bits frequency
* and most significant 16 bits access time). */
int refcount; // 4byte 引用计数法
void *ptr; // 8byte 实际数据指针
} robj; // 总空间:4bit + 4bit + 24bit + 4byte + 8byte = 16byte
type为string类型时,encoding可能为int、embstr、raw
如果redis val时整数,并且范围在8byte范围内,ptr指针存储的是实际的数据
验证:
当设置int为2^63 - 1时,value编码类型是int
当设置int为2^63时,value编码类型是embstr
> set int 9223372036854775807
OK
> object encoding int
"int"
> set int 9223372036854775808
OK
> object encoding int
"embstr"
如果redis val长度超过44,会变成raw类型
embstr范围分析:因为cpu缓存行时64byte,而redisObject占用16字节,ptr还最大可以使用sdshdr8类型存储,其中len,alloc,flags各占用1byte,buf结尾’\0’占用1byte,所以buf剩余空间最多存储64-16-4=44byte的数据,所以超过44长度时就会转成raw类型的数据,值得注意的是raw类型的值删减后不会回退为embstr
验证:
如果字符串的长度<=44,查看编码类型是embstr
如果字符串的长度>44,编码类型是raw
> set str 12345678901234567890123456789012345678901234
OK
> object encoding str
"embstr"
> set str 123456789012345678901234567890123456789012345
OK
> object encoding str
"raw"
五、Redis value类型之ziplist类型(未完待续…)