终极套娃 2.0|云原生 PaaS 平台的可观测性实践分享
本文约 2900 字,预计阅读时间:9 分钟
用户 B:“帮忙看一下,执行流水线报错……”
用户 C:“我们的系统今天要上线,现在部署页面都打不开了,都要急坏了!”
用户 D:……
﹀
﹀
﹀
平台已经提供了服务观测能力,再引入外部平台造成重复建设,对平台使用的资源成本也有增加
开发团队日常使用自己的平台来排查故障和性能问题,吃自己的狗粮对产品的提升也有一定的帮助
对于可观测性系统的核心组件比如 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 和 Cacheservice_call_*_error描述服务的异常调用,包括 HTTP、RPC、DB 和 Cacheservice_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.serverHandlertype serverHandler struct {srv *http.Server}//go:linkname serveHTTP net/http.serverHandler.ServeHTTP//go:noinlinefunc serveHTTP(s *serverHandler, rw http.ResponseWriter, req *http.Request)//go:noinlinefunc 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.URLu.RawQuery = ""u.ForceQuery = falsereturn r.Method + " " + u.String()}))type _serverHandlerKey int8const serverHandlerKey _serverHandlerKey = 0func 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:noinlinefunc 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 Github 地址 : https://github.com/erda-project/erda -
Erda Cloud 官网 : https://www.erda.cloud/
本文分享自微信公众号 - 尔达 Erda(gh_0f507c84dfb0)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。
