Go微服务实战——服务的监控与链路追踪(监控数据可视化)

news2024/11/23 22:22:09

链路追踪背景

对于早期系统或者服务来说,开发人员一般通过打日志的方式来进行埋点(常用的数据采集方式),然后再根据日志系统和性能监控定位及分析问题。对于单体的应用通过日志系统完全可以定位到问题,从而排查异常。但是对于微服务来说,各个服务之前存在调用关系,服务之间是相互依赖的,一个服务异常可能其由于其他服务引起的,那么就需要查看和该服务相关联的其他服务的所有日志信息排查时那个服务引造成的。

随着服务数量的增多和内部调用链的复杂化,开发者仅凭借日志和性能监控,难以做到全局的监控,运维难度极大。为了解决这个问题,业界推出了分布式链路追踪组件。Google 内部开发了 Dapper 用于收集更多的复杂分布式系统的行为信息;同时,也有很多其他公司开发了自己的链路追踪组件Twitter 开源了分布式链路追踪组件 Zipkin等。

Dapper,大规模分布式系统的跟踪系统

服务监控应该至少包含如下的内容:

在这里插入图片描述

微服务 - 应用性能监测 · 链路追踪 · 概念规范 · 产品接入 · 方法级追踪 · 创建指标跨度

微服务 - Nginx网关 · 进程机制 · 限流熔断 · 性能优化 · 动态负载 · 高可用

分布式链路追踪

分布式链路追踪(Distributed Tracing)是一种用于监视和诊断分布式系统性能问题的技术。在大规模的分布式系统中,由于服务之间的复杂交互,单个请求可能会在多个服务之间传输,并涉及多个计算节点和数据存储。在这样的环境中,出现性能问题时,追踪问题的根本原因可能会非常困难。

分布式链路追踪通过在整个请求处理路径上添加唯一标识符,并记录请求在不同服务和组件之间的传输情况和时间戳,从而使开发人员能够跟踪请求的完整生命周期。当出现性能问题时,开发人员可以利用这些信息来确定瓶颈所在,优化系统性能。

常见的分布式链路追踪工具包括Zipkin、Jaeger和OpenTelemetry等。这些工具提供了可视化界面和分析工具,帮助开发人员更轻松地理解分布式系统的运行状况。

在dapper中介绍了Tracing 链路追踪是一种用于分析和监视应用程序的方法,尤其是那些使用微服务体系结构构建的分布式的应用程序。一个完整请求链路的追踪(TraceID)用于查出本次请求调用的所有服务/接口/组件等,调用的每个服务/接口/组件等都被称为跨度(Span),用来记录调用顺序,上游跨度(ParenetID)用来记录调用的层级关系。调用时间周期Timestamp,是把请求发出、接收、处理的时间都记录下来。跨度还可以记录一些其它属性信息,比如发起调用服务名称、被调服务名称、返回结果、IP、请求状态、日志、故障等。最后再把拥有相同(TraceID)的跨度(Span)合成一个更大范围的试图,就形成了一个完整的单次请求调用链。

这个概念都是Google Dapper论文中提出的:

在这里插入图片描述
Google-Dapper 是 Google 内部长期经过打磨后形成的产品,于2010年公布,对外是一篇论文,讲述的是分布式链路追踪的理论和 Dapper 的设计思想。大致由 [植入应用、收集跟踪数据、图形化UI] 三部分组成。后续市场的发展,有很多链路追踪系统也是基于 Dapper 论文的思想和理论为基础的。

通过统一服务监控追踪标准,OpenTracing 项目横空出世并得到开发者的认可,为分布式追踪,提供统一的概念、规范和接口。它是一个轻量级的标准化层,并不是功能实现代码,它只是为跟踪数据,用代码定义了一套数据模型,和一套API,是供统一遵循的规范,用于在应用程序中创建和管理这些数据模型。现在大多数链路跟踪产品系统都在尽量兼容遵循 OpenTracing 设计原则。

在这里插入图片描述

OpenTracing官方标准-中文版

opentracing

OpenTracing中文文档

OpenTracing 仅包含 Model 和 API 的定义,不会将产生的数据发送到第三方;需要进一步集成第三方的SDK,发送到第三方并呈现。

OpenTracing

OpenTracing通过提供平台无关、厂商无关的API,使得开发人员能够方便的添加(或更换)追踪系统的实现。

  • trace:race代表了一个事务或者流程在(分布式)系统中的执行过程
  • span: span表示一个调用,这个调用可以使一个方法,一个数据库,一个rpc服务等。

