Redis第十章 Redis HyperLogLog与事务、Redis 7.0前瞻

news2024/11/17 17:40:10

HyperLogLog

HyperLogLog(Hyper[ˈhaɪpə®])并不是一种新的数据结构(实际类型为字符串类型),而是一种基数算法,通过 HyperLogLog 可以利用极小的内存空间完成独立总数的统计,数据集可以是 IP、Email、ID 等。
如果你的页面访问量非常大,比如一个爆款页面几千万的 UV(登录的用户数),你需要一个很大的 set 集合来统计,这就非常浪费空间。

这就是 HyperLogLog 的用武之地,Redis 提供了 HyperLogLog 数据结构就是用来解决这种统计问题的。HyperLogLog 提供不精确的去重计数方案,虽然不精确但是也不是非常不精确,Redis 官方给出标准误差是 0.81%,这样的精确度已经可以满足上面的 UV 统计需求了

操作命令

HyperLogLog 提供了 3 个命令: pfadd、pfcount、pfmerge。
例如 08-15 的访问用户是 u1、u2、u3、u4,
08-16 的访问用户是 u-4、u-5、u-6、u-7

  1. pfadd
 pfadd key element [element …]

pfadd 用于向 HyperLogLog 添加元素,如果添加成功返回 1:
在这里插入图片描述
2. pfcount

pfcount key [key …]

pfcount 用于计算一个或多个 HyperLogLog 的独立总数,例如 08-15:u:id 的独立总数为 4:
在这里插入图片描述
如果此时向插入 u1、u2、u3、u90,结果是 5:
在这里插入图片描述
如果我们继续往里面插入数据,比如插入 100 万条用户记录。内存增加非常少,但是 pfcount 的统计结果会出现误差。
在这里插入图片描述

  1. pfmerge
pfmerge destkey sourcekey [sourcekey ... ]

pfmerge 可以求出多个 HyperLogLog 的并集并赋值给 destkey
在这里插入图片描述
原理概述
HyperLogLog 基于概率论中伯努利试验并结合了极大似然估算方法,并做了分桶优化。
实际上目前还没有发现更好的在大数据场景中准确计算基数的高效算法,因此在不追求绝对准确的情况下,使用概率算法算是一个不错的解决方案。概率算法不直接存储数据集合本身,通过一定的概率统计方法预估值,这种法可以大大节省内存,同时保证误差控制在一定范围内。目前用于基数计数的概率算法包括:
Linear Counting(LC):早期的基数估计算法,LC 在空间复杂度方面并不算优秀;
LogLog Counting(LLC):LogLog Counting 相比于 LC 更加节省内存,空间复杂度更低;
HyperLogLog Counting(HLL):HyperLogLog Counting 是基于 LLC 的优化和改进,在同样空间复杂度情况下,能够比 LLC 的基数估计误差更小。
在这里插入图片描述
k 是每回合抛到 1(硬币的正面)所用的次数,我们已知的是最大的 k 值,也就是 Mark 老师告诉 Fox 老师的数,可以用 k_max 表示。由于每次抛硬币的结果只有 0 和 1 两种情况,因此,能够推测出 k_max 在任意回合出现的概率 ,并由 kmax 结合极大似然估算的方法推测出 n 的次数 n = 2^(k_max) 。概率学把这种问题叫做伯努利实验。
所以这种预估方法存在较大误差,为了改善误差情况,HLL 中引入分桶平均的概念。

分桶平均的基本原理是将统计数据划分为 m 个桶,每个桶分别统计各自的k_max, 并能得到各自的基数预估值,最终对这些基数预估值求平均得到整体的基数估计值。LLC 中使用几何平均数预估整体的基数值,但是当统计数据量较小时误差较大;HLL 在 LLC 基础上做了改进,采用调和平均数过滤掉不健康的统计值。

什么叫调和平均数呢?举个例子
求平均工资:A 的是 1000/月,B 的 30000/月。采用平均数的方式就是:(1000 + 30000) / 2 = 15500
采用调和平均数的方式就是: 2/(1/1000 + 1/30000) ≈ 1935.484
可见调和平均数比平均数的好处就是不容易受到大的数值的影响,比平均数的效果是要更好的。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

事务

Redis 事务
事务表示一组动作,要么全部执行,
要么全部不执行。例如在社交网站上用户 A 关注了用户 B,那么需要在用户 A 的关注表中加入用户 B,并且在用户 B 的粉丝表中添加用户 A,这两个行为要么全部执行,要么全部不执行,否则会出现数据不一致的情况。
Redis 提供了简单的事务功能,将一组需要一起执行的命令放到 multi 和 exec两个命令之间。multi 命令代表事务开始,exec命令代表事务结束,如果要停止事务的执行,可以使用 discard 命令代替 exec 命令即可。
它们之间的命令是原子顺序执行的,例如下面操作实现了上述用户关注问题。
在这里插入图片描述
可以看到 sadd 命令此时的返回结果是 QUEUED,代表命令并没有真正执行,而是暂时保存在 Redis 中的一个缓存队列(所以 discard 也只是丢弃这个缓存队列中的未执行命令,并不会回滚已经操作过的数据,这一点要和关系型数据库的Rollback 操作区分开)。
如果此时另一个客户端执行

sismember user1 1

在这里插入图片描述
只有当 exec 执行后
在这里插入图片描述
才会存入进去
在这里插入图片描述
如果事务中的命令出现错误,Redis 的处理机制也不尽相同。
1、命令错误
例如下面操作错将 set 写成了 sett,属于语法错误,会造成整个事务无法执行,key 和 counter 的值未发生变化:
在这里插入图片描述
2.运行时错误
例如误把sadd命令(针对集合)写成了zadd命令(针对有序集合),这种就是运行时命令,因为语法是正确的:
在这里插入图片描述
可以看到 Redis 并不支持回滚功能,sadd user4 2 命令已经执行成功,开发人员需要自己修复这类问题。

有些应用场景需要在事务之前,确保事务中的 key 没有被其他客户端修改过,才执行事务,否则不执行(类似乐观锁)。Redis 提供了 watch 命令来解决这类问题。

客户端1在这里插入图片描述
客户端2在这里插入图片描述
客户端 1 继续:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
Pipeline 和事务的区别
1、pipeline 是客户端的行为,对于服务器来说是透明的,可以认为服务器无法区分客户端发送来的查询命令是以普通命令的形式还是以 pipeline 的形式发送到服务器的;

2 而事务则是实现在服务器端的行为,用户执行 MULTI 命令时,服务器会将对应这个用户的客户端对象设置为一个特殊的状态,在这个状态下后续用户执行的查询命令不会被真的执行,而是被服务器缓存起来,直到用户执行 EXEC 命令为止,服务器会将这个用户对应的客户端对象中缓存的命令按照提交的顺序依次执行。

3、应用 pipeline 可以提服务器的吞吐能力,并提高 Redis 处理查询请求的能力。
但是这里存在一个问题,当通过 pipeline 提交的查询命令数据较少,可以被内核缓冲区所容纳时,Redis 可以保证这些命令执行的原子性。然而一旦数据量过大,超过了内核缓冲区的接收大小,那么命令的执行将会被打断,原子性也就无法得到保证。因此 pipeline 只是一种提升服务器吞吐能力的机制,如果想要命令以事务的方式原子性的被执行,还是需要事务机制,或者使用更高级的脚本功能以及模块功能。

4、可以将事务和 pipeline 结合起来使用,减少事务的命令在网络上的传输时间,将多次网络 IO 缩减为一次网络 IO。

Redis 提供了简单的事务,之所以说它简单,主要是因为它不支持事务中的回滚特性,同时无法实现命令之间的逻辑关系计算,当然也体现了 Redis 的“keep it simple”的特性。

Redis 7.0 前瞻

