Springboot使用Redis暨Redis集群搭建小结

前言

最近又重温了一下Redis相关知识,第一次学习的时候没有留下资料,重新学起来有点费劲,这次就留下来点资料留着以后回顾用。

目录 

0、Redis与Springboot相关配置 // 这个0是因为写完了想着再添个啥。

1、Redis分布式缓存

2、Redis主从复制

3、Redis哨兵机制

4、Redis集群

内容 

零、Redis与Springboot相关配置

1、目录结构:

2、引入依赖pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.ccb</groupId>
    <artifactId>redis_test</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>redis_test</name>
    <description>Springboot Date Redis Demo</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <!--引入依赖 spring data redis依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.19</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

3、application.properties文件配置

#redis配置
spring.redis.host=192.168.23.128
spring.redis.port=6379
spring.redis.database=0


spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/ems?characterEncoding=UTF-8&useSSL=false&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=123456

mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.type-aliases-package=com.ccb.entity

logging.level.com.ccb.dao=debug

一、Redis分布式缓存

1、概念:

本地缓存:存储在当前应用服务器内存中数据称之为本地缓存 (例如:Mybatis二级缓存)

分布式缓存:存储在当前应用服务器内存之外数据称之为分布式缓存 (distribute cache)

集群:将同一种服务的多个节点放在一起共同对系统提供服务过程称之为集群。

分布式:有多个不同服务集群共同对系统提供服务这个系统称之为分布式系统(distribute system)

2、利用Mybatis自身本地缓存结合Redis实现分布式缓存

mybatis 开始二级缓存只需在mapper.xml文件中添加<cache />标签即可,其实cache标签底层默认使用的是org.apache.ibatis.cache.impl.PerpetualCache来实现的。而这个方法实现的cache接口,我们只需自己写一个cache类来 implements Cache接口,并对里边的方法自行实现。

mapper.xml添加代码: 

<cache type="com.ccb.cache.RedisCache"/>

实现接口类具体代码:

package com.ccb.cache;

import com.ccb.util.ApplicationContextUtils;
import org.apache.ibatis.cache.Cache;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.util.DigestUtils;

//自定义Redis缓存实现
public class RedisCache implements Cache {

    // 当前放入缓存的mapper的namespace
    private final String id;

    // 获取redisTemplate
    private RedisTemplate getRedisTemplate() {
        // 通过ApplicationContextUtils获取RedisTemplate
        RedisTemplate redisTemplate = (RedisTemplate) ApplicationContextUtils.getBean("redisTemplate");
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        return redisTemplate;
    }

    //将key进行Md5加密转换成16位字符节省空间
    private String getKeyToMd5(String key) {
        return DigestUtils.md5DigestAsHex(key.getBytes());
    }

    //必须存在构造方法
    public RedisCache(String id) {
        this.id = id;
    }

    //返回cache唯一标识
    @Override
    public String getId() {
            return this.id;
    }

    // 缓存放入值
    @Override
    public void putObject(Object key, Object value) {
        // 使用redisHash作为缓存存储模型
        getRedisTemplate().opsForHash().put(id.toString(), getKeyToMd5(key.toString()), value);

    }

    //获取缓存中值
    @Override
    public Object getObject(Object key) {
        // 获取redis缓存中的值
        return getRedisTemplate().opsForHash().get(id.toString(), getKeyToMd5(key.toString()));
    }

    // 删除缓存为mybatis预留方法,在mybatis中没有实现
    @Override
    public Object removeObject(Object o) {
        return null;
    }

    // 清除缓存
    @Override
    public void clear() {
        // 在数据发生改变后清空缓存
        getRedisTemplate().delete(id.toString());
    }

    //用来计算缓存数量
    @Override
    public int getSize() {
        //获取hash中缓存的数量
        return getRedisTemplate().opsForHash().size(id.toString()).intValue();
    }
}

大功告成。

当然这种仅仅实现了单表的缓存,如果多表关联会出现缓存错误。解决办法是借助Mybatis的:

<cache-ref namespace="com.ccb.dao.UserDao"/>

在其他关联的mapper.xml中用该方法开启二级缓存。

其中击穿和雪崩的解决方案:

击穿:即数据库中不存在的数据每次都直接访问数据库,缓存没用发挥作用。mybatis缓存机制中,数据库不存在的值也放入缓存,最大程度减少重复访问直接访问数据库。

雪崩:1.将数据缓存的时间设置为永久的(不推荐)2、不同DAO设置不同的存活时间。

二、Redis主从复制

