Redis(基础)——Redis集群架构与数据存储

1、简介

Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。

2、Redis集群架构

2.1、Replication+Sentinel

在这里插入图片描述
Sentinel的作用:

  • 监控:监控主服务器和从服务器是否运行正常
  • 通知:当某个Redis服务器出现异常后,能够及时向管理员或者其他程序发送通知
  • 自动的故障转移
    在这里插入图片描述
  • 通过选举将某个slave升级为master,原master的其他slave修改为新master的slave
  • 根据Sentinel配置(client-reconfig-script)动态修改VIP(虚拟IP),将VIP指向新的master
  • 客户端修改连接
  • 老的master如重启成功,变成新master的slave

缺点在于主从切换过程中会丢失数据,只能够实现单点写,不能水平扩容

2.2、Proxy+Replication+Sentinel

以Twemproxy为例:
在这里插入图片描述

  • 前端使用Twemproxy+KeepAlived做代理,将其后端的多台Redis实例分片进行统一管理与分配
  • 每一个分片节点的Slave都是Master的副本且只读
  • Sentinel监控每个分片节点的Master,当Master出现故障时,Sentinel会发出通知/启动自动故障转移
  • Sentinel 可以在发生故障转移动作后触发相应脚本(通过 client-reconfig-script 参数配置 ),脚本获取到最新的Master来修改Twemproxy配置

缺点:

  • 部署麻烦,不易运维
  • 可扩展性差,进行扩缩容需要手动干预

2.3、Redis Cluster

在这里插入图片描述

3、Redis数据存储

Redis的数据存储涉及到内存分配器如jemalloc、简单动态字符串SDS、redisObject以及五种对象类型及内部编码等等。

3.1、jemalloc

Redis编译时候会指定内存分配器,默认是jemalloc;在64位的操作系统中,jemalloc将内存空间划分成小、大、巨大三个范围;每个范围内又被划分成了许多小的内存块单位;当Redis存储数据时候就会选择最合适的内存块进行存储。
在这里插入图片描述

3.2、redisObject

typedef struct redisObject {
  unsigned type:4;
  unsigned encoding:4;
  unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */
  int refcount;
  void *ptr;
} robj;

type字段:表示的是对象的类型占四个bit;其中包括REDIS_STRING(字符串)、REDIS_LIST (列表)、REDIS_HASH(哈希)、REDIS_SET(集合)、REDIS_ZSET(有序集合)。

encoding:表示对象内部编码占四个bit;比如字符串对象,有int、embstr、raw三种编码;encoding属性优点是可以根据不同场景去设置不同的编码,从而可提高Redis的灵活性和效率。

Lru字段:最后一次被命令访问的时间,4.0版本占24bit;

refCount:记录该对象被引用的次数,整型,4Byte;作用主要是引用计数与内存回收

ptr字段:指向具体数据的指针,如set hello world,ptr指向包含world的SDS

在这里插入图片描述
小结:redisObject的结构和对象类型、编码、内存回收、共享对象都有关系。一个redisObject对象的大小是16个字节:4bit+4bit+24bit+4Byte+8Byte=16Byte

3.3、SDS

redis没有直接使用C字符串,而是使用了SDS(Simple Dynamic String,简单动态字符串),结构如下:

struct sdshdr {
    int len;    // buf已使用的长度
    int free;   // buf未使用的长度
    char buf[]; // 字节数组,用来存储字符串
};

占用空间:
free所占长度+len所占长度+ buf数组的长度=4+4+free+len+1 = free+len+9 字节。
在这里插入图片描述

4、五种数据类型和内部编码

redis支持5种对象类型,每种结构都有多种编码方式,其优点在于接口与实现分离,当需要增加或改变内部编码时,用户使用不受影响,另一方面可以根据不同的应用场景切换内部编码,提高效率。
在这里插入图片描述

4.1、string:用于缓存、计数器、分布式锁等。

  1. 字符串是redis中最基本的数据类型,所有的键(key)都是字符串类型,且字符串外其他几种复杂类型的元素也是字符串;长度不超过512M;
  2. 三种内部编码:
    a、int:8个字节的长整型。字符串值是整型时,这个值使用long整型表示。
    b、embstr:<=39字节的字符串。embstr与raw都使用redisObject和sds保存数据,区别在于,embstr的使用只分配一次内存空间(因此redisObject和sds是连续的),而raw需要分配两次内存空间(分别为redisObject和sds分配空间)。因此与raw相比,embstr的好处在于创建时少分配一次空间,删除时少释放一次空间,以及对象的所有数据连在一起,寻找方便。而embstr的坏处也很明显,如果字符串的长度增加需要重新分配内存时,整个redisObject和sds都需要重新分配空间,因此redis中的embstr实现为只读。
    c、raw:大于39个字节的字符串

