一个自动化测试框架 vearne/autotest

注意: 本文基于 vearne/autotest v0.0.9 1. 引言 萌叔手上的API服务不少,核心的项目都有CI和单元测试。 但是毕竟在单元测试中,对外部数据库、微服务的调用都是mock的,缺乏对整个链路的自动化测试 这段时间开发了一个自动化测试框架 vearne/autotest 初步实现了对HTTP协议API服务的支持,后期应该还会支持gRPC协议的API服务 2. 框架的优势 无需进行程序开发,只需要编写配置文件 可以指定testcase之间的依赖关系 无依赖关系的testcase可以并发执行,执行速度更快 使用xpath提取变量,书写方便 支持从文件中导入变量,支持从response中提取变量 3. 完整的示例 3.1 启动API服务 使用docker compose启动一个HTTP RESTful API服务 cd docker-compose docker compose up -d 这个服务是book管理服务,它支持对book的增删改查 添加 curl -X POST 'http://localhost:8080/api/books' \ --header 'Content-Type: application/json' \ --data '{"title": "book3_title", "author": "book3_author"}' 接口返回 { "id": 3, "title": "book3_title", "author": "book3_author" } 修改 curl -X PUT 'localhost:8080/api/books/3' \ --header 'Content-Type: application/json' \ --data '{"title": "book3_title", "author": "book3_author-2"}' 接口返回 { "id": 3, "title": "book3_title", "author": "book3_author-2" } 3.2 自动化测试 autotest run -c=./config_files/autotest.yml -e=./config_files/.env.dev 自动化测试中的每一个测试用例都是 ...

May 8, 2024 · 2 min

channel的有趣用法

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 引子 萌叔在阅读tailsamplingprocessor源码时,发现channel的一种有趣的玩法,这里记录一下 FIFO 队列 tailsamplingprocessor中通过NumTraces 设置内存中最多保存的trace的数量, 超过这个阈值,就从按照先进先出的原则,删除最先进入队列的trace // NumTraces is the number of traces kept on memory. Typically most of the data // of a trace is released after a sampling decision is taken. NumTraces uint64 `mapstructure:"num_traces"` processor.go postDeletion := false currTime := time.Now() for !postDeletion { select { case tsp.deleteChan <- id: postDeletion = true default: traceKeyToDrop := <-tsp.deleteChan tsp.dropTrace(traceKeyToDrop, currTime) } } channel刚好满足这个特性, 如果tsp.deleteChan 没有满, 则往tsp.deleteChan写入一个traceID; 如果tsp.deleteChan已经装满,则从队列(tsp.deleteChan)中取出头部元素, 其实就是最先进入队列的traceID,将其对应的trace信息从内存中删除(tsp.dropTrace())。 ...

April 17, 2024 · 1 min

OpenTelemetry原理及实战

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1. 简介 OpenTelemetry 是一个开源的可观测性框架,它提供了一系列工具、API 和 SDK,用于收集、处理和导出遥测数据,如追踪(traces)、指标(metrics)和日志(logs)。OpenTelemetry 的目标是提供一个与供应商无关的、跨平台的解决方案,以帮助开发者和运维人员监控和分析分布式系统的性能和行为。 1.1 OpenTelemetry的终极目标 OpenTelemetry的终极目标了:实现Metrics、Tracing、Logging的融合及大一统,作为APM的数据采集终极解决方案。 Tracing:提供了一个请求从接收到处理完成整个生命周期的跟踪路径,一次请求通常过经过N个系统,因此也被称为分布式链路追踪 Metrics:例如cpu、请求延迟、用户访问数等Counter、Gauge、Histogram指标 Logging:传统的日志,提供精确的系统记录 三者的组合可以形成大一统的APM解决方案: 基于Metrics告警发现异常 通过Tracing定位到具体的系统和方法 根据模块的日志最终定位到错误详情和根源 1.2 核心工作 标准 + 通用实现 OpenTelemetry的核心工作目前主要集中在3个部分: 规范的制定和协议的统一,规范包含数据传输、API的规范,协议的统一包含:HTTP W3C的标准支持及GRPC等框架的协议标准 多语言SDK的实现和集成,用户可以使用SDK进行代码自动注入和手动埋点,同时对其他三方库(Log4j、LogBack等)进行集成支持; 数据收集系统的实现,当前是基于OpenCensus Service的收集系统,包括Agent和Collector。 1.3 数据模型 1.3.1 Span SpanKind Status只有3种状态 // The default status. STATUS_CODE_UNSET = 0; // The Span has been validated by an Application developer or Operator to // have completed successfully. STATUS_CODE_OK = 1; // The Span contains an error. STATUS_CODE_ERROR = 2; ...

