Redis入门使用

1 Redis

1.1 简介

1.1.1 NoSQL 简介

目前市场主流数据存储都是使用关系型数据库。每次操作关系型数据库时都是I/O操作,I/O操作是主要影响程序执行性能原因之一,连接数据库关闭数据库都是消耗性能的过程。尽量减少对数据库的操作能够明显的提升程序运行效率

针对上面的问题,市场上就出现了各种 NoSQL(Not Only SQL,不仅仅可以使用关系型数据库)数据库,它们的宣传口号:不是什么样的场景都必须使用关系型数据库,一些特定的场景使用 NoSQL 数据库更好。

常见 NoSQL 数据库:

memcached :键值对,内存型数据库,所有数据都在内存中。

Redis:和Memcached类似,还具备持久化能力。

HBase:以列作为存储。

MongoDB:以Document做存储。

1.1.2 Redis简介

Redis 是以 Key-Value 形式进行存储的 NoSQL 数据库。

Redis 是使用 C 语言进行编写的。

平时操作的数据都在内存中,效率特高,读的效率 110000/s,写 81000/s,所以多把 Redis 当做缓存工具使用

Redis以 solt(槽)作为数据存储单元,每个槽中可以存储 N 多个键值对。Redis中固定具有16384。理论上可以实现一个槽是一个Redis。每个向Redis存储数据的 key 都会进行 crc16 算法得出一个值后对 16384 取余就是这个 key 存放的 solt 位置。

同时通过 Redis Sentinel 提供高可用,通过 Redis Cluster 提供自动分区

1.2 Redis 单机版安装

1 安装 C 语言依赖

# yum install -y gcc-c++ automake autoconf libtool make tcl 

进行编译

# make

2 解压 redis 安装包

# tar -xzvf redis-5.0.5.tar.gz

到解压目录下进行编译

# make

安装

# make install PREFIX=/usr/local/redis

3 修改配置

拷贝 解压包下的 redis.conf 到 redis 的安装目录下

# cp reids.conf /usr/local/redis

编辑 redis.conf

# cd /usr/local/redis/bin
# vim redis-conf

修改 daemonize 的值由 yes 开启守护进程
注释 bind 127.0.0.1
修改 protected-mode 的值为 no

4 启动测试

# ./redis-server redis.conf

启动客户端命令

# ./redis-cli

1.3 Redis 常用命令

redis 以 key-value 的方式存储数据
key 为 String 类型
value 有以下五种类型
String 字符串类型
Hash 哈希表
List 列表
Set 集合
Sorted Set 有序集合

1.3.1 key 操作

判断 key 是否存在 存在返回数字,不存在返回 0

# exists [key]

20201212170952285.png

exprie :设置 key 的过期时间 成功则返回 1 不成功则返回 0

ttl:查看 key 剩余生存时间 time to live

# expire [key] [seconds]

20201212173325274

删除 key

# del [key]

20201212173804206

查看当前 redis 中 key 数据

# keys [pattern]
# keys *

20201212174320854

查看 key 对应的 value 类型

# type [key]

20201212185237856

1.3.2 字符串值操作

set : 设置指定 key 的值

get : 查询指定 key 的值

# set [key] [value]
# get [key]

20201212170343750

setnx : 当且仅当 key 不存在的时候新增 SET IF NOT EXISTS

# setnx [key] [value]

20201212190311672

setex : 是一个原子性操作,为指定的 key 设置值和过期时间

# setex [key] [seconds] [value] 

20201212194630313

incr : 用于 value 值的递增,默认步长为 1

decr : 用于 value 值的递减,默认步长为 1

redis 是单线程的,不会存在并发(业务:评论数点赞数)

# incr [key]
# decr [key]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YbBEc0EX-1624767035609)(E:\Java\img\image-20201212191813316.png)]

1.3.3 hash 值操作

设置 value 值

# hset [key] [field] [value]

20201212191813316

# hset [key] [field] [value] [field] [value] [field] [value] ...

20201212200109769

获取 value 值

# hget [key] [value]
# hvals [key]

20201212200224269

获取 value 中的 field 字段名以及对应的值

# hgetall [key]

20201212200334031

删除 value 中的字段以及其对应的值

# hdel [key] [field] [field]

20201212203339922

1.3.4 list 值操作

