Redis

入门概述

Redis简介

Redis:REmote Dictionary Server(远程字典服务器)

官网解释:

Remote Dictionary Sercer(远程字典服务)是完全开源的,使用ANSIC语言编写遵守BSD协议,是一个高性能的Key-Value数据库,提供了丰富的数据结构,例如String,Hash,List,Set,SortedSet等等,数据是存在内存中的,同时Redis支持事务、持久化、LUA脚本、发布/订阅、缓存淘汰、流技术等多种功能特性提供了主从模式、Redis Sentinel和Redis Cluster集群架构方案

Redis功能

主流功能与应用

  1. 分布式缓存,挡在MySQL数据库之前的带刀护卫
  2. 内存存储和持久化(RDB+AOF)
    Redis支持异步将内存中的数据写到硬盘上,同时不影响继续服务
  3. 高可用架构搭配(单机,主从,哨兵,集群)
  4. 缓存穿透、击穿、雪崩
  5. 分布式锁
  6. 队列
    Redis提供list和set操作,这使得Redis能作为一个很好的消息队列平台来使用。我们常通过Redis的队列功能做购买限制,比如节假日或者推广期间,进行一些活动,对用户购买行为进行限制,限制今天只能购买几次商品或者一段时间内只能购买一次,也比较适合使用
  7. 排行版+点赞
    在互联网应用中,有各种各样的排行榜,Redis提供的zset数据类型能够快速实现这些复杂的排行榜

与传统数据库关系(MySQL)

  1. Redis是Key-value数据库(NoSQL一种),MySQL是关系数据库
  2. Redis数据操作主要在内存,而MySQL主要存储在磁盘
  3. Redis在某一些场景使用中有明显优于MySQL,比如计数器、排行榜等方面
  4. Redis通常用于一些特定场景,需要与MySQL一起配合使用
    两者并不是相互替换和竞争关系,而是共用和配合使用

Redis优势

  1. 性能极高,Redis能读的速度是110000次/秒,写的速度是81000次/秒
  2. Redis数据类型丰富,不仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储
  3. Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用
  4. Redis支持数据的备份,即master-slace模式的数据备份

小总结

Redis下载

Redis - The Real-time Data Platform

Redis迭代演化和Redis7新特性浅谈

时间推移和版本升级

Redis版本迭代推演介绍

Redis历史大版本核心特性

Redis命名规则

版本号第二位如果是奇数,则为非稳定版本,如2.7,2.9,3.1

版本号第二位如果是偶数,则为稳定版本,如2.6,2.8,3.0,3.2

当前奇数版本就是下一个稳定版本的开发版本,如2.9是3.0的开发版本

Redis新特性概述

对Redis7的一部分新特性做说明

多AOF文件支持7.0版本中一个比较大的变化就是aof文件由一个变成了多个,主要分为两种类型:基本文件(base files)、增量文件(Incr files),请注意这些文件名称是复数形式说明每一类文件不仅仅只有一个,此外还引入了一个清单文件(manifest)用于跟踪文件以及文件的创建和应用顺序(恢复)
config命令增强对于Config Set和Get命令,支持在一次调用过程中传递多个配置参数。
限制客户端内存使用Client-eciction一旦Redis连接较多,再加上每个连接的内存占用都比较大的时候,Redis总连接内存占用可能会达到maxmemory的上限,可以增加允许限制所有客户端的总内存使用量配置项,redis.config中对应的配置项
//两种配置形式:指定内存大小、基于maxmemory的百分比
maxmemory-client 1g
maxmemory-client 10%
listpack紧凑列表调整listpack是用来代替ziplist的新数据结构,在7.0版本中已经没有ziplist的配置了,listpack已经替换了ziplist类似hash-max-ziplist-entries的配置了
访问安全性增强ACLV2在redis.conf配置文件中,protected-mode默认为yes,只有当你希望你的客户端在没有授权的情况下可以连接到Redis server的时候可以将protected-mode设置为no
Redis FunctionsRedis函数,一种新的通过服务端脚本扩展Redis的方式,函数与数据本身一起存储。简言之,redis自己要去抢夺Lua脚本(主流)的饭碗
RDB保存时间调整将持久化文件RDB的保存规则发生了改变,尤其是时间记录频度变化
命令新增和变动Zset(有序集合)增加ZMPOP、BZMPOP、ZINTERCARD等命令
Set(集合)增加SINTERCARD命令
LIST(列表)增加LMPOP、BLMPOP,从提供的键名列表中的第一个非空列表键中弹出一个或多个元素
性能资源利用率、安全等改进自身底层部分优化改动,Redis核心在许多方面进行了重构和改进
主动碎片整理V2:增强版主动碎片整理,配合Jemalloc版本更新,更快更智能,延时更低
HyperLogLog改进:在Redis5.0中,HyperLogLog算法得到改进,优化了计数统计时的内存使用效率,更加优秀更好的内存统计报告

Redis安装

Linux环境安装Redis必须先具备gcc编译环境

gcc

gcc是Linux下的一个编译程序,是c程序的编译工具

查看gcc版本gcc -v

安装

安装Redis之前需要具备C++库环境

yum -y install gcc-c++

安装步骤:

  1. 下载获得redis-7.0.0.tar.gz后将它放入Linux下/usr/local/redis
  2. 解压redis tar -zxvf ...
  3. 进入目录cd redis-7.0.0
  4. 在redis-7.0.0目录下执行make & make install命令
  5. 查看默认安装目录:usr/local/bin
  6. 设置全局命令ln -s /usr/local/redis/redis-7.0.0/src/redis-server /usr/bin/redis-server
  7. 启动服务
  8. 连接服务
Redis版本选择
  1. 查看自己Redis版本的命令redis-server -v
  2. 安全Bug按照官网提示,升级成为6.0.8及以上

Redis数据类型

  1. redis字符串(String)
  2. redis列表(List)
  3. redis哈希表(Hash)
  4. redis集合(Set)
  5. redis有序集合(ZSet)
  6. redis地理空间(GEO)
  7. redis基数统计(HyperLogLog)
  8. redis位图(bitmap)
  9. redis位域(bitfield)
  10. redis流(Stream)