March 7, 2024 · 2 min

玩转GRPC(2)-状态码

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1. 前言 和Http协议一样,gRPC协议也提供了一组基础的状态码。 一般情况下,仅使用这组基础状态码就可以反应gPRC请求处理的所有错误信息。 2. 示例代码 grpc_status_error server var counter uint64 = 0 const ( port = ":50051" ) type server struct { pb.UnimplementedGreeterServer } // SayHello implements helloworld.GreeterServer func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) { fmt.Println("pb.HelloRequest", in.Name) md, ok := metadata.FromIncomingContext(ctx) if !ok { fmt.Printf("get metadata error") } for key, val := range md { fmt.Printf("%v:%v\n", key, val) } x := atomic.AddUint64(&counter, 1) % 3 switch x { case 0: return &pb.HelloReply{Message: "Hello " + in.Name}, nil case 1: return nil, status.Error(codes.DataLoss, "--DataLoss--") default: return nil, status.Error(codes.Unauthenticated, "--Unauthenticated--") } } func main() { lis, err := net.Listen("tcp", port) if err != nil { log.Fatalf("failed to listen: %v", err) } s := grpc.NewServer() pb.RegisterGreeterServer(s, &server{}) // Register reflection service on gRPC server. reflection.Register(s) log.Println("say_hello_grpc starting...") if err := s.Serve(lis); err != nil { log.Fatalf("failed to serve: %v", err) } } client func main() { conn, err := grpc.Dial("localhost:50051", grpc.WithTransportCredentials(insecure.NewCredentials())) if err != nil { log.Fatalf("did not connect: %v", err) } defer conn.Close() client := pb.NewGreeterClient(conn) // Contact the server and print out its response. ctx, cancel := context.WithTimeout(context.Background(), time.Second) defer cancel() r, err := client.SayHello(ctx, &pb.HelloRequest{Name: "lily"}) if err != nil { s := status.Convert(err) log.Printf("code:%v, message:%v\n", s.Code(), s.Message()) } else { log.Printf("reply:%v\n", r.String()) } } 也可以使用status.Code(err),直接得到code 当 err == nil 时,code为codes.OK, 值为0 3. wireshark 抓包 wireshark 抓包gRPC参考 Analyzing gRPC messages using Wireshark ...

February 5, 2024 · 2 min

skywalking-go 原理剖析

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 本文代码示例基于 skywalking-go v0.3.0 1. 引言 apache/skywalking-go 的内部实现比较复杂,本文针对几个核心的点进行展开,以便于大家更好的阅读和理解。 2.TracingID生成 详细参考代码 id.go skywalking-go中的TraceID形如: “ab95670cae9d11ee87ca5626e1cdcfe2.14.39165238789840005” 一共由4部分组成: 1)uuid 使用uuid version1 2)goroutine ID,golang协程ID 3)timestamp 自1900年以来的毫秒值 4)sequence, 从0 ~ 10000 3. 跨协程传递Tracing信息 在没有skywalking-go的情况下,如果想在多个协程中传递Tracing信息, 开发者必须要用到context。使用skywalking-go之后,很多细节,开发者无需关心。 下面是一个在gin中使用多协程的示例,完整代码见参考资料2 r.GET("/ping", func(c *gin.Context) { g, _ := errgroup.WithContext(context.Background()) g.Go(func() error { val, err := rdb.Incr(context.Background(), "helloCounter2").Result() zlog.Info("ping", zap.Int64("val", val), zap.Error(err)) return nil }) g.Go(func() error { hsetRes, err := rdb.HSet(context.Background(), "xyz", "def", 0).Result() zlog.Info("ping", zap.Int64("setRes", hsetRes), zap.Error(err)) return nil }) c.JSON(http.StatusOK, gin.H{ "message": "pong", }) }) ...

