Akka.net開發第一個分布式應用


Akka.net開發第一個分布式應用

系列主題:基於消息的軟件架構模型演變

 

既然這個系列的主題是”基於消息的架構模型演變“,少不了說說Actor模型。Akka.net是一個基於Actor模型的分布式框架。如果你對分布式應用還非常陌生,當別人在談”分布式“、”雲計算“等名詞時你感到茫然,那么本篇文章將帶你進行一次分布式開發之旅。

一、什么是Actor模型

Actor模型由Carl Hewitt於上世紀70年代早期提出並在Erlang語言中得到了廣泛應用,目的是為了解決分布式編程中一系列問題。其主要特點如下:

  • 系統由Actor構成
  • Actor之間完全獨立
  • 消息傳遞是非阻塞和異步的
  • 所有消息發送都是並行的

在Actor模型中Everything is an Actor。為什么感覺忽悠又開始了。。。

如果你看過了我寫的”基於消息的架構演變“系列,你就會發現軟件系統從觀察者模式到事件然后再到消息,經過了不斷的抽象。當軟件通過消息來交互的時候再沒有了直接引用,沒有了耦合,所有的一切都變成了異步和並行。這時候再加上分布式支持,雲計算也就變成了可能。

二、什么是Akka.net

Akka是一個基於scala語言的Actor模型庫,旨在構建一套高並發、分布式、自動容錯、消息驅動應用的工具集。Akka.net則是C#寫的Akka版本,並且有很友好的F#Api接口。git地址:https://github.com/akkadotnet/akka.net

出自微軟研究院的另一個Actor模型庫:Orleans。此項目旨在提供分布式、高伸縮性的雲計算框架。git地址:https://github.com/dotnet/orleans,我隨后將寫關於orleans的入門文章,請關注。

三、響應式宣言

說到Akka.net不得不提到響應式宣言。隨着互聯網和軟件行業的發展,早先的軟件架構已經不適應社會發展的需求。軟件系統的架構應該具備:彈性、松耦合、可伸縮性,更加容易開發和維護,發生錯誤時能夠自我容錯。所以響應式系統的概念隨之而來:

  • Responsive:The system responds in a timely manner if at all possible(系統應盡可能的及時響應)
  • Resilient: The system stays responsive in the face of failure(系統在發生錯誤時任然能夠及時響應)
  • Elastic: The system stays responsive under varying workload(系統在各種負載之下都能及時響應)
  • Message Driven: Reactive Systems rely on asynchronous message-passing to establish a boundary between components that ensures loose coupling, isolation, location transparency, and provides the means to delegate errors as messages.(反應式系統依賴於異步消息組件之間建立邊界確保松耦合、隔離、位置透明並提供委托錯誤消息的手段,這句翻譯的有點不夠准確)

之所以要提到這個宣言是因為Akka.net正是這樣一個能夠幫你建立響應式系統的框架。

四、從HelloWorld開始

1、新建一個Console Application

2、從Nuget中安裝Akka

3、新建一個GreetMessage類來通知Actor

1
2
3
public  class  GreetingMessage
{
}

3、重點來了,既然在Akka.net中一切都是Actor,那么我們想要輸出一個”Hello world”也需要通過一個Actor來完成。新建GreetingActor類:

1
2
3
4
5
6
7
public  class  GreetingActor : ReceiveActor
{
     public  GreetingActor()
     {
         Receive<GreetMessage>(greet =>Console.WriteLine( "Hello World" ));
     }
}

正如代碼所示:當Actor收到GreetMessage消息時,輸出”Hello World”。

4、在Main方法中發送消息

1
2
3
4
5
6
7
8
9
10
11
12
13
static  void  Main( string [] args)
{
     // Create a new actor system (a container for your actors)
     var  system = ActorSystem.Create( "MySystem" );
 
     // Create your actor and get a reference to it.
     var  greeter = system.ActorOf<GreetingActor>( "greeter" );
 
     // Send a message to the actor
     greeter.Tell( new  GreetingMessage());
 
     Console.ReadLine();
}

一個ActorSystem是一組Actor的容器。

1
var  greeter = system.ActorOf<GreetingActor>( "greeter" );

創建了一個名為"greeter”的Actor。

1
greeter.Tell( new  GreetingMessage());

向greeter這個Actor發送GreetMessage消息。

Ctrl+F5跑起來看看:

這個例子雖然和簡單,但是向大家展示了Akka.net中如何使用消息和Actor。

五、開發一個分布式的HelloWorld

