缓存技术Redis

缓存技术Redis

1 下载 docker-compose.yml

version: '3.1'
services: 
  redis:
      image: daocloud.io/library/redis:5.0.7
      restart: always
      container_name: redis
      environment:
          - TZ=Asia/Shanghai
      ports:
          - 6379:6379

2 redis 数据结构

常用的5种数据结构

  • key-string:一个key对应一个值。
  • key-hash:一个key对应一个Map。
  • key-list:一个key对应一个列表。(list)
  • key-set:一个key对应一个集合。 (HashSet)
  • key-zset;一个key对应一个有序的集合。 (linkedHashSet)

另外三种数据结构。

  • HyperLogLog:计算近似值的。
  • GEO:地理位置
  • BIT:一般存储的也是一个字符串,存储的是一个byte[]
  • 使用场景

    key-string:最常用的,一般用于存储一个值。
    key-hash:存储一个对象数据的。
    key-list:使用list结构实现栈和队列结构。
    key-set:交集,差集和并集的操作。
    key-zset:排行榜,积分存储等操作。|

3 常用命令

3.1 string常用命令

#1.添加值
set key value
#2.取值
get key
#3.批量操作
mset key value[key value...]
mget key[key..]

#4.自增命令(自增1)
incr key
#5.自减命令(自减1)
decr key
#6.自增或自减指定数量
incrby key increment
decrby key increment

#8.设置值的同时,指定生存时间(每次向Redis中添加数据时,尽量都设置上生存时间)
# setex zhangsan 10 man   秒值
setex key second value
#9.设置值,如果当前key不存在的话(如果这个key存在,什么事都不做,如果这个key不存在,和set命令一样)
setnx key value 
#9.在key对应的value后,追加内容
append key value
#10.查看value字符串的长度
strlen key

3.2 hash常用命令

#1.存储数据
hset key field value
#2.获取数据
hget key field
#3.批量操作
hmset key field value[field value..]
hmget key field[field..]

#5.设置值(如果key-field不存在,那么就正常添加。如果存在,什么事都不做)
hsetnx key field value
#6.检查field是否存在
hexists key field
#7.删除key对应的field,可以删除多个
hdel key field[field]
#8.获取当前hash结构中的全部field和value 
hgetall key
#9.获取当前hash结构中的全部field 
hkeys key
#10.获取当前hash结构中的全部value 
hvals key
#11.获取当前hash结构中field的数量
hlen key

3.3 list 常用命令

