Redis事务、持久化、主从复制、哨兵、JRedis和JRedis Pool(摘抄)

事务是指一系列操作步骤,这一系列的操作步骤,要么完全执行,要么完全地不执行
Redis中的事务是一组命令的集合,至少是两个或两个以上的命令,redis事务保证这些命令被执行时中间不会被任何操作打断
(1)multi标记一个事务的开始,事务内的多条命令会按照先后顺序被放入一个队列中,返回值总是ok
(2)exec执行所有事务内的命令,返回事务内的所有执行语句内容,事务被打断返回nil,如果其中一条事务语法错误,则无法执行事务(任意一条),会完全放弃该事务内的任意命令。
另一个错误是语法没有错误,但执行出错,不报错的事务会执行成功,执行错误的命令报错(因为没有回滚机制)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
(3)discard取消事务,放弃执行事务块的所有命令,返回值综述ok
在这里插入图片描述
(4)watch监视该值的改变
redis的watch机制:使用watch监视一个或多个key,跟踪key的value修改情况,如果有key的value值在事务Exec执行之前被修改了,整个事务被取消。Exec返回提示信息,表示事务已经失败。
监视后,发现age的值已经被改动,所以放弃当前的事务。注意,redis同一时间只操作一个key
在这里插入图片描述
这事实上就是乐观锁的实现机制
(4)持久化,即存储将数据存储到一个不会丢失的地方,如果把数据放到内存中,非常容易丢失,所以放在内存中的数据不是持久化,而放到磁盘就算一种持久化,Redis提供两种机制对数据进行持久化存储,便于发生故障后能迅速回复数据(AOF和RDB)

=================================
Redis Database(RDB)指定的时间间隔将内存中的数据写到磁盘,数据恢复时将快照文件读到内存中。

RDB保存了某个时间点的全部数据集,存储在一个二进制文件中,只有一个文件,默认是dump.rdb。RDB技术非常适合做备份,可以保存最近一个小时,一天,一个月的全部数据。保存数据是在单独的进程中写文件,不影响redis的正常使用。RDB回复数据时比其它AOP速度更快

RDB方式的数据持久化,仅需在redis.conf文件中配置即可,默认配置是启用的。在配置文件redis.conf中搜索SNAPSHOTTING,查找在注释开始和结束之间的关于RDB的配置说明。配SNAPSHOTTING地方有三处。

①配置执行RDB生成快照文件的时间策略,对Redis进行设置,让它在“N秒内数据集至少有M个key改动”这一条件被满足时,自动保存一次数据集。

配置格式:save seconds change
save 900 1
save 300 10
save 60 100000
这三个策略是可以同时触发的

②dbfilename:设置RDB的文件名,默认文件名为dump.rdb

③dir:指定RDB文件的存储位置,默认是当前目录

RDB的缺点就是,其会丢失数据,一旦没有满足触发策略容易发生数据丢失

=================================
Append-only File(AOF),Redis每次接收到一条改变数据的命令时,它将把该命令写到一个AOF文件中(只记录命令,是一个文本文件,可以修改),当Redis重新启动时,它通过执行AOF文件中的所有命令来恢复数据。

AOF方式的数据持久化,在redis.conf文件中配置即可:
①appendonly:默认是no,改成yes,即开启aof持久化
②appendfilename:指定AOF文件名,默认文件名为appendonly.aof
③dir:指定RDB和AOF文件存放的目录,默认是
④appendfsync:配置向aof文件写命令数据的策略:
no:不主动进行同步操作,而是完全交给操作系统来做(即每30秒一次),比较快但不是很安全
always:每次执行写入都会执行同步,慢但是安全
everysec:每秒执行一次同步操作,慢一些但是比较安全
⑤auto-aof-rewrite-min-size:允许重写的最小AOF文件大小,默认是64M。当aof文件大于64M时,开始整理aof文件,去掉无用的操作命令,缩小aof文件。
(5)redis服务器的主从复制
为了避免单点故障,我们需要将数据复制多份部署在多台不同的服务器上,即使有一台服务器出现故障,其他服务器依然可以继续提供服务。
这就要求当一台服务器上的数据更新后,自动将更新的数据同步到其它服务器上,那该怎么实现?Redis主从复制
在这里插入图片描述
主master负责数据的修改操作,从redis全部负责数据的读操作。读写分离可以降低服务器压力。

