一、Redis介绍

1.主要解决的问题:

  1. 用户数量大,请求量大,数据库读写压力大。
  2. 多台应用服务器之间数据不同步。
  3. 多台服务器之间的锁,已经不存在互斥性,无法保障线程安全的操作。

2.Redis-NoSQL数据库

  • Redis是一款NoSql数据库(非关系型数据库)
  • Key-Value:Redis。
  • 文档型:ElasticSearch,Solr,MongoDB
  • 面向列:HBASE, Cassandra
  • 图形化:Neo4j
  • 除了关系型数据库都是菲关系型数据库。
  • NoSQL只是一种概念,泛指非关系非关系型数据库,和关系型数据库做区分

二、Redis安装

1. 官网下载直接安装 Redis下载地址

2.使用Docker-Compose安装

2.1 docker-compose.yml文件

version: '3.1'
services:redis:image: daocloud.io/library/redis:5.0.7restart: alwayscontainer_name: redisenvironment:- TZ=Asia/Shanghaiports:-6379:6379

1.在LInux下建立docker-compose.yml文件
2.使用docker-compose up -d 命令启动docker容器

2.2使用redis-cli连接Redis

1.进入容器内部:docker exec -it 容器id bash
2.在容器内部使用redis-cli连接Redis

3.使用图形化工具连接Redis

下载链接

三、Redis常用命令

1.Redis数据的存储结构

常用的五种数据结构:

  • key-string:一个key对应一个值

  • key-hash:一个key对应一个Map

  • key-list:一个key对用一个列表

  • key-set:一个key对应一个集合

  • key-zset:一个key对应一个有序的集合
    另外三种数据结构

  • HyperLogLog:计算近似值

  • GEO:地理位置

  • BIT:一般存储的是一个字符串,存储的是一个byte[]。

  • key-string:最常用,一般用于存储一个值。

  • key-hash:存储一个对象数据

  • key-list:使用list结构实现栈和队列结构

  • key-zset:排行榜,积分存储等操作

2.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不存在的话(存在的话,什么也不做,如果不存在,同set命令)
setnx key value
# 9. 在key对应的value后,追加内容(相当于字符串拼接)
append key value
# 10. 查看value字符串的长度
strlen key

3.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. 设置值(如果可以-field不存在,就正常添加,存在,什么也不做)
hsetnx key field value
# 6. 检查filed是否存在
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

4、 list常用命令

# 1. 存储数据
# 左插入
lpush key value [value ...]
# 右插入
rpush key value [value ...]
# 2. 存储数据(如果key不存在,什么事都不做,如果key存在,但不是list结构,什么也不做)
lpushx key value
rpushx key value
# 3. 修改数据(在存储数据时,指定好你的索引位置,覆盖之前索引位置的数据,index超出整个列表的长度会失败)
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从左侧向右删除,count < 0 从右向左删除,count == 0 删除全部的value)
lrem key count value
# 9. 保留列表中的数据(保留你指定索引范围内的数据,超过索引范围被移除掉)
ltrim key start stop
# 10. 将一个列表中的最后一个数据,插入到另外一个列表的头部位置
rpoplpush list1 list2

5、set常用命令

# 1. 存储数据
sadd key member [member ...]
# 2. 获取数据(获取全部数据)
smembers key
# 3. 随机获取一个数据(获取的同时,移除数据,count默认为1,代表弹出的数据量)
spop key [count]
# 4. 交集(去多个set集合交集)
sinter set1 set2
# 5. 并集(获取全部集合中的数据)
sunion set1 set2
# 6. 差集(获取多个集合中不一样的数据)
sdiff set1 set2
# 7. 删除数据
srem key member [member ...]
# 8. 查看当前set集合中是否包含此值
sismember key member

6 、zset的常用命令

