舒大少博客

一个95后少年的个人博客

当前时间为:
欢迎大家来到舒大少博客http://admin.evshou.com,广告合作以及淘宝商家推广请微信联系15357240395
...
零基础学Python从入门到精通 python基础教程基础

【在售价】34.90 元
【在售价】34.90 元

立即领券
...
Python编程从入门到精通 视频教学 python语言程序设计

【在售价】29.80 元
【券后价】19.80元

立即领券
...
未来教育计算机二级ms office题库电子版c语言

【在售价】28.00 元
【在售价】28.00 元

立即领券
...
Python3视频零基础教程自学入门到精通编程语言程序设计网络爬虫

【在售价】62.00 元
【券后价】52.00元

立即领券
...
Python编程从入门到精通 零基础学python数据分析

【在售价】29.80 元
【券后价】19.80元

立即领券

2020java微服务架构四之Redis教程

2021-01-28 15:08:55
swq1822677238

手机扫码查看

2020java微服务架构四之Redis教程

2020java微服务架构四之Redis教程

一、Redis介绍

1.NoSQL介绍

Redis就是一款NoSQL
NoSQL->非关系型数据库–>Not Only SQL
key-value:Redis
文档型:ElasticSearch,Solr,Mongdb
面向列:Hbase,Cassandra
图形化:Neo4j
除了关系型数据库都是非关系型数据库
noSQL只是一种概念,泛指非关系型数据库,和关系型数据库做一个区分

2.Redis介绍

有一位意大利人,在开发一款LLOOGG的统计页面,因为MySQL的性能不好,自己研发了一款非关系型数据库,并命名为Redis。Salvatore。
Redis (Remote Dictionary Server)即远程字典服务,Redis是由C语言去编写,Redis是一款基于Key-Value的NoSQL,而且Redis是基于内存存储数据的,Redis还提供了多种持久化机制,性能可以达到110000/s读取数据以及81000/s写入数据,Redis还提供了主从,哨兵以及集群的搭建方式,可以更方便的横向扩展以及垂直扩展。

二、Redis安装

1.安装Redis

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

2.使用redis-cli连接Redis

进入Redis容器内部:docker exec -it 标识 bash
连接Redis:redis-cli

3.使用图形化界面连接Redis

Redis图形化管理:https://github.com/lework/RedisDesktopManager-Windows/releases

三、redis常用命令【重点】

1.redis存储数据的结构

常用的五种数据结构:
1.key-string: 一个key对应一个值
2.key-hash:一个key对应一个map
3.key-list:一个key对应一个列表
4.key-set:一个key对应一个集合
5.key-zset:一个key对应一个有序的集合

另外三种数据结构:
HyperLogLog:计算近似值
GEO:地理位置
BIT:一般存储的也是一个字符串,存储的是一个byte[]

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

2.常用命令

2.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
7.设置值的同时,指定生存时间(每次向redis中添加数据时,尽量都设置生存时间)
setex key second value
8.设置值,如果当前key不存在的话,存储值,否则什么事不做
setnx key value
9.在key对应的value后,追加内容
append key value
10.查看value字符串的长度
strlen key

redis文档教程:http://redisdoc.com/

2.2 hash常用命令

1.存储数据:hset key field value
2.获取数据:hget key field
3.批量操作:
hmset key field value field value
hmget key field field
4.自增数据(指定自增的值):hincrby key field increment
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

2.3 list常用命令

1.存储数据(批量):
左侧插入:lpush key value
右侧插入:rpush key value

2.存储数据(单个)
lpushx key value / rpush key value

3.修改数据(覆盖指定位置的数据)
lset key index value

4.弹栈方式获取数据(弹出后删除数据)
lpop key / rpop key

5.获取指定索引范围的数据(start 从 0开始,stop输入-1代表最后一个,-2代表倒数第二个)
lrange key start stop

6.获取指定索引位置的位置
lindex key index

7.获取整个列表的长度
llen key

8.删除列表中的数据,删除当前表中的count个value值,count>0从左侧向右侧删除,<0从右向左删除,==0删除列表中全部的value
lrem key count value

9.保留列表中的数据(保留你指定索引范围内的数据,超过整个索引范围被移除掉)
ltrim key start stop

