阶段十-分布式-Redis01

2024-01-07 23:28:21

第一章 Redis入门

1.1 节 什么是NoSql型数据库

?NoSQL ,泛指非关系型的数据库, NoSQL Not Only SQL,它可以作为关系型数据库的良好补充。 NoSQL 不依赖业务逻辑方式存储,而以简单的key-value模式存储。因此大大的增加了数据库的扩展能力。NoSQL与SQL数据库区别对比如下:

SQLNoSQL
数据结构结构化非结构化
数据关联关联的无关联的
查询方式SQL查询非SQL查询
事务特征ACIDBASE
存储方式磁盘内存
扩展性垂直水平
使用场景数据结构固定;相关业务对数据安全性、一致性要求较高数据结构不固定;对一致性,安全性要求不高,对性能要求高

常见NoSQL数据库:

  • Reids (键值对)

  • MongoDB(文档类型)

  • HBase (列类型)

  • Neo4j(Graph类型)

1.2 节 Reids介绍

Redis诞生于2009年全称是Remote Dictionary Server,远程词典服务器,是一个基于内存的键值型NoSQL数据库。其主要特征如下:

  • 键值(key-value)型,value支持多种不同数据结构,功能丰富;

  • 单线程,每个命令具备原子性;

  • 低延迟,速度快(基于内存、IO多路复用、良好的编码);

  • 支持数据持久化;

  • 支持主从集群、分片集群;

  • 支持多语言客户端;

1.3?节 Reids 安装

需要的文件

链接:https://pan.baidu.com/s/10o9t5OOX2A4s98vnFnJwmA?pwd=rxtc?
提取码:rxtc

基于Linux服务器来部署项目

1.4.1 Redis安装

【1】依赖库,Redis是基于C语言编写的,因此首先需要安装Redis所需要的gcc依赖:

yum install -y gcc tcl

【2】上传安装包并解压,然后将资料提供的Redis安装包上传到虚拟机的/usr/local/目录

【3】解压缩:

tar -xzf redis-6.2.6.tar.gz

【4】进入redis目录:

cd redis-6.2.6

【5】运行编译命令:

make && make install

默认的安装路径是在 /usr/local/bin目录下:该目录已经默认配置到环境变量,因此可以在任意目录下运行这些命令。其中:

  • redis-cli:是redis提供的命令行客户端

  • redis-server:是redis的服务端启动脚本

  • redis-sentinel:是redis的哨兵启动脚本

redis的启动方式有很多种,例如:

  • 默认启动

  • 指定配置启动

  • 开机自启

1.4.2 默认启动

安装完成后,在任意目录输入redis-server命令即可启动Redis:

redis-server

这种启动属于前台启动,会阻塞整个会话窗口,窗口关闭或者按下CTRL + C则Redis停止。不推荐使用。

1.4.3 指定配置启动

如果要让Redis以后台方式启动,则必须修改Redis配置文件,就在我们之前解压的redis安装包下(/usr/local/redis-6.2.6),名字叫redis.conf:

我们先将这个配置文件备份一份:

cp redis.conf redis.conf.bck

修改redis.conf文件中的一些配置:

# 允许访问的地址,默认是127.0.0.1,会导致只能在本地访问。修改为0.0.0.0则可以在任意IP访问,生产环境不要设置为0.0.0.0
bind 0.0.0.0
# 守护进程,修改为yes后即可后台运行
daemonize yes 
# 密码,设置后访问Redis必须输入密码
# requirepass 123456

Redis的其它常见配置:

# 监听的端口
port 6379
# 工作目录,默认是当前目录,也就是运行redis-server时的命令,日志、持久化等文件会保存在这个目录
dir .
# 数据库数量,设置为1,代表只使用1个库,默认有16个库,编号0~15
databases 16
# 设置redis能够使用的最大内存
maxmemory 512mb
# 日志文件,默认为空,不记录日志,可以指定日志文件名
logfile "redis.log"

启动Redis:

# 进入redis安装目录 
cd /usr/local/redis-6.2.6
# 启动
redis-server redis.conf

停止服务:

# 利用redis-cli来执行 shutdown 命令,即可停止 Redis 服务,
# 因为之前配置了密码,因此需要通过 -u 来指定密码
redis-cli -u 123456 shutdown

1.4.4 开机自启

我们也可以通过配置来实现开机自启。

首先,新建一个系统服务文件:

vi /etc/systemd/system/redis.service

内容如下:

[Unit]
Description=redis-server
After=network.target

[Service]
Type=forking
ExecStart=/usr/local/bin/redis-server /usr/local/redis-6.2.6/redis.conf
PrivateTmp=true

[Install]
WantedBy=multi-user.target

然后重载系统服务:

systemctl daemon-reload

现在,我们可以用下面这组命令来操作redis了:

# 启动
systemctl start redis
# 停止
systemctl stop redis
# 重启
systemctl restart redis
# 查看状态
systemctl status redis

执行下面的命令,可以让redis开机自启:

systemctl enable redis

1.5 节 Redis 基于Docker安装

【1】下载镜像

docker pull redis:6.2.6

【2】运行容器

docker run --name redis -d -p 6379:6379 redis:6.2.6

1.6 节 Redis桌面客户端

安装完成Redis,我们就可以操作Redis,实现数据的CRUD了。这需要用到Redis客户端,包括:

  • 命令行客户端

  • 图形化桌面客户端

  • 编程客户端

1.6.1 Redis命令行客户端

Redis安装完成后就自带了命令行客户端:redis-cli,

redis-cli [options] [commonds]

其中常见的options有:

  • -h 127.0.0.1:指定要连接的redis节点的IP地址,默认是127.0.0.1

  • -p 6379:指定要连接的redis节点的端口,默认是6379

  • -a 123456:指定redis的访问密码

其中的commonds就是Redis的操作命令,例如:

  • ping:与redis服务端做心跳测试,服务端正常会返回pong

不指定commond时,会进入redis-cli的交互控制台

1.6.2 图形化桌面客户端

【1】在资料中可以找到Redis的图形化桌面客户端:

【2】解压缩后,运行安装程序即可安装:

【3】安装完成后,在安装目录下找到rdm.exe文件:

【4】建立连接,点击左上角的连接到Redis服务器按钮:

【5】在弹出的窗口中填写Redis服务信息:

Redis默认有16个仓库,编号从0至15. 通过配置文件可以设置仓库数量,但是不超过16,并且不能自定义仓库名称。如果是基于redis-cli连接Redis服务,可以通过select命令来选择数据库 ?

# 选择 0号库
select 0

第二章 Redis基本知识

2.1 节 Reids 多路复用

在Redis6/7中,非常受关注的第一个新特性就是多线程。

