redis学习笔记

1.认识redis

  1. redis是一种内存数据库
  2. 也支持持久化,可以通过定期将数据刷入磁盘或者将每条记录附加到基于磁盘的日志的方式实现
  3. 支持集群
  4. 单台设备的redis的QPS是mysql的10倍,一般10w左右,mysql则为1w左右,能承受的请求远远超过mysql

2、Redis 和 Memcached 有什么区别?

  1. redis支持多种数据类型,Memcached只支持key-vlaue
  2. redis支持持久化,Memcached不支持
  3. redis原生支持集群,Memcached不支持
  4. redis支持发布订阅模型、Lua脚本、事务等,Memcached不支持

3、redis目前有9种数据结构

  1. String
    1. 应用场景:缓存对象、常规计数、分布式锁、共享session信息等
    2. 数据结构:SDS
    3. 底层数据结构实现主要是SDS(简单动态字符串),他和C语言的字符串有下列区别
      1. 它有一个存放字符串长度的“len属性”,所以查找字符串长度的复杂度为O(1),而C语言的字符串为O(n)
      2. 它不仅能存放文本数据,还能存放二进制数据,如图片、音频、视频、压缩文件,而C语言的字符串不行
      3. 拼接字符串不会造成缓冲区溢出,因为每次拼接前,都会检查SDS空间是否满足要求,如果空间不够,会自动扩容
  2. Hash
    1. 应用场景:缓存对象、购物车等
    2. 数据结构:在redis7.0之前,底层数据结构主要由“哈希表”和“压缩列表”实现,7.0之后,由“listpack”来实现
  3. Set
    1. 应用场景:聚合计算(并集、交集、差集)场景,比如点赞、共同关注、抽奖活动等
    2. 数据结构:如果集合中的元素全是整数且元素个数小于512,则底层数据结构为“整数集合”;否则为“哈希列表”
  4. Zset
    1. 应用场景:排序场景,比如排行榜,电话、姓名排序等
    2. 数据结构:在redis7.0之前,如果元素个数小于128,并且每个元素小于64字节,则底层数据结构为“压缩列表”,否则为“跳表”;7.0之后,为“listpack”
  5. List
    1. 应用场景:消息队列(但是有两个问题:1. 生产者需要自行实现全局唯一 ID;2. 不能以消费组形式消费数据)等
    2. 数据结构:在redis3.2之前,底层数据结构为“压缩列表”或“双向列表”来实现,3.2之后,未quicklist
  6. BitMap
    1. 应用场景:二值状态统计的场景,比如是否签到、是否登录、连续签到人数统计
  7. Geo
    1. 应用场景:存储地理位置信息,不如滴滴打车
  8. Stream
    1. 应用场景:消息队列,相比于用List实现的消息队列,支持了自动生成全局唯一ID、以消费组形式消费数据
  9. HyperLogLog
    1. 应用场景:海量数据基数统计的场景,如百万级网页的UV计数统计

 

4、redis是否为单线程?

redis是单线程,不过在redis6.0之后,加入了I/O多线程;这是因为之前redis的性能瓶颈主要在内存,但随着网络硬件的性能提升,redis的性能瓶颈有时候会出线在网络I/O的处理上,所以在6.0之后才会引入I/O多线程,但是对于redis的命令执行,还是采用单线程来处理的,所以redis还是单线程;另外I/O多线程默认情况也只是针对发送响应数据(write client socket),并不会以多线程的方式处理读请求(read client socket),需要在Redis.conf文件中进行配置,而且线程数量也可以进行配置,但线程数量推荐小于CPU核数。总而言之,redis6.0后只是支持了网络请求层面的多线程,对于读写命令还是单线程处理,所以也不存在并发问题。

5、redis单线程为什么这么快

  1. 大部分操作都在内存中,并且采用了高效的数据结构
  2. 采用了I/O多路复用机制
  3. 避免了多线程之间的竞争,省去了多线程切换带来的时间和性能上的开销,也避免了死锁

