Redis学习

Reids说明

对于Reids来说单CPU的性能更优于多CPU,因为CPU缓存(L1,L2,L3)一致性的问题涉及到CPU之间的通性

支持的数据结构

  • string
  • hashMap
  • list
  • set
  • zSet
    使用type查看key是哪种类型,使用encoding判断是什么对象类型,可以知道底层使用的哪种数据结构
    所有的value都是RedisObject对象。
    Redis为什么快?
    1、完全基于内存,绝大部分请求是纯粹的内存操作,非常快速
    2、采用单线程,避免了不必要的上下文切换和竞争条件,并且不需要考虑锁的问题
    3、使用多路I/O复用模型,非阻塞IO
    4、采用多种合适的优化的数据结构,比如字符串存储使用sds等
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;

(encoding表示 ptr 指向的具体数据结构,即这个对象使用了什么数据结构作为底层实现)
encoding的取值,如图:


image.png

不同的数据类型,底层存储结构:


image.png

(Redis的List类型中多了一种quickList,在3.2之后)

Reids底层存储结构(value)

String

底层以int、raw、embstr作为结构存储,redis中规定了string的最大长度为512M
什么时候使用什么类型?

  • 如果一个字符串对象保存的是整数值,并且这个整数值可以用 long 类型标识,那么字符串对象会讲整数值保存在 ptr 属性中,并将 encoding 设置为 int


    image.png
  • 如果字符串对象保存的是一个字符串值,并且这个字符串的长度大于 32 字节,那么字符串对象将使用一个简单动态字符串(SDS)来保存这个字符串值,并将对象的编码设置为 raw


    image.png
  • 如果字符串对象保存的是一个字符串值,并且这个字符串的长度小于等于 32 字节,那么字符串对象将使用 embstr 编码的方式来保存这个字符串。


    image.png

    既然有了 raw 的编码方式,为什么还会有 embstr 的编码方式呢?
    因为 embstr 的编码方式有一些优点,如下:

  • embstr 编码将创建字符串对象所需的内存分配次数从 raw 编码的两次降低为一次。

  • 释放 embstr 编码的字符串对象只需要调用一次内存释放函数,而释放 raw 编码的字符串对象需要调用两次内存释放函数。

  • 因为 embstr 编码的字符串对象的所有数据都保存在一块连续的内存里面,所以这种编码的字符串对象比起 raw ,编码的字符串对象能够更好地利用缓存带来的优势。

sds结构说明

struct sdshdr {
            // 记录buf数组中已使用字节的数量,等于SDS所保存字符串的长度
            int len;
            // 记录buf数组中未使用字节的数量   
            int free;
            // 字节数组,用于保存字符串
            char buf[];
        }

如:


image.png

为什么使用SDS这种结构,而不是直接存字符串?


image.png

缺点:占用无用内容,典型的用空间换时间

HashMap

哈希对象的编码有两种,分别是:ziplist、hashtable。
当哈希对象保存的键值对数量小于 512,并且所有键值对的长度都小于 64 字节时,使用压缩列表存储;否则使用 hashtable 存储。


image.png

image.png

HashMap渐进式扩容?


image.png

List

列表对象的编码有两种,分别是:ziplist、linkedlist
ziplist(压缩列表)主要是为节省内存而设计的内存结构,它的优点就是节省内存,但缺点就是比其他结构要消耗更多的时间,所以 Redis 在数据量小的时候使用压缩列表存储。

当列表的长度小于 512,并且所有元素的长度都小于 64 字节时,使用压缩列表存储;否则使用 linkedlist 存储。


image.png

image.png

考虑到链表的附加空间相对太高,prev 和 next 指针就要占去 16 个字节 (64bit 系统的指针是 8 个字节),另外每个节点的内存都是单独分配,会加剧内存的碎片化,影响内存管理效率。后续版本对列表数据结构进行了改造,使用 quicklist 代替了 ziplist 和 linkedlist.
quickList 是 zipList 和 linkedList 的混合体,它将 linkedList 按段切分,每一段使用 zipList 来紧凑存储,多个 zipList 之间使用双向指针串接起来。


image.png

Set

集合对象的编码有两种,分别是:intset、hashtable
intset(整数集合)主要是为节省内存而设计的内存结构,它的优点就是节省内存,但缺点就是比其他结构要消耗更多的时间,所以 Redis 在数据量小的时候使用整数集合存储。

当集合的长度小于 512,并且所有元素都是整数时,使用整数集合存储;否则使用 hashtable 存储。


image.png

ZSet

有序集合对象的编码有两种,分别是:ziplist、skiplist
当有序集合的长度小于 128,并且所有元素的长度都小于 64 字节时,使用压缩列表存储;否则使用 skiplist 存储。


image.png

image.png
image.png

AOF

