.NET分布式Orleans - 6 - 变乱溯源

打印 上一主题 下一主题

主题 887|帖子 887|积分 2661

基本概念

变乱溯源(Event Sourcing)是一种设计模式,它记录并存储了应用程序状态变化的所有变乱。
其焦点头脑是将系统中的每次状态变化都视为一个变乱,并将这些变乱以时间顺序的方式持久化存储。
如许,通过重放这些变乱,我们可以重建系统在任何特定时间点的状态。
每个变乱通常都包罗了描述状态变化的必要信息,以及发生状态变化的缘故原由和时间戳。
工作原理

工作原理方面,变乱溯源重要依赖于两个关键部门:变乱天生和变乱存储。
当系统中发生状态变化时,会天生一个或多个变乱,这些变乱随后被存储到变乱存储中。
变乱存储必要设计成高可用、高一致且可伸缩的,以支持大规模的系统操纵。
之后,当必要重建系统状态时,只需从变乱存储中按顺序读取变乱,并依次应用这些变乱到系统状态即可。
使用场景

在Orleans7中,变乱溯源重要应用在以下几个场景:

  • 分布式系统状态同步:在分布式系统中,各个节点之间的状态同步是一个重要问题。通过变乱溯源,每个节点都可以记录并发送自己的状态变化变乱,其他节点则可以通过订阅这些变乱来同步自己的状态。
  • 历史数据追踪和审计:在某些业务场景下,必要追踪系统的历史操纵记录,以进行审计或分析。变乱溯源提供了完整的操纵历史,可以方便地查询和回放历史变乱。
  • 容错和恢复:当系统发生故障时,通过变乱溯源可以方便地恢复到故障发生前的状态,或者根据变乱日记进行故障排查。
优势

变乱溯源在Orleans7中带来了以下优势:

  • 数据完整性和一致性:由于变乱溯源记录了所有状态变化的历史,因此可以确保数据的完整性和一致性。
  • 灵活性和可扩展性:变乱溯源的设计使得系统可以很容易地添加新的状态变化变乱,同时也支持大规模的系统扩展。
  • 容错和恢复本领:通过变乱溯源,可以轻松地恢复到系统的任何历史状态,大大进步了系统的容错和恢复本领。
  • 清楚的业务逻辑:每个变乱都代表了一个详细的业务操纵,因此通过查看变乱日记,可以清楚地了解系统的业务逻辑和操纵流程。
总的来说,变乱溯源是一种强盛而灵活的设计模式,它在Orleans7中的应用为分布式系统带来了诸多优势。对于软件开发者来说,理解和把握变乱溯源机制,将有助于构建更加健壮、可靠和可扩展的分布式系统。
示例

下面使用变乱溯源,来跟踪一个账户的变动记录。
首先必要安装必须的nuget包
  1. [/code]然后设置Orleans,除了Orleans的通例设置外,还必要 siloHostBuilder.AddLogStorageBasedLogConsistencyProvider("LogStorage") 来设置LogConsistencyProvider
  2. [code]builder.Host.UseOrleans(static siloHostBuilder =>
  3. {
  4.     var invariant = "System.Data.SqlClient";
  5.     var connectionString = "Data Source=localhost\\SQLEXPRESS;Initial Catalog=orleanstest;User Id=sa;Password=12334;";
  6.     siloHostBuilder.AddLogStorageBasedLogConsistencyProvider("LogStorage");
  7.     // Use ADO.NET for clustering
  8.     siloHostBuilder.UseAdoNetClustering(options =>
  9.     {
  10.         options.Invariant = invariant;
  11.         options.ConnectionString = connectionString;
  12.     }).ConfigureLogging(logging => logging.AddConsole());
  13.     siloHostBuilder.Configure<ClusterOptions>(options =>
  14.     {
  15.         options.ClusterId = "my-first-cluster";
  16.         options.ServiceId = "SampleApp";
  17.     });
  18.     // Use ADO.NET for persistence
  19.     siloHostBuilder.AddAdoNetGrainStorage("GrainStorageForTest", options =>
  20.     {
  21.         options.Invariant = invariant;
  22.         options.ConnectionString = connectionString;
  23.         //options.GrainStorageSerializer = new JsonGrainStorageSerializer()
  24.      
  25.     });
  26. });