在指定 key 的值列表末尾添加值

# rpush [key] [value] [value] ...

从左到右遍历指定 key 的 value 值

// -1 表示到末尾
# lrange [key] [start] [end]

20201212204932156

在列表的前面添加值

# lpush [key] [value] [value]

20201212205050868

获取列表长度

# llen [key]

20201212205203469

**从左到右删除指定的 value ,count 表示个数 **

正整数表示从左到右删除的个数 负整数表示从右到左

# lrem [key] [count] [value]

20201212210033359

1.3.5 集合(set)操作

sadd
向集合中添加内容。不允许重复。
语法:sadd key value value value
返回值:本次命令新增数据个数
scard
返回集合元素数量
scard key
返回值:集合长度
smembers 
查看集合中元素内容
语法:smembers key
返回值:集合中元素
srem
删除集合中的元素
语法: srem key member [member...]
返回值:删除元素个数
sinter
获取多个集合的交集
语法: sinter key [key ...]
返回:多个集合的交集元素

1.3.6 有序集合(Sorted Set)操作

127.0.0.1:6379> select 2
OK
127.0.0.1:6379[2]> zadd names 1.0 cl 2.0 ky 2.1 cc
(integer) 3
127.0.0.1:6379[2]> ZRANGE names 0 2
1) "cl"
2) "ky"
3) "cc"
127.0.0.1:6379[2]> ZRANGE names 0 2 withscores
1) "cl"
2) "1"
3) "ky"
4) "2"
5) "cc"
6) "2.1000000000000001"
127.0.0.1:6379[2]> zrem names cl
(integer) 1
127.0.0.1:6379[2]> keys *
1) "names"
127.0.0.1:6379[2]> ZRANGE names 0 -1
1) "ky"
2) "cc"
127.0.0.1:6379[2]> 

1.4 Redis 持久化策略

1.4.1 RDB

RDB redis database 一种基于内存快照的持久化策略

RDB 模式是默认模式,可以在指定的时间间隔内生成数据快照(snapshot),

默认保存到dump.rdb文件中,

当redis重启后会自动加载dump.rdb文件中内容到内存中。

用户可以使用SAVE(同步)或BGSAVE(异步)手动保存数据。

可以设置服务器配置的save选项,让服务器每隔一段时间自动执行一次BGSAVE命令。

优点
RDB 文件是一个紧凑文件,直接使用 RDB 文件就可以还原数据。
数据保存会一个子进程进行保存,不影响父进程。
恢复数据的效率要高于 AOF
缺点
每次保存点之间,因 redis 不可意料的关闭,可能会导致丢失数据。
由于每次保存数据都需要 fork() 子进程,在数据量比较大时可能会比较耗费性能(可忽略)。

默认配置文件:

20201225130843195

查看 dump.rdb:

[root@localhost ~]# cd /usr/local/redis/bin/
[root@localhost bin]# ls -a
.   dump.rdb         redis-check-aof  redis-cli   redis-sentinel
..  redis-benchmark  redis-check-rdb  redis.conf  redis-server
[root@localhost bin]# vim dump.rdb
[root@localhost bin]# 

20201225125939114

1.4.2 AOF

AOF append only file 一种基于操作日志的持久化策略

AOF默认是关闭的,需要在配置文件中开启AOF。Redis支持AOF和RDB同时生效,如果同时存在,

AOF优先级高于RDB(Redis重新启动时会使用AOF进行数据恢复)

监听执行的命令,如果发现执行了修改数据的操作,同时直接同步到数据库文件中。

AOP类似日志型的持久化,数据库key发生改变马上同步磁盘

20201225131255661

优点
相对RDB数据更加安全。
不会造成数据丢失
缺点
相同数据集AOF要大于RDB。
相对RDB可能会慢一些。

1.5 Redis 主从复制

Redis 主从复制功能保证了单一节点可用性,每一个节点都有 N 个复制品(replica)

其中一个是主节点(master) 其他的节点都是从节点,实现一主多从。

(每一个从节点可以看成又一个主节点)

1.5.1 主从优点

  1. 增加单一节点的健壮性,从而提升整个集群的稳定性。(Redis中当超过1/2节点不可用时,整个集群不可用)
  2. 从节点可以对主节点数据备份,提升容灾能力。
  3. 读写分离。在redis主从中,主节点一般用作写(具备读的能力),从节点只能读,利用这个特性实现读写分离,写用主,读用从。