十大数据类型

redis字符串(String)

String是redis最基本的类型,一个key对应一个value。

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

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

redis列表(List)

Redis列表是简单的字符串列表,按照插入顺序。可以添加一个元素到列表的头部(左边)或者尾部(右边)。

它的底层实际是个双端链表,最多可以包含2^32-1个元素

redis哈希表(Hash)

Redis hash是一个String类型的field(字段)和value(值)的映射表,hash特别适用与存储对象。

Redis中每个hash可以存储2^32-1键值对

redis集合(Set)

Redis的Set是String类型的无序集合。集合成员是唯一的,这就意味着编辑和中不能出现重复的数据,集合对象的编码可以是intset或者hashtable。

Redis中Set集合是通过哈希表实现的,所以添加、删除、查找的复杂度都是O(1)。

集合中最大的成员数为2^32-1

redis有序集合(ZSet)

zset(sorted Set:有序集合)

Redis zset和set一样也是String类型元素的集合,且不允许重复。

不同的是每个元素都会关联一个double类型的分数,redis正是通过分数来为集合中的成员进行从小到大的排序。

zset的成员是唯一的,但分数(score)确是可以重复的。

zset集合是通过哈希表实现的,所以添加、删除、查找的复杂度都是O(1)。集合中最大的成员数为2^32-1

redis地理空间(GEO)

Redis GEO主要用于存储地理位置信息,并对存储的信息进行操作,包括:

  1. 添加地理位置的坐标
  2. 获取地理位置的坐标
  3. 计算两个位置之间的距离
  4. 根据用户给定的经纬度坐标来获取指定范围内的地理位置集合

redis基数统计(HyperLogLog)

HyperLogLog是用来做基数统计的算法,HyperLogLog的优点是在输入元素的数量或者体积非常大时,计算基数所需的空间总是固定且很小的。

在Redis里面,每个HyperLogLog键只需要花费12KB内存,就可以计算接近2^64个不同元素的基数,这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。

但是,因为HyperLogLog只会根据输入元素来计算基数,而不会储存元素本身,所以HyperLogLog不能像集合那样,返回输入的各个元素。

redis位图(bitmap)

Bit arrays(or simply bitmaps)我们可以称之为位图

上图由许多小格子组成,每个格子表示1个bit,每个格子里面只能放1或者0,用它来判断Y/N状态。

由0和1状态表现的二进制位的bit数组

redis位域(bitfield)

通过bitfield命令可以一次性操作多个比特位域(指的是连续的多个比特位),他会执行一系列操作并返回一个响应数组,这个数组中的元素对应参数列表中的响应操作的执行结果.

redis流(Stream)

Redis Stream是Redis 5.0 版本新增的数据结构。

Redis Stream 主要是用于消息队列(MQ,Message Queue),Redis本身是有一个Redis发布订阅(pub/sub)来实现消息队列的功能,但它有个缺点就是消息无法持久化,如果出现网络断开、Redis宕机等,消息就会被丢弃。

简单来说发布订阅(pub/sub)可以分发消息,但无法记录历史消息。

而Redis Stream 提供了消息持久化和主备复制功能,可以让任何客户端访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失

获取redis常见数据类型操作命令

官网https://redis.io/commands/

中文http:www/redis/cn/commands.html

Redis键(key)

常用操作命令

  1. keys * 查看当前库所有的key
  2. exist key 判断某个key是否存在
  3. type key 查看key是什么类型
  4. del key 删除指定的key数据
  5. unlink key 非阻塞删除,仅仅将keys从keyspace元数据中删除,真正的删除会在后续异步中操作
  6. ttl key 查看还有多少秒过期,-1表示永不过期,-2表示已过期
  7. expire key 秒钟,为给定的key设置过期时间
  8. move key dbindex [0-15] 将当前数据库的key移动到给定的数据库db当中
  9. select dbindex,切换数据库[0-15],默认为0
  10. dbsize 查看当前数据库key的数量
  11. flushdb 清空当前库
  12. flushall 通杀全部库

数据类型命令及落地运用

命令不区分大小写,而key是区分大小写的

永远的帮助命令,help @类型

Redis字符串(String)

特点:单值单value

常用命令

最常用:set key value,get key

set key value [NX|XX] [GET] [EX seconds|PX milliseconds|EXAT unix-time-seconds|PXAT unix-time-milliseconds|KEEPTTL]

SET命令有EX、PX、NX、XX以及KEEPTTL五个可选参数,其中KEEPTTL为6.0版本添加的可选参数,其他为2.6.12版本添加的可选参数。

EX seconds:以秒为单位设置过期时间

PX milliseconds:以毫秒为单位设置过期时间

EXAT timestamp:设置以秒为单位的UNIX时间戳所对应的时间为过期时间

PXAT milliseconds-timestamp:设置以毫秒为单位的UNIX时间戳所对应的时间为过期时间

NX:键不存在的时候设置键值

XX:键存在时设置键值

KEEPTTL:保留设置前指定键的生存时间

GET:返回指定键原本的值,若键不存在时返回nil

SET命令使用EX、PX、NX参数,其效果等同于SETEX、PSTEX、SETNX命令。根据官方文档的描述,未来版本中SETEX、PSETEX、SETNX命令可能会被淘汰

EXAT、PXAT以及GET为Redis6.2新增的可选参数

同时设置/获取多个键值

MSET key1 value1 [key2 value2 …]

MGET key1 [key2 key3 …]

mset/mget/msetnx

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

获取指定区间范围内的值

getrange/setrange

getrange:获取指定区间范围内的值,类似between…and的关系,从零到负一表示全部

setrange设置指定区间范围内的值,格式是setrange key值 具体值

数值增减

一定要是数字才能进行加减

递增数字 INCR key

增加指定的整数

INCRBY key increment

递减数值 DECR key

