Day128 全面理解Redis

Redis

基础原理

为什么为什么Redis是单线程的?

  1. 因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了。
  2. 用集群来提高计算能力。今天的计算环境中,即使是单机多线程的上限也往往不能满足需要了,需要进一步摸索的是多服务器集群化的方案,这些方案中多线程的技术照样是用不上的。

Redis单线程的优势?

  1. 代码更清晰,处理逻辑更简单
  2. 不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗
  3. 不存在多进程或者多线程导致的切换而消耗CPU。索然无法发挥多核CPU性能,不过可以通过在单机开多个Redis实例来完善;

Redis是单进程单线程的,为什么还这么快?

  1. 是redis是基于内存的,内存的读写速度非常快;
  2. redis是单线程的,省去了很多上下文切换线程的时间;
  3. redis使用多路复用技术,可以处理并发的连接。非阻塞IO 内部实现采用 epoll,采用了epoll+自己实现的简单的事件框架。epoll中的读、写、关闭、连接都转化成了事件,然后利用epoll的多路复用特性,绝不在io上浪费一点时间。

https://zhuanlan.zhihu.com/p/58038188

Redis如何解决key冲突:链地址,头插法。

  • 如果Redis有1亿个key,使用keys命令是否会影响线上服务?
  • keys命令:这个命令会返回匹配到符合表达式的所有key,时间复杂度为O(N)。
  • 上面是官方文档声明,KEYS命令不能用在生产的环境中,这个时候如果数量过大效率是十分低的。(在入门级的笔记本电脑上,Redis扫描100万条key只需要40毫秒,1亿条需要4s)

Redis 并发

就是如果你用redis缓存技术的话,肯定要考虑如何用redis来加多台机器,保证redis是高并发的,还有就是如何让Redis保证自己不是挂掉以后就直接死掉了,redis高可用

  • Redis 的并发竞争问题是什么?如何解决这个问题?
    所谓 Redis 的并发竞争 Key 的问题也就是多个系统同时对一个 key 进行操作,但是最后执行的顺序和我们期望的顺序不同,这样也就导致了结果的不同!

推荐一种方案:分布式锁(zookeeper 和 redis 都可以实现分布式锁)。(如果不存在 Redis 的并发竞争 Key 问题,不要使用分布式锁,这样会影响性能)

Redis实现分布式锁,简单来说就是设置一个key为lock的键值对,value作为锁标记,拿到锁之前先判断里面值是否为null(通过setnx指令),null的话就可以设置值并拿到锁,执行完后释放锁即删除值;不为null说明锁已被拿走,返回信息即可。这利用了redis单线程的特点,使得即使多个请求最终也只会有一个拿到锁。

基于zookeeper临时有序节点可以实现的分布式锁。大致思想为:每个客户端对某个方法加锁时,在zookeeper上的与该方法对应的指定节点的目录下,生成一个唯一的瞬时有序节点。 判断是否获取锁的方式很简单,只需要判断有序节点中序号最小的一个。 当释放锁的时候,只需将这个瞬时节点删除即可。同时,其可以避免服务宕机导致的锁无法释放,而产生的死锁问题。完成业务流程后,删除对应的子节点释放锁。

在实践中,当然是从以可靠性为主。所以首推Zookeeper。

如何保证 Redis 高并发、高可用?

  • redis高并发:主从架构,一主多从,一般来说,很多项目其实就足够了,单主用来写入数据,单机几万QPS,多从用来查询数据,多个从实例可以提供每秒10万的QPS。
  • redis高并发的同时,还需要容纳大量的数据:一主多从,每个实例都容纳了完整的数据,比如redis主就10G的内存量,其实你就最对只能容纳10g的数据量。如果你的缓存要容纳的数据量很大,达到了几十g,甚至几百g,或者是几t,那你就需要redis集群,而且用redis集群之后,可以提供可能每秒几十万的读写并发。
  • redis高可用:如果你做主从架构部署,其实就是加上哨兵就可以了,就可以实现,任何一个实例宕机,自动会进行主备切换。