虽然分布式系统很复杂,但是使用OpenTracing让监控一个分布式调用过程简单化,并快速配置一个监控系统。

OpenTracing 有一套自己的一个 Library 库定义了一套通用的数据上报接口,要求各个分布式追踪系统都来实现这套接口。这样一来,应用程序只需要对接 OpenTracing,而无需关心后端采用的到底是什么分布式追踪系统,因此开发者可以无缝切换分布式追踪系统,也使得在通用代码库增加对分布式追踪的支持成为可能。

Twitter Zipkin是一款分布式链路追踪组件,由 Twitter 开源,同样也兼容 OpenTracing API:它基于 Google Dapper 的论文设计。

在这里插入图片描述
https://github.com/openzipkin

云原生链路监控组件 Uber Jaeger受 Dapper 和 OpenZipkin 的启发,由 Uber 开源的分布式追踪系统,兼容 Open Tracing API。它用于微服务的监控和排查,支持分布式上下文传播、分布式事务的监控、报错分析、服务的调用网络分析以及性能/延迟优化。Jaeger 的服务端使用 Go 语言实现。

Jaeger架构:

在这里插入图片描述

在这里插入图片描述

OpenTelemetry

基于 OpenTracing,新项目 OpenTelemetry 是 OpenTracing + OpenCensus 的产物,包含一组用于分布式跟踪和监视的工具的集合,支持集成更多的框架和语言。它仅用来生成/收集和导出更多种遥测数据(指标/链路/日志),可将数据发送到任何可观测性后端进行分析。旨在提供一种检测跟踪代码的标准方法,收集有关通过系统的请求流的数据,以帮助分析软件的性能和行为。同样,数据存储和可视化呈现留给其它工具去完成(如Jaeger、Prometheus)。

OpenTelemetry

OpenTelemetry GO API

OpenTelemetry GO API中文文档

概念

  1. 可观测性

可观测性使我们能够从外部了解一个系统,通过提出关于该系统的问题而无需了解其内部工作方式,因此应用程序代码必须发出诸如 信号 的东西,例如 跟踪、指标 和 日志,通过这些信号来观测系统。

日志是由服务或其他组件发出的带时间戳的消息。跨度表示一项工作或操作的单位。跟踪,记录了请求(由应用程序或最终用户发起)在多服务架构中传播时所经过的路径。为了使系统可观察,必须进行仪表化:也就是说,系统组件的代码必须发出跟踪、指标和日志。

如何生成跟踪,指标和日志呢,可以通过使用 OpenTelemetry API 进行手动仪表化,在特点的地方的生成。

配置OpenTelemetry API为了创建跟踪或跨度,你需要先创建一个tracer和/或meter provider。通常情况下,我们建议SDK应该为这些对象提供一个单一的默认provider。然后你将从该provider获取一个tracer或meter实例,跟踪和快读都是从这个实力创建。

如果你正在构建一个服务进程,你还需要使用适当的选项配置OpenTelemetr SDK,以将你的遥测数据导出到某个分析后端。

一旦你配置了API和SDK,你就可以自由地通过从provider中获取的tracer和meter对象创建跟踪和度量事件,创建遥测数据。

一旦你创建了遥测数据,你就需要将其发送到某个地方。OpenTelemetry支持从你的进程直接发送数据到分析后端的两种主要方法:直接从进程发送或通过OpenTelemetry Collector进行代理发送。

在这里插入图片描述

专业术语

OpenTelemetry API:在OpenTelemetry项目中,用于定义如何根据数据源生成遥测数据。

Exporter:提供将遥测数据传递给消费者的功能。由仪表化库和收集器使用。

Metric:(度量)将数据点记录为时间序列,包括原始测量值或预定义的聚合

OTel:OpenTelemetry的缩写。

OTelCol:OpenTelemetry Collector的缩写。

SDK:软件开发工具包的缩写。指实现OpenTelemetryAPI的遥测SDK的库。

Span:跨度,表示Trace内的单个操作。

Trace:跟踪,Span的DAG,其中Span之间的边被定义为父/子关系。

Tracer:跟踪器,负责创建Span。

在这里插入图片描述

使用两个开源项目:OpenTelemetryJaeger