减少指定的整数 DECRBY key decrement

获取字符串长度和内容追加

获取字符串长度 STRLEN key

内容追加 APPEND key value

分布式锁

setnx key value

setex(set with expire)键 秒 值/setnx(set if not exist)

getset key value

先get再set

Redis列表(List)

特点:

  1. 单key多value
  2. 一个双端链表的结构,容量是2的32次方减1个元素,大概40多亿,主要功能有push/pop等,一般用在栈、队列、消息队列等场景。
  3. left、right都可以插入添加,如果键不存在,创建新的链表;如果键已存在,新增内容;如果值全移除,对应的键也就消失了。
  4. 底层实际是个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差。

常用命令

lpush、rpush、lrange

lpop、rpop

lindex

按照索引下标获得元素(从上到下)

llen

获取列表中元素的个数

lrem key 数字N 给定值v1

删除N个值等于v1的元素

ltrim key 开始index 结束index

截取指定范围的值后再赋值给key

rpoplpush 源列表 目的列表

lset key index value

linsert key before/after 已有值 插入的新值

Redis哈希(Hash)

KV模式不变,但V是一个键值对

Map<String,Map<Object,Object>>

常用命令

hset/hget/hmset/hmget/hgetall/hdel

hlen

获取某个key内的全部数量

hexists key 在key里面的某个值的key

判断某个值的key是否在数据库中存在

hkeys/hvals

hincrby/hincrbyfloat

hsetnx

不存在则赋值,存在则无效

Redis集合(Set)

特点:

  1. 单值多value,且无重复
常用命令

SADD key member [member…]

添加元素,自动去重

SMEMBERS key

遍历集合中所有元素

SISMEMBER key member

判断元素是否在集合中

SREM ky member [member…]

删除元素

scard

获取集合里面的元素个数

SRANDMEMBER key [数字]

从集合中随机展示设置的数字个数元素,元素不删除

SPOP key [数字]

从集合中随机弹出一个元素,弹出元素删除

SMOVE key1 key2 在key1里已存在的某个值

将key1里已存在的某个值赋给key2

集合运算

假设集合A:a,b,c,1,2;集合B:1,2,3,a,x

  1. 集合的差集运算 A-B
    SDIFF key [key…]
  2. 集合的并集运算 A∪B
    SUNION key [key…]
  3. 集合的交集运算 A∩B
    SINTER key [key…]
    SINTERCARD numkeys key [key…] [LIMIT limit]
    redis7新命令,不返回结果集,只返回结果的基数,返回由所有给定集合的交集产生的集合的基数(去重过后元素个数)

Redis有序集合(Zset)

sorted set

在set基础上,每个val值前面加一个score分数值,之前set是k1 v1 v2 v3,

现在是k1 score v1 score v2

常用命令

ZADD key score member [score member …]

向有序集合中加入一个元素和该元素的分数

ZRANGE key start stop [WITHSCORES]

按照元素分数从小到大的顺序,返回索引从start到stop之间的所有元素

ZREVRANGE key start stop [WITHSCORES]

按照元素分数从大到小的顺序,返回索引从start到stop之间的所有元素

ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]

获取指定分数返回的元素

ZSCORE key member

获取元素的分数

ZCARD key

获取集合中元素的数量

ZREM key 某score下对应的vlaue值

删除元素

ZINCRBY key increment member

增加某个元素的分数

ZCOUNT key min max

获取指定分数范围内的元素个数

ZMPOP

从键名列表中的第一个非空排序集中弹出一个或多个元素,他们是成员分数对

ZRANK key values值

获得下标值

ZREVRANK key values值

逆序获得下标值

Redis位图(bitmap)

由0和1状态表现的二进制位的bit数组

用于状态统计,Y\N,类似AtomicBoolean

setbit key offset value
 setbit   键  偏移位 只能0/1

Bitmap的偏移量是从0开始算的

getbit key offset
strlen key

统计字节数占用多少

bitcount

全部键里面含有1的个数

bitop

Redis基数统计(HyperLogLog)

去重复统计功能的基数估计算法就是HyperLogLog

用于统计一个集合中不重复的元素个数,就是对集合去重复后剩余元素的计算

不存储数据本身

基本命令

PFADD key element [element…]

PFCOUNT key [key…]

PFMERGE destkey sourcekey [sourcekey]

Redis地理空间(GEO)

核心思想就是将球体转换为平面,区块转换为一个点,主要分为三步:

  1. 将三维的地球变为二维的坐标
  2. 将二维的坐标转换为一维的点块
  3. 将一维的点块转换为二进制再通过base32编码

Redis在3.2版本以后增加了地理位置的处理

GEOADD

多个经度(longitude)、纬度(latitude)、位置名称(member)添加到指定的key中

如果有中文乱码登录时redis-cli --raw

GEOPOS

从键里面返回所有给定位置元素的位置

GEODIST

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

GEORADIUS

以给定的经纬度为中心,返回与中心的距离不超过给定最大距离的所有位置元素

GEORADIUSBYMEMBER

跟GEORADIUS类似

GEOHASH

返回一个或多个位置元素的Geohash表示

Redis流(Stream)

能实现消息队列,支持消息的持久化,支持自动生成全局唯一ID、支持ACK确认消息的模式、支持消费组模式等,让消息队列更加的稳定和可靠

队列相关指令

消费组相关指令

四个特殊符号
    • / + :最小和最大可能出现的id
  1. $ :表示只消费新的消息,当前流中最大的id,可用于将要到来的信息
  2. :用于XREADGROUP命令,表示迄今还没有发送给组中使用者的信息,会更新消费组最后id

    • :用于XADD命令中,让系统自动生成id

位域(bitfield)

了解即可

Redis持久化

为什么需要持久化

Redis是内存数据库,在运行使用过程中,数据存储在内存中,内存中的数据在断电后就会数据消失,如果我们的缓存在内存中,会因为服务器宕机、断电后缓存消失,所有的数据都打到MySQL上,这样的结果会带给系统灾难性,无法接受的,所以我们需要Redis缓存中的数据长期使用,需要在重启故障宕机恢复过以后,还是能从磁盘上读回曾经保存的数据

