分布式电商项目(七)--Redis缓存(下)

Redis持久化策略

什么是持久化

说明:Redis运行环境在内存中,如果redis服务器关闭,则内存数据将会丢失.
需求: 如何保存内存数据呢?
解决方案: 可以定期将内存数据持久化到磁盘中.
持久化策略规则:
当redis正常运行时,定期的将数据保存到磁盘中,当redis服务器重启时,则根据配置文件中指定的持久化的方式,实现数据的恢复.(读取数据,之后恢复数据.)

RDB模式

RDB模式特点说明

1).RDB模式是Redis默认的策略.
2).RDB模式能够定期(时间间隔)持久化. 弊端:可能导致数据的丢失.
3).RDB模式记录的是内存数据的快照.持久化效率较高. 快照只保留最新的记录.

RDB模式命令

1.save命令: 将内存数据持久化到磁盘中 主动的操作 会造成线程阻塞
2.bgsave命令: 将内存数据采用后台运行的方式,持久化到文件中. 不会造成阻塞.
3.默认的持久化的机制
save 900 1 如果在900秒内,执行了1次更新操作,则持久化一次
save 300 10 如果在300秒内,执行了10次更新操作,则持久化一次
save 60 10000 如果在60秒内,执行了10000次更新操作,则持久化一次

持久化文件配置

1).指定持久化文件
在这里插入图片描述

AOF模式

AOF模式特点

1).AOF模式默认条件下是关闭的.需要手动开启
2).AOF模式记录的是用户的操作过程,所以可以实现实时持久化操作.
3).AOF模式由于记录的是实时的操作过程,所以持久化文件较大.需要定期维护.

启动AOF模式

说明:如果一旦开启AOF模式,则以AOF模式为准.
在这里插入图片描述

关于持久化操作总结

1.当内存数据允许少量丢失时,采用RDB模式 (快)
2.当内存数据不允许丢失时,采用AOF模式(定期维护持久化文件)
3.一般在工作中采用 RDB+AOF模式共同作用,保证数据的有效性.

面试题


问题: 如果小李(漂亮妹子)在公司服务器中执行了flushAll命令,问怎么办?
答: 需要找到aof文件之后,删除flushAll命令 之后重启redis,执行save命令即可.

内存优化策略

为什么需要内存优化

说明: 由于redis在内存中保存数据.如果一直存储,则内存数据必然溢出.所以需要定期维护内存数据的大小.
维护策略: 删除旧的不用的数据,保留新的常用的数据

LRU算法

(设置上次至今的范围间隔时间t,挑选t最大的删除)

LRU是Least Recently Used的缩写,即最近最少使用,是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰。该算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 t,当须淘汰一个页面时,选择现有页面中其 t 值最大的,即最近最少使用的页面予以淘汰。
计算维度: 时间T
注意事项: LRU算法是迄今为止内存中最好用的数据置换算法.

LFU算法

(设置使用次数num,为了将一些很久不适用但之前使用次数很多的数据挑选,所以,num数当很久不被引用时按照指数衰减即,定时右移一位。最后挑选num数最小的删除)

LFU(least frequently used (LFU) page-replacement algorithm)。即最不经常使用页置换算法,要求在页置换时置换引用计数最小的页,因为经常使用的页应该有一个较大的引用次数。但是有些页在开始时使用次数很多,但以后就不再使用,这类页将会长时间留在内存中,因此可以将引用计数寄存器定时右移一位,形成指数衰减的平均使用次数。
维度: 使用次数

随机算法(随机挑选删除)

随机算法.

TTL算法

(根据存活时间挑选存活时间最小的,提前删除)

根据剩余的存活时间,将马上要超时的数据提前删除.

配置内存优化策略

(redis.conf文件的570行~600行设置)

