redis学习

1、数据类型

  • string
  • 底层

增删改查

  • set key value
  • get key
  • del k
  • strlen k 

加减

  • incr article
  • incrby article 3
  • decr article
  • decyby article

取v中特定位置数据

  • getrange name 0 -1
  • getrange name 0  1
  • setrange name 0 x

设置过期时间

  • setex pro 10 华为

        等价于

  • set pro 华为
  • expire pro 10

在分布式系统里面可以使用如下命令实现分布式锁

  • setnx(set if not exist)
  •     如果返回1:设置成功
  •     如果返回0:设置失败
  • List 有序、可重复

  • lpush num 1 2 3 4 5
  • rpush num2 1 2 3 4 5

弹出(获取数据的同时将数据从list中删除)

  • lpop
  • rpop

  • lrange num 0 -1
  • lrange num2 0 -1

根据下标获取元素

  • LINDEX key index

大小

  • LLEN key

队列:先进先出

  • lpush num3 1 2 3  #左边推进去
  • rpop num3 1       #右边取出来
  • 或者
  • rpush num4 1 2 3
  • lpop num4

栈:先进后出

  • lpush num5 1 2 3
  • lpop num5
  • 或者
  • rpush num6 1 2 3
  • rpop num6
  • #list的长度
  • llen num5
  • set无序,不可重复

  • sadd ips '192.168.22.1' '192.168.22.2' '192.168.22.2'

  • smembers ips

查看某个元素在集合中是否存在

  • SISMEMBER key member

  • srem ips '192.168.22.1'

大小

  • scard ips #获取set的长度

随机

  • sadd nums 3 4 5 0 9 8 9 0 8 6 
  • srandmember nums 3

随机并移除

  • spop rands 3

交集

  • redis 127.0.0.1:6379> SADD myset "hello"
  • (integer) 1
  • redis 127.0.0.1:6379> SADD myset "foo"
  • (integer) 1
  • redis 127.0.0.1:6379> SADD myset "bar"
  • (integer)
  • redis 127.0.0.1:6379> SADD myset2 "hello"
  • (integer) 1
  • redis 127.0.0.1:6379> SADD myset2 "world"
  • (integer) 1
  • redis 127.0.0.1:6379> SINTER myset myset2
  • 1) "hello"

并集

  • redis> SADD key1 "a"
  • (integer) 1
  • redis> SADD key1 "b"
  • (integer) 1
  • redis> SADD key1 "c"
  • (integer) 1
  • redis> SADD key2 "c"
  • (integer) 1
  • redis> SADD key2 "d"
  • (integer) 1
  • redis> SADD key2 "e"
  • (integer) 1
  • redis> SUNION key1 key2
  • 1) "a"
  • 2) "c"
  • 3) "b"
  • 4) "e"
  • 5) "d"
  • Hash:hash的key不能重复,如果重复就覆盖

  • hset person name 'jack'
  • hset person age 40

  • hget person name
  • hget person age

存多个

  • hmset person name 'rose' age 12

大小

  • hlen person

判断k是否存在

  • hexists person age


hkeys person
hvals person

person  "{'name':'zhangsan'}"  string


name jack
age 12

person:hash() 
      

#hash可以大大减少redis中的K  同时hash结构特别适合存放对象
person :
        name   'jack'
        age   '18' 
hget  person age

  • Zset:有序,不可重复,通过score来进行排序,score必须是数字

通过score进行排序
zadd hot 300 '华为met10' 10 '苹果10'  19 '小米'
zrange hot 0 -1
zrevrange hot 0 -1

#分数范围过滤
zrangebyscore hot 11 100
zrangebyscore hot 10 100 limit 0 1


#删除
zrem hot '小米'
zcard hot #查看集合的元素个数

2、redis事务

  • mutli #开启事务
  • exec #提交事务
  • discard #回滚事务

3、redis事物不是原子性

因为,有一条命令执行失败,之前的命令不会回滚,其他命令仍然继续执行。

redis所有命令都会顺序执行,事物执行过程中不会被其他客户端的命令打断

4、redis为什么不支持事物回滚

redis 只会因为语法错误而失败,如果这些错误不会在入队的时候发现,说明时程序错误造成的

不需要对回滚进行支持,所以redis才非常的快

 5、持久化

RDB

Redis会单独fork一个子进程进行持久化工作,该子进程先将数据写入一个临时文件,等待持久化完毕,再将临时文件覆盖替换上此持久化好的文件,整个过程主进程是不会进行任何的IO操作,确保了极高的性能,而且当进行大规模数据恢复的时候RDB性能也非常高. 但是RDB有缺点,没法保证数据不丢失

触发方式:

