OpenTelemetry系列 - 第4篇 OpenTelemetry K8S生态

目录

    • 一、【Helm】添加OTel Helm repo
    • 二、【Helm Chart】OTel Collector
      • 2.1 daemonset
      • 2.2 deloyment
    • 三、【K8S Operator】OTel Operator
      • 3.1 安装OTel Operator
      • 3.2 部署OpenTelemetryCollector
        • 3.2.1 Deloyment Mode
        • 3.2.2 DeamonSet Mode
        • 3.2.3 StatefulSetMode
        • 3.2.4 Sidecar Mode
      • 3.3 部署Instrumentation - 配置应用端自动注入OTel Agent
        • 3.3.1 全局配置Instrumentation
        • 3.3.2 工作负载通过annotation启用自动注入
        • 3.3.3 Pod内多个container注入
        • 3.3.4 Java Pod自动注入
        • 3.3.5 剔除/actuator/health

一、【Helm】添加OTel Helm repo

helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-charts
helm repo update

二、【Helm Chart】OTel Collector

收集器可以部署为以下四种模式之一:

  • deployment(默认)
  • daemonSet
  • statefulSet

默认模式为deployment。

helm install otel-collector open-telemetry/opentelemetry-collector \
--set mode=<value>
helm install otel-collector open-telemetry/opentelemetry-collector \
--values <path where you saved the chart>

2.1 daemonset

部署OpenTelemetry Collector的daemonset实例,以收集节点(node)和运行在这些节点上的工作负载(workloads)相关的遥测数据(telemetry)。使用daementset来保证在所有节点上都安装了这个收集器实例。daemenset收集器的每个实例将只从其运行的节点收集数据。

收集器的实例将使用以下组件:

  • OTLP Receiver:收集应用程序跟踪、度量和日志。
  • Kubernetes Attributes Processor:将Kubernetes元数据添加到传入的应用遥测中。
  • Kubeletstats Receiver:从kubelet上的API服务器提取节点、pod和容器指标。
  • Filelog Receiver:用于收集写入stdout/stderr的Kubernetes日志和应用程序日志(/var/log/pods/*/*/*.log)。

values-for-daemonset.yaml:

mode: daemonsetpresets:# enables the k8sattributesprocessor and adds it to the traces, metrics, and logs pipelineskubernetesAttributes:enabled: true# enables the kubeletstatsreceiver and adds it to the metrics pipelineskubeletMetrics:enabled: true# Enables the filelogreceiver and adds it to the logs pipelineslogsCollection:enabled: true
## The chart only includes the loggingexporter by default
## If you want to send your data somewhere you need to
## configure an exporter, such as the otlpexporter
# config:
# exporters:
#   otlp:
#     endpoint: "<SOME BACKEND>"
# service:
#   pipelines:
#     traces:
#       exporters: [ otlp ]
#     metrics:
#       exporters: [ otlp ]
#     logs:
#       exporters: [ otlp ]

2.2 deloyment

部署Collector的deloyment实例,以收集与整个集群相关的遥测数据。只有一个副本的部署确保我们不会产生重复的数据。

收集器的实例将使用以下组件:

  • Kubernetes Cluster Receiver:收集集群级指标和实体事件。
  • Kubernetes Objects Receiver:从Kubernetes API服务器收集对象,例如events。

values-for-deloyment

mode: deployment# We only want one of these collectors - any more and we'd produce duplicate data
replicaCount: 1presets:# enables the k8sclusterreceiver and adds it to the metrics pipelinesclusterMetrics:enabled: true# enables the k8sobjectsreceiver to collect events only and adds it to the logs pipelineskubernetesEvents:enabled: true
## The chart only includes the loggingexporter by default
## If you want to send your data somewhere you need to
## configure an exporter, such as the otlpexporter
# config:
# exporters:
#   otlp:
#     endpoint: "<SOME BACKEND>"
# service:
#   pipelines:
#     traces:
#       exporters: [ otlp ]
#     metrics:
#       exporters: [ otlp ]
#     logs:
#       exporters: [ otlp ]

三、【K8S Operator】OTel Operator

OTel K8S整体架构:
在这里插入图片描述

3.1 安装OTel Operator

$ helm install \
--set admissionWebhooks.certManager.enabled=false \
--set admissionWebhooks.certManager.autoGenerateCert=true \
opentelemetry-operator open-telemetry/opentelemetry-operator
helm uninstall opentelemetry-operator

