8 个版本
0.3.0 | 2024 年 7 月 19 日 |
---|---|
0.2.3 | 2024 年 3 月 5 日 |
0.2.2 | 2024 年 2 月 27 日 |
0.1.2 | 2024 年 1 月 10 日 |
在 缓存 中排名 #113
每月下载量 120 次
235KB
6K SLoC
Possum
是什么?
Possum 是一个直接存储在磁盘上的键值缓存。它支持多个进程并发访问,无需进程间通信或旁路进程。它通过使用打孔和稀疏文件高效地驱逐数据。它通过使用文件克隆(在支持文件克隆的文件系统中,如 Btrfs、XFS、ZFS、APFS 和 ReFSv2)支持读取快照。
值读取和写入直接在文件上发生,允许内存映射、零拷贝/拼接、向量 I/O、轮询等。
为什么?
我找不到一个支持直接在磁盘上存储、多个进程并发访问而不需要专用进程以及限制磁盘空间使用的缓存实现。现有的解决方案似乎都是内存中的,具有将快照存储到磁盘上的功能(例如 Redis),或者单进程的,其中磁盘管理(包括所有键)也维护在内存中(包括 Bitcask 衍生品)。有大量的单进程解决方案(这通常在单个应用程序中实现),但并发键值磁盘存储较少,而且它们不重视空间限制,并且对用户级缓存的支持不佳(例如,几乎所有基于 LSM 的数据库都属于这一类,例如 RocksDB、Badger 和 Pebble)。因此,尽管内存键值缓存得到了很好的支持,但磁盘缓存领域仍然存在空白,尤其是那些可以被多个应用程序共享的磁盘缓存。有很多系统,其中大量的磁盘空间可以被包管理器、HTTP 代理和反向代理、缩略图生成、API 缓存等共享,而这些系统中不需要主内存延迟。
技术细节
Possum 维护一个稀疏文件池和清单文件来同步写入和读取。
写作是通过启动一个批处理来完成的。Possum记录键并公开一个位置以并发地写入值。可以使用文件句柄进行值写入,以允许拼接和高效的系统调用将数据卸载到磁盘,并直接将文件复制或重命名到缓存中。完成写入后,批处理键被提交,并释放追加和新的文件回缓存以供未来的读取和写入。批处理可以并行准备。写入不会阻塞读取。
读取是通过锁定缓存并记录要读取的键来完成的。当所有要读取的键都已提交时,包含值数据的缓存中文件的区域会被克隆到临时文件中(这是一种非常高效的、常数时间的系统操作),并在快照的生命周期内可用于读取。
写入批处理最终化时键的提交和读取快照的创建是唯一的串行操作。写入批处理准备和读取快照可以共存于任何安排和数量中,包括与上述串行操作同时进行。
高效地删除数据,创建读取快照需要打孔和稀疏文件分别。这两个功能在Windows、macOS、Solaris、BSD和Linux上均可用,具体取决于使用的文件系统。
支持的系统
macOS、Linux和Windows。
FreeBSD 14+。不幸的是,缺少文件克隆和打开文件描述符锁定。实现会回退到flock(2),并必须分别处理写入和读取文件。
Solaris需要少量工作来完成实现。
在不支持块克隆的文件系统上(Linux上的ext4和Windows上的NTFS是显著的例子),实现会回退到文件区域锁定,除非这也不可用(FreeBSD)。
anacrolix/squirrel
我之前写了anacrolix/squirrel,由于SQLite的VFS,它可以作为内存或磁盘缓存的替代品。然而,它是用Go编写的,因此从其他语言中不太容易访问。使用SQLite进行值存储意味着大流写入是独占的,即使是在单个事务内。值数据被序列化为blob格式,可能跨越多个链接页面,并在项目被逐出和移动时多次复制。SQLite不支持直接文件I/O,并且必须在写入之前知道值的大小,这意味着在将流写入SQLite文件之前,可能需要将流复制到临时文件中。
依赖项
~38–82MB
~1.5M SLoC