Redis-day04 Redis学习高级部分(三 收尾 架构相关)

Redis学习高级部分(三 收尾 架构相关)

1. Redis 主从复制

1.1 主从复制

主从复制架构仅仅用来解决数据的冗余备份,从节点仅仅用来同步数据

无法解决: 1.master节点出现故障的自动故障转移

1.2 主从复制架构图

1.3 搭建主从复制(做之前拍快照)(带同学们结合官网看redis7.0.0的做法)

第一步,创建三个目录代表三台机器,master,node1,node2

拷贝源码中的redis.conf分别到master,node1,node2中

[root@master redis-install]# cp redis-7.0.0/redis.conf ./master/
[root@master redis-install]# cp redis-7.0.0/redis.conf ./node1/
[root@master redis-install]# cp redis-7.0.0/redis.conf ./node2/

# 1.准备3台机器并修改配置,修改端口号,开启远程连接,配置主节点是谁
- master
	port 6379
	protected-mode no
	
- node1
	port 6380
	protected-mode no
	replicaof <masterip> <masterport>    # replicaof 192.168.40.110 6379

- node2
	port 6381
	protected-mode no
	replicaof <masterip> <masterport>    # replicaof 192.168.40.110 6379
# 2.启动3台机器进行测试
- cd /usr/local/soft/bigdata17/redis-install
- redis-server ./master/redis.conf
- redis-server ./node1/redis.conf
- redis-server ./node2/redis.conf



2. Redis哨兵机制

2.1 哨兵Sentinel机制

Sentinel(哨兵)是Redis 的高可用性解决方案:由一个或多个Sentinel 实例 组成的Sentinel 系统可以监视任意多个主服务器,以及这些主服务器属下的所有从服务器,并在被监视的主服务器进入下线状态时,自动将下线主服务器属下的某个从服务器升级为新的主服务器。简单的说哨兵就是带有自动故障转移功能的主从架构

无法解决: 1.单节点并发压力问题 2.单节点内存和磁盘物理上限

2.2 哨兵架构原理

3. Redis集群

3.1 集群

Redis在3.0后开始支持Cluster(模式)模式,目前redis的集群支持节点的自动发现,支持slave-master选举和容错,支持在线分片(sharding shard )等特性。reshard

PING PONG协议(心跳机制)

3.2 集群架构图

3.3 集群细节(需要画图带同学理解)

- 所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.
- 节点的fail是通过集群中超过半数的节点检测失效时才生效.(半数机制,后面hadoop也会说到 ) 
- 客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
- redis-cluster把所有的物理节点映射到[0-16383]slot上,cluster 负责维护node<->slot<->value

3.4 集群搭建

判断一个是集群中的节点是否可用,是集群中的所用主节点选举过程,如果半数以上的节点认为当前节点挂掉,那么当前节点就是挂掉了,所以搭建redis集群时建议节点数最好为奇数,搭建集群至少需要三个主节点,三个从节点,至少需要6个节点

# 1.准备环境安装ruby以及redis集群依赖
- yum install -y ruby rubygems
# https://rubygems.org/gems/redis/versions
- gem install redis-xxx.gem

# 2.在一台机器创建7个目录

# 3.每个目录复制一份配置文件
[root@master redis-cluster]# cp /usr/local/soft/bigdata17/redis-install/redis-7.0.0/redis.conf ./7000/
[root@master redis-cluster]# cp /usr/local/soft/bigdata17/redis-install/redis-7.0.0/redis.conf ./7001/
[root@master redis-cluster]# cp /usr/local/soft/bigdata17/redis-install/redis-7.0.0/redis.conf ./7002/
[root@master redis-cluster]# cp /usr/local/soft/bigdata17/redis-install/redis-7.0.0/redis.conf ./7003/
[root@master redis-cluster]# cp /usr/local/soft/bigdata17/redis-install/redis-7.0.0/redis.conf ./7004/
[root@master redis-cluster]# cp /usr/local/soft/bigdata17/redis-install/redis-7.0.0/redis.conf ./7005/
[root@master redis-cluster]# cp /usr/local/soft/bigdata17/redis-install/redis-7.0.0/redis.conf ./7007/