这是因为,Redis一直被大家熟知的就是它的单线程架构(Redis6以前是单线程架构),虽然有些命令操作可以用后台线程或子进程执行(比如数据删除、快照生成、AOF重写)。但是,从网络IO处理到实际的读写命令处理,都是由单个线程完成的。

随着网络硬件的性能提升,Redis的性能瓶颈有时会出现在网络IO的处理,也就是说,单个主线程处理网络请求的速度跟不上底层网络硬件的速度,

为了应对这个问题:

采用多个IO线程来处理网络请求,提高网络请求处理的并行度,Redis6/7就是采用的这种方法。

但是,Redis的多线程只是用来处理网络请求的,对于读写操作命令Redis仍然使用单线程来处理。这是因为,Redis处理请求时,网络处理经常是瓶颈,通过多个IO线程并行处理网络操作,可以提升实例的整体处理性能。而继续使用单线程执行命令操作,就不用为了保证Lua脚本、事务的原子性,额外开发多线程互斥加锁机制了(不管加锁操作处理),这样一来,Redis线程模型实现就简单了

2.2 节 Redis 默认16 库

Redis是一个字典结构的存储服务器,一个Redis实例提供了多个用来存储数据的字典,客户端可以指定将数据存储在哪个字典中。 这与在一个关系数据库实例中可以创建多个数据库类似(如下图所示),所以可以将其中的每个字典都理解成一个独立的数据库。

Redis默认支持16个数据库,可以通过调整Redis的配置文件redis/redis.conf中的databases来修改这一个值,设置完毕后重启Redis便完成配置。

2.2.1 切换数据库

语法结构:

select number

示例:

127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> get k1
"v1"
# 切换数据库,获取不到k1数据
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> get k1
(nil)?

2.2.2 清空当前库

Redis Flushdb 命令用于清空当前数据库中的所有 key。

语法结构:

127.0.0.1:6379> FLUSHDB

2.2.3 通杀全部库

Redis Flushall 命令用于清空整个 Redis 服务器的数据(删除所有数据库的所有 key )。

语法结构:

redis 127.0.0.1:6379> FLUSHALL

2.3 节 Redis数据类型_key键

2.3.1 keys

查看当前库中所有的key 。

语法结构:

keys *

有3个通配符 *, ? ,[]

  • *: 通配任意多个字符

  • ?: 通配单个字符

  • []: 通配括号内的某1个字符

注意: 生产已经禁止。因为长时间阻塞redis而导致其他客户端的命令请求一直处于阻塞状态。 更安全的做法是采用scan。

新版本也进行了替代:

redis-cli -h 127.0.0.1 -p 6379 -a 123456 --scan "*"

2.3.2 exists

判断某个key是否存在,返回1表示存在,0不存在。

语法结构:

exists key
#查看k1是否存在,如果存在返回1
exists k1 ?
# 查看k1 k2 k3是否存在,如果k1 k2存在,k3不存在,则返回2
exists k1 k2 k3

注意: 可以设置多个key,只返回存在的个数,但不返回哪一个存在/不存在。

2.3.3 type

查看当前key 所储存的值的类型。返回当前key所储存的值的类型, 如string 、list等。

语法结构:

type key

2.3.3 del

删除已存在的key,不存在的 key 会被忽略。

语法结构:

del key

示例:

可以设置多个key,返回删除成功的个数。

# 删除k1,如果成功返回1,失败返回0
del k1
# 删除k1 k2 k3,如果k1 k2存在,k3不存在,则返回2
del k1 k2 k3

2.3.4 expire

给key设置time秒的过期时间。设置成功返回 1 。 当 key 不存在返回 0。

语法结构:

expire key time

示例:

# 给k1设置10秒后过期
expire k1 10

2.3.4 ttl

以秒为单位返回 key 的剩余过期时间。

语法结构:

ttl key

注意: 当 key 不存在时,返回 -2 。 当 key 存在但没有设置剩余生存时间时,返回 -1 。 否则,以秒为单位,返回 key 的剩余生存时间。

2.3.5 persist

移除给定 key 的过期时间,使得 key 永不过期。

语法结构:

persist key

注意: 当过期时间移除成功时,返回 1 。 如果 key 不存在或 key 没有设置过期时间,返回 0 。

第三章 Redis 数据类型

3.1 节 String

3.1.1 简介

String是Redis最基本的类型,一个key对应一个value。String是二进制安全的,意味着String可以包含任何数据,比如序列化对象或者一张图片。String最多可以放512M的数据

3.1.2 常用命令

【1】set

用于设置给定 key 的值。如果 key 已经存储其他值, set 就重写旧值,且无视类型。

语法格式:

set key value

【2】get

用于获取指定 key 的值。如果 key 不存在,返回 nil 。

语法格式:

get key

【3】append

将给定的value追加到key的值的末尾。

语法格式:

append key value

注意: 如果 key 已经存在并且是一个字符串, append 命令将 value 追加到 key 原来的值的末尾。 如果 key 不存在, append 就简单地将给定 key 设为 value ,就像执行 set key value 一样。

【4】strlen

获取指定 key 所储存的字符串值的长度。当 key 储存的不是字符串值时,返回一个错误。

语法格式:

strlen key

【5】setex

给指定的 key 设置值及time 秒的过期时间。如果 key 已经存在, setex命令将会替换旧的值,并设置过期时间。

语法格式:

setex key time value

【6】setnx

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

语法格式:

setnx key value

【7】getrange

获取指定区间范围内的值,类似between........and 的关系,下标的起始与结束

语法格式:

getrange key start end

【8】setrange

设置指定区间范围内的值,类似between........and 的关系,下标的起始与结束

语法结构:

setrange key offset value

【9】incr

将 key 中储存的数字值增一。

语法格式:

incr key

注意: 如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 incr 操作。 如字符串类型的值不能表示为数字、或者是其他类型,那么返回一个错误。

【10】decr

将 key 中储存的数字值减一。

语法格式:

decr key

注意:

如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 decr 操作。 如字符串类型的值不能表示为数字、或者是其他类型,那么返回一个错误。

【11】incrby/decrby key step

将key存储的数字值按照step进行增减。

语法格式:

incrby/decrby key 步长

注意:

如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 incrby/decrby 命令。 如字符串类型的值不能表示为数字、或者是其他类型,那么返回一个错误。

【12】mset

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

语法格式:

mset key1 value1 key2 value2

【13】mget

返回所有(一个或多个)给定 key 的值。

语法格式:

mget key1 key2

【14】getset

将给定key值设为value,并返回key的旧值(old value),简单一句话(先get然后立即set)。

语法格式:

getset key value

3.1.3 使用场景

value 除了是字符串以外还可以是数字。

  • 计数器

  • 统计多单位的数量

  • 粉丝数

  • 对象缓存存储

  • 分布式锁

3.2 节 List

3.2.1 简介

List是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。底层是一个双向链表, 对两端操作性能极高,通过索引操作中间的节点性能较差。