1.volatile-lru 在设定了超时时间的数据中,采用lru算法
2.allkeys-lru 在所有的数据中,采用lru算法
3.volatile-lfu 在设定了超时时间的数据中,采用lfu算法
4.allkeys-lfu 所有数据采用lfu算法
5.volatile-random 设置超时时间数据的随机算法
6.allkeys-random 所有数据的随机
7.volatile-ttl 将设定了超时时间的数据,提前删除.
8.noeviction 默认规则 如果设定noeviction 则不删除数据,直接报错返回.

手动修改redis内存优化策略:
在这里插入图片描述

关于缓存面试问题

问题出发点:
由于缓存失效,导致大量的用户的请求,直接访问数据库服务器.导致负载过高,从而引发整体宕机的风险!!!

缓存穿透

(访问数据库中没有的数据,所以每次redis中都无法命中,直接访问数据库,可能威胁到数据库)

说明: 用户频繁访问数据库中不存在的数据,可能出现缓存穿透的现象.如果该操作是高并发操作,则可能直接威胁数据库服务器.
解决方案:
1.采用IP限流的方式 降低用户访问服务器次数. IP动态代理(1分钟变一次)
2.微服务的处理方式: 利用断路器返回执行的业务数据即可不执行数据库操作 从而保护了数据库.
3.微服务处理方式: API网关设计. 不允许做非法操作

缓存击穿

(高并发的查询同一数据时,redis中没有该数据,但数据库中有,全部都访问了数据库时,可能威胁到数据库)

说明: 由于redis中某个热点数据由于超时/删除等操作造成数据失效.同时用户高并发访问该数据,则可能导致数据库宕机.该操作称之为 缓存击穿.
解决方案: 可以采用多级缓存的设计. 同时数据的超时时间采用随机数的方式.
在这里插入图片描述

缓存雪崩

(redis中大量数据同时失效或丢失,此时压力一下都到了数据库这边,直接威胁到数据库)

说明: 由于redis内存数据大量失效.导致用户的访问命中率太低.大量的用户直接访问数据库,可能导致数据库服务器宕机. 这种现象称之为缓存雪崩.
解决:
1.采用多级缓存.
2.设定不同的超时时间
3.禁止执行 flushAll等敏感操作.

Redis分片机制

(reids进行扩容,如果一台出现问题,数据分散存储,访问到有问题的就会报错)

Redis分片说明

说明: 如果需要Redis存储海量的内存数据,使用单台redis不能满足用户的需求,所以可以采用Redis分片机制实现数据存储.
注意事项:
如果有多台redis,则其中的数据都是不一样的…
在这里插入图片描述

Redis部署

搭建端口:6379/6380/6381

准备配置文件:

6379.conf 6380.conf 6381.conf
在这里插入图片描述

修改端口号

只修改80/81的端口即可
在这里插入图片描述

Redis分片测试

@Test
    public void testShards(){
        List shards = new ArrayList<>();
        shards.add(new JedisShardInfo("192.168.126.129", 6379));
        shards.add(new JedisShardInfo("192.168.126.129", 6380));
        shards.add(new JedisShardInfo("192.168.126.129", 6381));
        ShardedJedis shardedJedis = new ShardedJedis(shards);
        shardedJedis.set("shards", "redis分片操作!!!");
        System.out.println(shardedJedis.get("shards"));
    }

一致性HASH算法

(数据计算hash后,在hash环中查看交给哪一个node管理,一致性hash只计算管理归属问题,三大特性:平衡性:虚节点;单调性:增删节点时只对单一节点有影响;分散性:数据分散在各个节点)

概念

一致性哈希算法在1997年由麻省理工学院提出,是一种特殊的哈希算法,目的是解决分布式缓存的问题
[1] 在移除或者添加一个服务器时,能够尽可能小地改变已存在的服务请求与处理请求服务器之间的映射关系。一致性哈希解决了简单哈希算法在分布式哈希表( Distributed Hash Table,DHT) 中存在的动态伸缩等问题 [2] 。

原理说明

知识复习:

  1. 常规hash由多少位16进制数组成??? 8位16进制数组成 2^32次方
  2. 如果对相同的数据进行hash计算问结果是否相同??? 结果必然相同.

在这里插入图片描述

