2.1 什么是 Orleans 的 Grain

<<返回目录

Grain 是 Orleans 中的重要素素。它是组成 Orleans 应用程序的基本组成部分,具有原子性,事务被封装在 Grain 中,与其它Grain互相隔离,并在分布式网络上进行分发。对开发人员来说,Grain封装了实体的状态和逻辑,并可以通过彼此间的公开方法进行交互。

Orleans 通过下面的特性,简化构建可伸缩的应用,降低开发人员处理并发的门槛:

  • 不要在 Grain 间共享数据,除非通过 Grain 间的消息传递
  • 通过单线程运行每个 Grain 的逻辑来保证 Grain 的高可用性

一个经典的 Grain 将实体的状态和行为封装在 Grain中

Grain 标识

每个 Grain实例具有一个唯一的地址,并通过一个 grain key进行标识,grain key 可以是如下类型:

  • Guid
  • string
  • long
  • long + string
  • Guid + string

调用 Grain

一个 Grain 实现一个或多个 IGrain 接口,要调用一个Grain,开发者需要知道它实现了哪个接口,以及相应的 grain key,如下代码将通过用户的电子邮件获取一个用户配置(IUserProfile)的实例,并调用它的UpdateAddress方法修改此用户的联系地址。

var user = grainFactory.GetGrain(userEmail);
await user.UpdateAddress(newAddress);

注意:我们不需要像平时编程一样通过new或者DI去实例化一个Grain,我们调用它的时候,它就已经激活并准备好被我们使用了。这是Orleans的魅力所在:我们永远不需要创建、实例化或删除 Grain,好像所有可能的 Grain (例如有成千上百万的用户配置实例)始终在内存中等待我们调用;这都是因为有 Orleans Runtime 在幕后替我们管理这些繁重的工作。

Grain 的生命周期

Grain 生存在称为 Silo 的容器中。众多的 Silo 组成了 Orleans 集群。当用户请求访问一个Grain时,Orleans 先会检查集群中的 Silo 上是否有一个该 Grain 的实例在运行,如果没有则会进行创建,这个过程称为激活;如果 Grain 使用一持久化特性,那么在激活时会自动从存储中加载状态来初始化这个 Grain。

一旦 Grain 在Silo 中激活,那么它就开始接受调用(外部调用、内部 Grain 间的调用)。在处理请求的过程中,Grain 可能会调用其它的 Grain 或一些外部服务。

如果 Grain 空闲一段时间(可配置)后, Orleans 会从内存中移除Grain 以释放其资源。等到再次请求调用此 Grain 时再次它激活。但不一定在之前的 Silo 上(对开发者来说,不需要关注Grain 在哪一个Silo,即不必关注 Grain的物理位置,开发者永远通过grain key调用它)

Grain 生命周期

Orleans 控制着 Grain 激活、停用的过程,开发人员进行开发时不必理会,只需假设所有的 Grain 均处于激活状态,直接调用。

Grain 生命周期中的关键事件序列如下:

  • 其它 Grain 或客户端调用此 Grain 的方法
  • 激活 Grain(如果它没有在任何一个集群中被激活)
    • 执行 Grain 构造
    • 如果使用了持久化策略,将从存储中加载 Grain 状态
    • 如果有重写OnActivateAsync,将在此时被触发
  • Grain 处理传入的请求
  • Grain 空闲一段时间
  • Silo runtime 决定停止一个 Grain
  • 如果有重写 OnDeactivateAsync Silo runtime 先触发OnDeactivateAsync
  • Silo runtime 从内存移除 Grain

Grain执行

Grain在块中执行,并在执行下一个块之前必须完成当前块的工作(其中包括响应来自其它 Grain 或 Client 的方法调用)。

一个块中执行的基本单位称之为流。

Orleans 可以并行执行多个激活的流,且每个只执行一次。这个机制保障了不需要使用锁或其他同步方法来防止数据竞争或多线程危险。

你可能感兴趣的:(2.1 什么是 Orleans 的 Grain)