Redis 主从复制原理
Redis 主从复制的基本原理。Redis 的主从复制主要分为两种情况:

  • 全量同步
    主库通过 fork 子进程产生内存快照,然后将数据序列化为 RDB 格式同步到从库,使从库的数据与主库某一时刻的数据一致。
  • 命令传播(增量同步)
    当从库与主库完成全量同步后,进入命令传播阶段,主库将变更数据的命令发送到从库,从库将执行相应命令,使从库与主库数据持续保持一致。

Redis 复制缓存区相关问题分析
多从库时主库内存占用过多
OutputBuffer 拷贝和释放的堵塞问题
Redis 为了提升多从库全量复制的效率和减少 fork 产生 RDB 的次数,会尽可能的让多个从库共用一个 RDB,从代码(replication.c)上看:
在这里插入图片描述
当已经有一个从库触发 RDB BGSAVE 时,后续需要全量同步的从库会共享这次 BGSAVE 的 RDB,为了从库复制数据的完整性,会将之前从库的OutputBuffer 拷贝到请求全量同步从库的 OutputBuffer 中。
其中的 copyClientOutputBuffer 可能存在堵塞问题,因为 OutputBuffer 链表上的数据可达数百 MB 甚至数 GB 之多,对其拷贝可能使用百毫秒甚至秒级的时间,而且该堵塞问题没法通过日志或者 latency 观察到,但对 Redis 性能影响却很大。
同样地,当 OutputBuffer 大小触发 limit 限制时,Redis 就是关闭该从库链接,而在释放 OutputBuffer 时,也需要释放数百 MB 甚至数 GB 的数据,其耗时对 Redis 而言也很长。

ReplicationBacklog 的限制
复制积压缓冲区 ReplicationBacklog 是 Redis 实现部分重同步的
基础,如果从库可以进行增量同步,则主库会从 ReplicationBacklog 中拷贝从库缺失的数据到其 OutputBuffer。拷贝的数据量最大当然是 ReplicationBacklog 的大小,为了避免拷贝数据过多的问题,通常不会让该值过大,一般百兆左右。但在大容量实例中,为了避免由于主从网络中断导致的全量同步,又希望该值大一些,这就存在矛盾了。
而且如果重新设置 ReplicationBacklog 大小时,会导致 ReplicationBacklog 中的内容全部清空,所以如果在变更该配置期间发生主从断链重连,则很有可能导致全量同步。

Redis7.0 共享复制缓存区的设计与实现
每个从库在主库上单独拥有自己的 OutputBuffer,但其存储的内容却是一样的,一个最直观的想法就是主库在命令传播时,将这些命令放在一个全局的复制数据缓冲区中,多个从库共享这份数据,不同的从库对引用复制数据缓冲区中不同的内容,这就是『共享复制缓存区』方案的核心思想。实际上,复制积压缓冲区(ReplicationBacklog)中的内容与从库 OutputBuffer 中的数据也是一样的,所以该方案中,ReplicationBacklog 和从库一样共享一份复制缓冲区的数据,也避免了 ReplicationBacklog 的内存开销。

『共享复制缓存区』方案中复制缓冲区 (ReplicationBuffer) 的表示采用链表的表示方法,将 ReplicationBuffer 数据切割为多个 16KB 的数据块(replBufBlock),然后使用链表来维护起来。为了维护不同从库的对ReplicationBuffer 的使用信息,在 replBufBlock 中存在字段:
refcount:block 的引用计数
id:block 的唯一标识,单调递增的数值
repl_offset:block 开始的复制偏移
在这里插入图片描述
ReplicationBuffer 由多个 replBufBlock 组成链表,当 复制积压区 或从库对某个 block 使用时,便对正在使用的 replBufBlock 增加引用计数,上图中可以看到,复制积压区正在使用的 replBufBlock refcount 是 1,从库 A 和 B 正在使用的 replBufBlock refcount 是 2。当从库使用完当前的 replBufBlock(已经将数据发送给从库)时,就会对其 refcount 减 1 而且移动到下一个 replBufBlock,并对其 refcount 加 1。