RDB和AOF

RDB

简介

Reids DataBase(Redis数据库)

RDB持久性以指定的时间间隔执行数据集的时间点快照

实现类似照片记录效果的方式,就是把某一时刻的数据和状态以文件的形式写到磁盘上,也就是快照,这样一来即使故障宕机,快照文件也不会丢失,数据的可靠性也就得到了保障,这个快照文件就称为RDB文件(dump.rdb)

作用

在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是Snapshot内存快照,它恢复时再将硬盘快照文件直接读回内存中

Redis的数据都在内存中,保存备份时它执行的是全量快照,也就是说把内存中所有数据都记录到磁盘中

自动触发

触发备份条件:1.存储超过阈值 2.时间超过阈值 ,其一即可

如何恢复:1.将备份文件(dump.rdb)移动到redis安装目录并启动服务即可

2.物理恢复,一定服务和备份分机隔离

分机隔离:将备份文件dump.rdb和生产redis服务器分开各自存储,以防生产机物理损坏后备份文件损坏

测试:备份成功后故意用flushdb清空redis,看看是否可以恢复数据

结论:执行flushall/flushdb命令也会产生dump.rdb文件,但里面是空的,无意义

手动触发

Redis提供了两个命令来生成RDB文件,分别是save和bgsave

  1. SAVE
    在主程序中执行会阻塞当前redis服务器,直到持久化工作完成。执行save命令期间,Redis不能处理其他命令,线上**禁止使用**
  2. BGSAVE(默认)
    Redis会在后台异步进行快照操作,**不阻塞
    **** **快照同时还可以响应客户端请求,该触发方式会fork一个子进程,由子进程复制持久化过程
    Redis会使用bgsave对当前内存中的所有数据做快照,这个操作是子进程在后台完成的,这就允许主进程同时可以修改数据
    在Linux程序中,fork()会产生一个和父进程完全相同的子进程,但子进程在此后多会exec系统调用,出于效率考虑,尽量避免膨胀
lastsave

上一次保存的时间,会返回一个时间戳

优点和缺点

优点:

  1. RDB是Redis数据的一个非常紧凑的单文件时间点表示,RDB文件非常适合备份。
  2. RDB非常适合灾难恢复,它是一个可以传输到远程数据中心或Amazon S3(可能已加密)的压缩文件
  3. RDB最大限度地提高了Redis的性能,因为Redis父进程为了持久化而需要做的唯一工作就是派生一个将完成所有其余工作的子进程。父进程永远不会执行磁盘I/O或类似操作
  4. 与AOF相比,RDB允许使用大数据集更快地重启
  5. 在副本上,RDB支持重启和故障转移后的部分重新同步

缺点:

  1. 如果需要在Redis停止工作时(例如断电后)将数据丢失的可能性降到最低,那么RDB并不好,可以配置生成RDB的不同保存点。但是,通常会每5分钟或更长时间创建一次RDB快照,因此,如果Redis由于任何原因在没有正确关闭的情况下停止工作,应该准备好丢失最新分钟的数据
  2. RDB需要经常fork()以便使用子进程在磁盘上持久化。如果数据集很大,fork()可能会很耗时,并且如果数据集很大并且CPU性能不是很好,可能会导致Redis停止为客户端服务几毫秒甚至一秒钟,AOF也需要fork(),但频率较低,可以调整要重写日志的频率,而不需要对持久性进行任何权衡
如何检查修复dump.rdb文件

哪些情况会触发RDB快照

如何禁用快照
  1. 动态所有停止RDB保存规则的方法:redis-cli config set save ""
配置文件SNAPSHOTTING模块

AOF

Append Only File

以日志的形式来记录每个写操作,将Redis执行过的所有写指令记录下来(读操作不记录),只允许追加文件不允许改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作

默认情况下,redis是没有开启AOF的,开启AOF功能需要设置配置:appendonly yes

AOF保存的是appendonly.aof文件

AOF持久化工作流程

  1. Client作为命令的来源,会有多个源头以及源源不断的请求命令
  2. 在这些命令到达Redis Server以后并不是直接写入AOF文件,会将其这些命令先放入AOF缓存中进行保存。这里的AOF缓冲区实际上是内存中的一片区域,存在的目的是当这些命令到达一定量以后再写入磁盘,避免频繁的磁盘IO操作
  3. AOF缓冲会根据AOF缓冲区同步文件的三种写回策略将命令写入磁盘上的AOF文件
  4. 随着写入AOF内容的增加为避免文件膨胀,会根据规则进行命令的合并(又称为AOF重写),从而起到AOF文件压缩的目的
AOF缓冲区的三种写回策略
  1. Always
    同步写回,每个写命令执行完立刻同步地将日志写回磁盘
  2. everysec
    每秒写回
  3. no
    操作系统控制的写回,每个写命令执行完,只是先把日志写到AOF文件的内存缓冲区,由操作系统决定何时将缓冲区内容写回磁盘

默认写回策略是everysec

Redis7.0 Multi Part AOF的设计

在redis6及以前,aof文件只且仅有一个。

Redis7.0之后,MP-AOF将原来的单个AOF文件拆分成多个AOF文件,在MP-AOF中,将AOF分为三种类型:

  1. BASE:表示基础AOF,它一般由子进程通过重写产生,该文件最多只有一个
  2. INCR:表示增量AOF,它一般会在AOFRW开始执行时被创建,该文件可能存在多个
  3. HISTORY:表示历史AOF,它由BASE和INCR AOF变化而来,每次AOFRW成功完成时,本次AOFRW之前对应的BASE和INCR AOF都将变成HISTORY,HISTORY类型的AOF会被Redis自动删除

为了管理这些AOF文件,我们引入了一个manifest(清单)文件来个跟踪、管理这些AOF。同时,为了便于AOF备份和拷贝,我们将所有的AOF文件和manifest文件放入一个单独的文件目录中,目录名由aooenddirname配置决定

