Redis笔记
1|0Redis笔记
2|0关于NoSQL概述
2|1一、NoSQL的发展历程
1、单机MySQL时代
90年代,一个网站的访问量一般不会太大,单个数据库完全够用。随着用户增多,网站出现以下问题:
- 数据量增加到一定程度,单机数据库就放不下了(MySQL中数据超过300万条,需要添加索引)
- 数据的索引(B+ Tree),一个机器内存也存放不下
- 访问量变大后(读写混合),一台服务器承受不住。
2、Memcached(缓存) + Mysql + 垂直拆分(读写分离)
网站80%的情况都是在读,每次都要去查询数据库的话就十分的麻烦!所以说我们希望减轻数据库的压力,我们可以使用缓存来保证效
率!
优化过程经历了以下几个过程:
- 优化数据库的数据结构和索引(难度大)
- 文件缓存,通过IO流获取比每次都访问数据库效率略高,但是流量爆炸式增长时候,IO流也承受不了
- MemCache,当时最热门的技术,通过在数据库和数据库访问层之间加上一层缓存,第一次访问时查询数据库,将结果保存到缓存,后续的查询先检查缓存,若有直接拿去使用,效率显著提升。
3、分库分表 + 水平拆分 + Mysql集群
4、如今最近的年代
如今信息量井喷式增长,各种各样的数据出现(用户定位数据,图片数据等),大数据的背景下关系型数据库(RDBMS)无法满足大量数据要求。Nosql数据库就能轻松解决这些问题。目前一个基本的互联网项目:
2|2二、为什么要用NoSQL
用户的个人信息,社交网络,地理位置。用户自己产生的数据,用户日志等等爆发式增长!这时候我们就需要使用NoSQL数据库的,Nosql可以很好的处理以上的情况!
1.NoSQL是什么:
NoSQL = Not Only SQL(不仅仅是SQL)
Not Only Structured Query Language
关系型数据库:列+行,同一个表下数据的结构是一样的。
非关系型数据库:数据存储没有固定的格式,并且可以进行横向扩展。
NoSQL泛指非关系型数据库,随着web2.0互联网的诞生,传统的关系型数据库很难对付web2.0时代!尤其是超大规模的高并发的社区,暴露出来很多难以克服的问题,NoSQL在当今大数据环境下发展的十分迅速,Redis是发展最快的。
2…NoSQL特点:
1.方便扩展(数据之间没有关系,很好扩展!)
2.大数据量高性能(Redis一秒可以写8万次,读11万次,NoSQL的缓存记录级,是一种细粒度的缓存,性能会比较高!)
3.数据类型是多样型的!(不需要事先设计数据库,随取随用)
4.传统的 RDBMS 和 NoSQL
传统的 RDBMS(关系型数据库)
结构化组织
SQL
数据和关系都存在单独的表中 row col
操作,数据定义语言
严格的一致性
基础的事务
…Nosql
不仅仅是数据
没有固定的查询语言
键值对存储,列存储,文档存储,图形数据库(社交关系)
最终一致性
CAP定理和BASE
高性能,高可用,高扩展
…
5.大数据时代的3V :主要是描述问题的
- 海量Velume
- 多样Variety
- 实时Velocity
6.大数据时代的3高 : 主要是对程序的要求
- 高并发
- 高可扩
- 高性能
真正在公司中的实践:NoSQL + RDBMS 一起使用才是最强的。
推荐文章:《阿里云的这群疯子》和 阿里云技术架构
2|3三、NoSQL的四大分类
1.KV键值对:
-
新浪:Redis
-
美团:Redis+Tair
-
阿里、百度:Redis + Memcache
2.文档型数据库 (bson格式和 json一样)
-
MongoDB (一般必须掌握!)
- MongoDB是一个基于分布式文件存储的数据库,c++编写,主要用来处理大量文档
- MongoDB是一个介于关系型数据库RDBMS和非关系型数据库NoSQL的中间产品(最像关系型数据库!)
-
CouchDB
3.列存储数据库
- Hbase
- 分布式文件系统
4.图关系数据库
- 用于存放关系的而非图片!比如:朋友圈社交网络、产品推荐
- Neo4j,InfoGrid
3|0Redis入门
3|1一.概述
Redis是什么?
Redis (Remote Dictionary Server ) 即远程字典服务!
-
redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件(简称:数据的持久化),并且在此基础上实现了master-slave(主从)同步(简称:主从复制)。
-
免费和开源!是当前最热门的非关系型数据库之一,也被人们称作结构化数据库!
Redis能干嘛?
- 内存存储,持久化,内存当中是断电即失的,所以说持久化很重要!(rdb,aof)
- 效率高,可用于高速缓存
- 发布订阅系统
- 地图信息分析
- 计时器、计数器(浏览量!)
…
Redis的一些特性
-
多样的数据类型
-
持久化
-
集群
-
事务
学习需要的东西
官网:https://redis.io/
中文网:http://www.redis.cn/
注意:windows在GitHub下载 (停更很久了,官方不推荐在windows使用Redis),因此,我们基于Linux学习!
3|2二.Windows安装
1.下载安装包:https://github.com/microsoftarchive/redis/releases/tag/win-3.2.100
2.下载好解压到自己电脑windows就可以了!Redis十分的小只有5M
3.开启Redis,双击运行服务即可!
默认端口:6379
4.使用Redis客户端连接redis服务
在客户端做一个简单的测试,以<k,v>形式存储一个数据,并取出!
记住:windows下使用虽然简单,但是Redis推荐我们使用Linux去开发使用!
地址:https://www.redis.io/topics/introduction
3|3三.Linux安装
3.进入Redis解压后的文件,可以看到redis的配置文件!
4.基本的环境安装
执行完make后执行make install
5.可以看到我们的redis被安装在/usr/local/bin(默认路径)下
6.将redis配置文件复制到我们的当前目录下(拷贝到当前目录下新建的一个config),之后就使用这个拷贝过来的配置文件redis.config去启动
7.默认我们的redis不是后台启动的,所以使用vim修改配置文件redis.config
将deamonize 的属性改为yes
8.启动我们的Redis服务(6.24版本启动后无任何返回值,老版本的会返回启动成功),无返回值可使用ps -ef检验是否启动
9.启动成功后我们可以用redis-cli连接,测试成功!
10.使用命令 查看redis的进程是否开启
11.如何关闭我们的redis服务
3|4四.测试性能
redis-benchmark是一个压力测试工具 ,来模拟 N 个客户端同时发出 M 个请求 【官方自带的性能测试工具】
redis性能测试工具可选参数:
我们来简单的测试下:
测试的是单机性能!
3|5五.基础知识
redis默认有16个数据库!
默认使用的是我们的第0个,
可以使用select
切换数据库,和DBSIZE
查看数据库的大小,keys *
查看数据库所有的key,flushdb
清除当前数据库数据!flushall
清空全部的数据库内容!
思考:为什么选择6379为redis的默认端口?明星名字 [了解即可]
Redis是单线程的!
明白redis是很快的,官方表示redis是基于内存操作cpu并不是Redis性能的瓶颈,而是在于内存和网络带宽!
大家所熟知的 Redis 确实是单线程模型,指的是执行 Redis 命令的核心模块是单线程的,而不是整个 Redis 实例就一个线程,Redis 其他模块还有各自模块的线程的。Redis 4.0 开始就有多线程的概念了,比如 Redis 通过多线程方式在后台删除对象、以及通过 Redis 模块实现的阻塞命令。Redis 6.0 网络处理多线程,即Theaded IO 指的是在网络 IO 处理方面上了多线程!
Redis为什么单线程还那么快?
-
误区一:高性能的服务器一定是多线程的?
-
误区二:多线程(cpu会上下文切换,消耗一定资源)一定比单线程快?
cpu、内存、硬盘的速度需要了解一下
核心:redis的数据全部是放在内存当中,所以使用单线程处理效率就是最高的,多线程(上下文切换:耗时的操作!),对于内存来说。如果没有上下文切换效率是最高的!,多次读写在一个cpu上的,在内存情况下这个就是最佳的方案!
4|0五大基本数据类型
Redis官网介绍:
全段翻译:
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
所以提到的命令需要全部记住!
RedisKey
expire key 时间
多少秒后失效,key消失,时间的单位是s
ttl key
查看key还能存活多少秒
EXISTS key
判断当前key是否存在
move key 数据库号
将key移动到某数据库下
type key
查看当前key的一个数据类型
不会的命令去官网查即可
String(字符串)
常用操作:
String类型的使用场景:value除了是我们的字符串,也可能是我们的数字
-
计数器!
-
统计数量
List(列表)
基本的数据类型,列表
举一个例子,一个list列表存放4个元素,再redis中我们可以通过定义规则,把List玩成 栈、队列、阻塞队列!
所有的list命令都是使用l开头的!
小节
- 他其实就是一个链表,before 、node、 after、 left、right都可以插入值!
- key不存在,创建新的链表
- key存在,新增内容
- 如果移除了所有值,空链表也是不存在!
- 在两边插入或改动值,效率最高!中间元素相对来说效率会低一些!
可用作消息队列:从左边存值,右边取值,达成排队效果(lpush、rpop)|栈 左边存值,左边取值(lpush、lpop)
Set(无序集合)
set当中的值是不能重复的!
微博:将A用户关注的所有的人放在一个set集合当中,将他的粉丝也放在一个集合当中!
共同关注、共同爱好、推荐好友 !
Hash(哈希)
Map集合!key-value(map集合)、key对应的值是一个键值对集合(map集合)、
hash做一些变更的数据,user,age,,name尤其是经常变动的信息和用户信息之类的!
- 【hash更适合于对象的存储!】比如:hset user:1 name zhangsan age 20
- 【String适合字符串存储!】比如 :set username zhangsan
Zset(有序集合)
在set的基础上,增加了一个值 !区别: set k1 v1 | zset k1 score1 v1
其余的一些api,通过我们的学习剩下的工作中有需要去查查看官方文档!
案例思路:存储班级成绩表、工资表排序、排行榜实现、带权重的消息判断:为消息分级别赋予权重!
5|0三大特殊数据类型
5|1geospatial地理位置
应用:朋友的定位、附近的人、打车距离计算!
在Redis的3.2版本就推出了这个Geo地理位置功能,这个功能可以推算地理位置的信息、两地之间的距离、方圆几里的人!
城市经度纬度在线查询:http://www.jsons.cn/lngcode/
关于geospatial地理位置的官方文档:http://www.redis.cn/commands/geoadd.html
Geo的相关命令:中文文档翻译的是有一点问题的!
在这个使用命令时redis的提示可以看出就是、经度、纬度、名称!
geoadd
geopos
获取当前定位:一定是一个坐标值!
geodist
获取两地之间的直线距离!
单位如下:
- m 表示单位为米。
- km 表示单位为千米。
- mi 表示单位为英里。
- ft 表示单位为英尺。
georadius 以给定的经纬度为中心,找出某一半径内的元素!
附近的人(获得所有的人附近的的地址、定位!)通过半径来查询
获取指定数量的人!
所有的城市都要录入,china:city 当中!
georadiusbymember
geohash 了解即可
简述:就是将二维的经纬度转换为一纬的字符串!
其底层就就是Zset,所以说我们可以使用Zset命令去操作geo、删除数据就可以使用Zrem
5|2Hyperloglog处理基数
什么是基数?
A {1,3,5,7,8,7} 基数:5
B {1,3,5,7,8} 基数:5
基数的概念:不重复的元素的个数!
- 比如:1 2 3 4 2 3 4的基数就是4因为只有1 2 3 4 而2 3 4 是重复的(基本就4个)
简介
Redis2.8.9版本就更新了Hyperloglog数据结构!
Redis Hyperloglog基数统计的算法!
- 优点:占用的内存十分的小,而且是固定的!2^64元素只占12kb内存!如果是考虑内存的话首选Hyperloglog
- 缺点:存在0.81%的错误率,但是还在接受范围内!
网站的UV(一个人访问一个网站多次,但还是只算作一个人!)
- 传统的方式,set保存用户的id,然后统计set元素的的数量去作为标准判断!比如:用户:1 用户:2 去访问某个网站后,2个id内保存在set集合此时set集合中的数据为{1,2},然后用户:1又来访问则id:1又被保存在set集合当中,此时set集合中的数据为{1,2,1}此时统计的id将毫无意义,因为id重复,而且我们需要的并不是保存用户的id而是同时数量!
- 我们将用户的id用PFadd存在hyperloglog当中,然后去使用PFcount去统计基数数量!
测试使用!
如果允许容错,那么一定可以使用我们的Hyperloglog!否则,只能使用set或我们自己的数据类型!
5|3Bitmaps位图
位存储
统计用户信息,活跃,不活跃!登录、未登录!打卡,365打卡!两个状态的,都可以使用Bitmaps !
Bitmaps位图,数据结构!都是操作二进制位来进行记录,就只有0和1两个状态!
365天=365 bit1字节= 8bit46个字节左右!
例如:如下统计7天的签到情况:如果某天签到设为1、如果某天未签到设为0
查看某一天是否打卡
统计操作我们的打卡天数
6|0事务
6|1事务的概述
Redis 事务的本质:一组命令的集合 !一个事务当中的所有命令都会被序列化,在事务执行的过程中会按照顺序执行!
一次性、顺序性、排他性
Redis与MySQL区别:
- MySQL事务满足ACID(原子性、一致性、隔离性、持久性)
- MySQL的原子性体现在一组事务,一组事务中的命令必须同时成功或者失败!
- Redis没有隔离级别的概念
- Redis单条命令是保持原子性的,但事务不保证原子性!
- Redis事务满足一次性(一次执行一组命令)、顺序性(顺序执行)、排他性(不允许干扰)
6|2Redis事务的执行
- 开启事务(multi)
- 命令入队(…)
- 执行事务(exec)
所有的命令在事务中,并没有直接执行,只有发起执行命令的时候才会执行!
正常执行事务!
取消事务discard
6|3事务错误
语法错误(编译时异常),所有命令都不执行
代码逻辑错误(运行时异常),其他命令可保证正常执行,所以不保证事务的原子性
6|4监控
悲观锁:
- 很悲观,认为什么时候都会出现问题,无论做什么都会加锁
乐观锁:
- 很乐观,认为什么时候都不会出现问题,所以不会上锁!更新数据的时候去判断一下,在此期间是否有人修改过这个数据
- 获取version
- 更新的时候比较version
使用watch key监控指定数据,相当于乐观锁加锁。
正常执行
测试多线程修改值,使用watch可以当做redis的乐观锁操作(相当于getversion)
我们启动另外一个客户端模拟插队线程。
线程1:
模拟线程插队,线程2:(在xshell开启一个客户端,先执行)
回到线程1,执行事务
解锁获取最新值,然后再加锁进行事务。
unwatch进行解锁。
注意:每次提交执行exec后都会自动释放锁,不管是否成功
7|0Jedis
使用Java来操作Redis,Jedis是Redis官方推荐使用的Java连接远程Linux的redis的客户端。
Java操作Redis的中间件!
7|1Redis远程配置
具体操作步骤:
-
在阿里云配置安全组,开放6379端口
-
防火墙放行6379
接下来通过Vim去修改redis.conf中的一些配置!
-
daemonize yes
-
protected-mode no
-
注释 bind 127.0.0.1
-
bind 0.0.0.0 所有ip可以连接,引出安全问题,我们去设置一个密码即可!
-
requirepass xxxx 配置redis密码
上边的配置工作完成后,我们重启redis-server
然后执行下图操作,ping后返回pong连接成功!
完成!
7|2Java连接远程redis
接下来就是使用jedis连接远程redis,实现java操作redis!
1.创建一个空的Maven项目(注意:project,moudle,javacomplie需要配置JDK)
2.添加Moudle即可!
3.导入对应的依赖
4.编码测试
- 连接数据库
- 操作命令
- 断开连接
做一个测试,判断是否连接成功!
输出:
连接远程成功!
如果想要连接本地windows下的方法如下,只需修改jedis!
7|3常用的API
就是在jedis中将我们之前的命令,改为方法即可!
- Rediskey
String、Set、List、Hash、Zset使用方法同上!
使用Jedis对事务进行一个测试!
8|0Springboot整合Redis
SpringBoot 操作数据:spring-data、 jpa、 jdbc、 mongodb 、redis 等 !
SpringData 也是和 SpringBoot 齐名的项目!
说明: 在 SpringBoot2.x 之后,原来使用的jedis 被替换为了 lettuce 音标:[letɪs]?
- jedis : 采用的直连,多个线程操作的话,是不安全的,如果想要避免不安全的,使用 jedis pool 连接池! 更像 BIO 模式
- lettuce : 采用netty,实例可以再多个线程中进行共享,不存在线程不安全的情况!可以减少线程数据了,更像 NIO 模式
8|1源码分析
我们在学习Springboot的时候,学习了自动装配的原理,让我们具体的分析下Redis的整个流程吧!
Springboot项目启动默认会加载spring.factories文件,只有当我们导入redis的启动器后,通过@conditional注解判断后,我们对应的RedisAutoConfiguration生效,如下:
RedisAutoConfiguration:Redis的自动配置类
我们可以看到这是一个javaconfig配置类,其中有2个bean,RedisTemplate和StringRedisTemplate会被注入到IOC容器当中,供我们以后使用!
同时,我们知道每一个自动配置类的属性和方法都在一个配置文件当中这次是RedisProperties!我们点进去就可以看到我们可以在配置文件中通过配置去改动的属性和一些方法!
RedisTemplate:需要传递一个RedisConnectionFactory,我们点入这个工厂的源码发现,这是一个接口,并且存在2个实现类
一个是关于Jedis的一个是关于lettuce的,他们具有相同的作用我们jeids上我们已经详细介绍了(封装java操作操作redis的方法)!
我们分别点入这2个实现类
- JedisConnectionFactory :爆红,提示缺少对应的包!
- LettuceConnectionFactory:完美使用,一切正常,
我们可以得出Lettuce才是我们现在RedisTemplate默认使用的,java操作Redis的类!
此时可得出一个结论:我们的RedisTemplate之所以可以操作Redis,其本质还是我们传入的 Jedis或者Lettuce,只是相当于又套了一层外壳!
最后我们回到RedisTemplate我们发现这个类上存在如下注解:
我们看到这个注解我们就该想到,这是再给我们自定义的机会,我们可以通过配置一个叫redisTemplate来替代原有的RedisTemplate,是我们开发更加的便捷!
以上便是对Redis的简单源码分析!
8|2整合测试
1.导入依赖
2.配置连接
3.测试类
8|3自定义RestTemplate
到此我们已经知道什么是RestTemplate了,但是默认的RestTemplate不是太好用,我们探究源码发现,
可以配置一个redisTemplate去替代我们原生的RestTemplate;
当我们调用的时候通过自动装配即可!
8|4序列化问题
如果数据传递不适序列化,就会出现乱码情况如下:
关于序列化问题,举个例子:
此时我们的User对象不是按照Json格式,也没有实现序列化执行后!
我们可以看到爆红了,提示我们,我们没有实现默认的序列化!
所以我们需要去实现序列化:
方式一:pojo下的User实现序列化接口!
方式二:自定义序列化规则,设置再RestTemplate中
代码如下,【模板】
设置好序列化规则后,我们再调用我们自己的Restemplate就行!
使用步骤!
至此,序列化问题得以解决!
8|5RedisUtils
所以我们会自定义一个工具类RedisUtils,把常用的一些个命令写入即可!
说实话:我感觉,又回到了Jredis,可能是自己功力太浅!
9|0Redis.conf详解
我们知道,启动Redis服务的时候,就是依赖这个配置文件!
让我们进入配置文件分析一下!Vim Redis.conf 然后gg直接从文件头部开始分析!
单位
配置文件中,Unit单位对大小写是不敏感的!
包含 INCLUDES
相当于我们学习Spring的时候,整合配置文件时的import,JSP、Thymeleaf中的include标签!
网络 NETWORK
通用 GENERAL
快照 SNAPSHOTTING
持久化,在规定的时间内,执行了多少次操作,会持久化到文件.rdb 和.aof文件
redis是内存数据库,如果没有持久化,那么数据就会断电即使失!
复制 REPLICATION 我们讲解Redis主从复制的时候再进行详解!
安全 SECURITY
限制 CLIENTS、MEMORY MANAGEMENT
APPEND ONLY MODE模式,aof配置(一种持久化操作!)
具体的配置会在Redis持久化中详细分析!
10|0Redis持久化(重点)
面设和工作必须!
Redis是内存数据库,如果不将内存中的数据保存在磁盘当中,那么一旦服务器进程退出,服务器中的数据库状态也会消失,所以Redis提供了持久化功能!
10|1RDB
什么是RDB(Redis DataBase)
-
在指定的时间间隔内将内存中的数据集快照写入磁盘,也就是行话讲的Snapshot快照,它恢复时是将快照文件直接读到内存里。
-
Redis会单独创建(fork)一个子进程来进行持久化, ,会先将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何IO操作的。
-
这就确保了极高的性能。如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那RDB方式要比AOF方式更加的高效。
-
RDB的缺点是最后一次持久化后的数据可能丢失。我们默认的就是RDB,一般情况下不需要修改这个配置! 有时候在生产环境我们会将这个文件进行备份!
-
rdb保存的文件是dump.rdb 都是在我们的配置文件中快照中进行配置的!
-
在生产环境一般会对rdb文件进行保存!
个人理解:就是将内存的数据按一定时间间隔后去保存到rdb文件当中,然后我们可以继续对内存中的数据进行操作,如果出现错误,我们可以读取rdb文件,失去当前的内存状态而回rdb中记录的状态,所以这种操作称之为快照!
测试:
我们去自定义一下我们的策略!
测试前我们保证不存在dump.rdb文件!
接下来,我们使用save命令:
Save 命令执行一个同步保存操作,将当前 Redis 实例的所有数据快照(snapshot)以 RDB 文件的形式保存到硬盘。
执行完save发现生成了dump.rdb文件
如果此时删除rdb文件然后我们测试我们1分钟内修改5次key,判断是否会持久化
然后并没有生成rdb文件,我们再次执行save,发现生成了dump.rdb文件
由上得,当我们1分钟内修改5次key的时候,没有生成rdb文件,而是将内存数据保存在快照当中,而当我们执行save,会将快照中的数据以rdb文件的形式持久化到我们的硬盘当中!
触发机制
- save的规则满足的情况下,会自动触发rdb原则
- 执行flushall命令,也会触发我们的rdb原则
- 退出redis,也会自动产生rdb文件
备份就是生成一个rdb文件!
恢复我们的rdb文件!
我们将我们redis中的内存数据恢复至rdb文件中保存的状态!
步骤:就是将我们的dump.rdb文件放在我们的redis启动目录即可,redis启动后会自动检查dump.rdb文件,恢复其中的数据!
我们将其dump.rdb文件移如即可!
其实rdb机制的默认配置已经足够使用了,但是我们仍然要学习!
优点:
- 适合大规模的数据恢复(因为是单独开启一个进程去处理!)
- 对数据的完整性要求不高
缺点:
- 需要一定的时间间隔进行操作,如果redis意外宕机了,这个最后一次修改的数据就没有了。
- fork进程的时候,会占用一定的内容空间。
10|2AOF
什么是AOF (APPEND ONLY FILE)
将我们所有的命令都记录下来,history,恢复的时候就把这个文件全部再执行一遍
以日志的形式来记录每个写的操作,将Redis执行过的所有指令记录下来(读操作不记录),只许追加文件但不可以改写文件,redis启动之初会读取该文件重新构建数据,换言之,redis重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。
aof保存的文件是 appendonly.aof文件
aof默认是不开启的,我们需要手动进行开启,将如下配置改为yes
接下来重启我们的redis就可以生效了,发现已经存在appendonly.aof
如果aof文件损坏(被修改)redis是启动不起来的,我们该怎么办?
redis给我们提供了一个修复工具redis-check-aof --fix
我们只需执行如下命令redis-check-aof --fix appenfonly.aof
文件得以修复!
我们接下来重启redis,发现数据也都通过读取aof的信息恢复了!
重写规则说明
aof默认是文件的无限制追加!文件会越来越大!
我们可以看到,当我们aof文件的大小大于64M,太大了,我们会fork一个新的进程,来将我们的文件进行重写!
优点和缺点!
优点:
- 每一次修改都会同步,文件的完整性会更加好
- 每秒同步一次,可能会丢失一秒的数据(默认)
- 从不同步,效率最高
缺点:
- 相对于记录数据文件来说,因为aof记录的是所有操作(日志),就文件大小来说,aof远远大于rdb,
- 修复速度比rdb慢!
- Aof运行效率也要比rdb慢,所以我们redis默认的配置就是rdb持久化
扩展 (了解即可)
1、RDB 持久化方式能够在指定的时间间隔内对你的数据进行快照存储
2、AOF 持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据,AOF命令以Redis 协议追加保存每次写的操作到文件末尾,Redis还能对AOF文件进行后台重写,使得AOF文件的体积不至于过大。
3、只做缓存,如果你只希望你的数据在服务器运行的时候存在,你也可以不使用任何持久化
4、同时开启两种持久化方式
- 在这种情况下,当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。
- RDB 的数据不实时,同时使用两者时服务器重启也只会找AOF文件,那要不要只使用AOF呢?作者建议不要,因为RDB更适合用于备份数据库(AOF在不断变化不好备份),快速重启,而且不会有AOF可能潜在的Bug,留着作为一个万一的手段。
5、性能建议
- 因为RDB文件只用作后备用途,建议只在Slave上持久化RDB文件,而且只要15分钟备份一次就够了,只保留 save 900 1 这条规则。
- 如果Enable AOF ,好处是在最恶劣情况下也只会丢失不超过两秒数据,启动脚本较简单只load自己的AOF文件就可以了,代价一是带来了持续的IO,二是AOF rewrite 的最后将 rewrite 过程中产生的新数据写到新文件造成的阻塞几乎是不可避免的。只要硬盘可,应该尽量减少AOF rewrite的频率,AOF重写的基础大小默认值64M太小了,可以设到5G以上,默认超过原大小100%大小重写可以改到适当的数值。
- 如果不Enable AOF ,仅靠 Master-Slave Repllcation 实现高可用性也可以,能省掉一大笔IO,也减少了rewrite时带来的系统波动。代价是如果Master/Slave 同时倒掉,会丢失十几分钟的数据,启动脚本也要比较两个 Master/Slave 中的 RDB文件,载入较新的那个,微博就是这种架构。
11|0Redis订阅发布
Redis可以做,消息队列做的更好
Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。微信、 微博、关注系统!
Redis 客户端可以订阅任意数量的频道。
订阅/发布消息图: 第一个:消息发送者, 第二个:频道 第三个:消息订阅者!
下图展示了频道channel,以及订阅这个频道的三个客户端client1,client2,client5之间的关系
当有新的消息通过PUBLISH命令发送给频道时,这个消息就会发送给订阅他的三个客户端
命令
这些命令被广泛应用于构建即时通信应用,比如网络社交聊天(chatroom)和实时广播和实时提醒
测试一下
如下,我们开启2个客户端连接我们的Redis服务,
我们可以看到当一个用户订阅一个频道后,如果频道接收到消息用户可以实时收到!
代码展示:
客户端1(订阅端):
客户端2(发送端):
原理
Redis是使用C实现的,通过分析 Redis 源码里的 pubsub.c 文件,了解发布和订阅机制的底层实现,籍此加深对 Redis 的理解。
Redis 通过 PUBLISH 、SUBSCRIBE 和 PSUBSCRIBE 等命令实现发布和订阅功能。
每个 Redis 服务器进程都维持着一个表示服务器状态的 redis.h/redisServer 结构, 结构的 pubsub_channels 属性是一个字典, 这个字典就用于保存订阅频道的信息,其中,字典的键为正在被订阅的频道, 而字典的值则是一个链表, 链表中保存了所有订阅这个频道的客户端。
下面两个图来解释一下上述话的意思:
客户端订阅,就被链接到对应频道的链表的尾部,退订则就是将客户端节点从链表中移除。(看来图是不是通俗易懂哈哈哈哈)
应用场景
1.实时消息系统
2.实时聊天(频道当作聊天室,将信息回显给所有人即可!)
3.订阅关注系统都是可以的
简单的我们可以使用Redis去做,复杂的就要交给专业的技术kafka、RabbitMQ、RocketMQ等都可以!
12|0Redis主从复制
12|1概念
主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(Master/Leader),后者称为从
(Slave/Follower), 数据的复制是单向的!只能由主节点复制到从节点(主节点以写为主、从节点以读为主)。
默认情况下,每台Redis服务器都是主节点,
一个主节点可以有0个或者多个从节点,但每个从节点只能由一个主节点。
12|2作用
- 数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余的方式。
- 故障恢复:当主节点故障时,从节点可以暂时替代主节点提供服务,是一种服务冗余的方式
- 负载均衡:在主从复制的基础上,配合读写分离,由主节点进行写操作,从节点进行读操作,分担服务器的负载;尤其是在多读少写的场景下,通过多个从节点分担负载,提高并发量。
- 高可用基石:主从复制还是哨兵和集群能够实施的基础。
12|3为什么使用集群
一般来说,要将Redis运用于工程项目中,只使用一台Redis是万万不能的(宕机),原因如下:
1、从结构上,单个Redis服务器会发生单点故障,并且一台服务器需要处理所有的请求负载,压力较大;
2、从容量上,单个Redis服务器内存容量有限,就算一台Redis服务器内存容量为256G,也不能将所有内存用作Redis存储内存,一般来说,单台Redis最大使用内存不应该超过20G。
电商网站上的商品,一般都是一次上传,无数次浏览的,说专业点也就是"多读少写"。
对于这种场景,我们可以使如下这种架构:
主从复制,读写分离! 80% 的情况下都是在进行读操作!减缓服务器的压力!架构中经常使用! 一主二从!
只要在公司中,主从复制就是必须要使用的,因为在真实的项目中不可能单机使用Redis!
总结
- 单台服务器难以负载大量的请求
- 单台服务器故障率高,系统崩坏概率大
- 单台服务器内存容量有限。
12|4模拟Redis集群
由于我们是一台服务器去模拟一个Redis集群,所以就模拟最简单的 “一主二仆”
首先我们通过创建连接先模拟是3台服务器!
其次我们要准备好3个redis.conf 配置文件(复制原有的redis.conf 三份即可)!
然后通过Vim为每个配置文件修改一些配置,需要修改的配置如下
为上述的3个配置文件修改以下4个部分
- port:进程占用的端口号
- pid(port ID):记录了进程的 ID,文件带有锁。可以防止程序的多次启动。【并不是进程号】
- logfile:明确日志文件的位置
- dbfilename:dumpxxx.file 持久化文件位置
修改完成后启动我们的3个Redis服务
查看服务是否启动成功!
成功开启3个redis服务!
12|5配置"一主二从"
首先是模拟访问3个Redis服务,**默认情况下,每台Redis服务器都是主节点,**可以通过命令
所以一般情况下,我们只需要配置从机就可以了,认老大,一主(79)二从(80,81)
从机配置
注意:如果6379的配置文件中redis设置了密码,就再去80和81文件中添加一个除之前修改的的4个属性外还需配置一个
masterauth 123456如果不配置将无法实现主从复制!
设置好后,再次使用info replication
查看当前主机信息即可!
真实的主从配置应该是在配置文件中去配置是永久的,而我们通过命令配置的是暂时的!
如下:在配置文件的的REPLICATION复制模块下
细节
主机可以写,从机只能读不能写!主机中的所有信息(数据)都会被从机保存!
从机中不可写,一旦写入报错
测试存在问题
1.如果现在老大没了,主机宕机了,什么情况?
在从机中查看信息发现,主机信息不变,但是没有了写操作!如果此时老大又回来了 ,从机依旧可以获取到主机中的信息!
2.如果从机宕机了,什么情况?
如果是使用我们的命令行配置的主从,重启后就会变回主机!只要再变回从机,就可以立刻获取到主机中的所有信息(数据)!
12|6主从复制原理
Slave 启动成功连接到 master 后会发送一个sync同步命令
Master 接到命令,启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,master将传送整个数据文件到slave,并完成一次完全同步。
- 全量复制:而slave服务在接收到数据库文件数据后,将其存盘并加载到内存中。
- 增量复制:Master 继续将新的所有收集到的修改命令依次传给slave,完成同步
但是只要是重新连接master,一次完全同步(全量复制)将被自动执行! 我们的数据一定可以在从机中看到!
层层链路
我们一主二从是如下
我们还可以这样设计
此时中间的仍然是从节点,只能读!
注:【真实开发上述的2种模型都不会使用!】
上述模型行中,老大宕机的话,从机不重启依旧连接着宕机的老大!所以引入新问题?
如果老大宕机,这个时候能否产生新的老大?手动【谋朝篡位】
其他的节点,就可以手动连接到我们新的主节点!如果此时老大修复了,那就只能重新连接,无法恢复老大地位!
上面是手动配置,接下来引入自动配置模式也就是哨兵模式!
13|0哨兵模式(重点)
(自动选举老大的模式!)
13|1概述
主从切换技术的方法是:当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费事费力,还会造成一段时间内服务不可用。这不是一种推荐的方式,更多时候,我们优先考虑哨兵模式。Redis从2.8开始正式提供了Sentinel(哨兵) 架构来解决这个问题。能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库。
哨兵模式是一种特殊的模式,首先Redis提供了哨兵的命令,哨兵是一个独立的进程,作为进程,它会独立运行。其原理是哨兵通过发送命令,等待Redis服务器响应,从而监控运行的多个Redis实例。
哨兵的作用:
- 通过发送命令,让Redis服务器返回监控其运行状态,包括主服务器和从服务器。
- 当哨兵监测到master宕机,会自动将slave切换成master,然后通过发布订阅模式通知其他的从服务器,修改配置文件,让它们切换主机。
然而一个哨兵进程对Redis服务器进行监控,可能会出现问题,为此,我们可以使用多个哨兵进行监控。各个哨兵之间还会进行监控,这样就形成了多哨兵模式。
假设主服务器宕机,哨兵1先检测到这个结果,系统并不会马上进行failover过程,仅仅是哨兵1主观的认为主服务器不可用,这个现象成为主观下线。当后面的哨兵也检测到主服务器不可用,并且数量达到一定值时,那么哨兵之间就会进行一次投票,投票的结果由一个哨兵发起,进行failover[故障转移]操作。切换成功后,就会通过发布订阅模式,让各个哨兵把自己监控的从服务器实现切换主机,这个过程称为客观下线。
13|2哨兵测试
我们目前的状态是 “一主二从”
1.配置一个sentinel.conf的配置文件,进行如下配置!
意思是:哨兵监控我们的主机 6379的redis服务,1代表如果该服务宕机,salve就进行投票,票数最多的就会成为主机!
2.启动哨兵
如果我们的Master节点断掉了,这个时候就会从"从机"中随计选择一个服务器!
此时Master再回来也无济于事,只能重新连接,或者改做为奴(slave),新主机称霸天下!
13|3优缺点
优点:
- 哨兵集群,基于主从复制模式,所有主从复制的优点,它都有
- 主从可以切换,故障可以转移,系统的可用性更好
- 哨兵模式是主从模式的升级,手动到自动,更加健壮
缺点:
- Redis不好在线扩容,集群容量一旦达到上限,在线扩容就十分麻烦
- 实现哨兵模式的配置其实是很麻烦的,里面有很多配置项
13|4哨兵模式的配置
14|0Redis缓存穿透和雪崩(重点)
14|1缓存穿透
概念
在默认情况下,用户请求数据时,会先在缓存(Redis)中查找,若没找到即缓存未命中,再在数据库中进行查找,数量少可能问题不大,可是一旦大量的请求数据(例如秒杀场景)缓存都没有命中的话,就会全部转移到数据库上,造成数据库极大的压力,就有可能导致数据库崩溃。网络安全中也有人恶意使用这种手段进行攻击被称为洪水攻击。
所谓缓存穿透:(即缓存中查询不到)
解决方案
1.布隆过滤器 :
布隆过滤器是一种数据结构,对所有可能查询的参数以hash形式存储,在控制层先进行校验,不符合则丢弃,从而避免了对底层存储系统的查询压力
2.缓存空对象 :
当存储层不命中后,即使返回的空对象也将其缓存起来,同时会设置一个过期时间,之后再访问这个数据将会从缓存中获取,保护了后端数据源;
这样做有2个问题:
- 存储空对象也需要空间,大量的空对象会耗费一定的空间,存储效率并不高。解决这个缺陷的方式就是设置较短过期时间
- 即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响。
14|2缓存击穿
微博服务器宕机!(量太大缓存过期!)
概述
相较于缓存穿透,缓存击穿的目的性更强,一个存在的key,在缓存过期的一刻,同时有大量的请求,这些请求都会击穿到DB,造成瞬时DB请求量大、压力骤增。这就是缓存被击穿,只是针对其中某个key的缓存不可用而导致击穿,但是其他的key依然可以使用缓存响应。
比如热搜排行上,一个热点新闻被同时大量访问就可能导致缓存击穿。
解决方案
1.设置热点数据永不过期
这样就不会出现热点数据过期的情况,但是当Redis内存空间满的时候也会清理部分数据,而且此种方案会占用空间,一旦热点数据多了起来,就会占用部分空间。
2.加互斥锁(分布式锁)
在访问key之前,采用SETNX(set if not exists)来设置另一个短期key来锁住当前key的访问,访问结束再删除该短期key。保证同时刻只有一个线程访问。这样对锁的要求就十分高。
14|3缓存雪崩
概述
大量的key设置了相同的过期时间,导致在缓存在同一时刻全部失效,造成瞬时DB请求量大、压力骤增,引起雪崩。
缓存雪崩,是指在某一个时间段,缓存集中过期失效。Redis 宕机!
产生雪崩的原因之一,比如在写本文的时候,马上就要到双十二零点,很快就会迎来一波抢购,这波商品时间比较集中的放入了缓存,假设缓存一个小时。那么到了凌晨一点钟的时候,这批商品的缓存就都过期了。而对这批商品的访问查询,都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰。于是所有的请求都会达到存储层,存储层的调用量会暴增,造成存储层也会挂掉的情况。
其实集中过期,倒不是非常致命,比较致命的缓存雪崩,是缓存服务器某个节点宕机或断网。因为自然形成的缓存雪崩,一定是在某个时间段集中创建缓存,这个时候,数据库也是可以顶住压力的。无非就是对数据库产生周期性的压力而已。而缓存服务节点的宕机,对数据库服务器造成的压力是不可预知的,很有可能瞬间就把数据库压垮。
解决方案
Redis高可用
这个思想的含义是,既然redis有可能挂掉,那我多增设几台redis,这样一台挂掉之后其他的还可以继续工作,其实就是搭建的集群
限流降级
这个解决方案的思想是,在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
数据预热
数据加热的含义就是在正式部署之前,我先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。
完结撒花!
如需要Markdown版本的笔记,我上传的资源当中是有的可以下载!
__EOF__

本文链接:https://www.cnblogs.com/qxsong/p/15837310.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 25岁的心里话
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现