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

链路追踪背景

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

随着服务数量的增多和内部调用链的复杂化,开发者仅凭借日志和性能监控,难以做到全局的监控,运维难度极大。为了解决这个问题,业界推出了分布式链路追踪组件。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 tracerprovicerimport ("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 tracerprovicerimport ("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 mainimport ("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.Clientr   *gin.Engine
)func main() {//设置Exporter,将Jaeger的exporter设置为otel的Exporter// 返回以Jaeger为exporter的traceProvidertp, tpErr := tracerprovicer.JaegerTraceProvider()if tpErr != nil {log.Fatal(tpErr)}// 设置otel的providerotel.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() {// connectMongocli = 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.mzph.cn/news/758017.shtml

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

相关文章

Jpg图片怎么变成gif?三步在线转换gif动画

JPG是一种常见的图像格式,而GIF动态则是一种流行的动态图像格式。如果你想将多张JPG图片合成为一个GIF动画,下面是一些简单的方法来帮助你完成这个任务。通过使用Gif动画制作工具-GIF中文网,上传多张jpg格式图片轻松一键在线转换gif动画&…

Python爬虫获取接口数据

Python爬虫获取接口数据 正常人的操作​​​​​​​​​​爬虫的思路标题获取请求信息标题请求转换为代码完整代码请求返回信息执行程序获取静态网页数据的教程,适用于我们要爬取的数据在网页源代码中出现,但是还是有很多的数据是源代码中没有的,需要通过接口访问服务器来获…

Docker与containerd:容器技术的双璧

🐇明明跟你说过:个人主页 🏅个人专栏:《Docker幻想曲:从零开始,征服容器宇宙》 🏅 🔖行路有良友,便是天堂🔖 目录 一、前言 1、Docker和containerd的背景…

cobbler批量装机工具,可以实现同时装多台或多台不同系统的主机,也可以实现定制安装

cobbler批量装机工具 文章目录 cobbler批量装机工具1. cobbler简介2. cobbler服务端部署uos3. 客户端安装(内存和cpu可以多个点,以免后面出错)4.cobbler服务端部署centos75.客户端安装6.cobbler服务端部署centos87.客户端安装8.cobbler服务端部署rockylinux99.客户端…

面试笔记——Redis(集群方案:主从复制、哨兵模式和分片集群)

主从复制 在 Redis 主从集群中,一个主节点(Master)负责处理客户端的读写请求,而多个从节点(Slave)则负责复制主节点的数据,并对外提供读取服务——解决高并发问题。 主节点(Master&…

最新ChatGPT/GPT4科研应用与AI绘图及论文高效写作教程

原文链接:最新ChatGPT/GPT4科研应用与AI绘图及论文高效写作教程https://mp.weixin.qq.com/s?__bizMzUzNTczMDMxMg&mid2247598050&idx5&sn70fd3f5946d581ad9c1363295b130ef5&chksmfa823e05cdf5b713baf9cf1381bfb2455ad675a0b21e194bef8b76f35d6aa77…

C++初阶 | [九] list 及 其模拟实现

摘要:介绍 list 容器,list 模拟实现,list与vector的对比 list(带头双向循环列表) 导入:list 的成员函数基本上与 vector 类似,具体内容可以查看相关文档(cplusplus.com/reference/list/list/)&…

Linux中使用vim编辑器的时候提示:发现交换文件“XXX.swap“

目录 问题描述解决方案 问题描述 有时候vim编辑文件的时候 系统突然卡了 无奈只能强制退出关机 然后重启 这个时候想重新回来继续编辑刚刚的文件 注意:我这种操作方式 虽然之后可以继续正常编辑了 但是发现文件是没有保存的 vim XXX进去有如下提示 解决方案 注意:我这种操作…

基于python的变配电室运行状态评估与预警系统flask-django-nodejs-php

近年来,随着我国工业化、城镇化步伐的不断加快,城市配电网络取得令人瞩目的发展成果。变配电室是供配电系统的核心,在供配电系统中占有特殊的重要地位[1]。变配电室电气设备运行状态和环境信息缺乏必要的监测评估预警手段,如有一日遭遇突发情…

Linux-线程同步

文章目录 前言一、为什么要线程同步?二、线程同步pthread_cond_initpthread_cond_destroypthread_cond_wait、pthread_cond_signal和 pthread_cond_broadcast 三、示例代码 前言 上节课学习了线程互斥,这节课针对线程互斥内容在做进一步的补充和完善&am…

[C语言]一维数组二维数组的大小

对于一维数组我们知道取地址是取首元素的地址,二维数组呢,地址是取第一行的地址,sizeof(数组名)这里计算的就是整个数组的大小,&数组名 表示整个数组,取出的是整个数组的地址,显示的是数组的首元素 记…

网络工程师练习题2

网络工程师 将专用IP地址转换为公用IP地址的技术是()。 A.ARPB.DHCPC.UTMD.NAT 【答案】D 【解析】概念题,NAT技术将源地址从内部专用地址转换成可以在外部Internet上路由的全局IP地址。 R1、R2是一个自治系统中采用RIP路由协议的两个相…

【计算机网络篇】物理层(4)信道的极限容量,信道复用技术

文章目录 🍔信道的极限容量🛸造成信号失真的主要因素⭐码元的传输速率 🛸奈氏准则🛸香农公式🎈练习 🗒️小结 🍔信道复用技术⭐常见的信道复用技术🎈频分复用FDM🎈时分复…

时序分解 | Matlab实现GWO-CEEMDAN基于灰狼算法优化CEEMDAN时间序列信号分解

时序分解 | Matlab实现GWO-CEEMDAN基于灰狼算法优化CEEMDAN时间序列信号分解 目录 时序分解 | Matlab实现GWO-CEEMDAN基于灰狼算法优化CEEMDAN时间序列信号分解效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.CEEMDAN方法的分解效果取决于白噪声幅值权重(Nstd)和噪声添…

【刷题】滑动窗口入门

送给大家一句话: 那脑袋里的智慧,就像打火石里的火花一样,不去打它是不肯出来的。——莎士比亚 滑动窗口入门 认识滑动窗口Leetcode 209. 长度最小的子数组题目描述算法思路 Leetcode 3. 无重复字符的最长子串题目描述算法思路 Leetcode 1004…

部署应用到K8s集群(未完)

(等熟悉一番再来写,因为按小时结算的。。。) 1 、 kubectl run 启动 nginx 应用 kubectl run nginx --imagenginx:latest 2、将本地机器的80端口转发到集群中名为nginx的Pod的80端口 kubectl port-forward --address 0.0.0.0 pod/nginx 80:8…

AHI对MySQL性能的影响

MySQL中出现很多latch锁,而这个很大程度上和MySQL自适应hash索引有关。 AHI概述 MySQL InnoDB存储引擎的自适应哈希(Adaptive Hash Index,下简称AHI)功能 若用户的访问模式基本都是类似KV操作的点查询(point select&…

es bulk批量操作简单实例

(1)定义 bulk允许在单个步骤中进行多次create、index、update或delete请求。 bulk与其他的请求体格式稍有不同,如下所示: { action: { metadata }}\n { request body }\n { action: { metadata }}\n { request body …

FPGA高端项目:FPGA基于GS2971+GS2972架构的SDI视频收发+HLS图像缩放+多路视频拼接,提供4套工程源码和技术支持

目录 1、前言免责声明 2、相关方案推荐本博主所有FPGA工程项目-->汇总目录本博已有的 SDI 编解码方案本方案的SDI接收发送本方案的SDI接收图像缩放应用本方案的SDI接收纯verilog图像缩放纯verilog多路视频拼接应用本方案的SDI接收OSD动态字符叠加输出应用本方案的SDI接收HLS…

【CSS】html滚动条相关

1.滚动条样式 ::-webkit-scrollbar {width: 10px;height: 10px;z-index: 101; } ::-webkit-scrollbar-thumb {border-radius: 5px;background: #cecece; } ::-webkit-scrollbar-track {// background: #f5f5f5be;background: rgba(33, 85, 163, 0); } ::-webkit-scrollbar-but…