Redis学习个人总结

学习心得,记录于此。自己能随时查漏补缺,也望诸君不吝赐教,批评指正。同时有好的工作机会可以联系一下我。

1.Redis的六大数据类型详细用法

1.string数据类型:字符串

key-value,value最大存储512M,二进制安全,SDS底层数据结构,setnx实现分布式锁
主要命令:set,get,mset,mget,setnx,incr,decr,incrby,decrby
典型应用:
一、计数
  由于Redis单线程的特点,我们不用考虑并发造成计数不准的问题,通过 incrby 命令,我们可以正确的得到我们想要的结果。
二、限制次数
  比如登录次数校验,错误超过三次5分钟内就不让登录了,每次登录设置key自增一次,并设置该key的过期时间为5分钟后,每次登录检查一下该key的值来进行限制登录。

简单动态字符串

对象:int len(等于 SDS 保存字符串的长度),int free(记录 buf 数组中未使用字节的数量),char buf [] (字节数组,用于保存字符串)。
好处:空间预分配,惰性空间释放,二进制安全。

2.hash数据类型:哈希

1.hash 是一个键值对集合,是一个 string 类型的 key和 value 的映射表,key 还是key,但是value是一个键值对(key-value)。类比于 Java里面的 Map<String,Map<String,Object>> 集合。
2.主要命令:hset,hget,hdel,hexists,hgetall,hincrby,hkeys,hlen,hmset,hvals
3.典型应用:
查询的时间复杂度是O(1),用于缓存一些信息。

3.list数据类型:列表

1.list 列表,它是简单的字符串列表,按照插入顺序排序,你可以添加一个元素到列表的头部(左边)或者尾部(右边),它的底层实际上是个链表。有序可重复。
一、栈
 通过命令 lpush+lpop
二、队列
 命令 lpush+rpop
三、有限集合
 命令 lpush+ltrim
四、消息队列
 命令 lpush+brpop

链表实现

Redis链表特性:
  ①、双端:链表具有前置节点和后置节点的引用,获取这两个节点时间复杂度都为O(1)。
  ②、无环:表头节点的 prev 指针和表尾节点的 next 指针都指向 NULL,对链表的访问都是以 NULL 结束。  
  ③、带链表长度计数器:通过 len 属性获取链表长度的时间复杂度为 O(1)。
  ④、多态:链表节点使用 void* 指针来保存节点值,可以保存各种不同类型的值。

4.set数据类型:集合

Redis 的 set 是 string 类型的无序集合。无序不重复。
典型应用:
利用集合的交并集特性,比如在社交领域,我们可以很方便的求出多个用户的共同好友,共同感兴趣的领域等。

5.zset数据类型:有序集合

sorted set ,有序,不可重复
典型应用:
和set数据结构一样,zset也可以用于社交领域的相关业务,并且还可以利用zset 的有序特性,还可以做类似排行榜的业务。

6.Redis5.0新数据结构-stream:类似kafka消息队列

Redis的作者在Redis5.0中,放出一个新的数据结构,Stream。Redis Stream 的内部,其实也是一个队列,每一个不同的key,对应的是不同的队列,每个队列的元素,也就是消息,都有一个msgid,并且需要保证msgid是严格递增的。在Stream当中,消息是默认持久化的,即便是Redis重启,也能够读取到消息。那么,stream是如何做到多播的呢?其实非常的简单,与其他队列系统相似,Redis对不同的消费者,也有消费者Group这样的概念,不同的消费组,可以消费同一个消息,对于不同的消费组,都维护一个Idx下标,表示这一个消费群组消费到了哪里,每次进行消费,都会更新一下这个下标,往后面一位进行偏移。

7.底层数据小结

大多数情况下,Redis使用简单字符串SDS作为字符串的表示,相对于C语言字符串,SDS具有常数复杂度获取字符串长度,杜绝了缓存区的溢出,减少了修改字符串长度时所需的内存重分配次数,以及二进制安全能存储各种类型的文件,并且还兼容部分C函数。
  通过为链表设置不同类型的特定函数,Redis链表可以保存各种不同类型的值,除了用作列表键,还在发布与订阅、慢查询、监视器等方面发挥作用(后面会介绍)。
  Redis的字典底层使用哈希表实现,每个字典通常有两个哈希表,一个平时使用,另一个用于rehash时使用,使用链地址法解决哈希冲突。
  跳跃表通常是有序集合的底层实现之一,表中的节点按照分值大小进行排序。
  整数集合是集合键的底层实现之一,底层由数组构成,升级特性能尽可能的节省内存。
  压缩列表是Redis为节省内存而开发的顺序型数据结构,通常作为列表键和哈希键的底层实现之一。

8.RDB持久化