收集器可以部署为以下四种模式之一:

  • deployment(默认)
  • daemonSet
  • statefulSet
  • sidecar

默认模式为deployment。

3.2 部署OpenTelemetryCollector

3.2.1 Deloyment Mode

独立部署、运维Collector,方便scale、回滚版本。

$ kubectl apply -f - <<EOF
apiVersion: opentelemetry.io/v1alpha1
kind: OpenTelemetryCollector
metadata:name: my-collector
spec:mode: deployment # This configuration is omittable.config: |receivers:jaeger:protocols:grpc:processors:exporters:debug:service:pipelines:traces:receivers: [jaeger]processors: []exporters: [debug]
EOF
3.2.2 DeamonSet Mode

作为DaemonSet运行Collector于每个K8s Node之上,收集Node上pod信息。

$ kubectl apply -f - <<EOF
apiVersion: opentelemetry.io/v1alpha1
kind: OpenTelemetryCollector
metadata:name: my-collector
spec:mode: daemonsethostNetwork: trueconfig: |receivers:jaeger:protocols:grpc:processors:exporters:debug:verbosity: detailedservice:pipelines:traces:receivers: [jaeger]processors: []exporters: [debug]
EOF
3.2.3 StatefulSetMode

将Collector部署为StatefulSet基本上有三个主要优势:

  • Collector实例的name可预测
    如果使用上述两种方法来部署Collector,则Collector实例的pod名称将是唯一的(它的名称加上随机序列)。但是,statfulset中的每个Pod都从statfulset的名称和Pod的序号(my-col-0、my-col-1、my-col-2等)中派生其主机名。
  • 当Collector副本失败时,将安排重新调度
    如果Collector pod在StatefulSet中失败,Kubernetes将尝试重新调度具有相同名称的新pod到同一节点。Kubernetes也会尝试将相同的粘性身份(例如volumnes)附加到新的pod上。
$ kubectl apply -f - <<EOF
apiVersion: opentelemetry.io/v1alpha1
kind: OpenTelemetryCollector
metadata:name: my-collector
spec:mode: statefulsetreplicas: 3config: |receivers:jaeger:protocols:grpc:processors:exporters:debug:service:pipelines:traces:receivers: [jaeger]processors: []exporters: [debug]
EOF
3.2.4 Sidecar Mode

将Collector作为sidecar注入Pod中,
sidecar模式的最大优点是,它允许人们尽可能快速、可靠地从应用程序中卸载遥测数据。这个Collector实例将在容器级别上工作,不会创建新的pod,这对于保持Kubernetes集群的整洁和易于管理是完美的。此外,当您希望使用不同的收集/导出策略时,还可以使用sidecar模式,这正好适合此应用程序。
一旦Collector Sidecar实例存在于给定的名称空间中,您就可以从该名称空间为deployment注入sidecar(以下2种方式任选1种即可):

  • 为Deployment添加annontation - sidecar.opentelemetry.io/inject: true
  • 为Namespace添加annontation - sidecar.opentelemetry.io/inject: true
$ kubectl apply -f - <<EOF
apiVersion: opentelemetry.io/v1alpha1
kind: OpenTelemetryCollector
metadata:name: sidecar-for-my-app
spec:mode: sidecarconfig: |receivers:jaeger:protocols:thrift_compact:processors:exporters:debug:service:pipelines:traces:receivers: [jaeger]processors: []exporters: [debug]
EOF
$ kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:name: my-applabels:app: my-app
spec:selector:matchLabels:app: my-appreplicas: 1template:metadata:labels:app: my-appannotations:sidecar.opentelemetry.io/inject: "true" # CORRECTspec:containers:- name: myappimage: jaegertracing/vertx-create-span:operator-e2e-testsports:- containerPort: 8080protocol: TCP
EOF

3.3 部署Instrumentation - 配置应用端自动注入OTel Agent

operator可以注入和配置OpenTelemetry自动注入agent。目前支持:

  • Apache HTTPD
  • DotNet
  • Go
  • Java
  • Nginx
  • NodeJS
  • Python
