Redis前言!
一、在编写程序的过程中为什么需要redis呢?
1)、企业需求
1.1、高并发
1.2、高可用
1.3、高性能
1.4、有着海量用户
2)、关系型数据库如(Mysql)-问题
2.1、性能瓶颈:磁盘IO性能底下
2.2、扩展瓶颈:数据关系复杂,扩展性差,不便于大规模集群
3)、Redis的优势
3.1 、内存存储-降低磁盘的读写次数
3.2、不存储关系,仅存储数据-数据间关系,越简单越好
Redis简介
一句话:Redis(Remote Dlctionary Server)是使用C语言开发的一个开源的高性能键值对(Key—Value)数据库
特征!
1、数据间没有必然哦关联关系
2、高性能。官方提供测试数据,50个并发执行100000个请求,读写的熟读是110000次/s,写的速度是81000次/s。
支持多种数据结构
- 字符串类型 ( String )
- 列表类型 (list)
- 散列类型 (hash)
- 集合类型 (set)
- 有序集合类型 (sorted_set)
注:持久化支持,可以支持数据灾难恢复。
Nosql数据库
特点:
1、可扩容,可伸缩
2、大数据下高性能
3、灵活的数据模型
4、高可用
常见的 Nosql 数据库:
Redis
HBase
MongoDB
memcache
关于Redis的安装
1.1 、Redis 下载
下载地址: https://redis.io/download
在实际开发中 Redis 都在 Linux 下工作, Linux 版本: Redis6
1.2、Redis 安装
前提是大家需要安装:Linux-CentOS7 开发环境。
安装Xshell7(一款可以远程登录Linux的软件,其他远程登陆软件也是可以) 登录CentOS7软件
(关于具体的安装教程 鲨鱼建议大家按照网上博主的教程进行安装,原因是更加的详细和透彻,鲨鱼在这里介绍一位 CSDN博主的安装教程, 有兴趣的鱼友可以按照他的方式进行安装:Redis的安装与配置_redis安装配置-CSDN博客 )
进入正题了鲨友们。。
接下来鲨鱼就带着大家一起开始对Redis进行一番透彻的打击吧!!
Redis指令
Redis 命令十分丰富,包括的命令组有 Cluster、Connection、Geo、Hashes、HyperLogLog、 Keys、Lists、Pub/Sub、Scripting、Server、Sets、Sorted Sets、Strings、Transactions 一共 14个 redis 命令组两百多个 redis 命令。
1、基础操作
1.1、set key value ;设置 key,value 数据
1.2、get key ;根据key查询对应的 value 值
1.3、clear ;清除屏幕中的信息
1.4、quit/exit ;退出客户端 (说明redis 服务还没有结束)
1.5、help ;获取命令帮助文档,获取组中所有命令信息
2、对key(键)的操作
2.1、keys* ;查看当前库所有 key (匹配:key*1)
2.2、exists key ;判断某个key是否存在
2.3、type key ;查看你的key是什么类型
2.4、del key ;删除指定的key数据
2.5、unlink key ;根据value选择非阻塞删除
2.6、expire key 10 ;给key设置10秒钟过期时间
2.7、ttl key ;查看key还有多少秒后过期 (-1表示永不过期,-2表示已经过期)
3、对数据库(DB)的操作
select :命令切换数据库
redis安装后会有16个数据库,0-15
3.1、dbsize ;查看当前数据库的key数量
3.2、flushdb ;清空当前数据库
3.3、flushall ; 清空全部数据库
Redis五大数据类型/结构
redis 数据存储格式
一句话:redis本身就是一个 Map,其中所有的数据都是采用 key : value 的形式从存储
key 是字符串,value 是数据,数据支持多种类型/结构
1、Redis 数据类型-5种常用
1.1、string
1.2、List
1.3、set
1.4、Hash
1.5、sorted_set
String 类型说明:
1. String是Redis最基本的类型,一个Key对应一个value。
2. String类型是二进制安全的,Redis 的 String可以包含任何数据,比如jpg图片或者序列化的对象。
3. String类型是 Redis 基本的数据类型,一个Redis中字符串Value最多可以是512M。
String 常用指令:
- set <key><value> 添加键值对
- get <key>查询对应键值
- append <key><value>将给定的<value>追加到原值的末尾
- strlen <key>获得值的长度
- setnx <key><value>只有key不存在时,设置key的值
- mset <key1><value1><key2><value2>...,同时设置一个或者多个key-value对
- mget <key1><key2><key3>...,同时获取一个或者多个value
- msetnx <key1><value1><key1><value2> ...,同时设置一个或者多个 key-value对,当且仅当所有给定的 key 都不存在,原子性,有一个失败则都失败。
- setex <key><过期时间><value> 设置键值对的过期时间,单位秒。
- getset <key><value>,以新换旧,设置了新值的同时获得旧值
list 类型说明:
一句话:list类型,保存多个数据,底层使用的是双向链表存储结构实现
list存储结构示意图
解图:
- Redis 列表是简单的字符串列表,按照插入的顺序进行排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。
- 底层是一个双向链表,对两端的操作性能高,通过索引下标的操作中间的节点性能较差。
list 常用指令:
- lpush/rpush <key1><value1><value2><value3> ... 从左边/右边插入一个或多个值
- lpop/rpop <key>从左边/右边吐出值
- rpoplpush <key1><key2>从<key1>列表吐出一个值,插到<key2>列表左边
- lrange <key><start><stop>按照索引下标获得元素(从左到右)
- lindex <key><index>按照索引下标获得元素(从左到右)
- llen <key>获得列表长度
- lrem <key><n><value>从左边删除n个value(从左到右)
- lset <key><index><value>将列表key下标为index的值替换成value
set 类型说明:
set底层是dict字典,字典是用哈希表实现的
set指令:
- sadd <key><value1><value2>... ,将一个或者多个 member 元素加入到集合key中,已经存在的member将被忽略
- smembers <key><value>判断集合<key>是否含有该<value>值,有1,没有0
- scard <key>返回该元素的集合个数
- srem <key><value1><value2>...,删除元素中的某个元素
- spop <key>随机从该集合中吐出某个元素
- smove <source><destination> value,把集合中一个值从一个集合移动到另一个集合
- sinter <key1><key2>返回两个集合的交集元素
- sunion <key1><key2>返回两个集合的并集元素
- sdiff <key1><key2>返回两个集合的差集元素(key1中的,不包含key2中的)
hash 类型说明:
一句话:Redis hash 是一个键值对集合,hash适合用于存储对象,类似 Java里面的 Map<String,Object>。
hash存储结构示意图
hash 指令:
- hset <key><field><value>给<key>集合中的 <field>键赋值<value>
- hget <key1><field>从<key1>集合<filed>取出 value
- hmset <key1><field1><field2><field2><value2> ...,批量设置hash的值
- hmget <key1><field1><field2> ...,批量取出hash 的 field的值
- hexists <key1><field>查看哈希表 key中,给定域的 field 是否存在
- hkeys <key>列出该hash集合所有的 field
- hvals <key>列出该hash集合所有的 value
- hincrby <key><field><increment>为哈希表 key中的域 field 的值加上增量1 ,-1
- hsetnx <key><field><value>将哈希表 key中的域 field 的值设置为 value ,当且仅当域 field 不存在
有序集合 Zset(sorted_set)说明:
有序集合 sorted_set 指令:
- zadd <key><score1><value1><vlaue2><vlaue3> .. 将一个或者多个 member 元素及其 score值加入到有序集 key 当中
2. zrange <key><start><stop> [WITHSCORES] 返回有序集 key 中,下标在<start><stop>之间的元素,带 WITHSCORES,可以让分数一起和值返回结果集。
3. zscore <key><member>返回有序集key中,成员 member 的 score 值
4. zrangebyscore key min max [withscores] [limit offset count] 返回有序集 key 中,所有 score 值介于min 和 max 之间
5. zincrby <key><increment><value> 为元素的 score 加上给增量
6. zrem <key><value>删除该集合下,指定值的元素
7. zcount <key><min><max> 统计该集合,分数区间内的元素个数
8. zrank <key><value>返回值在集合中的排名,从0开始。
发布和订阅
1、发布和订阅是什么?
一句话:Redis 发布订阅(pub/sub)是一种消息通信模式,发送者(pub)发送消息,订阅者(sub)接收消息
一图千言
客户端订阅频道示意图
当这个频道发布消息后,消息就会发送给订阅的客户端
2、如何理解发布和订阅模式?
2.1、任务队列
- 顾名思义,就是“传递消息的队列”
- 与任务队列进行交互的实体有两类,一类是生产者(producer),另一类是消费者(consumer)。生产者将需要处理的任务放入到队列中,而消费者则不断地从任务队列中读入任务信息并执行。
2.2、如何理解
- 可以这样简单的理解:
1)、Subscriber:收音机,可以收入到多个频道,并以队列的形式显示
2)、Publisher:电台,可以往不同的 FM 频道中发消息
3)、Channel:不同频率的 FM 频道
- 从Pub/Sub 的机制来看,他更像是一个广播系统,多个订阅者(Subscriber)可以订阅多个频道(Channel),多个发布者(Publisher)可以往多个频道 (Channel)中发布消息。
3、发布订阅模式分类
3.1、一个发布者,多个订阅者
- 主要应用:通告、公告
- 可以作为消息队列或者消息管道
3.2、多个发布者,一个订阅者
- 各应用程序作为 Publisher 向 Channel 中发送消息,Subscriber 端收到消息后执行相应的业务逻辑,比如写数据库,显示...
- 主要应用:排行榜、投票、计数
3.3、多个发布者,多个订阅者
- 可以向不同的 Channel 中发送消息,由不同的 Subscriber接收到
- 主要应用:群聊,聊天
4、命令实现发布和订阅
4.1、发布订阅操作
1)、PUBLISH channel msg ;将信息message 发送到指定的频道 channel
2)、SUBSCRIBE channel [channel ...] ;订阅频道,可以同时订阅多个频道
3)、UNSUBSCRIBE [chammel ...] ;取消订阅指定的频道,如果不指定频道,则会取消订阅所有频道
4)、PSUBSCRIBE pattern [patten ...] ; 订阅一个或者多个符合给定模式的频道,每个模式以 * 作为匹配符,比如 it* 、;匹配所有以 it 开头的频道
5)、PUNSUBSCRIBE [pattern [pattern...] ] ;退定指定的规则,如果没有参数则会退订所有规则
4.2、代码快速入门
1)、打开一个客户端订阅 channel1
2)、打开另外一个客户端,给 channel1 发布消息 hello
- 返回的 1,是订阅者数量
- 发布的消息没有持久化
- 订阅的客户端,只能收到订阅后发布的消息
Redis 持久化-RDB
1、持久化方案
1.1、RDB(Redis DataBase)
1.2、AOF(Append Of File)
2、RDB是什么?
在指定的时间间隔内将内存中的数据快照写入磁盘,也就 Snapshot 快照,恢复时,将快照文件读到内存。
3、RDB持久化流程
一图胜前言
对上图的理解
具体流程如下:
1)、redis客户端执行 bgsave 命令或者自动触发 bgsave 命令。
2)、主进程判断当前是否已经存在正在执行的子进程,如果存在,那么进程直接返回;
3)、如果不存在正在执行的子进程,那么就 fork 一个新的子进程进行持久化数据,fork 过程是阻塞的,fork操作完成后主进程即可执行其他操作;
4)、子进程先将数据写入到 临时的rdb文件中,待快照数据写入完成后再原子替换旧的rdb文件;
3)、同时发送信号给主进程,通知主进程 rdb 持久化完成,主进程更新相关的统计信息。
3.1、小结
- 整个过程中,主进程是不进行任何 IO 操作的,这就确保了极高的性能
- 如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那么RDB方式要比AOF方式更加的高效
- RDB 的缺点是最后一次持久化的数据可能丢失
- 如果你是正常关闭Redis,仍然会进行持久化,不会造成数据丢失
- 如果是Redis 异常终止/宕机,就可能造成数据丢失
4、RDB 配置
4.1、介绍
在redis.conf 中配置文件名称,默认为 dump.rdb
4.2、如何配置
默认为Redis 启动时命令行所在的目录下
进入到/usr/local/bin 目录下, 启动 Redis, 这个 ./ 就是 /usr/local/bin , 如果你在 /root/ 目录下启动 Redis , 那么 ./ 就是 /root/ 下了 , 这点请小伙伴注意一把
4.2、相关配置
配置如图
注意需要理解这个时间观念
4.2.1、如果我们没有开启 save 的注释,那么在退出的时候 Redis 也会进行备份,更新 dupm.db
4.3、save VS bgsave
- save:save时只是暂时保存,其他不管,全部阻塞。手动保存,并不建议。
- bgsave:Redis 会在后台异步进行快照操作,快照的同时还可以相应客户端的请求。
- 可以通过 lastsave 命令获取最后一次成功执行快照的时间(unix 时间戳),可以使用工具转换。
4.4、flushall(小心使用)
- 执行flushall 命令,也会产生 dump.rdb 文件,数据为空。
- Redis Flushall 命令用于清空整个 Redis 服务器的数据。
4.5、Save
4.5.1、格式:save 秒钟 写操作次数,如图
4.5.2、RDB 是整个内存的压缩过的 Snapshot,RDB 的数据结构,可以配置复合的快照出发条件。
4.5.3、禁用:给 save 传入空字符串。
4.6、stop-writes-on-bgsave-erro
4.6.1、配置如图
4.6.2、对于存储到磁盘中的快照,可以设置是否进行压缩存储。如果是的话,redis 会采用 LZF 算法进行压缩。
4.6.3、如果你不想耗费 CPU 来进行压缩的话,可以设置为关闭此功能,默认yes
4.7、 rdbcompression
4.7.1、配置如图
4.7.2、在存储快照后 ,还可以让redis 使用 CRC64算法来进行数据校验,保证文件是完整的
4.7.3、但是这样做会增加大约 10%的性能消耗,如果希望获取到最大的性能提升,可以关闭此功能,推荐 yes
4.8、动态停止 RDB
4.8.1、动态停止RDB:redis-cli config set save " "
4.8.2、说明:save后给空值,表示禁用保存策略
4.9、RDB 备份&恢复
4.9.1、Redis 可以充当缓存,对项目进行优化,因此重要的数据建议在 mysql 保存一份。
4.9.2、从设计层面说,Redis 的内存数据,都是可以重新获取的(可以是来自程序,也可以来自mysql)
4.9.3、因此我们这里说的备份&恢复 主要是给大家说明一下 Redis启动时,初始化数据是从dump.rdb 来的,这个机制
4.10、RDB 的持久化小结
4.10.1、优势
- 适合大规模的数据恢复
- 对数据的完整性和一致性要求不高更适合使用
- 节省磁盘空间
- 恢复速度快
4.10.2、劣势
- 虽然Redis 在fork时使用了写时拷贝技术(Copy-On-Write),但是如果数据庞大时还是比较消耗性能。
- 在备份周期在一定间隔时间做一次备份,所以如果 Redis 意外 down 掉的话(如果正常关闭redis,仍然会进行RDB备份,不会丢失数据),就是会丢失最后一次快照后的所有修改。
Redis 持久化-AOF
1、AOF是什么?
- AOF(Append Only FiIe)
- 以日志的形式来记录每个写的操作(增量保存),将Redis 执行过的所有写指令记录下来(比如set/del 操作会记录,读操作 get 不记录)
- 只许追加文件但不可以改写文件
- redis 启动之初会读取文件重新构建数据
- redis 重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作
2、AOF 持久化流程
2.1、持久化流程示意图
2.2、解读上图
- 客户端的请求写命令会被 append 追加到 AOF 缓冲区
- AOF 缓冲区根据 AOF 持久化策略 [always,everysec,no]将操作 sync 同步到磁盘的 AOF 文件中
- AOF 文件大小超过重写策略或手动重新时,会对AOF 文件 rewrite 重写,压缩 AOF 文件容量
- Redis 服务重启时,会重新 load 加载 AOF 文件中的写操作达到数据恢复的目的
3、AOF开启
3.1、在redis.conf 中配置文件名称,默认 appendonly.aof
3.2、AOF文件的保存路径,同 RDB 的路径一致
3.3、AOF 和 RDB 同时开启,系统默认取 AOF 的数据。
3.4、当开启AOF后,Redis从 AOF 文件取数据。
-- 关闭 redis --
4、AOF 启动/修复/恢复
4.1、基本说明
AOF的备份机制和性能虽然和 RDB 不同,但是备份和恢复的操作同 RDB 一样,都是拷贝备份文件,需要恢复时再拷贝到 Redis 工作目录下,启动系统即加载
5、正常恢复
- 修改默认的 appendonly no ,改为 yes
- 将有数据的 aof 文件定时备份,需要恢复时复制一份保存到对应目录
- 恢复:重启 redis 然后重新加载
6、异常恢复
- 如遇到 AOF 文件损坏,通过 /usr/local/bin/redis-check-aof --fix appendonly.aof 进行恢复
- 建议先:备份被写坏的AOF文件
- 恢复:重启 redis,然后重新加载
- 案例:
7、同步频率设置
7.1、配置位置
7.2、解读上图
1)、appendfsync always
始终同步,每次redis 的写入都会立刻记入日志;性能较差但数据完整性比较好
2)、appendfsync everysec
每秒同步,每秒记入日志一次,如果宕机,本秒的数据可能丢失。
3)、appendfsync no
redis 不主动进行同步,把同步时机交给操作系统
8、Rewrite 压缩
1、rewrite 重写介绍
1)、 AOF 文件越来越大,需要定期对 AOF 文件进行重写达到压缩
9、重写出发配置
9.1、手动触发
直接调用 bgrewriteaof 命令
9.2、自动触发
1、auto-aof-rewrite-min-size: AOF 文件最小重写大小 , 只有当 AOF 文件大小大于该值时候才能 重写 , 默认配置 64MB2、auto-aof-rewrite-percentage: 当前 AOF 文件大小和最后一次重写后的大小之间的比率等于3、或者大于指定的增长百分比,如 100 代表当前 AOF 文件是上次重写的两倍时候才重写系统载入时或者上次重写完毕时, Redis 会记录此时 AOF 大小,设为base_size,如果 Redis 的 AOF 当前大小>= base_size +base_size*100% (默认)且当前
大小 >=64mb( 默认 ) 的情况下, Redis 会对 AOF 进行重写
10、redis 持久化小结
10.1、优势
- 备份机制更稳健,丢失数据概率更低
- 可读的日志文本,通过操作 AOF 文件,可以处理误操作
10.2、劣势
- 比起 RDB 占用更多的磁盘空间
- 恢复备份速度要慢
- 每次读写的都同步的话,有一定的性能压力
11、RDB 还是 AOF??
11.1、 官方文档地址: https://redis.io/topics/persistence
11.2、官方推荐两个都启用
11.3、如果只做缓存:如果你希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化方式
Redis_事务_锁机制_秒杀
1、Redis 事务是什么?
- Redis 事务是一个单独的隔离操作:事务中的所有命令都会序列化、桉顺序地执行
- 事务在执行的过程中,不会被其他客户端发来的命令请求所打断
- Redis 事务的主要作用就是串联多个命令防止别的命令插队
2、Redis 事务三大特性
2.1、单独的隔离操作
2.1.1、事务中的所有命令都会序列化、按顺序地执行
2.1.2、事务在执行的过程中,不会被其他客户端发送来的命令请求所打断
2.2、没有隔离级别的概念
2.2.1、队列中的命令(指令),在没有提交前都不会实际被执行
2.3、不保证原子性
2.3.1、事务执行过程中,如果有指令执行失败,其他的指令仍然会被执行,没有回滚。
3、事务的相关指令:Multi、Exec、discard
3.1、一图胜千言
Redis 事务指令示意图
解读上图:
- 从输入 Multi 命令开始,输入的命令都会依次进入命令队列中,但不会执行(类似 Mysql 的 start transaction 开启事务)
- 输入 Exec 后,Redis会将之前的 命令队列中的命令依次执行(类似 Mysql 的 commit 提交事务)
- 组队的过程中可以通过 discard 来放弃组队(类似 Mysql 的 rollback 回顾事务)
- Redis 事务和 Mysql 事务本质是完全不同的。
4、快速入门
需求:请依次向 Redis 中,添加三组数据,k1-v1、k2-v2、k3-v3,要求使用 Redis 的事务完成本次任务。
注意事项和细节:
1、组队过程中,可以通过 discard 来放弃组队
2、如果在组队阶段报错,会导致 exec 失败,那么事务的所有指令都i不会被执行
3、如果组队成功,但是指令不能正常执行的,那么 exec 提交,会出现有成功有失败情况,也就是事务得到部分执行,这中请款下,Redis 事务不具备原子性。
5、事务冲突及解决方案
1、看一个经典案列;
1)、一个请求想要购买6张票
2)、一个请求想要购买5张票
3)、一个请求想要购买1张票
- 解读上图:
- 如果没有控制,会造成超卖现象
- 如果3个指令,都得到执行,最后剩余的票数是 -2
悲观锁、乐观锁的介绍。
悲观锁
1、工作示意图:
- 解读上图:
- 悲观锁(Pessimistic Lock),顾名思义,就是很悲观,每次去拿数据的时候都会认为别人会修改,所以每次在拿数据的时候都会上锁。
- 这样别人,在请求想要拿这个数据的时候就会 block 知道他拿到锁
- 悲观锁是锁设计理念,传统的关系型数据库里面就用到了很多这种机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁
乐观锁
1、工作示意图
- 解读上图:
- 乐观锁(Optimistic Lock),顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁。
- 但是会在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。
- 乐观锁适用于多读的应用类型,这样可以提高吞吐量,Redis 就是利用这种 check-and-set 机制实现事务的。
- 乐观锁是锁的设计理念
watch & unwatch
1、watch
- 基本语法:watch key[key...]
- 在执行 mulit 之前,先执行 wach key1[key2],可以监视一个(或多个)key,如果在事务执行之前这个(或这些)key 被其他命令所改动,那么事务将被打断
- 可以结合乐观锁机制进行理解。
2、unwatch
- 取消 watch 命令对所有key 的监视
- 如果在执行 watch 命令后,exec 命令或 discard 命令先被执行了的话,那么就不需要再执行 unwatch 了。
主从复制
废话不多说,直接上图
- 解读上图:
- 上图描述了主机数据更新后,会自动同步到Master/Slaver 机制
- Master 以写为主,Slaver 以读为主
- 好处:读写分离,提升效率(理解:读写分离后,将读和写操作分布到不同的Redis,减少单个Redis 的压力,提升效率)
- 好处:容灾快速恢复(理解:如某个 salver,不能正常工作,可以切换到另一个 salver)
- 主从复制,要求是 1 主都从,不能有多个Master(理解:如果有多个主服务器 Master,那么 slaver 不能确定和哪个 Master 进行同步,出现数据絮乱)
- 要解决主服务器的高可用性,可以使用 Redis 集群。
搭建一主多从
需求说明
1)、搭建主从复制结构
2)、这里我们搭建一主二仆即可,其他 slaver 可以依次完成
3)、开始分析我的演示结果
注意:将redis.conf 文件可以拷贝到 自己单独的一个文件中,这里鲨鱼将该文件拷贝到
itemsredis 文件中 如下:
对redis.conf,进行如下配置。
创建3个文件,并对文件的内容进行编辑 如下:
随后启动三台 redis
连接3个redis 服务器,info replication 打印主从复制的相关信息,如下图,这时候三台redis 都是 Master
将 6380和6381 设置成 slaver,6379作为主机
- 在 slaver 执行命令,成为某个实例的从服务器
- 指令说明:slaverof <masster_ip><master_port>
在主机上写,在从机上读取数据,如果在从机上写入数据,就报错
到此一个基本的主从复制就ok了。
主从复制原理
1、原理示意图
解读上图:
- Slave 启动成功连接到 Master 后会发送一个 sync 命令
- Master 接到命令启动后后台的存盘进程,同时收集所有接到的用于修改数据集命令,在后台进程执行完毕之后。master 将传送整个数据文件到 slave,一次性完成同步。
- Slave 服务在接收到数据库的数据文件后,将其存盘并加载到内存中,即 全量复制
- Master 数据变化了,会将新的收集到的修改命令依次传给 Slave,完成同步,即 增量复制
- 但是只要是重新连接 master,一次完成同步(全量复制)将被自动执行。
一主二仆
1、如果服务器 down 了,重新启动,仍然可以获取 Master 的最新数据
2、进行实验
3、如果主服务 down掉了,从服务器并不会抢占主服务,当主服务器恢复后,从服务器仍然指向原来的主服务器。
4、实验
薪火相传
1、示意图
2、解读上图
- 上一个 slave 可以是下一个 slave 的 Master,Slave 同样可以接收其他 slaves 的连接和同不请求,那么该 slave 作为链条中的下一个的 master ,可以有效减轻 master的写压力,去中心化降低风险
- 用 slaveof <master_ip><master_port?
- 风险是一旦某个 slave 宕机,后面的 slave 都没法同步
- 主机挂了,从机还是从机,无法写数据
3、实验
3.1、将 6381 的主机设置为 6380,他的数据同步就是从 6380 中获取的
3.2、查看6380 和 6379
反客为主
1、在薪火相传的结构下,当一个 master 宕机后,只想Master 的 slave 可以升为 master,其后面的 slave 不用做任何修改
2、用 slaveof no one 将从机变为主机(提示:可以使用哨兵模式)
3、实验
哨兵模式(sentonel)
1、工作示意图
2、哨兵模式(如上图):反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将库转换为主库
3、实验
1)、调整一主二仆模式,6379 带着 6380、6381,根据前面讲解的调整即可
2)、创建 /items/sentinel.conf,名字不能乱写,按照指定的来
sentinel monitor redis_master 127.0.0.1 6379 1
说明:
- redis_master 为监控对象起的服务名称
1 表示至少有多少个哨兵同意迁移的数量,这里我配置1 表示只有 1个哨兵同意迁移就可以切换
3)、启动哨兵,注意看哨兵的端口是 26379
4)、当主机挂掉后,从机选举中产生新的主机
5)、如果原来的主机重启,会自动成为主机
注意事项和细节
1、在哨兵模式下,主机 down后的执行流程分析
2、解读上图
- 优先级在 redis.conf 中默认:replica-priority 100,值越小优先级越高
- 偏移量是指获得原主机数据的量,数据用量最高的优先级高
- 每个 redis 实例启动后都会随机生成一个 40 位的 runid,值越小优先级越高
集群
为什么需要集群--高可用性
1、生产环境的实际需要和问题
- 容量不够,redis如何进行扩容?
- 并发写操作,redis 如何分摊?
- 主从模式,薪火相传模式,主机宕机,会导致ip地址发生变化,应用程序中配置需要修改对应的主机地址、端口等信息
2、传统解决方案-代理主机来解决
解读上图
- 客户端请求先到代理服务器
- 由代理服务器进行请求转发到对应的业务处理服务器
- 为了高可用性,代理服务、A服务、B服务、C服务都需要搭建主从结构(至少是一主一从),这样就需求搭建至少 8 台服务器
- 这种方案的缺点是:成本高,维护困难,如果是一主多从,成本就会更高。
3、redis3.0 提供解决方案-无中心化集群配置
解读上图:
- 各个redis 服务任然采用主从结构
- 各个redis 服务是连通的,任何一台服务器,都可以作为请求入口。
- 各个redis 服务器因为是连通的,可以进行请求转发。
- 这中方式,就是无中心化集群配置。
- 无中心化集群,还会根据 key 值,计算 slot,把数据分散到不同的主机,从而缓解单个主机的存取压力
- Redis 推荐使用无中心化集群配置
- 在实际的生产环境各个Redis 服务器,应当部署在不同的机器(防止机器宕机,主从复制失效
集群介绍
1、redis 集群实现了对 Redis 水平的扩容,即启动N个 redis 节点,将整个数据库分布储存在这N个节点中,每个节点储存数据的 1/N
2、redis 集群通过分区(parition)来提供一定程度的可用性(availability):即集群中有一部分节点失效或者无法进行通讯,集群也可以继续处理命令请求。
redis 集群搭建
图解说明:
Redis 集群的使用
1、什么是 slots
1)redis集群启动后,会看到如下提示
2)一个redis 集群包含 16384 个插槽(hash slot),编号从0~16383,Redis中每个键都属于这 16384 个插槽的其中一个。
3)集群使用公式 CRC16(key)%16384 来计算键 key 属于哪个槽,其中 CRC16(key) 语句用来计算键 key 的 CRC16 校验
- 节点 A 负责处理 0 号至 5460 号插槽。- 节点 B 负责处理 5461 号至 10922 号插槽。- 节点 C 负责处理 10923 号至 16383 号插槽。
2、在集群中录入值
5) 可以通过{}来定义组的概念,从而使 key 中{}内相同内容的键值对放到一个 slot 中去
3、查询集群中的数值
1) 指令 : CLUSTER KEYSLOT <key> 返回 key 对应的 slot 值2) 指令 : CLUSTER COUNTKEYSINSLOT <slot> 返回 slot 有多少个 key3) 指令 : CLUSTER GETKEYSINSLOT <slot><count> 返回 count 个 slot 槽中的键
Redis集群的优缺点
优点:
- 实现扩容
- 分摊压力
- 无中心配置相对简单
缺点:
- 多建操作是不被支持的
- 多建的Redis事务是不被支持的,Lua脚本不被支持
- 由于集群方案出现比较晚,很多公司已经采用其他的集群方案,而其他的方案要迁移到 redis cluster,需要的是整体迁移,而不是逐步过渡,复杂度过大。
Redis缓存解决方案
缓存穿透
1、问题描述--如图
-- 缓存穿透的原因
1) key 对应的数据在数据源并不存在,每次针对此 key 的请求从缓存获取不到,请求都会压到数据源, 可能压垮数据源
-- 缓存穿透的表现/现象
1) 应用服务器压力变大
2) Redis 命中率降低
3) 一直查数据库
-- 解决方案/思路
1) 对空值缓存
如果一个查询返回的数据为空,我们仍然把这个空结果(null)进行缓存,设置空结果的过期时间应该短些,最长不超过五分钟
2) 设置可访问的名单(白名单)
定义一个可以访问的名单,每次访问和白名单的 id 进行比较,如果访问 id 不在白名单里面,进行拦截,不允许访问, 比如使用 bitmaps 实现.
3) 采用布隆过滤器
缓存击穿
问题描述-如图
-缓存击穿的原因
1) key 对应的数据存在,但在 redis 中过期,此时若有大量并发请求过来,这些请求发现缓存过期, 会从后端 DB 加载数据并回设到缓存,这时大并发的请求可能会瞬间把后端 DB 压垮。
-- 缓存击穿的现象/表象
-- 解决方案
1) 预先设置热门
在 redis 高峰访问之前,把一些热门数据提前存入到 redis 里面,加大这些热门数据 key 的时长
2) 实时调整
现场监控哪些数据热门,实时调整 key 的过期时长
3) 使用锁
-就是在缓存失效的时候(判断拿出来的值为空),不是立即去 load db。
-先使用缓存工具的某些带成功操作返回值的操作(比如 Redis 的 SETNX)去 set 一个 mutex key
-当操作返回成功时,再进行 load db 的操作,并回设缓存,最后删除 mutex key;
-当操作返回失败,证明有线程在 load db,当前线程睡眠一段时间再重试整个 get 缓存的方法
-使用锁效率会有影响
缓存雪崩
问题描述-如图
-缓存雪崩的原因
--缓存雪崩的现象/表象
1) 数据库访问压力变大, 服务器崩溃
2) 在极短时间内, 访问大量 Key, 而这些 Key 集中过期
--解决方案/思路
1) 构建多级缓存架构
nginx 缓存 + redis 缓存 +其他缓存(ehcache 等) , 这种方式开发/维护成本较高
2) 使用锁或队列
用加锁或者队列的方式来保证不会有大量的线程对数据库一次性进行读写,从而避免失效时大量的并发请求落到底层存储系统上。不适用高并发情况
3) 设置过期标志更新缓存
记录缓存数据是否过期,如果过期会触发通知另外的线程在后台去更新实际 key 的缓存。
4) 将缓存失效时间分散开
比如我们可以在原有的失效时间基础上增加一个随机值,比如 1-5 分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。
各位鱼友大家好,到这里关于基本的 Redis讲解就结束了,很感谢的大家的阅读大家下期再见! 🦈🌶