自动触发

  • 如900秒有1个被改变
  • save 900 1
  • save 300 10
  • save 60 10000

手动触发

  • 1.正常关闭redis-server(shutdown,flushdb手动)

  • 2.save该命令会阻塞当前Redis服务器,执行save命令期间,Redis不能处理其他命令,直到RDB过程完成为止。 显然该命令对于内存比较大的实例会造成长时间阻塞,这是致命的缺陷。

  • 3.bgsave 执行该命令时,Redis会在后台异步进行快照操作,快照同时还可以响应客户端请求。具体操作是Redis进程执行fork操作创建子进程,RDB持久化过程由子进程负责,完成后自动结束。阻塞只发生在fork阶段,一般时间很短。

AOF:

  • 以日志的形式记录每个写操作(命令),当redis重启时,加载aof文件,将修改命令执行一遍。

AOF重写

将命令压缩由于AOF持久化是Redis不断将写命令记录到 AOF 文件中,随着Redis不断的进行,AOF 的文件会越来越大,文件越大,占用服务器内存越大以及 AOF 恢复要求时间越长。为了解决这个问题,Redis新增了重写机制,当AOF文件的大小超过所设定的阈值时,Redis就会启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集。可以使用命令 bgrewriteaof 来重新。

6、redis内存满了怎么解决

加服务器。

通过配置文件修改配置

7、内存淘汰

实际上Redis定义了几种策略用来处理这种情况:

  • noeviction(默认策略):对于写请求不再提供服务,直接返回错误(DEL请求和部分特殊请求除外)

  • allkeys-lru:从所有key中使用LRU算法进行淘汰,LRU(Least Recently Used)

  • volatile-lru:从设置了过期时间的key中使用LRU算法进行淘汰,LRU(Least Recently Used)

  • allkeys-random:从所有key中随机淘汰数据

  • volatile-random:从设置了过期时间的key中随机淘汰

  • volatile-ttl:在设置了过期时间的key中,根据key的过期时间进行淘汰,越早过期的越优先被淘汰

策略

名称

说明

noeviction

不驱逐

(默认)写入新数据时,如果内存满了,直接返回错误,不删任何数据。

allkeys-lru

所有key,最近最少使用

基于访问时间,淘汰最久没被用的key,不管是热点还是冷数据。

allkeys-random

所有key,随机淘汰

在所有key里随机淘汰一个,运气决定谁被踢。

volatile-lru

仅过期key,最近最少使用

只在**设置了过期时间(TTL)**的key中,按最少使用原则淘汰。

volatile-random

仅过期key,随机淘汰

只在有TTL的key中随机踢掉。

volatile-ttl

仅过期key,快要过期的优先淘汰

谁的TTL时间短(快过期),谁优先被淘汰。

策略

适合场景

典型例子

noeviction

要求绝不丢数据,比如缓存穿透时快速失败

银行账单、支付订单系统(写失败更好,也不要乱删数据)

allkeys-lru

全部是缓存,需要保证热点数据留存

商品详情页、推荐系统缓存

allkeys-random

低成本,不在乎删谁,只求稳定

秒杀抢购活动时的临时数据

volatile-lru

只有部分key有过期,想优先清理过期的缓存

用户session(设置了TTL)、短期缓存

volatile-random

只要清过期key,不care删哪个

临时推广数据、广告投放缓存

volatile-ttl

优先删掉快过期的数据,保持整体TTL

活动报名、积分有效期数据缓存

 

8、为什么删除数据后,Redis内存占用依然很高?

  • 内存碎片

9、为什么会出现内存碎片

Redis提供了多种的内存分配策略,比如libcjemalloctcmalloc,默认使用jemalloc

jemalloc这种分配策略并不是按需分配,而是固定大小分配,比如8字节、32字节....2KB、4KB等

10、如何判断存在内存碎片?

INFO memory

11、如何清理内存碎片?

Redis提供了参数配置,可以控制清除内存碎片的时机,命令

12、缓存击穿

  • 某一个热点key,在失效的一瞬间,持续的高并发访问击破缓存直接访问数据库,导致数据库造的周期性压力(极端情况下导致数据库宕机)  

解决:

  • 布隆过滤器的基本原理是利用多个哈希函数和一个位数组来表示一个集合。当元素被加入到集合中时,通过多个哈希函数将其映射到位数组中的多个位置,并将这些位置的位设置为1。当查询一个元素是否存在于集合中时,同样使用多个哈希函数计算其哈希值,并检查对应的位数组位置是否都为1,如果有任何一个位置为0,则可以确定该元素一定不在集合中;如果所有位置都为1,则该元素可能存在于集合中。
  • 加锁:确保只有一个请求能够访问数据库加载数据,其他请求等待加载完成后直接从缓存获取数据。
  • 热点数据永不过期
  • 热点数据预热

