TL;DR:这里有数学可以准确预测我的计数器应该使用多少个分片吗?
我是计数器的忠实粉丝(是的,这很奇怪),并且我正在编写一个小型民意调查应用程序。
我有计数器集合,其中每个文档都是一个计数器,每个计数器都有一个分片子集合。
<root_level>
├── [counters]
│ └── counterID
│ ├── num_shards: 20
│ └── [shards]
│ ├── 1
│ │ └── counts: 2
│ ├── 2
│ │ └── counts: 7
│ └── 3...
├── [votes]
└── voteId
...
此外,我还设置了一个云函数来跟踪投票集合中任何新添加的投票文档。该函数获取一个随机分片 ID 并递增它...就像文档中的示例一样。
const counterRef = db.doc('counters/counter')
export const onVote = functions.firestore
.document('votes/{voteId}')
.onCreate(async snapShot => {
const counterDoc = (await counterRef.get())
const { num_shards } = counterDoc.data()
const shard_id = Math.floor(Math.random() * num_shards).toString()
const shard_ref = counterRef.collection('shards').doc(shard_id)
return db.runTransaction(async tsx => {
const shardDoc = (await tsx.get(shard_ref))
const oldCount = shardDoc.data().count
return tsx.update(shard_ref, { count: oldCount + 1 })
})
})
在我的客户端中,我组合了两个可观察量:一个用于计数器,另一个用于其相关的分片子集合,并且我执行了基本的 reduce() 来对总计数进行求和。
combineLatest(counter$, shards$)
.pipe(
map(([counter, shards]) => {
const count = shards.reduce(
(acc: any, shards: any) => shards.count + acc,
0
)
return { ...counter, count }
})
)
.subscribe(counter => /* display counter */)
嗯,我用 5、10、15 个分片和 1000 票进行了多次测试,但遇到了数据争用错误。但对于 100 个分片,我没有遇到任何错误。但这似乎是一个抛硬币游戏。事实上,有时它只需要很少的分片就可以工作,有时我需要更多的分片。
所以我的问题是:这里是否有任何数学方法可以准确预测我的计数器应该使用多少个分片?我希望以最低的成本获得最佳的性能。
最佳答案
您需要预测最大负载是什么,并根据该负载进行分片。一个文档可以处理持续的1 write per second不会产生拒绝写入的错误。因此,如果您希望能够每秒处理 50 次写入,则需要至少 50 个文档进行分片(假设写入在这些文档之间完美分布)。如果您不想假设完美的分布,请设置更高的值以减少单个文档因写入而承受过大压力的可能性。
如果您提前不知道最大负载,那么您将无法优化要使用的文档分片的数量。在这种情况下,您将需要任意高,并希望它满足您的实际需求。
关于firebase - Firestore分布式计数器: How to know the ideal shards sum we need?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55713837/