10.将一个列表中最后一个值,插入到另外一个列表的头部位置
rpoplpush list1 list2


2.4 set常用命令

1.存储数据:sadd key member

2.获取数据:smembers key

3.随机获取一个数据:spop key count

4.交集,取多个set集合交集:sinter set1 set2

5.并集,获取全部集合中 的数据:sunion set1 set2

6.差集,获取多个集合中不一样的数据:sdiff set1 set2

7.删除数据:srem key member

8.查看当前的set集合中是否包含这个值:sismember key member

2.5 zset的常用命令

1.添加数据(score必须是数值,member不能重复)
zadd key score memeber score member

2.修改member的分数(如果member存在则正常增加,否则添加数据zadd)
zincrby key increment member

3.查看指定的member的分数
zscore key member

4.获取zset中数据的数量
zcard key

5.根据score的范围查询member数量
zcount key min max

6.删除zset中的成员
zrem key member

#7.根据分数从小到大排序,获取指定范围内的数据(withscores如果添加这个参数,那么会返回member对应的分数)
zrange key start stop [withscores]

#8、根据分数从大到小排序。获取指定范围内的数据(withscores如果添加这个参数,那么会返回member对应的分数)
zrevrange key start stop [withscores]

#9、根据分数的范围去获取member(withscores代表同时返句score,添加limit,就和MySQL中一样、如果不希望等于min或者max的值被查询出来可以见用‘(分数’相当于<但是不等于的方式,最大值和最小值使用+inf和-inf来表示)
zrangebyscore key min max [withscores] [limit offset count]

#10.根据分数的范围去获取member(withscores代表同时返回score,添加limit,就和MySQL中一样)
zrangebyscore key max min[withscores][limit offset count]


2.6 key常用指令

1.查看redis中的全部key(pattern:*,xxx*,*xxx)
keys pattern

2.查看某一个key是否存在(1:key存在。0:key不存在)
exists key

3.删除key:del key

4.设置key的生存时间,单位为秒/毫秒
expire key second / pexpire key milliseconds

5.设置key的生存时间,单位为秒/毫秒,设置能活到什么时间
expire key timestamp / pexpire 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



2.7 库的常用命令

1.清空当前所在的数据库:flushdb

2.清空所有的数据库:flushall

3.查看当前所在的库有多少个key:dbsize

4.查看最后一次操作的时间:lastsave

5.实时监控Redis服务接收到的命令(需新建session会话):monitor

四、java连接Redis【重点】

1.jedis连接redis

1.1导入依赖:lombok,junit,jedis

  <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.4</version>
  </dependency>
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
    <scope>test</scope>
  </dependency>
  <dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.9.0</version>
  </dependency>

1.2 测试

public class Demo1 {
    @Test
    public void set(){
        //1.连接 Redis
        Jedis jedis=new Jedis("192.168.2.123",6379);
        //2.操作 Redis--redis命令是什么,Jedis 命令就是什么
        jedis.set("name","李四");
        //3.释放资源
        jedis.close();
    }
    @Test
    public void get(){
        //1.连接 Redis
        Jedis jedis=new Jedis("192.168.2.123",6379);
        //2.操作 Redis--redis命令是什么,Jedis 命令就是什么
        String name = jedis.get("name");
        System.out.println(name);
        //3.释放资源
        jedis.close();
    }
}

2. jedis存储一个对象到redis以byte[]的形式

2.1 创建一个实体类并且实现Serializable接口

2.3 导入spring-content依赖

2.4编写测试类

public class Demo2 {
    //存储对象,以byte[] 形式存储在redis中
    @Test
    public void setByteArray(){
        //1.连接 Redis
        Jedis jedis=new Jedis("192.168.2.123",6379);
        //2.1 准备key(Sring)-->value(User)
        String key="user";
        User user=new User(1,"张三","男",new Date(),5000.2);
        byte[] byteKey = SerializationUtils.serialize(key);
        byte[] byteValue = SerializationUtils.serialize(user);
        jedis.set(byteKey,byteValue);
        //3.释放资源
        jedis.close();
    }
    @Test
    public void getByteArray(){
        //1.连接 Redis
        Jedis jedis=new Jedis("192.168.2.123",6379);
        //2.1 准备key
        String key="user";
        byte[] byteKey = SerializationUtils.serialize(key);
        byte[] bytesValue = jedis.get(byteKey);
        User user = (User) SerializationUtils.deserialize(bytesValue);
        System.out.println("user:" + user);
        //3.释放资源
        jedis.close();
    }
}