6、 redis持久化的方式

  1. AOF日志:每执行一条写操作命令,就将该命令记录到一个文件里
    1. 优点:丢失数据少;在 Redis.conf 配置文件中的 appendfsync 配置项可以有以下 3 种参数可填,Always、Everysec、No,分别代表每步、没秒、由操作系统控制将AOF文件数据写入磁盘
    2. 缺点:恢复数据慢
    3. AOF重写机制:当AOF文件大小超过了设定的阀值,会压缩AOF文件,保留最新纪录,剔除历史记录
  2. RDB快照:将某一时刻的内存数据,以二进制的方式写入磁盘
    1. 优点:丢失数据多;因为快照是将某一时刻的所有数据同步到磁盘,这就导致不能实时将数据进行同步,否则会影响到redis的性能,意味着同步数据的间隔会长一点,中间出了问题丢的数据也会多一点
    2. 缺点:恢复数据快;因为直接将 RDB 文件读入内存就可以,不需要像 AOF 那样还需要额外执行操作命令的步骤才能恢复数据。
    3. 两种方式生成RDB文件:
      1. save:由主线程生成,因为和操作命令共用一个线程,如果将RDB文件写入磁盘耗时太长,会造成主线程的阻塞
      2. bgsave:创建一个子线程将RDB文件写入磁盘
    4. 写时复制技术:
      1. 场景:RDB在执行快照的时候,也可以修改数据
      2. 原理:在执行bgsave的时候,会通过fork()创建一个子线程,主线程和子线程共享一片内存数据,当主线程执行写操作时,子线程可以将被修改的数据写入RDB文件
  3. 混合持久化方式:在redis4.0后引入,集成AOF和RDB的优点
    1. 工作时间:AOF开始日志重写的时候(当AOF文件大小超过设定的阀值时,就会重写)
    2. 原理:先fork()一个子线程将内存中的数据以RDB方式写入到AOF文件,然后将主线程的操作命令写入到重写缓冲区,重写缓冲区的增量命令会以AOF的方式写入到AOF文件,也就是说启用混合持久化方式生成AOF文件,前半部分是RDB格式的全量数据,后半部分是AOF格式的增量数据,这样也就保证了redis数据恢复速度,也保证了持久化数据丢失数量。
    3. 缺点:生成的AOF文件可读性变差,而且只支持在redis4.0后使用

7、redis如何实现服务高可用

  1. 采用主从复制、哨兵、分片集群模式三种方式配合来实现
  2. 主从复制:将redis部署到多台服务器,指定其中一个台为“主服务器”,其中只有“主服务器”同时支持读、写数据,“从服务器”只支持读数据,“从服务器”数据通过“主服务器”生成RDB文件进行同步,因为同步数据是一个耗时操作,所以会出现数据不一致的情况。
  3. 哨兵模式:适用于一主多从的情况;当主服务器宕机时,可以通过哨兵模式重新选择一个从服务器作为主服务器,并且修改从服务器配置,给它们指定新的主服务器,这样就重新生成了一套主从服务,整个过程不需要人工参与。
  4. 分片集群模式:横向扩展,当一台服务器存储的数据过大时,希望将数据分散到多个服务器以提高读写性能
    1. 原理:在redis clusters方案中,一个切片集群会有16384个哈希槽,哈希槽有平均分配、手动分配两种方式进行分配,如果一个切片集群有9个节点,按平均分配的方式进行分配的话,每台服务器拥有的哈希槽数量为16384/9;然后将每个键值对的key用CRC16算法计算得到一个16bit的值,用这个值对16384取模,可以得到0~16383范围的数,每个模数代表一个相应编号的哈希槽,这样就完成了数据在服务器中的分配。
  5. 集群脑裂导致数据丢失怎么办?
    1. 脑裂:主从架构中,主节点被误切换,然后原主节点还在处理数据,导致新主节点这部分数据丢失的现象。
    2. 脑裂为什么会丢数据:在redis的主从架构中,一般是采用一主多从的方式,如果主节点的网络突然出现了问题,与所有子节点都失去了联系,但是与客户端的网络是正常的,这时哨兵发现了主节点失联了,就会从子节点挑选一个作为新的主节点,但是由于老主节点与客户端的网络是正常的,客户端还会不断向老主节点写入数据,当老主节点恢复正常,需要降级,删除数据,同步新主节点的数据,那么这个时候老主节点网络断开的这段时间客户端写入的数据全部丢失了。
    3. 解决方案:当主节点发现与从节点的连接数量小于min-slaves-to-write(个)或主从数据复制和同步的延迟超过了min-slaves-max-lag(秒),则禁止主节点写入数据,并把错误返回给客户端,min-slaves-to-write和min-slaves-max-lag都可以在redis.conf文件中进行配置。

