暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Redis 连载(四) : 主从复制,读写分离,java-Jedis

小败笔的颠沛流离 2019-02-21
1006
上期回顾

上期我们讲了对于Redis来说最重要的部分,配置文件,持久化与Redis事务的使用.有兴趣的同学可以看一下.

Redis 连载(三) : 配置文件,持久化,事务

本期内容

本期为Redis连载的最后收尾篇。主要讲一下在Redis中如果建议Redis集群,以及主从关系.另外就是如何在Java程式中调用Redis.

简介:

    主机数据更新后根据配置和策略,自动同步到备机的master/slaver机制.Master以写为主,Slave以读为主.

作用 :

    - 读写分享

    - 容灾恢复

使用技巧:

    

- 配从(库)不配主(库)

- 从库配置:slaveof主库IP主库端口(每次与master断开之后,都需要重新连接,除非你配置进redis.conf文件)

- 修改配置文件细节操作

- 常用3招

  - 一主二仆

  - 薪火相传

  - 反客为主

创建集群:

1:通过复制多个redis.conf文件,修改成不同的端口.通过

redis-server /pathxxx/redis.conf 来启动.

# redis.conf位置,/etc/redis/redis.conf
redis-server /pathxxx/redis.conf

打开redis.conf文件

# 打开复制的redis.conf
sudo vim /pathxxx/redis

2:修改各自的port

# 通过/port找到修改port的地方,把端口修改成一个其他任意端口,只要不冲突就可以.
port 6380

3:修改pid文件名

# 通过 /.pid 找到修改 pip 的地方.
pidfile /var/run/redis/redis-server-80.pid

4:修改log文件名

# 通过 /logfile 找到修改log名的地方,进行文件名修改.
logfile /var/log/redis/redis-server-80.log

5:修改rdb文件名

# 通过/dbfilename 找到修改 pip 的地方.
dbfilename dump-80.rdb

6:修改完成保存退出

键盘按下esc键
键盘按下shift+ZZ

7:分别通过以下命令来启动Redis

redis-server /pathxxx/redis.conf


一主二仆

首先要查看本台服务器的基本信息(前提要通过 redis-cli redis.conf登录到当前redis)

info replication

设置从机数据备份,就是如果主机上的数据有什么变化,从机跟着变化.

slaveof 127.0.0.1 6379 [slaveof 主机IP 主机Port]

例如:要主机上面:

# 主机 
set k1 v1
# 从机是可以get到的
get k1

知识点
- 从机的数据和主机的数据一样,是从头到尾都有的.
- 从机只有读的权限,没办法添加一个新值到Redis.
- 当生机挂掉以后,从机会选择待命状态,原值还可以get到.
- 主机从down机状态恢复正常后.从机随机恢复连接状态. 
- 从机down机后重新启动后,除写入配置文件(Redis.conf)以外的情况,需要重新与主机进行连接.
薪火相传

原因:

单一主机在面对多台从机的时候会变成主机压力较大,比减小主机压力.需要去中心化,在从机上面再挂从机.

操作:

一个slave可以是下一个slave的master.slave同样可以接收其他slave的连接和请求.那么该slave作为下一人slave的master.从而减小主maser的负担 .

设置:

    设置非常的简单,像第一台从机一样.只能通过命令直接告诉Redis备用机需要挂载到哪一台下面就好了.

slaveof 127.0.0.1 6380

结果:

当我们在主机master上面添加一个新值的时候,数据首先被第一级从机备份,紧接着被第二级从机备份.此时,两三从机都可以get到最新的数据.


反客为主

出现原因:

当redis主机down机以后.为了服务器可以正常运行.我们需要选择一台新的机器来作为主机使用.

例如,我们选择一台原来主机的从机作为现在的主机.

执行命令

# 恢复从机的主机身份
# 使当前的数据库停止与其他数据库的同步.转为主库,形成一个新的中心点.     
slaveof no one


哨兵模式

简介:

反客为主的自动版.

原理:

写一个配置档(固定名称:sentinel.conf)与自定义redis.conf文件同级,设置去监控主机.如果主机出现down机的话.以投票的形式选出一台新主机.

Sentinel.conf