# 1. 添加数据(score必须是数值。member不允许重复)
zadd key score member [score member]
# 2. 修改member的分数(如果member是存在于key中的,正常增加分数,如果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 [member ...]
# 7. 根据分数从小到大排序,获取指定范围内的数据(withscores如果添加这个参数,那么就会返回member对应的分数)
zrang 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中一样)
zrangbyscore key max min[withscores] [limit offset count]

7、key的常用命令

# 1. 查看Redis中的全部的key (pattern: *,xxx*,*xxx)
keys pattern
# 2. 查看某一个key是否存在(1 - 存在,0 - 不存在)
exists key
# 3. 删除key
del key [key ...]
# 4. 设置key的生存时间,单位秒,单位毫秒,设置过期时间
expire key second
pexpire key milliseconds
# 5. 设置key的生存时间,单位为秒,单位为毫秒,设置能活到啥时候
expireat key timestamp
pexpireat key milliseconds
# 6. 查看key的剩余生存时间,单位秒,单位毫秒(-2 - 可以不存在,-1 - key没有设置生存时间,具体剩余的生存时间)
ttl key
pttl key
# 7 移除key的生存时间(1 - 移除成功, 0 - key不存在生存时间,key不存在)
persist key
# 8. 选择操作的库
select 0~15
# 9. 移动key到另外一个库中
move key db

8、Redis库常用命令

# 1. 清空当前所在的数据库
flushdb
# 2. 清空全部数据库
flushall
# 3. 查看当前数据库中有多少key
dbsize
# 4. 查看最后一次操作的时间(返回时间戳)
lastsave
# 5. 实时监控Redis服务接收到的命令
monitor

四、Java连接Redis

1.Jedis连接Redis

1.1 idea创建springboot项目添加依赖

        <!--redis--><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>3.2.0</version><type>jar</type><scope>compile</scope></dependency><!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.16</version><scope>provided</scope></dependency>

