redis Op

Redis简介

主流应用架构
在这里插入图片描述
客户端 存储层 中间加一个缓存层

  1. 缓存层有数据,返回
  2. 缓存层无数据穿透到存储层,找到数据回写到缓存层,返回客户端
  3. 熔断机制,当存储层服务失效,直接在缓存层请求数据,有无数据都直接返回

缓存中间件–Memcache和Redis的区别

Memcache: 代码层次类似Hash
△支持简单数据类型
△不支持数据持久化存储
△不支持主从
△不支持分片 shading 指将整个数据库打碎的过程,简单理解为将大数据分布到多个物理节点上的分区方案
Redis: V
△数据类型丰富
△支持数据磁盘持久化存储
△支持主从
△支持分片

为什么Redis能这么快

性能:100000+ 的PQS (QPS即query per second, 每秒内查询次数)
完全基于内存,绝大部分请求是纯粹的内存操作,执行效率高
(Redis单进程单线程的kv数据库,由C语言编写,他将数据储存在内存里面,读写数据的时候都不会受到硬盘IO速度的限制,所以速度极快)
数据结构简单,对数据操作也简单
(类似Hash Map查找和操作的时间复杂度都是O(1))
采用单线程,单线程也能处理高并发请求, 想多核也可启动多实例
(一般在对面多并发请求的时候,想到的是用多个线程处理,将IO线程可业务线程分开,业务线程使用线程时来避免频繁创建和销毁线程,即便是一次请求,阻塞了也不会影响到其他请求, Redis反其道而行, redis的单线结构是指主线程是单线程的,这里主线程包括IO事件的处理以及IO对应的相关请求的处理, 此外主线程还负责过期键的处理,赋值协调以及集群协调等等, 这些除了IO时间的逻辑, 会被封装成周期性的任务,由主线程周期性的处理,正因为采用单线程的设计,对于客户端的所有读写请求, 都由一个主线程串行的处理,因此多个客户端对一个键进行写操作的时候, 就不会有并发的问题,避免了频繁的上线文切换和锁竞争,使得redis执行起来效率更高.单线程可以处理高并发的请求吗?redis可以实现!并发不是并行,并行性意味着服务器能够同时执行几个事情,具有多个计算单元,而并发性IO流意味着能够让一个计算单元来处理来自多个客户端的流请求,redis使用单线程配合IO多路复用能大幅度的提升性能,在多核CPU流行的今天只有一个线程只用一个核,多少让人感觉很浪费,并且无法用计算机利用其他的计算能力,不会,redis早对此问题进行相关验证,实际redis支持的QPS相当高,并且在QPS峰值的时候CPU并没有被跑满,只是由于网络等原因导致并发处理量不能进一步上升,因此CPU并不是制约redis性能的瓶颈,此外大家依旧可以在多核的服务器中启动多个redis实例来利用多核的特性.强调的单线程: 处理网络请求的时候,只有一个单线程来处理,一个正式的redis server在运行的时候肯定是不止一个线程的, 例如redis进行持久化的时候,会根据实际情况以子进程或者子线程的方式来执行)
使用多路IO复用模型,非阻塞IO
redis是跑在单线程中的,所有的操作都是按照顺序线性执行的,但是由于读写操作等待用户输入/输出都是阻塞的,所以IO操作在一般情况下,往往不能直接返回,就会导致某一文件的IO阻塞,进而导致整个进程无法对其他客户端提供服务,而IO多路复用就是为了解决这个问题

多路IO复用模型

FD: File Descriptor, 文件描述符(Linux)
一个打开的文件通过唯一的描述进行引用,该描述是打开文件的元数据到文件本身的映射
传统的阻塞IO模型
当使用read/write 对某个文件描述符FD进行读写时,如果当前FD不可读或者不可写,整个redis服务就不会对其他的操作做出响应,导致整个服务不可用,即阻塞模型,阻塞模型非常常见也非常易于理解,但是由于它会影响其他FD的的服务,所以处理多个客户端任务的时候,往往都不会使用阻塞模型,需要更高效率的模型来支撑redis的高并发处理
在这里插入图片描述
最重要的多路IO复用模型
select系统调用
select方法能够同时监控多个文件描述的可读可写情况,当其中的某些文件描述符可读/可写时,select方法就会返回可读/可写的文件描述符各是什么,selector监听Channel是否可读/可写,监听事件被selector执行,程序又可以去做别的事情而不被阻塞了
在这里插入图片描述
IO多路复用函数:epoll/kqueue/evport/select (前面的优秀性能一些)
Redis采用的IO多路复用函数:
因地制宜
优先选择时间复杂度为O(1)多路复用函数作为底层实现

常用数据类型

String

最基本的数据类型,二进制(可包含任何数据,入jpg图片或者序列化的对象)安全,最常用的kv键值对.最大存储512M,单个操作是原子性的

