redis学习

最近学习了一段时间的redis,以下是笔记,欢迎各位大佬们留言评论,若有不对的地方请指出,我会及时更正!蟹蟹大家!

目录:

1.redis简介

2.redis丰富的数据结构

3.redis事务、分布式锁

4.持久化

5.reids存储使用的数据模型

6.redis淘汰策略

7.redis底层数据类型介绍


redis简介

基于内存存储的非关系型数据库、

性能强劲、单线程运作、请求入队

支持的数据结构丰富:string、list、hash、set、zset

支持RDB和AOF持久化


redis支持的数据结构:string

set key value

setnx key value

setex key seconds value

exists key

get key

mget key1 key2 …

mset k1 v1 k2 v2 …

incr key

getset key value

pttl key

.....................................

redis支持的数据结构:hash

hset key field value

hsetnx key value 如果field存在则不改变

hget key field

hdel key fidle1 field2 …

hlen key 返回字段个数

hmget key f1 f2 …

hmset key f1 v1 f2 v2 …

hexists key field

hkeys key

hvals key

hgetall key

hincrby key field

hincrbyfloat key

field

..............................................

Ps:哈希类型的内部编码有ziplist 和 hashtable

当哈希元素小于hash-max-ziplist-entries配置、同时所有值都小于hash-max-ziplist-value配置,就会利用ziplist这样更节省内存    /etc/redis/redis.conf

object encoding key 可以查看数据的编码,我们可以发现,当超过上述两个配置的值后,编码会发生改变

redis支持的数据结构:list

lpush key v1 v2 …

rpush key v1 v2 …

lrange start end 0 -1查找所有

linsert key before/after value

lindex key index -1返回最后一个

llen key

lpop key

rpopkey 

lremkey count value  

…………………........................

Ps:内部编码有ziplist 和 linkedlist

当list元素小于list-max-ziplist-entries配置、同时所有值都小于list-max-ziplist-value配置,就会利用ziplist这样更节省内存

Redis3.2版本新增了quicklist编码,以ziplist为节点的linkedlist,结合了两者的优势

redis支持的数据结构:set

set:无索引、无重复、无序

sadd key v1 v2 …

srem key v1 v2 …

scard key 计算元素个数

sismember key element 判断元素是否在集合中

spop key 随机弹出元素

smembers key 返回所有元素

sinter key1 key2 返回两个集合交集

sunion key1 key2 返回两个集合并集 

sdiff key1 key2 返回两个集合差集,顺序影响结果

…………………..................

Ps:内部编码有intset 和 hashtable

当set集合元素小于set-max-intset-entries配置默认512个且都是整数,就会利用intset这样更节省内存,当数量没有达到,但是其中只要有一个元素不是整数,编码都会变为hashtable

redis支持的数据结构:zset

zset:元素有分数作为排序依据、无重复

zadd key score member …

zcard key 计算成员个数

zscore key member 返回这个成员分数

zrank key member 从低到高返回排名

zrevrank key member 从高到低返回排名,从0开始算的

zrem key member 移除元素

zincrby key increment member 给元素增加分数

zrange key start end 返回排名的成员从低到高 

zrevrange key start end 返回排名的成员反之

zcount key min max 返回指定分数范围元素个数

zremrangebyscore key min max 删除指定分数范围成员

…………………..................................

Ps:内部编码有ziplist 和 skiplist

当zset集合元素个数小于zset-max-ziplist-entries配置默认128,且每个元素的值都小于zset-max-ziplist-value默认64字节,就会使用ziplist编码,否则编码都会变为skiplist,因为超过设置值,读写效率就会下降

redis事务

1.multi 事务开始

2.一个事务需要执行的操作,例如多条命令行

3.exec结束事务;discard取消事务

redis事务不支持回滚,只要事务开始到事务提交,期间只要有命令执行成功,就会改变,所以redis提供了watch命令解决这个问题

1.watch key

2.multi

3.命令…

