Grains (Actors): 分布式的基本单元
分布式应用天生是并发的,这导致了它的复杂性。Actor模型减少了处理并发的复杂性,是使得Actor模型高效和具有生产品的原因之一。
Actor使用两种方法来解决复杂性问题:
- 通过单线程来访问一个actor的内部状态
- 除了通过消息传递以外actor间不共享数据
Grain是Orleans应用的基石,是隔离、分布和持久化的最小单元。 一个典型的grain封装了状态和单个实体的行为(例如,一个具体的用户)。
Turns: 执行的基本单元
Actor单线程调用的背后思想是,调用器(远程)轮流“调用”它的方法。因此,一个从actor A到actor B的消息将会放到一个队列里,并且只有当前面的消息处理完后相关的处理器才会被调用。
这使得我们可以不是用任何锁来保护actor的状态,并且它天生避免了数据竞争问题。然而,这可能导致当消息来回传递的时候形成消息循环。如果A发送了一条消息给B等待B处理完成,并且B发送了一条消息给A,也等待A处理完成,这个应用会很快锁起来。
一个Grain的激活 - Grain的运行时实例
当有工作需要grain处理的时候,Orleans确保一个Orleans Silos上有一个grain的实例。当silo上没有grain实例时,运行时会创建一个。这个过程称作激活。当一个grain使用Grain持久化,运行时在激活时从持久化存储中自动读取状态。 Orleans透明地控制激活和注销的过程。当编写一个grain的时候,开发者只要假设所有的grain永远是被激活的。
grain的激活工作是分块执行的,一块执行完成移动到下一块。每块工作包含响应其他actor或者外部客户端的请求的方法调用,并且下一个闭包在前一个分块完成后被调度。执行的基础相当于一块工作也被叫做一个turn。
然而Orleans可能同时并行执行属于不同激活的多个turn,每一个激活将永远同一时间只执行一个turn。这表示不需要使用锁或者其他同步机制来避免数据竞争或者其他的多线程带来的问题。正如之前提到的,预定的闭包的无法预知的turn交替会导致grain的状态与被预定的时候不同,所以开发者必须注意turn交替产生的bug。
激活模式
Orleans支持两种模式:单激活模式(默认),每个grain仅有一个激活。和无状态可做模式,一个grain有多个独立激活创建来提高吞吐。 “独立”指的是同一个grain的不同激活之间没有状态协调。 所以这个模式适合本地无状态的grain,或者本地状态是静态的grain,例如一个用作持久状态缓存的grain。
Next
下面我来看一下Silos,grain的宿主单元。