CloudKit 是强一致还是最终一致?

Posted

技术标签:

【中文标题】CloudKit 是强一致还是最终一致?【英文标题】:Is CloudKit strongly consistent, or eventually consistent? 【发布时间】:2014-06-11 06:51:26 【问题描述】:

官方文档是否在某处谈论 CloudKit 一致性?根据我的测试,它似乎最终是一致的——在写入后立即读取记录可能有效,也可能无效(返回空结果):

CKDatabase *database = [[CKContainer defaultContainer] publicCloudDatabase];
CKRecord *record = [[CKRecord alloc] initWithRecordType:@"Foo"];

dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
[database saveRecord:record completionHandler:^(CKRecord *record, NSError *error) 
    CKQuery *query = [[CKQuery alloc] initWithRecordType:@"Foo" predicate:[NSPredicate predicateWithFormat:@"TRUEPREDICATE"]];
    [database performQuery:query inZoneWithID:nil completionHandler:^(NSArray *results, NSError *error) 
        XCTAssertEqualObjects(results, @[], @"Freshly written object not returned by query."); // succeeds
        dispatch_semaphore_signal(semaphore);
    ];
];

dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

有没有办法强制进行反映所有先前更新的强一致性读取?

【问题讨论】:

我在测试中注意到了同样的事情。我正在保存记录并等待它成功完成。如果我随后对所有记录执行查询,则不会返回我的新记录。您是否发现任何说明 CloudKit 最终一致的信息? 幸运的是,我的用例非常简单,所以我“解决”了数据存储层中的一种缓存问题:当一个项目插入数据存储时,它被写入 iCloud 在客户端上存储一小段时间。当查询数据存储层时,它会将活动缓存记录添加到结果集中。愚蠢,但有效。 @zoul 有没有找到更好的方法来处理这个问题? CKModifyRecordsOperation.h 中用于 modifyRecordsCompletionBlock 的内联注释的最后一部分表明这是设计的行为:“一旦服务器看到所有记录更改,就会发生此调用,并且可以在服务器处理边时调用这些变化的影响。" 服务器更新可能需要一些时间,并且不能保证以查询的形式反映当前记录。但是,如果您使用 recordID 进行检索,它将是一致的。我认为延迟是处理此问题的一种肮脏方式。在我构建的需要跟踪实时记录的应用程序中(至少从用户的角度来看),我一直在保存更改的 RecordID 和 moddate 并根据查询的记录检查修改日期。如果记录不是最新的,我会从结果中删除这些记录,然后通过 CKRecordID 检索这些特定记录并将它们拼接到结果中。 【参考方案1】:

两者兼而有之:如果您通过标识符获取记录,CloudKit 是高度一致的,但当您通过查询获取记录时最终是一致的。

CKModifyRecordsOperation 成功返回时,记录可立即通过其标识符获取。

但是,服务器扫描记录的值并更新和分发其搜索索引需要一些时间。在索引完成之前,您不会在任何查询中看到记录。

【讨论】:

【参考方案2】:

我对“最终一致性”一词的唯一经验是使用 CouchDB,它最终是一致的。 CloudKit 与 CouchDB 的不同之处在于 CouchDB 允许复制分布式数据库,而 CloudKit 仅提供“管理与 iCloud 服务器之间的数据传输的服务”——它只是一种传输机制。

我很确定传输机制本身最终并不一致 - 它直接从 CloudKit 服务器保存和检索。

由于 CloudKit 只是一种传输机制,您有责任维护自己的本地缓存/数据库。您的本地数据库将被认为是最终一致的,因为它在同步之间不一定是一致的,只有在您最终使用 CloudKit 同步它时才会变得一致。

现在,您说在您的测试中您正在保存然后尝试检索记录。但是我在您的代码中注意到您没有检查保存操作中的错误。那么,也许您在保存过程中丢失了错误?

【讨论】:

我不了解 Apple 的 iCloud 基础设施,但我怀疑有许多不同的 iCloud 服务器在某种负载平衡方案后面运行。因此,保存记录的调用似乎完全有可能被路由到一个服务器实例,而随后的调用被路由到另一个实例。根据 iCloud 保持这些实例同步的程度,在这里拥有一个最终的一致性模型可能是相当合理的。

以上是关于CloudKit 是强一致还是最终一致?的主要内容,如果未能解决你的问题,请参考以下文章

聚合必须是强一致的吗?

面试官:ZooKeeper 是强一致的吗?

一致性协议-RAFT简述

如何解决设备之间的 CloudKit 功能不一致

分布式系统架构系列讲解七(分布式一致性 7):Quorum NWR算法

分布式事务解决方案