4.exec提交事务

watch代表监听一个key,执行事务的时候如果这个key发生了改变,事务执行就不成功,返回nil,这个时候需要人工干预

redis分布式锁

这些命令是分布式锁需要用到的命令,具体的流程如图所示

setnx key value 返回1则代表拿到锁,返回0则代表没有拿到锁

expire key timeout 为key设置一个超时时间,防止出现锁永远不被释放的情况

del key 释放锁

getset key

value


redis持久化

rdb

RDB持久化是把当前进程数据生成快照保存到硬盘的过程,触发RDB持久化过程分为手动触发和自动触发。

手动:save bgsave,执行save命令的时候会阻塞redis直到RDB完成为止;bgsave则是fork出子线程完成RDB操作,不会阻塞redis,只是在fork子线程会阻塞,这个时间不会很长;

自动:在配置文件中有默认save 900 1 save 300 10 save 60 10000,只要满足这三个其中的任意一个都会执行自动bgsave;

redis的save m n 是通过serverCron,dirty,lastsave时间戳来实现的;

serverCron检查配置文件、

dirty计数器记录数据库一共执行了多少次修改,执行bgsave会置零

lastsave是记录上次执行bgsave的时间

当前时间-lastsave>m&&dirty>=n

RDB文件载入工作是在服务器启动时自动执行,AOF优先级高于RDB,所以如果要使用RDB就要关闭AOF,redis载入RDB文件期间,redis处于阻塞状态,直到载入完成为止;

aof

AOF持久化是将每次redis执行的命令记录起来,类似于mysqlbinlog,redis重启时执行aof文件中的命令来恢复数据

配置文件开启appendonly yes ,aof是自动记录,aof执行流程;

1.命令追加:将命令追加到缓冲区aof_buf,这是为了避免磁盘io导致性能降低;

2.文件写入和文件同步:缓冲区的文件同步策略参数由appendfsync控制

Everysec,默认,每次的命令都写入aof文件中,但是每秒执行一次文件同步操作;

Always:每次的命令写入aof文件中,并且执行文件同步操作,速度最慢但是最安全;

No:每次命令写入aof文件中,但是由操作系统决定何时执行文件同步,速度最快但是不安全; 

3.文件重写:子线程执行,不影响主线程,目的主要是消除重复命令,过期的数据,减少aof文件的大小;

redis数据模型

涉及到内存分配器(如jemalloc)、简单动态字符串(SDS)、5种对象类型及内部编码、redisObject。

下图是执行set hello world时,涉及到的数据模型

dictEntry:每个键值对都会有一个dictEntry,里面存储了指向key和value的指针,next指向下一个dictEntry;

Key:并不是直接存储hello,而是存储在sds结构中;

Value:redisObject,redis支持的五种数据类型都是通过redisObject来存储的,type代表类型,ptr指向对象所在地址,字符串类型的值虽然通过redisObject包装,但是仍然通过sds来存储;


Jemalloc:redis内存分配器有三种,libc、jemalloc、tcmalloc,默认是jemalloc,在64位系统中,将内存分为,小,大,巨大三个级别,每个级别又有很多区域,redis存储数据时,会找最合适的区域来存储;

RedisObject:类似于这样的属性RedisObject(type, lru, redis, refcount, encoding)

type,表示对象的类型,也就是redis支持的数据结构,占4个比特;

encoding,表示对象的内部编码,占4个比特;

lru,记录了对象最后一次被命令访问的时间,对比这个时间和当前时间可以得出这个对象的空转,从而在redis内存回收机制是-lru的时候,会优先选择空转时间最长的对象进行释放,4.0版本占24比特,2.6版本占22比特;

refcount,表示该对象被引用的次数,整型,初始化系对象为1,被新的调用,+1,当对象不再被新的调用,-1,如果为0,则释放该对象,refcount>1被称为共享对象,因为出现重复的对象,redis不会重复创建;