复制代码
界说账户的存储和提取变乱类
  1. // the classes below represent events/transactions on the account
  2. // all fields are user-defined (none have a special meaning),
  3. // so these can be any type of object you like, as long as they are serializable
  4. // (so they can be sent over the wire and persisted in a log).
  5. [Serializable]
  6. [GenerateSerializer]
  7. public abstract class Transaction
  8. {
  9.     /// <summary> A unique identifier for this transaction  </summary>
  10.     [Id(0)]
  11.     public Guid Guid { get; set; }
  12.     /// <summary> A description for this transaction  </summary>
  13.     [Id(1)]
  14.     public string Description { get; set; }
  15.     /// <summary> time on which the request entered the system  </summary>
  16.     [Id(2)]
  17.     public DateTime IssueTime { get; set; }
  18. }
  19. [Serializable]
  20. [GenerateSerializer]
  21. public class DepositTransaction : Transaction
  22. {
  23.     [Id(0)]
  24.     public uint DepositAmount { get; set; }
  25. }
  26. [Serializable]
  27. [GenerateSerializer]
  28. public class WithdrawalTransaction : Transaction
  29. {
  30.     [Id(0)]
  31.     public uint WithdrawalAmount { get; set; }
  32. }
复制代码
再界说账户的Grain,此中有存钱,取钱,获取余额,与变动记录操纵
Grain类必须具有 LogConsistencyProviderAttribute 才气指定日记一致性提供程序。 还必要 StorageProviderAttribute设置存储。
  1. /// <summary>
  2. /// An example of a journaled grain that models a bank account.
  3. ///
  4. /// Configured to use the default storage provider.
  5. /// Configured to use the LogStorage consistency provider.
  6. ///
  7. /// This provider persists all events, and allows us to retrieve them all.
  8. /// </summary>
  9. /// <summary>
  10. /// A grain that models a bank account
  11. /// </summary>
  12. public interface IAccountGrain : IGrainWithStringKey
  13. {
  14.     Task<uint> Balance();
  15.     Task Deposit(uint amount, Guid guid, string desc);
  16.     Task<bool> Withdraw(uint amount, Guid guid, string desc);
  17.     Task<IReadOnlyList<Transaction>> GetTransactionLog();
  18. }
  19. [StorageProvider(ProviderName = "GrainStorageForTest")]
  20. [LogConsistencyProvider(ProviderName = "LogStorage")]
  21. public class AccountGrain : JournaledGrain<AccountGrain.GrainState, Transaction>, IAccountGrain
  22. {
  23.     /// <summary>
  24.     /// The state of this grain is just the current balance.
  25.     /// </summary>
  26.     [Serializable]
  27.     [Orleans.GenerateSerializer]
  28.     public class GrainState
  29.     {
  30.         [Orleans.Id(0)]
  31.         public uint Balance { get; set; }
  32.         public void Apply(DepositTransaction d)
  33.         {
  34.             Balance = Balance + d.DepositAmount;
  35.         }
  36.         public void Apply(WithdrawalTransaction d)
  37.         {
  38.             if (d.WithdrawalAmount > Balance)
  39.                 throw new InvalidOperationException("we make sure this never happens");
  40.             Balance = Balance - d.WithdrawalAmount;
  41.         }
  42.     }
  43.     public Task<uint> Balance()
  44.     {
  45.         return Task.FromResult(State.Balance);
  46.     }
  47.     public Task Deposit(uint amount, Guid guid, string description)
  48.     {
  49.         RaiseEvent(new DepositTransaction()
  50.         {
  51.             Guid = guid,
  52.             IssueTime = DateTime.UtcNow,
  53.             DepositAmount = amount,
  54.             Description = description
  55.         });
  56.         // we wait for storage ack
  57.         return ConfirmEvents();
  58.     }
  59.     public Task<bool> Withdraw(uint amount, Guid guid, string description)
  60.     {
  61.         // if the balance is too low, can't withdraw
  62.         // reject it immediately
  63.         if (State.Balance < amount)
  64.             return Task.FromResult(false);
  65.         // use a conditional event for withdrawal
  66.         // (conditional events commit only if the version hasn't already changed in the meantime)
  67.         // this is important so we can guarantee that we never overdraw
  68.         // even if racing with other clusters, of in transient duplicate grain situations
  69.         return RaiseConditionalEvent(new WithdrawalTransaction()
  70.         {
  71.             Guid = guid,
  72.             IssueTime = DateTime.UtcNow,
  73.             WithdrawalAmount = amount,
  74.             Description = description
  75.         });
  76.     }
  77.     public Task<IReadOnlyList<Transaction>> GetTransactionLog()
  78.     {
  79.         return RetrieveConfirmedEvents(0, Version);
  80.     }
  81. }
复制代码
最后即可通过client天生grain,并获取账户变动记录
  1. var palyer = client.GetGrain<IAccountGrain>("zhangsan");
  2. await palyer.Deposit(1000, Guid.NewGuid(), "aaa");
  3. var logs = await palyer.GetTransactionLog();
  4. return Results.Ok(logs);
复制代码
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

干翻全岛蛙蛙

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表