RDB是Redis用来进行持久化的一种方式,是把当前内存中的数据集快照写入磁盘,也就是 Snapshot 快照(数据库中所有键值对数据)。恢复时是将快照文件直接读到内存里。
RDB 有两种触发方式,分别是自动触发和手动触发(bgsave)。
停用RDB,命令为sava " "。
优点:只有一个dump.rdb,方便持久化,容灾性好,性能最大化,数据大的时候比Aof好
缺点:持久化的时候宕机会产生数据丢失。

9.AOF持久化

将Rdis执行的每次写操作记录到单独的日志文件中,重启redis就会将持久化的日志文件中恢复。当两种方式同时开启,redis优先使用AOF恢复。
优点:数据安全,不会收宕机影响,
缺点:Aof文件比RDB大,恢复比较慢,数据大的时候比RDB效率低。
如果Redis被当做缓存使用,使用一致性哈希实现动态扩容缩容。

10.Redis的过期键删除

Redis使用惰性过期和定期过期两种过期策略。
惰性过期:只有当访问一个key时,才会判断该key是否已过期,过期则清除。该策略可以最大化地节省CPU资源,却对内存非常不友好。极端情况可能出现大量的过期key没有再次被访问,从而不会被清除,占用大量内存。

定期过期:每隔一定的时间,会扫描一定数量的数据库的expires字典中一定数量的key,并清除其中已过期的key。该策略是前两者的一个折中方案。通过调整定时扫描的时间间隔和每次扫描的限定耗时,可以在不同情况下使得CPU和内存资源达到最优的平衡效果。
(expires字典会保存所有设置了过期时间的key的过期时间数据,其中,key是指向键空间中的某个键的指针,value是该键的毫秒精度的UNIX时间戳表示的过期时间。键空间是指该Redis集群中保存的所有键。)

11.内存淘汰策略

1.redis内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略。
2.内存淘汰策略用于处理内存不足时的需要申请额外空间的数据
Redis的内存淘汰策略是指在Redis的用于缓存的内存不足时,怎么处理需要新写入且需要申请额外空间的数据。
全局的键空间选择性移除
noeviction:当内存不足以容纳新写入数据时,新写入操作会报错。
allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的key。(这个是最常用的)
allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个key。
设置过期时间的键空间选择性移除
volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的key。
volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个key。
volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的key优先移除。

12.Redis的事务

1.Redis 事务的本质是通过MULTI、EXEC、WATCH等一组命令的集合。事务支持一次执行多个命令,一个事务中所有命令都会被序列化。在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中。
总结说:redis事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令。
事务三个阶段:事务开始MULTI,命令入队,事务执行。执行过程中,服务器收到EXEC,DISCARD,WATCH,MULTI之外的请求,就会把请求放到队列中排。
2.Redis事务总是天然隔离的。
3.Redis事务的其他实现
基于lua脚本的内的命令都是一次性,按顺序执行的。

13.哨兵模式

哨兵是 redis 集群机构中非常重要的一个组件,主要有以下功能:
集群监控:负责监控 redis master 和 slave 进程是否正常工作。
消息通知:如果某个 redis 实例有故障,那么哨兵负责发送消息作为报警通知给管理员。
故障转移:如果 master node 挂掉了,会自动转移到 slave node 上。
配置中心:如果故障转移发生了,通知 client 客户端新的 master 地址。

哨兵的核心知识

2.哨兵至少需要 3 个实例,来保证自己的健壮性。
哨兵 + redis 主从的部署架构,是不保证数据零丢失的,只能保证 redis 集群的高可用性。
对于哨兵 + redis 主从这种复杂的部署架构,尽量在测试环境和生产环境,都进行充足的测试和演练。

14.Redis Cluster(服务端路由查询)

1.Redis Cluster是一种服务端Sharding技术,3.0版本开始正式提供。Redis Cluster并没有使用一致性hash,而是采用slot(槽)的概念,一共分成16384个槽。将请求发送到任意节点,接收到请求的节点会将查询请求发送到正确的节点上执行
2.实现方案
一.通过哈希的方式,将数据分片,每个节点均分存储一定哈希槽(哈希值)区间的数据,默认分配了16384 个槽位
二.每份数据分片会存储在多个互为主从的多节点上
三.数据写入先写主节点,再同步到从节点(支持配置为阻塞同步)
四.同一分片多个节点间的数据不保持一致性
五.读取数据时,当客户端操作的key没有分配在该节点上时,redis会返回转向指令,指向正确的节点
六.扩容时时需要需要把旧节点的数据迁移一部分到新节点。
优点
无中心架构,支持动态扩容,对业务透明。
客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。
高性能,客户端直连redis服务,免去了proxy代理的损耗。
缺点
运维也很复杂,数据迁移需要人工干预
只能使用0号数据库
不支持批量操作(pipeline管道操作)

