Redis 学习part one

Redis核心技术与实战

具体内容去购买相关课程。

01基本架构:一个键值数据库包含什么?

Redis 的持久化模块能支持两种方式:日志(AOF)和快照(RDB),这两种持久化方式具有不同的优劣势,影响到 Redis 的访问性能和可靠性。

02数据结构:

底层数据结构一共有 6 种,分别是简单动态字符串、双向链表、压缩列表、哈希表、跳表和整数数组。

Redis 解决哈希冲突的方式,就是链式哈希。链式哈希也很容易理解,就是指同一个哈希桶中的多个元素用一个链表来保存,它们之间依次用指针连接。

冲突太多后,redis需要rehash。采取双哈希表,结合渐进式 rehash:

简单来说就是在第二步拷贝数据时,Redis 仍然正常处理客户端请求,每处理一个请求时,从哈希表 1 中的第一个索引位置开始,顺带着将这个索引位置上的所有 entries 拷贝到哈希表 2 中;等处理下一个请求时,再顺带拷贝哈希表 1 中的下一个索引位置的 entries。(那么如果没有请求呢?)

压缩列表, 和数组类似,使用连续的内存空间,但允许数据大小不同。

跳表,有序链表中添加多级索引(步程变跨大)。

Hash 类型的 HGETALL 和 Set 类型的 SMEMBERS,或者返回一个范围内的部分数据,比如 List 类型的 LRANGE 和 ZSet 类型的 ZRANGE。这类操作的复杂度一般是 O(N),比较耗时,我们应该尽量避免。Redis 从 2.8 版本开始提供了 SCAN 系列操作(包括 HSCAN,SSCAN 和 ZSCAN),这类操作实现了渐进式遍历,每次只返回有限数量的数据。

03高性能IO模型

Redis 是单线程,主要是指 Redis 的网络 IO 和键值对读写是由一个线程来完成的,这也是 Redis 对外提供键值存储服务的主要流程。(真是蛋疼有称呼,它还是有其他线程的)

04 AOF日志

数据库的写前日志(Write Ahead Log, WAL),也就是说,在实际写数据前,先把修改的数据记到日志文件中,以便故障时进行恢复。不过,AOF 日志正好相反,它是写后日志,“写后”的意思是 Redis 是先执行命令,把数据写入内存,然后才记录日志。写后日志这一方式,避免出现记录错误命令。

AOF 机制给我们提供了三个选择,也就是 AOF 配置项 appendfsync 的三个可选值。

Always,Everysec,No.

AOF 重写,它相当于只记录最后的值,把overwrite的删掉,从而减少日志的大小。这个可以异步执行。

05内存快照

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

  1. save:在主线程中执行,会导致阻塞;

  2. bgsave:创建一个子进程,专门用于写入 RDB 文件,避免了主线程的阻塞,这也是 Redis RDB 文件生成的默认配置。

Redis 就会借助操作系统提供的写时复制技术(Copy-On-Write, COW),在执行快照的同时,正常处理写操作。

增量快照

Redis 4.0 中提出了一个混合使用 AOF 日志和内存快照的方法。

06数据同步:主从库数据一致性

当我们启动多个 Redis 实例的时候,它们相互之间就可以通过 replicaof(Redis 5.0 之前使用 slaveof)命令形成主库和从库的关系,之后会按照三个阶段完成数据的第一次同步。

  1. 从库给主库发送 psync 命令,表示要进行数据同步.psync 包含 runID和offset参数, offset -1从头开始复制。

  2. 主库将所有数据同步给从库。从库收到数据后,在本地完成数据加载。主库生成RDB文件,并发送给从库。

  3. 在生成RDB后的相关操作记录在replication buffer,在上面完成后也会同步给从库。

从 Redis 2.8 开始,网络断了之后,主从库会采用增量复制的方式继续同步。

网络断开

当主从库断连后,主库会把断连期间收到的写操作命令,写入 replication buffer,同时也会把这些操作命令也写入 repl_backlog_buffer 这个缓冲区。

repl_backlog_buffer 是一个环形缓冲区。如果从库的读取速度比较慢,就有可能导致从库还未读取的操作被主库新写的操作覆盖了,这会导致主从库间的数据不一致。我们可以调整 repl_backlog_size 这个参数。

07哨兵机制

哨兵其实就是一个运行在特殊模式下的 Redis 进程,主从库实例运行的同时,它也在运行。哨兵主要负责的就是三个任务:监控、选主(选择主库)和通知。

哨兵集群

08哨兵集群

基于 pub/sub 机制的哨兵集群组成

基于 pub/sub 机制的客户端事件通知

09切片集群

简单说就是分库。

11 string的局限