1.5.2 搭建主从复制

1.5.2.1 创建目录
[root@localhost ~]# mkdir /usr/local/replica
[root@localhost ~]# cd /usr/local/replica/
[root@localhost replica]# pwd
/usr/local/replica
1.5.2.2 从 redis 单机中复制 bin 目录下的配置文件
[root@localhost redis]# cp -r bin /usr/local/replica/master
[root@localhost redis]# cp -r bin /usr/local/replica/slave1
[root@localhost redis]# cp -r bin /usr/local/replica/slave2
1.5.2.3 修改各个从节点的配置文件
[root@localhost redis]# vim /usr/local/replica/slave1/redis.conf 
[root@localhost redis]# vim /usr/local/replica/slave2/redis.conf 

在从节点中指定自己的端口以及主节点的 ip 和端口

port 6380

replicaof 192.168.72.12 6379

1.5.2.4 启动三个 redis 实例

添加 .sh 脚本启动实例

cd /usr/local/replica/master

./redis-server redis.conf

cd /usr/local/replica/slave1

./redis-server redis.conf

cd /usr/local/replica/slave2

./redis-server redis.conf

[root@localhost replica]# vim startup.sh
# 修改 startup.sh 权限
[root@localhost replica]# chmod u+x startup.sh 
# 执行 startup.sh 
[root@localhost replica]# ./startup.sh 

1.5.3 测试

1.5.3.1 查看 redis 启动进程
# 查看 redis 启动进程
[root@localhost master]# ps -aux | grep redis
root        1523  0.1  0.8 273296 15872 ?        Ssl  22:04   0:00 ./redis-server *:6379
root        1535  0.1  0.5 269200  9588 ?        Ssl  22:07   0:00 ./redis-server *:6380
root        1540  0.1  0.9 273296 17880 ?        Ssl  22:07   0:00 ./redis-server *:6381
root        1577  0.0  0.0 221904  1084 pts/0    S+   22:16   0:00 grep --color=auto redis
1.5.3.2 数据演示
# 只有主节点能进行读写
# 从节点只读
[root@localhost master]# ./redis-cli -p 6380
127.0.0.1:6380> keys *
1) "age"
2) "password"
3) "username"
127.0.0.1:6380> set phone 12345678910
OK
127.0.0.1:6380> 
[root@localhost master]# ./redis-cli -p 6379
127.0.0.1:6379> set id 416240304
(error) READONLY You can't write against a read only replica.
127.0.0.1:6379> 
[root@localhost master]# ./redis-cli -p 6381
127.0.0.1:6381> set id 416240304
(error) READONLY You can't write against a read only replica.
127.0.0.1:6381> 

1.5.4 主从复制总结

1、主节点可以进行读写操作,单数据变化时自动将数据同步到从节点
2、从节点是只读的
3、一个主节点可以拥有多个从节点,但一个从节点只能对应一个主节点
4、从节点宕机不影响其他从节点以及主节点的读写
5、主节点宕机,不影响从节点的读,但是整个节点不具备写功能

1.6 哨兵

redis 中默认只有主节点具备写的能力,假设主节点宕机,那么整个节点不具备写的能力。

Redis的哨兵可以帮助监控整个节点,当主节点宕机等情况下,帮助重新选取主节点。

Redis中哨兵支持单哨兵和多哨兵:

单哨兵:只要哨兵发现主节点宕机了,就直接选取另一个 从节点作为主节点。

多哨兵:根据我们设定,达到一定数量哨兵认为主节点宕机后才会进行重新选取主节点

1.6.1 搭建多哨兵

# 新建哨兵目录
[root@localhost ~]# mkdir /usr/local/sentinel
 
# 复制 redis 配置文件 到 sentinel 目录下
[root@localhost sentinel]# cp -r /usr/local/redis/bin/* /usr/local/sentine