# 4.修改不同目录配置文件
- port 	7000 .....                		 //修改端口
- # bind 127.0.0.1 -::1                //开启远程连接
- protected-mode no
- daemonize yes                         //开启守护进程
- dbfilename dump-7000.rdb              //每台机器的文件不能一样
- cluster-enabled  yes 	        			 //开启集群模式
- cluster-config-file  nodes-port.conf //集群节点配置文件
- cluster-node-timeout  5000      	   //集群节点超时时间
- appendonly  yes   		               //开启AOF持久化
- appendfilename "appendonly-7000.aof"       //修改aof文件名
- appenddirname "appendonlydir-7000"

# 5.指定不同目录配置文件启动七个节点(7003,7004的忘记修改了守护进程)
[root@master redis-cluster]# redis-server 7000/redis.conf 
[root@master redis-cluster]# redis-server 7001/redis.conf 
[root@master redis-cluster]# redis-server 7002/redis.conf 
[root@master redis-cluster]# redis-server 7003/redis.conf 
[root@master redis-cluster]# redis-server 7004/redis.conf 
[root@master redis-cluster]# redis-server 7005/redis.conf 
[root@master redis-cluster]# redis-server 7006/redis.conf 
# 6.查看进程
- [root@localhost bin]# ps aux|grep redis

1.创建集群

# 1.复制集群操作脚本到bin目录中
[root@master redis-cluster]# cp /usr/local/soft/bigdata17/redis-install/redis-7.0.0/src/redis-trib.rb /usr/local/soft/redis/bin/

# 2.创建集群
redis7.0.0之前的命令:redis-trib.rb create --replicas 1 192.168.40.110:7000 192.168.40.110:7001 192.168.40.110:7002 192.168.40.110:7003 192.168.40.110:7004 192.168.40.110:7005

redis7.0.0之后的命令:redis-cli --cluster create 192.168.40.110:7000 192.168.40.110:7001 192.168.40.110:7002 192.168.40.110:7003 192.168.40.110:7004 192.168.40.110:7005 --cluster-replicas 1

# 3.集群创建成功出现如下提示

2.查看集群状态

# 1.查看集群状态 check [原始集群中任意节点] [无]
redis-cli --cluster check 192.168.40.110:7000

# 2.集群节点状态说明
- 主节点 
	主节点存在hash slots,且主节点的hash slots 没有交叉
	主节点不能删除
	一个主节点可以有多个从节点
	主节点宕机时多个副本之间自动选举主节点

- 从节点
	从节点没有hash slots
	从节点可以删除
	从节点不负责数据的写,只负责数据的同步

使用集群(演示其中一个主节点宕机的状态,然后从节点接管)

3.添加主节点

# 1.添加主节点 add-node [新加入节点] [原始集群中任意节点]
redis-cli --cluster add-node 192.168.40.110:7006 192.168.40.110:7000 --cluster-slave 	
- 注意:
	1.该节点必须以集群模式启动
	2.默认情况下该节点就是以master节点形式添加

4.添加从节点

# 1.添加从节点 add-node --slave [新加入节点] [集群中任意节点]
- redis-trib.rb  add-node --slave 192.168.40.110:7006 192.168.40.110:7000
- 注意:
	当添加副本节点时没有指定主节点,redis会随机给副本节点较少的主节点添加当前副本节点
	
# 2.为确定的master节点添加主节点 add-node --slave --master-id master节点id [新加入节点] [集群任意节点]
- redis-trib.rb  add-node --slave --master-id 3c3a0c74aae0b56170ccb03a76b60cfe7dc1912e 127.0.0.1:7006  127.0.0.1:7000

5.删除副本节点

# 1.删除节点 del-node [集群中任意节点] [删除节点id]
- redis-trib.rb  del-node 192.168.40.110:7002 0ca3f102ecf0c888fc7a7ce43a13e9be9f6d3dd1
- 注意:
 1.被删除的节点必须是从节点或没有被分配hash slots的节点

