服务结构 - 有状态服务持久性

时间:2015-11-19 16:01:04

标签: azure azure-service-fabric

我是服务架构的新手,并开始查看有关该主题的MSDN文章。我首先实现了Hello World样本here

我将原来的RunAsync实现更改为:

var myDictionary = await this.StateManager.GetOrAddAsync<IReliableDictionary<int, DataObject>>("myDictionary");

while (!cancellationToken.IsCancellationRequested)
{
    DataObject dataObject;

    using (var tx = this.StateManager.CreateTransaction())
    {
        var result = await myDictionary.TryGetValueAsync(tx, 1);

        if (result.HasValue)
            dataObject = result.Value;
        else
            dataObject = new DataObject();
        //
        dataObject.UpdateDate = DateTime.Now;
        //
        //ServiceEventSource.Current.ServiceMessage(
        //    this,
        //    "Current Counter Value: {0}",
        //    result.HasValue ? result.Value.ToString() : "Value does not exist.");

        await myDictionary.AddOrUpdateAsync(tx, 1, dataObject, ((k, o) => dataObject));

        await tx.CommitAsync();
    }
    await Task.Delay(TimeSpan.FromSeconds(1), cancellationToken);
}

我还介绍了一种DataObject类型,并在该类型上公开了UpdateDate属性。

[DataContract(Namespace = "http://www.contoso.com")]
public class DataObject
{
    [DataMember]
    public DateTime UpdateDate { get; set; }
}

当我运行应用程序(Visual Studio 2015中的F5)时,在词典中找不到 dataObject 实例(键入为1),因此我创建一个,设置UpdateDate,将其添加到词典中并提交交易。在下一个循环期间,它找到 dataObject (键入为1)并设置UpdateDate,更新字典中的对象并提交事务。完美。

这是我的问题。当我停止并重新启动服务项目(Visual Studio 2015中的F5)时,我希望在RunAsync的第一次迭代中,可以找到dataObject(键入为1),但不是。我希望所有州都能刷新它的复制品。

我是否必须为有状态服务执行任何操作才能将其内部状态刷新到其主副本?

从我所读过的内容来看,它听起来好像所有这些都是由服务结构处理的,并且调用commit(在事务上)就足够了。如果我找到主副本(在Service Fabric Explorer-&gt; Application View中),我可以看到RemoteReplicator_xxx LastACKProcessedTimeUTC在我提交事务后(当单步执行时)更新。

非常感谢任何帮助。

谢谢!

-Mark

2 个答案:

答案 0 :(得分:4)

这是Visual Studio中默认本地开发体验的一项功能。如果在点击F5后仔细观察“输出”窗口,您将看到如下消息:

Visual Studio output window during Service Fabric deployment

部署脚本检测到已经注册了相同类型和版本的现有应用程序,因此将其删除并部署新应用程序。在此过程中,将删除与旧应用程序关联的数据。

您有几种方法可以解决这个问题。

在生产中,您将执行application upgrade以在保持状态的同时安全地推出更新的代码。但是,在开发框中快速迭代时不断更新版本可能会很乏味。

另一种方法是翻转项目属性&#34;保留数据开始&#34;到&#34;是&#34;。这将自动阻止生成的应用程序包的所有版本(不触及源中的版本),然后代表您执行应用程序升级。

enter image description here

请注意,由于升级路径中固有的某些系统检查,此部署选项可能比默认的删除和替换要慢一些。但是,当您考虑重新创建测试数据所需的时间时,它通常会被洗掉。

答案 1 :(得分:3)

您需要将ReliableDictionary视为包含对象集合而不是引用集合。也就是说,当您在字典中添加“对象”时,您必须认为您正在完全关闭对象;并且你不能再改变这个对象的状态了。当您向ReliableDictionary请求“对象”时,它会返回对其内部对象的引用。出于性能原因返回引用,您可以自由地读取对象的状态。 (如果CLR支持只读对象,但它不会很好。)但是,你不能修改对象的状态(或调用任何会修改对象状态的方法),就像修改内部对象一样字典的数据结构破坏了它的状态。

要修改对象的状态,必须复制返回引用所指向的对象。您可以通过序列化/反序列化对象或通过其他方式(例如创建一个全新的对象并将旧状态复制到新对象)来完成此操作。然后,您将新对象写入字典。在Service Fabric的未来版本中,我们打算改进ReliableDictionary的API,以使这种必需的使用模式更容易被发现。