Redis基础(Jedis、持久化)

3 篇文章 0 订阅

Redis基础

 
前文:Redis入门
 

1.HelloWorld(Jedis版)

1.1 Jedis简介

编程语言与redis

Jedis用户Java语言连接redis服务,并提供对应的操作API

image-20210423173624144

Java语言连接redis服务:

  • Jedis
  • SpringData Redis
  • Lettuce

C、C++、C#、Erlang、Lua、Objective-C、Perl、PHP、Python、Ruby、Scala

1.2 准备工作

jar包导入

下载地址:https://mvnrepository.com/artifact/redis.clients/jedis

修改redis服务启动配置文件redis-6379.conf

[root@192 conf]# vim redis-6379.conf
#bind 192.168.0.102
protected-mode no
port 6379
# timeout 0
daemonize no
logfile "log-6379.log"
dir /redis/data

开启redis服务:

[root@192 ~]# redis-server /redis/conf/redis-6379.conf

1.3 IDEA编写代码

测试类:

package com.itheima;

import redis.clients.jedis.Jedis;

public class JedisTest {
    public static void main(String[] args) {
        //1.获取连接对象
        Jedis jedis = new Jedis("192.168.0.102",6379);
        //2.执行操作
        jedis.set("name","itheima");
        //3.关闭连接
        jedis.close();
    }
}

出现异常

redis.clients.jedis.exceptions.JedisConnectionException: Failed connecting to host xxxxx:6379

百度到一篇优秀的博文,解决办法如下:

  1. 进入redis启动配置文件,注释bind,并将protected-mode设置为no

    image-20210423205745182
  2. 查看防火墙,并将6379端口设为白名单

    1. [root@192 conf]# systemctl status firewalld 查看防火墙状态
    2. [root@192 conf]# firewall-cmd --state 查看防火墙状态
    3. [root@192 conf]# firewall-cmd --permanent --add-port=6379/tcp 将6379端口设为白名单
    4. [root@192 conf]# firewall-cmd --permanent --query-port=6379/tcp 查询6379端口是否为白名单
    5. [root@192 conf]# firewall-cmd --reload 重启防火墙
    image-20210423210304869
  3. 重启redis服务

    redis-server /redis/conf/redis-6379.conf

  4. 进入idea运行无异常

    image-20210423210650551

如有疑问,可访问博文:点击查看

1.4 客户端连接redis

连接redis

  • Jedis jedis = new Jedis("192.168.0.102",6379);
    

操作redis

  • jedis.set("hello","redis");
    String s = jedis.get("hello");
    System.out.println(s);//redis
    

关闭redis连接

  • jedis.close();
    

API文档

  • http://xetorthio.qithub.io/jedis/
  • https://www.mklab.cn/onlineapi/jedis/ [Jedis 2.9.0 API]

Java代码操作redis数据:

package com.itheima;

import redis.clients.jedis.Jedis;

import java.util.List;

public class JedisTest {
    public static void main(String[] args) {
        //1.获取连接对象
        Jedis jedis = new Jedis("192.168.0.102",6379);
        //2.执行操作
//        jedis.set("age","30");

//        String s = jedis.get("hello");
//        System.out.println(s);

//        jedis.lpush("list1","a","b","c","d");
//        List<String> list1 = jedis.lrange("list1", 0, -1);
//        for (String s : list1) {
//            System.out.println(s);
//        }

        jedis.sadd("set1","abc","abc","cde");
        Long len = jedis.scard("set1");
        System.out.println(len);//2

        //3.关闭连接
        jedis.close();
    }
}

基于maven:

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>3.3.0</version>
</dependency>

 

2.Jedis简易工具类开发

2.1 基于连接池获取连接

JedisPool:jedis提供的连接池技术

  • poolConfig:连接池配置对象
  • host:redis服务地址
  • port:redis服务端口号
public JedisPool(GenericObjectPoolConfig poolConfig, String host, int port) {
    this(poolConfig, (String)host, port, 2000);
}

还需要导入jar包:

commons-pool2-2.9.0.jar

log4j-1.2.17.jar

slf4j-api-1.7.30.jar

slf4j-log4j12-1.7.25.jar

maven资源:https://mvnrepository.com/

2.2 封装连接参数

创建配置文件:jedis.properties

redis.maxTotal=50
redis.maxIdel=10
redis.host=192.168.0.102
redis.port=6379

2.3 加载配置信息

静态代码块初始化资源

