squbs-1. 引導

原文地址:Unicomplex & Cube Bootstrapping

Unicomplex和Cube的引導

squbs默認自帶一個org.squbs.unicomplex.Bootstrap的引導類。它可以通過IDE、命令行、sbt、Maven啟動。引導類掃描類加載器,并在每個加載的jar包資源中查找META-INF/squbs-meta.<ext&gt。如果squbs的元數據是有效的,jar包將被當做squbs的cube或擴展,并通過元數據的聲明進行初始化。引導(Bootstrap)會首先初始化擴展程序、cubes,然后服務處理器,而不是他們在classpath中的先后順序。

在正常情況下,引導細節沒有太大的意義。然而,有種情況可能需要通過不同方式的編程來引導squbs。這在在進行測試用例(需要自定義配置和并發運行)時特別常見。更多信息可以參見Testing squbs Applications。引導squbs的語法如下:
Option 1) 用戶自定義啟動配置

UnicomplexBoot(customConfig)  
    .createUsing {(name, config) => ActorSystem(name, config)}  
    .scanResources() 
    .initExtensions  
    .stopJVMOnExit  
    .start()

Option 2) 使用默認配置啟動

UnicomplexBoot {(name, config) => ActorSystem(name, config)}
  .scanResources()
  .initExtensions
  .stopJVMOnExit
  .start() 

讓我們來看看每個部分:

  1. 創建UnicomplexBoot (boot) 對象。它可以通過傳遞一個自定義的配置文件或是actor系統創建者的閉包 UnicomplexBoot.apply()來完成。

  2. 在例子中展示的customConfig即為配置對象 。這是一個從Typesafe配置類庫解析函數中獲取的配置對象。此配置對象尚未與application.conf 合并。

  3. ActorSystem創建者通過傳遞一個函數或者閉包來創建ActorSystem。這個實際的創建在開始階段(條目7)。默認的函數是{(name, config) => ActorSystem(name, config)}。其中輸入的name是從配置項中讀取的ActorSystem的名稱。這個config將會在其他所有配置項合并之后再進行加載。大多是用例都希望以這種方式創建ActorSystem,因此并不需要提供該函數。 createUsing 完全可以避免使用。

  4. 通過scanResources()函數掃描cubes,服務,擴展等組件。這個是強制默認的,否則將沒有組件被啟動。如果沒有參數傳入,suqbs引導將會掃描它的類加載器。測試用例可能希望僅掃描其中某些組件。通過傳遞附加的配置文件squbs-meta.conf將可以實現(作為參數的方式傳入scanResources),例如:scanResources("component1/META-INF/squbs-meta.conf", "component2/META-INF/squbs-meta.conf")。它將掃描你的類路徑和附加的資源文件路徑。如果你不想讓類路徑被掃描,在資源列表前傳入withClassPath = false 或僅僅false即可:.scanResources(withClassPath = false, "component1/META-INF/squbs-meta.conf", "component2/META-INF/squbs-meta.conf")

  5. 使用 initExtension函數初始化擴展。它會初始化掃描到的擴展。在ActorSystem創建前,擴展將會完成初始化。在多重Unicomplex用例中(多個ActorSystem),同樣的擴展至多初始化一次。一個擴展只能用在一個測試用例中。在一些測試用例中,我們根本不想初始化擴展,并且不會調用initExtension

  6. 在退出的時候停止JVM。調用 stopJVMOnExit 這個函數啟動該功能。這個選項通常不會在測試用例里面使用。它被用在squbs引導中以保證subqs正常的關閉與退出。

  7. 調用start()方法啟動Unicomplex。這個是強制性的步驟。如果沒有這個ActorSystem將不會啟動,并且Actor也不可運行。該啟動調用在完全啟動并運行或者超時前會處于阻塞。如果啟動超時,某些組件可能依然在初始化,從而使系統處于Initializing 狀態,但是,任何單個組件故障將在超時時將系統狀態轉變為 Failed 。這將允許類似系統組件的系統診斷執行和結束。默認的啟動超時時間為60秒。對于期望超時的測試,可以設置一個較低的超時時間作為參數傳遞給 start() 函數,如start(Timeout(5 seconds)) ,或者通過如start(5 seconds)隱式轉換的方式設置超時時間。

