Dapr
Distributed Application Runtime. An event-driven, portable runtime for building microservices on cloud and edge.
分散式應用執行時、事件驅動、為雲和邊緣構建微服務提供便攜化執行時。
我現在也不是很懂。
dapr/dapr
Dapr is a portable, serverless, event-driven runtime that makes it easy for developers to build resilient, stateless and stateful microservices that run on the cloud and edge and embraces the diversity of languages and developer frameworks.
Dapr codifies the best practices for building microservice applications into open, independent, building blocks that enable you to build portable applications with the language and framework of your choice. Each building block is independent and you can use one, some, or all of them in your application.
比上面的介紹多了 stateless or stateful 的標籤。學《計算理論》的時候接觸過一些狀態機。
”狀態是萬惡之源“
注意提到了多語言和多開發者框架,我認為這是他選擇的透過通訊共享資訊,即 HTTP
和 GRPC
支援多語言等特性。微軟想透過這個設定一個構建微服務應用的規則。從根本上確立你開發的每一個應用的獨立性。
下面進行一個 QuickStart
環境
- Install Docker(微服務已經離不開容器化了)
- Install Dapr
- Node.js version 8 or greater(這個 Helloworld 是 node 應用)
On MacOS
Install the latest darwin Dapr CLI to /usr/local/bin
curl -fsSL https://raw.githubusercontent.com/dapr/cli/master/install/install.sh | /bin/bash
有條件可以加速
執行初始化(會啟動 docker 容器)
$ dapr init
⌛ Making the jump to hyperspace...
Downloading binaries and setting up components
✅ Success! Dapr is up and running
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b3a5600e672f redis "docker-entrypoint.s…" 44 hours ago Up 44 hours 0.0.0.0:6379->6379/tcp xenodochial_hofstadter
e5010ba0c33f daprio/dapr "./placement" 44 hours ago Up 44 hours 0.0.0.0:50005->50005/tcp dapr_placement
HelloWorld
Application Architecture
能夠看到暴露兩個 endpoint
是 HTTP
訪問,一個建立一個查詢。
主要看我們使用 Dapr
的互動。在圖中它作為 Runtime
- 提供 Dapr API 給多語言呼叫。
- 提供 狀態管理 By state stores
Download Code
下載並進入相應資料夾
git clone https://github.com/dapr/samples.git
cd samples/1.hello-world
Cat app.js
// $ cat app.js
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
// ------------------------------------------------------------
const express = require('express');
const bodyParser = require('body-parser');
require('isomorphic-fetch');
const app = express();
app.use(bodyParser.json());
const daprPort = process.env.DAPR_HTTP_PORT || 3500;
const stateUrl = `http://localhost:${daprPort}/v1.0/state`;
const port = 3000;
app.get('/order', (_req, res) => {
fetch(`${stateUrl}/order`)
.then((response) => {
return response.json();
}).then((orders) => {
res.send(orders);
});
});
app.post('/neworder', (req, res) => {
const data = req.body.data;
const orderId = data.orderId;
console.log("Got a new order! Order ID: " + orderId);
const state = [{
key: "order",
value: data
}];
fetch(stateUrl, {
method: "POST",
body: JSON.stringify(state),
headers: {
"Content-Type": "application/json"
}
}).then((response) => {
console.log((response.ok) ? "Successfully persisted state" : "Failed to persist state");
});
res.status(200).send();
});
app.listen(port, () => console.log(`Node App listening on port ${port}!`));
這是一些路由和 handlers
注意 14-16 行
const daprPort = process.env.DAPR_HTTP_PORT || 3500;
const stateUrl = `http://localhost:${daprPort}/v1.0/state`;
const port = 3000;
3500 是 Dapr
的環境埠,如果你安裝時有改動,需要考慮。stateurl
就是 Dapr
提供的 URL 了
Handlers
/neworder
app.post('/neworder', (req, res) => {
const data = req.body.data;
const orderId = data.orderId;
console.log("Got a new order! Order ID: " + orderId);
const state = [{
key: "order",
value: data
}];
fetch(stateUrl, {
method: "POST",
body: JSON.stringify(state),
headers: {
"Content-Type": "application/json"
}
}).then((response) => {
console.log((response.ok) ? "Successfully persisted state" : "Failed to persist state");
});
res.status(200).send();
});
這裡重點是狀態儲存,即將 state
透過 stateurl
儲存在 Dapr
中。
/order
我們並不是直接透過 res.json
作為 Response
來進行已經持久化的資料的使用,而是透過暴露一個 GET endpoint 透過訪問它來驗證持久化是否成功。
app.get('/order', (_req, res) => {
fetch(`${stateUrl}/order`)
.then((response) => {
return response.json();
}).then((orders) => {
res.send(orders);
});
});
現在我們透過狀態轉移在 Dapr
裡實現了 stateless
,同樣我們也可以在加上一個 local cache
並透過一個新的 endpoint 訪問來使 Node
application 變成 stateful
Dapr Run Node.js App
npm install
:透過當前目錄下的package.json
, 會安裝express
和body-parser
,在 app.js 7-8行我們可以看到這兩項。dapr run --app-id mynode --app-port 3000 --port 3500 node app.js
$ dapr run --app-id mynode --app-port 3000 --port 3500 node app.js
ℹ️ Starting Dapr with id mynode. HTTP Port: 3500. gRPC Port: 55099
✅ You're up and running! Both Dapr and your app logs will appear here.
應該是有後臺執行的 CLI
命令,這裡是前臺列印的日誌
== DAPR == time="2019-11-06T10:37:41+08:00" level=info msg="starting Dapr Runtime -- version 0.1.0 -- commit 4358565-dirty"
== DAPR == time="2019-11-06T10:37:41+08:00" level=info msg="log level set to: info"
== DAPR == time="2019-11-06T10:37:41+08:00" level=info msg="standalone mode configured"
== DAPR == time="2019-11-06T10:37:41+08:00" level=info msg="dapr id: mynode"
== DAPR == time="2019-11-06T10:37:41+08:00" level=info msg="loaded component messagebus (pubsub.redis)"
== DAPR == time="2019-11-06T10:37:41+08:00" level=info msg="loaded component statestore (state.redis)"
== DAPR == time="2019-11-06T10:37:41+08:00" level=info msg="application protocol: http. waiting on port 3000"
== APP == Node App listening on port 3000!
== DAPR == time="2019-11-06T10:37:42+08:00" level=info msg="application discovered on port 3000"
== DAPR == 2019/11/06 10:37:42 redis: connecting to localhost:6379
== DAPR == 2019/11/06 10:37:42 redis: connected to localhost:6379 (localAddr: [::1]:55130, remAddr: [::1]:6379)
== DAPR == time="2019-11-06T10:37:42+08:00" level=info msg="actor runtime started. actor idle timeout: 1h0m0s. actor scan interval: 30s"
== DAPR == time="2019-11-06T10:37:42+08:00" level=info msg="actors: starting connection attempt to placement service at localhost:50005"
== DAPR == time="2019-11-06T10:37:42+08:00" level=info msg="http server is running on port 3500"
== DAPR == time="2019-11-06T10:37:42+08:00" level=info msg="gRPC server is running on port 55099"
== DAPR == time="2019-11-06T10:37:42+08:00" level=info msg="local service entry announced"
== DAPR == time="2019-11-06T10:37:42+08:00" level=info msg="dapr initialized. Status: Running. Init Elapsed 945.8297490000001ms"
== DAPR == time="2019-11-06T10:37:42+08:00" level=info msg="actors: established connection to placement service at localhost:50005"
== DAPR == time="2019-11-06T10:37:42+08:00" level=info msg="actors: placement order received: lock"
== DAPR == time="2019-11-06T10:37:42+08:00" level=info msg="actors: placement order received: update"
== DAPR == time="2019-11-06T10:37:42+08:00" level=info msg="actors: placement tables updated"
== DAPR == time="2019-11-06T10:37:42+08:00" level=info msg="actors: placement order received: unlock"
⚠️:注意到 Node App
在指定的 3000
埠執行,同時還有狀態儲存的 redis
在 6379
埠執行
Post and Get
Post
Curl
curl -XPOST -d @sample.json http://localhost:3500/v1.0/invoke/mynode/method/neworder
Vscode
如果你用 vscode ,使用這個外掛 Rest Client Plugin
然後開啟目錄下的 sample.http
, 可以看到 send request 的選項
sample.http
POST http://localhost:3500/v1.0/invoke/mynode/method/neworder
{
"data": {
"orderId": "42"
}
}
Postman
如圖: http://localhost:3500/v1.0/invoke/mynode/method/neworder
Result Update
你可以在你啟動的終端中看到新的日誌
== APP == Got a new order! Order ID: 42
== APP == Successfully persisted state
Get
Curl
curl http://localhost:3500/v1.0/invoke/mynode/method/order
Vscode
GET http://localhost:3500/v1.0/invoke/mynode/method/order
Postman
Terminate
ctrl + c
或者 dapr stop --app-id mynode
^C
ℹ️ terminated signal received: shutting down
✅ Exited Dapr successfully
✅ Exited App successfully
Feature
- 具有可插入提供程式和至少一次語義的事件驅動的Pub-Sub系統
- 使用可插入提供程式的輸入和輸出繫結
- 具有可插拔資料儲存的狀態管理
- 一致的服務到服務發現和呼叫
- 選擇加入狀態模型:強大/最終一致性,首次寫入/最後寫入獲勝
- 跨平臺虛擬演員
- 限速
- 使用OpenTelemetry的內建分散式跟蹤
- 使用專用的Operator和CRD在Kubernetes上本地執行
- 透過HTTP和gRPC支援所有程式語言
- 來自Azure,AWS,GCP的多雲,開放式元件(繫結,釋出-訂閱,狀態)
- 作為過程或容器化在任何地方執行
- 輕量級(58MB二進位制,4MB實體記憶體)
- 作為輔助工具執行-無需特殊的SDK或庫
- 專用的CLI-易於除錯的開發人員友好體驗
- Java,Dotnet,Go,Javascript和Python的客戶端
Refer
- https://github.com/dapr/dapr
- https://github.com/dapr/docs/blob/master/g...
- https://github.com/dapr/docs/tree/master/h...
- https://github.com/dapr/samples
- https://github.com/dapr/samples/tree/maste...
本作品採用《CC 協議》,轉載必須註明作者和本文連結