static {
    ResourceBundle bundle = ResourceBundle.getBundle("jedis");
    maxTotal = Integer.parseInt(bundle.getString("redis.maxTotal"));
    maxIdle = Integer.parseInt(bundle.getString("redis.maxIdel"));
    host = bundle.getString("redis.host");
    port = Integer.parseInt(bundle.getString("redis.port"));

    //Jedis连接池配置
    jpc = new JedisPoolConfig();
    jpc.setMaxTotal(maxTotal);
    jpc.setMaxIdle(maxIdle);

    //连接池对象
    jp = new JedisPool(jpc,host,port);
}

2.4 获取连接

对外访问接口,提供jedis连接对象,连接从连接池获取

public static Jedis getJedis() {
    return jp.getResource();
}

2.5 测试工具类

工具类:

package com.itheima.util;

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

import java.util.ResourceBundle;

public class JedisUtils {
    private static int maxTotal;
    private static int maxIdle;
    private static String host;
    private static int port;

    private static JedisPoolConfig jpc;
    private static JedisPool jp;

    static {
        ResourceBundle bundle = ResourceBundle.getBundle("jedis");
        maxTotal = Integer.parseInt(bundle.getString("redis.maxTotal"));
        maxIdle = Integer.parseInt(bundle.getString("redis.maxIdel"));
        host = bundle.getString("redis.host");
        port = Integer.parseInt(bundle.getString("redis.port"));

        //Jedis连接池配置
        jpc = new JedisPoolConfig();
        jpc.setMaxTotal(maxTotal);
        jpc.setMaxIdle(maxIdle);

        //连接池对象
        jp = new JedisPool(jpc,host,port);
    }

    public static Jedis getJedis() {
        return jp.getResource();
    }
}

测试类:

package com.itheima;

import com.itheima.util.JedisUtils;
import redis.clients.jedis.Jedis;

import java.util.List;

public class JedisTest {
    public static void main(String[] args) {
        //1.获取连接对象
//        Jedis jedis = new Jedis("192.168.0.102",6379);
        Jedis jedis = JedisUtils.getJedis();
        //2.执行操作
//        jedis.set("age","30");

//        String s = jedis.get("hello");
//        System.out.println(s);

//        jedis.lpush("list1","a","b","c","d");
//        List<String> list1 = jedis.lrange("list1", 0, -1);
//        for (String s : list1) {
//            System.out.println(s);
//        }

        jedis.sadd("set1","abc","abc","cde","poi","cba");
        Long len = jedis.scard("set1");
        System.out.println(len);//4

        //3.关闭连接
        jedis.close();
    }
}

 

3.可视化客户端

工具:Redis Desktop Manager

image-20210423234800050

连接操作:

在这里插入图片描述

数据页面:

image-20210423235408785

 

4.持久化

4.1 持久化简介

意外断电,内存断电即失,硬盘永久保存

自动备份:数据自动从内存保存到硬盘

持久化:利用永久性存储介质将数据进行保存,在特定的时间将保存的数据进行恢复的工作机制称为持久化

持久化用于防止数据的意外丢失,确保数据安全性

持久化过程保存什么

  • 将当前数据状态进行保存,快照形式,存储数据结果,存储格式简单,关注点在数据
  • 将数据的操作过程进行保存,日志形式,存储操作过程,存储格式复杂,关注点在数据的操作过程
image-20210424000812173

4.2 RDB

RDB启动方式-save指令

手动执行一个保存操作

  • save

RDB启动方式-save指令相关配置

设置本体数据库文件名,默认为dump.rdb,通常设置为dump-端口号.rdb

  • dbfilename filename

设置存储.rdb文件的路径,通常设置成存储空间较大的目录,目录名称data

  • dir path

设置存储至本地数据库时是否压缩数据,默认yes,设置为no,节省CPU运行时间,但存储文件变大

  • rdbcompression yes|no

设置读写文件过程是否进行RDB格式校验,默认yes,设置为no,节约读写10%时间消耗,但存在数据损坏的风险

  • rdbchecksum yes|no

