OpenTelemetry个性化采样-根据特定Header决定是否采样

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 建议阅读,萌叔2024年的文章 OpenTelemetry原理及实战 1.前言 统一术语: 采样: sample,在OpenTelemetry的语境下,是指收集tracing(包含span)信息,并上报 对于订单类的服务而言,由于服务特别重要,QPS不高,全量采样问题不大。 但是对于内容型的服务,比如微博、抖音服务,这类读多写少的服务,全量采样成本巨大, 不仅不现实,也没有必要。此时当然可以考虑按照百分比采样, 另一种更为保守的做法,只收集异常的请求(客户端收集,指标告警,客服报障),进行流量重放, 并同时采集tracing信息。 2.根据特定Header决定是否采样 这时候我们需要特定的标识表明这个请求需要强制采样。 以HTTP请求为例,可以给定特殊的Header X-Force-Trace: 1 2.1 上游服务 OpenTelemetry的SDK预留了Sampler接口,用于定义个性化的采样需求(是否采样) // Sampler decides whether a trace should be sampled and exported. type Sampler interface { // DO NOT CHANGE: any modification will not be backwards compatible and // must never be done outside of a new major release. // ShouldSample returns a SamplingResult based on a decision made from the // passed parameters. ShouldSample(parameters SamplingParameters) SamplingResult // DO NOT CHANGE: any modification will not be backwards compatible and // must never be done outside of a new major release. // Description returns information describing the Sampler. Description() string // DO NOT CHANGE: any modification will not be backwards compatible and // must never be done outside of a new major release. } 完整代码见 vearne/otel-test ...

December 11, 2025 · 3 min

一个自动化测试框架 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

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

玩转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

由grafana-image-renderer引出的一个问题

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1.引言 前段时间利用grafana/grafana-image-renderer 做了一个自动截图服务。 见萌叔的文章抓取GRAFANA PANEL视图。但是我发现了一个问题(grafana版本v6.0.1),如果grafana的实例数量超过1个,在grafana中访问grafana render link时,就会有一定的概率失败,图片无法成功渲染。这到底是是为什么? 本文将给出完整的问题排查和解决过程,希望读者可以从中汲取一些养分,为以后排查其它问题提供一些思路。 2. 日志,一切从日志开始 看到这种问题,首先看看日志中是否有线索 2.1 首先看grafana的日志 只能了解到点击grafana render link之后,会触发一个GET请求,访问grafana服务的 /render/d-solo/P3a2p0cZz/redis-and-mysql-and-cache,然后引起一个内部错误 2.2 看看grafana-image-renderer的日志 我们已经知道,图片渲染的过程,grafana要调用grafana-image-renderer,让我们来看下grafana-image-renderer的日志。 需要注意,grafana-image-renderer的日志默认是打印在标准输出和标准错误输出里的。 对比成功和失败的case我发现,在失败的case中,日志中会多了一条401 (Unauthorized)的日志 对应的链接,就是我们要渲染成图片的panel所对应的网页地址 猜测1 现在我们可以猜测grafana-image-renderer可能是请求grafana服务对应的网页资源失败,然后导致图片渲染失败。 2.3 抓包,需要API入口 2.3.1 对grafana-image-renderer抓包 为了进一步验证这个上面的猜测,抓包看一下,grafana-image-renderer所收到的请求 萌叔抓包使用的是buger/goreplay ./gor --input-raw :8081 --output-stdout 1 1a1a5c7c2e733bf0ed41f7ce35bee28da845ab49 1616730655714291898 2541293 GET /render?domain=grafana.example.com&encoding=&height=500&renderKey=HPXorbVBhC6taLHFEe6Jg9O3e5w6R5xn&timeout=60&timezone=Asia%2FShanghai&url=http%3a%2f%2fgrafana.example.com%2fd-solo%2fP3a2p0cZz%2fredis-and-mysql-and-cache%3forgId%3d1%26from%3d1616719854090%26to%3d1616730654091%26var-instance%3d192.168.1.100%3a9090%26panelId%3d8%26width%3d1000%26height%3d500%26tz%3dAsia%2fShanghai%26render%3d1&width=1000 HTTP/1.1 X-Forwarded-Proto: http Host: grafana-image-renderer.example.com Connection: keep-alive User-Agent: Go-http-client/1.1 Accept-Encoding: gzip 展开来看 将url参数解码以后,确实就是grafana中panel对应的网页地址, 到这里猜测1,已经被证实了。 猜测2 请求的参数中有个renderKey非常的可疑,它会不会是请求grafana获取对应网页时,用来鉴权的token呢? 2.3.2 对grafana抓包 这里使用tcpdump抓取之后,然后用wireshark中观察 tcpdump -i eth0 host 192.168.1.102 and port 3000 -w /tmp/xxx.cap grafana-image-renderer请求grafana时,确实在Cookie中携带了renderkey。离真相越来越近了。 ...

March 26, 2021 · 3 min

抓取Grafana Panel视图

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1.引言 最近萌叔在做监控系统的改造,其中一个目标是,当Prometheus触发告警之后需要将Alert Rule对应的grafana图表以邮件的形式发送给处理人员。 2. grafana/grafana-image-renderer 经过搜索资料,萌叔发现grafana官方出了一个插件,可以直接用于抓取grafana的Panel图表。 传送门: grafana/grafana-image-renderer 它有2种运行方式 以grafana的插件方式运行 以外部服务的形式运行 这里以第2种方式展开。 2.1 docker模式运行 这个外部服务是一个nodejs的程序 node build/app.js server --config=config.json puppeteer很像,它接收一个URL地址作为参数,然后运行Headless Chrome,向目标地址发起请求,解析并渲染网页,最后截图。 Headless Chrome可以这样理解,无需显卡、显示器,Chrome以命令行程序的方式运行对网页的请求、渲染、截图等工作。详见参考资料4 Grafana官方提供了docker镜像 grafana/grafana-image-renderer 直接运行即可 2.2 Grafana配置 [rendering] # grafana image renderer服务地址 server_url = http://grafana-image-renderer.example.com:8081/render # grafana服务地址 callback_url = http://grafana.example.com:3000/ 3. 获取图片地址 点击share 蓝色区域是Panel的网页地址,红色区域是Panel的图片地址 图片地址形如: http://dev2:3000/render/d-solo/TBeJbKBmz/fake_service?refresh=1m&panelId=6&orgId=1&from=1611216312639&to=1611218112639&theme=dark&width=1000&height=500&tz=Asia%2FShanghai 注意: from、to参数可能需要修改 6小时图表 now-6h 至 now http://dev2:3000/render/d-solo/TBeJbKBmz/fake_service?refresh=1m&panelId=6&orgId=1&from=now-6h&to=now&theme=dark&width=1000&height=500&tz=Asia%2FShanghai 2天图表 now-2h 至 now http://dev2:3000/render/d-solo/TBeJbKBmz/fake_service?refresh=1m&panelId=6&orgId=1&from=now-2d&to=now&theme=dark&width=1000&height=500&tz=Asia%2FShanghai 4.总结 webhook服务只需要在alert被触发时,请求对应的图片地址,下载图片,再将图片打包在邮件中发送出来即可。 参考资料 puppeteer/puppeteer grafana/grafana-image-renderer Grafana Image Renderer headless chrome 请我喝瓶饮料

January 21, 2021 · 1 min

