マイクロソフトのMicroservice開発用PaaSが素敵だった件

先日は[瞬殺で作るMesos + Chronos + Marathon + Dockerクラスタ環境](http://qiita.com/TsuyoshiUshio@github/items/9d8f5b952b635d94ae6f)で書いた通り、Mesosの環境を作ったのですが、今回はマイクロソフトが発表したService Fabricを触ってみました。実際触ってみるとかなり面白い感じなので、皆さんにも共有してみたいと思います。

Service Fabricとは
---
[Azure Service Fabric](http://azure.microsoft.com/en-us/documentation/services/service-fabric/)は[マイクロサービス](http://martinfowler.com/articles/microservices.html)ベースのアプリケーションを素早く開発するためのPaaSです。


マイクロサービスとは
---
その前にそもそもマイクロサービスとは何でしょうか？[マイクロサービス](http://martinfowler.com/articles/microservices.html)はマーチンファウラー氏が提唱した用語です。具体的なイメージはこの記事がわかりやすいです。[モノリシックなRubyからGoによるマイクロサービスへ](http://postd.cc/from-a-ruby-monolith-to-microservices-in-go/)　

![Microservices](http://martinfowler.com/articles/microservices/images/sketch.png) 
上記マーチンファウラー氏のMicroservicesのページより


　今までのアプリケーションは例えば私も大好きなRuby on Railsを想像すればわかりやすいですが、モノリシックといわれる構造になっています。一つのサービスの中にさまざまな機能が盛り込まれています。例えばPDF作成だとか、業務的な個別の機能だったり、アラート機能かもしれません。もちろんサービス内部はオブジェクト指向等の考え方を使ってモジュール化されていますが、サービス自体はたくさんの機能を含んで一つにまとまっています。一方、マイクロサービスは、「それぞれのプロセスで動作する単一の問題を解決するサービス」のことを指します。
 　マイクロサービスアーキテクチャは、複数のマイクロサービスを組み合わせて、大きなサービスを提供するようなアーキテクチャを指します。

![Microservices](http://martinfowler.com/articles/microservices/images/decentralised-data.png)
上記マーチンファウラー氏のMicroservicesのページより
  
マイクロサービスが解決する問題
---
モノリシックな構造のアプリケーションはもちろんうまくいったのですが、クラウドが活用されるようになったときに、何かをちょっとでも変更すると、サービス全体をデプロイしないといけませんし、サービス自体の複雑さが増しているので、メンテナンスも難しくなってきています。

　また、大量のトランザクションに耐えるためにはスケールすることが求められますが、複雑なサービス全体をスケールさせるようにする手間はとても面倒くさいものです。
 
 これらの問題を解決する方法の一つがマイクロサービスのアーキテクチャを採用することです。

マイクロサービスを組み合わせた構成を採用すると、それぞれのサービスが小さく、分割されているので、デプロイも容易ですし、必要な個別のサービスだけをデプロイすることができるので、それぞれのサービスを保守することはそこまで難しくなくなります。またスケールに関しても、大きく複雑なモノリシックのアプリケーションをスケールさせるのは大変ですが、小さなサービスをスケール指させることはそんなに難しくありません。[Docker](https://www.docker.com/whatisdocker/)等のコンテナ技術はこのような背景で生まれてきたと思います。


マイクロサービスを実装する難しさ
---
さて、この良さそうな雰囲気のマイクロサービスですが、実際に開発すると次のような問題が出てきそうです。

* 並列処理を意識したコードを書かないといけない
* サービスを組み合わせが大変そう
* どうやってテストするの？

マイクロサービスはマイクロサービス化されるような設計でコードを書く必要があります。また、大量のトランザクションをこなすということを考えると、マルチコア時代なので、並列処理を意識したコーディングも必要でしょう。そこで近年では、並列処理がしやすく、副作用の無い関数型プログラミングが脚光を浴びています。
　さらに、マイクロサービスができたとして、きっとそれを組み合わせて動かしたり、テストしたりするのも相当大変かと思われます。場合によっては、クラスタの中のサーバーが落ちる場合もありますが、その時はどうしましょうか？
 　実際に私もDockerを利用していますが、それぞれのサービスを作るのは本当に楽だな！と感じますが、今の課題は組み合わせやそれを作ったテストをどうやって行くかに移行しています。
 
 Azure Service Fabricの面白いところ
 ---
 日本ではあまり注目されていないみたいですが、その点が[Azure Service Fabric](http://azure.microsoft.com/en-us/documentation/services/service-fabric/)のとても面白いところです。[Azure Service Fabric](http://azure.microsoft.com/en-us/documentation/services/service-fabric/)は、アプリケーション開発者がマイクロサービスを開発するときに、サービス自体の開発以外のめんどくさいことに頭を悩ませなくても開発できる基盤がそろっている感じです。マジでこれは楽そう。

![Service Fabric](https://tctechcrunch2011.files.wordpress.com/2015/04/azure-service-fabric.png?w=1024&h=576) 
[Microsoft Announces Azure Service Fabric, A New Framework For Building Highly Scalable Cloud Services](http://techcrunch.com/2015/04/20/microsoft-announces-azure-service-fabric-a-new-framework-for-building-scalable-cloud-services/)より
 
 実際に触ってみると、ローカルにガチにクラスタ環境を簡単に作れたり、マイクロサービスを作るもの本当にちゃっちゃとできる感じでした。デプロイやオーケストレーションも簡単です。そして、また、クラスタにデプロイしたマイクロサービスのテストなんかも簡単にできる基盤がそろっていて、ご丁寧に様々な障害を発生させる機能までありますw 
 
　並列処理に関しても、Scalaでも採用しているActorという仕組みを使ってちゃっちゃとコーディングができるようになっています。
 
 　さらに、お気に入りの部分がこの、Service Fabricは結構枯れた技術であるということです。なんでここまで実際の運用考えてすごくよくできているのかな？と思ったのですが、その理由が[ここ](http://azure.microsoft.com/en-us/documentation/articles/service-fabric-overview/)でも述べられているとおり、この技術はマイクロソフトがAzure SQL Databases  や Azure Document DBやSkype for Business等のガチサービスで使っている基盤だからとのことです。つまり、自分でガチスケールする、そういう基盤が自分で作れちゃうサービスなわけです。これは熱いっですね。あーなんか作りたい！
  
 Service Fabricの環境づくり
 ---
 もう説明はそろそろいいでしょう。実際に触ってみましょう。
 英語に抵抗ない人は[Set up your Service Fabric development environment](http://azure.microsoft.com/en-us/documentation/articles/service-fabric-get-started/)を読んでみてください。
 
 現在サポートしている環境は下記の通りのようです。将来はLinuxもサポートするらしいです。
 
### OS
 
 * Windows 8/8.1
 * Windows Server 2012 R2
 * Windows 10 Techinical Preview
 
### Visual Studio 2015
 
 Visual Studio 2015 RC が必要のようです。[ここ](https://www.visualstudio.com/en-us/downloads/visual-studio-2015-downloads-vs)
からダウンロードできました。


**NOTE: 日本語環境ではまだ動作しなさそうです**

あと、手順には載ってませんでしたが、まだPreviewということもあり、言語が日本語の場合、うまく動作しませんでした。Visual Studio 2015 RCをダウンロードすると日本語環境のOSの場合、日本語になってしまうので、その場合、Language Packをダウンロードするとうまくいきました。[Language Pack](https://www.microsoft.com/en-us/download/details.aspx?id=46847)をインストールしたら、Tools(ツール) > Options (オプション) > International Settings(国際化設定)で英語モードを有効にしてトライしましょう。

![SnapCrab_Options_2015-5-21_22-55-0_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/3470/e007bb18-72d2-121c-447b-d21e7fc165a5.png)


[Microsoft Visual Studio 2015 RC Language Pack](https://www.microsoft.com/en-us/download/details.aspx?id=46847)

### SDK

[ここ](http://www.microsoft.com/web/handlers/webpi.ashx?command=getinstallerredirect&appid=MicrosoftAzure-ServiceFabric)からダウンロードできます。

ダウンロードしてら、実行して、インストールしてください。

### PowerShellの設定
 
 Service FabricはPowerShellを使って、開発環境を作ったり、デプロイするようなのですが、デフォルトでVisual Studioからできないようです。次のコマンドを管理者権限で実行されたPowerShellで実行しましょう。
 
 尚、管理者権限でPowerShellを実行する方法は、PowerShellを起動させてから
 
 ```
 Start-Process powershell -Verb runAs

 ```

を実行すると、管理者権限で実行されたPowerShellのウインドウが立ち上がります。


 ```
 Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Force -Scope CurrentUser
 ```
 
### クラスタのインストールと設定

Service Fabricのクラスタを作ります。同じく、管理者権限で実行されたPowerShellで以下のコマンドを実行します。

```
cd "$env:ProgramFiles\Microsoft SDKs\Service Fabric\ClusterSetup"
.\DevClusterSetup.ps1
```

スクリプトが実行されて、私の環境だと`C:\SfDevCluster`にクラスターのファイルが生成されました。

＃＃＃クラスタの確認

次のコマンドを管理者権限のPowerShellで実行すると、ローカルに作ったクラスタ用のエクスプローラを実行することができます。

```
cd "$env:ProgramFiles\Microsoft SDKs\ServiceFabric\Tools\ServiceFabricExplorer"
 .\ServiceFabricExplorer.exe
```

次のようなService Fabricエクスプローラが起動したら準備完了です！スクリーンショットのように、Nodeが緑色になってるのを確認してくださいね。

![スクリーンショット 2015-05-21 12.19.11.png](https://qiita-image-store.s3.amazonaws.com/0/3470/4eef68af-c390-71a4-1f5a-964686172616.png)


Service Fabricで開発してみる
---

### プログラミングモデルを選ぶ

Service Fabricの開発では、次の中から[プログラミングモデル](http://azure.microsoft.com/en-us/documentation/articles/service-fabric-choose-framework/)を選びます。

* Reliable Actors API (Stateless)
* Reliable Actors API (Stateful)
* Reilable Service API (Stateless)
* Reliable Service API (Stateful)

おおざっぱなイメージを説明しておきますと、Actors APIのほうは、独立した小さなロジックをクラスタで実行したいようなケースで用います。並行性とか、どのクラスタで実行するかとかは、Service Fabricがやってくれます。

一方、Service APIのほうはそれよりももう少し大きな粒度です。サンプルで出てくる例としては、Service APIでStatelessのサービスを使って、WebApiサービスを作成する例が出てきました。

両方のパターンにおいて、Stateless/Statelfulサービスがあります。Statelessだとステートを共有できませんが、Statefulだと、クラスタ間でデータを共有してくれて、なおかつ、ノードが死んだ場合も自動的に引き継がれます。

[Build](http://www.buildwindows.com/)の動画では、この４種類以外にも、Node.js のアプリをデプロイとかもできたりするよと説明がありましたが、その手順は今のところ私は見つけられていません。

Stateful Actorでクラスタと戯れてみる
---
じゃあ、早速Actorを作ってみましょう。Templates > Visual C# > Cloud > Service FabricのApplication with Stateful Actor Serviceを選択します。プロジェクト名は何でもいいですが、私はHelloStatefulActorという名前にしてみました。

![SnapCrab_New Project_2015-5-21_13-47-56_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/3470/f2948ac2-601c-ee81-c8db-2f528b1518f1.png)

たくさんのテンプレートファイルが生成されました。まずはマイクロサービス側のActorを一作ってみます。![SnapCrab_HelloStatefulActor - Microsoft Visual Studio (Administrator)_2015-5-21_14-21-47_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/3470/f9f60956-fe8c-04c8-7bdc-906382bf7552.png)


![SnapCrab_HelloStatefulActor - Microsoft Visual Studio (Administrator)_2015-5-21_13-50-14_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/3470/d416edca-6f31-d628-d171-331c691b66cb.png)


### Stateful Actorを作成する

実はこの時点で、Statefulなサンプルが出来上がっていますが、Actorのイメージをつかむためにも自分でもコーディングしてみましょう。

まずはIHelloStatefulActor.csを開いてください。これはアクターのインターフェイスです。SayHelloというメソッドを追加してみました。

**HelloStatefulActor.cs**

インターフェイスを追加したので、実装のほうにもSayHelloを追加しましょう。ほかの部分はもともとテンプレートから作成されています。単純にわたってきた引数に対して、こんにちわを返しているだけですね。この部分はステートレスですが、参考のため書いています。

```csharp
namespace HelloStatefulActor.Interfaces
{
    public interface IHelloStatefulActor : IActor
    {
        Task<int> GetCountAsync();

        Task SetCountAsync(int count);

        Task<string> SayHello(string greeting); // 追加した
    }
}
```
**HelloStatefulActor.cs**

```csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using HelloStatefulActor.Interfaces;
using Microsoft.ServiceFabric;
using Microsoft.ServiceFabric.Actors;

namespace HelloStatefulActor
{
    public class HelloStatefulActor : Actor<HelloStatefulActorState>, IHelloStatefulActor
    {
        public override Task OnActivateAsync()
        {
            if (this.State == null)
            {
                this.State = new HelloStatefulActorState() { Count = 0 };
            }

            ActorEventSource.Current.ActorMessage(this, "State initialized to {0}", this.State);
            return Task.FromResult(true);
        }

        public Task<int> GetCountAsync()
        {
            ActorEventSource.Current.ActorMessage(this, "Getting current count value as {0}", this.State.Count);
            return Task.FromResult(this.State.Count);
        }

        public Task SetCountAsync(int count)
        {
            ActorEventSource.Current.ActorMessage(this, "Setting current count of value to {0}", count);
            this.State.Count = count;

            return Task.FromResult(true);
        }

        public Task<string> SayHello(string greeting)  // 追加した
        {
            return Task.FromResult("You said: '" + greeting + "', I say: Hello Stateful Actors!");
        }
    }
}
```

はい、これでサービス側終わり。むっちゃ簡単ですね。

**Program.cs**

次にクライアント側です。複雑そうですが、大したことはしていません。最初にActorをクライアントから使うためには、クラスタに接続する必要がありますが、次のようなActorProxyを使うことで簡単に接続することができます。

```csharp
 var proxy = ActorProxy.Create<IHelloStatefulActor>(ActorId.NewId(), "fabric:/HelloStatefulActorApplication");
```

次にSayHelloを実際にクライアントから読んでるところを見てみます。むっちゃ簡単ですね。proxyに対してそのままSayHelloを呼ぶだけです。これで実際にはクラスタにアクセスされて、現在actorが実行されているノードで処理が実施されます。

```csharp
Console.WriteLine("From Actor {0}: {1}", proxy.GetActorId(), proxy.SayHello("よろしく").Result);
```

その後は、既存のメソッドを使って、自動的に割り当てられるActorのIDと、カウンタの数字を無限ループでインクリメントするだけの作りになっています。

```csharp
using HelloStatefulActor.Interfaces;
using Microsoft.ServiceFabric.Actors;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace HelloStatefulActor.Client
{
    public class Program
    {
        public static void Main(string[] args)
        {
           // Actorプロキシの取得
            var proxy = ActorProxy.Create<IHelloStatefulActor>(ActorId.NewId(), "fabric:/HelloStatefulActorApplication");
            // SayHelloを使ってみる
            Console.WriteLine("From Actor {0}: {1}", proxy.GetActorId(), proxy.SayHello("よろしく").Result);

            // Stateful Actorを使ってみる
            int count = 10;
           
            while(true)
            {
                count = proxy.GetCountAsync().Result;
                
                Console.WriteLine("Count from Actor {1}: {0}", proxy.GetActorId(), count);
                count++;
                Console.WriteLine("Setting Count to in Actor {0}: {1}", proxy.GetActorId(), count);
                proxy.SetCountAsync(count).Wait();
                Thread.Sleep(100);
            }

        }
    }
}
```

クラスタにデプロイしてみる
---

実際に、デバッグ実行してみましょう。スクリーンショットの通りStartボタンを押します。

![SnapCrab_HelloStatefulActor - Microsoft Visual Studio (Administrator)_2015-5-21_14-21-47_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/3470/20f5fe1c-0f51-8fff-bf19-4cd4185f2f71.png)

作成したActorがデプロイされている感じです。Diagnostic Eventのウインドウを見るとActorがクラスタにデプロイされている感じです。

![SnapCrab_HelloStatefulActor (Running) - Microsoft Visual Studio (Administrator)_2015-5-21_14-22-37_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/3470/3d66fb6d-d5e5-5ca4-50b3-52d81a60567e.png)


実際に、Service Fabric Explorerを見てみると、ガッツリデプロイされています。しかもクラスタ構成になっていて、プライマリとかセカンダリなどのレプリカセットが組まれてはります。

![SnapCrab_Service Fabric Explorer_2015-5-21_14-23-44_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/3470/35ef9cc6-fbc6-df35-0b87-d3aae91cf003.png)



これは楽ちんですね。


クライアントからActorを動かしてみる
---
最後に、さくっとクライアントからActorを動かしてみましょう。一旦デバッグ実行を止めて、クライアントをビルドしてみます。HelloStatefulActor.Clientを右クリックしてBuildを選択してみてください。

![SnapCrab_HelloStatefulActor - Microsoft Visual Studio (Administrator)_2015-5-21_14-27-5_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/3470/167bfc09-9702-0e24-519d-313f01131a1c.png)


### クライアントの実行

さて、ビルドされたクライアントの場所は環境によって異なりますが、上記でビルドするとOutput タブにクライアントのexeの場所が出力されています。私の環境だと、PowerShellで下記のようにすると実行されました。

```
cd "C:\Users\ushio\Source\HelloFabric\HelloStatefulActor\HelloStatefulActor.Client\bin\Debug"

.\HelloStatefulActor.Client.exe
```
実行していると、次のように、最初のSayHelloが実行されたのちに、whileループにより、Actorが定期的に呼ばれて、１づつ数値がインクリメントされます。

![SnapCrab_管理者 Windows PowerShell_2015-5-21_23-15-56_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/3470/5f3144cf-9205-ffed-9fa7-e6f4e3b47c0f.png)


### クラスタの障害を再現してみる

さて、これだけだと面白くないので、クラスタに障害を起こしてみましょう。Fabric Explorerを開いて、Application View > HelloStatefulActorApplicationType > fabric:/HelloStatefulActorApplication > fabric:/HelloStatefulActorApplication/HelloStatefulActorService

![SnapCrab_Service Fabric Explorer_2015-5-21_21-46-5_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/3470/71ffc8c6-35dc-e3c1-4627-76bc65a1248e.png)


をみると、HelloStatefulActorのレプリカセットが複数デプロイされていることがわかります。それぞれ、Primary, Secondaryを持ったレプリカ構成になっています

現在、PowerShellで実行しているクライアントを見ると数字が出ています。これは、自動で割り振られているActorのIDです。

```
From Actor 3878874698898263532: You said: 'よろしく', I say: Hello Stateful Actors!
Count from Actor 0: 3878874698898263532
Setting Count to in Actor 3878874698898263532: 1
Count from Actor 1: 3878874698898263532
Setting Count to in Actor 3878874698898263532: 2
Count from Actor 2: 3878874698898263532
Setting Count to in Actor 3878874698898263532: 3
Count from Actor 3: 3878874698898263532
```
このPartitionInformation のLowKey とHighKeyの数字の間にこのアクターのIDが含まれているレプリカセットを探します。

![SnapCrab_Service Fabric Explorer_2015-5-21_21-46-5_No-00_02.png](https://qiita-image-store.s3.amazonaws.com/0/3470/83a8ab97-38c5-38ce-def0-c5ccc7d8aafe.png)


私の例では下記のレプリカセットがそれに該当します。そのレプリカセットのPrimaryのノードが障害を起こしたと仮定して実際にノードを停止させてみます。上記のスクリーンショットの例だと、PrimaryはNode.5ですね。

```
LowKey : 3074457345618258604
HighKey : 5124095576030431005
```

Node View > Node.x (停止させるノードは先ほどの手順で発見した、いま実行中のアクターが使っているレプリカセットのプライマリノードを停止させてください）を右クリックして停止させています。

![SnapCrab_Service Fabric Explorer_2015-5-21_21-46-52_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/3470/526b07bd-6946-2f5b-ec55-e5edd9b4322e.png)


尚、Fabric Explorerの表示は、リロードボタンをクリックしないと変わりませんのであしからず。

![SnapCrab_Service Fabric Explorer_2015-5-21_21-48-45_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/3470/27b5e7e0-243c-f718-361f-a1e7fe5d1d65.png)


リロードボタンを押すと、Nodeが停止されて、レプリカセットのノードのセカンダリがプライマリに自動的に昇格（この例ではNode.1がプライマリに昇格しています）しているのがわかります。

そしてさらにかっこいいことに、PowerShellを見ていると、ノードを落とした後一瞬動作が止まるのですが、数値のインクリメント自体は番号がかけることなく実行されます。

![SnapCrab_管理者 Windows PowerShell_2015-5-21_21-48-14_No-00.png](https://qiita-image-store.s3.amazonaws.com/0/3470/bfb8ed27-5173-eedb-09af-929cca31d31c.png)


つまり、レプリカ間でしっかりステートが共有されていて、ノードの障害時にも他のノードがその数値を引き継いで処理を実行しているのがわかります。うーん。かっこいい！これがこれだけのプログラミングでできてしまうService Fabricは相当素敵です！

まとめ
---
さて、いかがでしたでしょうか？最初はピンと来なかったのですが、実際に触ってみるとこれは相当おしゃれ感が漂っています。

こんなにも簡単にクラスタ用のアプリが作れて、簡単に障害に強いような環境ができちゃうのは末恐ろしいですね。マイクロソフトが言っている「ビジネスロジックに集中できるようにする」というのは本当ですね。

自分はオープンソース系なので、マイクロソフト基盤に触ってこなかったですが、さすがの完成度です。次回はServiceの方を深掘りして実際何か作ってみたり、Azureでクラスタ組んだりしてみたいですね！

ちなみにアーキテクチャをよく理解したいかたは次の動画とか見るとおすすめです！[Service Fabric documentation](http://azure.microsoft.com/en-us/documentation/services/service-fabric/)

では、よいマイクロサービスを！