AOF策略就是每次执行修改命令的时候都将命令写到AOF文件中,AOF是有缓存的,什么时候真正落文件,Redis提供了三种策略
redis通过appendfsync配置提供了三种写盘的方式:

  • appendfsync=always,每次修改事件都将aof buffer的内容写到aof文件并同步aof文件,这种同步策略的安全性最高,效率最低,发生系统奔溃时最多丢失一个事件循环的数据。
  • appendfsync=everysec,每次修改都aof buffer内容写到aof文件,每秒同步一次aof文件,这种同步策略与每次修改都同步的策略相比,安全性差一些,但性能高一些,是性能与安全性的折中,发生系统奔溃时最多会丢失1s的数据。
  • appendsync=no,每次修改都将aof buffer内容写到aof文件,同步动作的进行时机交给操作系统来决定,redis不管,这种安全性最低,但性能最好。操作系统系统一般考虑繁忙程度以及其它一些因素综合判断同步时机。

AOF重写

AOF随着操作的增加会越来越大,就需要重写(把对一个key的多条操作合并成一条)来减少文件的大小


image.png

Redis通过fork一个子进程来进行文件的重写,在重写的过程中如果有新的操作,则会把操作记录写两份,一份在源AOF的缓存区(避免重写失败导致数据的丢失),一份在重写缓存区,重写完成后将重写缓存区的信息写入重写文件,将原来的文件进行替换

在重写过程中,fork子进程以及重写完成后进行合并替换都会阻塞Reids的主线程的操作

为什么开启子进程而不是线程?
线程的创建和销毁会比子进程快的多,但是子进程会更稳定些,对于需要频繁创建和销毁的场景可以使用线程,如果追求稳定,使用子进程比较合适

内存快照(RDB)

AOF只要不是设置为always策略,对性能不会造成太大影响,但是由于记录的是命令而不是实际数据,所以AOF在恢复的时候就会比较缓慢

内存快照就是指内存中的数据在某一时刻的状态记录,类似于照片,快照对于恢复数据很友好但会有两个问题

  • 对哪些数据做快照?关系到执行效率的问题
  • 做快照时,数据还能增删改查吗?关系到Reids是否被阻塞
  • 多久做一次快照

对哪些数据做快照?
Redis数据都是在缓存,为了提供可靠性必须对所有数据进行快照,执行全量快照

Reids提供两种快照方法

  • SAVE 在主线程中执行会导致阻塞
  • BGSAVE 创建子进程,专门用于写入RDB文件,避免阻塞,也是默认的配置

做快照时数据可以修改吗?
读操作不用关心,和写快照没有冲突,写操作时Reids借助操作系统提供的写时复制技术,在执行快照的同时正常处理写操作(COW)

多久做一次快照?
如果太频繁会影响主进程导致Reids性能下降,如果时间长则会丢失的数据比较多,所以这个时间需要根据具体情况来定,不好把控,Reids4.0提出了一个混合使用AOF和内存快照的方法,简单的来说,内存快照以一定的频率执行,在两次快照之间使用AOF记录这期间的操作(建议在实践中使用)

缓存淘汰策略

参考二八原则,缓存设置比较合理是在总数据量的15%-30%,不过缓存写满是不可避免的,Redis又有哪些淘汰策略?


image.png
  • noevction策略不会淘汰数据,在写满后再有写请求时,报错
  • volatile-ttl 在筛选时,对越早过期的越优先删除
  • volatile-random 在设置了过期时间的键值对中进行随机删除
  • volatile-lru 使用LRU算法对设置了过期时间的键值对中删除
  • volatile-lfu 使用LFU算法对设置了过期时间的键值对中删除
  • allkeys-random 所有键值对随机删除
  • allkeys-lru 使用LRU对所有键值对删除
  • allkeys-lfu 使用LFU对所有键值对删除

LRU和LFU都需要链表来记录最新访问或最频繁访问的数据,这样会对性能造成影响,Reids的做法是在ReidsObject中记录了时间和次数,在淘汰的时候随机选一批进行LFU或者LRU的淘汰,不会维护整个链表,所以是不公平的淘汰策略

LRU的时间字段和LFU的次数都是用一个字段来保存的,只使用了8bit来保存访问次数(最大255),在实现LFU的时候并没有采用每次访问都把对应的counter的值加一,而是,采用一种算法,在访问到一定的量级才counter的值会到某个值

算法源码

double r = (double)rand()/RAND_MAX;
...
double p = 1.0/(baseval*server.lfu_log_factor+1);
if (r < p) counter++;

次数和counter的对应关系


image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,482评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,377评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,762评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,273评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,289评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,046评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,351评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,988评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,476评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,948评论 2 324
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,064评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,712评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,261评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,264评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,486评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,511评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,802评论 2 345

推荐阅读更多精彩内容