一个List最多可以包含 $2^{32}-1$个元素 ( 每个列表超过40亿个元素)。

3.2.2 常用命令

【1】lpush/rpush

从左边(头部)/右边(尾部)插入一个或多个值。

语法结构:

lpush/rpush key1 value1 value2 value3……

示例:

#从左边放入v1 v2 v3
127.0.0.1:6379> lpush k1 v1 v2 v3
(integer) 3

【2】lrange

返回key列表中的start和end之间的元素(包含start和end)。 其中 0 表示列表的第一个元素,-1表示最后一个元素。

语法结构:

lrange key start end

示例:

#取出列表里前3个值,结果为v3 v2 v1
127.0.0.1:6379> lrange k1 0 2
#取出列表里全部值,结果为v3 v2 v1 v4 v5 v6
127.0.0.1:6379> lrange k1 0 -1

【3】lpop/rpop

移除并返回第一个值或最后一个值。

语法格式:

lpop/rpop key

示例:

# lpop k1 从列表中删除v3,并返回,当前列表全部值v2 v1 v4 v5 v6
127.0.0.1:6379> lpop k1
"v3"

# rpop k1 从列表中删除v6,并返回,当前列表全部值v2 v1 v4 v5
127.0.0.1:6379> rpop k1
"v6"

注意:

值在键在,值光键亡

【4】lindex

获取列表index位置的值(从左开始)。

语法结构:

lindex key index

【5】llen

获取列表长度。

语法结构:

llen key

【6】lrem

从左边开始删除与value相同的count个元素。

语法结构:

lrem key count value

示例:

#从左边开始删除k1列表中2个v1元素
lrem k1 2 v1

【7】linsert

在列表中value值的前边/后边插入一个new value值(从左开始)。

语法结构:

linsert key before/after value newvalue

示例:

#  在v1前面插入一个v5
linsert k1 before v1 v5

【8】lset

将索引为index的值设置为value

语法结构:

lset key index value

3.2.3 使用场景

  • 消息队列

  • 排行榜

  • 最新列表

3.3 节 Set

3.3.1 简介

与List类似是一个列表功能,但Set是自动去重的,当需要存储一个列表数据,又不希望出现重复数据时,Set是一个很好的选择。 Set是String类型的无序集合,它底层其实是一个value为null的hash表,所以添加、删除、查找的时间复杂度都是O(1)。

【1】sadd

将一个或多个元素添加到集合key中,已经存在的元素将被忽略。

语法结构:

sadd key value1 value2……

【2】smembers

取出该集合的所有元素。

语法结构:

smembers key

【3】sismember

判断集合key中是否含有value元素,如有返回1,否则返回0。

语法结构:

sismember key value

【4】scard

返回该集合的元素个数。

语法结构:

scard key

【5】srem

删除集合中的一个或多个成员元素,不存在的成员元素会被忽略。

语法结构:

srem key value1 value2……

【6】spop

随机删除集合中一个元素并返回该元素。

语法结构:

spop key

【7】srandmember

随机取出集合中count个元素,但不会删除。

语法结构:

srandmember key count

【8】smove

将value元素从sourcekey集合移动到destinationkey集合中。

语法结构:

smove sourcekey destinationkey value

注意:

如果 sourcekey集合不存在或不包含指定的 value元素,则smove 命令不执行任何操作,仅返回 0 。

【9】sinter

返回两个集合的交集元素。

语法结构:

sinter key1 key2

【10】sunion

返回两个集合的并集元素。

语法结构:

sunion key1 key2

【11】sdiff

返回两个集合的差集元素(key1中的,不包含key2)

语法结构:

sdiff key1 key2

3.3.3 使用场景

  • 黑白名单

  • 随机展示

  • 好友

  • 关注人

  • 粉丝

  • 感兴趣的人集合

3.4 节 Hash

3.4.2 常用命令

【1】hset

给key集合中的field赋值value。

语法结构:

hset key field value

注意:

如果哈希表不存在,一个新的哈希表被创建并进行 HSET 操作。

如果字段已经存在于哈希表中,旧值将被重写。

【2】hget

从key哈希中,取出field字段的值。

语法结构:

hget key field

【3】hmset

批量设置哈希的字段及值。

语法结构:

hmset key field1 value1 field2 value2……

【4】hexists

判断指定key中是否存在field

语法结构:

hexists key field

【5】hkeys

获取该哈希中所有的field。

语法结构:

hkeys key

【6】hvals key

获取该哈希中所有的value。

语法结构

hvals key

【7】hincrby

为哈希表key中的field字段的值加上增量increment。

语法结构:

hincrby key field increment

注意:

  • 增量也可以为负数,相当于对指定字段进行减法操作。

  • 如果哈希表的 key 不存在,一个新的哈希表被创建并执行 hincrby 命令。

  • 如果指定的字段不存在,那么在执行命令前,字段的值被初始化为 0 。

  • 对一个储存字符串值的字段执行 hincrby 命令将造成一个错误。

【8】hdel

删除哈希表 key 中的一个或多个指定字段,不存在的字段将被忽略。

语法结构:

hdel key field1 field2……

【9】hsetnx

给key哈希表中不存在的的字段赋值 。

语法结构:

hsetnx key field value

3.4.3 使用场景

  • 购物车

  • 存储对象

3.5 节 Zset

3.5.1 简介

Zset与Set非常相似,是一个没有重复元素的String集合。不同之处是Zset的每个元素都关联了一个分数(score),这个分数被用来按照从低分到高分的方式排序集合中的元素。集合的元素是唯一的, 但分数可以重复。有顺序的Set

注意:

因为元素是有序的,所以可以根据分数(score)或者次序(position)来获取一个范围内的元素。

3.5.2 常用命令

【1】zadd

将一个或多个元素(value)及分数(score)加入到有序集key中。

语法结构:

zadd key score1 value1 score2 value2……

示例:

zadd k1 100 java 200 c++ 300 python 400 php

注意:

  • 如果某个元素已经是有序集的元素,那么更新这个元素的分数值,并通过重新插入这个元素,来保证该元素在正确的位置上。

  • 分数值可以是整数值或双精度浮点数。

  • 如果有序集合 key 不存在,则创建一个空的有序集并执行 zadd 操作。

【2】zrange

返回key集合中的索引start和索引end之间的元素(包含start和end)。

语法结构:

zrange key start end [withscores]

示例:

zrange k1 0 -1 返回集合中所有元素
zrange k1 0 -1 withscores 返回集合中所有元素,并携带元素分数

注意:

  • 其中元素的位置按分数值递增(从小到大)来排序。 其中 0 表示列表的第一个元素,-1表示最后一个元素。

  • withscores是可选参数,是否返回分数。

【3】zrangebyscore

