Redis第二天课堂笔记

**课程目标**

* 能够理解Redis的主从复制架构
* 能够理解Redis的Sentinel架构
* 能够理解Redis集群架构

## Redis的主从复制架构    44

1. Redis可以配置主从复制结构,主节点就是Master节点,从节点就是Slave,Slave会不断地从Master节点同步数据
2. 一个Master节点可以对应多个Slave节点
3. Slave节点会向Master节点发送SYNC的请求,Master接收到SYNC请求之后,做两件事情:(初始化)
    1. 第一、以RDB的形式保存快照
    2. 第二、因为保存快照是比较耗时的,所以会将保存快照期间的命令缓存下来
    3. 当RDB保存完整后,就开始发送给Slave节点开始同步数据
    4. 一旦初始化完成,后续Master节点每接收一个写命令,就会立刻同步到Slave节点
4. 主从复制结构的应用场景
    1. 备份容错(如果只有一个节点,会存在单点故障问题)
    2. 读写分离(读多写少的场景很适用),如果写操作很多,就得使用集群
    3. 从数据库持久化(可以将持久化的性能消耗移动到从节点)

###     另外两台服务器安装Redis    45

注意事项:

* 如果发现虚拟机无法联网,需要检查虚拟机的NAT网络配置,NAT的网络其实类似于家里的路由器,相当于Linux服务器要和Windows宿主机进行连接,就是通过这个路由器来连接的。所以网关地址都需要配置成NAT的网络
* 如果发现yum安装软件的时候下载速度比较慢,可以在网上搜索配置一个阿里云YUM源
* make test是表示执行测试用例,消耗的时间会比较长,大家晚上安装的时候可以跳过。因为这个Redis包已经在CentOS7.7做过测试了,没有兼容性问题

安装主从复制主要有一条配置:

slaveof master_ip master_port

###     启动Redis服务    47

要检查主从复制已经配置好了:

就是当启动node2.itcast.cn、node3.itcast.cn时,如果数据都已经同步过来了,就表示OK了。但往node1.itcast.cn写入数据,数据会马上同步到另外两个节点。

## Redis中的Sentinel架构    47

###     Sentinel介绍    47

* 哨兵是主要用来保障Redis主从复制架构是高可用的,是能够自动进行主节点切换的
* 它可以监控主从复制中的节点,当主节点崩溃的时候,会自动进行切换
* 一般哨兵的配置节点数不能是1个,最好是有几个主从节点,就配置几个哨兵。不能哨兵自己出现单点故障
* 哨兵在Linux系统上是一个独立的进程,它的默认端口号是26379
* 当我们去查看操作哨兵的时候,需要指定客户端的连接端口号为:26379

###     配置哨兵    49

* 哨兵的配置文件是: sentinel.conf
* 启动哨兵是:redis-sentinel sentinel.conf

###     Redis的sentinel模式代码开发连接    52

* 因为有了哨兵之后,哨兵能够自动进行主节点的切换,所以在Java代码中,为了同步实现高可用,就不能将主节点的地址写死,需要使用哨兵来进行连接,当哨兵进行主节点切换的时候,Java代码也能自动进行切换

```java
        // JedisPoolConfig配置对象
        JedisPoolConfig config = new JedisPoolConfig();
        // 指定最大空闲连接为10个
        config.setMaxIdle(10);
        // 最小空闲连接5个
        config.setMinIdle(5);
        // 最大等待时间为3000毫秒
        config.setMaxWaitMillis(3000);
        // 最大连接数为50
        config.setMaxTotal(50);

        HashSet<String> sentinelSet = new HashSet<>();
        sentinelSet.add("node1.itcast.cn:26379");
        sentinelSet.add("node2.itcast.cn:26379");
        sentinelSet.add("node3.itcast.cn:26379");

        jedisSentinelPool = new JedisSentinelPool("mymaster", sentinelSet, config);
```

##     Redis 集群    54

### 引言    54