January 10, 2024 · 2 min

使用Skywalking-go自动进行监控增强

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1. 引言 使用Skywalking-go,我们可以基于Golang build提供的-toolexec参数,实现了编译期劫持,达到在对代码几乎无侵入的情况下,实现埋点。 Skywalking对大量的框架(比如: gin)提供了支持, 然后这种支持仅限于增加了tracing信息。我们知道完整的监控往往离不开3个重要部分Metrics、Tracing、Logging。那些需要埋点的位置,往往这3种信息都是需要的,是否可以修改Skywalking-go,来达到代码增强的过程同时添加Metrics、Tracing、Logging呢?答案是肯定的。 本文的代码可参考 1)改动后的Skywalking-go vearne/skywalking-go 注意: 如果读者有自己改动的计划,建议好好阅读官方文档,并参考萌叔的改动代码 git diff f9929c6c9275b12f70ec2368544244f27a92f768 2) 测试项目 vearne/sw-test 2.解决问题 2.1 Tracing tracing保持不变 2.2 Logging Skywalking默认提供了对zap、logrus的劫持,因此可以直接在插件对应的拦截器中增加对应的日志即可 intercepter.go package gin import ( "fmt" "github.com/gin-gonic/gin" // 需要增加的import "github.com/apache/skywalking-go/plugins/core/log" "github.com/apache/skywalking-go/plugins/core/operator" "github.com/apache/skywalking-go/plugins/core/prom" "github.com/apache/skywalking-go/plugins/core/tracing" ) type HTTPInterceptor struct { } ... func (h *HTTPInterceptor) AfterInvoke(invocation operator.Invocation, result ...interface{}) error { ... // add logging log.Infof("url:%v", context.Request.URL.Path) ... return nil } 经过上述改动以后,插件拦截器新增的日志,也会输出到和业务日志相同的位置 ...

January 8, 2024 · 3 min

玩转CONSUL(6)–consul读写分离方案

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1. 引言 在萌叔之前的文章里,我曾经提到过使用consul进行注册和发现的时候,consul agent默认情况下,只会转发watch请求,所以负载最终还是会施加在consul server上。 为了解决这个问题,有如下几种方案: 1.1 降低watch的频率 1.1.1 增加wait参数的值 1.1.2 打开consul agent的cache功能 不过使用consul agent的cache可能导致在一个很短的时间窗口数据不一致 1.1.3 在watch请求返回之后,增加sleep 同1.1.2 在很短的时间窗口,数据可能不一致 1.2 增强Consul Server的处理能力 官方推荐Consul Server硬件配置,可以达到816核,内存可以达到3264GB 1.3 增加Consul Server的数量 官方推荐的Consul Server的数量一般不超过5个。增加Consul Server的数量,确实可以提高整个集群的读请求的负载能力,但是由于Server数量增多,达成共识的速度可能会下降,也就是说,可能会影响写能力。 1.4 Enterprise feature: enhanced read scalability Read-heavy clusters (e.g. high RPC call rate, heavy DNS usage, etc.) will generally be bound by CPU and may take advantage of the read replicas Enterprise feature for improved scalability. This feature allows additional Consul servers to be introduced as non-voters. As a non-voter, the server will still participate in data replication, but it will not block the leader from committing log entries. Additional information can be found in the Server Performance section of the Consul product documentation. ...

December 18, 2023 · 1 min

apache/skywalking-go 源码分析

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc apache/skywalking-go 源码分析 参考资料 1.劫持 Golang 编译 2.SkyWalking Go Agent 快速开始指南 3.support-plugins 4.Hybrid Compilation 5.Key Principle 6.通过SkyWalking上报Go应用数据 1. 前言 Skywalking是什么? Skywalking 是一个开源的应用性能监控工具,它专注于分布式系统架构中的性能监控和故障排查。 它能够跟踪分布式系统中的请求流,并提供实时的性能指标、调用链追踪、错误分析等功能。 使用 Skywalking 可以帮助开发人员和运维团队更好地理解应用程序的性能特征, 并快速定位和解决潜在的性能问题和故障。 几年前,当我最开始知道Skywalking的时候,它似乎只支持Java,它给我的最大的惊喜时,是直接使用字节码注入的方式来实现埋点, 减少开发人员埋点的工作量,且代码几乎无侵入。 2023年上半年,Skywalking推出一个全新的Go Agent skywalking-go。 它基于Golang build提供的-toolexec参数,实现了编译期劫持,也达到了在对代码几乎无侵入的情况下,实现埋点。 截止2023年12月1日,已经有大量的库得到了支持。参看support-plugins 日志库 zap、logrus 数据库Client gorm、sql HTTP Server gin、http HTTP Client http RPC框架 gRPC 它是如何做到代码几乎无入侵埋点的呢?本文试图解答这个问题 2. skywalking-go实现埋点 关于skywalking-go的使用参看SkyWalking Go Agent 快速开始指南 skywalking-go实现埋点主要依靠在golang build编译阶段的编译劫持。 go build -toolexec="/myopt/bin/skywalking-go-agent" -x -work -a -o test . 这里我们增加了2个额外参数 -x:这个标志告诉 Go 打印它执行的命令。 -work:这个标志告诉 Go 打印临时工作目录的名称,并在退出时不删除它。 ...

December 4, 2023 · 3 min

docker buildx 设置insecure registry

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 警告:本文仅用于萌叔自己总结之用,对其它人而言可能毫无营养,没有阅读价值。 1.前言 使用docker buildx 可以在一次build中生成支持多个平台的image。但在推动给私有仓库时,报"x509: certificate signed by unknown authority"。经过确认是,私有仓库使用的证书是自签名证书,导致SSL握手失败导致的。 2. 解决 docker buildx使用的builder配置方式与docker配置方式不同,需要在创建builder时,即指定 1) 创建配置文件 cat <<EOF > ./config.toml debug = true # root is where all buildkit state is stored. root = "/var/lib/buildkit" # insecure-entitlements allows insecure entitlements, disabled by default. insecure-entitlements = [ "network.host", "security.insecure"] [registry."my-registry.abc.local"] http = true insecure = true EOF 2) 创建builder 指定以./config.toml作为mybuilder的配置文件 docker buildx create --use --name=mybuilder —-config=./config.toml --bootstrap --bootstrap 表示启动builder ...