這個HelloWorld它的NB之處在於它不是一個簡單的HelloWorld,他是一個分布式的HelloWorld。。。

既然是分布式,我們需要建立兩個Console Application分別部署在雲端和本地,另外新建一個Class liabrary項目用來放公用的message等類型。

這次Client和Server兩個項目都需要從Nuget中安裝Akka.Remote用來遠程通信。

先從Client端開始說起:

1、既然涉及到了遠程通信,免不了要配置本地的地址,通信協議,端口等信息。所有的這些配置都可以配置到web.config中。Akka.net使用HOCON(Human-Optimized Config Object Notation)的格式來配置,為了簡單期間,我們將這個配置直接寫到代碼里-其實內容跟寫web.config是一樣的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var  config = ConfigurationFactory.ParseString( @"
akka { 
     actor {
         provider = ""Akka.Remote.RemoteActorRefProvider, Akka.Remote""
     }
     remote {
         helios.tcp {
             transport-class = ""Akka.Remote.Transport.Helios.HeliosTcpTransport, Akka.Remote""
             applied-adapters = []
             transport-protocol = tcp
             port = 0
             hostname = localhost
         }
     }
}
" );

你可以看到這個配置描述了遠程通信的provider、使用了helios來做TCP通信,另外定義了client的hostname,端口號等。

2、定義Client端的ActorSystem,並向遠程發送消息

1
2
3
4
5
6
7
8
9
10
11
12
13
using  ( var  system = ActorSystem.Create( "MyClient" , config))
     {
         var  greeting = system.ActorSelection( "akka.tcp://MyServer@localhost:8081/user/Greeting" );
 
         while  ( true )
         {
             var  input = Console.ReadLine();
             if  (input.Equals( "sayHello" ))
             {
                 greeting.Tell( new  GreetingMessage());
             }
         }
     }

這次的重點在於創建Actor是通過system.ActorSelection方法來實現,因為此Actor在雲端,我們沒有通過引用雲端的程序集,而是通過雲端的Actor地址akka.tcp://MyServer@localhost:8081/user/Greeting來訪問GreetingActor。MyServer是雲端的ActorSystem名稱,localhost:8081是雲端的地址和ip,由於我們在本地模擬,所以任然為localhost。user/Greeting表示我們要選取名稱為Greeting的Actor。

當用戶在client端輸入"sayHello"之后,會向GreetingActor發送一個GreetingMessage的消息。

3、Server端的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var  config = ConfigurationFactory.ParseString( @"
akka { 
     actor {
         provider = ""Akka.Remote.RemoteActorRefProvider, Akka.Remote""
     }
     remote {
         helios.tcp {
             transport-class = ""Akka.Remote.Transport.Helios.HeliosTcpTransport, Akka.Remote""
             applied-adapters = []
             transport-protocol = tcp
             port = 8081
             hostname = localhost
         }
     }
}
" );

Server端的配置跟Client端大同小異,只是擁有不同的端口號,如果部署在雲端,應該輸入雲端的ip。

4、Server端的ActorSystem

1
2
3
4
5
6
using  ( var  system = ActorSystem.Create( "MyServer" , config))
   {
       system.ActorOf<GreetingActor>( "Greeting" );
 
       Console.ReadLine();
   }

這個代碼很簡單,跟第一個例子中的代碼有點相似。

5、運行

在解決方案中把Client和Server同時設置為啟動項

然后Ctrl+F5,在client中輸入"sayHello"之后,sever端會輸出Hello World。

六、Actor結構

Akka.net中的Actor是一個具有層級結構的模型,每個ActorSystem都有多個Actor構成,而每個父Actor又可以創建自己的子Actor,對應到業務處理過程中,不同的Actor可以模擬面向對象的結構來處理具體的工作。而這個過程又可以分布在不同的服務器上,從而構成了一套完整的分布式計算系統。

七、總結

本文提到的例子非常簡單,但是展示了Actor和基於消息通信的方式。Akka.net的強大之處在於它不僅像ESB那樣解決消息的生產和消費,而且他提供了Actor並行消費消息的策略和機制,他更多的強調如何讓大量的Actor之間協調工作,從而構建分布式和響應式的系統。

使用Akka.net還可以輕松實現CQRS,如果說DDD玩的是面向對象分析,那么Akka.net將為你解決剩下的技術細節。已經有人使用scala在Akka上進行這樣的嘗試ddd-leaven-akka,期待.net平台下也有更好的應用讓我們進一步去學習和了解。

 
分類:  .NET


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM