如何为海量计数场景设计缓存体系?no.34

计数常规方案

在这里插入图片描述
计数服务在互联网系统中非常常见,用户的关注粉丝数、帖子数、评论数等都需要进行计数存储。计数的存储格式也很简单,key 一般是用户 uid 或者帖子 id 加上后缀,value 一般是 8 字节的 long 型整数。

最常见的计数方案是采用缓存 + DB 的存储方案。当计数变更时,先变更计数 DB,计数加 1,然后再变更计数缓存,修改计数存储的 Memcached 或 Redis。这种方案比较通用且成熟,但在高并发访问场景,支持不够友好。在互联网社交系统中,有些业务的计数变更特别频繁,比如微博 feed 的阅读数,计数的变更次数和访问次数相当,每秒十万到百万级以上的更新量,如果用 DB 存储,会给 DB 带来巨大的压力,DB 就会成为整个计数服务的瓶颈所在。即便采用聚合延迟更新 DB 的方案,由于总量特别大,同时请求均衡分散在大量不同的业务端,巨大的写压力仍然是 DB 的不可承受之重。因此这种方案只适合中小规模的计数服务使用。

在这里插入图片描述
在 Redis 问世并越来越成熟后,很多互联网系统会直接把计数全部存储在 Redis 中。通过 hash 分拆的方式,可以大幅提升计数服务在 Redis 集群的写性能,通过主从复制,在 master 后挂载多个从库,利用读写分离,可以大幅提升计数服务在 Redis 集群的读性能。而且 Redis 有持久化机制,不会丢数据,在很多大中型互联网场景,这都是一个比较适合的计数服务方案。

在互联网移动社交领域,由于用户基数巨大,每日发表大量状态数据,且相互之间有大量的交互动作,从而产生了海量计数和超高并发访问,如果直接用 Redis 进行存储,会带来巨大的成本和性能问题。

海量计数场景

以微博为例,系统内有大量的待计数对象。如从用户维度,日活跃用户 2 亿+,月活跃用户接近 5 亿。从 Feed 维度,微博历史 Feed 有数千亿条,而且每日新增数亿条的新 Feed。这些用户和 Feed 不但需要进行计数,而且需要进行多个计数。比如,用户维度,每个用户需要记录关注数、粉丝数、发表 Feed 数等。而从 Feed 维度,每条 Feed 需要记录转发数、评论数、赞、阅读等计数。

而且,在微博业务场景下,每次请求都会请求多个对象的多个计数。比如查看用户时,除了获取该用户的基本信息,还需要同时获取用户的关注数、粉丝数、发表 Feed 数。获取微博列表时,除了获取 Feed 内容,还需要同时获取 Feed 的转发数、评论数、赞数,以及阅读数。因此,微博计数服务的总访问量特别大,很容易达到百万级以上的 QPS。

因此,在海量计数高并发访问场景,如果采用缓存 + DB 的架构,首先 DB 在计数更新就会存在瓶颈,其次,单个请求一次请求数十个计数,一旦缓存 miss,穿透到 DB,DB 的读也会成为瓶颈。因为 DB 能支撑的 TPS 不过 3000~6000 之间,远远无法满足高并发计数访问场景的需要。

采用 Redis 全量存储方案,通过分片和主从复制,读写性能不会成为主要问题,但容量成本却会带来巨大开销。

因为,一方面 Redis 作为通用型存储来存储计数,内存存储效率低。以存储一个 key 为 long 型 id、value 为 4 字节的计数为例,Redis 至少需要 65 个字节左右,不同版本略有差异。但这个计数理论只需要占用 12 个字节即可。内存有效负荷只有 12⁄65=18.5%。如果再考虑一个 long 型 id 需要存 4 个不同类型的 4 字节计数,内存有效负荷只有 (8+16)/(65*4)= 9.2%。

另一方面,Redis 所有数据均存在内存,单存储历史千亿级记录,单份数据拷贝需要 10T 以上,要考虑核心业务上 1 主 3 从,需要 40T 以上的内存,再考虑多 IDC 部署,轻松占用上百 T 内存。就按单机 100G 内存来算,计数服务就要占用上千台大内存服务器。存储成本太高。

海量计数服务架构

