13_ redis数据库高可用

可莉
• 阅读 672

数据库高可用
1.1 数据库高可用说明
当数据库的主库宕机之后.如果没有高可用机制,则可能导致整个服务全部不能正常的使用.
解决策略: 双主模式(双机热备)

1.2 数据库双机热备实现
1.2.1 双机热备的说明
将2台数据库设置为双主模式.互为主从的结构.其中任意的数据库服务器既是主机.也是从机.
13_ redis数据库高可用

1.2.1 双机热备实现
规划:
之前配置:
192.168.126.129:3306 主机.
192.168.126.130:3306 从机.
优化后的配置
192.168.126.129:3306 主机.从机
192.168.126.130:3306 从机.主机

配置:
1).检查130 主机的状态信息
13_ redis数据库高可用
2).实现主从的挂载 操作的是129
/129 我是主机 现在当从机/
/实现主从挂载/
CHANGE MASTER TO MASTER_HOST=“192.168.126.130”,
MASTER_PORT=3306,
MASTER_USER=“root”,
MASTER_PASSWORD=“root”,
MASTER_LOG_FILE=“mysql-bin.000001”,
MASTER_LOG_POS=714;

/2.开启主从服务/
START SLAVE

/3.检查主从的状态/
SHOW SLAVE STATUS;

13_ redis数据库高可用
1.2.2 双机热备的测试
测试A: 修改129中的数据,检查130中是否实现了数据的同步!!
测试B: 修改130中的数据.检查129种是否实现了数据的同步!!!

1.3 数据库高可用实现
1.3.1 Mycat配置

<mycat:schema xmlns:mycat="http://io.mycat/">
    
    <!--name属性是自定义的  dataNode表示数据库的节点信息  jtdb表示逻辑库-->
    <schema name="jtdb" checkSQLschema="false" sqlMaxLimit="100" dataNode="jtdb"/>

    <!--定义节点名称/节点主机/数据名称-->
    <dataNode name="jtdb" dataHost="localhost1" database="jtdb" />
        <!--参数介绍-->
        <!--balance 0表示所有的读操作都会发往writeHost主机 -->  
        <!--1表示所有的读操作发往readHost和闲置的主节点中-->
        <!--writeType=0 所有的写操作都发往第一个writeHost主机-->    
        <!--writeType=1 所有的写操作随机发往writeHost中-->
        <!--dbType 表示数据库类型 mysql/oracle-->
        <!--dbDriver="native"  固定参数 不变-->
        <!--switchType=-1 表示不自动切换, 主机宕机后不会自动切换从节点-->
        <!--switchType=1  表示会自动切换(默认值)如果第一个主节点宕机后,Mycat会进行3次心跳检测,如果3次都没有响应,则会自动切换到第二个主节点-->
        <!--并且会更新/conf/dnindex.properties文件的主节点信息 localhost1=0 表示第一个节点.该文件不要随意修改否则会出现大问题-->
    <dataHost name="localhost1" maxCon="1000" minCon="10" balance="1"
              writeType="0" dbType="mysql" dbDriver="native" switchType="1"  slaveThreshold="100">
        <heartbeat>select 1</heartbeat>

        <!--配置第一台主机主要进行写库操作,在默认的条件下Mycat主要操作第一台主机在第一台主机中已经实现了读写分离.因为默认写操作会发往137的数据库.读的操作默认发往141.如果从节点比较忙,则主节点分担部分压力.
        -->
        <writeHost host="hostM1" url="192.168.126.129:3306" user="root" password="root">
            <!--读数据库1-->
            <readHost host="hostS1" url="192.168.126.130:3306" user="root" password="root" />
            <!--读数据库2-->
            <readHost host="hostS2" url="192.168.126.129:3306" user="root" password="root" />
            
        </writeHost>

            <!--定义第二台主机 由于数据库内部已经实现了双机热备.-->
            <!--Mycat实现高可用.当第一个主机137宕机后.mycat会自动发出心跳检测.检测3次.-->
            <!--如果主机137没有给Mycat响应则判断主机死亡.则回启东第二台主机继续为用户提供服务.-->
            <!--如果137主机恢复之后则处于等待状态.如果141宕机则137再次持续为用户提供服务.-->
            <!--前提:实现双机热备.-->
        
        <writeHost host="hostM2" url="192.168.126.130:3306" user="root" password="root">
            <!--读数据库1-->
            <readHost host="hostS1" url="192.168.126.130:3306" user="root" password="root" />
            <!--读数据库2-->
            <readHost host="hostS2" url="192.168.126.129:3306" user="root" password="root" />
        </writeHost>
    </dataHost>
