IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 大数据 -> Redis核心设计原理 -> 正文阅读

[大数据]Redis核心设计原理

深入底层C源码

1.Redis K-V 底层设计原理
2.Redis 渐进式rehash及动态扩容机制
3.Redis核心编码结构精讲
4.亿级用户日活统计BitMap实战及源码分析

Redis 基本特性

1. 非关系型的键值对数据库,可以根据键以O(1) 的时间复杂度取出或插入关联值

2. Redis 的数据是存在内存中的

3. 键值对中键的类型可以是字符串,整型,浮点型等,且键是唯一的

4. 键值对中的值类型可以是string,hash,list,set,sorted set 等

5. Redis 内置了复制,磁盘持久化,LUA脚本,事务,SSL,? ACLs,客户端缓存,客户端代理等功能

6. 通过Redis哨兵和Redis Cluster 模式提供高可用性

缓存

?

?

Redis应用场景

计数器
可以对 String 进行自增自减运算,从而实现计数器功能。Redis 这种内存型数据库的读写性能非常高,很适合存储频繁读写的计数量。

分布式ID生成
利用自增特性,一次请求一个大一点的步长如 incr 2000 ,缓存在本地使用,用完再请求。

海量数据统计
位图(bitmap):存储是否参过某次活动,是否已读谋篇文章,用户是否为会员, 日活统计。

会话缓存
可以使用 Redis 来统一存储多台应用服务器的会话信息。当应用服务器不再存储用户的会话信息,也就不再具有状态,一个用户可以请求任意一个应用服务器,从而更容易实现高可用性以及可伸缩性。

分布式队列/阻塞队列
List 是一个双向链表,可以通过 lpush/rpush 和 rpop/lpop 写入和读取消息。可以通过使用brpop/blpop 来实现阻塞队列。

分布式锁实现
在分布式场景下,无法使用基于进程的锁来对多个节点上的进程进行同步。可以使用 Redis 自带的 SETNX 命令实现分布式锁。

热点数据存储
最新评论,最新文章列表,使用list 存储,ltrim取出热点数据,删除老数据。

社交类需求
Set 可以实现交集,从而实现共同好友等功能,Set通过求差集,可以进行好友推荐,文章推荐。

排行榜
sorted_set可以实现有序性操作,从而实现排行榜等功能。

延迟队列
使用sorted_set,使用 【当前时间戳 + 需要延迟的时长】做score, 消息内容作为元素,调用zadd来生产消息,消费者使用zrangbyscore获取当前时间之前的数据做轮询处理。消费完再删除任务 rem? key? member

---------------------------------------------------------------------------------------------------------

String

String 常用API

/> help @string

/> SET/GET
/> SETNX
/> GETRANGE/SETRANGE

/> INCR/INCRBY/DECR/DECRBY

/> GETBIT/SETBIT/BITOPS/BITCOUNT

/> MGET/MSET

数据结构

redis 3.2 以前
struct sdshdr {
??? int len;
??? int free;
??? char buf[];
};

redis 3.2 后

typedef char *sds;

