redis笔记③——redis的使用(单机模式)

redis

概述

redis是什么?

redis是完全开源免费的,用c语言编写的,是一个单线程,高性能的(key/value)内存数据库,基于内存运行并支持持久化的nosql数据库。

redis有什么用?

redis主要是用来做缓存,但不仅仅只能做缓存,比如:redis的计数器生成分布式唯一主键,redis实现分布式锁,队列,会话缓存。

下载和安装

下载redis

可以通过官网下载或者通过yum命令下载

官网下载地址
在这里插入图片描述
下载后就可以解压了

安装redis

进入解压后的redis文件夹
在这里插入图片描述
使用make命令

make

在这里插入图片描述
如果make的过程中报错,如果是gcc报错的话,那就要先安装一个gcc
在这里插入图片描述
安装gcc

yum install gcc-c++

在安装好后需要先把之前make的东西清除一下

make distclean

然后在make
在这里插入图片描述
最后通过make install命令完成安装

make install

在这里插入图片描述
redis的默认安装位置是/usr/local/bin
在这里插入图片描述

配置redis

配置redis只需要关注redis文件夹中的redis.conf文件,而且我们一般不会直接使用默认给的配置文件,我们会将它复制一份放到其他地方
在这里插入图片描述

下面是一份带有注释的配置文件
https://pan.baidu.com/s/1wHlRUneRJfP8KH-2-Tz5WA

这里只对其中的一些比较重要的配置做一些介绍

  • 绑定Ip
# 绑定Ip   指定可以连接本实例Redis的ip  如果注释(删掉)则任意IP都可以连接
bind 127.0.0.1

bind可以配置绑定ip,只有绑定的ip才能访问redis,如果注释掉这个配置或者配置成0.0.0.0代表任何ip都可以访问。不过这两种配置还是有所区别的,和后面的配置有所关联,之后再说。

  • 保护模式
#禁止外网访问redis,如果启用了,即使注释掉了bind 127.0.0.1,再访问redisd时候还是无法连接的
#它启用的条件有两个,第一是没有使用bind,第二是没有设置访问密码。
protected-mode yes

这个配置代表是否开启保护模式,如果开启了保护模式,那么只有本机能够访问redis,不过它有两个启用条件,第一是没有使用bind,第二是没有设置访问密码。所以如果在上面bind配置了0.0.0.0那么还是可以访问的。

  • 守护进程
# 是否以守护进程启动
daemonize no

是否以守护进程的方式启动,如果开启了守护进程的方式启动就可以后台启动了,否则我们在一个终端上启动了redis,如果关闭了这个终端就会同时关闭redis。

  • dbf文件目录存放位置
# dbfilename文件存放目录。必须是一个目录,aof文件也会保存到该目录下。
dir ./

配置dbfilename文件存放目录,aof文件也会保存到该目录下,如果我们像上面这样配置为./,那么就是在哪里启动的redis,文件就存放在哪。

启动单机版redis

启动redis很简单,不过我们需要先配置一些东西,因为我们需要让外网访问,需要注意下面几点

  1. 注释bind并且把protected-mode no
  2. 使用bind
  3. 设置密码
  4. protected-mode它启用的条件有两个,第一是没有使用bind,第二是没有设置访问密码。

我们只要注释bind并且把protected-mode no就可以了
在这里插入图片描述
在这里插入图片描述
接着就可以直接启动,主要就是运行redis-server,后面的参数就是我们刚刚的配置文件

/usr/local/bin/redis-server /usr/tool/redis-conf/redis.conf

在这里插入图片描述
我们可以看到redis确实启动了
在这里插入图片描述

redis客户端

redis客户端这里介绍两种,一种是redis自带的,一种是java客户端

命令行客户端

/usr/local/bin/redis-cli

在这里插入图片描述

java客户端

只需要引入一个依赖

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

连接redis服务端

public static void main(String[] args) {
    // 创建jedis客户端,只需要ip和端口就可以连接redis
    Jedis jedis = new Jedis("192.168.123.19", 6379);
    // 发送ping,查看是否连接上了redis
    System.out.println(jedis.ping());
    // 关闭redis客户端
    jedis.close();
}

在这里插入图片描述

客户端的命令和API

redis数据类型及api操作,可以参考下面的文档
http://redisdoc.com/