</mycat:schema>

1.3.2 上传配置文件
13_ redis数据库高可用
重启mycat.

13_ redis数据库高可用
1.3.3数据库高可用测试
测试策略:
1).启动服务器检查用户数据是否正确获取.
13_ redis数据库高可用
2).将Mysql数据库的主库宕机.检查数据是否正确获取
关闭mysql主机.

13_ redis数据库高可用
修改数据库记录:
13_ redis数据库高可用

3).将mysql数据库重启,检查mysql数据库是否实现数据的同步.
检查主库记录:

1.4 京淘项目Linux发布(终极)
1.4.1 发布架构图
13_ redis数据库高可用

1.4.2 项目打包部署
13_ redis数据库高可用

1.4.3 重启nginx服务器

13_ redis数据库高可用
1.4.4 京淘后台项目发布测试

13_ redis数据库高可用
2 Redis 缓存机制
2.1 准备工作
1).还原端口号信息
13_ redis数据库高可用
2).修改图片上传地址
13_ redis数据库高可用
3).修改HOSTS文件
13_ redis数据库高可用
4).修改nginx.conf文件
13_ redis数据库高可用
修改完成之后,重启nginx服务器.

2.2 为什么要引入缓存
说明:提供用户查询数据的速度.
13_ redis数据库高可用

2.3 缓存设计的因素
缓存的存储的数据结构应该 K-V结构. key是唯一标识符.
缓存的运行环境 应该让缓存运行在内存中.
缓存的开发语言 C语言开发
缓存中的内存优化策略 LRU算法/LFU算法
缓存数据有效性的设定 多久超时
如何防止内存数据丢失 数据落地(数据进行持久化操作)
2.4 Redis
2.4.1 Redis介绍
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。

核心: 内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件
数据类型: 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets)
处理速度: 写操作 8.6万/秒 读操作 11.2万/秒 平均10万/秒

2.5 Redis安装
2.5.1 上传安装包
13_ redis数据库高可用

2.5.2 解压安装包
命令:
1).tar -xvf redis-5.0.4.tar.gz
2).删除安装包,修改文件名称
13_ redis数据库高可用

2.5.3 安装Redis
说明:跳转到redis根目录中执行如下指令

make
make install
13_ redis数据库高可用

2.5.3 修改redis配置文件
1).编辑配置文件 vim redis.conf
13_ redis数据库高可用
2).注释IP绑定
13_ redis数据库高可用
3).关闭保护模式

13_ redis数据库高可用
4).开启后台启动
13_ redis数据库高可用

2.5.4redis常规命令
1).启动redis redis-server redis.conf
2).进入redis客户端
13_ redis数据库高可用
2).关闭redis redis-cli -p 6379 shutdown

小结
1.完成数据库高可用!!!
2.了解为什么需要使用redis
3.redis基本方法 开启 关闭等

2.6 Redis入门案例
2.6.1 引入jar包

<!--spring整合redis -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
        </dependency>

2.6.2 String类型的测试

public class TestRedis {
    
    /**
     * 如果测试有误,则检查上午修改的三处配置文件. 重启redis.
     * @throws InterruptedException 
     */
    @Test
    public void testString() throws InterruptedException {
        Jedis jedis = new Jedis("192.168.126.129",6379);
        jedis.set("aaaa","123456");
        System.out.println(jedis.get("aaaa"));
        
        //判断redis中的key是否存在
        if(!jedis.exists("abc")) {
            jedis.set("abc","123456");
        }
        
        //为数据添加超时时间
        jedis.set("h", "123");
        jedis.expire("h", 10);
        Thread.sleep(2000);
        System.out.println("剩余的存活时间:"+jedis.ttl("h")+"秒");
        
    }
    
    
    /**
     * 要求:如果key已经存在,则不允许修改!!!
     * @throws InterruptedException
     */
    @Test
    public void testStringSetNX() throws InterruptedException {
        Jedis jedis = new Jedis("192.168.126.129",6379);
        jedis.flushAll();    //清空redis
        jedis.setnx("abc", "123");    //只有当数据不存在时才会赋值.
        jedis.setnx("abc", "456");
        System.out.println(jedis.get("abc"));
    }
    