3. jedis存储一个对象到redis以String形式

3.1 导入依赖 fastjson

3.2  测试

public class Demo3 {
    //存储对象-以String形式存储
    @Test
    public void setString(){
        //1.连接 Redis
        Jedis jedis=new Jedis("192.168.2.123",6379);
        //2.1 准备key(String)-->value(User)
        String stringKey="stringUser";
        User value=new User(2,"admin2","女",new Date(),6666.66);
        //2.2 使用 fastJson 将 value 转化为 json字符串
        String stringValue = JSON.toJSONString(value);
        //2.3 存储到 redis 中
        jedis.set(stringKey,stringValue);
        //3.释放资源
        jedis.close();
    }
    //获取对象-以String形式获取
    @Test
    public void getString(){
        //1.连接 Redis
        Jedis jedis=new Jedis("192.168.2.123",6379);
        //2.1 准备key(String)-->value(User)
        String stringKey="stringUser";
        //2.2 去redis中查询value
        String value = jedis.get(stringKey);
        //2.3 将value反序列化为User
        User user = JSON.parseObject(value,User.class);
        //2.4 输出
        System.out.println("user:" + user);
        //3.释放资源
        jedis.close();
    }
}

4. jedis 连接池的操作

使用连接池操作redis,避免频繁创建和销毁连接对象消耗资源

public class Demo4 {
    @Test
    public void pool(){
        //1. 创建连接池配置信息
        GenericObjectPoolConfig pc=new GenericObjectPoolConfig();
        pc.setMaxTotal(100);//连接池中最大的活跃数
        pc.setMaxIdle(10);//最大空闲数
        pc.setMinIdle(5);//最小空闲数
        pc.setMaxWaitMillis(3000);//当连接池空了以后,多久没获得到jedis对象,就超时
        //2. 创建连接池
        JedisPool jp=new JedisPool("192.168.2.123",6379);
        //3. 通过连接池获取 jedis 对象
        Jedis jedis = jp.getResource();
        //4. 操作
        String value = jedis.get("stringUser");
        System.out.println("User:" + value);
        jp.close();
    }
}

 

5. Redis 管道的操作

因为在操作Redis的时候,执行一个命令需要先发送请求到Redis服务器,这个过程需要经历网络的延迟,Redis还需要给客户端一个响应。
如果我需要一次性执行很多个命令,上述的方式效率很低,可以通过Redis的管道,先将命令放到客户端的一个Pipeline中,之后一次性的将全部命令都发送到Redis服务,Redis服务一次性的将全部的返回结果响应给客户端。

public class Demo5 {
    @Test
    public void pipeline(){
        //1. 创建连接池
        JedisPool pool=new JedisPool("192.168.2.123",6379);
        long l=System.currentTimeMillis();
        //2. 获取一个连接对象
        Jedis jedis = pool.getResource();
        //3. 创建管道
        Pipeline pipelined = jedis.pipelined();
        //3.1 执行incr - 100000次放到管道中
        for(int i=0;i<100000;i++){
            pipelined.incr("qq");
        }
        //4. 执行命令
        pipelined.syncAndReturnAll();
        //5. 释放资源
        jedis.close();
        System.out.println(System.currentTimeMillis()-l);
    }
}

五、 Redis其他配置及集群

修改yml文件,以方便后期修改redis配置信息

version: '3.1'
services:
  redis:
    restart: always
    image: daocloud.io/library/redis:5.0.7
    container_name: redis
    environment:
      - TZ=Asia/Shanghai
    ports:
      - 6379:6379
    volumes:
      - ./conf/redis.conf:/user/local/redis/redis.conf
    command:  ["redis-server","/user/local/redis/redis.conf"]

执行:docker-compose down
执行:docker-compose up -d

5.1 Redis的AUTH

修改文件:redis.conf

# Redis的AUTH密码
requirepass redis

然后在idea中修改测试代码


redis设置密码:config set requirepass password