因为jedis的API将客户端的命令封装的很好,这些API在客户端的命令中都有很好的对应。

key

在redis中每一个数据都有一个key

命令行中的常用命令

查看所有的key,在生产环境中不建议使用,容易引起卡顿

keys *  

一般如果要查询key通常会使用scan,这种查询相当于分页查询

# 0代表从第0个开始查询
# match后面跟着的是查询条件
# 最后count代表要查询的数目
scan  0 match  *  count  1

判断某个key是否存在

exists key 

当前库就没有了,到指定的库中去了

move key db

为给定的key设置过期时间

expire key

查看还有多少时间过期 -1表示永不过期 -2表示已过期

ttl key

查看key是什么类型

type key

jedis客户端常用的API

public static void testKey(){
    Jedis jedis = connRedis();
    System.out.println(jedis.keys("*"));
    System.out.println(jedis.exists("k1"));
    jedis.expire("k1", 60);
    System.out.println(jedis.ttl("k1"));
    System.out.println(jedis.type("k1"));

    System.out.println(jedis.incr("count"));
    System.out.println(jedis.incr("count"));
    System.out.println(jedis.incr("count"));
    System.out.println(jedis.decr("count"));
    System.out.println(jedis.decr("count"));
    System.out.println(jedis.decr("count"));

    System.out.println(jedis.incrBy("count",2));
    System.out.println(jedis.incrBy("count",2));
    System.out.println(jedis.decrBy("count",2));
    System.out.println(jedis.decrBy("count",2));
}
string

string是redis最基本的类型,你可以理解成与Memcached一模一样的类型,一个key对应一个value。

string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。

string类型是Redis最基本的数据类型,一个redis中字符串value最多可以是512M

命令行中的常用命令

设置key value

set  key  value 

查看当前key的值

get  key

删除key

del  key

如果key存在,则在指定的key末尾添加,如果key存在则类似set

append key  value

返回此key的长度

strlen  key

获取指定区间范围内的值,类似between…and的关系 (0 -1)表示全部

getrange  key  0(开始位置)  -1(结束位置)

设置(替换)指定区间范围内的值

setrange key 1(开始位置,从哪里开始设置) 具体值

设置带过期时间的key,动态设置。

setex 键 秒值 真实值

只有在 key 不存在时设置 key 的值。

setnx  key   value 

同时设置一个或多个 key-value 对。

mset   key1   value  key2   value

获取所有(一个或多个)给定 key 的值。

mget   key1   key 2 

同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在。

msetnx   key1   value  key2   value

将给定 key 的值设为 value ,并返回 key 的旧值(old value)。

getset   key    value

以下几个命令只有在key值为数字的时候才能正常操作

为执定key的值加一

incr  key 

为指定key的值减一

decr  key

为指定key的值增加数值

incrby key 数值

为指定key的值减数值

decrby key  数值

常用的jedis客户端API

public static void testString(){
    Jedis jedis = connRedis();
    System.out.println(jedis.set("k1", "v2"));
    System.out.println(jedis.get("k1"));
    System.out.println(jedis.del("k1"));

    System.out.println(jedis.append("k1","v1"));
    System.out.println(jedis.append("k1","v1"));
    System.out.println(jedis.get("k1"));
    System.out.println(jedis.strlen("k1"));
    System.out.println(jedis.mset("k1", "v1", "k2", "v2", "k3", "v3"));
    System.out.println(jedis.mget("k1",  "k2", "k3"));


    System.out.println(jedis.setnx("k1","kkkkk"));
    System.out.println(jedis.get("k1"));

    System.out.println(jedis.setex("k9", 60, "v9"));
    System.out.println(jedis.ttl("k9"));

    System.out.println("=========================");
    SetParams setParams=new SetParams();
    setParams.ex(100);
    setParams.nx();
//        其实NX表示使用NX模式,PX表示过期时间的单位,这里表示毫秒
//        System.out.println(jedis.set("k11", "k11", "NX","PX",100000));
    System.out.println(jedis.set("k11", "k11", setParams));
    System.out.println(jedis.ttl("k11"));
}
list

它是一个字符串链表,left、right都可以插入添加;如果键不存在,创建新的链表;如果键已存在,新增内容;如果值全移除,对应的键也就消失了。