优点和缺点

优点:

  1. 使用AOF Redis更加持久:可以有不同的fsync策略,使用每秒Fsync的默认策略,写入性能依然很棒。fsync是使用后台线程执行的,当没有fsync在进行时,主线程将努力执行写入,因此最差的情况只丢失一秒钟的写入
  2. AOF日志是一个仅附加日志,因此不会出现导道问题,也不户在断电时出现损坏问题。即使由于某种原因(磁盘已满或者其他原因)日志以写一半的命令结尾,redis-check-aof工具也能轻松修复它
  3. 当AOF变得太大时,Redis能够在后台自动重写AOF。重写是完全安全的,因为当Redis继续附加到旧文件时,会使用创建当前数据集所需的最少操作集生成一个全新的文件,一旦第二个文件准备就绪,Redis就会切换两者并开始附加到新的那一个
  4. AOF以易于理解和解析的格式依次包含所有操作的日志。可以轻松导出AOF文件。如果不小心使用FLUSHALL命令刷新了所有内容,只要在此期间没有执行日志重写,仍然可以通过停止服务器、删除最新命令并重启Redis来保存数据集

缺点:

  1. AOF文件通常比相同数据集的等效RDB文件大
  2. 根据确切的fsync策略,AOF可能比RDB慢,一般来说,将fsync设置为每秒性能仍然非常高,并且在禁用fsync的情况下,即使在高负载下他也应该与RDB一样块。即使在巨大的写入负载的情况下,RDB仍然能够提供关于最大延迟的更多保障
AOF重写机制

AOF持久化是Redis不断将写命令记录到AOF文件中,随着Redis不断地进行,AOF的文件会越来越大,文件越大,占用服务器内存越大以及AOF恢复要求时间越长。为了解决这个问题,Redis新增了重写机制,当AOF文件的大小超过所设定的峰值时,Redis就会自动启动AOF文件的内容压缩,只保留可以恢复数据的最小指令集后者可以手动使用命令bgrewriteaof来重新

AOF重写不仅降低了文件的占用空间,同时更小的AOF也可以更更快地被Redis加载

官网默认配置

同时满足,且的关系才会触发

  1. 根据上次重写的aof大小,判断当前aof大小是否增长了一倍
  2. 重写时满足的文件大小
自动触发

满足配置文件中的选项后,Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时

手动触发

客户端向服务器发送bgrewriteaof命令

小结

AOF文件重写并不是对原文件进行重新整理,而是直接读取服务器现有的键值对,然后用一条命令去替换原来的AOF文件。

AOF文件重写触发机制:通过redis.conf配置文件中的auto-aof-rewrite-percentage:默认值为100,以及auoto-aof-rewrite-min-size:64mb配置,也就是说默认Redis会记录上次重写时的AOF大小,默认配置是当AOF文件大小是上次rewrite后大小的一倍且文件大于64M时触发

重写原理
  1. 在重写开始前,redis会创建一个“重写子进程”,这个子进程会读取现有的AOF文件,并将其包含的指令进行分析压缩并写入到一个临时文件中。
  2. 与此同时,主进程会将新接收到的写指令一边累积到内存缓冲区中,一边继续写入到原有的AOF文件中,这样做是保证原有AOF文件的可用性,避免在重写过程中出现意外
  3. 当“重写子进程”完成重写工作后,它会给父进程发一个信号,父进程收到信号后就会将内存中缓存的写指令追加到新AOF文件中
  4. 当追加结束后,redis就会用新AOF文件来代替旧AOF文件,之后再有新的写指令,就都会追加到新的AOF文件中
  5. 重写AOF文件的操作,并没有读取旧的AOF文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,这点和快照有点类似

RDB+AOF混合持久化

Redis会优先加载AOF文件

数据恢复顺序和加载流程

在同时开启RDB和AOF持久化时,重启时只会加载aof文件,不会加载rdb文件

怎么选
  1. RDB持久化方式能够在指定的时间间隔能对数据进行快照存储
  2. AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以Redis协议追加保存每次写的操作到文件末尾
同时开启两种持久化方式

在这种情况下,当Redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下,AOF文件保存的数据集要比RDB文件保存的数据集要完整。

RDB的数据不实时,同时使用两者时服务器重启也只会找AOF文件。作者建议不要只使用AOF,因为RDB更适合用于备份数据库(AOF在不断变化不好备份),留着RDB作为一个万一的手段。

推荐方式

RDB+AOF混合方式

结合了RDB和AOF的优点,既能快速加载又能避免丢失过多的数据。

结论:RDB镜像做全量持久化,AOF做增量持久化。

纯缓存模式

同时关闭RDB+AOF

  1. save “” 禁用RDB
    禁用RDB持久化模式下,但仍可使用save、bgsave生成rdb文件
  2. appendonly no 禁用AOF,禁用AOF持久化模式下,仍可使用命令bgrewriteaof生成AOF文件

Redis事务

是什么

可以一次执行多个命令,本质是一组命令的集合。一个事务中的所有命令都会序列化,按顺序地串行化执行而不会被其他命令插入,不许加塞

能干嘛

一个队列中,一次性、顺序性、排他性的执行一系列命令

Redis事务VS数据库事务

单独的隔离操作Redis的事务仅仅是保证事务里的操作会被连续独占的执行,redis命令执行时单线程架构,在执行完事务内所有指令前是不可能再去同时执行其他客户端的请求的
没有隔离级别的概念因为事务提交前任何指令都不会被实际执行,也就不存在“事务内的查询要看到事务里的更新,在事务外查询不能看到”这种问题
不保证原子性Redis的事务不保证原子性,也就是不保证所有指令同时成功或同时失败,只有决定是否开始执行全部指令的能力,没有执行到一半进行回滚的能力
排他性Redis会保证一个事务内的命令依次执行,而不会被其他命令插入

怎么用

常用命令