4.2、hash:用于用户信息、Hash 表等。

  1. 哈希(作为一种数据结构),不仅是redis对外提供的5种对象类型的一种(与字符串、列表、集合、有序结合并列),也是Redis作为Key-Value数据库所使用的数据结构。为了说明的方便,在本文后面当使用“内层的哈希”时,代表的是redis对外提供的5种对象类型的一种;使用“外层的哈希”代指Redis作为Key-Value数据库所使用的数据结构。
  2. 内部编码
    a. 压缩列表(ziplist):用于元素个数少、长度小的场景;优势在于集中存储,节省空间;操作复杂度O(n);
    使用条件:元素数量小于512,且所有键值字符串的长度都小于64Byte;
    b. 哈希表(hashtable):
    在这里插入图片描述
    从上到下依次是:
    dictEntry
typedef struct dictEntry{
    void *key;                     // 键,8Byte
    union{
        void *val;
        uint64_tu64;
        int64_ts64;
    }v;                           // 值,指针、64位整型或无符号64位整型,8Byte
    struct dictEntry *next;       // 指向next,用于解决hash冲突问题,8Byte
}dictEntry;   

bucket:数组,各元素是指向dictEntry的指针,大小取2^n
dictht

typedef struct dictht{
    dictEntry **table;           // 指向bucket的指针
    unsigned long size;          // 记录bucket的大小
    unsigned long sizemask;      // size-1
    unsigned long used;          // 已使用的dictEntry的数目
}dictht;

dict

typedef struct dict{
    dictType *type;            // 适应不同类型的键值对
    void *privdata;            // 适应不同类型的键值对
    dictht ht[2];              // 数据存在ht[0]中,ht[1]在rehash时使用
    int trehashidx;            // 用于rehash
} dict;

4.3、list:用于表、队列、微博关注人时间轴列表等。

  1. 列表(list)用来存储多个有序的字符串,每个字符串称为元素;一个列表可以存储2^32-1个元素。Redis中的列表支持两端插入和弹出,并可以获得指定位置(或范围)的元素,可以充当数组、队列、栈等
  2. 内部编码
    双端链表:
    在这里插入图片描述

双端链表同时保存了表头指针和表尾指针,并且每个节点都有指向前和指向后的指针;
链表中保存了列表的长度;
dup、free和match与节点值类型设置有关,链表可以用于保存各种不同类型的值。
链表中每个节点指向的是type为字符串的redisObject。

压缩链表:
优点是节省内存空间,缺点是不方便进行修改或插入删除操作;在节点数较少时使用,条件同hash使用压缩列表的条件,节点数量多时还是使用双端链表;

4.4、set:用于去重、赞、踩、共同好友等

  1. 集合(set)与列表类似,都可以用来保存多个字符串,但集合与列表有两点不同:集合中的元素是无序的,因此不能通过索引来操作元素;集合中的元素不能有重复。一个集合中最多可以存储2^32-1个元素;除了支持常规的增删改查,Redis还支持多个集合取交集、并集、差集。
  2. 内部编码
    a.哈希表(hashtable):类似hash中使用的hashtable,区别在于值有key,值全部被置为null
    b.整数集合:适用于元素数量较小的情况,优势是集中存储,节省空间,操作复杂度O(n);使用条件是元素数量小于512,且所有元素都是整数;
typedef struct intset{
    uint32_t encoding;             // contents中存储内容的类型
    uint32_t length;               // contents中元素个数
    int8_t contents[];             // 实际存储的值是int16_t、int32_t或int64_t
} intset;
  1. 单向编码转换:整数集合转化为哈希表

4.4、zset(sorted set,有序集合):用于访问量排行榜和点击量排行榜等

  1. 有序集合与集合一样,元素都不能重复;但与集合不同的是,有序集合中的元素是有顺序的。与列表使用索引下标作为排序依据不同,有序集合为每个元素设置一个分数(score)作为排序依据。
  2. 内部编码
    a. 压缩列表(ziplist):同列表和hash
    b. 跳表(skiplist):支持平均O(logN),最坏O(N)的节点查找;跳表实现由zskiplist和zskiplistNode两个结构组成:前者用于保存跳跃表信息(如头结点、尾节点、长度等),后者用于表示跳跃表节点;
#define ZSKIPLIST_MAXLEVEL 32 //最大层数
#define ZSKIPLIST_P 0.25      //P

typedef struct zskiplistNode {
    robj *obj;
    double score;
    struct zskiplistNode *backward;        //后向指针
    struct zskiplistLevel {
        struct zskiplistNode *forward;     //每一层中的前向指针
        unsigned int span;                 //x.level[i].span 表示节点x在第i层到其下一个节点需跳过的节点数。注:两个相邻节点span为1
    } level[];
} zskiplistNode;

typedef struct zskiplist {
    struct zskiplistNode *header, *tail;       // 头节点,尾节点
    unsigned long length;                      // 节点总数
    int level;                                 // 表内节点的最大层数
} zskiplist;

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值