1.2 进行测试

 @Testvoid connection(){//测试连接//1.构建redis对象Jedis jedis = new Jedis("192.168.9.101",6379);//2、配置密码jedis.auth("123456");//3、测试连接String ping = jedis.ping();//4.返回pong表示连接成功System.out.println("ping = " + ping);}@Testvoid set() {//1、连接redisJedis jedis = new Jedis("192.168.9.101",6379);//2、密码认证jedis.auth("123456");//3、操作Redis,jedis和Redis命令一样,String value = jedis.set("name","李白");System.out.println("value = " + value);//4、释放资源,断开连接jedis.close();}@Testvoid get() {//1、连接redisJedis jedis = new Jedis("192.168.9.101",6379);//2、密码认证jedis.auth("123456");//3、操作Redis,jedis和Redis命令一样,String value = jedis.get("name");System.out.println("value = " + value);//4、释放资源,断开连接jedis.close();}

2、Jedis存储byte[]类型的对象到Redis中

2.1 准备一个实体类

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User  implements Serializable {private String name;private String address;private int age;private Date time;
}

2.2 测试

 @Testvoid  setByteRedis(){Jedis jedis = new Jedis("192.168.9.101",6379);jedis.auth("123456");User user = new User("libai","北京",11, new Date());// key 和 value 转化为 byte[] 类型byte[] byteValue = SerializationUtils.serialize(user);String key = "user";byte[] byteKey = SerializationUtils.serialize(key);jedis.set(byteKey, byteValue);jedis.close();}@Testvoid  getByteRedis(){Jedis jedis = new Jedis("192.168.9.101",6379);jedis.auth("123456");String key = "user";byte[] byteKey = SerializationUtils.serialize(key);byte[] user = jedis.get(byteKey);User deserialize = ((User) SerializationUtils.deserialize(user));System.out.println("deserialize = " + deserialize);jedis.close();}

3、Jedis以String的形式存储一个对象到Redis

3.1 导入依赖

     <!--fastjson--><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.75</version></dependency>

3.2 测试

@Testvoid setString(){Jedis jedis = new Jedis("192.168.9.101",6379);jedis.auth("123456");String key = "stringkey";User user = new User("王静","北京市",22,new Date());//使用fastJSON将value转化为json字符串String stringuser = JSON.toJSONString(user);jedis.set(key, stringuser);jedis.close();}@Testvoid getString(){Jedis jedis = new Jedis("192.168.9.101",6379);jedis.auth("123456");String key = "stringkey";String value = jedis.get(key);//将value 反序列化成UserUser user = JSON.parseObject(value, User.class);System.out.println("user = " + user);jedis.close();}

4、Jedis连接池操作

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

 @Testvoid jedispoolTest(){//1. 创建连接池配置信息GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();poolConfig.setMaxTotal(100);    //连接池中的最大活跃数poolConfig.setMaxIdle(10);      //最大空闲数poolConfig.setMinIdle(5);       //最小连接数poolConfig.setMaxWaitMillis(3000);  //当连接池空了之后,多久没获取到Jedis对象,就超时//2. 创建连接池JedisPool jedisPool = new JedisPool(poolConfig,"192.168.9.101",6379);//3. 通过连接池获取jedis对象Jedis jedis = jedisPool.getResource();jedis.auth("123456");//4. 操作String value = jedis.get("stringkey");System.out.println("value = " + value);jedis.close();}

5、Redis的管道操作

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

  //不使用管道操作@Testvoid unPipeline(){//1. 创建连接池JedisPool pool = new JedisPool("192.168.9.101",6379);long start = System.currentTimeMillis();//2. 获取连接对象Jedis jedis = pool.getResource();jedis.auth("123456");//3. 执行incr - 100000次for (int i = 0; i < 100000; i++) {jedis.incr("wulala");}//4. 释放资源jedis.close();long end = System.currentTimeMillis();// time = 60403System.out.println(end-start);}//使用管道操作@Testvoid pipeline(){//1. 创建连接池JedisPool pool = new JedisPool("192.168.9.101",6379);long start = System.currentTimeMillis();//2. 获取连接对象Jedis jedis = pool.getResource();jedis.auth("123456");//3. 创建管道Pipeline pipelined = jedis.pipelined();//4. 执行incr - 100000次 放入管道中操作for (int i = 0; i < 100000; i++) {pipelined.incr("wulala");}//5. 执行命令pipelined.syncAndReturnAll();//6. 释放资源jedis.close();long end = System.currentTimeMillis();// time = 288System.out.println(end-start);}

五、Redis配置及Redis集群

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

version: '3.1'
services:redis:image: daocloud.io/library/redis:5.0.7restart: alwayscontainer_name: redisenvironment:- TZ=Asia/Shanghaiports:-6379:6379volumes:- ./conf/redis.conf:/usr/local/redis/redis.confcommand: ["redis-server","/usr/local/redis/redis.conf"]

1、Redis-AUTH

  • 通过修改Redis的配置文件,实现Redis密码校验
# redis.conf
requirepass 密码

三种客户端连接方式

  • redis-cli 在输入正常命令之前,先输入auth密码即可
  • 图形化界面: 在连接Redis时指定密码
  • Jedis客户端:jedis.auth(“password”);
  • 使用Jedispool的方式
#使用有参构造设置密码
public JedisPool(final GenericObjectPoolConfig poolConfig, final String host, int port, int timeout, final String password)

在不修改redis.conf文件的前提下,第一次链接Redis时,输入命令 Config set requirepass 密码
后续再次操作Redis时,需要先AUTH 做验证。

2、Redis 事务

Redis事务:一次失误操作,该成功的成功,该失败的失败。
先开启事务,执行一些列的命令,但是命令不会立即执行,会存放在一个队列中,如果你执行事务,这个队列中的所有命令都会执行,取消事务,所有命令全部作废。

  • 开启事务: multi
  • 输入执行的命令:存放在队列中
  • 执行事务:exec
  • 取消事务:discard
    Redis的事务想要发挥功能,需要配置watch监听机制
    在开启事务之前,先通过watch命令去监听一个或多个key,在开启事务之后,如果有其它客户端修改了我监听的key,事务会自动取消。
    如果执行了事务,或者取消了事务,watch监听会自动消除,一般不需要执行unwatch

3、Redis 持久化

1. RDB

RDB是Redis默认的持久化机制

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

2.AOF

AOF持久化机制默认是关闭的,Redis官方推荐同时开启RDB和AOF持久化,更安全,避免数据丢失。

  • AOF持久化的速度,相对于RDB是较慢的,存储的是一个文本文件,到了后期文件会比较大,传输困难。
  • AOF持久化时机。
    appendfsync always:每执行一个写操作,立即持久化到AOF文件中,性能比较低。appendfsync ererysec:每一秒执行一次持久化。appendfsync no:会根据你的操作系统不同,环境的不同,在一定时间内持久。
  • AOF 相对RDB更安全,推荐同事开启AOF和RDB

3.注意事项

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

4.Redis的主从架构

Redis - docker-compose.yml 配置文件

version:
services:redis1:image: daocloud.io/library/redis:5.0.7restart: alwayscontainer_name: redis1environment:- TZ=Asia/Shanghaiports:- 7001:6379volumes:- ./conf/redis1.conf:/usr/local/redis/redis.confcommand: ["redis-server","/usr/local/redis/redis.conf"]redis2:image: daocloud.io/library/redis:5.0.7restart: alwayscontainer_name: redis2environment:- TZ=Asia/Shanghaiports:- 7002:6379volumes:- ./conf/redis2.conf:/usr/local/redis/redis.conflinks:     # redis1别名master  可以找到其他容器- redis1:mastercommand: ["redis-server","/usr/local/redis/redis.conf"]redis3:image: daocloud.io/library/redis:5.0.7restart: alwayscontainer_name: redis3environment:- TZ=Asia/Shanghaiports:- 7003:6379volumes:- ./conf/redis3.conf:/usr/local/redis/redis.conflinks:- redis1:mastercommand: ["redis-server","/usr/local/redis/redis.conf"]
# 从节点配置:redis2和redis3配置
replicaof master 6379

5.哨兵

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

version:
services:redis1:image: daocloud.io/library/redis:5.0.7restart: alwayscontainer_name: redis1environment:- TZ=Asia/Shanghaiports:- 7001:6379volumes:- ./conf/redis1.conf:/usr/local/redis/redis.conf- ./conf/sentinel1.conf:/data/sentinel.conf    #哨兵配置文件command: ["redis-server","/usr/local/redis/redis.conf"]redis2:image: daocloud.io/library/redis:5.0.7restart: alwayscontainer_name: redis2environment:- TZ=Asia/Shanghaiports:- 7002:6379volumes:- ./conf/redis2.conf:/usr/local/redis/redis.conf- ./conf/sentinel2.conf:/data/sentinel.conf    #哨兵配置文件links:     # redis1别名master  可以找到其他容器- redis1:mastercommand: ["redis-server","/usr/local/redis/redis.conf"]redis3:image: daocloud.io/library/redis:5.0.7restart: alwayscontainer_name: redis3environment:- TZ=Asia/Shanghaiports:- 7003:6379volumes:- ./conf/redis3.conf:/usr/local/redis/redis.conf- ./conf/sentinel3.conf:/data/sentinel.conf    #哨兵配置文件links:- redis1:mastercommand: ["redis-server","/usr/local/redis/redis.conf"]

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

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

在Redis容器内部启动sentinel即可
redis-sentinel sentinel.conf

6.Redis的集群

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

  • Redis集群是无中心的。
  • Redis集群有一个ping-pang机制
  • 投票机制,Redis集群节点的数量必须是2n+1.
  • Redis集群中默认分配了16384个hash槽,在存储数据时,就会将key进行crc16的算法,并且对16384取余,根据最终的结果,将key-value存放到指定Redis节点中,而且每一个Redis集群都在维护着相应的hash槽。
  • 为了保证数据的安全性,每一个集群的节点,至少要有一个从节点。
  • 单独针对Redis集群中的某一个节点搭建主从。
  • 当Redis集群中,超过半数的节点宕机之后,Redis集群就瘫痪了。
# docker-compose.yml文件
version: "3.1"
services:redis1:image: daocloud.io/library/redis:5.0.7restart: alwayscontainer_name: redis1environment:- TZ=Asia/Shanghaiports:- 7001:7001- 17001:17001volumes:- ./conf/redis1.conf:/usr/local/redis/redis.confcommand: ["redis-server","/usr/local/redis/redis.conf"]   redis2:image: daocloud.io/library/redis:5.0.7restart: alwayscontainer_name: redis2environment:- TZ=Asia/Shanghaiports:- 7002:7002- 17002:17002volumes:- ./conf/redis2.conf:/usr/local/redis/redis.confcommand: ["redis-server","/usr/local/redis/redis.conf"]   redis3:image: daocloud.io/library/redis:5.0.7restart: alwayscontainer_name: redis3environment:- TZ=Asia/Shanghaiports:- 7003:7003- 17003:17003volumes:- ./conf/redis3.conf:/usr/local/redis/redis.confcommand: ["redis-server","/usr/local/redis/redis.conf"]redis4:image: daocloud.io/library/redis:5.0.7restart: alwayscontainer_name: redis4environment:- TZ=Asia/Shanghaiports:- 7004:7004- 17004:17004volumes:- ./conf/redis4.conf:/usr/local/redis/redis.confcommand: ["redis-server","/usr/local/redis/redis.conf"]   redis5:image: daocloud.io/library/redis:5.0.7restart: alwayscontainer_name: redis5environment:- TZ=Asia/Shanghaiports:- 7005:7005- 17005:17005volumes:- ./conf/redis5.conf:/usr/local/redis/redis.confcommand: ["redis-server","/usr/local/redis/redis.conf"]   redis6:image: daocloud.io/library/redis:5.0.7restart: alwayscontainer_name: redis6environment:- TZ=Asia/Shanghaiports:- 7006:7006- 17006:17006volumes:- ./conf/redis6.conf:/usr/local/redis/redis.confcommand: ["redis-server","/usr/local/redis/redis.conf"]

配置文件说明:

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

启动了六个Redis节点。
随机进入到一个容器内部,使用redis-cli管理集群
注意:启动Redis集群必须保证集群内部是干净的。
查看redis cluster命令(redis-cli --cluster help)

redis-cli --cluster create 192.168.9.101:7001 192.168.9.101:7002 192.168.9.101:7003 192.168.9.101:7004 192.168.9.101:7005 192.168.9.101:7006 --cluster-replicas 1(每个主节点后面一个从节点)# 使用redis-cli 命令测试
redis-cli -h 192.168.9.101 -p 7001 -c(-c表示可以随意跳转到任意节点上)

7.Java连接Redis集群

 //Redsi-cluster 集群@Testvoid cluster(){//创建Set<HostAndPort> nodes 把所有的节点都加入Set<HostAndPort> nodes = new HashSet<>();nodes.add(new HostAndPort("192.168.9.101",7001));nodes.add(new HostAndPort("192.168.9.101",7002));nodes.add(new HostAndPort("192.168.9.101",7003));nodes.add(new HostAndPort("192.168.9.101",7004));nodes.add(new HostAndPort("192.168.9.101",7005));nodes.add(new HostAndPort("192.168.9.101",7006));// 创建JedisCluster对象JedisCluster jedisCluster = new JedisCluster(nodes);//操作String value = jedisCluster.get("wulala");System.out.println("value = " + value);}

六、Redis的常见问题

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

不会立即删除。

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

2.Redis淘汰机制

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

  • volatile-lru:在内存不足时,Redis会在设置了过了生存时间的key中干掉一个最近最少使用的key。
  • allkeys-lru:在内存不足时,Redis会在全部的key中干掉一个最近最少使用的key。
  • volatile-lfu:在内存不足时,Redis会在设置过了生存时间的key中干掉一个最近最少频次使用的key。
  • allkey-lfu:在内存不足时,Redis会在全部的key中干掉一个最近最少频次使用的key。
  • volatile-random:在内存不足时,Redis会在设置过生存时间的key中随机干掉一个。
  • allkeys-random:在内存不足时,Redis会在全部的ky中随机干掉一个。
  • volatile-ttl:在内存不足时,直接报错。
    指定淘汰机制的方式:maxmemory-policy 具体策略,设置Redis的最大内存:maxmemory 字节大小

3.Redis缓存问题

1.缓存雪崩:

大量Redis缓存同时到期:

  • 所有QPS全部落在数据库上,导致数据库宕机,如果没有做熔断等策略基本上会挂掉一片。
    解决方案:
  • 在往Redis里面存数据的时候,把每个key都添加上随机的过期时间,这样就可以保证在同一时间内不会有大范围的数据失效。
  • 如果是集群部署,将热点数据均匀的分布在不同的Redis库中同样也可以避免全部失效的问题。

2.缓存穿透和缓存击穿

缓存穿透:

  • 缓存穿透是指缓存和数据库中都没有数据;
  • 用户不断的发起请求,数据库中的id都是从1自增,如果用户发起特别大的id或者-1,不存在的数据。这时的用户可能是攻击者,攻击会导致数据库压力过大严重会击垮数据库;

解决方案:

  • 根据id查询时,如果id是自增的,将id的最大值放在Redis中,在查询之前,直接比较一下id;
  • 如果id不是整型,可以将全部的id放到set中,在用户查询之前,去set中查看下是否有这样一个id。
  • 获取客户端的ip地址,可以将ip访问添加限制(设置单个ip访问的阀值)。
  • 使用Redis布隆过滤器,他的原理是利用简单高效的数据结构和算法快速判断出当前key是否在数据库中存在,不存在直接return,存在去查然后刷新kv缓存;

缓存击穿:

  • 缓存击穿是一个热点数据key,不停的接收大并发的访问,大并发集中对一个热点访问,当这个热点数据失效,持续的大并发就会击穿缓存,直接访问数据库。

解决方案:

  • 设置热点数据用不过期
  • 加上互斥锁

3.缓存倾斜

缓存倾斜:

  • 热点数据放在单个redis节点上,导致Redis节点无法承受住大量的请求,最终宕机。

解决方案:

  • 扩展主从架构,搭建多个从节点,缓解Redis压力;
  • 可以在tomcat中做JVM缓存,在查询Redis之前,先去查询Tomcat中的缓存;

Redis快速入门(详细教程)相关推荐

  1. redis快速入门教程

    原文链接:redis快速入门教程 redis是什么 redis的作者何许人也 谁在使用redis 学会安装redis 学会启动redis 使用redis客户端 redis数据结构 – 简介 redis ...

  2. 视频教程-Linux+redis快速入门-其他

    Linux+redis快速入门 十年项目开发经验,主要从事java相关的开发,熟悉各种mvc开发框架. 王振伟 ¥12.00 立即订阅 扫码下载「CSDN程序员学院APP」,1000+技术好课免费看 ...

  3. spring入门详细教程(五)

    前言 本篇紧接着spring入门详细教程(三),建议阅读本篇前,先阅读第一篇,第二篇以及第三篇.链接如下: Spring入门详细教程(一) https://www.cnblogs.com/jichi/ ...

  4. Spring入门详细教程(四)

    前言 本篇紧接着spring入门详细教程(三),建议阅读本篇前,先阅读第一篇,第二篇以及第三篇.链接如下: Spring入门详细教程(一) https://www.cnblogs.com/jichi/ ...

  5. Spring入门详细教程(三)

    前言 本篇紧接着spring入门详细教程(二),建议阅读本篇前,先阅读第一篇和第二篇.链接如下: Spring入门详细教程(一) https://www.cnblogs.com/jichi/p/101 ...

  6. Spring入门详细教程(二)

    前言 本篇紧接着spring入门详细教程(一),建议阅读本篇前,先阅读第一篇.链接如下: Spring入门详细教程(一) https://www.cnblogs.com/jichi/p/1016553 ...

  7. Python 零基础 快速入门 趣味教程 (咪博士 海龟绘图 turtle) 4. 函数

    什么样的程序员才是优秀的程序员?咪博士认为"慵懒"的程序员才是真正优秀的程序员.听起来不合逻辑?真正优秀的程序员知道如何高效地工作,而不是用不止境的加班来完成工作任务.函数便是程序 ...

  8. ThinkJS框架入门详细教程(二)新手入门项目

    一.准备工作 参考前一篇:ThinkJS框架入门详细教程(一)开发环境 安装thinkJS命令 npm install -g think-cli 监测是否安装成功 thinkjs -v 二.创建项目 ...

  9. python海龟教程_Python 零基础 快速入门 趣味教程 (咪博士 海龟绘图 turtle) 7. 条件循环...

    条件循环能够让程序在条件成立时(即为真时)重复执行循环体中的语句.如果条件一直成立(即永远不会为假),则循环会一直进行下去,不会停止.如果初始时,条件不成立,则循环 1 次也不会执行.Python 中 ...

  10. NC65【新】功能快速开发详细教程(yyds神)

    Hello大家好,我是信息课的IT施sir,我是java开发工程师小施. 下面由我出具一份NC65版本最新的新功能快速开发详细教程文档. 一.准备条件: 有一个UAP STUDIO集成开发平台,PL/ ...

最新文章

  1. Linux监控实时log
  2. 转: linux 命令行设置网络
  3. maven报错解决: -source 1.5 中不支持 diamond 运算符
  4. go 怎么等待所有的协程完成_Go 编程:如何实现协程调度的精准控制
  5. SEO中HTML标签权重
  6. Fedora10 以root身份自启动
  7. JMM设计原理之双重检查Lock
  8. 关于Config.ARGB_8888、Config.ALPHA_8、Config.ARGB_4444、Config.RGB_565的理解
  9. 《101 Windows Phone 7 Apps》读书笔记-ALARM CLOCK
  10. 基于JAVA+SpringBoot+Mybatis+Vue+MYSQL的智慧养老管理系统
  11. 限时授权复制文件 1.0(2015.9.2更新)
  12. Ubuntu 18.04 下搭建 C/C++编译开发环境及GCC多版本切换
  13. 【Dynamics365】创建报表
  14. windows 7 旗舰版下,安装vs2010旗舰版终于成功!
  15. docker--privileged
  16. day---06 文件的操作
  17. loadrunner--浏览器不支持或禁止了网页脚本,导致您无法正常登录
  18. 初中计算机考试的题型,教师资格证考试中学信息技术科目题型及分值分布,快看!...
  19. mysql查看用户购买_mysql查询——购买所有产品的客户
  20. 一套有趣的期权套利题目

热门文章

  1. 吴恩达deeplearning.ai系列课程笔记+编程作业(13)序列模型(Sequence Models)-第一周 循环序列模型(Recurrent Neural Networks)
  2. vista和win7操作系统关闭用户账户控制
  3. FG96-2CH搭载NVIDIA 官方OrinNX套件移植GMSL相机
  4. 紫光展锐为Open RF Association增添RFIC专长
  5. 河北工业大学南大通用签署校企协同建设人才培养基地及战略合作协议
  6. 变频调速matlab仿真模型,SPWM变频调速系统的MATLAB仿真
  7. NUC970BSP Linux 3.10.x配置相关
  8. 【计算机网络】计算机三级计算机网络笔记记录
  9. 曾经优秀的人,怎么就突然不优秀了?
  10. Java 6 JVM参数选项大全(中文版)