OpenTelemetry 可以用于从应用程序收集数据。它是一组工具、API 和 SDK 集合,我们可以使用它们来检测、生成、收集和导出遥测数据(指标、日志和追踪),以帮助分析应用的性能和行为。

在这里插入图片描述
OpenTelemetry 提供了一个与供应商无关的可观测性标准,因为它旨在标准化跟踪的生成。通过 OpenTelemetry,我们可以将检测埋点与后端分离。这意味着我们不依赖于任何工具(或供应商)。

OpenTelemetry 为我们提供了创建跟踪数据的工具,为了获取这些数据,我们首先需要检测应用程序来收集数据。为此,我们需要使用 OpenTelemetry SDK。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
应用程序的遥测数据可以发送到 OpenTelemetry Collectors 收集器。

jaeger是用来可是监控的数据。

链路追踪实现

  1. 步骤

在OpenTelemetry中,将数据发送到指定的UI工具通常涉及以下几个步骤:

  • Instrumentation(仪表化):首先,你需要在你的应用程序中进行仪表化。这包括在代码中插入适当的代码以捕获关键事件和跟踪。这些事件可以是HTTP请求、数据库查询、函数调用等。OpenTelemetry提供了一系列语言库和框架的支持,使得在你的应用中添加仪表化变得相对简单。(基于OpenTelemetry API 和OpenTelemetry SDK实现)

  • 数据导出器(Exporters):OpenTelemetry提供了各种Exporter,用于将从应用程序中收集的跟踪数据、指标和日志发送到不同的目的地。你需要选择适合你用例的Exporter。例如,如果你想将数据发送到UI工具,你可能需要使用与该UI工具集成的Exporter,或者编写自定义的Exporter。

  • 配置Exporter:一旦选择了Exporter,你需要配置它,以确保数据被正确发送到UI工具。配置通常包括指定目标地址、端口、认证信息等。

  • 启动应用程序:最后,你需要启动你的应用程序,让它开始收集跟踪数据、指标和日志,并将其发送到UI工具。

  • 在UI工具中配置和查看数据:最终,在UI工具中配置数据源,并查看你的应用程序的跟踪数据、指标和日志。这可能涉及到在UI工具中创建仪表板或设置警报,以便监视应用程序的性能和健康状况。

  1. 安装jaeger ui工具

除了jaeger也可以选择其他工具。

在这里插入图片描述
jaeger官网

在jaeger中数据集采集的方式有两种jaeger-clientjaeger-agent前者是整合其他语言的SDK,后者是go语言专属的api,它们的实例将opentracingopentelemetry采集的数据发送到到jaeger-collector,再由jaeger-collector缓存存储到数据库中,最后jaeger-ui工具展示数据,jaeger-query数据查询数据。

jaeger提供了All in One一件安装jaeger所有的插件,参考官网

安装完之后输入地址http://localhost:16686如下所示:

在这里插入图片描述

Jeager官方文档翻译之——jeager架构(个人笔记)感谢作者Iron。

  1. 数据采集

jaeger-clientjaeger-agent发送数据是系统自动的,只需要开发者配置好otel-exporter即可,将其设置为otel-jaeger SDK的jaeger-exporter,这样系统会自动创建jaeger-client或者jaeger-agent向,远程jaeger-collector发送采集的信息。

现在到了关键的一部,采集程序信息,用于仪表化、生成、收集和导出诸如跟踪、度量、日志等遥测数据。

什么是OpenTelemetry?

Opentelemetry Traces数据模型介绍

otel-exporter

采集的信息需要发送到指定的collector才有意义,所以需要配置otel-exporter。各个框架都配置了exporter,例如jaeger-exporter等。

import "go.opentelemetry.io/otel/exporters/jaeger"
 
exp, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint("http://localhost:14268/api/traces")))
Tracer Provider

Tracer Provider是 Tracers 的工厂,在大多数应用程序中,Tracer Provider 会初始化一次,并且其生命周期与应用程序的生命周期相匹配。Tracer Provider 初始化还包括 Resource 和 Exporter 初始化。这通常是使用 OpenTelemetry 进行跟踪的第一步。在某些语言的 SDK 中,已经为您初始化了全局 Tracer Provider。

//设置Exporter,将Jaeger的exporter设置为otel的Exporter
// 返回以Jaeger为exporter的traceProvider
tp, tpErr := tracerprovicer.JaegerTraceProvider()
if tpErr != nil {
	log.Fatal(tpErr)
}
// 设置otel的provider
otel.SetTracerProvider(tp)
// 设置传播提取器
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))