3.3.1 全局配置Instrumentation
kubectl apply -f - <<EOF
apiVersion: opentelemetry.io/v1alpha1
kind: Instrumentation
metadata:name: my-instrumentation
spec:exporter:endpoint: http://otel-collector:4317propagators:- tracecontext- baggage- b3sampler:type: parentbased_traceidratioargument: "0.25"python:env:# Required if endpoint is set to 4317.# Python autoinstrumentation uses http/proto by default# so data must be sent to 4318 instead of 4317.- name: OTEL_EXPORTER_OTLP_ENDPOINTvalue: http://otel-collector:4318dotnet:env:# Required if endpoint is set to 4317.# Dotnet autoinstrumentation uses http/proto by default# See https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/blob/888e2cd216c77d12e56b54ee91dafbc4e7452a52/docs/config.md#otlp- name: OTEL_EXPORTER_OTLP_ENDPOINTvalue: http://otel-collector:4318go:env:# Required if endpoint is set to 4317.# Go autoinstrumentation uses http/proto by default# so data must be sent to 4318 instead of 4317.- name: OTEL_EXPORTER_OTLP_ENDPOINTvalue: http://otel-collector:4318
EOF

以上部署成功的CR Instrumentation可以通过如下命令查询:

kubectl get otelinst.
3.3.2 工作负载通过annotation启用自动注入

通过添加annotation启动自动注入:

  • 向pod添加annotation以启用注入
  • 将annotation添加到namespace中,以便该名称空间中的所有pod都将获得检测
  • 将annotation添加到单独的PodSpec对象中,这些对象可以作为Deployment、Statefulset和其他资源的一部分使用

Java:

instrumentation.opentelemetry.io/inject-java: "true"
# 注入到指定的container中(适用于一个Pod中有多个container)
# 如不指定则默认注入到第一个container中,
# 可通过此配置避免向istio-proxy中注入
instrumentation.opentelemetry.io/container-names: "myapp,myapp2"

NodeJS:

instrumentation.opentelemetry.io/inject-nodejs: "true"

Python:

instrumentation.opentelemetry.io/inject-python: "true"

.NET:

.NET auto-instrumentation also honors an annotation that will be used to set the .NET Runtime Identifiers(RIDs). Currently, only two RIDs are supported: linux-x64 and linux-musl-x64. By default linux-x64 is used.

instrumentation.opentelemetry.io/inject-dotnet: "true"
instrumentation.opentelemetry.io/otel-dotnet-auto-runtime: "linux-x64" # for Linux glibc based images, this is default value and can be omitted
instrumentation.opentelemetry.io/otel-dotnet-auto-runtime: "linux-musl-x64"  # for Linux musl based images

Go:

Go auto-instrumentation also honors an annotation that will be used to set the OTEL_GO_AUTO_TARGET_EXE env var. This env var can also be set via the Instrumentation resource, with the annotation taking precedence. Since Go auto-instrumentation requires OTEL_GO_AUTO_TARGET_EXE to be set, you must supply a valid executable path via the annotation or the Instrumentation resource. Failure to set this value causes instrumentation injection to abort, leaving the original pod unchanged.

instrumentation.opentelemetry.io/inject-go: "true"
instrumentation.opentelemetry.io/otel-go-auto-target-exe: "/path/to/container/executable"

Go auto-instrumentation also requires elevated permissions. The below permissions are set automatically and are required.

securityContext:privileged: truerunAsUser: 0

Apache HTTPD:

instrumentation.opentelemetry.io/inject-apache-httpd: "true"

Nginx:

instrumentation.opentelemetry.io/inject-nginx: "true"

OpenTelemetry SDK environment variables only:

instrumentation.opentelemetry.io/inject-sdk: "true"

可选值:

  • true - inject and Instrumentation resource from the namespace.
  • my-instrumentation - name of Instrumentation CR instance in the current namespace.
  • my-other-namespace/my-instrumentation - name and namespace of Instrumentation CR instance in another namespace.
  • false - do not inject
3.3.3 Pod内多个container注入
apiVersion: apps/v1
kind: Deployment
metadata:name: my-deployment-with-multi-containers-multi-instrumentations
spec:selector:matchLabels:app: my-pod-with-multi-containers-multi-instrumentationsreplicas: 1template:metadata:labels:app: my-pod-with-multi-containers-multi-instrumentationsannotations:instrumentation.opentelemetry.io/inject-java: "true"instrumentation.opentelemetry.io/java-container-names: "myapp,myapp2"instrumentation.opentelemetry.io/inject-python: "true"instrumentation.opentelemetry.io/python-container-names: "myapp3"spec:containers:- name: myappimage: myImage1- name: myapp2image: myImage2- name: myapp3image: myImage3
3.3.4 Java Pod自动注入