ptr,指向具体的数据,比如字符串就指向sds;

SDS:简单动态字符串(simple dynamic string),SDS(len, free, buf)

Len:表示buf已经使用的长度

Free:表示buf未使用的长度

Buf:字节数组

与C字符串类似的是,buf也是以’\0’作为结尾;

redis淘汰策略

noeviction: 不删除策略, 达到最大内存限制时, 如果需要更多内存, 直接返回错误信息。

allkeys-lru: 所有key通用; 优先删除最近最少使用(less recently used ,LRU) 的 key。

volatile-lru: 只限于设置了 expire 的部分; 优先删除最近最少使用(less recently used ,LRU) 的 key。

allkeys-random: 所有key通用; 随机删除一部分 key。volatile-random: 只限于设置了 expire 的部分; 随机删除一部分 key。

volatile-ttl: 只限于设置了 expire 的部分; 优先删除剩余时间(time to live,TTL) 短的key。

redis简单正则查询key

合理的运用一些正则符号,比如  *  ?  []    减少去全量查找产生的内存开销

keys hell* 可以查到到比如 hello helloo   *代表一位或者多位

keys hell? 可以查找到比如 hello hella     ?代表一位

keys hel[lo]o可以查到hello heloo     []里面填的什么内容就会在这个数组里面匹配,里面也可以放正则表达式,比如[a-zA-Z]

redis数据类型详解

linkedList:

linkedList:双向列表的每个数据节点都有两个指针,分别指向前面一个节点和后一个节点,因此从双向列表中的每一个节点都很容易获取前一个节点和后一个节点;

这个是linkedList的数据结构


特点:访问快速,从头部或者尾部插入元素快,时间复杂度为o(1),自带链表长度的属性,所以得出链表长度的时间复杂度为o(1);

zipList:

适用于存储小的整数值或者比较简短的字符串,如果超过redis的配置,会自动转换为linkedlist;

之所以达到了压缩的效果,是因为存储的原理避开了内存碎片,它占用的是一大块内存,每一个entry都是连续再一起的,而linkedlist是通过指针来指向的,首先指针会占内存,内存分配器分配内存的时候并不是数据多大就分配多大内存,而是分配一块合适这个数据的内存空间,也造成了内存浪费;

压缩的原理:entry里面的prevrawlen属性会记录前一个entry占用的字节总数,如果前一个entry的长度小于254字节,那么prevrawlen属性就会用1个字节的空间保存这个长度值,反之上一个entry大于等于254,就会用5个字节保存这个值;

弊端:连锁更新效应,假设现在有一个ziplist,有10个entry,每个entry的大小都是253,那么每个prevrawlen的都是占用1个字节,但是我现在插入了一条255的entry,这个时候新entry的后一个entry的prevrawlen属性就需要扩大,导致这个entry的大小变了,又导致后面的也变了,一直变到最后一个entry,这样子就一直连续在做内存分配操作,时间复杂度大大提升,最坏的情况是o(N^2)

intset:



创建一个set集合的时候,首先会指定一个默认编码,默认是INTSET_ENC_INT16

执行插入新元素的时候,会根据value得到合适的编码,然后比较当前集合的编码,如果不满足就对集合进行升级;

如果满足,先判断集合元素是否存在,如果存在就直接返回,如果不存在,扩大集合空间,选新的内存地址,添加新元素;

intset内部只有”编码升级”的过程,没有”降级”的操作。当将唯一一个高位元素从将集合移除时,此时,集合不会转换为低位编码集合。

hashtable:


table属性是一个数组,里面存储的都是一个指向dictEntry的指针,而每个dictEntry都有一个next指向下一个元素的指针属性,如果出现键哈希值相同的情况,会被分到同一个索引上,然后它们通过next就形成了一个单向链表,从而解决了哈希冲突的问题;

Set应用场景:它的特性是无序,不重复,求交集、并集、差集很方便;适用于存储用户粉丝,计算共同好友;

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