DISCARD取消事务,放弃执行事务块内的所有命令
EXEC执行所有事务块内的命令
MULTI标记一个事务块的开始
UNWATCH取消WATCH命令对所有key的监视
WATCH key [key…]监视一个或多个key,如果在事务执行之前这个(或这些)key被其他命令所改动,那么事务将被打断

正常执行

MULTI,EXEC

放弃事务

MULTI,DISCARD

一条命令出错都不执行

如果任何一个命令语法有错,Redis会直接返回错误,所有的命令都不会执行

错误的停下,正确的执行

前期语法没有错,编译能通过,执行EXEC后报错

Redis不提供事务回滚的功能,开发者必须在事务执行出错后,自行恢复数据库状态

watch监控

watch开启监控

Redis使用Watch来提供乐观锁定,类似与CAS(Check-and-Set)

watch命令是一种乐观锁的实现,Redis在修改的时候会检测数据是否被更改,如果更改了,则执行失败

unwatch放弃监控

小结

一旦执行了EXEC之前加的监控锁都会被取消掉了

当客户端连接丢失的时候(比如退出连接),所有的东西都会被取消监视

总结

开启:以MULTI开始一个事务

入队:将多个命令入队到事务中,接到这些命令并不会立即执行,而是放到等待执行的事务队列里面

执行:由EXEC命令触发事务

Redis管道

如何优化频繁命令往返造成的性能瓶颈?

问题由来:Redis是一种基于客户端-服务器模型以及请求/响应协议的TCP服务,一个请求会遵循以下步骤:

  1. 客户端向服务端发送命令分四步(发送命令->命令排队->命令执行->返回结果),并监听Socket返回,通常以阻塞模式等待服务端响应。
  2. 服务端处理命令,并将结果返回给客户端。

上述两步称为:Round Trip Time(简称RTT,数据包往返于两端的时间)

如果同时需要执行大量的命令,那么就要等待上一条命令应答后再执行,这中间不仅仅多了RTT,而且还频繁调用系统IO,发送网络请求,同时需要redis调用多次read()和write()系统方法,系统方法会将数据从用户态转移到内核态,这样就会对进程上下文有比较大的影响了,性能不太好。

管道(pipeline)可以一次性发送多条命令给服务端,服务端依次处理完毕后,通过一条响应一次性将结果返回,通过减少客户端与redis的通信次数来实现降低往返时间,pipeline实现的原理是队列,先进先出特性保证数据的顺序性。

定义

pipeline是为了解决RTT往返时,仅仅是将命令打包一次性发送,对整个Redis的执行不造成其他任何影响,即批处理命令变种优化措施,类似Redis的原生批命令(mget和mset)

Pipeline与原生批量命令对比

  1. 原生批量命令是原子性(如:mset,mget),pipeline是非原子性的
  2. 原生批量命令依次只能执行一种命令,pipeline支持批量执行不同命令
  3. 原生批量命令是服务端实现,而pipeline需要服务端与客户端共同完成

Pipeline与事务对比

  1. 事务具有原子性,管道不具有原子性
  2. 管道一次性将多条命令发送到服务器,事务是一条一条的发,事务只有在接收到exec命令后才会执行,管道不会
  3. 执行事务时会阻塞其他命令的执行,而执行管道中的命令时不会

使用pipeline注意事项

  1. pipeline缓冲的指令只是会依次执行,不保证原子性,如果执行中指令发生异常,将会继续执行后续的指令
  2. 使用pipeline组装的命令个数不能太多,不然数据量过大客户端阻塞的时间可能过久,同事服务端此时也被迫恢复一个队列答复,占用很多内存

Redis发布订阅

定义

是一种消息通信模式,发送者(PUBLISH)发送消息,订阅者(SUBSCRIBE)接收消息,可以实现进程间的消息传递,Redis可以实现消息中间件MQ的功能,通过发布订阅实现消息的引导和分流。

常用命令

PSUBSCRIBE pattern [pattern…]订阅一个或多个符合给定模式的频道
PUBSUB subcommand [argument [argument…]]查看订阅与发布系统的状态
PUBLISH channel message将信息发送到指定的频道
PUNSUBSCARIBE [pattern [pattern…]]退订所有给定模式的频道
SUBSCRIBE channel [channel …]订阅给定的一个或多个频道的信息
UNSUBSCRIBE [channel [channel …]]退订给定的频道

SUBSCRIBE channel [channel …]

订阅给定的一个或多个频道的信息

推荐先执行订阅后再发布,订阅成功之前发布的信息是收不到的

订阅的客户端每次可以收到一个3个参数的消息:

  1. 消息的种类
  2. 始发频道的名称
  3. 实际的消息内容

PUBLISTH channel message

发布消息到指定的频道

PSUBSCRIBE pattern [pattern…]

按照模式批量订阅,订阅一个或多个符合给定模式(支持*号?号之类的)的频道

每个模式以 * 作为匹配符,比如 it* 匹配所有以 it 开头的频道( it.news 、 it.blog 、 it.tweets 等等)。 news.* 匹配所有以 news. 开头的频道( news.it 、 news.global.today 等等),诸如此类。

PUBSUB subcommand [argument [argument…]]

查看订阅与发布系统状态

PUBSUB CHANNELS

由活跃频道组成的列表

PUBSUB NUMSUB [channel [channel…]]

某个频道有几个订阅者

PUBSUB NUMPAT

只统计使用PSUBSCRIBE命令执行的,返回客户端订阅的唯一模式的数量

案例演示

  1. 开启三个客户端,演示客户端A、B订阅消息,客户端C发布消息
    1. 客户端c
    2. 客户端a
    3. 客户端b
  2. 演示批量订阅和发布
  3. 取消订阅

总结

PUB、SUB缺点:

  1. 发布的消息在Redis系统中不能持久化,因此,必须先执行订阅,再等待消息发布。如果先发布了消息,那么该消息由于没有订阅者,消息将被直接丢弃
  2. 消息只管发送对于发布者而言消息是即发即失的,不管接收,也没有ACK机制,无法保证消息的消费成功

