某天自己在學習Grafana Tempo的時候, 看到它的範例有一個image叫做Synthetic Load Generator
好奇心驅使我來學習看看這是什麼?
官方定義
The synthetic load generator is a utility to generate synthetic operational data (traces, metrics, logs, events) for a simulated microservice-based application. The application is modeled through its topology and operation models for each of the components within the topology.
其中有一句話讓我感到興趣, 模擬微服務架構的應用程式其產生的(traces, metrics, logs, events)
就決定來玩看看
但我發現它目前只有traces :(
因為他的model只有定義了trace model連結 :(
整個配置檔案是JSON格式, 檔案中會描述各種服務以及路由方向, 來描述完整的拓樸關係.
建議先在腦海裡想一下...要多少節點跟行為.
主要定義的是topology這拓樸描述物件, 裡面會包含services和rootRoutes
{
"topology": {
"services": [
{
xxx
}
],
"rootRoutes": [
{
xxx
}
]
}
}
rootRoute表示拓樸中的root span, tracesPerHour還能設定每小時要發送的request數量.
這裡的service, 是對應到每個服務節點的名稱.
route則是打到該服務節點的API Path或RPC method的概念
昨天的範例, 就是說每小時打2880個請求到frontend/product
.
"rootRoutes": [
{
"service": "frontend",
"route": "/product",
"tracesPerHour": 2880
},
{
"service": "frontend",
"route": "/cart",
"tracesPerHour": 14400
}
]
接著是services內每個service物件的定義.
每個service物件內會有
{
"serviceName": "adservice",
"tagSets": [
{
"tags": {},
"tagGenerators": [],
"inherit": [],
"maxLatency": 500
}
],
"routes": [
{
"route": "/AdRequest",
"downstreamCalls": {},
"tagSets": []
},
{
"route": "/Ad",
"downstreamCalls": {},
"tagSets": []
}
],
"instances": [
"adservice-6b654dbf57-zq8dt",
"adservice-d847fdcf5-j6s2f"
],
"random": {
"seed": 22694143111805,
"nextNextGaussian": 0,
"haveNextNextGaussian": false
}
}
在service設定的tags, 會被套用到該service的所有route;
若tags只被配置在route上, 那就只有該route會被套用.
先來個暖身, 讓前端打login, 會隨機取得某一個tag
{
"topology": {
"services": [
{
"serviceName": "plateform",
"tagSets": [
{
"weight": 1,
"tags": {
"version": "v127",
"region": "us-east-1"
},
"tagGenerators": [],
"inherit": [],
"maxLatency": 100
},
{
"weight": 1,
"tags": {
"version": "v127",
"region": "us-east-2"
},
"tagGenerators": [],
"inherit": [],
"maxLatency": 100
},
{
"weight": 2,
"tags": {
"version": "v126",
"region": "us-west-1"
},
"tagGenerators": [],
"inherit": [],
"maxLatency": 110
}
],
"routes": [
{
"route": "/Login",
"downstreamCalls": { },
"tagSets": [
{
"weight": 1,
"tags": {
"account": "雷N"
},
"tagGenerators": [
],
"inherit": []
},
{
"weight": 1,
"tags": {
"account": "Virginia"
},
"tagGenerators": [],
"inherit": []
},
{
"weight": 1,
"tags": {
"account": "Nathan"
},
"tagGenerators": [],
"inherit": []
}
]
}
],
"instances": [
"plateform-001",
"plateform-002"
],
"random": {
"seed": 187004238864083,
"nextNextGaussian": 0,
"haveNextNextGaussian": false
}
}
]
},
"rootRoutes": [
{
"service": "plateform",
"route": "/Login",
"tracesPerHour": 120
}
]
}
可以比較一下Tag內容的不同
調用鏈路也是如預期, 單純到炸
新增一個Product服務
讓root, 可以偶爾打plateform/login, 偶爾打product/GetProduct
{
"topology": {
"services": [
{
"serviceName": "plateform",
"tagSets": [
{
"weight": 1,
"tags": {
"version": "v127",
"region": "us-east-1"
},
"tagGenerators": [],
"inherit": [],
"maxLatency": 100
},
{
"weight": 1,
"tags": {
"version": "v127",
"region": "us-east-2"
},
"tagGenerators": [],
"inherit": [],
"maxLatency": 100
},
{
"weight": 2,
"tags": {
"version": "v126",
"region": "us-west-1"
},
"tagGenerators": [],
"inherit": [],
"maxLatency": 110
}
],
"routes": [
{
"route": "/Login",
"downstreamCalls": { },
"tagSets": [
{
"weight": 1,
"tags": {
"account": "雷N"
},
"tagGenerators": [
],
"inherit": []
},
{
"weight": 1,
"tags": {
"account": "Virginia"
},
"tagGenerators": [],
"inherit": []
},
{
"weight": 1,
"tags": {
"account": "Nathan"
},
"tagGenerators": [],
"inherit": []
}
]
}
],
"instances": [
"plateform-001",
"plateform-002"
],
"random": {
"seed": 187004238864083,
"nextNextGaussian": 0,
"haveNextNextGaussian": false
}
},
{
"serviceName": "product",
"tagSets": [
{
"weight": 1,
"tags": {
"version": "v127",
"region": "us-east-1"
},
"tagGenerators": [],
"inherit": [],
"maxLatency": 100
},
{
"weight": 1,
"tags": {
"version": "v127",
"region": "us-east-2"
},
"tagGenerators": [],
"inherit": [],
"maxLatency": 100
},
{
"weight": 2,
"tags": {
"version": "v126",
"region": "us-west-1"
},
"tagGenerators": [],
"inherit": [],
"maxLatency": 110
}
],
"routes": [
{
"route": "/GetProducts",
"downstreamCalls": { },
"tagSets": [
{
"weight": 1,
"tags": {
"account": "雷N"
},
"tagGenerators": [
],
"inherit": []
},
{
"weight": 1,
"tags": {
"account": "Virginia"
},
"tagGenerators": [],
"inherit": []
},
{
"weight": 1,
"tags": {
"account": "Nathan"
},
"tagGenerators": [],
"inherit": []
}
]
}
],
"instances": [
"product-001",
"product-002"
],
"random": {
"seed": 187004238864083,
"nextNextGaussian": 0,
"haveNextNextGaussian": false
}
}
]
},
"rootRoutes": [
{
"service": "plateform",
"route": "/Login",
"tracesPerHour": 120
},
{
"service": "product",
"route": "/GetProducts",
"tracesPerHour": 1200
}
]
}
來玩一下downstream
讓product/GetProducts會去呼叫Recommendations/GetRecommendations
順便繼承GetProducts帶來的product tag
也順便測試出錯的話會怎辦?
在product蘋果那裡, 讓它噴錯error: true
, 回應http.status_code: 404
其他則正常
{
"topology": {
"services": [
{
"serviceName": "plateform",
"tagSets": [
{
"weight": 1,
"tags": {
"version": "v127",
"region": "us-east-1"
},
"tagGenerators": [],
"inherit": [],
"maxLatency": 100
},
{
"weight": 1,
"tags": {
"version": "v127",
"region": "us-east-2"
},
"tagGenerators": [],
"inherit": [],
"maxLatency": 100
},
{
"weight": 2,
"tags": {
"version": "v126",
"region": "us-west-1"
},
"tagGenerators": [],
"inherit": [],
"maxLatency": 110
}
],
"routes": [
{
"route": "/Login",
"downstreamCalls": { },
"tagSets": [
{
"weight": 1,
"tags": {
"account": "雷N"
},
"tagGenerators": [
],
"inherit": []
},
{
"weight": 1,
"tags": {
"account": "Virginia"
},
"tagGenerators": [],
"inherit": []
},
{
"weight": 1,
"tags": {
"account": "Nathan"
},
"tagGenerators": [],
"inherit": []
}
]
}
],
"instances": [
"plateform-001",
"plateform-002"
],
"random": {
"seed": 187004238864083,
"nextNextGaussian": 0,
"haveNextNextGaussian": false
}
},
{
"serviceName": "product",
"tagSets": [
{
"weight": 1,
"tags": {
"version": "v127",
"region": "us-east-1"
},
"tagGenerators": [],
"inherit": [],
"maxLatency": 100
},
{
"weight": 1,
"tags": {
"version": "v127",
"region": "us-east-2"
},
"tagGenerators": [],
"inherit": [],
"maxLatency": 100
},
{
"weight": 2,
"tags": {
"version": "v126",
"region": "us-west-1"
},
"tagGenerators": [],
"inherit": [],
"maxLatency": 110
}
],
"routes": [
{
"route": "/GetProducts",
"downstreamCalls": {
"recommendations": "/GetRecommendations"
},
"tagSets": [
{
"weight": 1,
"tags": {
"product": "檸檬"
},
"tagGenerators": [
],
"inherit": []
},
{
"weight": 5,
"tags": {
"product": "蘋果",
"error": true,
"http.status_code": 404
},
"tagGenerators": [],
"inherit": []
},
{
"weight": 2,
"tags": {
"product": "芭樂"
},
"tagGenerators": [],
"inherit": []
}
]
},
{
"route": "/GetCart",
"downstreamCalls": {
},
"tagSets": [
{
"weight": 1,
"tags": {
"product": "檸檬"
},
"tagGenerators": [
],
"inherit": []
},
{
"weight": 5,
"tags": {
"product": "蘋果",
"error": true,
"http.status_code": 404
},
"tagGenerators": [],
"inherit": []
},
{
"weight": 2,
"tags": {
"product": "芭樂"
},
"tagGenerators": [],
"inherit": []
}
]
}
],
"instances": [
"product-001",
"product-002"
],
"random": {
"seed": 187004238864083,
"nextNextGaussian": 0,
"haveNextNextGaussian": false
}
},
{
"serviceName": "recommendations",
"tagSets": [
{
"weight": 1,
"tags": {
"version": "v127",
"region": "us-east-1"
},
"tagGenerators": [],
"inherit": ["product"],
"maxLatency": 100
}
],
"routes": [
{
"route": "/GetRecommendations",
"downstreamCalls": { },
"tagSets": [
{
"weight": 1,
"tags": {
"query": "雷N"
},
"tagGenerators": [
{
"rand": {
"seed": 179867746078676,
"nextNextGaussian": 0,
"haveNextNextGaussian": false
},
"tagGen": {},
"valLength": 16,
"numTags": 50,
"numVals": 3000
}
],
"inherit": [],
"maxLatency": 2800
}
]
}
],
"instances": [],
"random": {
"seed": 187004238864083,
"nextNextGaussian": 0,
"haveNextNextGaussian": false
}
}
]
},
"rootRoutes": [
{
"service": "plateform",
"route": "/Login",
"tracesPerHour": 120
},
{
"service": "product",
"route": "/GetProducts",
"tracesPerHour": 800
}
,
{
"service": "product",
"route": "/GetCart",
"tracesPerHour": 600
}
]
}
正常的情況跟請求鍊結, 且有繼承product tag資料
出錯的情況跟請求鍊結
甚至還能做儀表板, 看看各服務的API log成長速率
搭配前幾天分享的LogQL Metric Queries
sum by (service, api) (rate({compose_service="synthetic-load-generator"} | json | line_format "{{.message}}" | __error__ = "" | regexp ".*service (?P<service>\\w+) route (?P<api>[\\w|/]+)" [1h]))
有這套生成器, 很快的就能模擬出一個微服務架構的拓樸.
連error都能模擬真的是很讚!
用來練習LogQL更是方便多了XD