在这里插入图片描述
为了解决海量计数的存储及访问的问题,微博基于 Redis 定制开发了计数服务系统,该计数服务兼容 Redis 协议,将所有数据分别存储在内存和磁盘 2 个区域。首先,内存会预分配 N 块大小相同的 Table 空间,线上一般每个 Table 占用 1G 字节,最大分配 10 个左右的 Table 空间。首先使用 Table0,当存储填充率超过阀值,就使用 Table1,依次类推。每个 Table 中,key 是微博 id,value 是自定义的多个计数。

微博的 id 按时间递增,因此每个内存 Table 只用存储一定范围内的 id 即可。内存 Table 预先按设置分配为相同 size 大小的 key-value 槽空间。每插入一个新 key,就占用一个槽空间,当槽位填充率超过阀值,就滚动使用下一个 Table,当所有预分配的 Table 使用完毕,还可以根据配置,继续从内存分配更多新的 Table 空间。当内存占用达到阀值,就会把内存中 id 范围最小的 Table 落盘到 SSD 磁盘。落盘的 Table 文件称为 DDB。每个内存 Table 对应落盘为 1 个 DDB 文件。

计数服务会将落盘 DDB 文件的索引记录在内存,这样当查询需要从内存穿透到磁盘时,可以直接定位到磁盘文件,加快查询速度。

计数服务可以设置 Schema 策略,使一个 key 的 value 对应存储多个计数。每个计数占用空间根据 Schema 确定,可以精确到 bit。key 中的各个计数,设置了最大存储空间,所以只能支持有限范围内的计数。如果计数超过设置的阀值,则需要将这个 key 从 Table 中删除,转储到 aux dict 辅助词典中。

同时每个 Table 负责一定范围的 id,由于微博 id 随时间增长,而非逐一递增,Table 滚动是按照填充率达到阀值来进行的。当系统发生异常时,或者不同区域网络长时间断开重连后,在老数据修复期间,可能在之前的 Table 中插入较多的计数 key。如果旧 Table 插入数据量过大,超过容量限制,或者持续搜索存储位置而不得,查找次数超过阀值,则将新 key 插入到 extend dict 扩展词典中。

微博中的 feed 一般具有明显的冷热区分,并且越新的 feed 越热,访问量越大,越久远的 feed 越冷。新的热 key 存放内存 Table,老的冷 key 随所在的 Table 被置换到 DDB 文件。当查询 DDB 文件中的冷 key 时,会采用多线程异步并行查询,基本不影响业务的正常访问。同时,这些冷 key 从 DDB 中查询后,会被存放到 LRU 中,从而方便后续的再次访问。

计数服务的内存数据快照仍然采用前面讲的 RDB + 滚动 AOF 策略。RDB 记录构建时刻对应的 AOF 文件 id 及 pos 位置。全量复制时,master 会将磁盘中的 DDB 文件,以及内存数据快照对应的 RDB 和 AOF 全部传送给 slave。

在之后的所有复制就是全增量复制,slave 在断开连接,再次重连 master 时,汇报自己同步的 AOF 文件 id 及位置,master 将对应文件位置之后的内容全部发送给 slave,即可完成同步。

在这里插入图片描述
计数服务中的内存 Table 是一个一维开放数据,每个 key-value 按照 Schema 策略占用相同的内存。每个 key-value 内部,key 和多个计数紧凑部署。首先 8 字节放置 long 型 key,然后按Schema 设置依次存放各个计数。

key 在插入及查询时,流程如下。

首先根据所有 Table 的 id 范围,确定 key 所在的内存 Table。

然后再根据 double-hash 算法计算 hash,用 2 个 hash 函数分别计算出 2 个 hash 值,采用公示 h1+N*h2 来定位查找。

在对计数插入或变更时,如果查询位置为空,则立即作为新值插入 key/value,否则对比 key,如果 key 相同,则进行计数增减;如果 key 不同,则将 N 加 1,然后进入到下一个位置,继续进行前面的判断。如果查询的位置一直不为空,且 key 不同,则最多查询设置的阀值次数,如果仍然没查到,则不再进行查询。将该 key 记录到 extend dict 扩展词典中。