输入密码:auth password

idea在连接池配置方法添加密码以及超时时间

public class Demo6 {
    @Test
    public void auth(){
        //1. 创建连接池配置信息
        GenericObjectPoolConfig pc=new GenericObjectPoolConfig();
        pc.setMaxTotal(100);//连接池中最大的活跃数
        pc.setMaxIdle(10);//最大空闲数
        pc.setMinIdle(5);//最小空闲数
        pc.setMaxWaitMillis(3000);//当连接池空了以后,多久没获得到jedis对象,就超时
        //2. 创建连接池
        JedisPool jp=new JedisPool(pc,"192.168.2.123",6379,3000,"redis");
        Jedis jedis = jp.getResource();
        jedis.set("name", "admin888");
        jedis.close();
    }
}

5.2 Redis的事务

Redis的事务:一次事务操作,改成功的成功,该失败的失败。
先开启事务,执行一些列的命令,但是密码不会立即执行,会被放在一个队列中,如果你执行事务,那么这个队列中的命令全部执行,如果取消了事务,一个队列中的命令全部作废。
1.开启事务:multi
2. 输入要执行的命令:被放入到一个队列中
3. 执行事务:exec
4. 取消事务:discard
Redis的事务想发挥功能,需要配置watch监听机制
在开启事务之前,先通过watch命令去监听一个或多个key,在开启事务之后,如果有其他客户端修改了我监听的key,事务会自动取消。 I
如果执行了事务,或者取消了事务,watch监听自动消除,一般不需要手动执行unwatch。

5.3 Redis持久化

RDB是Redis默认的持久化机制:

1.RDB持久化文件,速度比较快,而且存储的是一个二进制的文件,传输起来很方便。

2.RDB持久化时机:

save 900 1 :900秒之内,有1个key改变就执行RDB持久化
save 300 10 :300秒之内,有10个key改变就执行RDB持久化
save 60 10000 :60秒之内,有一万个key改变就执行RDB持久化

3.RDB无法保证数据的绝对安全

在redis文件夹下打开redis.conf文件,搜索RDB,复制

save 900 1
save 300 10
save 60 10000

rdbcompression yes

dbfilename dump.rdb

然后在Linux修改redis.conf文件

修改docker-compose.yml文件

添加数据卷:./data:/data

然后执行:docker-compose down 、docker-compose up -d

然后在配置文件查找 AOF,然后复制

appendonly no

appendfilename “appendonly.aof”

# appendfsync always
appendfsync everysec
# appendfsync no

修改配置文件 redis.conf

然后重启:docker-compose restart

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

同时开启RDB和AOF的注意事项
如果同时开启了AOF和RDB持久化,那么在Redis宕机重启之后,需要加载一个持久化文件,优先选择AOF文件。
如果先开启了RDB,再次开启AOF,如果RDB执行了持久化,那么RDB文件中的内容会被AOF覆盖掉。

5.4 Redis的主从架构

单机版 Redis存在读写瓶颈的问题

配置信息:

在opt目录下新建 docker_redis_master_slave,然后创建docker-compose.yml文件

主节点配置:

version: '3.1'
services:
  redis1:
    restart: always
    image: daocloud.io/library/redis:5.0.7
    container_name: redis1
    environment:
      - TZ=Asia/Shanghai
    ports:
      - 7001:6379
    valumes:
      - ./conf/redis1.conf:/usr/local/redis/redis.conf
    command:  ["redis-server","/usr/local/redis/redis.conf"]
  redis2:
    restart: always
    image: daocloud.io/library/redis:5.0.7
    container_name: redis2
    environment:
      - TZ=Asia/Shanghai
    ports:
      - 7002:6379
    valumes:
      - ./conf/redis2.conf:/usr/local/redis/redis.conf
    links:
      - redis1:master
    command:  ["redis-server","/usr/local/redis/redis.conf"]
  redis3:
    restart: always
    image: daocloud.io/library/redis:5.0.7
    container_name: redis3
    environment:
      - TZ=Asia/Shanghai
    ports:
      - 7003:6379
    valumes:
      - ./conf/redis3.conf:/usr/local/redis/redis.conf
    links:
      - redis1:master
    command:  ["redis-server","/usr/local/redis/redis.conf"]

 