返回key集合中的分数minscore 和分数maxscore 之间的元素(包含minscore 和maxscore )。其中元素的位置按分数值递增(从小到大)来排序。

语法结构:

zrangebyscore key minscore maxscore [withscores]

示例:

zrangebyscore k1 200 400 返回200-400分之间的元素递增排序

【4】zincrby

为元素value的score加上increment的值。

语法结构:

zincrby key increment value

示例:

zincrby k1 50 java 给java元素加上50分

【5】zrem

删除该集合下value的元素。

语法结构

zrem k1 php 删除php

【6】zcount

统计该集合在minscore 到maxscore分数区间中元素的个数。

语法结构:

zcount key minscore maxscore

示例:

zcount k1 100 300 统计100分到300分中间元素的个数

【7】zrank

返回value在集合中的排名,从0开始。

语法结构:

zrank key value

示例:

zrank k1 c++ 返回c++排名

3.5.3 使用场景

  • 延时队列

  • 排行榜

  • 限流

?

3.6 节 Bitmaps

3.6.1 简介

在计算机中,用二进制(位)作为存储信息的基本单位,1个字节等于8位。

例如 "abc" 字符串是由 3 个字节组成,计算机存储时使用其二进制表示,"abc"分别对应的ASCII码是97、98、99,对应的二进制是01100001、01100010、01100011,在内存中表示如下:

3.6.2 常用命令

【1】setbit

设置Bitmaps中某个偏移量的值。

语法结构:

setbit key offset value

示例: 记录张三 1月份上班打卡情况

127.0.0.1:6379> setbit zhangsan:1 0 1
(integer) 0
127.0.0.1:6379> setbit zhangsan:1 1 1
(integer) 0
127.0.0.1:6379> setbit zhangsan:1 2 1
(integer) 0
127.0.0.1:6379> setbit zhangsan:1 3 0
(integer) 0
127.0.0.1:6379> setbit zhangsan:1 4 1
(integer) 0
127.0.0.1:6379> setbit zhangsan:1 5 1
(integer) 0
127.0.0.1:6379> setbit zhangsan:1 6 0
(integer) 0

【2】getbit

获取Bitmaps中某个偏移量的值。

语法结构:

getbit key offset

示例:

查看张三1月份 第三天、第四天是否上班

127.0.0.1:6379> getbit zhangsan:1 2
(integer) 1
127.0.0.1:6379> getbit zhangsan:1 3
(integer) 0

【3】bitcount

统计字符串被设置为1的bit数量。一般情况下,给定的整个字符串都会被进行统计,可以选择通过额外的start和end参数,指定字节组范围内进行统计(包括start和end),0表示第一个元素,-1表示最后一个元素。

语法结构:

bitcount key [start end]

示例:统计张三上班天数

127.0.0.1:6379> bitcount zhangsan:1
(integer) 5

【4】bitop

将多个bitmaps通过求交集/并集方式合并成一个新的bitmaps。

语法结构:

bitop and/or destkey sourcekey1 sourcekey2……

示例:

bitop and k3 k1 k2 通过求交集将k1 k2合并成k3
bitop or k3 k1 k2 通过求并集将k1 k2合并成k3

3.6.3 使用场景

  • 活跃天数

  • 打卡天数

  • 登录天数

  • 用户签到

  • 统计活跃用户

  • 统计用户是否在线

  • 实现布隆过滤器

3.7 节 Geospatial

3.7.1 简介

GEO,Geographic,地理信息的缩写。该类型就是元素的二维坐标,在地图上就是经纬度。Redis基于该类型,提供了经纬度设置、查询、范围查询、距离查询、经纬度Hash等常见操作。

3.7.2 常用命令

【1】geoadd

用于存储指定的地理空间位置,可以将一个或多个经度 (longitude)、纬度(latitude)、位置名称(member)添加到指定的 key中。

语法结构:

geoadd key longitude latitude member

示例:

# 将北京的经纬度和名称添加到china
geoadd china 116.405285 39.904989 beijing
# 将成都和上海的经纬度、名称添加到china
geoadd china 104.065735 30.659462 chengdu 121.472644 31.231706 shanghai

【2】geopos

从给定的 key 里返回所有指定名称(member)的位置(经度和纬度),不存在的返回 nil。

语法结构:

geopos key member [member ……]

示例:

返回china中名称为shanghai和beijing的经纬度

geopos china shanghai beijing

【3】geodist

用于返回两个给定位置之间的距离。

语法结构:

geodist key member1 member2 [m|km|ft|mi]

参数说明:

  • m :米,默认单位。

  • km :千米。

  • mi :英里。

  • ft :英尺。

示例:

# 返回shanghai和beijing之间的距离,结果1067597.9668,单位米
geodist china shanghai beijing
# 返回shanghai和chengdu之间的距离,结果1660.0198,单位是千米
geodist china shanghai beijing km


【4】georadius

以给定的经纬度(longitude latitude)为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离(radius )的所有位置元素。

语法结构:

georadius key longitude latitude radius m|km|ft|mi

示例:

#获取经纬度110 30为中心,在china内1200公里范围内的所有元素。
georadius china 110 30 1200 km

3.7.3 使用场景

  • 附近的电影院

  • 附近的好友

  • 离最近的火锅店

3.8 节 HyperLogLog

3.8.1 简介

在我们做站点流量统计的时候一般会统计页面UV(独立访客:unique visitor)和PV(即页面浏览量:page view)。redis HyperLogLog是用来做基数统计的算法,HyperLogLog的优点是:在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且使很小的。

什么是基数?

比如数据集{1,3,5,7,5,7,8},那么这个数据集的基数集为{1,3,5,7,8}, 基数(不重复元素)为5.基数估计就是在误差可接受的范围内,快速计算基数。就是不重复的元素的个数

3.8.2 常用命令

【1】pfadd

将所有元素参数添加到 Hyperloglog 数据结构中。

语法结构:

pfadd key element1 element2……

示例:

如果至少有个元素被添加返回 1, 否则返回 0。

pfadd book1 uid1 uid2 uid3

注意:

添加元素到HyperLogLog中,如果内部有变动返回1,没有返回0。

【2】pfcount

计算Hyperloglog 近似基数,可以计算多个Hyperloglog ,统计基数总数。

语法结构:

pfcount key1 key2……

示例:

pfcount book1 ? ? ? ? ? ? #计算book1的基数,结果为3
pfadd book2 uid3 uid4 ? ? #添加两个元素到book2中
pfcount book1 book2 ? ? ? #统计两个key的基数总数,结果为5

【3】pfmerge

将一个或多个Hyperloglog(sourcekey1) 合并成一个 Hyperloglog (destkey )。

语法结构:

pfmerge destkey sourcekey1 sourcekey2……

示例: 比如每月活跃用户可用每天活跃用户合并后计算。

#将book1和book2合并成book,结果为5
pfmerge book book1 book2