8、reidis过期删除与内存淘汰

  导语:每当我们对一个key设置过期时间的时候,redis就会将这个key的带上过期时间存到一个过期字典,也就是说这个过期字典保存了所有key的过期时间。

  1. redis的过期删除策略:采用惰性删除+定时删除两种方式配合使用
    1. 惰性删除:客户端每从redis读取一个数据时,会将用该数据的key取过期字典中检查该数据是否过期,如果过期了,则删除数据,返回null
    2. 定时删除:每隔一段时间去过期字典中随机拉取一部分数据去检查key有没有过期,有就删除,如果当前拉取的数据的过期率大于25%,则再随机拉取一次数据,继续重复删除操作,但是为了避免定期删除数据循环过度,会有一个定期删除循环流程的时间上限,一般为25ms
  2. redis持久化时,对过期键怎么处理
    1.  用AOF文件持久化时,有文件写入和AOF重写两个阶段
      1. 文件写入:如果数据库某个过期键还没被删除,则AOF文件会保留该过期键,当数据库删除该过期键后,会在AOF文件中追加一条DEL命令来删除该过期键
      2. AOF重写:重写的过程中会对数据库中的键值对进行检查,已过期的键值对不会再写入AOF文件中
    2. 用RDB文件持久化时,有文件写入和文件加载两个阶段
      1. 文件写入:会对键值对进行检查,已过期的键值对不会写入RDB文件
      2. 文件加载:如果是在【主服务器】中加载RDB文件,会对过期键进行检查,已过期的键值对不会被恢复到数据库中;如果是在【从服务器】中加载RDB文件,不会对键值对是否过期进行检查,但【从服务器】同步【主服务器】数据时,会先清空自己的数据,所以一般来说,过期键对载入 RDB 文件的从服务器也不会造成影响。
  3. redis主从模式中,对过期键怎么处理?
    1. 【从服务器】不会对数据是否过期进行扫描,【主服务器】的key到期了并被删除时,会AOF文件中写入一条DEL命令,然后该AOF文件会被同步到所有【从服务器】并被执行,从而达到删除所有主从服务器中的过期数据的目的。
  4. redis内存满了,会发生什么?
    1. 当redis的运行内存达到某个阀值,则会启动内存淘汰策略,这个阀值可以在redis.conf中进行配置,配置项为maxmemory
    2.  内存淘汰策略:共8种,分为不淘汰和淘汰两大类;淘汰又分为设置了过期时间淘汰和没有设置过期时间淘汰两大类
      1. 不淘汰
        1. redis3.0后的默认内存淘汰策略,内存满了,直接报错
          1. 不进行数据淘汰:noeviction
      2. 淘汰
        1. 设置了过期时间
          1. 随机淘汰:volatile-random
          2. 淘汰最早过期的:volatile-ttl
          3. 淘汰最久未使用的:volatile-lru
          4. 滔淘汰使用次数最少的:volatile-lfu
        2. 没有设置过期时间
          1. 随机淘汰:allkeys-random
          2. 淘汰最久未使用的:allkeys-lru
          3. 淘汰使用次数最少的:allkeys-lfu
  5. LRU算法和LFU算法有什么区别?
    1. LRU(Least Recently Used):最久未被使用,会在redis的对象结构体中添加一个额外字段,用于记录此数据的最近访问时间,采用随机采样的方式来淘汰数据,随机采用个数可在redis.conf中进行配置,淘汰选取的数据中的最早使用的数据
    2. LFU(Least Frequently Used):最近最不常用,会在redis对象请求头中添加一个lru参数,LFU中也会有lru参数,但是在LRU中,lru只会记录最近访问时间,而在LFU中,lru会记录访问频率和最近访问时间

9、redis缓存设计

  1. 如果避免缓存雪崩、缓存击穿、缓存穿透?
    1. 缓存雪崩:
      1. 解释:当大量缓存数据在同一时间过期,而这些数据又刚好被大量请求,由于缓存失效了,就导致这些请求都将直接访问数据库,造成数据库的压力骤增,导致系统崩溃。
      2. 解决方案:
        1. 将缓存失效时间随机打散:在原有缓存失效时间上,再加一个随机值,比如1~10分钟,可以降低缓存集体失效的概率。
        2. 设置缓存不过过期:在后台服务中控制缓存的刷新。
    2. 缓存击穿
    3. 缓存穿透
posted @ 2023-04-06 21:50  xlfdy  阅读(72)  评论(0)    收藏  举报