Java Pod被OTel自动注入后,Pod定义被修改如下:

apiVersion: v1
kind: Pod
metadata:labels:app: app-atomversion: v1name: app-atom-6c97b8dd84-mw222namespace: otel-poc
spec:containers:- env:- name: SPRING_OUTPUT_ANSI_ENABLEDvalue: NEVER- name: LOGGING_CONFIGvalue: /config/logback-spring.xml- name: JAVA_TOOL_OPTIONSvalue: ' -javaagent:/otel-auto-instrumentation-java/javaagent.jar'- name: OTEL_SERVICE_NAMEvalue: app-atom- name: OTEL_EXPORTER_OTLP_ENDPOINTvalue: http://otel-collector.opentelemetry-operator-system.svc.cluster.local:4317- name: OTEL_RESOURCE_ATTRIBUTES_POD_NAMEvalueFrom:fieldRef:apiVersion: v1fieldPath: metadata.name- name: OTEL_RESOURCE_ATTRIBUTES_NODE_NAMEvalueFrom:fieldRef:apiVersion: v1fieldPath: spec.nodeName- name: OTEL_PROPAGATORSvalue: tracecontext,baggage,b3- name: OTEL_TRACES_SAMPLERvalue: parentbased_traceidratio- name: OTEL_TRACES_SAMPLER_ARGvalue: "0.25"- name: OTEL_RESOURCE_ATTRIBUTESvalue: k8s.container.name=app-atom,k8s.deployment.name=app-atom,k8s.namespace.name=otel-poc,k8s.node.name=$(OTEL_RESOURCE_ATTRIBUTES_NODE_NAME),k8s.pod.name=$(OTEL_RESOURCE_ATTRIBUTES_POD_NAME),k8s.replicaset.name=app-atom-6c97b8dd84,service.version=latestimage: otel-poc/app-atom:latestimagePullPolicy: IfNotPresentlivenessProbe:failureThreshold: 3httpGet:path: /actuator/healthport: 8080scheme: HTTPinitialDelaySeconds: 60periodSeconds: 10successThreshold: 1timeoutSeconds: 5name: app-atomports:- containerPort: 8080name: httpprotocol: TCP- containerPort: 9999name: http-xxljobprotocol: TCPreadinessProbe:failureThreshold: 3httpGet:path: /actuator/healthport: 8080scheme: HTTPinitialDelaySeconds: 60periodSeconds: 10successThreshold: 1timeoutSeconds: 5resources:limits:cpu: "1"memory: 1000Mirequests:cpu: 10mmemory: 128MiterminationMessagePath: /dev/termination-logterminationMessagePolicy: FilevolumeMounts:- mountPath: /config/name: app-config- mountPath: /var/run/secrets/kubernetes.io/serviceaccountname: kube-api-access-vxx27readOnly: true- mountPath: /otel-auto-instrumentation-javaname: opentelemetry-auto-instrumentation-javadnsPolicy: ClusterFirstenableServiceLinks: trueinitContainers:- command:- cp- /javaagent.jar- /otel-auto-instrumentation-java/javaagent.jarimage: ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-java:231128imagePullPolicy: IfNotPresentname: opentelemetry-auto-instrumentation-javaresources:limits:cpu: 500mmemory: 64Mirequests:cpu: 50mmemory: 64MiterminationMessagePath: /dev/termination-logterminationMessagePolicy: FilevolumeMounts:- mountPath: /otel-auto-instrumentation-javaname: opentelemetry-auto-instrumentation-java- mountPath: /var/run/secrets/kubernetes.io/serviceaccountname: kube-api-access-vxx27readOnly: truenodeName: k-node1preemptionPolicy: PreemptLowerPrioritypriority: 0restartPolicy: AlwaysschedulerName: default-schedulersecurityContext: {}serviceAccount: defaultserviceAccountName: defaultterminationGracePeriodSeconds: 30tolerations:- effect: NoExecutekey: node.kubernetes.io/not-readyoperator: ExiststolerationSeconds: 300- effect: NoExecutekey: node.kubernetes.io/unreachableoperator: ExiststolerationSeconds: 300volumes:- configMap:defaultMode: 420name: app-atomname: app-config- name: kube-api-access-vxx27projected:defaultMode: 420sources:- serviceAccountToken:expirationSeconds: 3607path: token- configMap:items:- key: ca.crtpath: ca.crtname: kube-root-ca.crt- downwardAPI:items:- fieldRef:apiVersion: v1fieldPath: metadata.namespacepath: namespace- emptyDir:sizeLimit: 200Miname: opentelemetry-auto-instrumentation-java
3.3.5 剔除/actuator/health