以上的缺点导致Redis的PUB、SUB模式就像小玩具,在生产环境中几乎无用武之地,为此Redis5.0版本新增Stream数据结构,不但支持多播,还支持数据持久化,相比PUB、SUB更加强大

Redis复制(replica)

是什么

主从复制,master以写为主,Slave以读为主,当master数据变化的时候,自动将新的数据异步同步到其他slave数据库

作用

  1. 读写分离
  2. 容灾恢复
  3. 数据备份
  4. 水平扩容支撑高并发

怎么用

  1. 配从(库)不配主(库)
  2. 权限细节
    1. master如果配置了requirepass参数,需要密码登录
    2. 那么slave就要配置masterauth来设置校验密码,否则的话master会拒绝slave的访问请求

基本操作命令

info replication

可以查看复制节点的主从关系和配置信息

replicaof 主库IP 主库端口

一般写进redis.conf配置文件内

slaveof 主库IP 主库端口
  1. 每次与master断开之后,都需要重新连接,除非配置仅redis.conf文件
  2. 在运行期间修改slave节点的信息,如果该数据库已经是某个主数据库的从数据库,那么会停止和原主数据库的同步关系转而和新的主数据库同步
slaveof no one

使当前数据库停止与其他数据库的同步,转成主数据库

案例演示

架构说明

  1. 一个Master两个Slave
  2. 拷贝多个redis.conf文件

小口诀

三边网络相互ping通且注意防火墙配置

三大命令
  1. 主从复制
    replicaof 主库IP 主库端口
    配从库不配主库
  2. 改换门庭
    slaveof 新主库IP 新主库端口
  3. 自立为王
    slaveof no one
修改配置文件细节操作

从机需要配置,主机不用

一主二仆
  1. 方案1
    配置文件固定写死
    1. 从机可以执行写命令吗?
    2. 从机切入点问题
    3. 主机shutdown后,从机会上位吗
      从机不动,原地待命,从机数据可以正常使用,等待主机重启
    4. 主机shutdown后,重启后主仆关系还在吗?从机还能否顺利复制?
      关系还在,能顺利复制
    5. 某台从机down后,master继续,从机重启后能跟上吗?
  2. 方案2
    命令操作手动指定
    从机停机去掉配置文件中的配置项,3台目前都是主机状态,各不从属,预设的从机上执行命令:slaveof 主库IP 主库端口

总结:

使用配置方式,持久稳定;使用命令方式,当次生效

薪火相传

上一个slave可以是下一个slave的master,slave同样可以接收其他slaves的连接和同步请求,那么该slave作为了链条中下一个的master,可以有效减轻主master的写压力

中途变更转向:会清除之前的数据,重新简历拷贝最新的

slaveof 新主库IP 新主库端口

反客为主

slaveof on one

使当前数据库停止与其他数据库

复制原理和工作流程

slave启动,同步初请

  1. slave启动成功连接到master后会发送一个sync命令
  2. slave首次全新连接master,依次完全同步(全量复制)将被自动执行,slave自身原有数据会被master数据覆盖清除

首次连接,全量复制

  1. master节点收到sync命令后会开始在后台保存快照(即RDB持久化,主从复制时会触发RDB),同时收集所有接收到的用于修改数据集命令缓存起来,master节点执行RDB持久化完后,master将rdb快照文件和所有缓存的命令发送到所有slave,以完成一次完全同步
  2. 而slave服务在接收到数据库文件数据后,将其存盘并加载到内存中,从而完成复制初始化

心跳持续,保持通信

repl-ping-replica-period 10

master发出PING包的周期,默认是十秒

进入平稳,增量复制

master继续将新的所有收集到的修改命令自动依次传递给slave,完成同步

从机下线,重连续传

master会检查backlog里面的offset,master和slace都会保存一个复制的offset还有一个masterId,offset是保存在backing中的。master只会把已经复制的offset后面的数据复制给slave,类似断点续传

复制的缺点

复制延时,信号衰减

由于所有的写操作都是先在master上操作,然后同步更新到slave上,所以从master同步到slave机器有一定的延时,当系统很繁忙的时候,延迟问题会更加严重,slave机器数量的增加也会使这个问题更加严重

master挂了怎么办?

默认情况下,不会在slave节点中自动重选一个master

每次都需要人工干预吗?

无人值守安装变成刚需

Redis哨兵(sentinel)

是什么

吹哨人巡查监控后台master主机是否故障,如果故障了根据投票数自动将某一个从库转换为新主库,继续对外开放

无人值守运维机制

哨兵作用:

  1. 监控redis运行状态,包括master和slave
  2. 当master 宕机,能自动将slave切换成新的master

作用

主从监控

监控主从redis库运行是否正常

消息通知

哨兵可以将故障转移的结果发送给客户端

故障转移

如果master异常,则会进行主从切换,将其中一个slave作为新master

配置中心

客户端通过连接哨兵来获得当前Redis服务的主节点地址

使用

Redis Sentinel架构

三个哨兵,自动监控和维护集群,不存放数据,只是吹哨人

一主二从,用于数据读取和存放

具体操作步骤

  1. /myredis目录下新建或者拷贝rentinel.conf文件,名字决不能错
  2. 先看看/opt目录下默认的sentinel.conf文件的内容
  3. 重点参数说明




  4. 本次案例哨兵sentinel文件通用配置
