Dapr 知多少 | 分散式應用執行時
阿新 • • 發佈:2021-02-20
![](https://upload-images.jianshu.io/upload_images/2799767-daf921ef4504be15.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
# Intro
Dapr 官方團隊已於最近(2021.1.17)正式釋出[Dapr v1.0](https://blog.dapr.io/posts/2021/02/17/announcing-dapr-v1.0/),Dapr已正式生產可用,可以部署到自託管環境或 Kubernetes 叢集。對於絕大多數開發者來說,想必對Dapr只是有所耳聞,而具體是什麼(What),可以解決什麼樣的問題(Why&How),有怎樣的應用場景(Where),並不知悉。本文就嘗試簡要梳理下Dapr,並嘗試回答以上問題。
# What's Dapr
> Distributed Application Runtime. An event-driven, portable runtime for building microservices on cloud and edge.
> 分散式應用執行時。一個事件驅動、可移植的執行時用於在雲上和邊緣計算上構建微服務。
以上是[Dapr官方GitHub倉庫](https://github.com/dapr)上對Dapr的簡介。文字雖短,口氣卻很大,因為其除了涵蓋了當前所有的技術熱點:分散式、雲、微服務,還自我標榜為:**分散式應用執行時**。分散式應用我們或多或少有些瞭解,執行時也聽到不少,比如常見的語言執行時:Java 執行時,.NET 執行時,Go 執行時等等,那執行時又是什麼東西?簡要來說:執行時是程式執行依賴的執行環境。以.NET 程式執行時CLR為例,它為.NET應用程式提供了一個託管的程式碼執行環境負責應用程式在整個執行期間的記憶體管理、執行緒管理、安全管理、遠端管理、即使編譯等。
那分散式應用執行時,就是提供分散式應用執行所依賴的的執行環境。那執行分散式應用需要哪些環境依賴呢?回答這個問題,我們要先思考開發分散式應用的挑戰是什麼?明確了挑戰,那就找到了答案。
從單機到分散式,是追求更快和更高的效能,但也帶來了更多的不確定性。比如,不確定計算機何時異常,不確定磁碟何時損壞,不確定網路通訊的延遲,也不確定訊息是否被正常消費。這些不確定性構成了分散式應用的挑戰,簡而言之:
1. 異構的機器與網路:穩定性問題
2. 普遍的節點故障:可靠性問題
3. 不可靠的網路:一致性問題
面對這些挑戰,業界提出了諸多的分散式理論、協議,如CAP定理,BASE理論,一致性協議2PC/3PC/ZAB,來保證系統的正常執行。雖然問題貌似是有了解決方案,但是應用的複雜度升高了。應用除了需要實現業務需求,還要兼顧非業務需求,整合諸如服務發現、負載均衡、失效轉移、動態擴容、資料分片、呼叫鏈路監控等分散式系統的核心功能,對應用有很強的**侵入性**,這就是以Spring Cloud為代表的微服務框架的常見做法。
那如何解決侵入性的問題呢?這個問題隨著容器編排技術的成熟有了新的解法。Kubernetes可以不侵入應用層,在容器層解決問題,比如K8S Service就具有服務發現、負載均衡的能力,HPA具有動態擴容的能力。隨著K8S的快速發展,雲原生的概念,也就越來越深入人心,那如何利用好K8S提供的基座能力,將更多的分散式能力下沉,讓應用開發迴歸業務呢?**其中Service Mesh提出的Sidecar模式,就很好的解決了微服務架構中網路通訊的問題**。Sidecar主要就是用來處理諸如服務發現、負載均衡、請求熔斷等一系列非業務需求,應用在部署時動態插入Sidecar,服務間的通訊通過Sidecar進行代理,以完成對服務間網路通訊的接管。
到這裡,微服務開發在Service Mesh的幫助下,已經漸漸迴歸業務本身,讓更多的開發者看到了一絲曙光。It's enough? 來看下Bilgin Ibryam在[Multi-Runtime Microservices Architecture](https://www.infoq.com/articles/multi-runtime-microservice-architecture/)文章中提及的分散式應用的四大需求:
![分散式應用的四大需求](https://upload-images.jianshu.io/upload_images/2799767-12a37d38029530f3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
從上圖可以看出,除了網路(Networking)外,生命週期(Lifecycle)、狀態(State)、捆綁(Binding)也是分散式應用要解決的問題之一。網路問題可以藉由Service Mesh 比如Istio予以解決。那其他三個該如何解決呢?又要應用自行開發整合嗎?顯然不符合應用迴歸業務本身的訴求。這時,Dapr登場了,Dapr提出的分散式應用執行時就是實現了以上四個需求並將其下沉作為分散式應用的執行環境。
簡而言之:**Dapr將分散式能力進行封裝下沉作為執行時以簡化分散式應用開發的技術複雜度。**
# How Dapr Works
那Dapr如何簡化分散式應用的開發呢?下面我們來看一看Dapr的主要特性。
![Any language, any framework, anywhere](https://upload-images.jianshu.io/upload_images/2799767-999e3583f2f9308f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
一圖勝千言:Dapr通過以HTTP/gRPC API這種與語言無關的方式暴露封裝的分散式能力供應用呼叫,從而支援使用任意語言或框架進行開發整合。目前官方已經提供了Go,Node,Python,.NET,Java, C++,PHP,Rust,Javascript的Sdk,簡化Dapr的整合。
其中Dapr的核心構建塊(Building Block)就是用來提供各種不同的分散式能力,我們來分別看一看。
![Building Block](https://upload-images.jianshu.io/upload_images/2799767-dec9d699da1910fa.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
**1. Service-to-service invocation(服務呼叫)**
提到跨服務方法呼叫,這個大家肯定會想,這簡單啊,不就是服務暴露API就好了嘛。是,但不完全是。比如nodeapp暴露了一個API:`http://10.0.0.2:8000/neworder`,按照傳統的方式,直接HTTP POST這個API訪問就得了,但在Dapr中,其提供了服務間方法呼叫的介面規範,需要按照
`POST/GET/PUT/DELETE http://localhost:/v1.0/invoke//method/
`的格式進行訪問。那假設pythonapp需要訪問nodeapp的方法,就需要POST一個請求到`http://localhost:3500/v1.0/invoke/nodeapp/method/neworder`。你可能會想為何多此一舉呢?此舉的意義何在呢?目的很簡單,就是為了實現對服務間網路通訊的控制以完成諸如服務發現、流量控制、重試熔斷、安全訪問等,而這相關的網路控制功能就是整合在Dapr的Sidecar中,以對應用透明的方式整合進來的。整體的服務呼叫流程如下圖所示:
![服務間呼叫](https://upload-images.jianshu.io/upload_images/2799767-4df6cd3ab8055bf0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
*PS:如果對Istio熟悉的同學需要注意,二者雖然都是通過Sidecar的模式進行網路控制,但二者是有有區別的。Dapr是以API的方式,而Istio是以代理的方式(不改變HTTP請求URI)。*
**2. State management(狀態管理)**
在進行微服務開發時,繞不開的話題就是服務間的狀態共享、併發一致性問題。對於狀態共享,你可能會說,各個服務連線到同一個Redis例項就OK了。是,但不得不考慮潛在的更新衝突的問題。Dapr 以更友好的HTTP API的方式進行狀態的儲存和讀取,同時支援通過ETags進行併發控制,並支援通過選項設定併發和一致性行為。
* 儲存:` POST http://localhost:/v1.0/state/`
* 讀取:` GET http://localhost:/v1.0/state//`
* 刪除:`DELETE http://localhost:/v1.0/state//`
以下是儲存狀態的舉例:
* `concurrency`用於指定併發選項:first-write-wins/last-write-wins(以第一次寫入為準/以最後一次寫入為準),預設以最後一次寫入為準。
* `consistency`用於指定一致性選項:strong/eventual(強一致性/最終一致性),預設為最終一致性。
```
curl -X POST http://localhost:3500/v1.0/state/starwars \
-H "Content-Type: application/json" \
-d '[
{
"key": "weapon",
"value": "DeathStar",
"etag": "xxxxx",
"options": {
"concurrency": "first-write",
"consistency": "strong"
}
}
]'
```
目前支援使用Azure CosmosDB、 Azure SQL Server、 PostgreSQL,、AWS DynamoDB、Redis 作為狀態儲存介質。
**3. Publish and subscribe(訊息釋出及訂閱)**
釋出訂閱模式,老生常談了,主要是用於微服務間基於訊息進行相互通訊。你可能也會說,這也要拿出來說,我搞個RabbitMQ/RocketMQ就是了。是的,但我還是要說,Dapr提供了一致性的訊息釋出、訂閱API,而無需關注具體使用的是何種Message Broker,從而和底層基礎設施解耦。
* 釋出:`POST http://localhost:/v1.0/publish//[?]`
* 獲取可訂閱主題:`GET http://localhost:/dapr/subscribe`
* 訂閱:`POST http://localhost:/`
![釋出訂閱](https://upload-images.jianshu.io/upload_images/2799767-082d07ff5e75d4b5.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
**4. Resource bindings and triggers (資源繫結及事件觸發)**
Dapr的Bindings與Azure Functions很類似,其是建立在事件驅動架構的基礎之上的。通過建立觸發器與資源的繫結,可以從任何外部源(例如資料庫,佇列,檔案系統等)接收和傳送事件,而無需藉助訊息佇列,即可實現靈活的業務場景。Dapr的Bindings分為兩種:
1. Input Bindings(輸入繫結):當外部資源的事件發生時,藉助輸入繫結,你的應用即可通過特定的API:`POST http://localhost:/`收到外部資源的事件,用於處理特定邏輯。
2. Output Bindings(輸出繫結):輸出繫結允許你呼叫外部資源。比如,在訂單處理場景中,在訂單建立成功後,可以將訂單資訊通過Dapr的繫結API:`POST/PUT http://localhost:/v1.0/bindings/`輸出到Kafka特定佇列上。
![資源繫結及事件觸發](https://upload-images.jianshu.io/upload_images/2799767-7890edd7396295b1.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
**5. Actors**
Dapr中的Actor模型,和Orleans的Virtual Actor一脈相傳,之前寫過一篇文章[Orleans 知多少 | .NET Core 分散式框架](https://www.cnblogs.com/sheng-jie/p/11163264.html)介紹過。簡單來講:Actor模型 = 狀態 + 行為 + 訊息。一個應用/服務由多個Actor組成,每個Actor都是一個獨立的執行單元,擁有隔離的執行空間,在隔離的空間內,其有獨立的狀態和行為,不被外界干預,Actor之間通過訊息進行互動,而同一時刻,每個Actor只能被單個執行緒執行,這樣既有效避免了資料共享和併發問題,又確保了應用的伸縮性。
Actor模型大大簡化了併發程式設計的複雜度,Dapr在Actor執行時中提供了許多功能,包括併發控制,狀態管理,生命週期管理如Actor的啟用/停用以及用於喚醒Actor的Timer(計時器)和Reminder(提醒)。這些功能同樣也是通過[API](https://docs.dapr.io/developing-applications/building-blocks/actors/howto-actors/)的方式予以提供。
* 呼叫Actor 方法:`POST/GET/PUT/DELETE http://localhost:3500/v1.0/actors///method/`
* 建立 Timer:`POST/PUT http://localhost:3500/v1.0/actors///timers/`
* 建立 Reminder:`POST/PUT http://localhost:3500/v1.0/actors///reminders/`
**6. Observability(遙測)**
Dapr記錄指標,日誌,鏈路以除錯和監視Dapr和使用者應用的執行狀況。 Dapr支援分散式跟蹤,其使用W3C跟蹤上下文標準和開放式遙測技術,可以輕鬆地診斷在生產環境中服務間的網路呼叫,併發送到不同的監視工具,如Prometheus。
**7. Secrets(安全)**
Dapr 提供了Secret管理,不過不同於K8S中的Secret,其支援與公有云和本地的Secret儲存整合,以供應用檢索使用。
# What Can We Do With Dapr
瞭解了Dapr是什麼,以及其提供的特性,那Dapr的應用場景就一目瞭然了。也就是[官網首頁](https://dapr.io)的Slogan:Simplify cloud-native application development--Focus on your application’s core logic and keep your code simple and portable。
*簡化雲原生應用的開發,確保應用專注於業務,並保證程式碼簡單可移植。*
因此,在考慮雲原生應用開發的技術選型時,盡情嘗試吧,目前在國內阿里雲也已採用。
# Last
在雲原生如火如荼發展之際,Dapr V1.0 的正式釋出,為開發者指明瞭雲原生時代微服務的開發方向。相信Dapr 在未來的微服務架構選型中必將佔有一席之地!
>參考:
[什麼是分散式系統,如何學習分散式系統](https://www.cnblogs.com/xybaby/p/7787034.html)
[Mecha:將Mesh進行到底](https://mp.weixin.qq.com/s/ywvy3O0wTA4SSNE86hw0Xg)