配置解決方案

squbs選擇一個應用配置,并將classpath中聚合的application.conf 、reference.conf進行合并。這個應用配置以下面這個順序進行合并:

  1. 如果在創建引導對象的時候已經提供了這個配置,則選擇這個配置。這就是上面例子中的customConfig字段。

  2. 如果在外部的配置目錄中提供了application.conf文件,這個application.conf文件將被選擇。外部的配置文件目錄可以通過配置squbs.external-config-dir參數設置,默認為squbsconfig。不是那樣的話,設置的目錄將不會被提供的目錄或外部配置文件改變和覆蓋(因為目錄本身是使用config屬性確定的)。

  3. 其他情況下,將使用應用程序提供的application.conf。最后使用reference.conf

插件模塊化系統

squbs將應用劃分成稱為cube的模塊。squbs中的模塊在平行的類路徑中隔離運行。模塊化意在達到模塊之間的松耦合,而不會導致發生任何依賴關系引起的類路徑沖突。

當前的實現是從一個平面(flat)類路徑進行引導。在引導下,squb會自動檢測classpath下掃描的模塊。掃描到的cubes將會自動被檢測和啟動。

Cube Jars

所有的cube通過一個頂級jar文件和cube本身呈現。所有的cube必須在文件META-INF/squbs-meta.<ext>.中有元數據。支持.conf、.json和.properties的擴展名。關于格式可以參考Typesafe config

cube的元數據至多配置唯一的cube和版本定義,并且申明和配置多個以下元素:

Actor: 定義squbs自動啟動的well known actor。

Service: 定義一個squbs服務

Extension: 定義一個squbs框架擴展。這個擴展入口必須繼承org.squbs.lifecycle.ExtensionLifecycle特性。

配置解決方案

當多個cube嘗試提供它們內部的 application.conf文件時,為cube提供 application.conf配置文件可能出現問題。合并這些配置文件的優先級規則未被定義。推薦cube僅提供reference.conf 并且可以在部署時可以被外部的application.conf覆蓋。

Well Known Actors

Well known actors 是僅僅指的是在Akka documentation中定義的 Akka actors。它們通過每個cube中的主管actor啟動。主管的名稱從cube中而來。因此任何well known actor有一個/<CubeName>/<ActorName>的路徑,并且可以通過調用ActorSelection查找/user/<CubeName>/<ActorName>。

一個well known actor可以啟動為一個單例actor或一個router。為了申明一個well known actor為一個router,加上:
with-router = true
在actor聲明中。well knwon actor如路由(Router)、調度員(dispatcher)、郵箱配置(mailbox configuration)根據Akka文檔通過reference.conf或application.conf 配置。

以下是一個cube的例子,配置在 META-INF/squbs-meta.conf下的一個well known actor:

cube-name = org.squbs.bottlecubecube-version = "0.0.2"
squbs-actors = [
  {
    class-name = org.squbs.bottlecube.LyricsDispatcher
    name = lyrics
    with-router = false  # Optional, defaults to false
    init-required = false # Optional
  }
]

參數init-required用于actors是否需要返回它們完全啟動后的狀態給系統,以便將其視為初始化完成。有關啟動/初始化鉤子完整的討論,可以參照Startup Hooks 中的Runtime Lifecycles & API

如果一個actor被配置了with-router (with-router = true)和一個非默認的調度員(dispatcher),那么通常是在非默認調度員(non-default dispatcher)上調度actor(routee)。路由(router)將承擔well known actor的名稱,而不是routee(你實現的actor)。一個路由(router)上設置的調度員(dispatcher)將僅影響當前路由(router),而不是routee。為了影響routee,你需要為了routee創建單獨的配置,并將"/*"附加到名稱上。接下來,您將要在下面的例子中,在routee部分設置調度員(dispatcher)