3.8.3 使用场景

基数不大,数据量不大就用不上,会有点大材小用浪费空间,有局限性,就是只能统计基数数量,而没办法去知道具体的内容是什么,和bitmap相比,属于两种特定统计情况,简单来说,HyperLogLog 去重比 bitmaps 方便很多,一般可以bitmap和hyperloglog配合使用,bitmap标识哪些用户活跃。

  • 网站PV统计

  • 网站UV统计

  • 统计访问量(IP数)

  • 统计在线用户数

  • 统计每天搜索不同词条的个数

  • 统计文章真实阅读数

第四章 Redis 配置文件

在redis的解压目录下有个重要的配置文件redis.conf

4.1 节 units单位

配置大小单位,开头定义基本度量单位,只支持bytes,大小写不敏感。

4.2 节 INCLUDES

Redis只有一个配置文件,如果多个人进行开发维护,那么就需要多个这样的配置文件,这时候多个配置文件就可以在此通过 include/path/to/local.conf 配置进来,而原本的 redis.conf 配置文件就作为一个总闸。

4.3 节 NETWORK

参数:

  • bind:绑定redis服务器网卡IP,默认为127.0.0.1,即本地回环地址。这样的话,访问redis服务只能通过本机的客户端连接,而无法通过远程连接。如果bind选项为空的话,那会接受所有来自于可用网络接口的连接。

  • port:指定redis运行的端口,默认是6379。由于Redis是单线程模型,因此单机开多个Redis进程的时候会修改端口。

  • timeout:设置客户端连接时的超时时间,单位为秒。当客户端在这段时间内没有发出任何指令,那么关闭该连接。默认值为0,表示不关闭。

  • tcp-keepalive :单位是秒,表示将周期性的使用SO_KEEPALIVE检测客户端是否还处于健康状态,避免服务器一直阻塞,官方给出的建议值是300s,如果设置为0,则不会周期性的检测。

4.4 节 GENERAL

具体配置详解:

  • daemonize:设置为yes表示指定Redis以守护进程的方式启动(后台启动)。默认值为 no

  • pidfile:配置PID文件路径,当redis作为守护进程运行的时候,它会把 pid 默认写到 /var/redis/run/redis_6379.pid 文件里面

  • loglevel :定义日志级别。默认值为notice,有如下4种取值:

    • debug(记录大量日志信息,适用于开发、测试阶段)

    • verbose(较多日志信息)

    • notice(适量日志信息,使用于生产环境)

    • warning(仅有部分重要、关键信息才会被记录)

  • logfile :配置log文件地址,默认打印在命令行终端的窗口上

  • databases:设置数据库的数目。默认的数据库是DB 0 ,可以在每个连接上使用select 命令选择一个不同的数据库,dbid是一个介于0到databases - 1 之间的数值。默认值是 16,也就是说默认Redis有16个数据库。

4.5 节 SNAPSHOTTING

这里的配置主要用来做持久化操作。

参数:

  • save:这里是用来配置触发 Redis的持久化条件,也就是什么时候将内存中的数据保存到硬盘

  • save 900 1:表示900 秒内如果至少有 1 个 key 的值变化,则保存

  • save 300 10:表示300 秒内如果至少有 10 个 key 的值变化,则保存

  • save 60 10000:表示60 秒内如果至少有 10000 个 key 的值变化,则保存

4.6 节 REPLICATION

参数:

  • slave-serve-stale-data:默认值为yes。当一个 slave 与 master 失去联系,或者复制正在进行的时候,slave 可能会有两种表现:

    • 如果为 yes ,slave 仍然会应答客户端请求,但返回的数据可能是过时,或者数据可能是空的在第一次同步的时候。

    • 如果为 no ,在你执行除了 info he salveof 之外的其他命令时,slave 都将返回一个 "SYNC with master in progress" 的错误

  • slave-read-only:配置Redis的Slave实例是否接受写操作,即Slave是否为只读Redis。默认值为yes。

  • repl-diskless-sync:主从数据复制是否使用无硬盘复制功能。默认值为no。

  • repl-diskless-sync-delay:当启用无硬盘备份,服务器等待一段时间后才会通过套接字向从站传送RDB文件,这个等待时间是可配置的。

  • repl-disable-tcp-nodelay:同步之后是否禁用从站上的TCP_NODELAY 如果你选择yes,redis会使用较少量的TCP包和带宽向从站发送数据。

4.7 节 SECURITY

requirepass:设置redis连接密码。 比如: requirepass 123 表示redis的连接密码为123。

4.8 节 CLIENTS

maxclients :设置客户端最大并发连接数,默认无限制,Redis可以同时打开的客户端连接数为Redis进程可以打开的最大文件。 描述符数-32(redis server自身会使用一些),如果设置maxclients为0 。表示不作限制。当客户端连接数到达限制时, Redis会关闭新的连接并向客户端返回max number of clients reached错误信息

4.9 节 MEMORY MANAGEMENT

参数:

  • maxmemory:设置Redis的最大内存,如果设置为0 。表示不作限制。通常是配合下面介绍的maxmemory-policy参数一起使用。

  • maxmemory-policy :当内存使用达到maxmemory设置的最大值时,redis使用的内存清除策略。有以下几种可以选择:

    1. volatile-lru 利用LRU算法移除设置过过期时间的key (LRU:最近使用 Least Recently Used )

    2. allkeys-lru 利用LRU算法移除任何key

    3. volatile-random 移除设置过过期时间的随机key

    4. allkeys-random 移除随机key

    5. volatile-ttl 移除即将过期的key(minor TTL)

    6. noeviction noeviction 不移除任何key,只是返回一个写错误 ,默认选项

4.10 节 APPEND ONLY MODE

参数:

  • appendonly:默认redis使用的是rdb方式持久化,这种方式在许多应用中已经足够用了。但是redis如果中途宕机,会导致可能有几分钟的数据丢失,根据save来策略进行持久化, Append Only File是另一种持久化方式, 可以提供更好的持久化特性。Redis会把每次写入的数据在接收后都写入appendonly.aof文件,每次启动时Redis都会先把这个文件的数据读入内存里,先忽略RDB文件。默认值为no。

  • appendfilename :aof文件名,默认是"appendonly.aof"

  • appendfsync:aof持久化策略的配置;no表示不执行fsync,由操作系统保证数据同步到磁盘,速度最快;always表示每次写入都执行fsync,以保证数据同步到磁盘;everysec表示每秒执行一次fsync,可能会导致丢失这1s数据

4.11 节 LUA SCRIPTING

参数: lua-time-limit:一个lua脚本执行的最大时间,单位为ms。默认值为5000.

4.12 节 REDIS CLUSTER