13、缓存穿透

  • 非法访问、数据库并不存在需要查找的数据,缓存也无法命中,请求都会到数据库,从而可能压垮数据源

解决:布隆

14、缓存雪崩

  • Redis中大量的key几乎同时过期,然后大量并发查询穿过redis击打到底层数据库上,此时数据库层的负载压力会骤增,我们称这种现象为"缓存雪崩"

解决方案

  • 在可接受的时间范围内随机设置key的过期时间分散key的过期时间,以防止大量的key在同一时刻过期;

  • 延长热点key的过期时间或者设置永不过期,这一点和缓存击穿中的方案一样

15、缓存预热

  • ​​​​当系统上线时,缓存内还没有数据,直接提供给用户使用,每个请求都会穿过缓存去访问底层数据库,如果并发大的话,很有可能在上线当天就会宕机,因此我们需要在上线前先将数据库内的热点数据缓存至Redis内再提供出去使用,这种操作就成为"缓存预热"。

解决:

  • 缓存预热的实现方式有很多,比较通用的方式是写个批任务,在启动项目时或定时去触发将底层数据库内的热点数据加载到缓存内。

16 、缓存更新/缓存同步

  • 缓存同步是指确保多个缓存副本之间的数据保持一致的过程。在分布式系统中,通常会部署多个缓存副本以提高系统的性能和可用性,但是这样就会引入缓存之间的数据一致性问题。缓存同步的目的是确保不同缓存副本中的数据保持同步,

解决:

  • 数据双写一致性:当写入数据时,同时更新数据库和缓存,保持数据的一致性。这种方式可以确保缓存数据与数据库数据同步,但会增加写入操作的耗时和复杂度。

17、缓存降级

  • Redis服务不可用,或者网络抖动,导致服务不稳定

解决

  • 使用熔断降级策略进行服务熔断降级

18、Redis6的新特性

  • 多线程
  • 访问控制权限功能

19、布隆过滤器

查:通过hash计算得到对应位置,如果当前位置由数据则代表数据存在

插入:通过hash计算得到对应位置,将当前位置改为1.布隆过滤器直有0和1

优点,由二进制组成占用空间非常小查询非常快,保密性好只有0和1

hash碰撞怎么办

用不同的hash算法取模落在不同位置

存在不一定存在,不存在一定不存在

可以算容错率 

20、集群

单节点访问压力大,单节点故障导致程序不可用

一主两从

采用一组2从,主节点负责写,从节点负责读,且要实现主从同步,主节点写后从节点也有相同数据

哨兵:

  • 监控:Sentinel 会不断地定期检查你的主服务器和从服务器是否运作正常。
  • 提醒: 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应用程序发送通知。
  • 自动故障迁移: 当主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作,选举新主
  • 哨兵:是整个集群的入口
  • (通过哨兵投票选出主节点,哨兵一定十奇数,2n+1)

分布式集群

会有16384个hash,根据分布式的集群个数分配如下图,将set进来的数进行hash算出对应的区间进行存储,get一样算处对应区间获取相应值

21、redis底层

为什么是单线程

6.0以后是多线程,是利用epoll实现多路复用的

底层

通过hashtable

hash表:一维数组加二维码链表。(hash,set)

压缩列表:把链表的指针去掉了,用偏移找到位置,类似于数组(zset,hash,list)

整数数组:查询很快,操作很慢(set)

双向链表:(list)

跳表:底层是链表,从左到右依次排序,有点像二分查找。从下往上看  (zset)

22、redis同步mysql先同步redis还是先同步sql

先操作redis

1、如果先修改同步redis 在同步mysql时出现网络原因,其他数据访问redis是新数据,而mysql存储是老数据(问题:数据不一致)

2、如果先删除redis,在同步mysql,在删除redis(要用延迟,是为了避免另一个线程进来删除后同步老数据)(问题:并发时会有一次数据不一致:解决用锁,限制速度不能使用)

先操作mysql

只会出现一次老数据

问题:如果删除失败,可以用重试消息通知

string

采用sds

特点有

1. 动态扩展

假设 SDS 初始存储 abc:

• len = 3, alloc = 10, buf = "abc\0"

• 当追加 defghijkl 时,发现剩余空间不足,会重新分配空间。

结果:

• len = 12, alloc = 20, buf = "abcdefghijkl\0"

2. 惰性释放

假设 SDS 存储 hello world:

• len = 11, alloc = 20

• 如果删除部分数据变为 hello:

• len = 5, alloc = 20

• 多余的空间仍保留,方便后续扩展。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值