Tracer Provider 初始化还包括 Resource 和 Exporter 初始化

Tracer Provider的初始化还有一部分在Tracer Exporter中。

Tracer Exporter

跟踪导出器将跟踪发送给消费者。该使用者可以是用于调试和开发时的标准输出、OpenTelemetry Collector 或您选择的任何开源或供应商后端。

package tracerprovicer

import (
	"go.opentelemetry.io/otel/exporters/jaeger"
	"go.opentelemetry.io/otel/sdk/resource"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
	semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
)

func JaegerTraceProvider() (*sdktrace.TracerProvider, error) {
	exp, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint("http://localhost:14268/api/traces")))
	if err != nil {
		return nil, err
	}
	tp := sdktrace.NewTracerProvider(
		sdktrace.WithBatcher(exp),
		sdktrace.WithResource(resource.NewWithAttributes(
			semconv.SchemaURL,
			semconv.ServiceNameKey.String("todo-service"),
			semconv.DeploymentEnvironmentKey.String("production"),
		)),
	)
	return tp, nil
}
Tracer

Tracer 创建的跨度包含有关给定操作并记录操作信息。

// 创建trace实例
tr := otel.Tracer("redis-conn")
Span

Span 是 Traces 的构建块,是追踪的基本单元。

spanCtx, span := tr.Start(c.Request.Context(), "get-todo")
span.End()
Context(上下文连接)

上下文传播是实现分布式跟踪的核心概念。通过上下文传播,Span 可以相互关联并组装成跟踪,无论 Span 是在哪里生成的。

总结

tracer跨度代表一个工作或操作单元,Span 是 Traces 的构建块,在 OpenTelemetry 中包含以下信息:

{
 "trace_id": "7bba9f33312b3dbb8b2c2c62bb7abe2d",
 "parent_id": "",
 "span_id": "086e83747d0e381e",
 "name": "/v1/sys/health",
 "start_time": "2021-10-22 16:04:01.209458162 +0000 UTC",
 "end_time": "2021-10-22 16:04:01.209514132 +0000 UTC",
 "status_code": "STATUS_CODE_OK",
 "status_message": "",
 "attributes": {
 "net.transport": "IP.TCP",
 "net.peer.ip": "172.17.0.1",
 "net.peer.port": "51820",
 "net.host.ip": "10.177.2.152",
 "net.host.port": "26040",
 "http.method": "GET",
 "http.target": "/v1/sys/health",
 "http.server_name": "mortar-gateway",
 "http.route": "/v1/sys/health",
 "http.user_agent": "Consul Health Check",
 "http.scheme": "http",
 "http.host": "10.177.2.152:26040",
 "http.flavor": "1.1"
 },
 "events": [
 {
 "name": "",
 "message": "OK",
 "timestamp": "2021-10-22 16:04:01.209512872 +0000 UTC"
 }
 ]}

完整代码实例如下:

package tracerprovicer

import (
	"go.opentelemetry.io/otel/exporters/jaeger"
	"go.opentelemetry.io/otel/sdk/resource"
	sdktrace "go.opentelemetry.io/otel/sdk/trace"
	semconv "go.opentelemetry.io/otel/semconv/v1.4.0"
)

func JaegerTraceProvider() (*sdktrace.TracerProvider, error) {
	exp, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint("http://localhost:14268/api/traces")))
	if err != nil {
		return nil, err
	}
	tp := sdktrace.NewTracerProvider(
		sdktrace.WithBatcher(exp),
		sdktrace.WithResource(resource.NewWithAttributes(
			semconv.SchemaURL,
			semconv.ServiceNameKey.String("todo-service"),
			semconv.DeploymentEnvironmentKey.String("production"),
		)),
	)
	return tp, nil
}
package main

import (
	"github.com/gin-gonic/gin"
	"github.com/redis/go-redis/v9"
	"go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/propagation"
	"log"
	"net/http"
	"oteldemo/tracing"
)

var (
	cli *redis.Client
	r   *gin.Engine
)