String 类型就会用简单动态字符串(Simple Dynamic String,SDS)结构体来保存,包含buf, len, alloc三个字段。

Redis不同数据类型都有些相同的元数据要记录(比如最后一次访问的时间、被引用的次数等),所以,Redis 会用一个 RedisObject 结构体来统一记录这些元数据,同时指向实际数据。

Redis 使用的内存分配库 jemalloc 。jemalloc 在分配内存时,会根据我们申请的字节数 N,找一个比 N 大,但是最接近 N 的 2 的幂次数作为分配的空间,这样可以减少频繁分配的次数。如果你申请 6 字节空间,jemalloc 实际会分配 8 字节空间;如果你申请 24 字节空间,jemalloc 则会分配 32 字节。(这个....)

Redis 有一种底层数据结构,叫压缩列表(ziplist),这是一种非常节省内存的结构。

Redis 基于压缩列表实现了 List、Hash 和 Sorted Set 这样的集合类型,这样做的最大好处就是节省了 dictEntry 的开销。

以图片 ID 1101000060 和图片存储对象 ID 3302000080 为例,我们可以把图片 ID 的前 7 位(1101000)作为 Hash 类型的键,把图片 ID 的最后 3 位(060)和图片存储对象 ID 分别作为 Hash 类型值中的 key 和 value。

hset 1101000 060  3302000080 

在刚才的二级编码中,我们只用图片 ID 最后 3 位作为 Hash 集合的 key,也就保证了 Hash 集合的元素个数不超过 1000,同时,我们把 hash-max-ziplist-entries 设置为 1000,这样一来,Hash 集合就可以一直使用压缩列表来节省内存空间了。

(这种只有在数据占满hashset的时候才真正省内存吧,数据多时才把成本压下来)

redis容量估计

12 有一亿个keys要统计,应该用哪种集合?

集合类型常见的四种统计模式,包括聚合统计、排序统计、二值状态统计和基数统计。

[ SDIFFSTORE destination key1 key2] 返回给定所有集合的差集并存储在 destination 中

[SINTER key1 key2] 返回给定所有集合的交集

[SINTERSTORE destination key1 key2] 返回给定所有集合的交集并存储在 destination 中

在 Redis 常用的 4 个集合类型中(List、Hash、Set、Sorted Set),List 和 Sorted Set 就属于有序集合。

List 是按照元素进入 List 的顺序进行排序的,而 Sorted Set 可以根据元素的权重来排序。

Bitmap 本身是用 String 类型作为底层数据结构实现的一种统计二值状态的数据类型。

HyperLogLog 是一种用于统计基数的数据集合类型,它的最大优势就在于,当集合元素数量非常多时,它计算基数所需的空间总是固定的,而且还很小。

不过,有一点需要你注意一下,HyperLogLog 的统计规则是基于概率完成的,所以它给出的统计结果是有一定误差的,标准误算率是 0.81%。这也就意味着,你使用 HyperLogLog 统计的 UV 是 100 万,但实际的 UV 可能是 101 万。虽然误差率不算大,但是,如果你需要精确统计结果的话,最好还是继续用 Set 或 Hash 类型。

13 GEO经纬坐标

Location-Based Service,LBS.

为了能高效地对经纬度进行比较,Redis 采用了业界广泛使用的 GeoHash 编码方法,这个方法的基本原理就是“二分区间,区间编码”。

GeoHash 的编码方法,利用二分法和二进制记数,在进行第一次二分区时,经度范围[-180,180]会被分成两个子区间:[-180,0) 和[0,180](我称之为左、右分区),左0右1。经度纬度分别编码。

在使用 GEO 类型时,我们经常会用到两个命令,分别是 GEOADD 和 GEORADIUS。

  • GEOADD 命令:用于把一组经纬度信息和相对应的一个 ID 记录到 GEO 类型集合中;

  • GEORADIUS 命令:会根据输入的经纬度位置,查找以这个经纬度为中心的一定范围内的其他元素。当然,我们可以自己定义这个范围。

如何自定义数据类型?

RedisObject 的元数据

  • type:表示值的类型,涵盖了我们前面学习的五大基本类型;

  • encoding:是值的编码方式,用来表示 Redis 中实现各个基本类型的底层数据结构,例如 SDS、压缩列表、哈希表、跳表等;

  • lru:记录了这个对象最后一次被访问的时间,用于淘汰过期的键值对;

  • refcount:记录了对象的引用计数;

  • *ptr:是指向数据的指针。

需要修改redis代码,先是定义数据结构和结构的new release函数,再是实现新数据类型的命令。

14 如何在redis中保存时间序列数据

无学习

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

FatherOfCodingMan

如果觉得有用的话,可以赏点饭钱

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

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

打赏作者

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

抵扣说明:

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

余额充值