• Redis学习记录-001


    Redis是什么?

    Redis是C语言开发的一个开源的(遵从BSD协议)高性能键值对(key-value)的内存数据库,可以用作数据库、缓存、消息中间件等。它是一种NoSQL(not-only sql,泛指非关系型数据库)的数据库。
    Redis作为一个内存数据库。
    1、性能优秀,数据在内存中,读写速度非常快,支持并发10W QPS;
    2、单进程单线程,是线程安全的,采用IO多路复用机制;
    3、丰富的数据类型,支持字符串(strings)、散列(hashes)、列表(lists)、集合(sets)、有序集合(sorted sets)等;
    4、支持数据持久化。可以将内存中数据保存在磁盘中,重启时加载;
    5、主从复制,哨兵,高可用;
    6、可以用作分布式锁;
    7、可以作为消息中间件使用,支持发布订阅

     Redis的缓存雪崩

    目前电商首页以及热点数据都会去做缓存,一般缓存都是定时任务去刷新,或者查不到之后去更新缓存的,定时任务刷新就有一个问题。举个栗子:如果首页所有Key的失效时间都是12小时,中午12点刷新的,我零点有个大促活动大量用户涌入,假设每秒6000个请求,
    本来缓存可以抗住每秒5000个请求,但是缓存中所有Key都失效了。此时6000个/秒的请求全部落在了数据库上,数据库必然扛不住,真实情况可能DBA都没反应过来直接挂了,此时,如果没什么特别的方案来处理,DBA很着急,重启数据库,但是数据库立马又被新流量给打死了。
    这就是我理解的缓存雪崩。

    缓存雪崩的解决方案

    处理缓存雪崩简单,在批量往Redis存数据的时候,把每个Key的失效时间都加个随机值就好了,这样可以保证数据不会再同一时间大面积失效。
    setRedis(key, value, time+Math.random()*10000);
    如果Redis是集群部署,将热点数据均匀分布在不同的Redis库中也能避免全部失效。或者设置热点数据永不过期,有更新操作就更新缓存就好了(比如运维更新了首页商品,那你刷下缓存就好了,不要设置过期时间),电商首页的数据也可以用这个操作,保险。

    缓存穿透和击穿,跟雪崩的区别

    缓存穿透是指缓存和数据库中都没有的数据,而用户(黑客)不断发起请求,举个栗子:我们数据库的id都是从1自增的,如果发起id=-1的数据或者id特别大不存在的数据,这样的不断攻击导致数据库压力很大,严重会击垮数据库。
    缓存击穿嘛,这个跟缓存雪崩有点像,但是又有一点不一样,缓存雪崩是因为大面积的缓存失效,打崩了DB,而缓存击穿不同的是缓存击穿是指一个Key非常热点,在不停地扛着大量的请求,大并发集中对这一个点进行访问,
    当这个Key在失效的瞬间,持续的大并发直接落到了数据库上,就在这个Key的点上击穿了缓存。

    缓存穿透和击穿解决方案

    缓存穿透我会在接口层增加校验,比如用户鉴权,参数做校验,不合法的校验直接return,比如id做基础校验,id<=0直接拦截。
    Redis里还有一个高级用法布隆过滤器(Bloom Filter) 这个也能很好的预防缓存穿透的发生,他的原理也很简单,就是利用高效的数据结构和算法快速判断出你这个Key是否在数据库中存在,不存在你return就好了,存在你就去查DB刷新KV再return。
    缓存击穿的话,设置热点数据永不过期,或者加上互斥锁就搞定了。

    六种淘汰策略

     补充一下:Redis4.0加入了LFU(least frequency use)淘汰策略,包括volatile-lfu和allkeys-lfu,通过统计访问频率,将访问频率最少,即最不经常使用的KV淘汰。

    Redis是单线程还是多线程呢?

    Redis在4.0之前使用的是单线程模式,之后增加了对多线程的支持。
    4.0之前的单线程模式,也只是说他的网络IO线程以及Set和Get操作是一个线程完成的,持久化、集群同步还是在其他线程来完成的。
    4.0之后添加了对多线程的支持,主要体现在大数据的异步删除功能,例如:unlink key、fulshdb async、fulshall async等

    那为什么Redis在4.0之前会选择使用单线程?而且使用单线程还那么快?

    Redis的操作都是在内存中,内存中进行操作本来就很快,不存在锁竞争,在无锁的情况下完成所有操作,自然也不会存在死锁以及线程切换带来的性能和时间上的开销。
    快的原因:
    1、大部分操作在内存中操作
    2、单线程避免了多线程的切换开销
    3、采用I/O多路复用机制处理大量客户端的socket请求,基于非阻塞的I/O模型,是Redis可以搞笑的进行网络通信

    那Redis是如何实现数据不丢失的呢?

    三种方式
    AOF(append only file)将redis操作成功后的命令以追加的方式写入文件中并保存到硬盘进行实现数据持久化,也就是写后记录,因为redis不对执行命令进行语法校验,所有只记录成功执行的操作。
    RDB(Redis DataBase)将某一个时刻的内存数据通过二进制的方式写入磁盘从而实现数据持久化。
    AOF和RDB的混合使用

    AOF和 RDB的实现原理

    AOF:将成功执行的Redis操作命令写入到文件中,然后写入磁盘中,保存的主要是操作命令,如果数据丢失,需要将操作命令全部执行即可。AOF可以做到全程持久化,只需要在配置中开启 appendonly yes。这样redis每执行一个修改数据的命令,
    都会把它添加到AOF文件中,当redis重启时,将会读取AOF文件进行重放,恢复到redis关闭前的最后时刻。
    优点:会让redis变得非常耐久。可以设置不同的fsync策略,aof的默认策略是每秒钟fsync一次,在这种配置下,就算发生故障停机,也最多丢失一秒钟的数据。
    缺点:对于相同的数据集来说,AOF的文件体积通常要大于RDB文件的体积。根据所使用的fsync策略,AOF的速度可能会慢于RDB。
    RDB:将内存中的数据全量进行备份,记录某一个时刻的所有数据,所以数据丢失时,直接将RDB数据读取到内存中即可。默认Redis是会以快照"RDB"的形式将数据持久化到磁盘的一个二进制文件dump.rdb。当Redis需要做持久化时,Redis会fork一个子进程,
    子进程将数据写到磁盘上一个临时RDB文件中。当子进程完成写临时文件后,将原来的RDB替换掉,这样的好处是可以copy-on-write
    优点:这种文件非常适合用于备份:比如,你可以在最近的24小时内,每小时备份一次,并且在每个月的每一天也备份一个RDB文件。这样的话,即使遇上问题,也可以随时将数据集还原到不同的版本。RDB非常适合灾难恢复。
    缺点:如果你需要尽量避免在服务器故障时丢失数据,那么RDB不合适你

    如何选择AOF和RDB

    如果你非常关心你的数据,但仍然可以承受数分钟内的数据丢失,那么可以只使用RDB持久。
    AOF将Redis执行的每一条命令追加到磁盘中,处理巨大的写入会降低Redis的性能,不知道你是否可以接受。
    数据库备份和灾难恢复:定时生成RDB快照非常便于进行数据库备份,并且RDB恢复数据集的速度也要比AOF恢复的速度快。
    当然了,redis支持同时开启RDB和AOF,系统重启后,redis会优先使用AOF来恢复数据,这样丢失的数据会最少

    Redis为什么要先执行命令,再把数据写入日志呢

    Redis执行命令是没有进行语法校验,为了避免记录错误命令,所以使用写后记录

    后写日志又有什么风险呢

    在执行命令后,还没来得及记录时发生故障,则会造成数据丢失。

    RDB做快照时会阻塞线程吗

    RDB做快照有两种方式,一种是通过save进行操作,是直接在主线程中操作。这样做快照时会造成阻塞。另外一种是bgsave,是另外创建一个子线程进行操作,不会造成阻塞。默认使用bgsave.

    RDB 做快照的时候数据能修改吗

    save是同步的所以会造成阻塞导致不能同步修改数据,bgsave可以修改。

    Redis是怎么解决在bgsave做快照的时候允许数据修改呢

    在进行读操作时,互不影响,在写操作时,会将修改的数据生成一个副本,然后将副本中的数据保存到RDB的文件中

    Redis如何实现高可用

    主从模式:一主多从
    哨兵模式:一主多从模式基础上添加一台监控,当主节点发生故障后,直接进行容灾恢复
    集群模式:多台机器部署一主多从

    使用哨兵模式在数据上有副本数据做保证,在可用性上又有哨兵监控,一旦master宕机会选举salve节点为master节点,这种已经满足了我们的生产环境需要,那为什么还需要使用集群模式呢?

    主要为了扩展写能力和存储能力

    参考链接:https://mp.weixin.qq.com/s/7f43n89J9VvqngZKIt16AA   https://mp.weixin.qq.com/s/QBkYNnKHIBl55ZJ8VAcc2g

         https://blog.csdn.net/qq_43371556/article/details/97174726#Redis1_24

  • 相关阅读:
    Android 系统广播机制
    NBUT 1457 Sona (莫队算法)
    内存分配--静态内存、栈和堆
    Hibernate主键生成策略
    UVA 1482
    servlet开篇
    C语言的代码内存布局具体解释
    Mirantis Fuel fundations
    openstack中文文档
    C++ 之再继续
  • 原文地址:https://www.cnblogs.com/qcq0703/p/15072794.html
Copyright © 2020-2023  润新知