Redis 事务的 CAS 方案

  • watch是一个非常实用的命令,基本所有的Linux发行版都带有这个小工具,如同名字一样,watch可以帮你监测一个命令的运行结果,省的你一遍遍的手动运行,在Linux下,watch是周期性的执行下个程序,并全屏显示执行的结果。你可以拿它来监测你想要的一切命令的结果变化,比如 tail 一个 log 文件,ls 监测某个文件的大小变化,看你的想象力了。
  • watch指令在redis事物中提供了CAS的行为。为了检测被watch的keys在是否有多个clients同时改变引起冲突,这些keys将会被监控。如果至少有一个被监控的key在执行exec命令前被修改,整个事物将会回滚,不执行任何动作,从而保证原子性操作,并且执行exec会得到null的回复。

https://www.cnblogs.com/baizhanshi/p/6393793.html
https://blog.csdn.net/ssllkkyyaa/article/details/84107474

常见问题

Redis常作为缓存来提高数据的查询效率,但一些情况请求会不经过缓存,落到数据库上,大量的这种请求会导致数据库崩溃。

  • 缓存穿透:缓存穿透是指缓存和数据库中都没有的数据,导致所有的请求都不经过缓存,直接落到数据库上,造成数据库短时间内承受大量请求而崩掉。

  • 解决办法:有很多种方法可以有效地解决缓存穿透问题,最常见的则是采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个一定不存在的数据会被 这个 bitmap 拦截掉,从而避免了对底层存储系统的查询压力。另外也有一个更为简单粗暴的方法(我们采用的就是这种),如果一个查询返回的数据为空(不管是数 据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短,最长不超过五分钟。

  • 布隆过滤器:就是引入了k(k>1)k(k>1)个相互独立的哈希函数,保证在给定的空间、误判率下,完成元素判重的过程。
    它的优点是空间效率和查询时间都远远超过一般的算法,缺点是有一定的误识别率和删除困难。Bloom-Filter算法的核心思想就是利用多个不同的Hash函数来解决“冲突”。Hash存在一个冲突(碰撞)的问题,用同一个Hash得到的两个URL的值有可能相同。为了减少冲突,我们可以多引入几个Hash,如果通过其中的一个Hash值我们得出某元素不在集合中,那么该元素肯定不在集合中。只有在所有的Hash函数告诉我们该元素在集合中时,才能确定该元素存在于集合中。这便是Bloom-Filter的基本思想。Bloom-Filter一般用于在大数据量的集合中判定某元素是否存在。

  • 缓存雪崩:缓存同一时间大面积的失效,所以,后面的请求都会落到数据库上,造成数据库短时间内承受大量请求而崩掉。

  • 解决方案:

    • 缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生。
    • 一般并发量不是特别多的时候,使用最多的解决方案是加锁排队。
    • 给每一个缓存数据增加相应的缓存标记,记录缓存的是否失效,如果缓存标记失效,则更新数据缓存。
  • 缓存击穿:缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。和缓存雪崩不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。

  • 解决方案:设置热点数据永远不过期;加互斥锁。

集群

  • 主从模式
    • 主从模式的一个作用是备份数据,这样当一个节点损坏(指不可恢复的硬件损坏)时,数据因为有备份,可以方便恢复。
    • 另一个作用是负载均衡,所有客户端都访问一个节点肯定会影响Redis工作效率,有了主从以后,查询操作就可以通过查询从节点来完成。
    • 主从模式的缺点其实从上面的描述中可以得出:master节点挂了以后,redis就不能对外提供写服务了,因为剩下的slave不能自动成为master这个缺点影响是很大的,需要手动切换,尤其是对生产环境来说,是一刻都不能停止服务的,所以一般的生产坏境是不会单单只有主从模式的。所以有了下面的sentinel模式。
  • 哨兵模式(sentinel):sentinel的中文含义是哨兵、守卫。也就是说既然主从模式中,当master节点挂了以后,slave节点不能主动选举一个master节点出来,那么我就安排一个或多个sentinel来做这件事,当sentinel发现master节点挂了以后,sentinel就会从slave中重新选举一个master。
    • 哨兵的作用:故障检测,自动切换。
    • 缺点在于主机只有一台,并发上线就是10w了。
      在这里插入图片描述
  • 原生模式(cluster):cluster可以说是 sentinel 和主从模式的结合体,通过 cluster 可以实现主从和 master 重选功能,所以如果配置两个副本三个分片的话,就需要六个Redis实例。
    • 因为Redis的数据是根据一定规则分配到cluster的不同机器的,当数据量过大时,可以新增机器进行扩容,这种模式适合数据量巨大的缓存要求,当数据量不是很大使用sentinel即可。
      在这里插入图片描述

https://blog.csdn.net/drdongshiye/article/details/84204392

  • 一致性Hash算法
  • 为什么:大量数据分配到多个Redis集群中,需要用Hash算法进行散列分配(负载均衡)。普通的Hash算法如果集群数量变化,意味着之前的缓存会全部失效,所以有下面的一致性hash算法来解决。
  • 是什么:整个Hash空间被构建成一个首尾相接的环,这样集群数量法术变化,最终都只有少部分的Key发生了失效。
    在这里插入图片描述
    问题与改建:如果结点(集群)很少,会发生数据倾斜,环上的位置会很不均匀,通过引入虚拟节点来解决。

https://blog.csdn.net/monokai/article/details/106626945

持久化机制

  • 快照方式持久化:快照方式持久化就是在某时刻把所有数据进行完整备份。

  • RDB:RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储。在默认情况下, Redis 将数据库快照保存在名字为 dump.rdb的二进制文件中。在 Redis 运行时, RDB 程序将当前内存中的数据库快照保存到磁盘文件中, 在 Redis 重启动时, RDB 程序可以通过载入 RDB 文件来还原数据库的状态。

    • 工作流程:当 Redis 需要保存 dump.rdb 文件时, 服务器执行以下操作
    • Redis 调用forks。同时拥有父进程和子进程。
    • 子进程将数据集写入到一个临时 RDB 文件中。
    • 当子进程完成对新 RDB 文件的写入时,Redis 用新 RDB 文件替换原来的 RDB 文件,并删除旧的 RDB 文件。
  • 日志方式持久化:写日志方式持久化就是把用户执行的所有写指令(增删改)备份到文件中,还原数据时只需要把备份的所有指令重新执行一遍即可。

  • AOF:快照功能(RDB)并不是非常耐久(durable): 如果 Redis 因为某些原因而造成故障停机, 那么服务器将丢失最近写入、且仍未保存到快照中的那些数据。于是,Redis 增加了一种完全耐久的持久化方式: AOF 持久化。

  • 工作流程:打开AOF后, 每当 Redis 执行一个改变数据集的命令时(比如 SET), 这个命令就会被追加到 AOF 文件的末尾。这样的话, 当 Redis 重新启时, 程序就可以通过重新执行 AOF 文件中的命令来达到重建数据集的目的。

  • 持久化方式的选择:

    • 一般来说, 如果想达到足以媲美 PostgreSQL 的数据安全性, 你应该同时使用两种持久化功能,为了防止AOF记录消耗资源,AOF已经快照保存的记录就可以在AOF中清除掉了,只要保证RDB快照间隙的数据保存下拉不丢失即可。
    • 如果你非常关心你的数据, 但仍然可以承受数分钟以内的数据丢失, 那么你可以只使用 RDB 持久化。
    • 有很多用户都只使用 AOF 持久化, 但并不推荐这种方式: 因为定时生成 RDB 快照(snapshot)非常便于进行数据库备份, 并且 RDB 恢复数据集的速度也要比 AOF 恢复的速度要快。

https://segmentfault.com/a/1190000016021217

内存淘汰机制

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

https://blog.csdn.net/ThinkWon/article/details/103522351
https://www.bilibili.com/video/BV1F64y1u79y

线程模型

(待学)
https://www.bilibili.com/video/BV1vE411o7Zr

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值