堵塞问题和限制问题的解决
多从库消耗内存过多的问题通过共享复制缓存区方案得到了解决,对于
OutputBuffer 拷贝和释放的堵塞问题和 ReplicationBacklog 的限制问题是否解决了呢?
首先来看 OutputBuffer 拷贝和释放的堵塞问题问题, 这个问题很好解决,因为 ReplicationBuffer 是个链表实现,当前从库的 OutputBuffer 只需要维护共享 ReplicationBuffer 的引用信息即可。所以无需进行数据深拷贝,只需要更新引用信息,即对正在使用的 replBufBlock refcount 加 1,这仅仅是一条简单的赋值操作,非常轻量。
OutputBuffer 释放问题呢?在当前的方案中释放从库
OutputBuffer 就变成了对其正在使用的 replBufBlock refcount 减 1,是一条赋值操作,不会有任何阻塞。
对于 ReplicationBacklog 的限制问题也很容易解决了,因为
ReplicatonBacklog 也只是记录了对 ReplicationBuffer 的引用信息,对
ReplicatonBacklog 的拷贝也仅仅成了找到正确的 replBufBlock,然后对其refcount 加 1。这样的话就不用担心 ReplicatonBacklog 过大导致的拷贝堵塞问题。而且对 ReplicatonBacklog 大小的变更也仅仅是配置的变更,不会清掉数据。

ReplicationBuffer 的裁剪和释放
在这里插入图片描述
数据结构的选择
在这里插入图片描述

选择记录

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/634320.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JUC基础认识(2)

线程池(重点):3大方法,7大参数,4种拒绝策略 程序运行的本质:占用系统资源!优化资源的使用!----->池化技术 池化技术的好处: 1.降低资源的消耗 2.提高响应速度 3.方便管理 线程复用,可以控制最大…

Java ~ Reference ~ FinalizerHistogram【总结】

前言 文章 相关系列:《Java ~ Reference【目录】》(持续更新)相关系列:《Java ~ Reference ~ FinalizerHistogram【源码】》(学习过程/多有漏误/仅作参考/不再更新)相关系列:《Java ~ Referenc…

通俗讲解元学习(Meta-Learning)

元学习通俗的来说,就是去学习如何学习(Learning to learn),掌握学习的方法,有时候掌握学习的方法比刻苦学习更重要! 下面我们进行详细讲解 1. 从传统机器学习到元学习 传统的机器学中,我们选择一个算法&…

Fiddler汉化(一箭三连)

我安装的fiddler 操作系统是:Win10 64Bit 操作系统的版本号是:v5.0.20194.41348 for .NET 4.6.1 fiddler下载地址: 我用夸克网盘分享了「02-Web调试工具-FiddlerSetup.exe」,点击链接即可保存。 链接:https://pan.quar…

python调用go语言的代码

最近在学习上述Python,go语言,研究下互相调用的事项,在windows下使用 linux下: gcc -o libpycall.so -shared -fPIC pycall.c windows下: gcc -o libpycall.dll -shared -fPIC pycall.c 但是实际的过程中编译成*.so…

使用扩展卡尔曼滤波(EKF)融合激光雷达和雷达数据(Matlab代码实现)

💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…

复习js的Object.defineProperty()

今天在看尚硅谷的Vue2时,讲到了Object.defineProperty()方法,有点忘了,所以找资料复习了一下。 总说 Object.defineProperty()是一种用于定义对象属性的JavaScript方法,它允许开发人员精确控制一个属性的行为,并可以…

【MySQL】库表的基本操作

文章目录 数据库的基本操作增查删改切入查看当前使用数据库 数据表的基本操作增查所有表查指定表查表字段信息删表改表名改字段名改字段属性增字段删字段 数据表的约束主键约束(PRIMARY KEY)非空约束(NOT NULL)默认值约束(DEFAULT)唯一性约束(UNIQUE)外键约束(FOREIGN KEY)删除…

VSCode 配置 C++ 环境

