(基于缓存成本高,实际架构中需要群访问延迟和成本。redis可提升系统性能,改善用户体验)
有点杂,后面整理
redis优势
纯内存 单线程模型 I/O多路复用
具有高效数据结构
全局哈希表,空间复杂度O(1)
渐进式哈希,一次性复制分摊到多次操作中
哈希结构和有序数据结构加快读写
redis对数据存储进行了优化,进行了压缩存储,可用根据实际数据类型选不同编码
redis与其他key-value数据库有何不同
1.更复杂数据结构
2运行在内存,并且可以持久化道磁盘,数据进行读写不能高于内存空间
redis记录用户的登录次数,查询活跃用户
2.redis安装和访问
以下是 Redis 安装和访问的一般步骤:
安装 Redis(以 Linux 系统为例):
- 下载 Redis 安装包,可以从 Redis 官方网站获取。
- 解压安装包。
- 进入解压后的目录,执行编译命令,如
make
。 - 可以选择执行安装命令,如
make install
。
启动 Redis:
可以通过执行 redis-server
命令来启动 Redis 服务器。
访问 Redis:
- 可以使用 Redis 客户端,如
redis-cli
来连接本地 Redis 服务器,直接执行redis-cli
即可进入交互模式。 - 在交互模式下,可以执行各种 Redis 命令,如
set key value
来设置键值对,get key
来获取对应的值等。
3.redis的数据结构
简单的动态字符串 跳跃表 压缩列表 整数集合
字典 快表 stream Hypeloglog
Redis数据结构有字符串,双端列表,字典,压缩列表,整数集合等。
但为了加快读写速度,并没有直接用这些数据结构,在此基础上封装包装了一层,称为RedisObject(Redis 对象(RedisObject):是 Redis 内部各种数据的基础封装。)
RedisObject5种
(字符串对象String,列表对象List,哈希对象Hash ,集合对象Set,有序对象Zset)
- 字符串(String):可以存储字符串、数字等。
- 列表(List):双向链表结构,支持在两端进行操作。
- 集合(Set):不允许重复元素的集合。
- 有序集合(Sorted Set):元素有顺序,且每个元素关联一个分值。
- 哈希(Hash):键值对的映射表。
- 位图(Bitmap):通过位操作来存储和处理数据。
- 地理空间(Geo):存储地理位置信息。
- 流(Stream):类似消息队列的数据结构。
- 基数估计(HyperLogLog):用于进行不精确的去重计数。
4.redis的存储结构
默认16个数据库,通过redis.conf文件中的参数database来指定当前数据库,默认redis连接0编号数据库。
可以通过select语句进行数据库切换 select 1 select 7等
5.键管理
键管理基本操作
通过键保存 value set key value
重命名键 rename key1 key2
查询键总数 dbsize
随机返回一个键 randomkey
遍历键
keys (help keys 查看说明)
keys *(全量遍历)
keys stu*(stu开头)
keys key?(匹配key开头切长度是4个字符的键)
scan(help scan 查看说明)
迭代遍历redis中的键,该命令是一个游标迭代器,每次使用返回一个新游标用于下次迭代,返回0则迭代结束(scancomand())
dbsize(数据库实例中数据量大小)
scan 0 count 150
scan 306 count 150
迁移键
1.采用move进行实例中的数据迁移(help move 查看说明)
切换数据库查看键
2.使用dump和restore命令实现实例间的数据迁移
分为两步:
1在源头redis实例上 dump用于键值序列化,rdb序列化字符串
2.目标redis数据库实例上进行 restore命令用于复原rdb序列化字符串
示例:
1.命令行窗口 help dump进行查看帮助信息
2.源redis数据库实例上插入数据,用dump进行持久化
set hello world
3.通过help查看restore命令的帮助信息
4.在目标redis数据库实例上使用restore命令恢复数据
3.使用migrate命令实现实例间的数据迁移(help migrate 查看说明)
1.将数据从源redis数据库实例上迁移键到目标Redis数据库实例
migrate 192.168.79.12 6379 hello 0 1000
2.在目标redis数据库实例上检查数据是否迁移成功
keys *
输出get hello
3.重复2步骤,显示 NOKEY证明ok 没有需要再迁移的key
Redis高级特性及其原理
3.1 消息的发布与订阅
3.1.1 发布者-订阅者模式
3.1.2 生产者-消费者模式
3.2 Redis的事务
哨兵用主从节点之间的通信监听
集群是采用分片哈希槽位分数据到 不同的redis节点上
BigKey HotKey
缓存常见问题
提高缓存命中率
缓存预热
缓存穿透(解决方式: 布隆过滤器/缓存控对象)
缓存雪崩(缓存大量失效)
缓存击穿
redis的数据结构使用场景
String
1.单值缓存(分布式token,网关分布式部署,记得设定过期时间,当然有需要也可以永存不定时)
2.对象缓存(高频访问,但是修改较少的数据对象,序列化保存,减缓关系型数据库压力)
3.计数器(高并发,接口限流,计算接口请求数目,每秒定量,防止服务器在高并发下宕机)
网站访问量统计:可以将每个用户的访问记录存储为一个字符串,并使用字符串的长度或特定的分隔符来表示访问次数。
-
商品库存计数:将商品的库存数量存储为一个字符串,可以进行增加、减少库存的操作。
-
投票计数:在投票系统中,每个投票选项可以对应一个字符串,字符串的值表示投票的数量。
4.唯一自增的ID或者流水号(提高数据库读写,会进行分库分表,但是又要两张表中的id是全局统一自增的,用redis服务自增,实现多表唯一自增id)
incryb id 1 如果采用雪花算法,则不考虑redis自增。
5.文章阅读,或者网页浏览数统计
6.分布式锁(用于秒杀场景。为防止服务器突然宕机,要去设定过期时间,防止线程中断,锁没释放)
Hash
优缺点(与string)string占用更多键,内存占用大,用户信息分散,需要序列化和反序列化,操作相对繁琐
1.作为实时数据库
2.实现购物车(userid作为redis的key,每个购物都是一个哈希表,存储商品id和订购数量之间的映射关系
3.作为计数器(用在记录网站一天,一月,一年的访问数量,每次访问,对应field自增1即可。 记录商品的好评数量和差评数量。 还有实时在线人数命令等)
List(用链表实现,顺序存储。可以存2的32次方-1的数量)
网站首页,一般访问最高,加速响应,可以把首页所有信息存储在list。提升并发量(分页获取文章,mget)
Set(元素无序且唯一的键值对集合)
1.明星绯闻和威迫瘫痪(点赞过多,或者评论导致并发问题)用缓存解决,再不定时把缓存刷到数据库,提升性能
2.抽奖逻辑(年会抽奖-所有参与者用户信息,公众号抽奖)
3.文章点赞,或者投票
4.共同好友统计
Zset(有序非重复集,采用score)
1.限流(缓存,降级,限流保护微服务系统稳定性三大利器),限制稀缺资源,数据库写操作,频繁重复查询等,滑动窗口,令牌桶等
2.新闻排行榜场景,直播打赏排名
HyperLogLog 作为计数器:
-
统计独立访客:HyperLogLog 可以用于估计不重复的访客数量,例如在网站分析中统计每天的独立访客。
-
大数据量的去重计数:当需要对大量数据进行去重计数时,HyperLogLog 可以高效地计算近似的唯一值数量。
-
实时统计:HyperLogLog 适用于实时统计数据,例如实时监控网站的活跃用户数量。
数据结构底层
string(三种编码)
hash(ziplist,hashTable,根据配置hash-max-ziplist-entries默认值,如果超过,则使用hashtable,否则用ziplist压缩列表)
List(快表, 是ziplist和链表结合体,每一个ziplist通过双向指针进行链接)
Set (根据设置判断,set-max-inset- entries值,超过切换成hashTable)
Zset(跳跃表,空间换时间。头节点64层,每层指向本层下一个节点指针,层数最多节点的层高为跳跃表高度。)
Redis 是一种开源的内存数据结构存储系统,支持多种数据类型,包括字符串(String)、哈希(Hash)、列表(List)、集合(Set)和有序集合(ZSet)。这些数据类型的键值对的键和值的数据结构如下:
• String:是一种二进制安全的数据结构,可以用来存储任何类型的数据,比如字符串、整数、浮点数、图片(图片的 base64 编码或者解码或者图片的路径)、序列化后的对象。其值的数据结构是简单动态字符串(Simple Dynamic String,SDS)。
• Hash:是一种字典结构,可以用来存储对象,如用户信息、商品信息等。其值的数据结构是哈希表(HashTable)。
• List:是一种双向链表结构,可以用来实现队列、栈等数据结构。其值的数据结构是双向链表。
• Set:是一种无序的、自动去重的集合数据类型,其值的数据结构是哈希表(HashTable)和整数集合(IntSet)。
• ZSet:是一种有序的、自动去重的集合数据类型,其值的数据结构是字典(Dict)和跳表( Skiplist)。
跳表(Skip List)是一种基于有序链表的数据结构,它通过在原始链表中增加一些额外的指针,实现了快速查找、插入和删除元素的功能。跳表的主要特点是可以在 O(log n) 的时间复杂度内完成对链表中元素的查找操作,相比于传统的有序链表,其效率有了很大的提高。
跳表由以下几个部分组成:
-
原始链表:跳表的基础是一个有序链表,链表中的每个节点包含一个关键字和相关的数据。
-
多级索引:除了原始链表,跳表还维护了多级索引。每一级索引都是一个指针数组,其中每个指针指向原始链表中的一个节点。索引的级别越高,指针之间的间隔就越大。
-
跳跃指针:在每一级索引中,除了指向原始链表节点的指针外,还可能存在一些跳跃指针。跳跃指针用于跳过一部分链表节点,直接指向更远的位置,从而加快查找速度。
通过多级索引和跳跃指针的结合,跳表可以在查找元素时根据关键字的大小快速定位到可能存在的位置,然后通过跳跃指针进一步缩小查找范围,最终找到目标元素。这样的设计使得跳表在查找操作上具有较高的效率,同时也保持了有序链表在插入和删除元素时的灵活性。
需要注意的是,跳表的具体实现方式可能因不同的算法和应用场景而有所差异,但总体上都遵循上述基本原理。在实际应用中,跳表常用于搜索引擎、数据库等领域,以提高数据检索的效率。
跳表是基于有序链表的数据结构,而有序链表既可以是双向链表,也可以是单向链表。
在跳表中,原始链表的具体实现方式可以根据具体的需求和场景来选择。如果需要在链表中双向移动,那么可以使用双向链表;如果只需要在链表中单向移动,那么可以使用单向链表。
一般来说,双向链表在某些情况下可能更加方便和灵活,因为它允许在链表中双向访问节点。但是,单向链表在一些特定场景下也可能更适合,例如在一些简单的情况下,或者在空间和性能要求较高的情况下。
无论使用双向链表还是单向链表,跳表的基本原理和操作都是相同的。跳表通过维护多级索引和跳跃指针来提高查找效率,使得在 O(log n) 的时间复杂度内可以快速定位到目标元素。
因此,跳表的原始链表可以是双向链表,也可以是单向链表,具体取决于具体的实现和需求。
数据持久化
Rdb 内存数据的快照,存储到磁盘,dump.rdb. 通过save/bgsave进行触发, 缺点意外宕机 数据丢失
Aof 通过日志记录redis所有操作 appendonly.aof 文件 三种持久化策略 每秒 总是 或者 no,这边有个重写概念,覆盖掉旧的键操作,保留最新
混合持久化 通过aof-use-rdb-preamble开启
Aof开启,则有限加载aof
混合持久化(4.0之后支持)
Redis 采用lua脚本替代事务,因为是按顺序执行lua脚本的命令
Pub/sub发布订阅模式(无法持久化到磁盘,也不存在ack确认机制。kafka可以)
Stream数据结构(给redis带来了持久化消息队列,仅追加内容的消息链表,且拥有ack消息确认机制)
主从复制
master和slave节点实现读写分离
原理:三阶段,链接建立,数据同步,命令传播。
1.存节点信息-建立socker链接-ping-身份验证-发送从节点端口信息
2.全量复制容易丢,部分复制redis2.8开始支持,断点续传
3.命令传播-主节点发送写命令,维持心跳机制ping和replconf ack
操作
注意事项
应用中的问题
作用
哨兵模式
哨兵作用和架构
架构(哨兵节点,数据节点)功能:监控,通知,自动故障转移 ,配置提供者
哨兵系统部署方法
需要注意事项
实现的基本原理
哨兵模式客户端链接方式
集群(3.0开启)
节点通信机制(通信端口,普通端口,集群端口+10000.配置的时候防火墙都要开起来,gossip协议)
Redis6
为啥执行命令只在一个主线程:
1.瓶颈:内存和IO。 带宽不太行,吞吐量一般还没到达cpu瓶颈,就开始有网络瓶颈。
2.多线程会带来线程不安全,竞争资源
3.哈希惰性rehash等不安全命令,都可以无锁执行,保证数据一致性
4.多线程可能存在线程切换,加锁,解锁,死锁会造成性能损耗
5.单线程降低redis内部实现复杂度,这也是分布式可以用redis实现原因之一
高并发原因之一:多路复用,epoll模型(先采用epoll_ctl()来注册文件描述符,描述符就绪后,内核会回调激活,epoll_wait接收到通知,
并且epoll采用内存映射技术(mmap)节省系统调用复制的开销,内核,用户空间
虽然io多路复用提升并发量。io读写依然阻塞(内存数据从内核到用户空间的复制,这也是redis6.0性能瓶颈之一, 命令的解析/处理/应答都由主线程负责,这些操作包含了IO操作
Redis6 开多线程------------主线-开多线程(主线程是网络io和内存数据读写的这块, 主线程的 io读写任务拆分给多个线程执行,实现多个套接字读写并行化)
开启多线程(官方建议4核以上才可以开启IO多线程,除非真性能瓶颈,否则不开,4核开2-3个,8核开6个,不是线程越多越好)
redis.conf
io-threads-do-reads yes
io-threads 4
布隆过滤器(解决缓存穿透问题)
原理
应用场景:
爬虫爬到重复内容
垃圾邮件过滤百名的
解决缓存穿透
避免消息推送给相同的人
Redis内存相关策略核内存碎片
maxmemory
数据淘汰策略
lru算法。 lfu算法
数据过期删除策略
内存碎片(4.0之后开启,并且可以设置大小峰值多少开始清理,cpu占用比率范围等)
RedLock 是一种分布式锁的实现算法,它通过在多个独立运行的 Redis 实例上同时获取锁的方式,来提高锁服务的可用性和安全性。RedLock 主要用于解决在分布式系统中实现可靠锁的问题。
RedLock 的原理如下:
- 获取锁:客户端尝试在多个 Redis 节点上分别执行 SETNX 命令来获取锁。只有当超过半数(N/2+1)的节点都成功设置了锁时,客户端才认为获取到了锁。
- 锁的有效期:客户端在获取到锁之后,会给锁设置一个有效期,以防止死锁情况的发生。
- 释放锁:客户端在完成操作后,需要在所有获取到锁的 Redis 节点上执行 DEL 命令来释放锁。
通过以上步骤,RedLock 实现了分布式锁的功能,确保了在分布式系统中的互斥性和安全性。同时,RedLock 还具有容错性,即使部分 Redis 节点出现故障,也能保证锁的正确性和可用性。