struct __attribute__ ((__packed__)) sdshdr5 {
??? unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
??? char buf[];
};
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 {
........

sdshdr5

?sdshdr8

?

#define SDS_TYPE_5? 0
#define SDS_TYPE_8? 1
#define SDS_TYPE_16 2
#define SDS_TYPE_32 3
#define SDS_TYPE_64 4

static inline char sdsReqType(size_t string_size) {
??? if (string_size < 32) ?
??????? return SDS_TYPE_5;
??? if (string_size < 0xff) //2^8 -1 ?
??????? return SDS_TYPE_8;
??? if (string_size < 0xffff) // 2^16 -1 ?
??????? return SDS_TYPE_16;
??? if (string_size < 0xffffffff)? // 2^32 -1
??????? return SDS_TYPE_32;
??? return SDS_TYPE_64;
}

RedisDb 数据结构

typedef struct redisDb {
??? dict *dict;???????????????? ?
??? dict *expires;???????? ?
??? dict *blocking_keys;???????? ?
??? dict *ready_keys;????????? ?
??? dict *watched_keys;??????? ?
??? int id;???????????????????? ?
??? long long avg_ttl;????????? ?
??? unsigned long expires_cursor; ?
??? list *defrag_later;???????? ?
} redisDb;

typedef struct dict {
??? dictType *type;
??? void *privdata;
??? dictht ht[2];
??? long rehashidx;
??? unsigned long iterators; ?
??? } dict;

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;

typedef struct redisObject {
??? unsigned type:4;
??? unsigned encoding:4;
??? unsigned lru:LRU_BITS; ?
??? int refcount;
??? void *ptr;
} robj;

List

List常用API

/> help @list

?
LPUSH key element [element ...]
RPOP key
RPUSH key element [element ...]
LPOP key
BLPOP key [key ...] timeout
BRPOP key [key ...] timeout
BRPOPLPUSH source destination timeout
RPOPLPUSH? source destination
LINDEX key index
LLEN key
LINSERT key BEFORE|AFTER pivot element
LRANGE key start stop
LREM key count element
LSET key index element
LTRIM key start stop

List是一个有序(按加入的时序排序)的数据结构,Redis采用quicklist(双端链表) 和 ziplist 作为List的底层实现。

可以通过设置每个ziplist的最大容量,quicklist的数据压缩范围,提升数据存取效率

list-max-ziplist-size? -2??????? //? 单个ziplist节点最大能存储? 8kb? ,超过则进行分裂,将数据存储在新的ziplist节点中
list-compress-depth? 1??????? //? 0 代表所有节点,都不进行压缩,1, 代表从头节点往后走一个,尾节点往前走一个不用压缩,其他的全部压缩,2,3,4 ... 以此类推

ziplist

?

zlbytes:32bit,表示ziplist占用的字节总数。
zltail:??? 32bit,表示ziplist表中最后一项(entry)在ziplist中的偏移字节数。通过zltail我们可以很方便地找到最后一项,从而可以在ziplist尾端快速地执行push或pop操作
zlen:???? 16bit, 表示ziplist中数据项(entry)的个数。
entry:表示真正存放数据的数据项,长度不定
zlend: ziplist最后1个字节,是一个结束标记,值固定等于255。
prerawlen: 前一个entry的数据长度。
len: entry中数据的长度
data: 真实数据存储

robj *createZiplistObject(void) {
    unsigned char *zl = ziplistNew();
    robj *o = createObject(OBJ_LIST,zl);
    o->encoding = OBJ_ENCODING_ZIPLIST;
    return o;
}

 unsigned char *ziplistNew(void) {
    unsigned int bytes = ZIPLIST_HEADER_SIZE+ZIPLIST_END_SIZE;
    unsigned char *zl = zmalloc(bytes);
    ZIPLIST_BYTES(zl) = intrev32ifbe(bytes);
    ZIPLIST_TAIL_OFFSET(zl) = intrev32ifbe(ZIPLIST_HEADER_SIZE);
    ZIPLIST_LENGTH(zl) = 0;
    zl[bytes-1] = ZIP_END;
    return zl;
}

robj *createObject(int type, void *ptr) {
    robj *o = zmalloc(sizeof(*o));
    o->type = type;
    o->encoding = OBJ_ENCODING_RAW;
    o->ptr = ptr;
    o->refcount = 1;
    if (server.maxmemory_policy & MAXMEMORY_FLAG_LFU) {
        o->lru = (LFUGetTimeInMinutes()<<8) | LFU_INIT_VAL;  
    } else {
        o->lru = LRU_CLOCK();   // 获取 24bit 当前时间秒数
    }
    return o;
}

quicklist

?

robj *createQuicklistObject(void) {
    quicklist *l = quicklistCreate();
    robj *o = createObject(OBJ_LIST,l);
    o->encoding = OBJ_ENCODING_QUICKLIST;
    return o;
}

quicklist *quicklistCreate(void) {
    struct quicklist *quicklist;

    quicklist = zmalloc(sizeof(*quicklist));
    quicklist->head = quicklist->tail = NULL;
    quicklist->len = 0;
    quicklist->count = 0;
    quicklist->compress = 0;
    quicklist->fill = -2;
    quicklist->bookmark_count = 0;
    return quicklist;
}

typedef struct quicklist {
    quicklistNode *head;
    quicklistNode *tail;
    unsigned long count;       
    unsigned long len;           
    int fill : QL_FILL_BITS;                
    unsigned int compress : QL_COMP_BITS;  
    unsigned int bookmark_count: QL_BM_BITS;
    quicklistBookmark bookmarks[];
} quicklist;

typedef struct quicklistNode {
    struct quicklistNode *prev;
    struct quicklistNode *next;
    unsigned char *zl;
    unsigned int sz;            
    unsigned int count : 16;    
    unsigned int encoding : 2;    
    unsigned int container : 2;  
    unsigned int recompress : 1; 
    unsigned int attempted_compress : 1; 
    unsigned int extra : 10;  
} quicklistNode;

Hash

Hash常用API

/> help? @hash
HSET key field value [field value ...]
HGET key field
HMGET key field [field ...]
HKEYS key
HGETALL key
HVALS key
HEXISTS key field
HDEL key field [field ...]
HINCRBY key field increment
HINCRBYFLOAT key field increment
HLEN key
HSCAN key cursor [MATCH pattern] [COUNT count]
HSETNX key field value
HSTRLEN key field

Hash 数据结构底层实现为一个字典( dict ),也是RedisBb用来存储K-V的数据结构,当数据量比较小,或者单个元素比较小时,底层用ziplist存储,数据大小和元素数量阈值可以通过如下参数设置。

hash-max-ziplist-entries? 512??? //? ziplist 元素个数超过 512 ,将改为hashtable编码
hash-max-ziplist-value??? 64????? //? 单个元素大小超过 64 byte时,将改为hashtable编码

Set

Set 为无序的,自动去重的集合数据类型,Set 数据结构底层实现为一个value 为 null 的 字典( dict ),当数据可以用整形表示时,Set集合将被编码为intset数据结构。两个条件任意满足时
Set将用hashtable存储数据。

1, 元素个数大于 set-max-intset-entries ,

2 , 元素无法用整形表示
set-max-intset-entries 512?????? // intset 能存储的最大元素个数,超过则用hashtable编码

intset

typedef struct intset {
    uint32_t  encoding;
    uint32_t  length;
    int8_t      contents[];
} intset; 
 
#define INTSET_ENC_INT16 (sizeof(int16_t))
#define INTSET_ENC_INT32 (sizeof(int32_t))
#define INTSET_ENC_INT64 (sizeof(int64_t))

整数集合是一个有序的,存储整型数据的结构。整型集合在Redis
中可以保存int16_t,int32_t,int64_t类型的整型数据,并且可以保证
集合中不会出现重复数据。

encoding: 编码类型
length: 元素个数
contents[]: 元素存储

Set常用API

/> help? @set


? SADD key member [member ...]???????????? ?
? SCARD key??????????????????????????????????????????????? ?
? SISMEMBER key member
? SPOP key [count]
? SDIFF key [key ...]
? SINTER key [key ...]
? SUNION key [key ...]
? SMEMBERS key
? SRANDMEMBER key [count]
? SREM key member [member ...]
? SMOVE source destination member
? SUNIONSTORE destination key [key ...]
? SDIFFSTORE destination key [key ...]
? SINTERSTORE destination key [key ...]
? SSCAN key cursor [MATCH pattern] [COUNT count]

ZSet

ZSet? 为有序的,自动去重的集合数据类型,ZSet 数据结构底层实现为 字典(dict) + 跳表(skiplist) ,当数据比较少时,用ziplist编码结构存储。

?

zset-max-ziplist-entries? 128??? // 元素个数超过128 ,将用skiplist编码
zset-max-ziplist-value???? 64???? //? 单个元素大小超过 64 byte, 将用 skiplist编码

Zset 数据结构

 //?创建zset?数据结构:?字典?+?跳表
robj?*createZsetObject(void)?{
????zset?*zs?=?zmalloc(sizeof(*zs));
????robj?*o;
????//?dict用来查询数据到分数的对应关系,?如?zscore?就可以直接根据?元素拿到分值?
????zs->dict?=?dictCreate(&zsetDictType,NULL);
????
????//?skiplist用来根据分数查询数据(可能是范围查找)
????zs->zsl?=?zslCreate();
????//?设置对象类型?
????o?=?createObject(OBJ_ZSET,zs);
????//?设置编码类型?
????o->encoding?=?OBJ_ENCODING_SKIPLIST;
????return?o;
typedef?struct?zskiplistNode?{
????sds?ele;
????double?score;
????struct?zskiplistNode?*backward;
????struct?zskiplistLevel?{
????????struct?zskiplistNode?*forward;
????????unsigned?long?span;
????}?level[];
}?zskiplistNode;
typedef?struct?zskiplist?{
????struct?zskiplistNode?*header,?*tail;
????unsigned?long?length;
????int?level;
}?zskiplist;
typedef?struct?zset?{
????dict?*dict;
????zskiplist?*zsl;
}?zset;

skiplist

ZSet常用API

/> help? @sorted_set

? ZADD key [NX|XX] [CH] [INCR] score member [score member ...]
? ZCARD key
? ZCOUNT key min max
? ZINCRBY key increment member
? ZRANGE key start stop [WITHSCORES]
? ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
? ZRANK key member
? ZREM key member [member ...]
? ZREMRANGEBYRANK key start stop
? ZREMRANGEBYSCORE key min max
? ZREVRANGE key start stop [WITHSCORES]
? ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]
? ZREVRANK key member
? ZSCAN key cursor [MATCH pattern] [COUNT count]
? ZSCORE key member

GeoHash算法

有空再说,太累了

  大数据 最新文章
实现Kafka至少消费一次
亚马逊云科技:还在苦于ETL?Zero ETL的时代
初探MapReduce
【SpringBoot框架篇】32.基于注解+redis实现
Elasticsearch:如何减少 Elasticsearch 集
Go redis操作
Redis面试题
专题五 Redis高并发场景
基于GBase8s和Calcite的多数据源查询
Redis——底层数据结构原理
上一篇文章      下一篇文章      查看所有文章
加:2021-12-07 12:05:45  更:2021-12-07 12:08:06 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 10:02:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码