参数:

  • cluster-enabled:集群开关,默认是不开启集群模式。

  • cluster-config-file:集群配置文件的名称。

  • cluster-node-timeout :可以配置值为15000。节点互连超时的阀值,集群节点超时毫秒数

  • cluster-slave-validity-factor :可以配置值为10。

第五章 Redis Java客户端

?在Redis官网中提供了各种语言的客户端,地址:https://redis.io/docs/connect/clients/

标记为*的就是推荐使用的java客户端,包括:

  • Jedis和Lettuce:这两个主要是提供了Redis命令对应的API,方便我们操作Redis,而SpringDataRedis又对这两种做了抽象和封装,因此我们后期会直接以SpringDataRedis来学习。

  • Redisson:是在Redis基础上实现了分布式的可伸缩的java数据结构,例如Map、Queue等,而且支持跨进程的同步机制:Lock、Semaphore等待,比较适合用来实现特殊的功能需求。

?

4.1 节 Jedis 客户端

Jedis的官网地址: https://github.com/redis/jedis

4.1.1.快速入门

1)引入依赖:

<!--jedis-->
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>3.7.0</version>
</dependency>
<!--连接池-->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-pool2</artifactId>
    <version>2.11.1</version>
</dependency>
<!--单元测试-->
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter</artifactId>
    <version>5.7.0</version>
    <scope>test</scope>
</dependency>

2)编写入门程序

新建一个单元测试类,内容如下:

/**
 * jedis入门程序
 */
public class JedisTest {
    Jedis jedis;
    @BeforeEach
    public void before(){
        //建立连接
        jedis = new Jedis("192.168.184.129",6379);
        //设置密码
        jedis.auth("123456");
        //选择库
        jedis.select(0);
    }
    @Test
    public void stringTest(){
        //存数据
        jedis.set("name","张三");
        //获取数据
        System.out.println(jedis.get("name"));
    }
    @Test
    public void hashTest(){
        //存数据
        jedis.hset("user:1","name","张三");
        jedis.hset("user:1","age","22");
        //取数据
        Map<String, String> map = jedis.hgetAll("user:1");
        System.out.println(map);

    }
    @AfterEach
    public void after(){
        if(jedis!=null){
            jedis.close();
        }
    }
}

4.1.2.连接池

Jedis本身是线程不安全的,并且频繁的创建和销毁连接会有性能损耗,因此我们推荐大家使用Jedis连接池代替Jedis的直连方式。

public class JedisConnectionFactory {
    private static JedisPool jedisPool;
    static {
        //配置连接池
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxTotal(8);
        poolConfig.setMaxIdle(8);
        poolConfig.setMinIdle(0);
        // 创建连接池对象,参数:连接池配置、服务端ip、服务端端口、超时时间、密码
        jedisPool = new JedisPool(poolConfig, "192.168.184.129", 6379, 1000, "123456");
    }

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

    public static void main(String[] args) {
        System.out.println(JedisConnectionFactory.getJedis());
    }
}

4.2 节 SpringDataRedis 客户端

SpringData是Spring中数据操作的模块,包含对各种数据库的集成,其中对Redis的集成模块就叫做SpringDataRedis,官网地址:Spring Data Redis

  • 提供了对不同Redis客户端的整合(Lettuce和Jedis)

  • 提供了RedisTemplate统一API来操作Redis

  • 支持Redis的发布订阅模型

  • 支持Redis哨兵和Redis集群

  • 支持基于Lettuce的响应式编程

  • 支持基于JDK、JSON、字符串、Spring对象的数据序列化及反序列化

  • 支持基于Redis的JDKCollection实现

SpringDataRedis中提供了RedisTemplate工具类,其中封装了各种对Redis的操作。并且将不同数据类型的操作API封装到了不同的类型中:

API返回值类型说明
redisTemplate.opsForValue()ValueOperations操作String类型数据
redisTemplate.opsForHash()HashOperations操作Hash类型数据
redisTemplate.opsForList()ListOperations操作List类型数据
redisTemplate.opsForSet()SetOperations操作Set类型数据
redisTemplate.opsForZset()ZSetOperations操作SortedSet类型数据
redisTemplate通用命令

4.2.1 快速入门

SpringBoot已经提供了对SpringDataRedis的支持,使用非常简单。

首先,新建一个maven项目,然后按照下面步骤执行:

1)引入依赖

<dependencies>
    <!--redis依赖-->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
    <!--common-pool-->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-pool2</artifactId>
    </dependency>
    <!--Jackson依赖-->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
    </dependency>
    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <optional>true</optional>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
</dependencies>

2)配置Redis

spring:
  redis:
    host: 192.168.184.129
    port: 6379
    password: 123456
    lettuce:
      pool:
        max-active: 8
        max-idle: 8
        min-idle: 0
        max-wait: 100ms

3)注入RedisTemplate,编写测试代码

@SpringBootTest
public class RedisTemplateTests {

    @Autowired
    private RedisTemplate redisTemplate;

    @Test
    public void testString() {
        // 写入一条String数据
        redisTemplate.opsForValue().set("name", "张三");
        // 获取string数据
        Object name = redisTemplate.opsForValue().get("name");
        System.out.println("name = " + name);
    }
}

4.2.2.自定义序列化

RedisTemplate可以接收任意Object作为值写入Redis:

只不过写入前会把Object序列化为字节形式,默认是采用JDK序列化,得到的结果是这样的:

我们可以自定义RedisTemplate的序列化方式,代码如下: ?

@Configuration
public class RedisConfig {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory){
        // 创建RedisTemplate对象
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        // 设置连接工厂
        template.setConnectionFactory(connectionFactory);
        // 创建JSON序列化工具
        GenericJackson2JsonRedisSerializer jsonRedisSerializer = 
            							new GenericJackson2JsonRedisSerializer();
        // 设置Key的序列化
        template.setKeySerializer(RedisSerializer.string());
        template.setHashKeySerializer(RedisSerializer.string());
        // 设置Value的序列化
        template.setValueSerializer(jsonRedisSerializer);
        template.setHashValueSerializer(jsonRedisSerializer);
        // 返回
        return template;
    }
}

这里采用了JSON序列化来代替默认的JDK序列化方式。最终结果如图:

整体可读性有了很大提升,并且能将Java对象自动的序列化为JSON字符串,并且查询时能自动把JSON反序列化为Java对象。不过,其中记录了序列化时对应的class名称,目的是为了查询时实现自动反序列化。这会带来额外的内存开销。 ?

4.2.3.StringRedisTemplate

为了节省内存空间,我们可以不使用JSON序列化器来处理value,而是统一使用String序列化器,要求只能存储String类型的key和value。当需要存储Java对象时,手动完成对象的序列化和反序列化。

省去了我们自定义RedisTemplate的序列化方式的步骤,而是直接使用:

@SpringBootTest
public class StringRedisTemplateTest {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    // JSON序列化工具
    private static final ObjectMapper mapper = new ObjectMapper();