redis2和redis3从节点配置

在配置文件搜索replicaof <masterip> <masterport>

创建 conf文件夹,然后创建 touch redis1.conf 、 touch redis2.conf 、 touch redis3.conf

然后编辑刚刚创建的文件,将下面的代码复制粘贴,然后保存即可。

replicaof master 6379

然后返回上一级目录,启动docker-compose up -d

查看日志:docker-compose logs -f

 

5.5 Redis的哨兵

哨兵可以帮助我们解决主从架构中的单点故障问题

准备哨兵的配置文件,并且在容器内部手动启动哨兵即可

在conf目录下创建 sentinel1.conf  sentinel2.conf sentinel3.conf

# 哨兵需要后台启动
daemonize yes
# 指定 master 节点的 ip和端口(主)
# sentinel monitor <master-name> <ip> <redis-port> <quorum>
sentinel monitor master localhost 6379 2
# 指定 master 节点的 ip和端口(从)
sentinel monitor master master 6379 2
# 哨兵每隔多久监听一次redis架构
sentinel down-after-milliseconds master 10000

修改 docker-compose.yml,为了可以在容器内部使用哨兵的配置

为每个redis添加数据卷

– ./conf/sentinel1.conf:/data/sentinel.conf

最后执行 docker-compose down、docker-compose up -d

然后进入容器内部:docker exec -it redis1标识bash

然后展示 ls,哨兵可运行文件在 cd /usr/local/bin

返回到data目录,然后运行:redis-sentinel sentinel.conf,然后exit

然后docker ps,docker exec -it redis2标识 bash

运行:redis-sentinel sentinel.conf,然后exit

然后docker ps,docker exec -it redis3标识 bash

运行:redis-sentinel sentinel.conf,然后exit

查看是否是master:进入容器内部,然后redis-cli,之后执行 info 查看是否是master,然后查看有几个哨兵

 

5.6 Redis的集群

Redis集群在保证主从加哨兵的基本功能之外,还能够提升Redis存储数据的能力

redis集群架构图

docker-compose.yml

先停止docker所有进程然后删除docker所有容器

在 opt目录下创建 docker_redis_cluster,然后进入该目录创建 docker-compose.yml文件

version: '3.1'
services:
  redis1:
    restart: always
    image: daocloud.io/library/redis:5.0.7
    container_name: redis1
    environment:
      - TZ=Asia/Shanghai
    ports:
      - 7001:7001
      - 17001:17001
    volumes:
      - ./conf/redis1.conf:/usr/local/redis/redis.conf
    command:  ["redis-server","/usr/local/redis/redis.conf"]
  redis2:
    restart: always
    image: daocloud.io/library/redis:5.0.7
    container_name: redis2
    environment:
      - TZ=Asia/Shanghai
    ports:
      - 7002:7002
      - 17002:17002
    volumes:
      - ./conf/redis2.conf:/usr/local/redis/redis.conf
    command:  ["redis-server","/usr/local/redis/redis.conf"]
  redis3:
    restart: always
    image: daocloud.io/library/redis:5.0.7
    container_name: redis3
    environment:
      - TZ=Asia/Shanghai
    ports:
      - 7003:7003
      - 17003:17003
    volumes:
      - ./conf/redis3.conf:/usr/local/redis/redis.conf
    command:  ["redis-server","/usr/local/redis/redis.conf"]
  redis4:
    restart: always
    image: daocloud.io/library/redis:5.0.7
    container_name: redis4
    environment:
      - TZ=Asia/Shanghai
    ports:
      - 7004:7004
      - 17004:17004
    volumes:
      - ./conf/redis4.conf:/usr/local/redis/redis.conf
    command:  ["redis-server","/usr/local/redis/redis.conf"]
  redis5:
    restart: always
    image: daocloud.io/library/redis:5.0.7
    container_name: redis5
    environment:
      - TZ=Asia/Shanghai
    ports:
      - 7005:7005
      - 17005:17005
    volumes:
      - ./conf/redis5.conf:/usr/local/redis/redis.conf
    command:  ["redis-server","/usr/local/redis/redis.conf"]
  redis6:
    restart: always
    image: daocloud.io/library/redis:5.0.7
    container_name: redis6
    environment:
      - TZ=Asia/Shanghai
    ports:
      - 7006:7006
      - 17006:17006
    volumes:
      - ./conf/redis6.conf:/usr/local/redis/redis.conf
    command:  ["redis-server","/usr/local/redis/redis.conf"]

 