分布式任务调度平台xxl-job

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1.前言 xuxueli/xxl-job是一个分布式任务调度平台。它在github上有1w多个star,有多家公司都已经用在生产实践中。 在萌叔看来这是一个"Less is more"的典型。它的设计的非常简单,最大的优点是实用。 2.主要结构和逻辑 XXL-JOB任务调度平台分为2个部分,Scheduler和Executor。具体的实现Scheduler对应是xxl-job-admin,同时xxl-job-admin还配有web UI,可以配置管理任务。 Scheduler和Executor之间通过HTTP API交互,因此Executor可以通过各种语言实现。比如Golang的 xxl-job/xxl-job-executor-go 以上图为例,scheduleThread将任务通过Executor是的/run api推送给Executor { "jobId": 3, "executorHandler": "task.test", "executorParams": "x=100", "executorBlockStrategy": "SERIAL_EXECUTION", "executorTimeout": 0, "logId": 17, "logDateTime": 1606100913829, "glueType": "BEAN", "glueSource": "", "glueUpdatetime": 1606099566000, "broadcastIndex": 0, "broadcastTotal": 1 } Executor会根据executorHandler找到对应的handler,执行完之后,又会调用xxl-job-admin的/xxl-job-admin/api/callback回报任务的执行结果。从上面的描述我们可以知道,xxl-job-admin和excutor都必须暴露出api服务(都是HTTP接口)。 Scheduler可以有多个。它们之间通过MySQL进行同步。 主要的调度逻辑在JobScheduleHelper中 在每一轮执行调度逻辑之前, Scheduler必须先获得行锁 while (!scheduleThreadToStop) { ... // 加行锁 try { preparedStatement = conn.prepareStatement( "select * from xxl_job_lock where lock_name = 'schedule_lock' for update" ); preparedStatement.execute(); ... } catch (Exception e) { ... } finally { ... // 注意:锁必须正常释放 conn.commit(); ... } 由于xxl_job_lock 表中只有一条记录,所以这个逻辑与请求表锁类似,开销是比较大的。 ...

November 23, 2020 · 1 min

k8s学习笔记(1)-安装dashboard

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1. 前言 警告:本文仅用于萌叔自己总结之用,对其它人而言可能毫无营养,没有阅读价值。 Dashboard 是基于网页的 Kubernetes 用户界面。 你可以使用 Dashboard 将容器应用部署到 Kubernetes 集群中,也可以对容器应用排错,还能管理集群资源。 你可以使用 Dashboard 获取运行在集群中的应用的概览信息,也可以创建或者修改 Kubernetes 资源 (如 Deployment,Job,DaemonSet 等等)。 通过一段时间的使用感受而言,Dashboard虽然做的差强人意,但聊胜于无。 2. 安装&配置 wget https://raw.githubusercontent.com/kubernetes/dashboard/v2.0.4/aio/deploy/recommended.yaml 建议脚本下载以后,先大致阅读以下 2.1 修改yaml kind: Service apiVersion: v1 metadata: labels: k8s-app: kubernetes-dashboard name: kubernetes-dashboard namespace: kubernetes-dashboard spec: ports: - port: 443 targetPort: 8443 type: NodePort # 改为NodePort方式暴露service selector: k8s-app: kubernetes-dashboard 2.2 安装 kubectl apply -f recommended.yaml 安装完成以后 ╰─$ kubectl get svc -n kubernetes-dashboard NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE dashboard-metrics-scraper ClusterIP 10.68.53.228 <none> 8000/TCP 18h kubernetes-dashboard NodePort 10.68.254.87 <none> 443:37736/TCP 17h 3. 访问web UI 3.1 方式1 通过 kubectl proxy 默认K8S采用Flannel网络的模型的情况下,集群内部和外部网络是不能直接互联的,但是能够通过kubectl proxy作为代理,进行通讯 ...

October 12, 2020 · 2 min

玩转PROMETHEUS(6) 实现自定义的Collector

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1. 前言 prometheus的官方和社区为了我们提供了丰富的exporter。对常见的硬件设备、数据库、消息队列以及常见的软件进行监控。另外官方还为我们提供了4种指标类型方便我们自定义exporter Counter Counter代表累计指标,它表示单调递增的计数器,通常用于表示服务请求数,完成的任务数,错误的数量。 Gauge Gauge表示某种瞬时状态,某一时刻的内存使用率、消息队列中的消息数量等等。它的值既可以增大,也可以减小。 Histogram 通常用于top percentile,比如请求耗时的TP90、TP99等 Summary 类似于Histogram 我们回顾一下prometheus的指标采集的一般过程 1) 创建指标 HTTPReqTotal = prometheus.NewCounterVec(prometheus.CounterOpts{ Name: "http_requests_total", Help: "Total number of HTTP requests made.", }, []string{"method", "path", "status"}) 2) 指标注册到 DefaultRegisterer prometheus.MustRegister( HTTPReqTotal, ) 3) 指标和对应的值通过HTTP API暴露出来 The caller of the Gather method can then expose the gathered metrics in some way. Usually, the metrics are served via HTTP on the /metrics endpoint. ...

August 23, 2020 · 2 min

动态修改容器中的配置文件

版权声明 本站原创文章 由 萌叔 发表 转载请注明 萌叔 | http://vearne.cc 1. 引言 前段时间接手了一个前端项目。这个前端项目采用docker方式部署。有3套不同的环境,开发联调、测试、生产分别指向不同的后端API服务。 项目目录结构如下 ├── DockerfileDev ├── DockerfileProd ├── DockerfileTest ├── Makefile ├── README.md ├── config │ ├── api.dev.conf │ ├── api.prod.conf │ ├── api.test.conf │ └── nginx.conf ├── package.json ├── src ├── tsconfig.json └── yarn.lock config目录中是nginx相关的配置文件, 仅仅因为后端API服务地址不同,Dockerfile就有3个,对于开发联调、测试和生产环境的docker镜像也需要分别build,显然是非常低效的。 2. 改造 2.1 想法 最好的办法是在容器启动时,使用环境变量传入,动态修改nginx配置文件。 2.2 envsubst 查阅资料,发现一个shell命令 envsubst substitutes environment variables in shell format strings 它可以替换shell字符串中的环境变量 用法大致如下 root@i-bf77szgn:~# export API_HOST=vearne.com root@i-bf77szgn:~# echo "hello ${API_HOST}" | envsubst hello vearne.com 2.3 精简代码 在这种情况下,web.dev.conf、web.test.conf、web.prod.conf合并成一个文件default.template,通过环境变量传入后端API服务地址 ...

March 21, 2020 · 1 min