特性一平衡性

①平衡性是指hash的结果应该平均分配到各个节点,这样从算法上解决了负载均衡问题.
实现平衡性的方案: 引入虚拟节点
在这里插入图片描述

特性二单调性

②单调性是指在新增或者删减节点时,不影响系统正常运行 [4] 。
特点:在进行数据迁移时,要求尽可能小的改变数据.
在这里插入图片描述

特性三分散性

③分散性是指数据应该分散地存放在分布式集群中的各个节点(节点自己可以有备份),不必每个节点都存储所有的数据 [4] 。
俗语: 鸡蛋不要到放到一个篮子里

SpringBoot整合Redis分片

编辑properties配置文件

# 配置单台redis服务器
#redis.host=192.168.126.129
#redis.port=6379

##配置redis分片
redis.nodes=192.168.126.129:6379,192.168.126.129:6380,192.168.126.129:6381

编辑配置类

package com.jt.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisShardInfo;
import redis.clients.jedis.ShardedJedis;

import java.util.ArrayList;
import java.util.List;

@Configuration  //标识我是配置类
@PropertySource("classpath:/properties/redis.properties")
public class RedisConfig {

    /**
     * SpringBoot整合Redis分片,实质:ShardedJedis对象,交给容器管理
     */
    @Value("${redis.nodes}")
    private String nodes;       //node,node,node

    @Bean
    public ShardedJedis shardedJedis(){
        List shards = new ArrayList<>();
        String[] nodeArray = nodes.split(",");
        for (String node : nodeArray){ //node=ip:port
            String host = node.split(":")[0];
            int port = Integer.parseInt(node.split(":")[1]);
            //准备分片节点信息
            JedisShardInfo info  = new JedisShardInfo(host, port);
            shards.add(info);
        }
        return new ShardedJedis(shards);
    }

   /* @Value("${redis.host}")
    private String  host;
    @Value("${redis.port}")
    private Integer port;

    @Bean
    public Jedis jedis(){

        return new Jedis(host, port);
    }*/
}

修改AOP缓存注入

无需修改其他代码,只需要修改接收依赖注入对象类型即可)

说明:将AOP中的注入对象切换为分片对象
在这里插入图片描述

Redis哨兵机制

(redis的高可用,当主机挂掉,通过哨兵选举,将一个从机百年未主机并重新搭建主从关系)

分片机制存在的问题

说明: redis分片主要的作用是实现内存数据的扩容.但是如果redis分片中有一个节点宕机,则直接影响所有节点的运行. 能否优化?
实现策略: 采用Redis哨兵机制实现Redis节点高可用.

Redis节点主从配置

准备主从节点

1).关闭redis分片的节点,之后复制配置文件准备哨兵的配置.
在这里插入图片描述

实现redis主从

命令: info replication 检查redis节点的状态信息
在这里插入图片描述
节点划分: 6379 当主机 6380/81 当从机

命令2: 实现主从挂载 slaveof host port
在这里插入图片描述
结论: redis所有节点都可以相同通信.并且路径当前的主从的状态.

数据主从同步的状态
在这里插入图片描述

哨兵机制工作原理

心跳检测ping-pong三次决定主机是否存活,选举制度通过配置文件设定)

1).当哨兵启动时,会链接redis主节点,同时获取所有节点的状态信息
2).当哨兵连续3次通过心跳检测机制(PING-PONG),如果发现主机宕机,则开始选举.
3).哨兵内部通过随机算法筛选一台从机当选新的主机.其他的节点应该当新主机的从.

在这里插入图片描述

哨兵机制配置

在这里插入图片描述

关闭保护模式

在这里插入图片描述

开启后台运行

在这里插入图片描述

配置投票机制

根据哨兵数量决定投票生效数 一般哨兵为奇数个(三局两胜,五局三胜...);我们测试只有一台哨兵,所以一票定主机)

在这里插入图片描述

修改投票时间

(哨兵选定从机后,给定上任时间,否则重新选举,防止死锁发生,即选好后,被选中的从机宕机了)