https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/1060
在这里插入图片描述


参考:
https://opentelemetry.io/docs/kubernetes/
https://opentelemetry.io/docs/kubernetes/operator/
https://github.com/open-telemetry/opentelemetry-helm-charts
https://github.com/open-telemetry/opentelemetry-operator
阿里技术 - 深入浅出eBPF|你要了解的7个核心问题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/198997.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

RocketMq原理(待完善)

MQ作用 异步解耦削峰 RocketMQ背景 ​ RocketMQ是阿里巴巴开源的一个消息中间件&#xff0c;在阿里内部历经了双十一等很多高并发场景的考验&#xff0c;能够处理亿万级别的消息。2016年开源后捐赠给Apache&#xff0c;现在是Apache的一个顶级项目。 ​ 早期阿里使用ActiveM…

基于SUMO和强化学习的交通优化

本文旨在解释强化学习方法如何通过 TraCl 与 SUMO 配合使用&#xff0c;以及这如何有利于城市交通管理和自动驾驶车辆的路径优化。 NSDT工具推荐&#xff1a; Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器 - REV…

Node包管理工具 - nvm、npm、yarn、cnpm、pnpm

转载说明 原文地址 简介 nvm : 可以实现一台电脑&#xff0c;拥有多个版本的Node npm : node package manager 下载Node后自带的一个包管理工具 yarn : npm 的升级版&#xff0c;更优秀 cnpm : 配置下载非官方地址的依赖&#xff08;淘宝、华为、腾讯镜像&#xff09; pnpm :…

day70

今日回顾 session 中间件 auth session Cookie虽然在一定程度上解决了“保持状态”的需求&#xff0c;但是由于Cookie本身最大支持4096字节&#xff0c;以及Cookie本身保存在客户端&#xff0c;可能被拦截或窃取&#xff0c;因此就需要有一种新的东西&#xff0c;它能支持更…

辛普森距离(SD,Sampson Distance)

定义 Sampson误差是复杂性介于代数误差和几何误差之间&#xff0c;但非常近似于几何误差的一种误差。 应用 SLAM对极几何中使用到SD来筛选内点&#xff1a; 1.随机采样8对匹配点 2.8点法求解基础矩阵 ​&#xff1b; 3.奇异值约束获取基础矩阵F&#xff1b; 4.计算误差&…

4、单例模式(Singleton Pattern)

单例模式是保证系统实例唯一性的重要手段。单例模式首先通过将类的实例化方法私有化来防止程序通过其他方式创建该类的实例&#xff0c;然后通过提供一个全局唯一获取该类实例的方法帮助用户获取类的实例&#xff0c;用户只需也只能通过调用该方法获取类的实例。 单例模式的设…

通达信指标公式19:龙虎榜股票池——主力控盘度的计算方法

0.小红牛本指标&#xff0c;选股的思路说明&#xff1a;控盘度&#xff0c;又称主力控盘&#xff0c;是指主力控制了某只股票的大部分流通股&#xff0c;从而控制了股票的价格。主力控盘的目的通常是为了获取更多的收益&#xff0c;通过控制股票价格来实现其策略。所以首要分析…

(04730)电路分析基础之电阻、电容及电感元件

04730电子技术基础 语雀&#xff08;完全笔记&#xff09; 电阻元件、电感元件和电容元件的概念、伏安关系&#xff0c;以及功率分析是我们以后分析电 路的基础知识。 电阻元件 电阻及其与温度的关系 电阻 电阻元件是对电流呈现阻碍作用的耗能元件&#xff0c;例如灯泡、…

Hadoop学习笔记(HDP)-Part.04 基础环境配置

目录 Part.01 关于HDP Part.02 核心组件原理 Part.03 资源规划 Part.04 基础环境配置 Part.05 Yum源配置 Part.06 安装OracleJDK Part.07 安装MySQL Part.08 部署Ambari集群 Part.09 安装OpenLDAP Part.10 创建集群 Part.11 安装Kerberos Part.12 安装HDFS Part.13 安装Ranger …