主从复制很简单,只需将主节点redis.cof文件中的bind更改为0.0.0.0开启远程访问权限。从节点的bind改为0.0.0.0后,更改slaveof 主节点IP地址 主节点端口号

由于主从复制仅仅实现了主节点的复制,当主节点宕机后就会瘫痪,所以引入了哨兵机制

三、Redis哨兵机制

首先在主节点上创建哨兵配置:

在Master对应的redis.conf同目录下新建sentinel.conf文件,注意此处名字不能出错

接着配置哨兵,在sentinel.conf文件中添加以下内容:

sentinel monitor 被监控数据库名字(自己随便起一个名字) ip port 1

说明这个后面的数字1,是指当前有几个哨兵,我们默认只有一个

这是我的配置:sentinel monitor mymaster 192.168.23.128 7001 1

最后启动哨兵:

./redis-sentinel /root/sentinel/sentinel.conf

Spring Boot操作哨兵 properites文件配置:

#redis sentinel配置
#master书写时使用哨兵监听的那个名称
spring.redis.sentinel.master=mymaster
#连接的不再是一个具体redis主机,书写的是多个哨兵节点
spring.redis.sentinel.nodes=192.168.23.128:26379

在哨兵的sentinel.conf 文件中添加 bind 0.0.0.0 

哨兵机制到此就结束了

四、Redis集群

到此为止,这篇博客的重头戏来了。 

概念:

Redis集群引入了插槽的概念,在集群创建时会根据主节点个数把【0-16383】即16384个槽均分给每个主节点。

所有的Redis节点彼此互联,内部使用二进制协议优化传输速度。

节点的fail是通过集群中超过半数的节点检测失败才生效。

redis-cluster把所有的物理节点映射到[0-16383]slot(插槽)上。

客户端传输一个数据过来会先把key经过CRC16算法来计,计算的结果必在【0-16383】之间,然后在对应插槽的节点放入数据。

环境准备

搭建Redis集群至少需要三个主节点,三个从节点,共计六个节点。

准备环境安装ruby以及redis集群依赖:

yum install -y ruby rubygems

然后考入redis-2.3.1.gem文件(下载链接https://download.csdn.net/download/qq_41181619/12619321

gem install redis-3.2.1.gem

都安装成功以后,开始进行下一项工作。

下边连接是我创建好的接口文档,不想自己麻烦的可以直接下载。

https://download.csdn.net/download/qq_41181619/12619502

由于博主用的是虚拟机,就在一台虚拟机上创建了6个节点,更改了端口号。

在 /root 下创建七个目录分别代表七个不同的节点,文件名代表着端口号,命令行如下

mkdir 7101 7102 7103 7104 7105 7106 7107

然后将原始的redis.conf文件分别考到每个目录下仅展示一个命令行:

cp redis-4.0.11/redis.conf 7101

然后分个更改redis.conf文件 其中更改的内容包括:

#修改不同目录的配置
port 7101                               //修改端口
bind 0.0.0.0                            //开启远程连接
cluster-enabled yes                     //开启集群模式
cluster-config-file nodes-port.conf     //集群节点配置文件   
cluster-node-timeout 15000              //集群节点超时时间
appendonly yes                          // 开启AOF持久化 

图片示意:

至此环境已经装配完成。

接下来就是启动各个节点,启动节点后查看节点,只要每个节点后边都有cluster说明成功。

接下来直接用redis-trib.rb文件来创建集群,由于我的redis启动脚本都在/usr/redis/bin目录下,而该目录下没有该文件,就去redis原始目录,即当初将redis安装包拷贝至虚拟机解压的目录 的src下拷贝一个至bin目录:

cp /root/redis-4.0.11/src/redis-trib.rb /usr/redis/bin

在bin目录下创建集群  其中--replicas 1 是指每个主节点只有一个从节点。 后边的是所有节点的 ip:端口号 :

./redis-trib.rb create --replicas 1 192.168.23.128:7101 192.168.23.128:7102 192.168.23.128:7103 192.168.23.128:7104 192.168.23.128:7105 192.168.23.128:7106 

然后就大功告成了,创建成功,还可以查看节点信息:

在Springboot中如何操作:

#redis cluster操作 书写集群中的所有节点
spring.redis.cluster.nodes=192.168.23.128:7101,192.168.23.128:7102,192.168.23.128:7103,192.168.23.128:7104,192.168.23.128:7105,192.168.23.128:7106

总体来说,redis集群的搭建就此结束。


版权声明:本文为qq_41181619原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。