15.基于代理服务器分片

1.客户端发送请求到一个代理组件,代理解析客户端的数据,并将请求转发至正确的节点,最后将结果回复给客户端
2.优点
透明接入,业务程序不用关心后端Redis实例,切换成本低
Proxy 的逻辑和存储的逻辑是隔离的
代理层多了一次转发,性能有所损耗
3.开源方案:豌豆荚开源的Codis

16.Redis 主从架构

单机的 redis,能够承载的 QPS 大概就在上万到几万不等。对于缓存来说,一般都是用来支撑读高并发的。因此架构做成主从(master-slave)架构,一主多从,主负责写,并且将数据复制到其它的 slave 节点,从节点负责读。所有的读请求全部走从节点。这样也可以很轻松实现水平扩容,支撑读高并发。

17.生产环境中的 redis 是怎么部署的?

redis cluster,10 台机器,5 台机器部署了 redis 主实例,另外 5 台机器部署了 redis 的从实例,每个主实例挂了一个从实例,5 个节点对外提供读写服务,每个节点的读写高峰qps可能可以达到每秒 5 万,5 台机器最多是 25 万读写请求/s。

机器是什么配置?32G 内存+ 8 核 CPU + 1T 磁盘,但是分配给 redis 进程的是10g内存,一般线上生产环境,redis 的内存尽量不要超过 10g,超过 10g 可能会有问题。

5 台机器对外提供读写,一共有 50g 内存。

因为每个主实例都挂了一个从实例,所以是高可用的,任何一个主实例宕机,都会自动故障迁移,redis 从实例会自动变成主实例继续提供读写服务。

你往内存里写的是什么数据?每条数据的大小是多少?商品数据,每条数据是 10kb。100 条数据是 1mb,10 万条数据是 1g。常驻内存的是 200 万条商品数据,占用内存是 20g,仅仅不到总内存的 50%。目前高峰期每秒就是 3500 左右的请求量。

18.Redis实现分布式锁

1.SETNX实现分布式锁。给锁设置合理的过期时间。
2.推荐还是用zookeeper临时有序节点实现分布式锁。
RedLock
Redis 官方站提出了一种权威的基于 Redis 实现分布式锁的方式名叫 Redlock,此种方式比原先的单节点的方法更安全。它可以保证以下特性:

安全特性:互斥访问,即永远只有一个 client 能拿到锁

避免死锁:最终 client 都可能拿到锁,不会出现死锁的情况,即使原本锁住某资源的 client crash 了或者出现了网络分区

容错性:只要大部分 Redis 节点存活就可以正常提供服务

19.缓存异常

缓存雪崩

过期时间设置随机,防止同一时间大量数据过期。

缓存穿透

接口层面进行校验:用户鉴权校验等等。
布隆过滤器,将所有可能存在的数据hash到一个足够大的bitmap中,一个一定不存在的数据一定会被拦截掉。
布隆过滤器:它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。
Bloom-Filter算法的核心思想就是利用多个不同的Hash函数来解决“冲突”

缓存击穿

设置的热点数据不过期,加锁也行。

缓存预热

将和系统强相关的数据加载到缓存系统中。定时刷新缓存。

缓存降级

Redis出现问题,不去数据库查询,而是直接返回默认值给用户。

20.如何保证缓存与数据库双写时的数据一致性?

一般来说,就是如果你的系统不是严格要求缓存+数据库必须一致性的话,缓存可以稍微的跟数据库偶尔有不一致的情况,最好不要做这个方案,读请求和写请求串行化,串到一个内存队列里去,这样就可以保证一定不会出现不一致的情况
还有一种方式就是可能会暂时产生不一致的情况,但是发生的几率特别小,就是先更新数据库,然后再删除缓存。

假如Redis里面有1亿个key,其中有10w个key是以某个固定的已知的前缀开头的,如果将它们全部找出来?

使用keys指令可以扫出指定模式的key列表。

对方接着追问:如果这个redis正在给线上的业务提供服务,那使用keys指令会有什么问题?

这个时候你要回答redis关键的一个特性:redis的单线程的。keys指令会导致线程阻塞一段时间,线上服务会停顿,直到指令执行完毕,服务才能恢复。这个时候可以使用scan指令,scan指令可以无阻塞的提取出指定模式的key列表,但是会有一定的重复概率,在客户端做一次去重就可以了,但是整体所花费的时间会比直接用keys指令长。

Redis如何实现延时队列

使用sortedset,使用时间戳做score, 消息内容作为key,调用zadd来生产消息,消费者使用zrangbyscore获取n秒之前的数据做轮询处理。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值