通过启动多个redis-server可以模拟主从复制结构。

Redis主从复制实现(master/salve)
方式1:修改配置文件,启动时,服务器读取配置文件,并自动称为指定服务器的从服务器,从而构成主从复制关系

新建三个redis的配置文件

如果redis启动,先停止
作为Master的redis端口是6380
作为Slaver的redis端口分别是6382,6384
从原有的redis.conf拷贝三份,分别命名为redis6380.conf,redis6382.conf,redis6384.conf。
复制这几个就是为了在一台机子上启动多个redis server
在这里插入图片描述
编辑Master配置文件
redis6380.conf在空文件中加入如下内容:
include /usr/local/redis-3.2.9/redis.conf
包含原来的配置文件的内容,将redis.conf加入到当前配置文件
daemonize yes
表示redis是后台启动
port 6380
当前redis的端口号
pidfile /var/run/redis_6380.pid
linux运行程序的唯一标识,需要一个位置存储唯一的表示路径
logfile 6380.log
设置日志文件位置
dbfilename dump6380.rdb
rdb存储的位置

编辑Slave配置文件
redis6382.conf和redis6384.conf在空文件中加入如下内容:
include /usr/local/redis-3.2.9/redis.conf
daemonize yes
port 6382
pidfile /var/run/redis_6382.pid
logfile 6382.log
dbfilename dump6382.rdb
slaveof 127.0.0.1 6380
设置主master地址

===================================
./redis-cli -p 6380
Master服务器的客户端
info replication
显示服务器的关系信息
在这里插入图片描述
同样,连接到6382,显示的是up
在这里插入图片描述
在主服务器上添加key和val,主从都会显示。从服务器只能读不能写。

当Master服务出现故障,需要手动将slave中的一个提升为master,剩下的slave挂至新的master上

命令:
①:slaveof no one
将一台slave服务器提升为Master
②:slaveof 127.0.0.1 6381

方式二:./redis-server --slaveof master-ip master-port在启动redis时指定当前服务成为某个主redis服务的从Slave

(6)哨兵系统
可自动化的处理故障

  • 监控:Sentinel不断的检查主服务和从服务是否按照预期正常工作
  • 提醒:被监控的redis出现问题时,Sentinel会通知管理员或其它应用程序
  • 自动故障转移:监控的主redis不能正常工作,Sentinel会开始进行故障迁移操作。就是将从服务器提升为主服务器,其它服务器挂到新主服务器之上。
  • 在这里插入图片描述
  • 每个哨兵(Sentinel)独立运行,可以进行通讯,并交换监控的结果。哨兵通过心跳机制来检查主从服务器是否正常。哨兵的个数必须是奇数,从而投票觉得当前主服务器是否运行正常。

安装完redis,哨兵就已经存在,redis-sentinel。我们在一台机子上模拟三个哨兵系统,复制三份sentinel.conf文件:
在这里插入图片描述
Sentinel系统默认port是26379。三个配置port分别设置为26380,26382,26384。三个文件分别命名:

  • sentinel26380.conf
  • sentinel26382.conf
  • sentinel26384.conf
    三个sentinel配置文件修改:
    1、修改port 26380 port 26382 port 26384
    2、修改sentinel monitor mymaster 127.0.0.1 6380 2
    格式:sentinel monitor name masterIp masterPort Quorum投票数
    在这里插入图片描述
    修改之后运行哨兵系统
    在这里插入图片描述
    一旦主redis关闭,会自动转化主redis
    在这里插入图片描述
    此外,如果新启动了一个服务器并且配置哨兵,会自动添加到从服务器之中
    (7)安全设置
    访问redis默认是没有密码的。要设置redis访问密码,修改redis.conf中requirepass 密码。因为redis速度很快,所以在一台比较好的 服务器下,一个外部用户可以1s进行150k次密码尝试,需要指定非常非常强大的密码来防止暴力破解。