在对计数 key 查找时,如果查询的位置为空,说明 key 不存在,立即停止。如果 key 相同,返回计数,否则 N 加 1,继续向后查询,如果查询达到阀值次数,没有遇到空,且 key 不同,再查询 aux dict 辅助字典 和 extend dict 扩展字典,如果也没找到该 key,则说明该 key 不存在,即计数为 0。

海量计数服务收益

微博计数服务,多个计数按 Schema 进行紧凑存储,共享同一个 key,每个计数的 size 按 bit 设计大小,没有额外的指针开销,内存占用只有 Redis 的 10% 以下。同时,由于 key 的计数 size 固定,如果计数超过阀值,则独立存储 aux dict 辅助字典中。

同时由于一个 key 存储多个计数,同时这些计数一般都需要返回,这样一次查询即可同时获取多个计数,查询性能相比每个计数独立存储的方式提升 3~5 倍。

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

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

相关文章

常见的100个Shell命令,超级实用!

在大多数的Linux和Unix系统、及其他类Unix系统中,Shell是用户与操作系统内核交互的主要方式。作为一种强大的命令行解释器,它也支持编程功能,用户可以写脚本来处理各种任务。 熟悉shell脚本,首先要对shell指令熟悉,今…

Vue3学习-用 vite@latest 初始化项目后,遇到无法识别 .vue 文件

引入app界面遇到 我的解决方案 1.根目录创建 env.d.ts&#xff0c;添加 declare module "*.vue" {import type { DefineComponent } from "vue"const vueComponent: DefineComponent<{}, {}, any>export default vueComponent }2.在 tsconfig.json…

基于ARM|DSP+FPGA+NVIDIA AI平台的摄像头ISP图像画质调试定制服务

基本框架及算法介绍 ISP(Image Signal Processor)&#xff0c;即图像处理&#xff0c;主要作用是对前端图像传感器输出的信号做后期处理&#xff0c;主要功能有线性纠正、噪声去除、坏点去除、内插、白平衡、自动曝光控制等&#xff0c;依赖于ISP才能在不同的光学条件下都…

scroll-snap-type——有滚动容器下吸附至吸附点的严格程度——css基础

scroll-snap-type有滚动容器下吸附至吸附点的严格程度&#xff1a;https://developer.mozilla.org/zh-CN/docs/Web/CSS/scroll-snap-type 此属性不为吸附点指定任何确切的动画或运行规律&#xff0c;留待用户代理处理。 //不吸附 scroll-snap-type:none; //表示吸附轴的关键字…

IPD在卷烟工业企业研发管理中应用

一、 什么是IPD IPD是Integrated Product Development几个英文单词的缩写&#xff0c;译成汉语就是“集成产品研发”&#xff0c;是上世纪九十年代以来世界上盛行的企业产品研发管理的成功模式。下文中汉捷咨询对IPD的由来进行分享。 最先将IPD付诸实践的是美国IBM公司。1992…

AI绘图副业创收,热门擦边变现赛道怎么玩?网友:瑟瑟才是人类前进的动力!

大家好&#xff0c;我是设计师阿威 今天给大家介绍一个用 AI 搞擦边的变现赛道 而且可以说是0 成本变现的 现在真的越来越多的人都想 0 成本变现&#xff0c;那么 0 成本到底能不能变现&#xff0c;变现的上下限又是多少&#xff1f; 今天这个案例就可以很好的进行说明 可以…

路由引入实验(华为)

思科设备参考&#xff1a;路由引入实验&#xff08;思科&#xff09; 技术简介 路由引入技术在网络通信中起着重要的作用&#xff0c;能够实现不同路由协议之间的路由传递&#xff0c;并在路由引入时部署路由控制&#xff0c;实现路径或策略的控制 实验目的 不同的路由协议之…

python web自动化(Pytest实战)

1.UnitTest框架与Pytest框架对⽐ 1&#xff09; unittest框架介绍 Unittest则是Python语⾔的标准单元测试框架。 Unittest⽀持⾃动化测试&#xff0c;测试⽤例的初 始化、关闭和测试⽤例的聚合等功能&#xff0c;它有⼀个很重要的特性&#xff…

深度学习-转置卷积

