当前位置: 首页 > web >正文

篇章九 消息持久化(一)

目录

1.消息存储格式设计

1.1 为什么不在数据库中存储消息

1.2 消息如何在文件中存储

2.消息垃圾回收的设计

2.1 为什么要消息垃圾回收

2.2 如何进行消息垃圾回收

2.3 什么时候触发GC

3. 思考:消息文件拆分合并


1.消息存储格式设计

1.1 为什么不在数据库中存储消息

1.消息操作并不涉及到复杂的增删改查

2.消息数量可能非常多 数据库的访问效率并不高

故直接把消息存储到文件中

1.2 消息如何在文件中存储

整体存储文件目录结构

        首先消息是依附于队列的,因此存储的时候就把消息按照队列维度展开。此时我们数据库那边有一个 数据目录 ./data,所以在data中创建一些子目录:每个队列有一个子目录,子目录的名字就是队列名。如下图所示:

此处,每个队列的子目录下,再分配两个文件,来存储消息

第一个文件:queue_data.txt 这里保存消息的内容

第二个文件:queue_stat.txt 这里保存消息的统计消息

对queue_data.txt 文件做出约定:

queue_data 这个文件将包含若干消息,每个消息以二进制的方式存储,每个消息格式如下图:

此处的Message序列化 将使用标准库的序列化来实现

消息的二进制数据 存储格式:

Message对象没有具体的长度(因为正文部分不固定长度,是个字节数据)

此处采用 offsetBeg 和 offsetEnd字段 来解决这个变长问题

Message对象 在内存中存一份,在硬盘中存一份。内存中的那一份要记录 offsetBeg 和 offsetEnd字段。 以便随时 找到内存中的 Message对象,就能找到对应的硬盘上的 Message对象

isValid字段的解析:

对于Broker Server 来说消息是需要新增,也需要删除的。

生产者生产一个消息需要新增,消费者消费一个消息需要删除。

新增和删除对于内存来说很好办(使用集合类),但是在文件中怎么办?

新增:直接把新消息追加到文件末尾

删除:

1.方案一——直接删除:文件表可以视为一个“顺序表”这样的结构。如果直接删除中间元素,就需要设计到类似于“顺序表搬运”的操作,效率很低。因此此方案不合适。

2.方案二——逻辑删除:采用isValid字段 ,并随消息存储到文件中

1 有效消息

0 无效消息(已经被删除)

对 queue_stat.txt 文件做出约定:

使用这个文件来 保存消息的统计信息

只存一行数据(文本格式):

一行 两列

第一列:queue_data.txt 中 消息数目

第二列:queue_data.txt 中 有效消息数目

两者使用 \t 分割

如下图所示:        

2.消息垃圾回收的设计

2.1 为什么要消息垃圾回收

采用上述方案二,随着时间的推移,这个消息文件会越来越大,并且,这里可能大部分都是无效消息,针对这种情况,就需要考虑对当前的消息数据文件,进行垃圾回收

2.2 如何进行消息垃圾回收

方案 :复制算法

如下图所示:

原始数据:

使用复制算法进行垃圾回收:

方案综述:

        直接遍历原有的消息数据文件,把所有有效的数据拷贝到一个新的文件中,再把之前整个旧的文件都删除。

2.3 什么时候触发GC

很显然你不能频繁触发它,毕竟它的开销很大,那么什么时候触发比较合适呢?

        为了避免频繁触发GC,此处做出约定,当消息数目超过 2000,并且有效消息数目低于总消息数目的 50%,就触发一次GC。上述的数字很显然可以灵活调整,先由程序员自己决定,最后根据项目测试得出一个比较合适的数值进行优化。

3. 思考:消息文件拆分合并

很显然上述的思路还有些欠缺,但是已经并不影响我们消息文件的存储了。这里提出一个可行的优化方案,如果后续时间充足就可以把它实现(RabbitMQ实现了):

如果某个队列,消息特别多,而且还都是有效消息怎么办?

此时就会导致整个消息的数据文件特别大,后续针对这个文件的操作,成本迅猛提升。

而RabbitMQ 的解决方案是,把一个较大的文件拆成若干个小的文件。

文件拆分:当单个文件长度达到一定阈值之后,就会拆分成两个文件。

文件合并:每个单独的文件都会进行 GC, 如果GC后,文件变小了很多,就可以和相邻文件合并

这样做的好处就是:可以在消息特别多的时候也能保证性能上的及时响应。

如何实现:

实现这个机制的大致思路:

1.需要专门的数据结构 来存储当前队列有多少个数据文件,每个文件的大小,消息数目,无效消息数目。

2.策略:什么时候触发文件拆分,什么时候触发文件合并

http://www.xdnf.cn/news/7962.html

相关文章:

  • GraphPad Prism设计国民经济和社会发展结构指标项目
  • JVM——类加载器
  • 【Python】总结像大模型一样一个字一个字输出的方法
  • Simon J.D. Prince《Understanding Deep Learning》
  • [TCG] QEMU TCG 概览
  • 【Python-Day 16】代码复用基石:详解 Python 函数的定义与调用
  • 台风灾害下考虑调节特性的多元资源紧急协调调度
  • 如何进行单表误删的恢复|OceanBases 运维实践
  • CMMI(能力成熟度模型集成)详解及5个级别案例
  • Qt多线程
  • 项目执行中缺乏风险管理,如何预防潜在问题?
  • 打破性能瓶颈:用DBB重参数化模块优化YOLOv8检测头
  • labview硬件部分——温度测量
  • ProtonBase 与您相约 AICon 上海站!
  • 【超长上下文检索评测】Qwen-Agent 智能体 vs 传统RAG vs 大上下文模型,谁更强?
  • Docker 镜像分层机制详解:UnionFS 如何实现高效存储与快速启动
  • jvm调优以及常见jvm问题解决等
  • idea无法识别Maven项目
  • LLaMA-Adapter
  • 使用MATLAB输出给定范围内的所有质数
  • Vue3 Element Plus el-table-column Sortable 排序失效
  • 多通道经颅直流电刺激器产品及解决方案特色解析
  • 告别手动绘图!2分钟用 AI 生成波士顿矩阵
  • 灾备认证助力构建数据资产安全防线‌
  • java中定时任务的实现及使用场景
  • NC028NQ472美光固态颗粒NQ484NQ485
  • MBSS-T1:基于模型的特定受试者自监督运动校正方法用于鲁棒心脏 T1 mapping|文献速递-深度学习医疗AI最新文献
  • 超越现有SOTA!DiT模型助力高分辨率图像生成
  • 工业物联网网关在变电站远程监控中的安全传输解决方案
  • 车辆诊断技术全生命周期管理与实践