RocksDB敏感数据过滤器项目实战之自定义压缩过滤器

RocksDB敏感数据过滤器项目实战之自定义压缩过滤器

1.背景

今天要分享的是rocksdb的compaction filter功能,该功能允许用户自定义filter与factory在compaction过程中完成自己的业务逻辑,比如本文的敏感数据过滤器项目完美展示了 CompactionFilter 的三大核心能力:

下面我们来深入CompactionFilter的源码,并以一个完整的项目来实战。

注:懒人版,完整代码已更新至星球

2.什么是CompactionFilter?

CompactionFilter 是 RocksDB 的核心扩展点,允许在 SST 文件创建过程中对键值对进行过滤和转换。

  • 多版本 API 设计 (Filter → FilterV2 → FilterV3)

Filter可以理解为你的过滤条件,FilterV2是普通类型实现,FilterV3是宽列的实现,当然v3也是支持普通类型传递调用v2。

整个设计层面有一个factory来构建各种filter,比如:我们在写入数据的时候会写很多empty value,那么compaction的时候可以进行remove,你可以自己实现自己的过滤factory来实现自己的filter。

像v2与v3返回的是Decision,比如:你要在compaction时删除掉emtpy数据,那么当检查到empty value时,你返回kRemove,否则返回kKeep。

enum class Decision {
    kKeep,                     // 保留键值对
    kRemove,                   // 移除(转换为墓碑)
    kChangeValue,              // 修改值
    kRemoveAndSkipUntil,       // 跳过键范围(性能优化)
    kChangeBlobIndex,          // 修改 Blob 索引
    kIOError,                  // 内部错误
    kPurge,                    // 转换为 SingleDelete
    kChangeWideColumnEntity,   // 修改宽列实体
    kUndetermined              // 无法确定决策
};

比如,你自己实现的RemoveEmptyValueCompactionFilter

bool RemoveEmptyValueCompactionFilter::Filter(int /*level*/,
                                              const Slice& /*key*/,
                                              const Slice& existing_value,
                                              std::string* /*new_value*/,
                                              bool* /*value_changed*/) const {
  // remove kv pairs that have empty values
  return existing_value.empty();
}

在filterV2默认实现中当filter返回true的话就会返回remove 决策。

virtual Decision FilterV2(int level, const Slice& key, ValueType value_type,
                            const Slice& existing_value, std::string* new_value,
                            std::string* /*skip_until*/) const {
    switch (value_type) {
      case ValueType::kValue: {
        bool value_changed = false;
        bool rv = Filter(level, key, existing_value, new_value, &value_changed);
        if (rv) {
          return Decision::kRemove;
        }
        return value_changed ? Decision::kChangeValue : Decision::kKeep;
      }
      // other......
    }
}

3.敏感数据过滤项目实战

我们创建一个敏感词的factory以及filter,核心逻辑是对于敏感的词进行过滤或者压缩,比如:用户写入了k=userid,v=password,那么这个password写入的时候是明文的,但是压缩时会自动变为md5加密,这样增加安全性,这种不仅可以提升实时写入效率,还可以自定义压缩的逻辑,非常的强大。

在该项目中我们将会使用正则做一些匹配工作,同时支持普通类型与宽列实体来完整的演示compaction filter功能。

比如:main函数逻辑如下,写入宽列数据之后,手动compact,最终得到:
原始数据存储完成
压缩之前数据
用户数据:
  credit_card: 1234-5678-9012-3456
  email: john@example.com
  name: John Doe
  ssn: 123-45-6789
开始压缩

压缩完成,读取数据...
用户数据:
  credit_card: 5d444387a5d39f5deb5b24a82a9b990d4ada981515d84469cda488f605799c10
  email: john@example.com
  name: John Doe
  ssn: 01a54629efb952287e554eb23ef69c52097a75aecc0e3a93ca0855ab6d7a31a0

密码 (处理后): d2360faa4c7109412588f56d8411a72dacf8df1de36fb405faa53d4412639829

添加新的敏感模式 'api_key'...
API密钥 (处理后): da4ec3358a10c9b0872eb877953cc7b07af5f4d75e4c1cb0597cbbf41e5dbe35

核心实现:

rocksdb::WideColumns sensitive_columns = {
    {"name", "John Doe"},
    {"email", "john@example.com"},
    {"credit_card", "1234-5678-9012-3456"},
    {"ssn", "123-45-6789"}
};

status = db->PutEntity(rocksdb::WriteOptions(), default_cf, "user:1001", sensitive_columns);
if (!status.ok()) {
    std::cerr << "Failed to write wide columns: " << status.ToString() << std::endl;
}

status = db->CompactRange(rocksdb::CompactRangeOptions(), nullptr, nullptr);
if (!status.ok()) {
    std::cerr << "Compaction failed: " << status.ToString() << std::endl;
}

// do something

学习更多干货,欢迎关注转发!

玩转cpp小项目星球3周年了!

图片

图片

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值