加密集合管理
了解字段级加密的性能和存储成本非常重要。每个加密字段:
在插入和更新操作中添加写入。
需要额外的存储空间,因为 MongoDB 维护着加密的字段索引。
本部分列出每个操作的写入次数,并说明如何压缩加密的集合索引,以便最大限度地降低写入和存储成本。
Overview
Queryable Encryption引入了使用随机加密对文档中的敏感字段进行加密的能力,同时仍然能够查询加密的字段。
使用 Queryable Encryption,给定的明文值始终会加密为不同的密文,同时仍然可查询。为了启用此功能,Queryable Encryption使用三种数据结构:
两个元数据集合
在加密collection中每个文档的字段叫做
__safeContent__
重要
不得修改或删除这些数据结构,这一点至关重要,否则查询结果将不正确。
元数据集合
创建加密集合时,MongoDB 会创建两个元数据集合:
enxcol_.<collectionName>.esc
,称为ESC
enxcol_.<collectionName>.ecoc
,称为ECOC
例子
如果创建名为“患者”的集合,MongoDB 将创建以下元数据集合:
enxcol_.patients.esc
enxcol_.patients.ecoc
当您插入具有可查询加密字段的文档时,MongoDB 会更新元数据集合以维护支持查询的索引。该字段将成为“索引字段”。 这是以每个此类字段的存储和写入速度为代价的。
删除加密collection
删除加密集合后,请立即删除关联的元数据集合enxcol_.<collectionName>.esc
和enxcol_.<collectionName>.ecoc
。 否则,重新创建具有相同名称的集合会使元数据集合处于冲突状态,从而消耗过多的存储空间并降低 CRUD 性能。
存储成本
存储和写入成本根据每个文档的索引字段数量而增加。
重要
预计一个 Queryable Encryption collection 的存储需求是文档的 2-3 倍,以考虑元数据集合。例如,1 GB 的集合可能需要 2-3 GB 的存储空间。
写入成本
插入操作
插入文档时,每个索引字段都需要对元数据集合进行两次额外写入。
一个写入
ESC
一个写入
ECOC
例子
插入具有两个索引字段的文档需要:
对加密collection的一次写入。
四次写入元数据集合。
更新操作
更新文档时,每个索引字段都需要对元数据集合进行两次额外写入。
一个写入
ESC
一个写入
ECOC
例子
更新具有两个索引字段的文档需要:
对加密collection的一次写入。
四次写入元数据集合。
删除操作
删除文档时,索引字段不需要任何额外写入。
元数据集合压实
当您插入或更新文档时,元数据集合会发生变化和增长。 元数据集合压实会修剪元数据集合并减小其大小。
重要
您必须手动运行元数据集合压缩。 压缩仅适用于配置了 Queryable Encryption 的客户端。
当ECOC
的大小超过 1 GB 时运行压实。
您可以使用 mongosh
并发出db.collection.totalSize()
命令来检查集合的大小。
例子
在此示例中,加密collection名为“患者”。
db.enxcol_.patients.ecoc.totalSize()
1407960328
要运行元数据集合压实,请使用mongosh
并运行db.collection.compactStructuredEncryptionData()
命令以减小元数据集合的大小。
例子
const eDB = "encryption" const eKV = "__keyVault" const secretDB = "records" const secretCollection = "patients" const localKey = fs.readFileSync("master-key.txt") const localKeyProvider = { key: localKey } const queryableEncryptionOpts = { kmsProviders: { local: localKeyProvider }, keyVaultNamespace: `${eDB}.${eKV}`, } const encryptedClient = Mongo("localhost:27017", queryableEncryptionOpts) const encryptedDB = encryptedClient.getDB(secretDB) const encryptedCollection = encryptedDB.getCollection(secretCollection) encryptedCollection.compactStructuredEncryptionData()
{ "stats": { ... }, "ok": 1, ... }