* QPS——Query Per Second、TPS——Tranaction Per Second
* Redis集群解决的问题
    * 高可用
    * 解决单机Redis内存是有限的问题(技术组件不是内存越多越好,因为内存配置得越高,例如JVM的Heap内存配置得很高后,就会导致内存碎片整理很耗时,垃圾回收会发生卡顿,导致集群的效率下降)
    * 解决单机Redis网络受限的问题
* 分布式存储的重点——分区
    * MySQL——根据顺序分区的方式,例如:根据主键来进行分区(分库分表),一般是在Java web开发中会遇到
    * 按照哈希取余的方式来进行分区(类似于MapReduce的默认分区策略)
        * 问题:当分区的数量发生变化的时候,会导致key产生较大影响,原先分布在第一个节点上的数据,分区数量调整后,指定到了其他的分区
    * 按照一致性Hash的方式来进行分区
        * 是一个环状的Hash空间,它的分区算法是和哈希取余算法不一样的
        * 首先将每一个分区的标号(0、1、2)进行算法计算,然后将计算出来的值,放入到环状的Hash空间空
        * 再将key同样进行算法计算,然后将计算出来的值,同样也放入到环状的Hash空间中
        * 最后,找到key在hash空间中距离自己位置最近的分区,放入到该分区中
        * 这样,当分区的数量发生变化的时候,影响不会太大
    * Redis集群是使用槽的方式来进行分区的
        * 现有有一个槽的空间(0-16383),需要将这些空间分布到不同的节点中
        * node1: 0 -3xxx
        * node2: 3xxx- 6xxx
        * ...
        * 有一个key,首先进行CRC16算法&16383 = 值,Redis会判断这个值应该在哪个槽中

### Redis Cluster 设计    55

### Redis Cluster 搭建    57

集群规划:

因为Redis集群一般推荐的是有几个主,就需要有几个从,我们搭建的是三主三从。

node1.itcast.cn:7001、7002

node2.itcast.cn:7001、7002

node3.itcast.cn:7001、7002

在配置期间,我们只能去做一些基本配置,但是配置的时候需要开启Redis集群

```properties
cluster-enabled yes

# Every cluster node has a cluster configuration file. This file is not
# intended to be edited by hand. It is created and updated by Redis nodes.
# Every Redis Cluster node requires a different cluster configuration file.
# Make sure that instances running in the same system do not have
# overlapping cluster configuration file names.
#
# cluster-config-file nodes-6379.conf
cluster-config-file nodes-7001.conf

# Cluster node timeout is the amount of milliseconds a node must be unreachable
# for it to be considered in failure state.
# Most other internal time limits are multiple of the node timeout.
#
# cluster-node-timeout 15000
cluster-node-timeout 15000
```

* 为了方便搭建集群,绑定的IP地址是0.0.0.0,监听本台电脑所有能够被访问到的IP。127.0.0.1是仅仅表示本主机,外部是不能连接进来的。

* 配置完后,需要启动所有的端口Redis进程,一共有六个
* 启动好六个节点后,需要进行集群初始化
    * 集群初始化会自动分配Master和Slave,我们可以指定一个Master可以对应几个Slave
    * Redis还会自动分配槽
* 连接Redis集群集群
    * redis-cli -c -h ip地址 -p 端口号
    * 但我们访问某个key的时候,如果这个key不再本机,Redis集群会自动跳转到另外的机器

1. 问题解决办法
    * 看Log(最好是把Log复制出来,找各种蛛丝马迹,异常:cause by:异常信息,调用栈:哪个类哪个方法出现的异常)
    * StackoverFlow(上面有各种异常解决办法)
    * 看源码(github去找到对应框架的版本,根据异常信息中的调用栈来查找问题)

2. 学习技术的三点
    * 轻量级框架、技术组件(轻量级是要华少一点时间去学习各种API,因为此时没有应用场景)
    * 重量级项目(将技术组件结合起来,切记:和业务场景结合在一起)
    * 大师级面试题(提升自己的沟通表达能力、组织话术、熟记各种原理)

### 启动Redis服务    62

* 制作一键启动脚本
    * 通过ssh在每个节点上执行启动命令、或者是shutdown命令
    * 就是正常启动每一个redis集群中的节点就可以了,因为集群已经初始化了,每个节点都已经有固定的槽位