链表的操作无论是头和尾效率都极高,但假如是对中间元素进行操作,效率就很惨淡了。

Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素导列表的头部(左边)或者尾部(右边)。它的底层实际是个链表

常用的命令

将一个或多个值加入到列表头部

lpush  key  value1  value2

将一个或多个值加入到列表底部

rpush  key  value1  value2

获取列表指定范围的元素(0 -1)表示全部

lrange key  start  end

移出并获取列表第一个元素

lpop key

移出并获取列表最后一个元素

rpop key

通过索引获取列表中的元素

lindex key index

获取列表长度

llen

表示删除全部给定的值。零个就是全部值 从left往right删除指定数量个值等于指定值的元素,返回的值为实际删除的数量

lrem key 0(数量)

截取指定索引区间的元素,格式是ltrim list的key 起始索引 结束索引

ltrim key  start(从哪里开始截)  end(结束位置)

常用的API

public static void testList(){
    Jedis jedis = connRedis();
//        jedis.del("lpush");
//        jedis.del("rpush");
    System.out.println(jedis.lpush("lpush","v1","v2","v3","v4"));
    System.out.println(jedis.rpush("rpush","v1","v2","v3","v4"));
    System.out.println(jedis.lrange("lpush",0,-1));
    System.out.println(jedis.lrange("rpush",0,-1));

    System.out.println(jedis.rpop("lpush"));
    System.out.println(jedis.rpop("rpush"));

    System.out.println(jedis.lpop("lpush"));
    System.out.println(jedis.lpop("rpush"));
}
set

Redis的Set是string类型的无序,不能重复的集合。

常用的命令

# 向集合中添加一个或多个成员
sadd key value1 value 2 
# 返回集合中所有成员
smembers  key  
# 判断member元素是否是集合key的成员
sismembers  key   member  
# 获取集合里面的元素个数
scard key  
# 删除集合中指定元素
srem key value  
# 从set集合里面随机取出指定数值个元素,如果超过最大数量就全部取出
srandmember key  数值     
# 随机移出并返回集合中某个元素
spop key  
# 作用是将key1中执定的值移除  加入到key2集合中
smove  key1  key2  value(key1中某个值)   
# 在第一个set里面而不在后面任何一个set里面的项(差集)
sdiff key1 key2  
# 在第一个set和第二个set中都有的(交集)
sinter key1 key2  
# 两个集合所有元素(并集)
sunion key1 key2  

常用的API

public static void testSet(){
    Jedis jedis = connRedis();
    jedis.sadd("set1","v1","v2","v3","v4","v5","v6","v7");
    System.out.println(jedis.smembers("set1"));
    System.out.println(jedis.sismember("set1","v1"));

    jedis.sadd("set2","v1","v2","v3","v4","v11","v12");
    System.out.println(jedis.sdiff("set1", "set2")); //在第一个set里面而不在后面任何一个set里面的项(差集)
    System.out.println(jedis.sinter("set1", "set2"));//在第一个set和第二个set中都有的 (交集)
    System.out.println(jedis.sunion ("set1", "set2"));//两个集合所有元素(并集)
}
hash

Redis的hash是一个键值对集合,是一个string类型的field和value的映射表,hash特别适合用于存储对象。kv模式不变,但v是一个键值对,类似Java里面的Map<String,Object>。

常用的命令

# 向hash表中添加一个元素
hset  key  (key value)  
# 向hash表中获取一个元素
hget key  key  
# 向集合中添加一个或多个元素
hmset  key key1 value1 key2 value2 key3 value3 
# 向集合中获取一个或多个元素
hmget key  key1 key2 key3  
# 获取在hash列表中指定key的所有字段和值
hgetall  key   
# 删除一个或多个hash字段
hdel  key  key1 key2 
# 获取hash表中字段数量
hlen key 
# 查看hash表中,指定key(字段)是否存在
hexits key key  
# 获取指定hash表中所有key(字段)
hkeys  key 
# 获取指定hash表中所有value(值)
hvals key 
# 执定hash表中某个字段加数量,和incr一个意思
hincrdy key  key1  数量(整数)  
# 执定hash表中某个字段加数量,和incr一个意思
hincrdyfloat key key1  数量(浮点数,小数)  
# 与hset作用一样,区别是不存在赋值,存在了无效。
hsetnx key key1 value1  