6.集群在线分片

# 1.在线分片 reshard [集群中任意节点] [无]
- redis-trib.rb  reshard  192.168.40.110:7000

3.5 java和springboot分别操作集群

1. java操作

引入依赖

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>redis-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <dependencies>
        <!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>4.2.3</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>


    </dependencies>

</project>

代码编写

        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(20);

        Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>();
        jedisClusterNode.add(new HostAndPort("192.168.40.110", 7000));
        jedisClusterNode.add(new HostAndPort("192.168.40.110", 7001));
        jedisClusterNode.add(new HostAndPort("192.168.40.110", 7002));
        jedisClusterNode.add(new HostAndPort("192.168.40.110", 7003));
        jedisClusterNode.add(new HostAndPort("192.168.40.110", 7004));
        jedisClusterNode.add(new HostAndPort("192.168.40.110", 7005));
        jedisClusterNode.add(new HostAndPort("192.168.40.110", 7006));

        JedisCluster jedisCluster = null;
        try {
            //connectionTimeout:指的是连接一个url的连接等待时间
            //soTimeout:指的是连接上一个url,获取response的返回等待时间
            jedisCluster = new JedisCluster(jedisClusterNode, config);

            Set<String> keys = jedisCluster.keys("*");
            System.out.println(keys);
            System.out.println(jedisCluster.set("age", "18"));
            System.out.println(jedisCluster.get("age"));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (jedisCluster != null)
                jedisCluster.close();
        }

2. Springboot操作

引入依赖

<?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.6.7</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.shujia</groupId>
	<artifactId>pringboot-redis-demo1</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>pringboot-redis-demo1</name>
	<description>Demo project for Spring Boot</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.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

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

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

</project>

修改配置文件

server:
  port: 8989

spring:
  redis:
#    host: 192.168.40.110
#    port: 7000
#    database: 0
    cluster:
      nodes:  192.168.40.110:7000,192.168.40.110:7001,192.168.40.110:7002,192.168.40.110:7003,192.168.40.110:7004,192.168.40.110:7005,192.168.40.110:7006

编写代码

Set<String> keys = stringRedisTemplate.keys("*");
System.out.println(keys);

4、Springboot整合mysql,Redis案例

1、新建项目

或者从官网创建

2、引入依赖

<?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.6.7</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.shujia</groupId>
	<artifactId>springboot-anlidemo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>springboot-anlidemo</name>
	<description>Demo project for Spring Boot</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-configuration-processor</artifactId>
			<optional>true</optional>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<!--让内嵌tomcat具有解析jsp功能-->
		<dependency>
			<groupId>org.apache.tomcat.embed</groupId>
			<artifactId>tomcat-embed-jasper</artifactId>
		</dependency>

		<!--c标签库-->
		<dependency>
			<groupId>jstl</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>

		<!--添加MySql依赖-->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
		</dependency>

		<!--添加JDBC依赖-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-jdbc</artifactId>
		</dependency>

		<!--使用thymelaf-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis</artifactId>
		</dependency>

		<!--单元测试-->
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
		</dependency>

		<!--mybatis相关-->
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>2.2.1</version>
		</dependency>

		<!--        获取页面session对象request对象response对象 HttpServletXXX jar包-->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>3.0.1</version>
		</dependency>

		<!--        获取页面session对象request对象response对象 HttpServletXXX jar包-->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>3.0.1</version>
		</dependency>
	</dependencies>

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

</project>

3、修改配置文件

# =========================修改服务器相关============================
server:
  port: 8083
  servlet:
    context-path: /bigdata17
  tomcat:
    uri-encoding: UTF-8

# =====================新增数据库配置=============================
spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://192.168.40.110:3306/bigdata17?useUnicode=true&characterEncoding=utf8&useSSL=false
    username: root
    password: 123456
  thymeleaf:
    cache: false  # 关闭缓存
    prefix: classpath:/templates/ #指定模板位置
    suffix: .html #指定后缀
  redis:
