#cache #data-structures #intrusive #hybrid #foyer #hybrid-cache #optimized

foyer-intrusive

为 foyer 提供入侵式数据结构 - Rust 的混合缓存

16 个版本 (8 个重大更新)

0.9.0 2024 年 8 月 21 日
0.8.1 2024 年 7 月 8 日
0.7.2 2024 年 6 月 5 日
0.3.0 2024 年 3 月 12 日
0.1.0 2023 年 11 月 29 日

172缓存

Download history 1988/week @ 2024-05-01 3049/week @ 2024-05-08 3081/week @ 2024-05-15 1925/week @ 2024-05-22 1213/week @ 2024-05-29 1255/week @ 2024-06-05 821/week @ 2024-06-12 662/week @ 2024-06-19 909/week @ 2024-06-26 1519/week @ 2024-07-03 1649/week @ 2024-07-10 5581/week @ 2024-07-17 5673/week @ 2024-07-24 4389/week @ 2024-07-31 3007/week @ 2024-08-07 5811/week @ 2024-08-14

每月 20,257 次下载
5 个 crate 中使用 (通过 foyer-memory)

Apache-2.0

115KB
2K SLoC

foyer

Crates.io Version Crates.io MSRV GitHub License

CI (main) License Checker codecov

foyer 旨在成为 Rust 中高效且用户友好的混合缓存库。

foyer 从 C++ 编写的备受赞誉的混合缓存库 Facebook/CacheLib 和其他项目(如流行的 Java 缓存库 ben-manes/caffeine)中汲取灵感。

然而,foyer 不只是一个在 Rust 中重写的努力;它引入了各种新功能和优化。

特性

  • 混合缓存:无缝集成内存和基于磁盘的缓存,以实现最佳性能和灵活性。
  • 即插即用算法:使用户能够轻松替换缓存算法,确保适应各种用例。
  • 无畏并发:采用强大的线程安全机制构建,确保在重负载下可靠运行。
  • 零拷贝内存缓存抽象:利用 Rust 强健的类型系统,foyer 中的内存缓存通过零拷贝抽象实现更好的性能。
  • 用户友好的界面:提供简单直观的 API,使缓存集成轻松且易于所有级别的开发者使用。
  • 开箱即用的可观察性:只需一行即可集成流行的观察系统,如 Prometheus、Grafana、Opentelemetry 和 Jaeger。

使用 foyer 的项目

请随意打开 PR 并在此处添加您的项目

  • RisingWave:SQL 流处理、分析和管理。
  • Chroma:LLM 应用程序的嵌入数据库。

用法

要在项目中使用 foyer,请将此行添加到 dependencies 部分 Cargo.toml

foyer = "0.11"

如果您的项目使用的是 nightly Rust 工具链,则需要启用 nightly 功能。

foyer = { version = "0.11", features = ["nightly"] }

开箱即用的内存缓存

use foyer::{Cache, CacheBuilder};

fn main() {
    let cache: Cache<String, String> = CacheBuilder::new(16).build();

    let entry = cache.insert("hello".to_string(), "world".to_string());
    let e = cache.get("hello").unwrap();

    assert_eq!(entry.value(), e.value());
}

易于使用的混合缓存

use foyer::{DirectFsDeviceOptionsBuilder, HybridCache, HybridCacheBuilder};

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let dir = tempfile::tempdir()?;

    let hybrid: HybridCache<u64, String> = HybridCacheBuilder::new()
        .memory(64 * 1024 * 1024)
        .storage()
        .with_device_config(
            DirectFsDeviceOptionsBuilder::new(dir.path())
                .with_capacity(256 * 1024 * 1024)
                .build(),
        )
        .build()
        .await?;

    hybrid.insert(42, "The answer to life, the universe, and everything.".to_string());
    assert_eq!(
        hybrid.get(&42).await?.unwrap().value(),
        "The answer to life, the universe, and everything."
    );

    Ok(())
}