    @Test
    void testSaveUser() throws JsonProcessingException {
        // 创建对象
        User user = new User();
        user.setId(2);
        user.setName("李四");
        user.setAge(33);
        // 手动序列化
        String json = mapper.writeValueAsString(user);
        // 写入数据
        stringRedisTemplate.opsForValue().set("user:2", json);

        // 获取数据
        String jsonUser = stringRedisTemplate.opsForValue().get("user:2");
        // 手动反序列化
        User user1 = mapper.readValue(jsonUser, User.class);
        System.out.println("user1 = " + user1);
    }
}

但一般还是常用自动序列化

第六章 Redis 发布订阅

6.1 节 什么是发布与订阅

Redis 发布订阅 (pub/sub) 是一种消息通信模式:发送者 (pub) 发送消息,订阅者 (sub) 接收消息。

6.2 节 什么时候用发布订阅

看到发布订阅的特性,可用来做一个简单的实时聊天系统。再比如,在一个博客网站中,有100个粉丝订阅了你,当你发布新文章,就可以推送消息给粉丝们拉。

6.3 节 Redis的发布订阅

6.4 节 发布订阅命令

订阅

语法格式:

subscribe 频道名字

示例:

127.0.0.1:6379> subscribe channel-1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel-1"
3) (integer) 1

发布命令

语法格式:

publish channel-1 hello

示例: 打开另一个客户端,给channel1发布消息hello

127.0.0.1:6379> publish channel-1 hello
(integer) 1

注意: 返回的1是订阅者数量。

打开第一个客户端可以看到发送的消息

127.0.0.1:6379> subscribe channel-1
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "channel-1"
3) (integer) 1
1) "message"
2) "channel-1"
3) "hello"

注意: 发布的消息没有持久化,如果在订阅的客户端收不到hello,只能收到订阅后发布的消息。

第七章 Redis 慢查询

7.1 节 什么是慢查询

慢查询,顾名思义就是比较慢的查询,但是究竟是哪里慢呢?

Redis执行命令过程如下:

说明:

  1. 慢查询发生在第3阶段

  2. 客户端超时不一定慢查询,但慢查询是客户端超时的一个可能因素

  3. 慢查询日志是存放在Redis内存列表中

7.2 节 慢查询日志

什么是慢查询日志?

慢查询日志是Redis服务端在命令执行前后计算每条命令的执行时长,当超过某个阈值是记录下来的日志。日志中记录了慢查询发生的时间,还有执行时长、具体什么命令等信息,它可以用来帮助开发和运维人员定位系统中存在的慢查询。

如何获取慢查询日志?

可以使用 slowlog get 命令获取慢查询日志,在 slowlog get 后面还可以加一 个数字,用于指定获取慢查询日志的条数,比如,获取3条慢查询日志:

127.0.0.1:6379> SLOWLOG get 3
1) (integer) 0
2) (integer) 1640056567
3) (integer) 11780
4) 1) "FLUSHALL"
5) "127.0.0.1:43406"
6) ""

参数:

  1. 唯一标识ID

  2. 命令执行的时间戳

  3. 命令执行时长

  4. 执行的命名和参数

如何获取慢查询日志的长度?

可以使用 slowlog len 命令获取慢查询日志的长度

> slowlog len
(integer) 121

注意: 当前Redis中有121条慢查询日志。

7.3 节 怎么配置慢查询参数

配置慢查询参数如下:

  • 命令执行时长的指定阈值 slowlog-log-slower-than:

    slowlog-log-slower-than的作用是指定命令执行时长的阈值,执行命令的时长超过这个阈值时就会被记录下来。

  • 存放慢查询日志的条数 slowlog-max-len。

    slowlog-max-len的作用是指定慢查询日志最多存储的条数。实际上,Redis使用了一个列表存放慢查询日志,slowlog-max-len就是这个列表的最大长度。

如何进行配置:

【1】查看慢日志配置

查看redis慢日志配置,登陆redis服务器,使用redis-cli客户端连接redis server

127.0.0.1:6379> config get slow*
1) "slowlog-max-len"
2) "128"
3) "slowlog-log-slower-than"
4) "10000"

慢日志说明:

10000阈值,单位微秒,此处为10毫秒,128慢日志记录保存数量的阈值,此处保存128条。

【2】修改Redis配置文件

比如,把slowlog-log-slower-than设置为1000,slowlog-max-len 设置为1200

slowlog-log-slower-than 1000
slowlog-max-len 1200

【3】也可以使用 config set 命令动态修改。

比如,还是把slowlog-log-slower-than设置为1000,slowlog-max-len设置为1200

> config set slowlog-log-slower-than 1000
OK
> config set slowlog-max-len 1200
OK
> config rewrite
OK

7.4 节 实践建议

slowlog-max-len配置建议

  • 线上建议调大慢查询列表,记录慢查询时Redis会对长命令做截断操作,并不会占用大量内存。

  • 增大慢查询列表可以减缓慢查询被剔除的可能,例如线上可设置为1000以上。

slowlog-log-slower-than配置建议

  • 默认值超过10毫秒判定为慢查询,需要根据Redis并发量调整该值。

  • 由于Redis采用单线程响应命令,对于高流量的场景,如果命令执行时间在1毫秒以上,那么Redis最多可支撑OPS不到1000。因此对于高OPS场景的Redis建议设置为1毫秒。

?

第八章 Redis 流水线 pipeline

8.1 节 Redis网络通讯模型弊端

1次网络命令通信模型

经历了1次时间 = 1次网络时间 + 1次命令时间。

批量网络命令通信模型

经历了 n次时间 = n次网络时间 + n次命令时间

8.2 节 什么是流水线

经历了 1次pipeline(n条命令) = 1次网络时间 + n次命令时间,这大大减少了网络时间的开销,这就是流水线。

8.3 节 案例

注意:

在执行批量操作而没有使用pipeline功能,会将大量的时间耗费在每一次网络传输的过程上;而使用pipeline后,只需要经过一次网络传输,然后批量在redis端进行命令操作。这会大大提高了效率。

pipeline-Jedis实现

【1】首先,引入jedis依赖包:

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

【2】没有pipeline的命令执行

@Test
void test1(){
    redisTemplate.opsForValue().set("k1","v1");
    redisTemplate.opsForValue().set("k2","v2");
    redisTemplate.opsForValue().set("k3","v3");
}
@Test
void test2() {
    long start = System.currentTimeMillis();
    Object k1 = redisTemplate.opsForValue().get("k1");
    Object k2 = redisTemplate.opsForValue().get("k2");
    Object k3 = redisTemplate.opsForValue().get("k3");
    long end = System.currentTimeMillis();
    System.out.println("话费时间:"+(end-start));
}

注意:

在不使用pipeline的情况下,使用for循环进行每次一条命令的执行操作,耗费的时间可能达到 1w 条插入命令的耗时为50s。