* 当我们搭建了Redis的集群后,不在需要哨兵了,Redis集群会自动完成主从切换

### Redis Cluster 管理    68

![image-20200907120953965](image/image-20200907120953965.png)

### JavaAPI操作redis集群    69

* JedisPool——操作单机版本的Redis
* JedisSentinelPool——操作哨兵系统的主从结构
* JedisCluster——操作Redis集群的

注意事项:

* 在构建JedisCluster的时候,需要将集群中的主、从节点所有节点都添加到Set里面
* 如果使用JedisCluster操作Redis时候,不再需要获取Redis连接,直接去操作Redis即可,因为JedisCluster已经封装好了对应的操作

```java
/*
 * 创建一个HashSet<HostAndPort>,用于保存集群中所有节点的机器名和端口号
 * 创建JedisPoolConfig对象,用于配置Redis连接池配置
 * 创建JedisCluster对象
 * 使用JedisCluster对象设置一个key,然后获取key对应的值
 */
public class RedisClusterTest {
    private JedisCluster jedisCluster;

    @BeforeTest
    public void beforeTest() {
        HashSet<HostAndPort> hostAndPortSet = new HashSet<>();
        hostAndPortSet.add(new HostAndPort("node1.itcast.cn", 7001));
        hostAndPortSet.add(new HostAndPort("node1.itcast.cn", 7002));
        hostAndPortSet.add(new HostAndPort("node2.itcast.cn", 7001));
        hostAndPortSet.add(new HostAndPort("node2.itcast.cn", 7002));
        hostAndPortSet.add(new HostAndPort("node3.itcast.cn", 7001));
        hostAndPortSet.add(new HostAndPort("node3.itcast.cn", 7002));

        // JedisPoolConfig配置对象
        JedisPoolConfig config = new JedisPoolConfig();
        // 指定最大空闲连接为10个
        config.setMaxIdle(10);
        // 最小空闲连接5个
        config.setMinIdle(5);
        // 最大等待时间为3000毫秒
        config.setMaxWaitMillis(3000);
        // 最大连接数为50
        config.setMaxTotal(50);

        jedisCluster = new JedisCluster(hostAndPortSet, config);
    }

    @Test
    public void setTest() {
        jedisCluster.set("k2", "v2");
        System.out.println(jedisCluster.get("k2"));
    }

    @AfterTest
    public void afterTest() throws IOException {
        jedisCluster.close();
    }
}

```

## Redis高频面试题    71

### 缓存穿透    71

* 缓存穿透指的是一些黑色发送一些数据库和缓存都不存在的key,这样的话就是穿透了缓存、也穿透了数据库。高并发的情况下,就会压垮数据库,导致系统崩溃
* 解决方案
    * 给非法的key也设置一些缓存,这样下一次发出请求的时候,就会直接查缓存
    * 布隆过滤器(BloomFilter):布隆过滤器可以快速地过滤掉缓存中不存在的key,但是有一个问题:布隆过滤器不能准确地判断这个已经存在的key真的存在。

### 缓存击穿    72

* 击穿指的是key存在的,击穿了Redis,数据库有数据。大量的并发会把数据库拖垮
* 使用互斥锁来去解决
* 通过sexnx("互斥锁", 1)
    * sexnx表示如果key不存在的时候,才会设置一个key,如果存在就直接返回
    * 这种方式可以确保只有一个线程能够进入到加载数据库的逻辑中

### 缓存雪崩    72

* 缓存服务器中大量的key失效或者在服务器重启的时候,会出现大量并发去直接访问数据库,导致数据库的压力过大,系统崩溃

解决办法:

* 不能让所有的key集中在某一个时刻失效,可以将过期时间设置为随机
* 不然后台系统直接操作数据库,通过消息队列来隔离业务系统和数据

### 缩写

常见英文缩写:

message -> msg

1. 去重元音(a、e、i、u...)
2. 去除重复的字母

* 减少key的长度,提升Redis的效率
* 命名以:业务:模块:ID...

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值