November 9, 2023 · 1 min

k8s分享

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 参考资料 1.技术分享:Kubernetes Networking Model 2.万字长文,带你搞懂 Kubernetes 网络模型 3.使用kubeadm搭建k8s集群 4.k8s的kubectl源码解析 5.Kubernetes–Service负载均衡机制 6.Kube Controller Manager 源码分析 7.k8s源码-scheduler流程深度剖析 8.kubectl 创建 Pod 背后到底发生了什么? 9.源码解析:一文读懂 Kubelet 10.kube-proxy源码分析:深入浅出理解k8s的services工作原理 本文基于k8s v1.28.2 大纲 1. k8s的架构 2. k8s的基本工作流程 3. k8s网络模型 4. k8s使用小贴士 1. k8s架构 1.1 架构图 HTTP/GRPC接口一般配有SSL的双向认证(使用自签名的根证书) kube-apiserver etcd kube-apiserver处于核心地位,其它组件通过它实现了解耦,其作用相当于看板 kube-apiserver也可以做高可用,比如使用负载均衡器(Load Balancer)来分发流量到多个kube-apiserver实例 扩展点 CNI 网络 CSI 存储 CRI container runtime Operator(CRD + controller) k8s可以独立于container runtime进行升级 1.2 组件 1.2.1 控制平面 1) kube-apiserver 组件负责公开 Kubernetes API,负责处理接受请求的工作。 ...

November 8, 2023 · 2 min