外包干了2个月,技术倒退2年。。。。。

先说一下自己的情况&#xff0c;本科生&#xff0c;20年通过校招进入深圳某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年国庆&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…

现代版“田忌赛马”:IPMT如何实现资源利用最大化

摘要&#xff1a;在流程调整和产品重整过程中&#xff0c;IPMT发挥了至关重要的作用。IPMT是什么&#xff1f;它的职责到底是什么&#xff1f;每个公司必须要有IPMT吗&#xff1f; 1992年&#xff0c;IBM在激烈的市场竞争下&#xff0c;遭遇到了严重的财政困难&#xff0c;利润…

Mysql中RTRIM、LTRIM、TRIM函数的区别

一、概述 在MySQL中&#xff0c;LTRIM、RTRIM和TRIM是用于去除字符串两端空格或指定字符的函数&#xff0c;它们的区别如下&#xff1a; LTRIM()&#xff1a; LTRIM表示"Left Trim"&#xff0c;用于去除字符串左侧的空格或指定字符。语法&#xff1a;LTRIM(str) …

机器学习-ROC曲线:技术解析与实战应用

本文全面探讨了ROC曲线&#xff08;Receiver Operating Characteristic Curve&#xff09;的重要性和应用&#xff0c;从其历史背景、数学基础到Python实现以及关键评价指标。文章旨在提供一个深刻而全面的视角&#xff0c;以帮助您更好地理解和应用ROC曲线在模型评估中的作用。…

Java 多线程之 Semaphore(信号量/限流/同步辅助类)

文章目录 一、概述二、使用方法三、测试示例 一、概述 Semaphore&#xff08;信号量&#xff09;是一种并发控制机制&#xff0c;用于控制对共享资源的访问。它维护了一个计数器&#xff0c;可以限制同时访问某个资源的线程数量。常用于限制同时访问某个资源的线程数量&#xf…

MySQL查看和修改时区

为了验证 TIMESTAMP 存储时间与时区有关&#xff0c;显示的值也依赖于时区 看了mysql 时区 时间网 世界时区 MySQL查看和修改时区的方法 查看当前时区 1. 在MySQL客户端&#xff0c;可以通过如下命令查看当前时区&#xff1a; SELECT global.time_zone;2. 查看当前时区的设…

字符串方法

字符串方法 字符串截取slice() 字符串截取subString() 字符串截取substr() 字符串切割slice() 字符串开始start() 字符串结束end() 字符串去空trim() 字符串合并 concat() 字符串包含includes() 字符串下标 indexOf() 字符串倒序查…

【新手解答8】深入探索 C 语言:递归与循环的应用

C语言的相关问题解答 写在最前面问题&#xff1a;探索递归与循环在C语言中的应用解析现有代码分析整合循环示例代码修改注意事项结论 延伸&#xff1a;递归和循环的退出条件设置解析使用递归使用循环选择适合的方法 写在最前面 一位粉丝私信交流&#xff0c;回想起了当初的我C…

Zabbix HA高可用集群搭建

Zabbix HA高可用集群搭建 Zabbix HA高可用集群搭建一、Zabbix 高可用集群&#xff08;Zabbix HA&#xff09;二、部署Zabbix高可用集群1、两个服务端配置1.1主节点 Zabbix Server 配置1.2 备节点 Zabbix Server 配置1.3 主备节点添加监控主机1.4 查看高可用集群状态 2、两个客户…

【数据结构与算法】JavaScript实现二叉搜索树

文章目录 一、二叉搜索树的封装1.插入数据2.遍历数据2.1.先序遍历2.2.中序遍历2.3.后续遍历 3.查找数据3.1.查找最大值&最小值3.2.查找特定值 4.删除数据4.1.情况1&#xff1a;没有子节点4.2.情况2&#xff1a;有一个子节点4.3.情况3&#xff1a;有两个子节点4.4.完整实现 …

成为AI产品经理——回归模型评估(MSE、RMSE、MAE、R方)

分类问题的评估是看实际类别和预测类别是否一致&#xff0c;它的评估指标主要有混淆矩阵、AUC、KS。回归问题的评估是看实际值和预测值是否一致&#xff0c;它的评估指标包括MAE、MSE、RMSE、R方。 如果我们预测第二天某支股票的价格&#xff0c;给一个模型 y1.5x&#xff0c;…