# 复制 sentinel.conf 到 sentinel 目录下
[root@localhost sentinel]# cd /usr/local/tmp/redis-5.0.5/
[root@localhost redis-5.0.5]# cp sentinel.conf /usr/local/sentinel/
[root@localhost redis-5.0.5]# cd /usr/local/sentinel/
[root@localhost sentinel]# mv sentinel.conf sentinel-6379.conf 
# 修改 sentinel-6379.conf 文件 配置其中的port(6379)、 daemonize(yes)、 sentinel monitor mymaster 192.168.72.12 6379 2
[root@localhost sentinel]# vim sentinel-6379.conf
[root@localhost sentinel]# cp sentinel-6379.conf sentinel-6380.conf 
[root@localhost sentinel]# vim sentinel-6380.conf
[root@localhost sentinel]# cp sentinel-6379.conf sentinel-6381.conf 
[root@localhost sentinel]# vim sentinel-6381.conf
# 编写脚本启动命令
[root@localhost sentinel]# vim startup.sh
# 设置 startup.sh 权限
[root@localhost sentinel]# chmod u+x startup.sh 
# 启动所有哨兵
[root@localhost sentinel]# ./startup.sh 
1700:X 26 Dec 2020 15:20:15.730 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1700:X 26 Dec 2020 15:20:15.730 # Redis version=5.0.5, bits=64, commit=00000000, modified=0, pid=1700, just started
1700:X 26 Dec 2020 15:20:15.730 # Configuration loaded
1702:X 26 Dec 2020 15:20:15.733 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1702:X 26 Dec 2020 15:20:15.733 # Redis version=5.0.5, bits=64, commit=00000000, modified=0, pid=1702, just started
1702:X 26 Dec 2020 15:20:15.733 # Configuration loaded
1707:X 26 Dec 2020 15:20:15.738 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1707:X 26 Dec 2020 15:20:15.738 # Redis version=5.0.5, bits=64, commit=00000000, modified=0, pid=1707, just started
1707:X 26 Dec 2020 15:20:15.738 # Configuration loaded
[root@localhost sentinel]# 

1.6.2 启动主从

[root@localhost master]# ./redis-cli
127.0.0.1:6379> keys *
1) "username"
127.0.0.1:6379> set password 12345
OK
127.0.0.1:6379> keys *
1) "username"
2) "password"
127.0.0.1:6379> 
[root@localhost master]# ./redis-cli -p 6380
127.0.0.1:6380> set age 12
(error) READONLY You can't write against a read only replica.
127.0.0.1:6380> 
[root@localhost master]# ./redis-cli -p 6381
127.0.0.1:6381> set age 12
(error) READONLY You can't write against a read only replica.
127.0.0.1:6381> 

1.6.3 测试哨兵

# 关闭端口为 6839 的主节点
[root@localhost master]# ./redis-cli shutdown
# 查看 redis 实例启动状态
[root@localhost master]# ps -aux | grep redis
[root@localhost master]# ./redis-cli -p 6380
127.0.0.1:6380> set age 12
OK
127.0.0.1:6380> keys *
1) "age"
2) "username"
3) "password"
127.0.0.1:6380> 
[root@localhost master]# ./redis-cli -p 6381
127.0.0.1:6381> set phone 12345678919
(error) READONLY You can't write against a read only replica.
127.0.0.1:6381> 
# 重新启动端口为 6379 的节点
[root@localhost master]# ./redis-server redis.conf 
1783:C 26 Dec 2020 15:47:19.758 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
1783:C 26 Dec 2020 15:47:19.758 # Redis version=5.0.5, bits=64, commit=00000000, modified=0, pid=1783, just started
1783:C 26 Dec 2020 15:47:19.758 # Configuration loaded
[root@localhost master]# ./redis-cli -p 6379
# 节点角色变为从节点
127.0.0.1:6379> role
1) "slave"
2) "192.168.72.12"
3) (integer) 6380
4) "connect"
5) (integer) -1
127.0.0.1:6379> 
[root@localhost master]# ./redis-cli -p 6380
127.0.0.1:6380> role
1) "master"
2) (integer) 340199
3) 1) 1) "192.168.72.12"
      2) "6381"
      3) "340058"
   2) 1) "192.168.72.12"
      2) "6379"
      3) "340199"
127.0.0.1:6380> 
[root@localhost master]# ./redis-cli -p 6381
127.0.0.1:6381> role
1) "slave"
2) "192.168.72.12"
3) (integer) 6380
4) "connected"
5) (integer) 341905
127.0.0.1:6381> 

1.7 集群(cluster)

1.7.1 复制 redis 单机版中的配置文件