主机宕机3秒之后开始选举
在这里插入图片描述

哨兵高可用测试(哨兵端口:26379)

1.启动哨兵 redis-sentinel sentinel.conf
在这里插入图片描述

4).启动之前的主机,检查是否当选新主机的从
在这里插入图片描述

哨兵入门案例

/**
* 测试Redis哨兵
*/
@Test
public void testSentinel(){
    Set set = new HashSet<>();
    //1.传递哨兵的配置信息
    set.add("192.168.126.129:26379");
    JedisSentinelPool sentinelPool =
    new JedisSentinelPool("mymaster",set);
    Jedis jedis = sentinelPool.getResource();
    jedis.set("aa","哨兵测试");
    System.out.println(jedis.get("aa"));
}

Redis集群说明

分片/哨兵有哪些缺点

1.分片缺点: 分片的主要的功能是实现内存的扩容的. 但是没有高可用的效果. 如果宕机将直接影响用户的使用.
2.哨兵缺点: 数据没有扩容,哨兵本身没有高可用机制
需求: 既可以实现内存数据的扩容,同时实现高可用机制(不用第三方). 应该使用Redis集群.

Redis集群搭建

1.为什么要搭建集群

通常,为了提高网站响应速度,总是把热点数据保存在内存中而不是直接从后端数据库中读取。

Redis是一个很好的Cache工具。大型网站应用,热点数据量往往巨大,几十G上百G是很正常的事儿。
由于内存大小的限制,使用一台 Redis 实例显然无法满足需求,这时就需要使用多台 Redis作为缓存数据库。但是如何保证数据存储的一致性呢,这时就需要搭建redis集群.采用合理的机制,保证用户的正常的访问需求.
采用redis集群,可以保证数据分散存储,同时保证数据存储的一致性.并且在内部实现高可用的机制.实现了服务故障的自动迁移.

2.集群搭建计划

主从划分:
3台主机 3台从机共6台 端口划分7000-7005

集群搭建步骤

3.准备集群文件夹

Mkdir cluste
在cluster文件夹中分别创建7000-7005文件夹
Image.png

4.复制配置文件

说明:
将redis根目录中的redis.conf文件复制到cluster/7000/ 并以原名保存

cp redis.conf cluster/7000/

5.编辑配置文件

1.注释本地绑定IP地址
![Image \[2\].png](/img/bVcKVkq)
2.关闭保护模式
![Image \[12\].png](/img/bVcKVlg)
3.修改端口号
![Image \[3\].png](/img/bVcKVku)
4.启动后台启动
![Image \[4\].png](/img/bVcKVkv)
5.修改pid文件
![Image \[5\].png](/img/bVcKVkw)
6.修改持久化文件路径
![Image \[6\].png](/img/bVcKVkx)
7.设定内存优化策略
![Image \[7\].png](/img/bVcKVky)
8.关闭AOF模式
![Image \[8\].png](/img/bVcKVkA)
9.开启集群配置
![Image \[9\].png](/img/bVcKVkE)
10.开启集群配置文件
![Image \[10\].png](/img/bVcKVkG)
11.修改集群超时时间
![Image \[11\].png](/img/bVcKVkH)

6.复制修改后的配置文件
说明:将7000文件夹下的redis.conf文件分别复制到7001-7005中

[root@localhost cluster]# cp 7000/redis.conf  7001/
[root@localhost cluster]# cp 7000/redis.conf  7002/
[root@localhost cluster]# cp 7000/redis.conf  7003/
[root@localhost cluster]# cp 7000/redis.conf  7004/
[root@localhost cluster]# cp 7000/redis.conf  7005/

7.批量修改
说明:分别将7001-7005文件中的7000改为对应的端口号的名称,
修改时注意方向键的使用
Image.png
8.通过脚本编辑启动/关闭指令

1.创建启动脚本 vim start.sh
Image.png
2.编辑关闭的脚本 vim shutdown.sh
![Image \[2\].png](/img/bVcKVlt)
3.启动redis节点
sh start.sh
4.检查redis节点启动是否正常
![Image \[3\].png](/img/bVcKVlu)