具体操作:

  1. 进入redis服务启动配置文件,添加保存数据文件dbfilename “dump-6379.rdb”

    [root@192 conf]# vim redis-6379.conf
    #bind 0.0.0.0
    protected-mode no
    port 6379
    # timeout 0
    #daemonize no
    #logfile "log-6379.log"
    dir /redis/data
    dbfilename "dump-6379.rdb"
    
  2. 重启服务器与客户端

    服务器:[root@192 ~]# redis-server /redis/conf/redis-6379.conf

    客户端:[root@192 ~]# redis-cli -h 192.168.0.102

  3. 客户端使用save指令,设置两条数据存入文件

    192.168.0.102:6379> save
    OK
    192.168.0.102:6379> set name itheima
    OK
    192.168.0.102:6379> save
    OK
    192.168.0.102:6379> set age 30
    OK
    192.168.0.102:6379> save
    OK
    192.168.0.102:6379> 
    
  4. 查看数据保存文件

    [root@192 data]# cat dump-6379.rdb
    REDIS0009dis-ver5.0.0edis-bitsctime¾zused-memf-preambleҽn[root@192 data]# 
    [root@192 data]# cat dump-6379.rdb
    REDIS0009dis-ver5.0.0edis-bitsctime¾zused-memf-preamblenameitheima"[root@192 data]# 
    [root@192 data]# cat dump-6379.rdb
    f-preamblenameitheimaageroot@192 data]# 
    
  5. 再查看服务器端窗口,会有保存指令日志记录(需要在redis启动配置文件中注释日志,即上面配置文件中logfile)

    26078:M 24 Apr 2021 09:53:39.233 * Ready to accept connections
    26078:M 24 Apr 2021 09:56:14.453 * DB saved on disk
    26078:M 24 Apr 2021 09:57:37.288 * DB saved on disk
    26078:M 24 Apr 2021 10:04:29.473 * DB saved on disk
    
  6. 重启服务器端和客户端,测试是否能获取保存的数据

    192.168.0.102:6379> get name
    "itheima"
    

    成功获取,已将数据库数据持久化保存到文件中

RDB启动方式-save指令

image-20210424103508818

注意:save指令的执行会阻塞当前Redis服务器,直到当前RDB过程完成为止,有可能会造成长时间阻塞,线上环境不建议使用

RDB启动方式-bgsave指令相关配置

后台存储过程中如果出现错误现象,是否停止保存操作,默认yes

  • stop-write-on-bgsave-error yes|no

其他

  • dbfilename filename
  • dir path
  • rdbcompression yes|no
  • rdbchecksum yes|no