[root@localhost bin]# cp /usr/local/redis/bin/redis.conf /usr/local/redis/bin/redis-7001.conf

1.7.2 修改 redis-7001.conf

port 7001

cluster-enabled yes

cluster-config-file nodes-7001.conf

cluster-node-timeout 15000

appendonly yes

daemonize yes

protected-mode no

pidfile /var/run/redis_7001.pid

1.7.3 复制多份配置文件并修改内容

20201227224500849

1.7.4 编辑脚本命令启动6个 redis

1.7.5 建立集群

./redis-cli --cluster create 192.168.72.12:7001 192.168.72.12:7002 192.168.72.12:7003 192.168.72.12:7004 192.168.72.12:7005 192.168.72.12:7006
--cluster-replicas 1

1.7.6 集群测试

# 启动端口为 7001 的客户端
[root@localhost bin]# ./redis-cli -p 7001 -c
127.0.0.1:7001> keys *
(empty list or set)
# 分配的槽位 14315 在 端口为 7003 的 redis 的服务器上 自动跳转到对应服务器
127.0.0.1:7001> set username cl
-> Redirected to slot [14315] located at 192.168.72.12:7003
OK
192.168.72.12:7003> keys *
1) "username"
192.168.72.12:7003> get username
"cl"
192.168.72.12:7003> set password 1234
-> Redirected to slot [9540] located at 192.168.72.12:7002
OK
192.168.72.12:7002> keys *
1) "password"
192.168.72.12:7002> set age 12
-> Redirected to slot [741] located at 192.168.72.12:7001
OK
192.168.72.12:7001> keys *
1) "age"
192.168.72.12:7001> info replication
# Replication
role:master
connected_slaves:1
slave0:ip=192.168.72.12,port=7005,state=online,offset=1663,lag=0
master_replid:9ce824bf758c4496086a700ad5c9c9f62f7db393
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:1663
second_repl_offset:-1
repl_backlog_active:1
repl_backlog_size:1048576
repl_backlog_first_byte_offset:1
repl_backlog_histlen:1663
192.168.72.12:7001> info cluster
# Cluster
cluster_enabled:1 

1.8 SpringBoot 整合 Redis

1.8.1 添加依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

1.8.2 在 classpath 目录下编写配置文件

# 配置单机 redis
# spring:
#   redis:
#   host: 192.168.72.12
#  端口默认 6379
#   port: 6379


# 配置集群环境
spring:
  redis:
    cluster:
      nodes: 192.168.72.12:7001,192.168.72.12:7002,192.168.72.12:7003,192.168.72.12:7004,192.168.72.12:7005,192.168.72.12:7006

1.8.3 编写配置类

package com.cl.redis.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * @Author chenlan
 * @Description TODO
 * @Date 2020/12/27 11:56
 * @Version 1.0
 */

@Configuration
public class RedisConfig {
    @Bean
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){
        RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(factory);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<Object>(Object.class));
        return redisTemplate;
    }
    
}

1.8.4 编写代码

package com.cl.redis;

import com.cl.redis.pojo.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author chenlan
 * @Description TODO
 * @Date 2020/12/27 12:10
 * @Version 1.0
 */
@SpringBootTest
@RunWith(SpringRunner.class)
public class SpringData4RedisTest {
    @Autowired
    private RedisTemplate redisTemplate;


    @Test
    public void testObject(){
        ValueOperations vos = redisTemplate.opsForValue();

        // 编写值序列化器
        // 不指定时会有异常 java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.cl.redis.pojo.User
        redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<User>(User.class));
        vos.set("cl", new User("cl","12"));
        User cl = (User) vos.get("cl");
        System.out.println(cl);

    }

    // 测试 list 类型
    @Test
    public void testList(){
        ValueOperations vos = redisTemplate.opsForValue();

        redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<List>(List.class));
        List<User> users = new ArrayList<>();
        users.add(new User("cl","12"));
        users.add(new User("ky","12"));
        vos.set("users",users);
        List<User> list = (List<User>) vos.get("users");
        System.out.println(list);
    }

}

1.9 使用 Redis

  1. 先判断缓存中是否存在。如果存在直接从缓存中取出数据。不执行2,3步骤
  2. 如果不存在,从mysql中获取数据
  3. 获取数据后,把数据缓存到redis中
    20201227175411615
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值