#1.存储数据(从左侧插入数据,从右侧插入数据)
1push key value[value...]
rpush key value[value..J
#2.存储数据(如果key不存在,什么事都不做,如果key存在,但是不是1ist结构,什么都不做)
1pushx key valuerpushx key value
#3.修改数据(在存储数据时,指定好你的索引位置)
1set key index value
#4.弹栈方式获取数据(左侧弹出数据,从右侧弹出数据)
1pop keyrpop key
#5.获取指定索引范围的数据(start从0开始,stop输入-1,代表最后一个,-2代表倒数第二个)
1range key start stop
#6.获取指定索引位置的数据
1index key index
#7.获取整个列表的长度
11en key

#8.删除列表中的数据(他是删除当前列表中的count个value值,count>0从左侧向右侧删除,count<0从右侧向左侧删除,count==0删除列表中全部的value)
1rem key count value
#9.保留列表中的数据(保留你指定索引范围内的数据,超过整个索引范围被移除掉)
1trim key start stop
#10.将一个列表中最后的一个数据,插入到另外一个列表的头部位置
rpoplpush list1 list2

3.4 set常用命令

#1.存储数据
sadd key member[member...]
#2.获取数据(获取全部数据)
smembers key
#3.随机获取一个数据(获取的同时,移除数据,count默认为1,代表弹出数据的数量)
spop key[count]

#4,交集(取多个set集合交集)
sinter setl set2..…
#5.并集(获取全部集合中的数据)
sunion setl set2...
#6.差集(获取多个集合中不一样的数据)
sdiff set1 set2..

#7.删除数据
srem key member[member...]
#8.查看当前的set集合中是否包含这个值
sismember key member

3.5 zset 常用命令

#1,添加数据(score必须是数值,member不允许重复的。)
zadd key score member[score member...]
#2.修改member的分数(如果member是存在于key中的,正常增加分数,如果memeber不存在,这个命令就相当于zadd)
zincrby key increment member

#3.查看指定的member的分数
zscore key member
#4.获取zset中数据的数量
zcard key
#5.根据score的范围查i询member数量
zcount key min max
#6.删除zset中的成员
zrem key member[member...]

#7.根据分数从小到大排序,获取指定范围内的数据(withscores如果添加这个参数,那么会返回menmber对应的分数)
zrange key start stop[withscores]
#8,根据分数从大到小排序,获取指定范围内的数据(withscores如果添加这个参数,那么会返回member对应的分数)
zrevrange key start stop[withscores]
#9.根据分数的返回去获取member(withscores代表同时返回score,添加1imit,就和MySQL中一样,如果不希望等于min或者max的值被查询出来可以采用‘(分数’相当于<但是不等于的方式,最大值和最小值使用+inf和-inf来标识)
zrangebyscore key min max[withscores][limit offset count]
#10.根据分数的返回去获取member(withscores代表同时返回score,添加1imit,就和MySOL中一样)
zrangebyscore key max min[withscores][limit offset count]

3.6 key 常用命令

#1.查看Redis中的全部的key(pattern:*,XXx*,*xxx)
keys pattern
#2.查看某一个key是否存在(1-key存在,0-key不存在)
exists key
#3.删除key 
del key[key...]

#4.设置key的生存时间,单位为秒,单位为毫秒,设置还能活多久
expire key second pexpire key mi1liseconds
#5。设置key的生存时间,单位为秒,单位为毫秒,设置能活到什么时间点
expireat key timestamp pexpireat key milliseconds
#6.查看key的剩余生存时间,单位为秒,单位为毫秒(-2-当前key不存在,-1-当前key没有设置生存时间,具体剩余的生存时
ttl key pttl key
#7.移除key的生存时间(1-移除成功,0-key不存在生存时间,key不存在)
persist key

#8.选择操作的库
select 0~15
#9.移动key到另外一个库中
move key db

3.7 库的常用命令

#1.清空当前所在的数据库
flushdb
#2.清空全部数据库
flushal1
#3.查看当前数据库中有多少个key
dbsize
#4.查看最后一次操作的时间
lastsave
#5.实时监控Redis服务接收到的目录
monitor

4 redis 配置文件

  • docker-compose.yml

    version: '3.1'
    services: 
      redis:
          image: daocloud.io/library/redis:5.0.7
          restart: always
          container_name: redis
          environment:
              - TZ=Asia/Shanghai
          ports:
              - 6379:6379
          volumes:
              - ./conf/redis.conf:/usr/local/redis/redis.conf
              - ./data:/data # 映射数据
          command: ["redis-server","/usr/local/redis/redis.conf"] # redis启动时加载该配置文件
    
  • redis.conf

    # 密码配置
    requirepass 075522yu
    
    # RDB持久化机制的配置
    # 代表RDB执行的时机
    # 900秒之内,有一个key改变了,就执行RDB持久化
    save 900 1
    save 300 10
    save 60  1000 
    # 开启RDB持久化的压缩
    rdbcompression yes
    # RDB持久化文件的名称 
    dbfilename redis.rdb
    

4.1 redis 持久化

redis 允许同时开启 RDB 和AOF 持久化

同时开启那么aof 的优先级更高,因为更安全

  • RDB

    RDB是Redis默认的持久化机制
    1.RDB持久化文件,速度比较快,而且存储的是一个二进制的文件,传输起来很方便。
    2.RDB持久化的时机:
    save 900 1:在900秒内,有1个key改变了,就执行RDB持久化。
    save 300 10:在300秒内,有10个key改变了,就执行RDB持久化。
    save 60 10000:在60秒内,有10000个key改变了,就执行RDB持久化。
    3.RDB无法保证数据的绝对安全。

  • AOF

    #AOF持久化策略
    #代表开启AOF持久化
    appendonly yes
    #AOF文件的名称
    appendfilename “redis.aof”
    #AOF持久化执行的时机
    #appendfsync always

    appendfsync everysec

    #appendfsync no

    A0F持久化机制默认是关闭的,Bedis官方推荐同时开启RDB和AOE持久化,更安全,避免数据丢失。
    1.AOF持久化的速度,相对RDB较慢的,存储的是一个文本文件,到了后期文件会比较大,传输困难。
    2.AOF持久化时机。
    appendfsync always:每执行一个写操作,立即持久化到AOE文件中,性能比较低。
    appendfsync everysec:每秒执行一次持久化。
    appendfsync no:会根据你的操作系统不同,环境的不同,在一定时间内执行一次持久化。
    3.AOF相对RDB更安全,推荐同时开启AOE和RDB。|

5 redis 事务

Redis的事务:一次事务操作,改成功的成功,该失败的失败。
先开启事务,执行一些列的命令,但是密码不会立即执行,会被放在一个队列中,如果你执行事务,那么这个队列中的命令全部执行,如果取消了事务,一个队列中的命令全部作废。
1.开启事务:multi
2.输入要执行的命令:被放入到一个队列中
3.执行事务:exec
4.取消事务:discard

redis的事务想发挥功能,需要配置watch监听机制在开启事务之前,先通过watch命令去监听一个或多个key,在开启事务之后,如果有其他客户端修改了我监听的key,事务会自动取消

6 redis 主从配置

主从可以提高 redis 的性能

主节点可以读写, 从节点只能读取数据

  • docker-compose.yml

    主节点不用改动, 从节点添加 links: 主节点

    version: '3.1'
    services: 
      redis1:
          image: daocloud.io/library/redis:5.0.7
          restart: always
          container_name: redis1
          environment:
              - TZ=Asia/Shanghaii
          ports:
              - 7001:6379
          volumes:
              - ./conf/redis1.conf:/usr/local/redis/redis.conf
              - ./data1:/data # 映射数据
              - ./conf/sentinel1.conf:/data/sentinel.conf # 哨兵配置文件
          command: ["redis-server","/usr/local/redis/redis.conf"] 
      redis2:
          image: daocloud.io/library/redis:5.0.7
          restart: always
          container_name: redis2
          environment:
              - TZ=Asia/Shanghai
          ports:
              - 7002:6379
          volumes:
              - ./conf/redis2.conf:/usr/local/redis/redis.conf
              - ./data2:/data # 映射数据
              - ./conf/sentinel2.conf:/data/sentinel.conf
          links:
              - redis1:master    
          command: ["redis-server","/usr/local/redis/redis.conf"] 
      redis3:
          image: daocloud.io/library/redis:5.0.7
          restart: always
          container_name: redis3
          environment:
              - TZ=Asia/Shanghai
          ports:
              - 7003:6379
          volumes:
              - ./conf/redis3.conf:/usr/local/redis/redis.conf
              - ./data3:/data # 映射数据
              - ./conf/sentinel3.conf:/data/sentinel.conf
          links:
              - redis1:master    
          command: ["redis-server","/usr/local/redis/redis.conf"] 
    
    • 从节点的redis.conf文件中添加

      replicaof master 6379
      

7 redis 哨兵

主从存在的问题, 当主节点挂了之后就无法写入数据了, 开启哨兵后可以监听 redis , 当主节点挂了后将会通过算法 把从节点提升为主节点

  • 编写 sentinel.conf 文件

    #哨兵需要后台启动
    daemonize yes
    #指定Master节点的ip和端口(主)
    sentinel monitor master localhost 6379 2
    #指定Master节点的ip和端口(从)
    sentinel monitor master master 6379 2
    #哨兵每隔多久监听一次redis架构
    sentinel down-after-milliseconds master 10000
    
  • 进入容器内 /data 下运行哨兵

    redis-sentinel sentinel.conf 
    

8 redis 集群配置

1.Redis集群是无中心的。
2.Redis集群有一个ping-pang机制。
3.投票机制,Redis集群节点的数量必须是2n+1。
4.Redis集群中默认分配了16384个hash槽,在存储数据时,就会将key进行crc16的算法,并且对16384取余,根据最终的结果,将key-value存放到执行Redis节点中,而且每一个Redis集群都在维护着相应的hash槽

5.为了保证数据的安全性,每一个群集节点都会跟随一个从节点, 这个从节点不是主从,不会分担主节点的查询压力,只会同步主节点的数据, 当主节点挂掉后, 从节点补上

  1. 如果集群单一节点中的查询压力过大,可以针对当前节点搭建主从
  2. 如果集群超过一半的节点挂掉,那么集群就瘫痪了
  • docker-compose.yml

    version: "3.1"
    services:
      redis1:
          images: daocloud.io/library/redis:5.0.7
          restart: always
          container_name: redis1
          environment:
              - TZ=Asia/Shanghaii
          ports:
              - 7001:7001
              - 17001:17001
          volumes:
              - ./conf/redis1.conf:/usr/local/redis/redis.conf
              - ./data1:/data # 映射data目录
              # - ./conf/sentinel1.conf:/data/sentinel.conf # 哨兵配置文件
          command: ["redis-server","/usr/local/redis/redis.conf"] 
      redis2:
          images: daocloud.io/library/redis:5.0.7
          restart: always
          container_name: redis2
          environment:
              - TZ=Asia/Shanghaii
          ports:
              - 7002:7002
              - 17002:17002
          volumes:
              - ./conf/redis2.conf:/usr/local/redis/redis.conf
              - ./data2:/data # 映射data目录
              # - ./conf/sentinel1.conf:/data/sentinel.conf # 哨兵配置文件
          command: ["redis-server","/usr/local/redis/redis.conf"] 
      redis3:
          images: daocloud.io/library/redis:5.0.7
          restart: always
          container_name: redis3
          environment:
              - TZ=Asia/Shanghaii
          ports:
              - 7003:7003
              - 17003:17003
          volumes:
              - ./conf/redis3.conf:/usr/local/redis/redis.conf
              - ./data3:/data # 映射data目录
              # - ./conf/sentinel1.conf:/data/sentinel.conf # 哨兵配置文件
          command: ["redis-server","/usr/local/redis/redis.conf"] 
      redis4:
          images: daocloud.io/library/redis:5.0.7
          restart: always
          container_name: redis4
          environment:
              - TZ=Asia/Shanghaii
          ports:
              - 7004:7004
              - 17004:17004
          volumes:
              - ./conf/redis4.conf:/usr/local/redis/redis.conf
              - ./data4:/data # 映射data目录
              # - ./conf/sentinel1.conf:/data/sentinel.conf # 哨兵配置文件
          command: ["redis-server","/usr/local/redis/redis.conf"] 
      redis5:
          images: daocloud.io/library/redis:5.0.7
          restart: always
          container_name: redis5
          environment:
              - TZ=Asia/Shanghaii
          ports:
              - 7005:7005
              - 17005:17005
          volumes:
              - ./conf/redis5.conf:/usr/local/redis/redis.conf
              - ./data5:/data # 映射data目录
              # - ./conf/sentinel1.conf:/data/sentinel.conf # 哨兵配置文件
          command: ["redis-server","/usr/local/redis/redis.conf"] 
      redis6:
          images: daocloud.io/library/redis:5.0.7
          restart: always
          container_name: redis6
          environment:
              - TZ=Asia/Shanghaii
          ports:
              - 7006:7006
              - 17006:17006
          volumes:
              - ./conf/redis6.conf:/usr/local/redis/redis.conf
              - ./data6:/data # 映射data目录
              # - ./conf/sentinel1.conf:/data/sentinel.conf # 哨兵配置文件
          command: ["redis-server","/usr/local/redis/redis.conf"] 
    
  • 集群下redis.conf

    每个redis 服务都需要改

    如果出现端口占用等异常情况重启docker

    #redis.conf
    #指定redis的端口号
    port 7001
    #开启Redis集群
    cluster-enabled yes
    #集群信息的文件
    cluster-config-file nodes-7001.conf
    #集群的对外ip地址
    cluster-announce-ip 120.25.249.140
    #集群的对外port
    cluster-announce-port 7001
    #集群的总线端口
    cluster-announce-bus-port 17001
    
    • 进入随笔一个redis 服务器中运行 redis-cli 命令

      redis-cli --cluster create 120.25.249.140:7001 120.25.249.140:7002 120.25.249.140:7003 120.25.249.140:7004 120.25.249.140:7005 120.25.249.140:7006 --cluster-replicas 1 
      

      redis-cli --cluster create ip:port … --cluster-replicas 1

      –cluster-replicas 1 是指定每个集群redis配置一个从节点

    • 搭建集群后可以通过任意一个cli 连接 任意节点

      redis-cli -h 120.25.249.140 -p 7002 -c
      

      -c 在存储数据时如果通过计算存入其他节点时自动切换连接

      示例 :

      120.25.249.140:7002> set 123 123
      OK
      120.25.249.140:7002> set qqqq 123
      -> Redirected to slot [3623] located at 120.25.249.140:7001
      OK
      120.25.249.140:7001>

9 redis 常见问题

  • key的生存时间到了,Redis会立即删除吗?

不会立即删除。
1.定期删除:
Redis每隔一段时间就去会去查看Redis设置了过期时间的key,会再100ms的间隔中默认查看3个key。
2.惰性删除:
如果当你去查询一个已经过了生存时间的key时,Redis会先查看当前key的生存时间,是否已经到了,直接删除当前key,并且给用户返回一个空值。

9.1 redis淘汰机制

在Redis内存已经满的时候,添加了一个新的数据,执行淘汰机制。

通过配置文件开启

maxmemory-policy 具体策略

设置redis 最大内存

maxmemory 字节大小

1.volatile-lru:

​ 在内存不足时,Bedis会再设置过了生存时间的key中干掉一个最近最少使用的key。
2.allkeys-lru:
​ 在内存不足时,Redis会再全部的key中干掉一个最近最少使用的key。
3.volatile-fu:

​ 在内存不足时,redis会再设置过了生存时间的key中干掉一个最近最少频次使用的key。
4.allkeys-lfu:

​ 在内存不足时,redis会再全部的key中干掉一个最近最少频次使用的key。
5.volatile-random:
​ 在内存不足时,redis会再设置过了生存时间的key中随机干掉一个。
6.alkeys-random:
​ 在内存不足时,redis会再全部的key中随机干掉一个。
7.volatile-:
​ 在内存不足时,redis会再设置过了生存时间的key中干掉一个剩余生存时间最少的key。
8.noeviction:(默认)

​ 在内存不足时,直接报错。

9.2 缓存穿透,缓存击穿,缓存雪崩,缓存倾斜

  • 缓存穿透

    • 原因

      缓存中没有, 去查数据库,数据库中也没有,导致访问量太大,数据库宕机

    • 解决方案

      首先要考虑是不是恶意攻击

      现在java中判断数据是否可能存在 如果是不合理的请求,那么直接无需处理,比如数据库主键是自增的,请求访问的数值超出的数据库的数据

      短时间内同一ip大量访问不存在的数据,进行 ip 限制

      1:根据id查询时,如果id是自增的,将id的最大值放到Redis中,在查询数据库之前,直接比较一下id。
      2:如果id不是整形,可以将全部的id放到set中,在用户查询之前,去set中查看一下是否有一个id。
      3:获取客户端的ip地址,可以将ip的访问添加限制。

      当访问一个数据库中没有的数据时, 在redis中设置一个生命周期短的假数据

  • 缓存击穿

    • 原因

      缓存中的热点数据过期了 , 大量的请求直达数据库, 导致数据库压力过大宕机

    • 解决方案

      1. 在访问缓存中没有数据的时候, 去数据库取数据时,添加锁, 只让几个请求取访问数据库,避免宕机
      2. 热点数据设置永不过期
  • 缓存雪崩

    • 原因

      同一时间,大量热点数据过期,导致同时访问数据库,数据库宕机

    • 解决方案

      1. 在设置过期时间时,分散设置 可以为30-60的一个随机时间
  • 缓存倾斜

    • 原因

      大量的热点数据存放在 一个 redis 集群节点中 ,导致redis节点宕机

    • 解决方案

      1. 给单个集群节点搭建主从,提高性能
      2. 在代码中使用map缓存数据,帮助 redis 分担压力 , 或使用其他缓存工具,分担redis节点压力
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值