布局:页面
标题:Orleans2.0中的交易
Orleans交易
Orleans支持针对持久Grains状态的分布式ACID交易。
建立
Orleans选择加入交易。必须将silos配置为使用事务。如果不是,对Grains上的事务方法的任何调用都将收到一个OrleansTransactionsDisabledException
。要在silos上启用交易,请调用UseTransactions()
在silos主机构建器上。
var builder = new SiloHostBuilder().UseTransactions();
交易状态存储
要使用事务,用户需要配置数据存储。为了支持带有事务的各种数据存储,存储抽象ITransactionalStateStorage
已经介绍了。这种抽象是特定于交易需求的,与普通的Grains存储不同(IGrain存储
)。要使用特定于事务的存储,用户可以使用以下任何实现来配置其silosITransactionalStateStorage
,例如Azure(AddAzureTableTransactionalStateStorage
)。
例:
var builder = new SiloHostBuilder()
.AddAzureTableTransactionalStateStorage("TransactionStore", options =>
{
options.ConnectionString = ”YOUR_STORAGE_CONNECTION_STRING”);
})
.UseTransactions();
出于开发目的,如果特定事务的存储不适用于您需要的数据存储,则IGrain存储
实现可以代替使用。对于任何未为其配置存储的事务状态,事务将尝试使用网桥故障转移到Grains存储。通过通往Grains存储的桥梁访问交易状态将效率较低,并且不是我们打算长期支持的模式,因此建议将其仅用于开发目的。
程式设计模型
grains接口
为了使Grains支持交易,必须使用“交易”属性将Grains接口上的交易方法标记为交易的一部分。该属性需求通过下面的事务选项指示在调用环境中grain调用的行为:
TransactionOption.Create
-调用是事务性的,即使在现有事务上下文中被调用,也总是会创建一个新的事务上下文(即它将启动一个新事务)。TransactionOption.Join
-调用是事务性的,但只能在现有事务的上下文中调用。TransactionOption.CreateOrJoin
-通话具有交易性。如果在事务上下文中调用,它将使用该上下文,否则它将创建一个新的上下文。TransactionOption.Suppress
-调用不是事务性的,但可以从事务中调用。如果在事务上下文中调用,则上下文将不会传递给调用。TransactionOption.Supported
-通话不是交易性的,但支持交易。如果在事务上下文中调用,则上下文将传递给调用。TransactionOption.NotAllowed
-访问不是事务性的,不能从事务中进行访问。如果在交易环境中调用,它将抛出一个NotSupportedException
。
可以将访问标记为“创建”,这意味着访问将始终启动自己的事务。例如,下面的ATM中的“转帐”操作将始终启动一个涉及两个引用帐户的新交易。
public interface IATMGrain : IGrainWithIntegerKey
{
[Transaction(TransactionOption.Create)]
Task Transfer(Guid fromAccount, Guid toAccount, uint amountToTransfer);
}
帐户上的提款和存款交易操作标记为“加入”,表示只能在现有交易的上下文中调用它们,如果在IATMGrain.Transfer(…)
。的取得平衡
通话被标记创建或加入
因此可以在现有交易中调用它,例如通过IATMGrain.Transfer(…)
,或单独使用。
public interface IAccountGrain : IGrainWithGuidKey
{
[Transaction(TransactionOption.Join)]
Task Withdraw(uint amount);
[Transaction(TransactionOption.Join)]
Task Deposit(uint amount);
[Transaction(TransactionOption.CreateOrJoin)]
Task<uint> GetBalance();
}
grain实施
grain实施需要使用ITransactionalState
facet(请参阅Facet System)以通过ACID事务管理grains状态。
public interface ITransactionalState<TState>
where TState : class, new()
{
Task<TResult> PerformRead<TResult>(Func<TState, TResult> readFunction);
Task<TResult> PerformUpdate<TResult>(Func<TState, TResult> updateFunction);
}
必须通过传递给事务状态方面的同步功能来执行对持久状态的所有读取或写入访问。这允许交易系统以交易方式执行或取消这些操作。要在Grains中使用事务状态,只需要定义一个可序列化的状态类即可保留,并在Grains的构造函数中使用交易状态
属性。后者声明状态名称和(可选)使用哪个事务状态存储(请参阅安装程序)。
[AttributeUsage(AttributeTargets.Parameter)]
public class TransactionalStateAttribute : Attribute
{
public TransactionalStateAttribute(string stateName, string storageName = null)
{
…
}
}
例:
public class AccountGrain : Grain, IAccountGrain
{
private readonly ITransactionalState<Balance> balance;
public AccountGrain(
[TransactionalState("balance", "TransactionStore")]
ITransactionalState<Balance> balance)
{
this.balance = balance ?? throw new ArgumentNullException(nameof(balance));
}
Task IAccountGrain.Deposit(uint amount)
{
return this.balance.PerformUpdate(x => x.Value += amount);
}
Task IAccountGrain.Withdrawal(uint amount)
{
return this.balance.PerformUpdate(x => x.Value -= amount);
}
Task<uint> IAccountGrain.GetBalance()
{
return this.balance.PerformRead(x => x.Value);
}
}
在上面的示例中,属性交易状态
用于声明“ balance”构造函数参数应与名为“ balance”的交易状态相关联。通过此声明,Orleans将注入ITransactionalState
从名为“ TransactionStore”的事务状态存储中加载状态的实例(请参阅安装程序)。可以通过以下方式修改状态执行更新
或通过阅读PerformRead
。交易基础架构将确保作为交易一部分进行的任何此类更改,即使是在分布于Orleans集群中的多个Grains之间,也将在创建交易的Grains调用完成后全部提交或全部撤消(IATMGrain.Transfer
在上述示例中)。
访问交易
如同其他任何Grains调用一样,调用Grains接口上的事务方法。
IATMGrain atm = client.GetGrain<IATMGrain>(0);
Guid from = Guid.NewGuid();
Guid to = Guid.NewGuid();
await atm.Transfer(from, to, 100);
uint fromBalance = await client.GetGrain<IAccountGrain>(from).GetBalance();
uint toBalance = await client.GetGrain<IAccountGrain>(to).GetBalance();
在上述访问中,使用ATMGrains将100个单位的货币从一个帐户转移到另一个帐户。转帐完成后,将查询两个帐户以获取其当前余额。货币转帐以及两个帐户查询均作为ACID事务执行。
如上例所示,事务可以像其他grain调用一样返回任务中的值,但是在调用失败时,它们不会引发应用程序异常,而是OrleansTransactionException
要么TimeoutException
。如果应用程序在事务期间引发异常,并且该异常导致事务失败(与其他系统故障导致的失败相反),则应用程序异常将是事务的内部异常。OrleansTransactionException
。如果抛出类型的交易异常OrleansTransactionAbortedException
,交易失败,可以重试。引发的任何其他异常都表示事务以未知状态终止。由于事务是分布式操作,因此处于未知状态的事务可能已经成功,失败或仍在进行中。因此,建议设置通话超时时间(SiloMessagingOptions.ResponseTimeout
)传递,以避免级联中止,然后再验证状态或重试操作。