具体操作:

  1. 配置文件上面使用save指令时已修改,此处不再修改

  2. 启动服务端和客户端

  3. 使用bgsave保存客户端设置的数据

    [root@192 ~]# redis-cli -h 192.168.0.102
    192.168.0.102:6379> keys *
    1) "age"
    2) "name"
    192.168.0.102:6379> set name2 itcasst
    OK
    192.168.0.102:6379> bgsave
    Background saving started
    192.168.0.102:6379> 
    
  4. 指令窗口查看保存的数据文件

    [root@192 data]# cat dump-6379.rdb
    REDIS0009dis-ver5.0.0edis-bitsctime`ed-memf-preambleagenameitheimaname2itcasst{[root@[root@192 data]# ^C
    [root@192 data]# 
    

    可以看出文件中有新设置的数据

  5. 再查看服务器端,可以看到保存的日志记录

    image-20210424110005637

RDB启动方式-bgsave指令工作原理

image-20210424104718471

注意:bgsave命令是针对save阻塞问题做的优化。Redis内部所有涉及到RDB操作都采用bgsave的方式,save命令可以放弃使用。

RDB启动方式-save配置

设置自动持久化的条件,满足限定时间范围内key的变化数量达到指定数量即进行持久化

  • save second changes

参数

  • second:监控时间范围
  • changes:监控key的变化量

范例:

  • save 900 1 900秒有1条key发生变化,执行持久化
  • save 300 10 300秒有10条key发生变化,执行持久化
  • save 60 10000 60秒有10000条key发生变化,执行持久化

RDB启动方式-save配置相关配置

其他

  • dbfilename filename
  • dir path
  • rdbcompression yes|no
  • rdbchecksum yes|no
  • stop-write-on-bgsave-error yes|no

具体操作:

  1. 进入redis服务启动配置文件,添加一条save指令 save 10 2

    [root@192 conf]# vim redis-6379.conf
    #bind 0.0.0.0
    protected-mode no
    port 6379
    # timeout 0
    #daemonize no
    #logfile "log-6379.log"
    dir /redis/data
    dbfilename "dump-6379.rdb"
    save 10 2
    
  2. 重启服务器与客户端

  3. 删除前面产生的dump-6379.rdb数据文件

    [root@192 data]# rm -rf *
    
  4. 客户端使用set指令存入数据

    [root@192 ~]# redis-cli -h 192.168.0.102
    192.168.0.102:6379> set name itheima
    OK
    192.168.0.102:6379> set age 39
    OK
    192.168.0.102:6379> set name itcast
    OK
    192.168.0.102:6379> set name2 itcast
    OK
    192.168.0.102:6379> 
    
  5. 指令窗口查看保存数据的文件

    [root@192 data]# ll
    总用量 0
    [root@192 data]# ll
    总用量 4
    -rw-r--r--. 1 root root 118 4月  24 11:17 dump-6379.rdb
    [root@192 data]# ll
    总用量 4
    -rw-r--r--. 1 root root 118 4月  24 11:17 dump-6379.rdb
    [root@192 data]# ll
    总用量 4
    -rw-r--r--. 1 root root 131 4月  24 11:18 dump-6379.rdb
    [root@192 data]# 
    

    可以看出,开始没有数据文件dump-6379.rdb,当添加两条数据name和age时,自动创建数据文件并存入数据。当修改name后,数据文件大小仍为118,无变化。当再添加一个数据name2时,此时以满足save指令要求,查看发现文件增长至131,说明已进行自动保存

  6. 服务端日志

    image-20210424114028283

RDB启动方式-save配置工作原理

image-20210424114134415

注意:save配置要根据实际业务情况进行设置,频度过高或过低都会出现性能问题,结果可能是灾难性的,save配置启动后执行的是bgsave操作

RDB三种启动方式对比

方式save指令bgsave指令save配置(同bgsave)
读写同步异步
阻塞客户端指令
额外内存消耗
启动新进程

RDB特殊启动形式

服务器运行过程中重启

  • debug reload

关闭服务器时指定保存数据

  • shutdown save

全量复制(在主从复制中详解)

RDB优点:

  • RDB是一个紧凑压缩的二进制文件,存储效率较高
  • RDB内部存储的是redis在某个时间点的数据快照,非常使用用于数据备份,全量复制等场景
  • RDB恢复数据的速度要比AOF快很多
  • 应用:服务器中每x小时执行bgsave备份,并将RDB文件拷贝到远程机器中,用于灾难恢复

RDB缺点:

  • RDB方式无论是执行指令还是利用配置,无法做到实时持久化,具有较大的可能性丢失数据
  • bgsave指令每次运行都要执行fork操作创建子进程,要牺牲掉一些性能
  • Redis的众多版本未进行RDB文件格式的版本统一,有可能出现各版本服务之间数据格式无法兼容现象

4.3 AOF

RDB存储的弊端:

  • 存储数据量较大,效率较低,基于快照思想,每次读写都是全部数据,当数据量巨大时,效率非常低
  • 大数据量下的IO性能较低
  • 基于fork创建子进程,内存产生额外消耗
  • 宕机带来的数据丢失风险

解决思路:

  • 不写全数据,仅记录部分数据
  • 降低区分数据是否改变的难度,该记录数据为记录操作过程
  • 对所有操作均进行记录,排除丢失数据的风险

AOF概念:

  • AOF(append only file)持久化:以独立日志的方式记录每次写命令,重启时再重新执行AOF文件中命令达到恢复数据的目的。与RDB相比可以简单理解为由记录数据改为记录数据产生的变化
  • AOF的主要作用少解决了数据持久化的实时性,目前已经是Redis持久化的主流方式

AOF写数据过程

image-20210424142123864

启动AOF相关配置

开启AOF持久化功能,默认no,即不开启状态

  • appendonly yes|no

AOF持久化文件名,默认文件名为appendonly.aof,建议配置为appendonly-端口号.aof

  • appendfilename filename

AOF持久化文件保存路径,与RDB持久化文件保存一致即可

  • dir

AOF写数据策略,默认为everysec

  • appendfsync always|everysec|no

AOF写数据三种策略(appendfsync):

  • always(每次):每次写数据操作均同步到AOF文件中。
    • 数据零误差,性能较低,不建议使用
  • everysec(每秒):每秒将缓冲区中的指令同步到AOF文件中,在系统突然宕机的情况下丢失1秒内的数据
    • 数据准确性较高,性能较高,建议使用,也是默认配置
  • no(系统控制):由操作系统控制每次同步到AOF文件的周期
    • 整体过程不可控

具体操作:

  1. 进入redis服务启动配置文件,添加aof相关指令

    [root@192 conf]# vim redis-6379.conf
    #bind 0.0.0.0
    protected-mode no
    port 6379
    # timeout 0
    #daemonize no
    #logfile "log-6379.log"
    dir /redis/data
    dbfilename "dump-6379.rdb"
    save 10 2
    appendonly yes
    appendfilename "appendonly-6379.aof"
    appendfsync everysec
    
  2. 重启服务器与客户端

  3. 查看aof产生的appendonly-6379.aof数据文件

    image-20210424145435275
  4. 客户端使用set指令存入数据

    image-20210424145526985
  5. 再次查看数据文件

    image-20210424150452160
  6. 查看文件内容

    image-20210424152406431
  7. 进行一些操作后查看

    image-20210424153110488

    AOF写数据遇到的问题:

    如果连续执行如下指令该如何处理

    image-20210424153949006

AOF重写

随着命令不断写入AOF,文件会越来越大,为了解决这个问题,Redis引入了AOF重写机制。AOF文件重写是将Redis进程内的数据转化为写命令同步到新AOF文件的过程。简单说就是将对用一个数据的若干条命令执行结果转化成最终结果数据对应的指令进行记录

AOF重写作用

  • 降低磁盘占用量,提高磁盘利用率
  • 提交持久化效率,降低持久化写时间,提高IO性能
  • 降低数据恢复用时,提高数据恢复效率

AOF重写规则

  • 进程内具有时效性的数据,并且数据已超时将不再写入文件
  • 非写入类的无效指令将被忽略,只保留最终数据的写入命令
    • 如del key1、hdel key2、srem key3、set key4 111、set key4 222等
    • 如select指令虽然不更新数据,但是更改了数据的存储位置,此类命令同样需要记录
  • 对同一数据的多条命令合并为一条命令
    • 如lpush list1 a、lpush list1 b、lpush list1 c可以转为:lpush list1 a b c
    • 为防止数据量过大造成客户端缓冲区溢出,对list、set、hash、zset等类型,每条指令最多写入64个元素

AOF重写方式

手动重写

  • bgrewriteaof

自动重写

  • auto-aof-rewrite-min-size size
  • auto-aof-rewrite-percentage percentage

具体操作:

  1. 停掉服务器和客户端,删除aof文件

    image-20210424161123014
  2. 重启服务器和客户端

  3. 客户端页面存入数据,命令操作查看aof文件

    image-20210424161459821
  4. 手动重写,查看文件内容

    image-20210424162354982 image-20210424162849257
  5. 再向redis中添加数据并查看

    image-20210424163245317

    image-20210424163457361

    可以看出重写后的数据与未重写的数据在文件中的格式不相同

    AOF手动重写-bgrewriteaof指令工作原理

    image-20210424163916027

AOF自动重写方式

自动重写触发条件设置

  • auto-aof-rewrite-min-size size
  • auto-aof-rewrite-percentage percentage

自动重写触发比对参数(运行指令info Persistence获取具体信息)

  • aof_current_size
  • aof_base_size

自动重写触发条件

  • aof_current_size > auto-aof-rewrite-min-size
  • (aof_base_size - aof_current_size) / aof_base_size >= auto-aof-rewrite-percentage

AOF重写流程

image-20210424165026642

4.4 RDB与AOF区别

RDB VS AOF

持久化方式RDBAOF
占用存储空间小(数据级:压缩)大(指令级:重写)
存储速度
恢复速度
数据安全性会丢失数据依据策略决定
资源消耗高/重量级低/轻量级
启动优先级

RDB与AOF的选择之惑

  • 对数据非常敏感,建议使用默认的AOF持久化方案
    • AOF持久化策略使用everysec,每秒中更新一次。该策略redis仍可以保持很好的处理性能,当出现问题时,最多丢失0-1秒内的数据
    • 注意:由于AOF文件存储体积较大,且恢复速度较慢
  • 数据呈现阶段有效性,建议使用RDB持久化方案
    • 数据可以良好的做到阶段内无丢失(该阶段是开发者或运维人员手工维护的),且恢复速度较快,阶段点数据恢复通常采用RDB方案
    • 注意:利用RDB实现紧凑的数据持久化会使Redis降的很低,慎重总结
  • 综合对比:
    • RDB与AOF的选择实际上是在做一种权衡,每种都有利有弊
    • 如不能承受数分钟以内的数据丢失,对业务数据非常敏感,选用AOF
    • 如能承受数分钟以内的数据丢失,且追求大数据集的恢复速度,选用RDB
    • 灾难恢复选用RDB
    • 双保险策略,同时开启RDB和AOF,重启后,Redis优先使用AOF来恢复数据,降低丢失数据的量

下文:Redis进阶
相关文章:Redis入门Redis基础Redis进阶Redis高级

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值