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

使用net-byte/vtun搭建VPN服务

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1.前言 萌叔发现了一个新库net-byte/vtun vtun可以用来快速部署VPN服务,代码粗略看了下,原理非常简单,就是利用隧道技术来实现的。 2.隧道技术原理图 vtun server通常暴露在公网中,这样客户端可以方便的接入 vtun-client在Client上创建了虚拟网卡tun0 在Client中的用户进程看来,它的流量都是发给tun0,但是实际上它的流量都被vtun-client捕获,从eth0发给vtun-server vtun-server所在Server开启了内核转发功能,因此可以转发给局域网中的其它实例 3.实验 我用青云的虚拟机构建了一个网络环境 vtun-server部署在青云的虚拟机上,IP地址为172.16.1.2, 测试机地址为172.16.3.2, 这2台机器位于2个不同的网段 测试机(IP: 172.16.3.2) 上部署了web服务,端口为8080 vtun-client部署在腾讯云的虚拟机上(用vtun创建虚拟网卡,配置IP为172.16.5.10) 172.16.0.0/24、172.16.1.0/24和172.16.3.0/24 通过路由器连接在一起 验证方式 在腾讯云的虚拟机上,ping 青云的测试机(172.16.3.2) 在腾讯云的虚拟机上,请求青云的测试机(172.16.3.2)上的web服务 3.1 部署 注意: 请自行修改密码 3.1.1 在Server上执行 1) 启动vtun server nohup vtun-linux-amd64 -p tcp -S -l :27080 -c 172.16.5.1/24 -k {password} & 注意:萌叔这里使用的网段172.16.5.1/24 与之前的172.16.1.0/24和172.16.3.0/24均不在一个网段 server上创建了虚拟网卡 tun0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST> mtu 1500 inet 172.16.5.1 netmask 255.255.255.0 destination 172.16.5.1 inet6 fced:9999::9999 prefixlen 64 scopeid 0x0<global> inet6 fe80::ab1f:1f20:fec5:78b prefixlen 64 scopeid 0x20<link> unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 500 (未指定) RX packets 52 bytes 3162 (3.1 KB) RX errors 0 dropped 0 overruns 0 frame 0 TX packets 33 bytes 3961 (3.9 KB) TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0 这个虚拟网卡使用的驱动明显与其它网卡不同 ...

September 6, 2023 · 2 min