原文地址:Unicomplex & Cube Bootstrapping
Unicomplex和Cube的引導
squbs默認自帶一個org.squbs.unicomplex.Bootstrap
的引導類。它可以通過IDE、命令行、sbt、Maven啟動。引導類掃描類加載器,并在每個加載的jar包資源中查找META-INF/squbs-meta.<ext>。如果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()
讓我們來看看每個部分:
創建UnicomplexBoot (boot) 對象。它可以通過傳遞一個自定義的配置文件或是actor系統創建者的閉包
UnicomplexBoot.apply()
來完成。在例子中展示的
customConfig
即為配置對象 。這是一個從Typesafe配置類庫解析函數中獲取的配置對象。此配置對象尚未與application.conf
合并。ActorSystem創建者通過傳遞一個函數或者閉包來創建ActorSystem。這個實際的創建在開始階段(條目7)。默認的函數是
{(name, config) => ActorSystem(name, config)}
。其中輸入的name是從配置項中讀取的ActorSystem的名稱。這個config將會在其他所有配置項合并之后再進行加載。大多是用例都希望以這種方式創建ActorSystem,因此并不需要提供該函數。createUsing
完全可以避免使用。通過
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")
。使用
initExtension
函數初始化擴展。它會初始化掃描到的擴展。在ActorSystem創建前,擴展將會完成初始化。在多重Unicomplex用例中(多個ActorSystem),同樣的擴展至多初始化一次。一個擴展只能用在一個測試用例中。在一些測試用例中,我們根本不想初始化擴展,并且不會調用initExtension
。在退出的時候停止JVM。調用
stopJVMOnExit
這個函數啟動該功能。這個選項通常不會在測試用例里面使用。它被用在squbs引導中以保證subqs正常的關閉與退出。調用
start()
方法啟動Unicomplex。這個是強制性的步驟。如果沒有這個ActorSystem將不會啟動,并且Actor也不可運行。該啟動調用在完全啟動并運行或者超時前會處于阻塞。如果啟動超時,某些組件可能依然在初始化,從而使系統處于Initializing
狀態,但是,任何單個組件故障將在超時時將系統狀態轉變為Failed
。這將允許類似系統組件的系統診斷執行和結束。默認的啟動超時時間為60秒。對于期望超時的測試,可以設置一個較低的超時時間作為參數傳遞給start()
函數,如start(Timeout(5 seconds))
,或者通過如start(5 seconds)
隱式轉換的方式設置超時時間。
配置解決方案
squbs選擇一個應用配置,并將classpath中聚合的application.conf 、reference.conf進行合并。這個應用配置以下面這個順序進行合并:
如果在創建引導對象的時候已經提供了這個配置,則選擇這個配置。這就是上面例子中的
customConfig
字段。如果在外部的配置目錄中提供了
application.conf
文件,這個application.conf
文件將被選擇。外部的配置文件目錄可以通過配置squbs.external-config-dir
參數設置,默認為squbsconfig
。不是那樣的話,設置的目錄將不會被提供的目錄或外部配置文件改變和覆蓋(因為目錄本身是使用config屬性確定的)。其他情況下,將使用應用程序提供的
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