常用的API

public static void testHash(){
    Jedis jedis = connRedis();
    Map<String,String> map= new HashMap<>();
    map.put("k1","v1");
    map.put("k2","v2");
    map.put("k3","v3");
    System.out.println(jedis.hset("hash", map));

    System.out.println(jedis.hkeys("hash"));
    System.out.println(jedis.hvals("hash"));
    System.out.println(jedis.hgetAll("hash"));
}
zset

Redis的zset和set一样也是string类型元素的集合,且不允许重复的成员。不同的是每个元素都会关联一个double类型的分数。

redis正是通过分数来为集合中的成员进行从小到大的排序,zset的成员是唯一的,但分数(score)却可以重复。

常用的命令

# 向集合中添加一个或多个成员
zadd  key  score 值   score 值   
# 表示所有返回指定集合中所有value
zrange key  0   -1  
# 返回指定集合中所有value和score
zrange key  0   -1  withscores  
# 返回指定score间的值
zrangebyscore key 开始score 结束score    
# 删除元素
zrem key score某个对应值(value),可以是多个值   
# 获取集合中元素个数
zcard key  
# 获取分数区间内元素个数
zcount key   开始score 结束score       
# 获取value在zset中的下标位置(根据score排序)
zrank key vlaue   
# 按照值获得对应的分数
zscore key value  

常用的API

public static void testZset(){
    Jedis jedis = connRedis();
    Map<String,Double> map=new HashMap();
    map.put("k1",10d);
    map.put("k4",40d);
    map.put("k3",30d);
    map.put("k2",20d);
    System.out.println(jedis.zadd("zset", map));
    System.out.println(jedis.zrange("zset", 0, -1));
    System.out.println(jedis.zrangeWithScores("zset", 0, -1));
}
scan

之前说了,我们一般用这个命令代替keys命令查看redis中的key

public void testScan(){
    this.methodScan("0");
}

public static void methodScan(String cursor){
    Jedis jedis = connRedis();
    // 游标初始值为0
    String key = "k*";
    ScanParams scanParams = new ScanParams();
    scanParams.match(key);
    scanParams.count(3);
    ScanResult<String> scanResult = jedis.scan(cursor, scanParams);
    cursor = scanResult.getCursor();// 返回0 说明遍历完成
    System.out.println("返回游标为:"+cursor);
    List<String> list = scanResult.getResult();
    for(int m = 0;m < list.size();m++){
        String mapentry = list.get(m);
        System.out.println("查询出key:"+mapentry);
    }
    System.out.println("==========================");
    if(!"0".equals(cursor)){
        this.methodScan(cursor);
    }
}

redis的持久化

redis的持久化说白了就是在指定的时间间隔内,将内存当中的数据集快照写入磁盘,它恢复时是将快照文件直接读到内存。

毕竟我们知道redis是基于内存存储数据的,但是如果我们关掉redis,再打开redis中的数据依然还在,这就要归功于redis的持久化机制了。我们一关机之后再启动的时候数据是还在的,所以它必然是在redis启动的时候重新去加载了持久化的文件

redis提供两种方式进行持久化,

  1. 一种是RDB持久化默认,

  2. 一种是AOF(append only file)持久化

RDB

RDB是什么?

原理是redis会单独创建(fork)一个与当前进程一模一样的子进程来进行持久化,这个子线程的所有数据(变量。环境变量,程序程序计数器等)都和原进程一模一样,会先将数据写入到一个临时文件中,待持久化结束了,再用这个临时文件替换上次持久化好的文件,整个过程中,主进程不进行任何的io操作,这就确保了极高的性能。

这个RDB文件中存储的就是二进制数据。

RDB持久化的文件存储在哪?

之前我们在redis.conf配置文件中也配置过它的位置
在这里插入图片描述
而且我们还需要配置这个文件的名字
在这里插入图片描述

什么时候fork子进程,或者什么时候触发rdb持久化机制?

  • shutdown时,如果没有开启aof,会触发,这里指的我们正常关闭redis
  • 配置文件中默认的快照配置
    在这里插入图片描述
  • 执行命令save或者bgsave。save是只管保存,其他不管,全部阻塞;bgsave是redis会在后台异步进行快照操作,同时可以响应客户端的请求
    在这里插入图片描述
    上面框住的就是bgsave命令fork出来的子进程,用来持久化数据
  • 执行flushall命令 ,但是里面是空的,无意义