9.创建redis集群
1表示一主一从,此处六台redis,表示三组,三主三从 ; 如果是2表示一主两从

#5.0版本执行 使用C语言内部管理集群
redis-cli --cluster create --cluster-replicas 1 192.168.126.129:7000 192.168.126.129:7001 192.168.126.129:7002 192.168.126.129:7003 192.168.126.129:7004 192.168.126.129:7005

Image.png
![Image \[2\].png](/img/bVcKVlG)

10.Redis集群高可用测试

1.关闭redis主机.检查是否自动实现故障迁移.
2.再次启动关闭的主机.检查是否能够实现自动的挂载.

一般情况下 能够实现主从挂载
个别情况: 宕机后的节点重启,可能挂载到其他主节点中(7001-7002) 正确的
![Image \[3\].png](/img/bVcKVlH)

Redis集群原理

11.Redis集群高可用推选原理
如图所示
Image.png
原理说明:
Redis的所有节点都会保存当前redis集群中的全部主从状态信息.并且每个节点都能够相互通信.当一个节点发生宕机现象.则集群中的其他节点通过PING-PONG检测机制检查Redis节点是否宕机.当有半数以上的节点认为宕机.则认为主节点宕机.同时由Redis剩余的主节点进入选举机制.投票选举链接宕机的主节点的从机.实现故障迁移.
12.Redis集群宕机条件
特点:集群中如果主机宕机,那么从机可以继续提供服务,
当主机中没有从机时,则向其它主机借用多余的从机.继续提供服务.如果主机宕机时没有从机可用,则集群崩溃.
答案:9个redis节点,节点宕机5-7次时集群才崩溃.
如图所示:
![Image \[2\].png](/img/bVcKVlN)
13.Redis hash槽存储数据原理
说明: RedisCluster采用此分区,所有的键根据哈希函数(CRC16[key]%16384)映射到0-16383槽内,共16384个槽位,每个节点维护部分槽及槽所映射的键值数据.根据主节点的个数,均衡划分区间.
算法:哈希函数: Hash()=CRC16[key]%16384
如图所示
![Image \[3\].png](/img/bVbnUhA)
当向redis集群中插入数据时,首先将key进行计算.之后将计算结果匹配到具体的某一个槽的区间内,之后再将数据set到管理该槽的节点中.
如图所示
![Image \[4\].png](/img/bVcKVlO)

Redis集群搭建问题说明

1.首先关闭所有的Redis服务器
在这里插入图片描述
5.搭建redis集群

redis-cli --cluster create --cluster-replicas 1 192.168.126.129:7000 192.168.126.129:7001 192.168.126.129:7002 192.168.126.129:7003 192.168.126.129:7004 192.168.126.129:7005

集群入门案例

@Test
public void testCluster(){
    Set sets = new HashSet<>();
    sets.add(new HostAndPort("192.168.126.129", 7000));
    sets.add(new HostAndPort("192.168.126.129", 7001));
    sets.add(new HostAndPort("192.168.126.129", 7002));
    sets.add(new HostAndPort("192.168.126.129", 7003));
    sets.add(new HostAndPort("192.168.126.129", 7004));
    sets.add(new HostAndPort("192.168.126.129", 7005));
    JedisCluster jedisCluster = new JedisCluster(sets);
    jedisCluster.set("jedis", "集群赋值");
    System.out.println(jedisCluster.get("jedis"));
}

关于选举机制-脑裂现象

说明: 当集群进行选举时,如果连续3次都出现了平票的结果的则可能出现脑裂的现象.
问题: 出现脑裂现象的概率是多少??? 1/8

数学建模:
抛银币连续3次出现平票的概念是多少? 1/8=12.5%
第一次: 正正 正反 反正 反反 1/2
第二次: 正正 正反 反正 反反 1/2
第三次: 正正 正反 反正 反反 1/2
预防: 增加主节点的数量可以有效的降低脑裂现象的发生.

