本部分提供有关使用可靠状态管理器和 Reliable Collections 的指导原则。 目的是帮助用户避免常见错误。
可靠集合指导原则
这些准则组织为简单建议,其前缀为 “Do”、“ 考虑”、“ 避免”和 “请勿”。
- 请勿修改读取操作返回的自定义类型的对象(例如,
TryPeekAsync或TryGetValueAsync)。 Reliable Collections 与 Concurrent Collections 一样,返回对这些对象的引用,而非副本。 - 在修改返回的自定义类型的对象之前,务必对其进行深层复制。 由于结构和内置类型是按值传递的,因此无需对其执行深层复制,除非它们包含要修改的引用类型字段或属性。
- 不要使用
TimeSpan.MaxValue来处理超时。 应使用超时值来检测死锁。 - 在提交、中止或释放事务后,请勿使用该事务。
- 不要在事务创建时的范围之外使用枚举。
- 不要在另一个事务的
using语句中创建事务,因为它可能会导致死锁。 - 不要在同一事务中创建可靠状态并使用该可靠状态。 这会导致 InvalidOperationException 异常。
- 务必确保
IComparable<TKey>实现正确。 系统依赖IComparable<TKey>进行检查点和行的合并。 - 请使用更新锁在读取某项时有意更新它,以防止某类死锁的发生。
- 请考虑将每个分区的可靠集合数保持在 1000 以下。 建议选择包含更多项的可靠集合,而不是多个包含较少项的可靠集合。
- 请考虑将您的元素(例如,Reliable Dictionary 的 TKey + TValue)控制在 80 千字节以下,越小越好。 这会减少大型对象堆的使用量,并降低磁盘和网络 IO 的要求。 通常情况下,当只更新值的一小部分时,它可以减少重复数据的复制。 在 Reliable Dictionary 中实现此效果的常用方法是将一行划分为多行。
- 请考虑使用备份和还原功能进行灾难恢复。
- 避免在同一事务中混合使用单个实体操作和多个实体操作(例如
GetCountAsync、CreateEnumerableAsync),因为它们的隔离级别不同。 - 请务必处理 InvalidOperationException。 系统可能出于各种原因中止用户事务。 例如,当可靠状态管理器将其角色从“主要”更改为其他角色时,或者当长时间运行的事务阻止截断事务日志时。 在这类情况下,用户可能会收到 InvalidOperationException,指示其事务已终止。 假设用户未请求终止事务,处理此异常的最佳方式是释放事务,检查取消令牌是否已发出信号(或副本的角色已更改),如果未创建新事务,则重试。
- 不要在事务中应用 并行 或 并发 操作。 一个事务中仅支持一个用户线程操作。 否则,会导致内存泄漏和锁定问题。
- 请在提交完成后尽快处理事务(特别是在使用 ConcurrentQueue 时)。
- 不要在事务中执行任何阻塞代码。
- 将字符串用作可靠字典的键时,排序顺序使用默认字符串比较器 CurrentCulture。 请注意,CurrentCulture 排序顺序不同于Ordinal 字符串比较器。
- 请勿处置或取消正在提交的事务。 这不受支持,可能会使主机进程崩溃。
- 在读取多个字典或向多个字典写入内容时,请确保所有并发事务中针对不同字典的操作顺序保持相同,以避免发生死锁情况。
需谨记以下几点:
- 所有 Reliable Collection API 的默认超时值均为 4 秒。 大多数用户应使用默认超时值。
- 所有 Reliable Collections API 中的默认取消标记均为
CancellationToken.None。 - 可靠字典的键类型参数 (TKey) 必须正确实现
GetHashCode()和Equals()。 键必须不可变。 - 若要实现 Reliable Collections 的高可用性,每个服务应至少有一个目标,并且最小副本集大小必须为 3。
- 辅助副本上的读取操作可能会读取未提交仲裁的版本。 这意味着从单个辅助副本读取的数据版本可能被错误处理。 从主副本读取的数据始终是稳定的:绝不会出现虚假进展。
- 在一个可靠集合中,由你的应用程序持久保存的数据的安全/隐私是由你决定的,并且受存储管理提供的保护措施制约;即,操作系统磁盘加密可用于保护你的静态数据。
-
ReliableDictionary枚举使用按键排序的排序数据结构。 为了提高枚举的效率,提交会被添加到临时散列表中,然后在检查点后移动到主要的排序数据结构中。 如果需要验证检查是否存在键,“添加”/“更新”/“删除”操作的最佳运行时为 O(1),最差运行时为 O(log n)。 读取可能是 O(1)或 O(log n),具体取决于您是从最新提交还是从早期提交中读取。
关于持久化可靠集合的其他指导原则
决定使用易失可靠集合时,请考虑以下事项:
-
ReliableDictionary具有易失性支持 -
ReliableQueue具有易失性支持 -
ReliableConcurrentQueue不具有易失性支持 - 持久化服务无法变为易失性服务。 将
HasPersistedState标志改为false需要从头开始重新创建整个服务 - 易失性服务无法变为持久化服务。 将
HasPersistedState标志改为true需要从头开始重新创建整个服务 -
HasPersistedState是服务级别的配置。这意味着所有集合都可归为持久化集合和易失性集合中的一种。 不能混合可变集合和持久化集合 - 由于法定人数的丧失,易失性分区会导致数据完全丢失
- 备份和还原不可用于易失性服务