#    host: 192.168.40.110
#    port: 7000
#    database: 0
    cluster:
      nodes: 192.168.40.110:7000,192.168.40.110:7001,192.168.40.110:7002,192.168.40.110:7003,192.168.40.110:7004,192.168.40.110:7005,192.168.40.110:7006

# ====================新增mybits配置=========================
mybatis:
  configuration:
    map-underscore-to-camel-case: true #下划线驼峰设置
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl   # 打印SQL语句

# ==================设置日志级别==============================
logging:
  level:
    root: info #指定根日志级别(一般不推荐修改根日志,输出信息太多,推荐使用子日志)

4、创建分层

5、运行测试没有问题后,一切准备就绪

6、第一个案例,用户登录案例(springboot结合mysql)

1. 创建数据库表,用户表(注意,主键设置成自增,方便后续查找或者删除)

2. 创建实体类,对应数据库表结构(规范是成员变量与表字段一样,大小写可以不一样)

package com.shujia.entity;

public class User {
    private Integer id;
    private String username;
    private String password;


    public User(Integer id, String username, String password) {
        this.id=id;
        this.username=username;
        this.password=password;
    }
    public User() {

    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }


    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

3. 编写对用户的方法接口(在service层中)

package com.shujia.service;

import com.shujia.entity.User;

import java.util.List;

public interface UserService {
    //根据账户名和密码查找
    User findByNameAndPwd(String name,String password);
}

4. 编写对接口的实现类(在service层中的impl包中),同时编写dao层的数据库操作类

package com.shujia.dao;

import com.shujia.entity.User;
import org.apache.ibatis.annotations.*;

import java.util.List;

@Mapper
public interface UserDao {

    //根据账户名和密码查找
    @Select("select * from user where username=#{username} and password=#{password}")
    public User findByNameAndPwd(String username,String password);

}
package com.shujia.service.impl;

import com.shujia.dao.UserDao;
import com.shujia.entity.User;
import com.shujia.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;

    @Override
    public User findByNameAndPwd(String name,String password) {
        return userDao.findByNameAndPwd(name,password);
    }
}

5. 编写控制类

package com.shujia.controller;

import com.shujia.entity.User;
import com.shujia.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

@Controller
public class UserController {
    @Autowired
    private UserService userService;

    //新增登录页面
    @GetMapping("/index.html")
    public String userLogin(){
        return "login";
    }

    //查询用户
    @PostMapping("/login")
    public String login(User user,Model model) {
//        userService.save(user);
        User byName = userService.findByNameAndPwd(user.getUsername(),user.getPassword());
        if(byName!=null){
            //表示重置index.html界面并且跳转到index.html界面
            return "index";
        }else {
            return "login";
        }

    }
}

6. 编写登录页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>用户列表</title>
    <!-- 引入 Bootstrap -->
    <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>

<style>
    a{
        color: #ffffff;
    }
    h2{
        /*文字对齐*/
        text-align: center;
    }
</style>

<body>
<h2>17期springboot案例-登录</h2>

<div style="width:600px;height:100%;margin-left:270px;">
    <form th:action="@{/login}" method="post">
        <!--        form-control给input添加这个class后就会使用bootstrap自带的input框-->
        用户名:<input class="form-control" type="text" th:value="${username}" name="username"><br>
        <!--注意参数的拼接-->
        密 码:<input class="form-control" type="password" th:value="${password}" name="password"><br>
        <button class="btn btn-primary btn-lg btn-block">保存</button>
    </form>
</div>

</body>

</html>

首页

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8">
  <title>用户列表</title>
  <!-- 引入 Bootstrap -->
  <link href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
</head>

<style>
    a{
        color: #ffffff;
    }
    h1{
        /*文字对齐*/
        text-align: center;
    }
</style>

<body>
<!--一开始写一个登录成功-->
<h2>登录成功</h2>

</body>

</html>




posted @ 2022-05-18 21:57  a-tao必须奥利给  阅读(66)  评论(0)    收藏  举报