面试题

1.redis集群中一共可以存储16384个KEY? 不对的
答: 16384只是槽位的数量 只负责规划这个数据归谁管理的问题.至于数据如何存储,是由redis内存决定的.
hash(key1) = 3000,
hash(key2) = 3000;

2.Redis集群中最多可以有多少台主机? 16384台主机.

3.Redis中如果遇到多线程操作,是否有线程安全性问题 ? 没有
因为:redis服务器是单进程单线程操作. 每次操作都是由一个线程执行,所以不会有线程安全性问题.

4.Redis如何实现内存数据的优化? LRU/LFU/随机算法/TTL

SpringBoot整合Redis集群

编辑properties文件

说明:将redis集群的节点写入pro配置文件中

# 配置单台redis服务器
#redis.host=192.168.126.129
#redis.port=6379

##配置redis分片
#redis.nodes=192.168.126.129:6379,192.168.126.129:6380,192.168.126.129:6381

# redis集群配置
redis.nodes=192.168.126.129:7000,192.168.126.129:7001,192.168.126.129:7002,192.168.126.129:7003,192.168.126.129:7004,192.168.126.129:7005

编辑配置类

@Configuration //标识我是配置类
@PropertySource("classpath:/properties/redis.properties")
public class RedisConfig {

    /*redis集群*/
    @Value("${redis.nodes}")
    private String nodes; //node,node,node

    @Bean
    public JedisCluster jedisCluster(){
        Set cluster=new HashSet<>();
        String[] nodeArray = nodes.split(",");
        for (String node :nodeArray){//host port
            String host=node.split(":")[0];
            int port=Integer.parseInt(node.split(":")[1]);
            cluster.add(new HostAndPort(host,port));
        }
        return new JedisCluster(cluster);
    }
}

编辑AOP配置

在AOP中注入Redis缓存对象

@Aspect //标识我是一个切面
@Component //交给spring容器管理
public class CacheAOP {

    @Autowired
    private JedisCluster jedis; //完成集群对象的注入
    //private JedisSentinelPool jedisSentinelPool;//单台哨兵
    //private ShardedJedis jedis;//切换成分片redis
    //private Jedis jedis;

关于京淘项目后台说明

知识点概括:

1.框架加强阶段
1.1SpringBoot 各个配置文件的说明 pom.xml配置 常用注解 springboot启动执行的流程
1.2 关于SpringBoot常见用法 属性赋值 @Value , 开发环境优化 ,配置文件引入 ,整合Mybatis , 整合MybatisPlus ,整合web资源(JSP)
1.3京淘后台项目搭建
1.3.1分布式思想 按照模块/ 按照层级拆分
1.3.2 聚合工程创建的思路 父级项目 统一管理jar包 ,工具API项目, 业务功能系统
1.4 UI工具 前端与后端进行数据交互时 如果想要展现特定的格式结构,则必须按照要求返回VO对象.
1.5 JSON结构形式 1.Object类型 2.Array类型 3. 复杂类型(可以进行无限层级的嵌套)
1.6 后台商品/商品分类的CURD操作.
1.7 引入富文本编辑器 /实现文件上传业务.
1.8 反向代理/正向代理
1.9 NGINX 实现图片回显, NGINX安装/命令/进程项说明/域名的代理/负载均衡机制/相关属性说明
1.10 windows tomcat服务器集群部署.

2.Linux学习
2.1 什么是VM虚拟机. 网络配置说明 桥接/NAT模式
2.2 介绍Linux发展, 介绍Linux基本命令 安装Linux JDK tomcatLinux部署. Linux安装Mysql数据
2.3 Linux安装Nginx服务器. 整个项目Linux部署.

3.项目真实部署
3.1 实现数据的读写分离/负载均衡/数据库高可用 mycat
3.2 Redis 命令/redis单台操作/redis分片/redis哨兵/redis集群/
3.3 AOP相关知识.
2020-11-16_192425.png

你可能感兴趣的:(redis)