sentinel monitor 监控主机名(随便启) 监控主机IP 监控主机port 票数(当某一台从机的票数大于这个额度时按票# # 数多少选为主机)
sentinel monitor xiaobaibi-redis 127.0.0.1 6379 1


此时如果之前用6.3中的安装方式的话.redis是不存在redis-sentinel 插件的.需要通过命令进行安装

sudo apt install redis-sentinel


启动sentinel:

# 如果当前路径不是sentinel.conf所有的路径,需要指定文件夹地址
sudo redis-sentinel sentinel.conf


启动成功


结论

当主机因各种原因下线down机时,sentinel会自己从从机中选择一台转换为主机.这个过程大概在主机离线30秒以后.当主机被修复好重新上线以后.会被sentinel安排为新主机的从机.

复制延时

由于所有的写操作都是在master上操作.然后同步更新到Slave上.所有从Master同步到slave机器有一定的延迟.当系统很繁忙的时候,延迟问题会更加严重.Slave机器数量的增加也会使这个问题更加严重.


Java客户端Jedis

1> 使用 IDEA 或 Eclipse创建一个普通的 Java Maven项目.

2> 导入 Jedis 的 Maven GVA

<?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>java-redis</groupId>
    <artifactId>jedis-study</artifactId>
    <version>1.0-SNAPSHOT</version>
    <dependencies>
        <!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.0.1</version>
        </dependency>
        <!-- 日志 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.5</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.5</version>
        </dependency>
    </dependencies>
</project>


3> 创建一个Java测试类,测试连接是否正常

package com.jedis;

import redis.clients.jedis.Jedis;

public class JedisTest {

    public static void main(String[] args) {
        try {
            Jedis jedis = new Jedis("192.168.93.43",6380);
            System.out.println(jedis.ping());
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}


附:

    如果Redis服务器与你的Java程式不在同一台服务器上面.需要对redis.conf进行修改,以让Redis 可以被其他服务器连接到.

修改地方:   

redis 服务器 IP 地址
bind 192.168.93.43 


4> API 操作

package com.api;

import redis.clients.jedis.Jedis;

import java.util.Set;

public class RedisAPITest {

    public static void main(String[] args) {
        Jedis jedis = new Jedis("192.168.93.43",6381);
        // 获取全部的 Key
        Set<String> sets = jedis.keys("k*");
        for (String key : sets) {
            System.out.println(key);
        }
        // 添加一个 key
        jedis.set("j_k1","这是一个 jedis value");
        System.out.println(jedis.get("j_k1"));
    }
}


5> 事务

package com.trans;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;

/**
 * 事务测试类
 */

public class RedisTransTest {
    public static void main(String[] args) {
        Jedis jedis = new Jedis("192.168.93.43",6381);
        // 开启事务
        Transaction multi = jedis.multi();
        // 执行操作
        multi.set("tk1","tv1");
        multi.set("tk2","tv2");
        multi.set("tk3","tv3");
        // 提交操作
        multi.exec();
        // 放弃本次操作
//      multi.discard();
    }
}


6> 其他的操作与之前的命令操作几本一样.遇到需要的直接以命令的格式使用即可.

7> 主从复制

package com.mands;

import redis.clients.jedis.Jedis;

/**
 * 主从复制
 */

public class RedisMAS {
    public static void main(String[] args) {
        Jedis jedis80 = new Jedis("192.168.93.43",6380);
        Jedis jedis81 = new Jedis("192.168.93.43",6381);

        // 将6381修改为6380的从机
        jedis81.slaveof("192.168.93.43",6380);
        // 主机写值
        jedis80.set("k3""v3");
        // 从机读值
        System.out.println(jedis81.get("k3"));

    }
}


连接池

知识点:


连接池主类

package com.pool;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

/**
 * redis 连接池
 */

public class JedisPoolTools {


    private static volatile JedisPool jedisPool = null;

    private JedisPoolTools(){};

    public static JedisPool getJedisInstance(){
        if (jedisPool == null){
            synchronized (JedisPoolTools.class){
                if (jedisPool == null){
                    JedisPoolConfig poolConfig = new JedisPoolConfig();
                    // 最多有多少个空闲状态的实例.
                    poolConfig.setMaxIdle(20);
                    poolConfig.setMaxWaitMillis(100*1000);
                    // 获取一个jedis实例的时候是否检查连接可用性.如果为true.得到jedis实例均是可用的.
                    poolConfig.setTestOnBorrow(true);
                    jedisPool = new JedisPool(poolConfig, "192.168.93.43",6380);
                }
            }
        }

        return jedisPool;
    }

    public static void close(JedisPool jedisPool, Jedis jedis){
        if (jedis != null){
            jedis.close();
        }
    }
}


连接池测试类

package com.pool;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

/**
 * 测试类
 */

public class JedisPoolTest {
    public static void main(String[] args) {
        try {

            JedisPool jedisPool = JedisPoolTools.getJedisInstance();
            Jedis jedis = jedisPool.getResource();
            jedis.set("k4","v4");
            jedis.close();
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}


总结 

今天讲的内容不太多,集群主从复制是非常实用的部分,面试也是重点内容.

Jedis只不过是Java中如何去调用Redis而已.所有的命令都是通过jedis那个对象就可以调用出来.只要会了命令就完全可以直接使用 edis.

下载Demo&小编笔记

公众号回复:

[ redisdemo ] :获取Java的Jedis Demo.

[ redisbook ] : 获取小编学习笔记.

文章转载自小败笔的颠沛流离,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论