127.0.0.1:6379> ping
PONG
127.0.0.1:6379>set name "redis"
OK
127.0.0.1:6379>get name
"redis"
127.0.0.1:6379>set name "memcache"             //修改成新name
OK
127.0.0.1:6379>get name
"memcache"
127.0.0.1:6379>set count 1
OK
127.0.0.1:6379>get count
"1"
127.0.0.1:6379>incr count
(integer) 2
127.0.0.1:6379>get count
"2"
127.0.0.1:6379>incr userId191024              //统计该用户今日访问次数,191024后还可添加精确到时间

在这里插入图片描述

Hash

String元素组成的字典, 适用于存储对象

127.0.0.1:6379>hm lilei name "LiLei" age 26 title "Senior"         //创建LiLei的一个映射表(Hash表)
OK
127.0.0.1:6379>hget lilei age        //获取年龄
"26"
127.0.0.1:6379>hset lilei title "Pricipal"   //重置title内容
(integer) 0
127.0.0.1:6379>hget lilei title
"Pricipal"

List

列表,按照元素String元素插入顺序排序, 类似栈

127.0.0.1:6379>lpush mylist aaa
(integer) 1
127.0.0.1:6379>lpush mylist bbb
(integer) 2
127.0.0.1:6379>lpush mylist ccc
(integer) 3
127.0.0.1:6379>lrange mylist 0 10    //从左侧开始取,0-10
1)"ccc"
2)"bbb"
3)"aaa"         //后进先出, 类似 栈, 大约能存储41个成员, 可以显示最新排行榜,越后越先查找出

Set

String元素组成的无序集合,通过哈希表实现,不允许重复,时间复杂度O(1)

127.0.0.1:6379>sadd myset 111
(integer) 1
127.0.0.1:6379>sadd myset 222
(integer) 1
127.0.0.1:6379>sadd myset 222
(integer) 0
127.0.0.1:6379>semembers myset
1)"111"
2)"222"
127.0.0.1:6379>sadd myset abc
(integer) 1
127.0.0.1:6379>semembers myset
1)"222"
2)"abc"
3)"111"

Sorted Set

通过分数来为集合的成员进行从小到大的排序, 成绩排序,权重优先执行

127.0.0.1:6379>zadd myzset 3 abc
(integer) 1
127.0.0.1:6379>zadd myzset 1 abd
(integer) 1
127.0.0.1:6379>zadd myzset 1 abd
(integer) 0           //添加重复的值失败
127.0.0.1:6379>zadd myzset 1 bgg
(integer) 1           //分数相同,值不同可以添加成功
127.0.0.1:6379>zrangebyscore myzset 0 10
1)"abd"
2)"bgg"
3)"abc"

用于计数的HyperLogLog

用于支持存储地理位置信息的Geo

底层数据类型基础

1.简单动态字符串
2.链表
3.字典
4.跳跃表
5.整数集合
6.压缩列表
7.对象

海量数据查询

在这里插入图片描述

从海量Key里查询出某一固定前缀的Key

细节: 摸清数据规模, 即问清楚边界
使用keys对线上的业务的影响

KEYS patterrn: 查找所有符合给定模式pattern的key

△KEYS指令一次性返回所有匹配的key
△键的数量过大会使服务卡顿

127.0.0.1:6379>dbsize
(integer) 20000010
127.0.0.1:6379>keys k1*            //一次性获取,数据过多有隐患,消耗内存
...

SCAN cursor [MATCH pattern] [COUNT count]

△基于游标的迭代器,需要基于上一次的游标延续之前的迭代过程
△以0作为游标开始一次新的迭代,直到命令返回游标0完成一次遍历
△不保证每次执行都返回某个给定数量的元素,支持模糊查询
△一次返回的数量不可控,只能是大概率符合count参数

127.0.0.1:6379>scan 0 match k1* count 10   //从0开始一次返回10个带k1的值
1)"11534336"           //cursor值
2) 1)"k17930789"
	2)"k12231719"
	3)"k19606980"
127.0.0.1:6379>scan 11534336  match k1* count 10
1)"30932992"           //cursor值
2) 1)"k16480524"
	2)"k12854300"
	3)"k16301048"
	4)"k1463101"
127.0.0.1:6379>scan 30932992 match k1* count 10 
1)"23330816"           //cursor值
2) 1)"k18230663"
	2)"k15985456"
	3)"k14126392"
	4)"k11173717"

可能会重复需要后台代码去重

如何实现分布式锁

如何实现异步列队

持久化 RDB

ls
vim redis.conf
1.文件查找save(218)
save 900 1         900s内有一条写入, 触发产生一次快照,理解为产生一次备份
save 300 10       300s内有10条写入, 产生快照,如果0<变动数<10, 会900s快照备份
save 60 10000   60s有一万次写入快照备份
因redis每个时段的读写请求不均衡, 为了平衡性能与数据安全,自由定制触发备份条件
2.文件查找stop-write
stop-write-on-bgsave-error yes(235)
当备份进程出错的时候,主进程就停止接受新的写入操作,目的为了保护数据持久化的一致性的问题, 如果业务有完善的数据备份系统可以不设置此项为yes
3.rdbcompression yes(241)   
yes代表压缩后进行备份,redis属于CPU密集型服务器,再开启压缩会带来更多的CPU的消耗,相比硬盘成本,CPU更值钱
禁用rdb配置: save ""
src> ls *rdb
dump.rdb  (这是一个二进制文件)

