Google Firestore和AWS DynamoDB是两个比较成熟的全托管的分布式数据库,这里对他们做一下简单的比较。
数据库结构
Firestore
Firestore的结构包括集合和文档。集合类似于一个文件夹,储存多个文档。而文档则类似于一个JSON文件,文档结构没有限制。文档有一个ID,如果创建文档的时候不手动指定的话会随机分配。一个集合中的文档ID不可以重复,如果创建重复的会直接覆盖旧文档。
文档中储存键值对。使用官方的SDK可以很方便地对对象进行序列化和反序列化,并且支持嵌套自定义对象。但这个序列化和反序列化有一个问题,就是文档的ID不能放到类属性里面,因为文档里面不支持主键,只能指定文档的ID。
DynamoDB
DynamoDB的结构为表。一张表里面必须规定一个分区键,可以单独作为表的主键。如果规定一个排序键,则会和分区键一起作为组合主键,此时的分区键可以重复,但分区键和排序键的组合需要在表中唯一。相同分区键的数据会被放在一起,查询起来会比较快。如果规定了分区键,那么query的结果会自动根据分区键排序。
DynamoDB的序列化和反序列化比Firestore限制也多一些。首先必须在对象中加入注解,指定分区键和可选的排序键。对象里面不支持继续嵌套自定义的对象。
查询
Firestore
Firestore的SDK支持对任何文档键的where查询,并可以组合多个文档键进行查询。
DynamoDB
DynamoDB就麻烦得多。首先DynamoDB的查询有两种,一种是query查询,指定某个分区键,取得该分区键的所有item。另一种是scan查询,即返回该数据库的所有数据。但如果说我想以其他表属性进行查询或者排序的时候,事情就麻烦起来了。一种做法是在query或者scan查询中加上filter expression,AWS会过滤好结果之后再返回。另一种做法就是自己根据query或者scan的结果进行进一步的查询或者排序,灵活度非常差。
举一个例子。如果我想储存一个学生的借还书记录,分区键使用学生的ID,排序键使用时间戳作为记录的ID,这样可以很方便地使用query查询一个学生的借还书记录。但如果我想查询所有在2022年1月1日有借还书记录的学生,只能用scan把表全部查一遍,外加使用filter expression或者自己手动过滤。query或者scan查询还有一个限制,那就是一次从数据库返回的最大数据量为1M,如果超过限制要进行多次查询。
定价
Firestore
Firestore按照使用量收费。除了储存费,按照读取、写入和删除的次数费用,每天提供5W次免费读取和2W次免费的写入和删除。对于大作业级别的项目不会产生费用,比托管式的SQL便宜得多。但如果使用量比较高,会比托管式的SQL价格更贵。
在单个文档里面嵌套对象可以有效地减少查询的次数,但是增删改查会难写一些。
DynamoDB
DynamoDB的支持两种定价模式。第一种是按量收费。第二种是按照预置的使用容量收费。AWS免费提供25个读和25个写容量。每张表最少阈值一个读和写容量,即最多免费创建25个表。提醒一下,不要开自动扩缩,因为自动扩缩依赖Cloudwatch的警报,一张表的自动扩缩就需要8个警报,而一个月的免费额度为10个,超出一个一个月0.1刀。一般情况下一张表设置一个读和一个写容量即可,在AWS控制台上可以看到表容量的使用情况。
共同的缺点
不支持多个数据库
一个GCP项目只支持一个Firestore数据库,并且一旦创建就不能修改,想改得重新创建项目。AWS一个账户的一个地区可以创建一个数据库。开发和测试不方便
Firestore和DynamoDB都提供了数据库的模拟器,但功能并不全,使用也不方便。Firestore在墙内会连不上,开Socks代理都没用,只能用路由代理。供应商锁定
MongoDB可以部署在任意服务器上,而Firestore和DynamoDB则没有其他供应商选择。并不便宜
对于玩具项目,这两家都可以免费用。但对于商用的项目,这两家一点都不便宜,可以参考某游戏公司的案例。
小结
Firestore和DynamoDB都不好用,还是用MySQL或者MongoDB吧。