    /**
     * 虽然expire可以为数据添加超时时间,但是从宏观角度分析,该方法不具备原子性的操作
     * 使用该方法可能存在风险.
     * @throws InterruptedException
     */
    @Test
    public void testStringSetEx() throws InterruptedException {
        Jedis jedis = new Jedis("192.168.126.129",6379);
        jedis.flushAll();    //清空redis
        jedis.setex("abc", 100, "123"); //保证了数据的原子性操作
    }
    
    /**
     * 1.set操作时,如果该数据存在则不允许赋值
     * 2.set操作的同时要求添加超时时间
     * 3.上述的操作,必须同时成功或者同时失败 保证原子性操作.
     * 
     * XX = "xx";  当key存在时    才会赋值
         NX = "nx";  当key不存在时才会赋值.  
       PX = "px";  添加超时时间的单位  毫秒
         EX = "ex";  秒
     */
    @Test
    public void testStringSet() throws InterruptedException {
        Jedis jedis = new Jedis("192.168.126.129",6379);
        jedis.flushAll();    //清空redis
        SetParams params = new SetParams();
        params.nx().ex(60);
        jedis.set("abc", "123456", params);
    }
}

2.7 商品分类缓存实现原理说明
2.7.1 什么样的数据添加缓存
说明: 变化范围不大的数据,并且需要被频繁查询的数据 可以添加缓存,
常见用法: 省/市/县/乡, 商品分类信息
13_ redis数据库高可用

2.7.2 缓存实现策略
13_ redis数据库高可用
说明:
1.商品分类信息采用redis方式进行缓存存取.
2.如果需要存储到Redis中,则必须准备 key(String)-value(String)
3.由于redis通常情况下使用String的数据类型.所以需要将key-value转化为String数据类型.
4.需要将返回值结果List对象转化为JSON数据.

2.8 ObjectMapper学习
2.8.1 入门案例

public class TestObjectMapper {
    
    @Test
    public void testObject() throws JsonProcessingException {
        //1.创建工具API对象
        ObjectMapper objectMapper = new ObjectMapper();
        //2.封装转化对象
        ItemDesc itemDesc  = new ItemDesc();
        itemDesc.setItemId(1001L).setItemDesc("测试json转化")
                .setCreated(new Date()).setUpdated(itemDesc.getCreated());
        //对象------JSON-------String字符串
        //3.对象转化为JSON时,调用的是对象的get()
        String json = objectMapper.writeValueAsString(itemDesc);
        System.out.println(json);  //{key:value,key2:value2}
        
        //4.将json串转化为对象 调用的是对象的set方法为属性赋值....
        ItemDesc itemDesc2 = objectMapper.readValue(json, ItemDesc.class);
        System.out.println(itemDesc2.toString());
    }
    
    
    @Test
    public void testList() throws JsonProcessingException {
        //1.创建工具API对象
        ObjectMapper objectMapper = new ObjectMapper();
        List<ItemDesc> list = new ArrayList<ItemDesc>();
        ItemDesc itemDesc1 = new ItemDesc();
        itemDesc1.setItemId(100L);
        ItemDesc itemDesc2 = new ItemDesc();
        itemDesc2.setItemId(200L);
        list.add(itemDesc1);
        list.add(itemDesc2);
        
        //测试list集合转化为JSON
        String json = objectMapper.writeValueAsString(list);
        System.out.println(json);
        
        //测试json结构,能否转化为List集合
        List<ItemDesc> list2 = objectMapper.readValue(json, list.getClass());
        System.out.println(list2);
    }
    
}

2.8.2 JSON转化的工具API封装
说明:该工具API主要的目的为了简化对象与JSON转化的过程.编辑如下的API

//简化代码而生!!
public class ObjectMapperUtil {
    
    //定义一个常量对象
    private static final ObjectMapper MAPPER = new ObjectMapper();
    
    //1.将对象转化为json串
    public static String toJSON(Object target) {
        
        String json = null;
        try {
            json = MAPPER.writeValueAsString(target);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            //将检查异常,转化为运行时异常!!!!
            throw new RuntimeException();
        }
        return json;
    }
    
