NDB缓存读取操作是否仍计入Cloud Datastore计费读取量?
首先直接给结论:从NDB的上下文缓存或memcache读取实体,都不会被计入Cloud Datastore的读取操作量——只有当缓存未命中,NDB不得不直接从Datastore获取数据时,才会产生计费的读取请求。
那为什么你的测试里读取量是写入量的3倍?结合你的测试场景,我梳理几个可能的分析漏洞:
1. 跨组事务中的读取会绕过缓存
你提到测试中有大量跨组事务,而且因为热点实体频繁重试(200-400次)。这里要注意:NDB在事务内部会强制绕过所有缓存(包括上下文缓存和memcache),因为事务需要保证强一致性,必须从Datastore获取实体的最新提交版本,不能依赖缓存中可能过期的数据。
也就是说,每次事务执行(包括重试)中的实体读取,都会直接触发Datastore读取操作并计费。如果你的事务里需要读取多个实体,加上几百次重试,这部分的读取量会非常可观,很可能是你观测到高读取量的主要原因。
2. keys_only查询本身会产生Datastore读取量
你说绝大多数读取是通过keys_only查询拿到的key去查找实体,但keys_only查询本身是直接查询Datastore的索引,不会走任何NDB缓存。这类查询的计费是按照扫描的索引条目数来算的——如果你的keys_only查询返回几百个key,每次查询都会产生对应数量的读取操作(或根据索引大小,可能更多)。这部分读取量是单独的,不会被你统计的“实体读取”覆盖,但会算在控制台的总读取量里。
3. 缓存失效后的重复读取叠加
虽然写入操作会失效对应实体的缓存,但如果你的测试中存在多个任务同时修改同一个实体,或者事务重试导致多次写入,会频繁触发缓存失效。每次失效后,第一个读取该实体的请求会从Datastore获取数据并重新缓存,这部分会被计费。如果同一实体被多次失效+重新读取,就会产生多次计费的读取请求。
4. memcache命中率统计可能不包含NDB内部调用
你看到的memcache命中率81%,大概率是应用代码直接调用memcache的统计,而NDB内部使用memcache的操作不会被计入这个指标。也就是说,NDB实际的memcache命中率可能远低于81%,导致更多的缓存未命中,进而触发更多Datastore读取。
官方逻辑参考
根据NDB的缓存设计:
NDB的两级缓存(上下文缓存、memcache网关)的核心作用就是减少直接访问Datastore的次数,从而降低计费和延迟。只有当缓存未命中时,才会向Datastore发起读取请求并产生计费。
而事务中绕过缓存的行为,是因为事务需要满足ACID特性的一致性要求,必须确保读取到的是最新的已提交数据,所以不会使用任何缓存层。
内容的提问来源于stack exchange,提问作者Dan Cornilescu