func main() {
	//设置Exporter,将Jaeger的exporter设置为otel的Exporter
	// 返回以Jaeger为exporter的traceProvider
	tp, tpErr := tracerprovicer.JaegerTraceProvider()
	if tpErr != nil {
		log.Fatal(tpErr)
	}
	// 设置otel的provider
	otel.SetTracerProvider(tp)
	// 设置传播提取器
	otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))

	// 创建gin实例
	ginWebServer()

	//gin OpenTelemetry工具化
	r.Use(otelgin.Middleware("todo-service"))
	r.GET("/todo", func(c *gin.Context) {
		// 创建trace实例
		tr := otel.Tracer("redis-conn")
		// 创建span实例
		spanCtx, span := tr.Start(c.Request.Context(), "get-todo")

		span.End()
		tp.Shutdown(spanCtx)

		c.JSON(http.StatusOK, "ok")
	})

	r.Run(":8001")
}

func ginWebServer() {
	r = gin.Default()
}

func redisConn() {
	// connectMongo
	cli = redis.NewClient(&redis.Options{
		Addr: "127.0.0.1:6379",
	})
	return
}

jaeger collector默认地址:http://localhost:14268/api/traces

在这里插入图片描述

项目地址:open-telemetry-demo

在初始化Tracer Provider时同时初始化otel-exporterotel-resourcesemconv.ServiceNameKey.String("todo-service")部分是填写服务名称,semconv.DeploymentEnvironmentKey.String("production")部分是填写开发环境。

对于每一个provider创建的tr := otel.Tracer("redis-conn")填写tracer名称,spanCtx, span := tr.Start(c.Request.Context(), "get-todo")填写的是span名称。

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

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

相关文章

Docker系列

目录 练习:去DockerHub搜索并拉取一个Redis镜像 练习:去DockerHub搜索并拉取一个Redis镜像 目标: 1)去DockerHub搜索Redis镜像 2)查看Redis镜像的名称和版本 3)利用docker pull命令拉取镜像 查看是否…

数据仓库的魅力及其在企业中的应用实践

数据仓库,这一创新性的概念来自于比尔恩门,从1980年代末提出以来,便凭借其独特的架构设计和强大的数据处理能力,在全球商业领域中掀起了一场革命。它不仅是解决企业海量数据存储和查询需求的关键技术,更是推动企业实现…

贵州省二级分类土地利用数据(矢量)

贵州省,地处中国西南腹地,地貌属于中国西南部高原山地,境内地势西高东低,自中部向北、东、南三面倾斜,平均海拔在1100米左右。贵州高原山地居多,素有“八山一水一分田”之说。全省地貌可概括分为&#xff1…

双向链表、单双向链表比较、双向链表的基本操作

我要成为嵌入式高手之3月20日数据结构第三天!! ———————————————————————————— 双向链表 双向链表与单向链表的区别:双向链表中的结点的指针域包含前驱结点的地址,而单向链表的结点中指针域只有后驱结…

PyTorch 深度学习(GPT 重译)(六)

十四、端到端结节分析,以及接下来的步骤 本章内容包括 连接分割和分类模型 为新任务微调网络 将直方图和其他指标类型添加到 TensorBoard 从过拟合到泛化 在过去的几章中,我们已经构建了许多对我们的项目至关重要的系统。我们开始加载数据&#xf…

RK3399 android10 移植SiS-USB触摸驱动

一,SiS USB触摸简介 SiS USB 触摸屏通常是一种外接式触摸屏设备,通过 USB 接口连接到计算机或其他设备上。这种触摸屏设备可以提供触摸输入功能,用户可以通过手指或触控笔在屏幕上进行操作,实现点击、拖动、缩放等操作。 SiS USB…

腾讯云GPU云服务器简介_GPU服务器购买指南_GPU云服务器操作

腾讯云GPU服务器是提供GPU算力的弹性计算服务,腾讯云GPU服务器具有超强的并行计算能力,可用于深度学习训练、科学计算、图形图像处理、视频编解码等场景,腾讯云百科txybk.com整理腾讯云GPU服务器租用价格表、GPU实例优势、GPU解决方案、GPU软…

学点儿Java_Day7_在实体类当中IDEA无法进行单元测试(@Test没有启动按钮)

在敲代码体会继承和访问修饰符的时候忽然遇到了单元测试不管用的情况,表现为没有启动按钮   经过一番折腾,发现我的测试是在具有构造函数的实体类Person当中进行的,当我把所有的构造函数删除后,启动按钮又出来了,加…

Pycharm实用快捷键

Pycharm实用快捷键 1.代码/函数提示2.查找同一变量位置3.添加类型提示4.一键代码规范化5.任意位置切换到下一行6.快速运行7.多行快速注释8.展开/折叠代码块9.全局搜索10.变量用过的地方11.快速包围12.跳到文件成员13.在项目内查找14.快速选中15.导入优化16.扩展 / 缩小选中17.复…