bind 0.0.0.0
daemonize yes
protected-mode no
port 26379
logfile "/myredis/sentine126379.log"
pidfile /var/run/redis-sentinel126379.pid
dir /myredis
sentinel monitor mymaster 192.168.110.132 6379 2
sentinel auth-pass mymaster 123456
bind 0.0.0.0
daemonize yes
protected-mode no
port 26380
logfile "/myredis/sentine126380.log"
pidfile /var/run/redis-sentinel126379.pid
dir /myredis
sentinel monitor mymaster 192.168.110.132 6379 2
sentinel auth-pass mymaster 123456
bind 0.0.0.0
daemonize yes
protected-mode no
port 26381
logfile "/myredis/sentine126381.log"
pidfile /var/run/redis-sentinel126379.pid
dir /myredis
sentinel monitor mymaster 192.168.110.132 6379 2
sentinel auth-pass mymaster 123456
  1. 先启动一主二从3个redis实例,测试正常的主从复制
  2. 再启动三个哨兵,完成监控
  3. 启动3个哨兵监控后再测试一次主从复制
  4. 原有的master挂了
    1. 两台从机数据是否OK?
      两台从机数据OK
    2. 是否会从剩下的2台机器上选出新的master
      会从剩下两台机器上选出新的master
    3. 之前宕机的master机器重新回来,谁会是master,会不会双master冲突
      之前宕机的master机器重新回来后,会变为slave,需要设置访问新主机的密码
  5. 对比配置文件
    总结:
  6. 文件的内容,在运行期间会被sentinel动态进行更改
  7. Master-Slave切换后,master_redis.conf、slave_redis.conf和sentinel.conf的内容都会发生改变,即master_redis.conf中会多一行slaveof的配置,sentinel.conf的监控目标会随之调换

哨兵运行流程和选举原理

当一个主从配置的mster失效之后,sentinel可以选举出一个新的master,用于自动接替原master的工作,主从配置中的其他redis服务器自动指向新的master同步数据。一般建议sentinel采取奇数台,防止某一台sentinel无法连接到mster导致误切换

运行流程,故障切换

  1. 三个哨兵监控一主二从,正常运行中…
  2. SDown主观下线(Subjectively Down)
    1. SDOWN(主观不可用)是单个sentinel自己主观上检测到的关于master的状态,从sentinel的角度来看,如果发送了PING心跳后,在一定时间内没有收到合法的回复,就会达到SDOWN的条件。
    2. sentinel配置文件中的down-after-millisecondes设置了判断主观下线的时间长度
  3. ODown客观下线(Objectively Down)
    1. ODOWN需要一定数量的sentinel,多个哨兵达成一致意见才能认为一个master客观上已经宕机
  4. 选举出领导者哨兵
    1. 当主节点被判断客观下线以后,各个哨兵节点会进行协商,先选出一个领导者哨兵节点并由该领导者节点进行failover(故障迁移)
    2. 哨兵领导者怎么选出来的?
      1. Raft算法
  5. 由领导者哨兵开始推动故障切换流程并选出一个新的master
    1. 某个Slave被选中成为新Master
      选出新Master的规则,剩余slave节点健康前提下:
      1. redis.conf文件中,优先级slave-priority或者replica-priority最高的从节点(数字越小优先级越高)
      2. 复制偏移位置offset最大的从节点
      3. 最小RunID的从节点 字典顺序,ASCII码
    2. 执行slaveof no one命令让选出的从节点成为新的主节点,并通过slaveof命令让其他节点成为其从节点
      1. Sentinel leader会对选举出的新master执行slaveof no one操作,将其提升为master节点
      2. Sentinel leader向其它slave发送命令,让剩余的slave成为新的master节点的slave
    3. 将之前已下线的老master设置为新的选出的master的从节点,当老master重新上线后,他会成为新master的从节点Sentinel leader会让原来的master降级为slave并恢复正常工作

哨兵使用建议

  1. 哨兵节点的数量应为多个,哨兵本身应该集群,保证高可用
  2. 哨兵节点的数量应该是奇数
  3. 各个哨兵节点的配置应该一致
  4. 如果哨兵节点部署在Docker等容器里面,尤其要注意端口的正确映射
  5. 哨兵集群+主从复制,并不能保证数据零丢失

Redis集群(cluster)

是什么

由于数据量过大,单个Master复制集难以承担,因此需要对多个复制集进行集群,形成水平扩展,每个复制集只负责存储整个数据集的一部分,这就是Redis的集群,起作用是提供在多个Redis节点间共享数据的程序集

总结:Redis集群是一个提供在多个Redis节点间共享数据的程序集,Redis集群可以支持多个Master

作用

  1. Redis集群支持多个Master,每个Master又可以挂载多个Slave
    1. 读写分离
    2. 支持数据的高可用
    3. 支持海量数据的读写存储操作
  2. 由于Cluster自带Sentinel的故障转移机制,内置了高可用的支持,无需再去使用哨兵功能
  3. 客户端与Redis的节点连接,不再需要连接集群中的所有节点,只需要任意连接集群中的一个可用节点即可
  4. 槽位slot负责分配到各个物理服务节点,由对应的集群来负责维护节点、插槽和数据之间的关系

集群算法-分片-槽位slot

redis集群的槽位slot

Redis集群没有使用一致性hash,而是引入了哈希槽的概念

Redis集群由16384个哈希槽(官网建议使用0-1000个),每个key通过CRC16校验后对16384取模来决定放置哪个槽,集群的每个节点负责一部分hash槽

举个例子,比如当前集群由3个节点,那么:

redis集群的分片

分片是什么

使用Redis集群时,我们会将存储的数据分散到多台redis机器上,这称为分片。简言之,集群中的每个Redis实例都被认为是整个数据的一个分片

如何找到给定的key的分片

为了找到给定key的分片,我们对key进行CRC16(key)算法处理并通过对总分片数量取模。然后,使用确定性哈希函数,这意味着给定的key将多次时钟映射到同一个分片,我们可以推断将来读取特定key的位置。

槽位slot和分片的优势

  1. 方便扩缩容和数据分派查找
    1. 这种结构很容易添加或者删除节点,比如如果我想新添加这个节点D,我需要从节点A,B,C中得到部分槽到D上,如果我想移除节点A,需要将A中的槽位移到B和C节点上,然后将没有任何槽位的A节点从集群中移除即可。由于从一个节点将哈希槽位移动到另一个节点并不会停止服务,所以无论添加删除或者改变某个节点的哈希槽的数量都不会造成集群不可用状态
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

还能做什么

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值