本文约 2900 字,预计阅读时间:9 分钟
﹀
﹀
﹀
平台已经提供了服务观测能力,再引入外部平台造成重复建设,对平台使用的资源成本也有增加
开发团队日常使用自己的平台来排查故障和性能问题,吃自己的狗粮对产品的提升也有一定的帮助
对于可观测性系统的核心组件比如 Kafka 和 数据计算组件,我们通过 SRE 团队的巡检工具来旁路覆盖,并在出问题时触发报警消息
Erda 微服务观测平台提供了 APM、用户体验监控、链路追踪、日志分析等不同视角的观测和诊断工具,本着物尽其用的原则,我们也把 Erda 产生的不同观测数据分别进行了处理,具体的实现细节且继续往下看。
OpenTelemetry 是 CNCF 的一个可观测性项目,由 OpenTracing 和 OpenCensus 合并而来,旨在提供可观测性领域的标准化方案,解决观测数据的数据模型、采集、处理、导出等的标准化问题,提供与三方 vendor 无关的服务。
https://opentelemetry.io/
关键代码参考 receivers/opentelemetry
https://github.com/erda-project/erda/tree/master/modules/oap/collector/plugins/receivers/opentelemetry
service_node
描述服务的节点和实例
service_call_*
描述服务和接口的调用指标,包括 HTTP、RPC、DB 和 Cache
service_call_*_error
描述服务的异常调用,包括 HTTP、RPC、DB 和 Cache
service_relation
描述服务之间的调用关系
关键代码参考 analyzer/tracing https://github.com/erda-project/erda-analyzer/tree/master/analyzer-tracing/src/main/java/cloud/erda/analyzer/tracing
关于 monkey 的原理可以参考 monkey-patching-in-go https://bou.ke/blog/monkey-patching-in-go/
//go:linkname serverHandler net/http.serverHandler
type serverHandler struct {
srv *http.Server
}
//go:linkname serveHTTP net/http.serverHandler.ServeHTTP
//go:noinline
func serveHTTP(s *serverHandler, rw http.ResponseWriter, req *http.Request)
//go:noinline
func originalServeHTTP(s *serverHandler, rw http.ResponseWriter, req *http.Request) {}
var tracedServerHandler = otelhttp.NewHandler(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
injectcontext.SetContext(r.Context())
defer injectcontext.ClearContext()
s := getServerHandler(r.Context())
originalServeHTTP(s, rw, r)
}), "", otelhttp.WithSpanNameFormatter(func(operation string, r *http.Request) string {
u := *r.URL
u.RawQuery = ""
u.ForceQuery = false
return r.Method + " " + u.String()
}))
type _serverHandlerKey int8
const serverHandlerKey _serverHandlerKey = 0
func withServerHandler(ctx context.Context, s *serverHandler) context.Context {
return context.WithValue(ctx, serverHandlerKey, s)
}
func getServerHandler(ctx context.Context) *serverHandler {
return ctx.Value(serverHandlerKey).(*serverHandler)
}
//go:noinline
func wrappedHTTPHandler(s *serverHandler, rw http.ResponseWriter, req *http.Request) {
req = req.WithContext(withServerHandler(req.Context(), s))
tracedServerHandler.ServeHTTP(rw, req)
}
func init() {
hook.Hook(serveHTTP, wrappedHTTPHandler, originalServeHTTP)
}
future1 := parallel.Go(ctx, func(ctx context.Context) (interface{}, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://www.baidu.com/api_1", nil)
if err != nil {
return nil, err
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
byts, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return string(byts), nil
})
future2 := parallel.Go(ctx, func(ctx context.Context) (interface{}, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://www.baidu.com/api_2", nil)
if err != nil {
return nil, err
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
byts, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return string(byts), nil
}, parallel.WithTimeout(10*time.Second))
body1, err := future1.Get()
if err != nil {
return nil, err
}
body2, err := future2.Get()
if err != nil {
return nil, err
}
return &pb.HelloResponse{
Success: true,
Data: body1.(string) + body2.(string),
}, nil
本文分享自微信公众号 - 尔达 Erda(gh_0f507c84dfb0)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。
|