转置卷积 转置卷积&#xff08;Transposed Convolution&#xff09;&#xff0c;也被称为反卷积&#xff08;Deconvolution&#xff09;&#xff0c;是深度学习中的一种操作&#xff0c;特别是在卷积神经网络&#xff08;CNN&#xff09;中。它可以将一个低维度的特征图&#x…

Java面试八股之有哪些线程安全的集合类

Java中有哪些线程安全的集合类 在Java中&#xff0c;并非所有的集合类都是线程安全的&#xff0c;但在多线程环境下&#xff0c;确保集合操作的线程安全性至关重要。以下是几个典型的线程安全集合类&#xff1a; Vector: 类似于ArrayList&#xff0c;但它是线程安全的。它通过…

搭建python环境

要想能够进行python开发&#xff0c;就需要搭建好python的环境。 需要安装的环境主要是两个部分&#xff1a; 运行环境&#xff1a;python 开发环境&#xff1a;pycharm 官方网站&#xff1a;https&#xff1a;//www.python.org pycharm软件调节字体大小 pycharm 软件调节背…

QT C++ QTableWidget 演示

本文演示了 QTableWidget的初始化以及单元格值改变时响应槽函数&#xff0c;打印单元格。 并且&#xff0c;最后列不一样,是combobox &#xff0c;此列的槽函数用lambda函数。 在QT6.2.4 MSVC2019 调试通过。 1.界面效果 2.头文件 #ifndef MAINWINDOW_H #define MAINWINDOW…

vue小记——小组件(1)

代码&#xff1a; <template><div><el-steps :active"active" finish-status"success" simple><el-step title"数据导入"><i class"fa fa-cloud-upload fa-icon-custom" slot"icon"></i…

大语言模型预训练新前沿:「最佳适配打包」重塑文档处理标准

源自&#xff1a;机器之心 "人工智能技术与咨询“ 发布 声明:公众号转载的文章及图片出于非商业性的教育和科研目的供大家参考和探讨&#xff0c;并不意味着支持其观点或证实其内容的真实性。版权归原作者所有&#xff0c;如转载稿涉及版权等问题&#xff0c;请立即联系…

BGP(一)边界网关协议

BGP协议基础 路由分类 直连路由 非直连路由&#xff08;间接路由&#xff09; 静态路由动态路由 IGP&#xff1a;内网网关路由协议&#xff08;在企业内部或数据中心内部使用&#xff09; DV&#xff1a;距离矢量路由协议RIP&#xff08;v1/v2&#xff09;IGRP——网络直径&…

【易生支付官网注册/登录安全分析报告】

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…

【会议征稿,IEEE独立出版】第四届计算机技术与信息科学国际研讨会(ISCTIS 2024)

第四届计算机技术与信息科学国际研讨会&#xff08;ISCTIS 2024)将于2024年7月12-14日在中国西安举行。大会将邀请国内外计算机技术与信息科学领域的知名专家学者出席会议&#xff0c;在大会上通过主题演讲、口头报告等方式与学者们分享最新研究成果、交流探讨学术难题。同时&a…

彩信JSON接口对接发送

随着通讯技术的飞速发展&#xff0c;传统的短信已经无法满足人们日益增长的沟通需求。在这样的背景下&#xff0c;群发彩信作为一种更为先进、更为丰富的信息传递方式&#xff0c;逐渐受到了企业和个人的青睐。那么&#xff0c;群发彩信应该怎么对接&#xff0c;又具体有哪些优…

模特百度百科怎么做出来的

百度百科是一个公正、开放、客观的平台&#xff0c;收录了大量的百科词条内容&#xff0c;形成了一定的“权威性”。以下是关于模特百度百科制作的具体步骤和注意事项&#xff1a; 准备阶段 收集资料&#xff1a;为了确保参赛作品的真实性和权威性&#xff0c;需要收集相关信息…

招展工作全面启动!2024深圳国际数字能源展览会

2024深圳国际数字能源展览会 2024 International Digital Energy Expo 时间:2024年9月8-11日 地点:深圳会展中心 指导单位&#xff1a; 国家能源局 深圳市人民政府 中国电力企业联合会 主办单位&#xff1a; 深圳市投资控股有限公司 深圳能源集团股份有限公司 深圳市资…