redis.conf

在docker_redis_cluster 创建 conf目录,分别创建 redis1.conf redis2.conf ~ redis6.conf

# 指定redis的端口号
port 7001
# 开启redis集群
cluster-enabled yes
# 集群信息的文件
cluster-config-file nodes-7001.conf
# 集群的对外ip地址
cluster-announce-ip Linux的ip
# 集群的对外端口
cluster-announce-port 7001
# 集群的总线端口
cluster-announce-bus-port 17001

然后在 docker_redis_cluster目录下 启动 docker-compose up -d

然后进入容器内部
执行 管理集群:redis-cli –cluster create Linux的ip:7001 ip:7002 ~ ip:7006 –cluster-replicas 1
然后 exit,之后执行:redis-cli -h ip -p 7001 -c




 

5.7 java连接Redis集群

使用JedisCluster对象连接Redis集群

@Test
public void test(){
    // 创建 Set<HostAndPort> nodes
    Set<HostAndPort> nodes=new HashSet<>();
    nodes.add(new HostAndPort("192.168.2.123",7001));
    nodes.add(new HostAndPort("192.168.2.123",7002));
    nodes.add(new HostAndPort("192.168.2.123",7003));
    nodes.add(new HostAndPort("192.168.2.123",7004));
    nodes.add(new HostAndPort("192.168.2.123",7005));
    nodes.add(new HostAndPort("192.168.2.123",7006));

    //创建 JedisCluster 对象
    JedisCluster jc=new JedisCluster(nodes);
    // 操作
    String value = jc.get("a");
    System.out.println("value:"+value);
}

 

六、Redis常见问题

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

不会立即删除。

1.定期删除:
Redis每隔一段时间就会去查看Redis设置了过期时间的key,会在100ms的间隔中默认查看3个key

2.惰性删除:
如果当你去查询一个已经过了生存时间的key时,Redis会查看当前key的生存时间,是否已经到了,直接删除当前key,并且给用户返回一个空值。

6.2 Redis的淘汰机制

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

1. volatile-lru
在内存不足时,Redis会在设置过了生存时间的key中干掉一个最近最少使用的key

2. allkeys-lru
在内存不足时,Redis会在全部的key中干掉一个最近最少使用的key

3. volatile-lfu
在内存不足时,Redis会在设置过了生存时间的key中干掉一个最近最少频次使用的key

4. allkeys-lfu
在内存不足时,Redis会在全部的key中干掉一个最近最少频次使用的key

5. volatile-random
在内存不足时,Redis会在设置过了生存时间的key中随机干掉一个

6. allkeys-random
在内存不足时,Redis会在全部的key中随机干掉一个

7. volatile-ttl
在内存不足时,Redis会在设置过了生存时间的key中干掉剩余生存时间最少的key

8. noeviction(默认)
在内存不足时,直接报错。

指定淘汰机制的方式:maxmemory-policy 具体策略

设置Redis的最大内存:maxmemory <bytes> //字节大小

6.3 Redis的缓存问题

缓存穿透

问题出现的原因:查询的数据,Redis中没有,数据库中也没有

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

缓存击穿

问题:缓存中的热点数据,突然到期了,造成了大量的请求都去访问数据库,造成数据库宕机

1.在访问缓存中没有的时候,直接添加一个锁,让几个请求去访问数据库,避免数据库宕机。
2.热点数据的生存时间去掉。

缓存雪崩

问题:当大量缓存同时到期时,最终大量的同时去访问数据,导致数据库宕机

将缓存中的数据的生存时间,设置为30~60的一个随机时间

缓存倾斜

问题:热点数据放在了一个Redis节点上,导致Redis节点无法承受住大量的请求,最终Redis宕机。

1.扩展主从架构,搭建大量的从节点,缓解Redis的压力
2.可以在Tomcat中做JVM缓存,在查询Redis之前,先去查询Tomcat中的缓存。

发表评论

邮箱地址不会被公开。 必填项已用*标注