akka.actor.deployment {
  # Router configuration
  /bottlecube/lyrics {
    router = round-robin-pool
    resizer {
      lower-bound = 1
      upper-bound = 10
    }
  }
  # Routee configuration. Since it has a '*', the name has to be quoted.
  "/bottlecube/lyrics/*" {
    # Configure the dispatcher on the routee.
    dispatcher = blocking-dispatcher
  }

路由的概念、例子、配置都被記錄在Akka documentation

服務(Services)

有關于服務所有的細節在 Implementing HTTP(S) Services會有描述。在 META-INF/squbs-meta.conf 中聲明的服務元數據,如下所示:

cube-name = org.squbs.bottlesvc
cube-version = "0.0.2"
squbs-services = [
  {
    class-name = org.squbs.bottlesvc.BottleSvc
    web-context = bottles # 例如,你還可以指定bottles/v1

    # 監聽的條目是可選的,默認為'default-listener'
    listeners = [ default-listener, my-listener ]

    # 可選,默認為一個默認的pipeline
    pipeline = some-pipeline

    # 可選,如果設置為false則禁用默認pipeline
    defaultPipelineOn = true

    # 可選,僅適用于actor
    init-required = false
  }
]

完整的描述可以參見Service Registration

擴展

squbs中的擴展是為環境所啟動的低等級設備。擴展初始化需要繼承org.squbs.lifecycle.ExtensionLifecycle特性同時復寫回調參數。一個擴展有很大的能力來反思系統,并且提供額外的squbs未提供的功能。在同一個cube中,一個擴展不可以與一個actor或service組合。

擴展按照順序一個一個加載的。擴展的生成者可以在擴展聲明中通過指定:sequence = [number]來為擴展啟動提供序列號。如果序列號沒有被指定,它默認為Int.maxValue。這代表著它將會在所有標有序列號的擴展啟動之后啟動。如果存在多個擴展沒有指定序列號或者制定了相同的序列號,那么他們之間啟動順序是不確定的。關閉寫順序和啟動的順序相反。

關閉squbs

運行中的squbs可以通過向Unicomplex()發送一個 GracefulStop 消息關閉。
默認的啟動main方法,org.squbs.unicomplex.Bootstrap,注冊一個JVM關閉掛鉤(hook),可以發送GracefulStop 消息至 Unicomplex。另外,如果一個squbs應用通過默認的main方法啟動,當JVM接收到SIGTERM消息時,系統將會優雅的關閉。

如果有其他監控進程負責關閉app,例如JSW,可以設置org.squbs.unicomplex.Shutdown的main方法優雅的關閉關閉系統。同樣的,Shutdown中的main方法發送一條 GracefulStop 消息至Unicomplex

在某些情況下,期望對關閉添加延遲。例如,如果一個負載均衡的健康每5s檢測一次,但app在健康監測的1s后關閉,這個應用將保持在未來的4s中繼續處理請求,直到下一次健康檢測;但是,它無法提供這些請求。如果你使用上面的其中一個方法,org.squbs.unicomplex.Bootstrap 或者org.squbs.unicomplex.Shutdown,你可以通過如下的配置添加一個延遲:

squbs.shutdown-delay = 5 seconds

通過以上的配置, GracefulStop將會延遲5s后向 Unicomplex 發送。

在接收到GracefulStop消息后,Unicomplex actor將會停止服務,并傳播 GracefulStop消息至所有的cube管理者中。每個管理者負責停止其cube中的actor(通過傳播GracefulStop消息至希望執行優雅停止的children),確保他們成功關閉或超時后回傳PoisonPill ,隨后其關閉自身。一旦所有的cube管理者和服務停止,squbs系統關閉。然后,一個關閉鉤子將被調用來關閉所有的擴展并且最后退出JVM.

目前web容器沒有一個標準的控制臺來允許squbs的用戶構建他們自己的控制臺。web控制臺可以提供正確的用戶關閉,通過發送一個停止消息至Unicomplex :

  Unicomplex() ! GracefulStop
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容