Redis知识点
2021-11-29 17:03:28 0 举报
AI智能生成
登录查看完整内容
为你推荐
查看更多
Redis缓存相关知识点
作者其他创作
大纲/内容
网络IO的本质是socket的读取,socket在linux系统被抽象为流,IO可以理解为对流的操作,对于一次IO访问(以read举例),数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间
第一阶段:等待数据准备 (Waiting for the data to be ready)。
第二阶段:将数据从内核拷贝到进程中
所以IO操作可以分为两部分
第一步:通常涉及等待网络上的数据分组到达,然后被复制到内核的某个缓冲区。
第二步:把数据从内核缓冲区复制到应用进程缓冲区。
对于IO的实现方式--socket 而言,也是两部分:
同步模型(synchronous IO)
异步IO(asynchronous IO)
阻塞IO(bloking IO)
非阻塞IO(non-blocking IO)
由于同步非阻塞方式需要不断主动轮询,轮询占据了很大一部分过程,轮询会消耗大量的CPU时间,而 “后台” 可能有多个任务在同时进行,人们就想到了循环查询多个任务的完成状态,只要有任何一个任务完成,就去处理它。如果轮询不是进程的用户态,而是有人帮忙就好了。那么这就是所谓的 “IO 多路复用”。UNIX/Linux 下的 select、poll、epoll 就是干这个的(epoll 比 poll、select 效率高,做的事情是一样的)
FD:File Descriptor,文件描述符,判断文件是否可读、可写。 IO多路复用的底层select 就是根据FD的状态来做判断的
多路复用IO(multiplexing IO)
信号驱动式IO(signal-driven IO)
IO模型的类型:
关于网络IO
Redis 使用数组作为其存储结构,value是数组元素,key是数组索引
typedef struct dictht { // 哈希表节点的指针数组 // key 的哈希值最终映射到这个数组的某个位置上 dictEntry **table;} dictht;
typedef struct dict { //(dict hash table)存储数据的 hash 表 // 数据在ht[0]中,ht[1]在 rehash 时会被使用 dictht ht[2]; } dict;
typedef struct redisDb { dict *dict; //存储了key和value dict *expires; //存储了key的过期信息 dict *watched_keys; //被wathch 的key int id; //数据库id .......} redisDb;
几个核心的数据结构
key 索引了 value 在内存中的位置,通过对客户端的 rehash 来存储或查找key
key在请求过来的时候会判断是否过期,过期会被移除
key
// 3.0struct sdshdr { unsigned int len;// 记录buf数组中已使用字节的数量,即SDS所保存字符串的长度 unsigned int free;// 记录buf数据中未使用的字节数量 char buf[];// 字节数组,用于保存字符串};
//3.0 之后会根据字符长度选择不同的构造static inline char sdsReqType(size_t string_size) { if (string_size < 1<<5) // 32 return SDS_TYPE_5; if (string_size < 1<<8) // 256 return SDS_TYPE_8; if (string_size < 1<<16) // 65536 64k return SDS_TYPE_16; if (string_size < 1ll<<32) // 4294967296 4G return SDS_TYPE_32; return SDS_TYPE_64;}
SDS(动态字符串)
string
typedef struct listNode { struct listNode *prev;// 前置节点 struct listNode *next;// 后置节点 void *value;// 节点值} listNode;
双向链表
list
typedef struct dictht { dictEntry **table;// 哈希表数组 unsigned long size;// 哈希表大小 unsigned long sizemask;// 哈希表大小掩码,用于计算索引值,等于size-1 unsigned long used;// 哈希表已有节点的数量} dictht;
字典
map
它内部的键值对是无序、唯一的。它的内部实现相当于一个特殊的字典,字典中所有的 value 都是一个值 NULL
类似hashset,他是一个value=null的字典
set
这个数据结构很复杂,zset用这个实现的
跳跃表
zset
value
数据结构
原因:Redis宕机或者缓存失效,大量请求会发送到数据库层,导致数据库层的压力激增。
解决方式:1、让缓存过期时间错开。2、通过服务降级让一部分请求返回默认值3、集群配置,防止所有节点宕机
缓存雪崩
原因:访问的某个数据,既不在缓存,也不再数据库,这种情况可能是:1、恶意攻击,专门访问数据库中没有的数据;2、业务请求的误操作,缓存和数据库中的数据都被误删除了,导致都没有数据;3、新业务上线时,缓存和数据库都没有用户的业务数据;
解决方式:1、设置空值或缺省值,防止不存在的数据访问到数据库2、使用布隆过滤器,对不存在的数据进行处理3、拦截恶意请求,前端/后端都可以做
缓存穿透
原因:某个热点数据的缓存失效,导致请求一直访问数据库
解决方式:这种请求一般是缓存到时间过期导致的,所以将相关数据的缓存设置为永不过期,就可以了
缓存击穿
控制 key 的长度:最简单直接的内存优化,就是控制 key 的长度。如果 key 数量达到了百万级别,那么,过长的 key 名也会占用过多的内存空间。
避免存储 bigkey如果大量存储 bigkey,也会导致 Redis 内存增长过快。
key的控制
Redis要注意的问题
这种加锁的思路是, key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作进行+1。
加锁和设置过期时间是分开的,不是原子性。如果没设置过期时间,这个锁会一直存在,后期操作会受影响。
INCR
如果 key 不存在,将 key 设置为 value如果 key 已存在,则 SETNX 不做任何动作返回0/1表示是否存在
用法-设置key名为lock的锁:加锁成功:setnx lock java -> 1加锁失败:setnx lock c++ -> 0设置过期时间100s:EXPIRE lock 100释放锁成功:del lock --> 1
SETNX
相对于setnx 增加了过期时间的设置,使得加锁和过期时间设置保持原子性
用法-用法-设置key名为lock的锁,30秒过期:加锁成功:setex lock 30 java -> OK解锁成功:del lock -> 1
SETEX
PSETEX key milliseconds value
同setex 不过这里用的是毫秒
PSETEX
2.6.12 版本可以使用set 调用nx、ex
set key value [EX seconds|PX milliseconds] [NX|XX] [KEEPTTL]
SET
Redis锁
详细的看下面的《关于网络IO》
在执行io操作,也就是网络读写的时候,是多线程这是基于IO多路复用,也就是reactor 模式的
请求作为FD
使用了事件处理器
Redis 服务采用 Reactor 的方式来实现文件事件处理器(每一个网络连接其实都对应一个文件描述符)
key的模糊检索会因为单线程的问题而阻塞,所以要使用scan
在网络请求和IO操作部分使用的是多线程,在执行命令方面使用的是单线程
redis 线程分两部分
Redis线程
缓存
分布式锁
全页缓存(FPC)
排行榜/计数器
会话过期
会话缓存(Session Cache)
redis业务上的使用
Redis
0 条评论
回复 删除
下一页