Dapr - actors之构建块(3)
Important
Because actors are randomly distributed across service instances, it should be expected that an actor operation always requires a call to a different node in the network.
由于actor是在各服务实例间随机分发的,因此Actor 始终需要调用网络中的其他节点。
The next figure shows an ordering service instance running in Pod 1 call the method of an instance with ID . Because the actor with ID is placed in a different instance, this results in a call to a different node in the cluster:ship
OrderActor
3
3
下图显示了在 Pod 1 中运行的ordering 服务实例调用 ship
OrderActor
ID 为的实例的方法 3
。 由于 ID 的actor 3
放在不同的实例中,因此将导致调用群集中的不同节点:
Figure 11-3. Calling an actor method.
图 11-3。 调用执Actor方法。
- The service calls the actor API on the sidecar. The JSON payload in the request body contains the data to send to the actor.
- The sidecar uses the locally cached partitioning information from the placement service to determine which actor service instance (partition) is responsible for hosting the actor with ID . In this example, it's the service instance in pod 2. The call is forwarded to the appropriate sidecar.
3
- The sidecar instance in pod 2 calls the service instance to invoke the actor. The service instance activates the actor (if it hasn't already) and executes the actor method.
- 服务在挎斗上调用Actor API。 请求正文中的 JSON 有效负载包含要发送到Actor 的数据。
- 挎斗使用placement 服务中的本地缓存的分区信息来确定哪个执行组件服务实例 (分区) 负责托管 ID 为的Actor 。 在此示例中,它是 pod 2 中的服务实例。 调用将转发到相应的挎斗 3。
- Pod 2 中的挎斗实例调用服务实例以调用Actor。 如果Actor尚未 并执行Actor方法,则该服务实例将激活该执行组件。
Turn-based access model
Turn-based 的访问模型
The turn-based access model ensures that at any time there's at most one thread active inside an actor instance. To understand why this is useful, consider the following example of a method that increments a counter value:
turn-based 的访问模型可确保在一个Actor实例内最多只有一个线程处于活动状态。 若要了解此操作的原因,请考虑以下用于递增计数器值的方法示例:
public int Increment()
{
var currentValue = GetValue();
var newValue = currentValue + 1;
SaveValue(newValue);
return newValue;
}
Let's assume that the current value returned by the method is . When two threads call the method at the same time, there's a risk of both of them calling the method before one of them calls . This results in both threads starting with the same initial value (). The threads then increment the value to and return it to the caller. The resulting value after the two calls is now instead of which it should be. This is a simple example to illustrate the kind of issues that can slip into your code when working with multiple threads, and is easy to solve. In real world applications however, concurrent and parallel scenarios can become very complex.GetValue
1
Increment
GetValue
SaveValue
1
2
2
3
假设方法返回的当前值 GetValue
为 1
。 当两个线程同时调用方法时,它们会在调用方法 Increment
GetValue
之前调用方法 SaveValue
。 这会导致两个线程以相同初始值开始 (1
) 。 然后,线程递增值并将 2
其返回给调用方。 现在,两次调用后的结果值是, 2
而不是它的值 3
。 这是一个简单的示例,说明了在使用多个线程时可能会滑入代码的问题种类,并且很容易解决。 但在实际应用程序中,并发和并行方案可能会变得非常复杂。
In traditional programming models, you can solve this problem by introducing locking mechanisms. For example:
在传统编程模型中,可以通过引入锁定机制来解决此问题。 例如:
public int Increment()
{
int newValue;
lock (_lockObject)
{
var currentValue = GetValue();
newValue = currentValue + 1;
SaveValue(newValue);
}
return newValue;
}
Unfortunately, using explicit locking mechanisms is error-prone. They can easily lead to deadlocks and can have serious impact on performance.
遗憾的是,使用显式锁定机制容易出错。 它们很容易导致死锁,并可能对性能产生严重影响。
- 点赞
- 收藏
- 关注作者
评论(0)