开启访问密码设置
修改redis.conf,找到requirepass
只要改了配置文件就重新加载
在这里插入图片描述
两种密码的使用方式:
在这里插入图片描述
在这里插入图片描述

其次,redis可以绑定ip,修改redis.conf文件,把#bind 127.0.0.1前面的注释#号去掉,然后把127.0.0.1改成允许访问你的redis服务器的ip地址,表示只允许该ip进行访问。多个ip使用空格分隔
在这里插入图片描述

最后,修改redis的端口是很重要的,使用默认端口非常危险,redis.conf中修改port6379,将其修改为自己指定的端口,端口1024以内是保留给操作系统,用户可以使用1024-65535
在这里插入图片描述
(8)Jedis操作Redis
在这里插入图片描述
Jedis有线程不安全的问题,一般跟commons-pool(线程池)一起使用。

package com.fty;	
import redis.clients.jedis.Jedis;
import java.util.List;
public class RedisString {
    public static void main(String[] args) {	
        /**
         * 1、修改redis.conf,启动redis需要指定redis.conf的位置
         * 2、关闭linux防火墙,或者让redis的端口号通过防火墙 systemctl statsu firewalld
         */

        //创建Jredis对象,指定连接的redis服务器的ip端口
        Jedis jedis = new Jedis("127.0.0.1", 6379);

//        jedis.auth("密码");

        //调用Jedis对象的方法操作Redis数据
        jedis.set("break", "豆浆和油条");

        //获取key的值
        String value = jedis.get("break");
        System.out.println(value);

        //mset一次创建多个key-value
        jedis.mset("lunch","红烧肉盖饭", "dinner", "牛排");

        //获取多个key对应的值mget
        List<String> values = jedis.mget("break", "lunch", "dinner");
        for(String val : values) {
            System.out.println(val);
        }
    }
}

使用Jedis Pool

package com.fty;	
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;	
public class RedisUtils {	
    private static JedisPool pool;

    //创建JedisPool对象
    public static JedisPool open(String ip, int port) {
        if(pool == null) {
            //创建JedisPool
            //创建JedisPoolConfig,给config设置连接池的参数,使用config对象去创建JedisPool
            JedisPoolConfig config = new JedisPoolConfig();

            //给config设置连接池的参数
            config.setMaxTotal(10);//设置最大的线程数,一个线程就是一个Jedis对象
            config.setMaxIdle(2);//设置最大空闲数
            config.setTestOnBorrow(true);//设置检查项为true,标识线程池中获取的对象一定是经过检查可用的

            /**
             * poolConfig 配置器
             * host:redis所在的ip
             * port:redis的端口
             * timeout:连接redis的超时事件
             * password:redis访问密码
             */
            pool = new JedisPool(config, "localhost", 6379, 6000, "密码");//创建Pool对象
        }
        return pool;
    }
    //关闭pool对象
    public static void close() {
        if(pool != null) {
            pool.close();
        }
    }

    public static void main(String[] args) {
        //从JedisPool中获取JedisPool对象
        JedisPool pool = null;
        Jedis jedis = null;
        try {
            pool = open("localhost", 6379);
            jedis = pool.getResource();

            /**
             * 拿到Jedis后就能进行set 和 get
             */
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //关闭Jedis对象,从Pool中获取的Jedis放回到Pool,共其它请求使用
            if(jedis != null) {
                jedis.close();//放回池中
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/wujingchangye/article/details/85231778