一、背景
在常见的内存队列(redis的list结构)中,经常会因为队列阻塞,导致内存撑爆。类似的,在redis主从同步过程中,由于内存限制,redo log的buffer是固定的,如果从库的进度在buffer之外,就需要进行一次全量同步,这是一个非常重量级的操作。
为解决上述问题,本文设计并实现一种数据结构,用于基本无内存限制的存储队列(受限于磁盘空间)。基本思路是限制队列使用的内存,将中间部分数据写到磁盘,push端和pop端在内存操作,通过后台线程在内存和磁盘间交换数据。
二、整体结构
InfQ内部结构包括:
1)内存队列:用于push和pop的buffer,保证push和pop都是内存操作。占用固定大小的内存block,并划分成n个大小相同的内存块。
2)文件队列:当内存队列空间耗尽时,存储中间数据,以腾出内存。由内存block dump成的文件组成。
3)后台线程:存在两种类型:
- dumper:在Push Queue内存使用超过一定阈值时,将内存block dump成文件块,添加到文件队列。
- loader:当Pop Queue存在空闲空间时,将文件队列中的文件块,load成内存block添加到POP Queue。
1. 内存队列
内存队列可以看成是二级队列,第一级是由内存block组成的环形队列。在初始化时,指定block的个数,保证占用固定大小内存。每一个内存block又组成了一个队列。结构如下: