feat: measure bounded worker execution with durable verification
This commit is contained in:
121
sdk/go/cmd/orbit-exec-load/report.go
Normal file
121
sdk/go/cmd/orbit-exec-load/report.go
Normal file
@@ -0,0 +1,121 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"math"
|
||||
"runtime"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
orbit "git.yuntuo.hk/k2safe/orbit/sdk/go"
|
||||
)
|
||||
|
||||
// distribution 只计算明确纳入的样本;空集合的百分位返回null,不能冒充零延迟。
|
||||
type distribution struct {
|
||||
Count int `json:"count"` // Count 样本数;完成阶段仅包含通过持久化核验的成功任务。
|
||||
P50 *float64 `json:"p50_ms"` // P50 最近秩中位数,毫秒。
|
||||
P95 *float64 `json:"p95_ms"` // P95 最近秩95百分位,毫秒。
|
||||
P99 *float64 `json:"p99_ms"` // P99 最近秩99百分位,毫秒。
|
||||
Max *float64 `json:"max_ms"` // Max 样本最大耗时,毫秒。
|
||||
}
|
||||
|
||||
// executionReport 是单次有界测量结果,不是容量承诺或持久化审计。
|
||||
type executionReport struct {
|
||||
RunID string `json:"run_id"` // RunID 固定提交键和处理器身份的组成部分。
|
||||
GoVersion string `json:"go_version"` // GoVersion 实际编译工具链版本,不从仓库要求推断。
|
||||
GOOS string `json:"goos"` // GOOS 负载进程操作系统。
|
||||
GOARCH string `json:"goarch"` // GOARCH 负载进程架构。
|
||||
StartedAt time.Time `json:"started_at"` // StartedAt 本机开始时间,包含预检。
|
||||
AdmissionFinishedAt time.Time `json:"admission_finished_at"` // AdmissionFinishedAt 本机受理组结束时间;预检失败时为零值。
|
||||
FinishedAt time.Time `json:"finished_at"` // FinishedAt 核验及Worker收尾结束时间。
|
||||
Requests int `json:"requests"` // Requests 计划独立任务数。
|
||||
Concurrency int `json:"concurrency"` // Concurrency 提交及核验各自最大并发。
|
||||
Workers int `json:"workers"` // Workers 同一负载进程内独立WSS运行器数。
|
||||
Capacity int `json:"capacity_per_worker"` // Capacity 每个运行器物理处理器并发上限。
|
||||
DurationsMS []int64 `json:"durations_ms"` // DurationsMS 按序号循环选取的模拟等待时长。
|
||||
RunTimeoutMS int64 `json:"run_timeout_ms"` // RunTimeoutMS 整体期限,收尾最多另加5秒。
|
||||
PollIntervalMS int64 `json:"poll_interval_ms"` // PollIntervalMS 每个活跃核验器两次读取之间的间隔。
|
||||
HTTPTimeoutMS int64 `json:"http_timeout_ms"` // HTTPTimeoutMS 单次HTTP请求时限,不是任务时限。
|
||||
Queue *orbit.Queue `json:"queue,omitempty"` // Queue 预检时队列额度快照;工具不会修改配置。
|
||||
Attempted int `json:"attempted"` // Attempted 实际发起的提交调用数,不自动重试。
|
||||
NotSubmitted int `json:"not_submitted"` // NotSubmitted 截止/错误前未发起的项数。
|
||||
Accepted int `json:"accepted"` // Accepted 收到并核验唯一回执的项数。
|
||||
AdmissionErrors int `json:"admission_errors"` // AdmissionErrors 明确拒绝或提交结果无法确认的项数,不能当作全部未落库。
|
||||
VerifiedSuccess int `json:"verified_success"` // VerifiedSuccess 最终任务、尝试及结果均通过核验的任务数。
|
||||
Unverified int `json:"unverified"` // Unverified 已受理但未获核验成功的数量,包括失败/核查/仍待执行。
|
||||
HandlerCalls int `json:"handler_calls"` // HandlerCalls 本进程有效输入处理器调用数。
|
||||
DuplicateInvocations int `json:"duplicate_invocations"` // DuplicateInvocations 同一序号超过一次的调用数。
|
||||
UnconfirmedHandlerCalls int `json:"unconfirmed_handler_calls"` // UnconfirmedHandlerCalls 没有已确认受理回执的处理器调用数。
|
||||
WorkerStarted uint64 `json:"worker_started"` // WorkerStarted SDK本进程统计,不替代持久化成功数。
|
||||
Reconnects uint64 `json:"worker_reconnects"` // Reconnects SDK重连计数。
|
||||
Renewals uint64 `json:"worker_renewals_confirmed"` // Renewals SDK续租确认数。
|
||||
Admission distribution `json:"admission"` // Admission 全部提交HTTP交换的本机单调时钟耗时,含失败。
|
||||
QueueWait distribution `json:"queue_wait"` // QueueWait 数据库available_at至authorized_at,含领取及开始授权。
|
||||
AuthorizedExecution distribution `json:"authorized_execution"` // AuthorizedExecution 数据库authorized_at至ended_at,止于结束事务取时点,不包含其后提交确认。
|
||||
TaskCompletion distribution `json:"task_completion"` // TaskCompletion 数据库created_at至completed_at,不受客户端轮询顺序影响。
|
||||
Errors map[string]int `json:"errors"` // Errors 固定分类,不保存内部异常、SQL、凭据或请求原文。
|
||||
Complete bool `json:"complete"` // Complete 仅所有计划任务和本地调用逐项核验且无错误时为true。
|
||||
}
|
||||
|
||||
func newReport(cfg config, runID string) executionReport {
|
||||
r := executionReport{RunID: runID, GoVersion: runtime.Version(), GOOS: runtime.GOOS, GOARCH: runtime.GOARCH, StartedAt: time.Now().UTC(), Requests: cfg.Requests, NotSubmitted: cfg.Requests, Concurrency: cfg.Concurrency, Workers: cfg.Workers, Capacity: cfg.Capacity, RunTimeoutMS: cfg.RunTimeout.Milliseconds(), PollIntervalMS: cfg.PollInterval.Milliseconds(), HTTPTimeoutMS: cfg.Timeout.Milliseconds(), Errors: map[string]int{}}
|
||||
for _, d := range cfg.Durations {
|
||||
r.DurationsMS = append(r.DurationsMS, d.Milliseconds())
|
||||
}
|
||||
return r
|
||||
}
|
||||
func (r executionReport) finish() executionReport {
|
||||
for code, count := range r.Errors {
|
||||
if count == 0 {
|
||||
delete(r.Errors, code)
|
||||
}
|
||||
}
|
||||
r.FinishedAt = time.Now().UTC()
|
||||
r.Unverified = r.Accepted - r.VerifiedSuccess
|
||||
r.Complete = r.Attempted == r.Requests && r.NotSubmitted == 0 && r.AdmissionErrors == 0 && r.Accepted == r.Requests && r.VerifiedSuccess == r.Requests && r.HandlerCalls == r.Requests && r.WorkerStarted == uint64(r.Requests) && r.DuplicateInvocations == 0 && r.UnconfirmedHandlerCalls == 0 && len(r.Errors) == 0
|
||||
return r
|
||||
}
|
||||
func distributionOf(values []time.Duration) distribution {
|
||||
d := distribution{Count: len(values)}
|
||||
if len(values) == 0 {
|
||||
return d
|
||||
}
|
||||
sort.Slice(values, func(i, j int) bool { return values[i] < values[j] })
|
||||
percentile := func(q float64) *float64 {
|
||||
v := float64(values[int(math.Ceil(float64(len(values))*q))-1]) / float64(time.Millisecond)
|
||||
return &v
|
||||
}
|
||||
d.P50 = percentile(.5)
|
||||
d.P95 = percentile(.95)
|
||||
d.P99 = percentile(.99)
|
||||
d.Max = percentile(1)
|
||||
return d
|
||||
}
|
||||
func classify(err error) string {
|
||||
if errors.Is(err, context.DeadlineExceeded) {
|
||||
return "TIMEOUT"
|
||||
}
|
||||
if errors.Is(err, context.Canceled) {
|
||||
return "CANCELLED"
|
||||
}
|
||||
var api *orbit.APIError
|
||||
if errors.As(err, &api) {
|
||||
switch api.StatusCode {
|
||||
case 401, 403:
|
||||
return "AUTH"
|
||||
case 409:
|
||||
return "CONFLICT"
|
||||
case 429:
|
||||
return "BACKPRESSURE"
|
||||
case 400, 422:
|
||||
return "INVALID_REQUEST"
|
||||
}
|
||||
return "HTTP"
|
||||
}
|
||||
var h *orbit.HTTPError
|
||||
if errors.As(err, &h) {
|
||||
return "HTTP"
|
||||
}
|
||||
return "TRANSPORT"
|
||||
}
|
||||
Reference in New Issue
Block a user