AOF

AOF是什么?

它的原理是将Reids的操作日志以追加的方式写入文件,读操作是不记录的。

AOF存储在哪里?

它的存储位置和RDB相同,一样是通过dir配置
在这里插入图片描述

AOF机制如何开启?

它是默认关闭的,在配置文件中也可以配置,配置appendonly属性
在这里插入图片描述

AOF机制如何触发?

它有三种触发机制可供选择,同样可以在配置文件中配置

  1. no:表示等操作系统进行数据缓存同步到磁盘(快,持久化没保证)
  2. always:同步持久化,每次发生数据变更时,立即记录到磁盘(慢,安全)
  3. everysec:表示每秒同步一次(默认值,很快,但可能会丢失一秒以内的数据)

配置appendfsync属性,通常选择always
在这里插入图片描述
AOF的重写机制是什么?

首先我们了解下什么时候会触发重写机制,我们同样可以在配置文件中配置

  • auto-aof-rewrite-percentage:当AOF文件增长到一定大小的时候Redis能够调用 bgrewriteaof对日志文件进行重写 。当AOF文件大小的增长率大于该配置项时自动开启重写(这里指超过原大小的100%)。

  • auto-aof-rewrite-min-size:当AOF文件增长到一定大小的时候Redis能够调用 bgrewriteaof对日志文件进行重写 。当AOF文件大小大于该配置项时自动开启重写。

在这里插入图片描述
接着我们来了解下什么是重写机制,首先我们需要知道AOF是将我们的操作日志存在aof文件中,而且只有增删改操作会存储,在触发重写机制的时候会将aof文件中的数据压缩,具体的压缩手段根据配置也有所不同,在4.0版本之前就是将存储的命令化简,简单来说就是取最终命令,比如有10个命令都是更改一个数据的值,压缩后只保留最后一次赋值的命令。

在4.0之后出现了混合持久化机制,重写机制也发生了改变,这里先不介绍,在后面介绍混合持久化机制的时候在详细分析。

什么是混合持久化机制?

4.0版本之后才出现的混合持久化机制,而且混合持久化默认关闭的,通过aof-use-rdb-preamble配置参数控制,yes则表示开启,no表示禁用,5.0之后默认开启。
在这里插入图片描述
混合持久化是通过bgrewriteaof完成的,不同的是当开启混合持久化时,fork出的子进程先将共享的内存副本全量的以RDB方式写入aof文件,然后在将重写缓冲区的增量命令以AOF方式写入到文件,写入完成后通知主进程更新统计信息,并将新的含有RDB格式和AOF格式的AOF文件替换旧的的AOF文件。

简单的说:新的AOF文件前半段是RDB格式的全量数据后半段是AOF格式的增量数据。

优点:混合持久化结合了RDB持久化 和 AOF 持久化的优点, 由于绝大部分都是RDB格式,加载速度快,同时结合AOF,增量的数据以AOF方式保存了,数据更少的丢失。

缺点:兼容性差,一旦开启了混合持久化,在4.0之前版本都不识别该aof文件,同时由于前部分是RDB格式,阅读性较差。

redis重写流程

在这里插入图片描述

redis启动加载持久化文件流程

在这里插入图片描述

总结

  • 优化数据丢失问题,rdb会丢失最后一次快照后的数据,aof丢失不会超过2秒的数据
  • 如果rbd和aof同时存在以aof优先

两者对比

  • rdb适合大规模的数据恢复,对数据完整性和一致性不高 , 在一定间隔时间做一次备份,如果redis意外down机的话,就会丢失最后一次快照后的所有操作
  • aof根据配置项而定

性能建议(单机版)

因为RDB文件只用作后备用途,只要15分钟备份一次就够了,只保留save 900 1这条规则。

如果Enalbe AOF,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自己的AOF文件就可以了。

代价一是带来了持续的IO,二是AOF rewrite的最后将rewrite过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。

只要硬盘许可,应该尽量减少AOF rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上。默认超过原大小100%大小时重写可以改到适当的数值。

redis客户端访问流程(单机版)

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值