【SQL】1141. 查询近30天活跃用户数(常规写法;date_add())

前述 mysql中date_add()函数的使用 题目描述 leetcode题目&#xff1a;1141. 查询近30天活跃用户数 Code 写法一 select activity_date as day, count(distinct user_id) as active_users from Activity where activity_date > 2019-06-27 and activity_date < 2019…

北斗短报文+4G应急广播系统:全面预警灾害信息 构建安全美好乡村

建设社会主义新农村是确保小康社会宏伟目标如期实现的必然要求&#xff0c;是构建和谐社会的重要内容。针对现代农业发展的要求&#xff0c;通过完善专业化监测预报技术&#xff0c;提高精细化的灾害监测预警能力&#xff0c;建设广覆盖的预警信息发布网络&#xff0c;建设有效…

Linux快速入门,上手开发 01.学习路线

少时曾许凌云志&#xff0c;当取世间第一流 再见少年拉满弓&#xff0c;不惧岁月不飓风 —— 24.3.20 1.Linux的发展历史 2.VM虚拟机的Linux初体验 3.图形化页面设置系统——快速上手 4.命令行操作——向专业前进 5.核心操作命令——必知必会&#xff08;管理企业级权限/定位b…

【web算法】列车车厢重排问题

💝💝💝欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学习,不断总结,共同进步,活到老学到老导航 檀越剑指大厂系列:全面总结 jav…

【Unity】Plastic云同步总是password error

【背景】 Plastic是Unity的项目版本控制功能&#xff0c;可以方便在多个地点同步项目进度。原本用得挺爽的&#xff0c;结果今天遇到糟心事&#xff0c;明明Hub也正常登着&#xff0c;可Plastic的一个update的dll就是不停反复运行并报Password invalid。 【问题分析】 听说I…

常见六大WEB安全问题

一、XSS跨站脚本攻击 1.Cross-Site Scripting&#xff08;跨站脚本攻击&#xff09;简称 XSS&#xff08;因为缩写和 CSS重叠&#xff0c;所以只能叫 XSS&#xff09;&#xff0c;是一种代码注入攻击。攻击者通过在目标网站上注入恶意脚本&#xff0c;使之在用户的浏览器上运行…

流畅的 Python 第二版(GPT 重译)(十)

第十八章&#xff1a;with、match 和 else 块 上下文管理器可能几乎与子例程本身一样重要。我们只是初步了解了它们。[…] Basic 有一个 with 语句&#xff0c;在许多语言中都有 with 语句。但它们的功能不同&#xff0c;它们都只是做一些非常浅显的事情&#xff0c;它们可以避…

关于v1.29.2 版本的Maxwell存在于mysql8.0后版本部分源码字符集处理确实问题

1. 先去GitHub下载源码.zip文件2. 找到上图中的这个 StringColumnDef.java 做如下修改 eg: 3.然后是pom文件部分的修改&#xff1a; 将这个org.jgroups的版本降低到0.5.2.Final 然后再去注释掉一个类的引用&#xff1a; MaxwellHA.java 3.1 还可以不用降低这个org.jgro…

大模型学习笔记七:LLM应用

文章目录 一、维护生产级别的LLM应用,需要做的事二、符合需求的LLM App维护平台三、LangFuse1)替换OpenAI客户端(把跟OpenAI交互记录到LangFuse)1.1)几个基本概念2)通过LangChain的回调函数触发记录(上面用的原生OpenAI接口,下面是调用LangChain的接口)3)构建一个实际…

3.20刷题--备赛ing

距离十五届蓝桥杯还有23天&#xff0c;奶奶的拼了。备赛ing 今天刷题 5道 有序分数递归方法 如何1/2 2/4都是相同的结果&#xff0c;但是需要的是1/2&#xff0c;如何解决这个问题呢&#xff0c;可以看出分子和分母约分最简的时候&#xff0c;他们的gcd1&#xff0c;所以求…

Socket类

2.2 Socket类 Socket 类&#xff1a;该类实现客户端套接字&#xff0c;套接字指的是两台设备之间通讯的端点。 构造方法 public Socket(String host, int port) :创建套接字对象并将其连接到指定主机上的指定端口号。如果指定的host是null &#xff0c;则相当于指定地址为回送…