完全配置的混合缓存

use std::sync::Arc;

use anyhow::Result;
use chrono::Datelike;
use foyer::{
    DirectFsDeviceOptionsBuilder, FifoPicker, HybridCache, HybridCacheBuilder, LruConfig, RateLimitPicker, RecoverMode,
    RuntimeConfig, TokioRuntimeConfig, TombstoneLogConfigBuilder,
};
use tempfile::tempdir;

#[tokio::main]
async fn main() -> Result<()> {
    let dir = tempdir()?;

    let hybrid: HybridCache<u64, String> = HybridCacheBuilder::new()
        .memory(1024)
        .with_shards(4)
        .with_eviction_config(LruConfig {
            high_priority_pool_ratio: 0.1,
        })
        .with_object_pool_capacity(1024)
        .with_hash_builder(ahash::RandomState::default())
        .with_weighter(|_key, value: &String| value.len())
        .storage()
        .with_device_config(
            DirectFsDeviceOptionsBuilder::new(dir.path())
                .with_capacity(64 * 1024 * 1024)
                .with_file_size(4 * 1024 * 1024)
                .build(),
        )
        .with_flush(true)
        .with_indexer_shards(64)
        .with_recover_mode(RecoverMode::Quiet)
        .with_recover_concurrency(8)
        .with_flushers(2)
        .with_reclaimers(2)
        .with_buffer_threshold(256 * 1024 * 1024)
        .with_clean_region_threshold(4)
        .with_eviction_pickers(vec![Box::<FifoPicker>::default()])
        .with_admission_picker(Arc::new(RateLimitPicker::new(100 * 1024 * 1024)))
        .with_reinsertion_picker(Arc::new(RateLimitPicker::new(10 * 1024 * 1024)))
        .with_compression(foyer::Compression::Lz4)
        .with_tombstone_log_config(
            TombstoneLogConfigBuilder::new(dir.path().join("tombstone-log-file"))
                .with_flush(true)
                .build(),
        )
        .with_runtime_config(RuntimeConfig::Separated {
            read_runtime_config: TokioRuntimeConfig {
                worker_threads: 4,
                max_blocking_threads: 8,
            },
            write_runtime_config: TokioRuntimeConfig {
                worker_threads: 4,
                max_blocking_threads: 8,
            },
        })
        .build()
        .await?;

    hybrid.insert(42, "The answer to life, the universe, and everything.".to_string());
    assert_eq!(
        hybrid.get(&42).await?.unwrap().value(),
        "The answer to life, the universe, and everything."
    );

    let e = hybrid
        .fetch(20230512, || async {
            let value = mock().await?;
            Ok(value)
        })
        .await?;
    assert_eq!(e.key(), &20230512);
    assert_eq!(e.value(), "Hello, foyer.");

    hybrid.close().await.unwrap();

    Ok(())
}

async fn mock() -> Result<String> {
    let now = chrono::Utc::now();
    if format!("{}{}{}", now.year(), now.month(), now.day()) == "20230512" {
        return Err(anyhow::anyhow!("Hi, time traveler!"));
    }
    Ok("Hello, foyer.".to_string())
}

其他示例

更多示例和详细信息可以在 这里 找到。

支持的 Rust 版本

foyer 是基于最近的稳定版本构建的。最低支持的版本是 1.77。当前的 foyer 版本不能保证在低于最低支持版本的 Rust 版本上构建。

开发状态 & 路线图

目前,foyer 仍在进行密集开发。

开发状态和路线图可以在 foyer - 开发路线图 中找到。

贡献

欢迎为 foyer 做出贡献!🥰

在提交 PR 之前,不要忘记在本地运行 make fast(这意味着快速检查 & 测试)。🚀

如果您想在本地运行更广泛的检查,请运行 make full。🙌

Star 历史

Star History Chart

依赖

~9–20MB
~253K SLoC