【3】使用pipeline

@Test
void test3() {

    redisTemplate.executePipelined((RedisConnection connection)->{
        long start = System.currentTimeMillis();
        Object k1 = connection.get("k1".getBytes());
        Object k2 = connection.get("k2".getBytes());
        Object k3 = connection.get("k3".getBytes());
        long end = System.currentTimeMillis();
        System.out.println("话费时间:"+(end-start));
        return null;
    });

}

耗时会大大减少

第九章 Redis 持久化机制

由于Redis的数据都存放在内存中,如果没有配置持久化,Redis重启后数据就全丢失了,于是需要开启Redis的持久化功能,将数据保存到磁盘上,当Redis重启后,可以从磁盘中恢复数据。

9.1 节 Redis持久化概述

对于Redis而言,持久化机制是指把内存中的数据存为硬盘文件, 这样当Redis重启或服务器故障时能根据持久化后的硬盘文件恢复数据

持久化机制的意义

redis持久化的意义,在于故障恢复。比如部署了一个redis,作为cache缓存,同时也可以保存一些比较重要的数据。

Redis提供了两个不同形式的持久化方式

  • RDB(Redis DataBase)

  • AOF(Append Only File)

9.2 节 RDB持久化机制

9.2.1 什么是RDB?

RDB是什么

在指定的时间间隔内将内存的数据集快照写入磁盘,也就是行话讲的快照,它恢复时是将快照文件直接读到内存里。

9.2.2 RDB基本配置

配置dump.rdb文件

RDB保存的文件,在redis.conf中配置文件名称,默认为dump.rdb。

440 # The filename where to dump the DB
441 dbfilename dump.rdb

rdb文件的保存位置,也可以修改。默认在Redis启动时命令行所在的目录下。

当前路径

dir ./

触发机制-主要三种方式

RDB配置

快照默认配置:

  • save 3600 1:表示3600秒内(一小时)如果至少有1个key的值变化,则保存。

  • save 300 100:表示300秒内(五分钟)如果至少有100个 key 的值变化,则保存。

  • save 60 10000:表示60秒内如果至少有 10000个key的值变化,则保存。

配置新的保存规则

给redis.conf添加新的快照策略,30秒内如果有5次key的变化,则触发快照。配置修改后,需要重启Redis服务。

save 3600 1
save 300 100
save 60 10000
save 30 5

flushall

执行flushall命令,也会触发rdb规则。

save与bgsave

手动触发Redis进行RDB持久化的命令有两种:

  • save

    该命令会阻塞当前Redis服务器,执行save命令期间,Redis不能处理其他命令,直到RDB过程完成为止,不建议使用。

  • bgsave

    执行该命令时,Redis会在后台异步进行快照操作,快照同时还可以响应客户端请求。

9.2.3 RDB高级配置

stop-writes-on-bgsave-error

默认值是yes。当Redis无法写入磁盘的话,直接关闭Redis的写操作。

rdbcompression

默认值是yes。对于存储到磁盘中的快照,可以设置是否进行压缩存储。如果是的话,redis会采用LZF算法进行压缩。如果你不想消耗CPU来进行压缩的话,可以设置为关闭此功能,但是存储在磁盘上的快照会比较大。

rdbchecksum

默认值是yes。在存储快照后,我们还可以让redis使用CRC64算法来进行数据校验,但是这样做会增加大约10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能。

恢复数据

只需要将rdb文件放在Redis的启动目录,Redis启动时会自动加载dump.rdb并恢复数据。

9.2.4 RDB的优势与劣势

优势

  • 适合大规模的数据恢复

  • 对数据完整性和一致性要求不高更适合使用

  • 节省磁盘空间

  • 恢复速度快

劣势

  • 在备份周期在一定间隔时间做一次备份,所以如果Redis意外down掉的话,就会丢失最后一次快照后的所有修改。

?

9.3 节 AOF持久化机制

9.3.1 什么是AOF

以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来。

AOF默认不开启

可以在redis.conf中配置文件名称,默认为appendonly.aof。

注意:

AOF文件的保存路径,同RDB的路径一致,如果AOF和RDB同时启动,Redis默认读取AOF的数据。

AOF同步频率设置

参数:

  1. appendfsync always 始终同步,每次Redis的写入都会立刻记入日志,性能较差但数据完整性比较好。

  2. appendfsync everysec 每秒同步,每秒记入日志一次,如果宕机,本秒的数据可能丢失。

  3. appendfsync no redis不主动进行同步,把同步时机交给操作系统。

优势

  • 备份机制更稳健,丢失数据概率更低。

  • 可读的日志文本,通过操作AOF稳健,可以处理误操作。

劣势

  • 比起RDB占用更多的磁盘空间。

  • 恢复备份速度要慢。

  • 每次读写都同步的话,有一定的性能压力。

9.4 节 如何选用持久化方式

综合使用AOF和RDB两种持久化机制

用AOF来保证数据不丢失,作为数据恢复的第一选择,用RDB来做不同程度的冷备,在AOF文件都丢失或损坏不可用的时候,还可以使用RDB来进行快速的数据恢复。

第十章 总结

【1】你都用过哪些Redis数据类型?

答:String、List、Set、Map、ZSet、BitMaps、GEO、HyperLogLog。

常规缓存用String类型 、对象经常修改字段用Map类型 、BitMaps处理打卡上班记录等问题,GEO处理地理坐标类问题,HyperLogLo处理PV,UV等基数统计操作。

List可以实现排行榜,最新列表等功能。Set实现共同联系人,黑白名单功能。

ZSet可以实现特定条件的排行榜。按照人气排行,人气作为存储分数。

【2】说一下发布订阅机制?

答:发布订阅机制可以实现类似你订阅某个频道后,该频带给你发送消息的功能,订阅频道命令

subscribie 频道
# 发送消息
publish 频道名 消息

【3】如何解决慢查询问题?

答:通过慢查询日志解决,slowlog len获取慢查询记录数,在通过slowlog get n获取具体信息去排查。

还可以通过

> config set slowlog-log-slower-than 1000
OK
> config set slowlog-max-len 1200
OK
> config rewrite
OK

慢查询阈值根据QPS设置

【4】说以下说什么是流水线操作 答:一次网络连接 执行n条redis指令。

【5】说以下Redis持久化机制?

答:Redis支持两种持久化机制:RDB和AOF。RDB是快照持久化,读写速度快,占用磁盘空间小。但有丢失数据风险。AOF通过记录命令日志持久化,不易丢失数据,但是占用磁盘空间大,读写速度慢。RDB适合做冷备,如一天一备份的常规备份。AOF适合做REDIS正常重启前的数据备份,不会丢失数据。

文章来源:https://blog.csdn.net/m0_59163770/article/details/135346281
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。