文章目录 VSCode 配置 C 环境1. 配置 C 编译器1.1 下载 MinGW1.2 添加环境变量1.3 测试 2. 配置编辑器 VSCode2.1 下载 VSCode2.2 安装插件2.3 运行代码 3. 优化Reference VSCode 配置 C 环境 VSCode(Visual Studio Code)是一款轻量级的代码编辑器&…

Linux系统之部署Node.js环境

Linux系统之部署Node.js环境 一、Node.js介绍1.1 Node.js简介1.2 npm简介1.3 Node.js官网 二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍 三、部署Node.js环境3.1 下载Node.js安装包3.2 解压Node.js安装包3.3 复制二进制文件3.4 配置环境变量3.5 检查node及npm版本 四、NP…

EXCEL的自定义格式,比如 @_ ,一个我很少用的功能的简单总结

目录 前言 1 入口: 2 有用的一些功能 2.1 可以自动在 你输入的字符串前后加 预设内容 2.1.1 具体见下面 2.1.2 对比EXCEL得常用拖动功能 2.2 设置填充下划线 2.2.1 效果如下 2.2.2 问题 2.2.3 下划线的显示问题 2.3 比如 #.## 2.4 比如 000.000 2.5 比…

自动化测试webdriver常用API总结

目录 前言: 1. selenium的简单介绍 2. selnium的下载 3. WebDriver常用API 前言: WebDriver 是一个自动化测试工具,主要用于模拟浏览器行为,实现自动化测试。下面是一些 WebDriver 常用 API 总结: 1. selenium的…

STM32--ESP8266物联网WIFI模块(贝壳物联)--远程无线控制点灯

本文适用于STM32F103C8T6等MCU,其他MCU可以移植,完整资源见文末链接 一、简介 随着移动物联网的发展,各场景下对于物联控制、数据上传、远程控制的诉求也越来越多,基于此乐鑫科技推出了便宜好用性价比极高的wifi物联模块——ESP…

CentOS 7.6安装 MongoDB 5.0.2

1、选择下载地址 进入下载官网 https://www.mongodb.com/try/download/community 选择右侧MongoDB Community Server Version:5.0.2(current) Platform:RedHat / CentOS 7.0 Package:tgz 点击Copy复制 安装位置&am…

爆肝总结,软件测试-常见并发问题+解决方案,测试进阶...

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 并发测试的定义 …

LVS负载均衡--NET模式

目录 企业群集应用概率 群集的含义 问题 根据群集所针对的目标差异,可分为三种类型 负载均衡群集(Load Balance Cluster) 高可用群集(High Availability Cluster) 高性能运算群集(High Performance Computer Cluster) 负载均衡群集架构 负载均衡的结构 LV…

XuperChain搭建+报错+注意事项

安装依赖 golang 这里安装的是15-17版本 wget -c https://dl.google.com/go/go1.15.2.linux-amd64.tar.gz -O - | sudo tar -xz -C /usr/local 添加环境变量 这个可以通过添加下面的行到/etc/profile文件(系统范围内安装)或者$HOME/.profile文件(当前用户安装 vim /etc…

论文笔记--GPT-4 Technical Report

论文笔记--GPT-4 Technical Report 1. 报告简介2. 报告概括3 报告重点内容3.1 Predictable Scaling3.2 Capabilities3.3 limitations3.3 Risks & mitigations 4. 报告总结5. 报告传送门6. References 1. 报告简介 标题:GPT-4 Technical Report作者:…

机器学习——单变量线性回归、梯度下降

文章目录 一、机器学习的分类二、线型回归Linear regression(单变量线性回归)三、代价函数3.1 建模误差3.2 平方误差代价函数 Squared error cost function3.3 梯度下降3.4 梯度下降与线性回归相结合 一、机器学习的分类 监督学习:学习数据带…

算法模板(3):搜索(6):做题积累

算法模板(3):搜索(6):做题积累 一、DFS 1. 1113. 红与黑 有一间长方形的房子,地上铺了红色、黑色两种颜色的正方形瓷砖。你站在其中一块黑色的瓷砖上,只能向相邻(上下…