    //2.将json串按照指定的类型转化为对象
    //实现:传递什么类型,就返回什么对象
    // <T> 定义泛型
    public static <T> T  toObj(String json,Class<T> target) {
        T t = null;
        try {
            t = MAPPER.readValue(json, target);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            throw new RuntimeException();
        }
        return t;
    }
}

2.9 Spring容器管理Redis对象
2.9.2 编辑pro文件
说明:在jt-common中添加配置文件.指定redis的链接地址

redis.host=192.168.126.129
redis.port=6379
13_ redis数据库高可用

2.9.1 编辑配置类
说明:如果需要将redis对象交给Spring容器管理则必须通过配置文件/配置类的形式管理.
13_ redis数据库高可用

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;

//代表早期的配置文件
@Configuration
@PropertySource("classpath:/properties/redis.properties")
public class RedisConfig {
    
    @Value("${redis.host}")
    private String host;
    @Value("${redis.port}")
    private Integer port;
    
    //bean注解  将生成的jedis对象交给Spring容器管理
    @Bean
    public Jedis jedis() {
        
        return new Jedis(host,port);
    }
}

2.10 实现商品分类缓存
2.10.1 编辑ItemCatController

/**
     * url:http://localhost:8091/item/cat/list 
     *   参数: 当展现二三级信息时,会传递父级的Id信息,如果展现1级菜单,则应该设定默认值
     *   返回值: List<EasyUITree>
     */
    @RequestMapping("list")
    public List<EasyUITree> findItemCatList
    (@RequestParam(name="id",defaultValue="0")Long parentId){
        
        //1.查询一级商品分类信息,所以
        //return itemCatService.findItemCatList(parentId); //数据库操作
        return itemCatService.findItemCatCache(parentId);           //缓存操作
    }

2.10.2 编辑ItemCatService

/**
     * 思路:
     *     1.定义查询redis的key, key要求唯一的
     *  2.第一次查询先查询redis.
     *      没有数据: 表示缓存中没有数据, 查询数据库,之后将数据保存到redis中
     *      有数据:   证明缓存中有值, 直接返回给用户即可.
     */
    @SuppressWarnings("unchecked")
    @Override
    public List<EasyUITree> findItemCatCache(Long parentId) {
        String key = "ITEM_CAT_PARENTID_"+parentId;
        List<EasyUITree> treeList = new ArrayList<>();
        //1.判断redis中是否有记录
        if(jedis.exists(key)) {
            //表示redis中有记录.
            String json = jedis.get(key);
            treeList = 
                    ObjectMapperUtil.toObj(json, treeList.getClass());
            System.out.println("实现redis缓存查询");
        }else {
            //redis中没有记录,需要先查询数据库.
            treeList = findItemCatList(parentId);
            //将数据库记录转化为json之后保存到redis中
            String json = ObjectMapperUtil.toJSON(treeList);
            jedis.set(key, json);
            System.out.println("第一次查询数据库!!!!!");
        }
        
        return treeList;
    }
点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Stella981 Stella981
3年前
Nginx keepalive 双机热备 主主主从模式
Nginxkeepalived高可用双机热备(主从模式/双主模式)基础介绍负载均衡技术对于一个网站尤其是大型网站的web服务器集群来说是至关重要的!做好负载均衡架构,可以实现故障转移和高可用环境,避免单点故障,保证网站健康持续运行。   关于负载均衡介绍,可以参考:linux负载均衡总结性说明(四层负载/七层负载)
Stella981 Stella981
3年前
Python3:sqlalchemy对mysql数据库操作,非sql语句
Python3:sqlalchemy对mysql数据库操作,非sql语句python3authorlizmdatetime2018020110:00:00coding:utf8'''
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Stella981 Stella981
3年前
Nginx+keepalived 高可用双机热备(主从模式)
环境:centos7.6最小化安装主:10.11.1.32从:10.11.1.33VIP:10.11.1.130修改主节点主机名:hostnamectlsethostnameweb_balance_01修改从节点主机名:hostnamectlsethostnameweb_balance_02一、安
Wesley13 Wesley13
3年前
nginx+keepalived实现双机热备高可用
转载自www.fwqtg.net(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fwww.fwqtg.net)服务器托管网(https://www.oschina.net/action/GoToLink?urlhttp%3A%2F%2Fwww.fwqtg.net)安装nginx(
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这