Service Fabric学习-从helloworld开始(无状态服务)

原先做服务器程序, 都是部署在xx云上, 也没理解云是个啥, 不就是个服务器(虚拟机)租赁商吗? 好吧, 其实这个是IaaS, 而接下来要学习的ServiceFabric(以下简称SF)是PaaS. 

首先SF和Orleans类似, 都是基于actor模型, 然后编程方式也很像, 大概就是定义公开接口, 然后后端服务实现接口, 前端调用接口这样.

这里说的前后端着实不够严谨, 其实是指服务器上的前后端, 前端是服务的前端并非服务器对应的客户端. 如果有web(asp.net)或是其他无状态类似网关的服务在前面接收客户端消息并调用服务接口, 那就是服务的使用者也就是这里语义上的前端了(语死早).  

服务根据其是否有状态分为: 无状态服务和有状态服务. 

无状态服务很容易理解, 一个helloword, echo示例, 计算器示例, 只处理用户输入本身不保存状态, 那就是无状态服务. 无状态服务的扩展很简单, 增加节点既是.

然而如计算器这种服务, 如果需要保存一些数据等待用户下次使用, 那就需要变成有状态服务了. 当然也可以引入第三方存储来规避状态, 继续使用无状态服务(伪), 因为此时的状态已经托付给第三方存储了. 

当然上述做法使得结构又复杂起来了, 也可能造成额外的调用等待, 不如使用有状态服务. 

而服务有了状态, 那又涉及到状态的落地, 容灾, 同步, 锁...这些东西烦扰了我整个编程生涯. 据说可以在SF中找到答案. 

官网的文档入门案例太复杂了, 引入了angular等加高门槛搅脑汁的东西, 而我今天不打算学太多, 先做一个helloworld消化下. 最后的功能是能通过一个console程序调用服务接口, 然后接收返回的字符串helloworld. 

一 安装必须工具

  毫无疑问, visual studio是必须的, 我选择目前最新的vs2017社区免费版.

  然后安装sdk

二 创建无状态服务

  打开vs->新建项目->Visual C#->cloud->Serivce Fabric Application, 名称为HelloWorldApplication

  选择无状态服务(stateless service), 名称为HelloWorldService

三 定义接口

  创建接口, IHelloWorldService.cs

  定义方法Task SayHello(string msg);

  为了能远程调用, 使用nuget安装包Microsoft.ServiceFabric.Services.Remoting

  此时打开"编辑项目文件csproj", 会看到如下的包引用 

  <ItemGroup>
    <PackageReference Include="Microsoft.ServiceFabric.Services" Version="3.1.301" />
    <PackageReference Include="Microsoft.ServiceFabric.Services.Remoting" Version="3.1.301" />
  </ItemGroup>

  编辑IHelloWorldService, 继承自IService(在刚才安装的remoting包中, 需要添加引用)

  最后如下

using Microsoft.ServiceFabric.Services.Remoting;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;

namespace HelloWorldService
{
    public interface IHelloWorldService : IService
    {
        Task<string> SayHello(string msg);
    }
}

这里的返回值是Task类型. 老实说我初次接触SF并不清楚其是否和Orleans一样将消息接收和处理异步开来, 同时通过task的同步调用使服务处理不用担心多线程问题. 但我猜自家产品没有理由不采用同样先进的方式吧?

四 实现接口

  编辑HelloWorldService.cs文件, 继承IHelloWorldService接口, 实现SayHello方法. 

  删除原先存在的StartAsync方法. (Azure Cloud Service方式的延续?)

  最后代码如下

    internal sealed class HelloWorldService : StatelessService, IHelloWorldService
    {
        public HelloWorldService(StatelessServiceContext context)
            : base(context)
        { }

        public Task<string> SayHello(string msg)
        {
            return Task.FromResult($"hello world! {msg}");
        }/// <summary>
        /// 可选择性地替代以创建侦听器(如 TCP、HTTP),从而使此服务副本可以处理客户端或用户请求。
        /// </summary>
        /// <returns>侦听器集合。</returns>
        protected override IEnumerable<ServiceInstanceListener> CreateServiceInstanceListeners()
        {
            //return new ServiceInstanceListener[0];
            return this.CreateServiceRemotingInstanceListeners();
        }
    }

服务到此就创建完毕了. 

五 发布到本地集群

  右键HelloWorldApplication项目, 然后发布, 选择LocalNode配置, 然后发布.

  经历漫长的等待之后, 右下角出现了一个SF的橘黄色图标, 右键Manage local cluster, 可以查看和管理已经发布的applicaiton, 以及具体运行的node. 

  注意, 忘记说了, vs需要用管理员打开...

六 接下来创建客户端.

  新建项目, console application, 任意, 我选择.net Core Console Application.

  nuget获取包

  <ItemGroup>
    <PackageReference Include="Microsoft.ServiceFabric.Services" Version="3.1.301" />
    <PackageReference Include="Microsoft.ServiceFabric.Services.Remoting" Version="3.1.301" />
  </ItemGroup>

  添加现有项, 将刚才的IHelloWorldService.cs添加进去(注意可以选择添加链接文件保持同步)

  保持接口同步的还有一个方法是另建一个类库项目, 引用同一个类库(如同Orleans示例中一样)

  修改Program中的main函数

        static void Main(string[] args)
        {
      
var client = ServiceProxy.Create<IHelloWorldService>(new Uri("fabric:/HelloWorldApplication/HelloWorldService"));
       string msg = Console.ReadLine();
       var result = client.SayHello(msg).Result; Console.WriteLine(result); Console.ReadKey(); }

F5运行客户端, 查看结果. 

同上示例, 还可以拓展为计算器服务. 

 

纠错: 上面说接口返回是Task可能是因为内部维持序列同步调用的关系, 其实是错误的. SF还有actor模型, 才和Orleans一样, 普通的有状态服务仍会异步调用.

上一篇:NPOI读取excel文件导出数据, 而此时文件正在打开中抛异常怎么办


下一篇:ml.net