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

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 的裁剪和释放
在这里插入图片描述
数据结构的选择
在这里插入图片描述

选择记录

在这里插入图片描述

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【工具】SecureCR-8.5下载、安装激活和使用教程(包含常用设置)

目录 一、安装包下载 二、安装教程 三、激活操作 四、使用教程 五、常用设置 一、安装包下载 SecureCRT8.5安装包: 链接:https://pan.baidu.com/s/1yy677I99ln_3evoHc5dMXg 提取码:9tyj 二、安装教程 1. 解压、双击进行安装 2. 安装进…

oppo r11 升级8.1系统 图文教程

Time: 2023年6月11日13:39:25 By:MemroyErHero 1 预留一定的空间,存放刷机包. 2 导入刷机包 r11.ozip 到手机上 3 手机文件管理器 打开 r11.ozip 文件 4 点击立即更新即可 5 重要的事情说三遍,刷机过程中 不能关机 不能断电 否则会变成砖头 重要的事情说三遍,刷机过程中 …

Java实训日记第一天——2023.6.6

这里写目录标题 一、关于数据库的增删改查总结:五步法1.增2.删3.改4.查 二、设计数据库的步骤第一步:收集信息第二步:标识对象第三步:标识每个实体的属性第四步:标识对象之间的关系 一、关于数据库的增删改查 总结&am…

web worker创建多个 JavaScript 线程 (使用GTP写的文章)

前言 最近在优化公司的一个项目,使用的就是web worker去优化,做了那些优化,一个是状态的优化,(通信的状态实时更新,以前的做法是做个定时任务实时获取它的状态,然后让它在页面渲染,这…

Baumer工业相机堡盟工业相机如何使用BGAPISDK对两个万兆网相机进行触发同步(C#)

Baumer工业相机堡盟工业相机如何使用BGAPISDK对两个万兆网相机进行触发同步(C#) Baumer工业相机Baumer工业相机BGAPISDK和触发同步的技术背景Baumer工业相机使用BGAPISDK进行双相机主从相机触发1.引用合适的类文件2.使用BGAPISDK设置主相机硬件触发从相机…

【C++】一文带你吃透C++多态

🍎 博客主页:🌙披星戴月的贾维斯 🍎 欢迎关注:👍点赞🍃收藏🔥留言 🍇系列专栏:🌙 C/C专栏 🌙那些看似波澜不惊的日复一日,…

详解WEB集群服务(LNMP+Nginx+Tomcat+Rewrite重写+七层反向代理+SNAT|DNAT策略)

实战项目演练 1.问题描述2.实验操作步骤2.1 CentOS 7-1客户端配置2.2 CentOS 7-2网关服务器配置2.3 CentOS 7-8 (Web1:Tomcat服务器)2.3.1 安装Tomcat服务器2.3.2 提供四层反向代理的动态页面 2.4 CentOS 7-9 (Nginx服务器)2.4.1 安装Nginx服务2.4.2 安装MySQL服务2.4.3 安装配…

算法刷题-哈希表-两数之和

两数之和 1. 两数之和思路总结其他语言版本 1. 两数之和 力扣题目链接 给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。 你可以假设每种输入只会对应一个答案。但是,数组中…

CSS基础学习--6 CSS Text(文本)

一、文本颜色 color:red; 颜色属性被用来设置文字的颜色。 颜色是通过CSS最经常的指定: 十六进制值 - 如: #FF0000一个RGB值 - 如: RGB(255,0,0)颜色的名称 - 如: red body {color:red;} h1 {color:#00ff00;} h2 {color:rgb(255,0,0);} 二、文本的…

无敌!我用【C语言】手搓出了一个体系完整的【员工管理系统】还能玩游戏听音乐?(超详细,附完整源码)

博主简介:Hello大家好呀,我是陈童学,一个与你一样正在慢慢前行的人。 博主主页:陈童学哦 所属专栏:C语言程序设计实验项目 如果本文对你有所帮助的话,还希望可以点赞👍收藏📂支持一下…

【云原生 | 53】Docker三剑客之Docker Compose应用案例一:Web负载均衡

🍁博主简介: 🏅云计算领域优质创作者 🏅2022年CSDN新星计划python赛道第一名 🏅2022年CSDN原力计划优质作者 🏅阿里云ACE认证高级工程师 🏅阿里云开发者社区专…

React Hook入门小案例 在函数式组件中使用state响应式数据

Hook是react 16.8 新增的特性 是希望在不编写 class的情况下 去操作state和其他react特性 Hook的话 就不建议大家使用class的形式了 当然也可以用 这个他只是不推荐 我们还是先创建一个普通的react项目 我们之前写一个react组件可以这样写 import React from "react&qu…

Java ~ Reference ~ ReferenceQueue【总结】

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

【前端 - CSS】第 9 课 - CSS 初体验

欢迎来到博主 Apeiron 的博客,祝您旅程愉快 ! 时止则止,时行则行。动静不失其时,其道光明。 目录 1、CSS 定义 2、基础选择器 3、文字控制属性 4、示例代码 5、总结 1、CSS 定义 层叠样式表(Cascading Style …

前端vue地图定位并测算当前定位离目标位置距离

前端vue地图定位并测算当前定位离目标位置距离, 下载完整代码请访问uni-app插件市场地址: https://ext.dcloud.net.cn/plugin?id12974 效果图如下: # #### 使用方法 使用方法 <!-- // 腾讯地图key注册地址&#xff08;针对H5端&#xff0c;manifest.json中web配置&…

触发器和事件自动化的讲解

触发器和事件自动化 一、触发器 1、触发器的基本概念 触发器是和表相关的一种数据库对象&#xff0c;可以将他看作一种特殊的存储过程&#xff0c;不需要人为调动的存储过程。 关键字&#xff1a;trigger 基本作用&#xff1a;通过对表进行数据的插入、更新或删除等操作来触…

XGBoost的介绍

一、XGBoost的介绍 1.什么是XGBoost&#xff1f; XGBoost&#xff08;eXtreme Gradient Boosting&#xff09;是一种基于梯度提升树的机器学习算法&#xff0c;它在解决分类和回归问题上表现出色。它是由陈天奇在2014年开发的&#xff0c;如今已成为机器学习领域中最流行和强…

那年我头脑发热,选择了自动化,后来我掉入计算机的世界无法自拔

首先&#xff0c;小雅兰是22届高考考生&#xff0c;而且当时填报志愿也没有填报到计算机相关的专业去&#xff0c;小雅兰是自动化专业的学生&#xff0c;是由于一次偶然的机会&#xff0c;了解到了这个行业&#xff0c;对于写代码所带来的成就感&#xff0c;总之&#xff0c;我…

2023春期末考试选择题R2-9AVL树插入调整详解

题目&#xff1a; 将 8, 9, 7, 2, 3, 5, 6, 4 顺序插入一棵初始为空的AVL树。下列句子中哪句是错的&#xff1f; A. 4 和 6 是兄弟 B. 5 是 8 的父结点 C. 7 是根结点 D. 3 和 8 是兄弟 解题要点&#xff1a; 需要对AVL树的4种旋转方式熟悉。 AVL旋转过程&#xff1a; 根据…