RDB(快照)持久化: 保存某个时间点的全量数据快照

△SAVE: 阻塞Redis的服务器进程,直到RDB文件被创建完毕
△BGSAVE: Fork出一个子进程来创建RDB文件,不阻塞服务器进程
在这里插入图片描述

自动化触发RDB持久化的方式

△根据redis.com配置里的SAVE m n定时触发(用的是BGSAVE)
△主从复制时,主节点自动触发
△执行Debug Reload
△执行Shutdown且没有开启AOF持久化

BGSAVE原理

在这里插入图片描述
系统调用fork():创建进程,实现了Copy-on-Write
Copy-on-Write
如果有多个调用者同时要求相同资源(如内存或磁盘上的数据存储),他们会共同获取相同的指针指向相同的资源,直到某个调用者试图修改资源的内容时,系统才会真正复制一份专用副本给调用者,而其他调用者所见到的初始的资源仍然保持不变
在这里插入图片描述

RDB持久化缺点

△内存数据的全量同步,数据量大会由于IO而严重影响性能
△可能会因为Redis挂掉而丢失从当前至最近一次快照期间的数据

持久化AOF

AOF(Append-Only-File)持久化: 保存写状态 默认关闭

△记录下除了查询以外的所有变更数据库状态的指令
△以append的形式追加保存到AOF文件中(增量)

vim redis.conf
文件显示
1. appendonly yes  (默认是no)
2..appendfilename "appendonly.aof"   默认生成的文件名
3.appendfsync everysec          三个参数之一,每隔一秒写入aof文件
重启redis服务器

日志重写解决AOF文件大小不断增大的问题

△调用fork(),创建一个子进程
△子进程把新的AOF写到一个临时文件里,不依赖原来的AOF文件
△主进程持续将新的变动同时写到内存和原来的AOF里
△主进程获取子进程重写AOF的完成信号,往新AOF同步增量变动
△使用新的AOF文件替换掉旧的AOF文件

RDB和AOF的优缺点

RDB优点: 全量数据快照,文件小,恢复快

RDB缺点: 无法保存最近一次快照之后的数据(前面设置时间save)

AOF优点: 可读性高, 适合保存增量数据, 数据不易丢失

AOF缺点: 文件体积大, 恢复时间长

redis4.0之后结合RDB-AOF混合持久化方式,且为默认

子进程在做AOF重写时,会通过管道从父进程读取增量数据,并缓存下来,再以RDB格式保存全量数据时也会从管道读取数据,同时不会造成管道的阻塞,也就是说AOF的前半段是RDB格式的全量数据,而后半段是redis命令格式的增量数据
△BGSAVE做镜像全量持久化,AOF做增量持久化
在这里插入图片描述

Pipeline及主从同步

△Pipeline跟Linux管道相似
△Redis基于请求/响应模式,单个请求处理需要一一应答
△Pipeline批量执行指令,节省多次IO往返的时间
△有顺序依赖的指令建议分批发送

Redis的同步机制

主从同步原理

在这里插入图片描述

全同步过程

△Slave发送sync命令到Master
△Master启动一个后台进程,将Redis中的数据快照保存到文件中
△Master将保存数据快照期间收到的命令缓存起来
△Master完成写文件操作后,将该文件发送给Slave
△使用新的RDB文件替换掉旧的RDB文件
△Master将这期间收集的增量命令发送给Slave

增量同步过程

△Master接收到用户的操作指令,判断是否需要传播到Slave
△将操作记录追加到AOF文件
△将操作传播到其他Slave:1、对齐主从库;2、往响应缓存写入指令
△将缓存中的数据发送给Slave

Redis Sentinel 解决主从同步Master宕机后主从切换问题

△监控:检查主从服务器是否运行正常
△提醒:通过API向管理员或者其他应用程序发送故障通知
△自动故障迁移: 主从切换(找一台从机变成主机)

流言协议

在杂乱无章中寻求一致
△每个节点都随机地方与对方通信,最终所有节点的状态达成一致
△种子节点定期随机向其他节点发送节点列表以及需要传播的消息
△不保证信息一定会传递给所有节点,但是最终会趋于一致

Redis集群

如何从海量数据里快速找到所需
△分片: 按照某种规则去划分数据,分散存储在多个节点上
△常规的按照哈希划分无法实现节点的动态增减

Redis的集群原理

一致性哈希算法: 对2^32取模,将哈希值空间组织成虚拟的圆环
哈希环:2^32个点组成的环
在这里插入图片描述
将数据key使用相同的函数Hash计算出哈希值(定位哈希环上的位置)
在这里插入图片描述
Node C 宕机
顺时针到下个node
在这里插入图片描述
新增服务器 Node X
在这里插入图片描述
Hash环数据倾斜问题
在这里插入图片描述
引入虚拟节点解决数据倾斜的问题(多了一步虚拟节点到实际节点的映射)
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

海啦啦喽

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

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

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

打赏作者

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

抵扣说明:

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

余额充值