链路传播(Propagate)机制及使用场景
服务间链路追踪传播机制是指在微服务架构中,通过记录和跟踪服务之间的请求和响应信息,来实现对服务间链路的追踪和监控。这种机制可以帮助开发人员快速定位服务间出现的问题,并进行优化和调整。
具体来说,服务间链路追踪传播机制可以通过在每个服务的请求和响应中添加唯一标识符来实现。当一个服务发送请求到另一个服务时,它会将自己的唯一标识符添加到请求头中,并发送给目标服务。目标服务收到请求后,会将请求头中的唯一标识符复制到响应头中,并返回给调用方。调用方收到响应后,可以通过唯一标识符来追踪服务间的调用链路。
为了实现服务间链路追踪传播机制,通常会使用一些开源工具或框架,比如
OpenTelemetry
、DataDog
、Zipkin
、SkyWalking
等。这些工具可以自动记录服务间的请求和响应信息,并提供可视化的界面来帮助开发人员进行调试和优化。
通常,我们会将这种特殊标识的请求头称之为传播协议。
常见传播协议
不同的 APM 工具支持一种或者多种传播协议,以便更好的服务于应用。
- b3
- uber
- sw8
- w3c
- datadog
- ot
OpenTelemetry 除了原生支持 ot
、w3c
、 b3
和uber
几种协议外,通过:opentelemetry-collector-contrib
支持 sw8
和datadog
传播协议。
B3 协议
B3 传播协议是第一个链路追踪协议,这里重点讲述 B3 传播协议相关内容。
B3 有两种编码:Single Header 和 Multiple Header。
- 多个标头编码 X-B3-在跟踪上下文中使用每个项目的前缀标头
- 单个标头将上下文分隔为一个名为 b3. 提取字段时,单头变体优先于多头变体。
这是一个使用多个标头编码的示例流程,假设 HTTP 请求带有传播的跟踪:
Multiple Headers
需要配合多个 header key 使用。
TraceId
X-B3-TraceId
标头编码为 32 或 16 个低十六进制字符。例如,128 位 TraceId 标头:X-B3-TraceId:463ac35c9f6413ad48485a3953bb6124
。除非仅传播“采样状态”,否则需要 X-B3-TraceId
标头。
SpanId
X-B3-SpanId
标头编码为16个较低的十六进制字符。例如:X-B3-SpanId:a2fb4a1d1a96d312
。除非仅传播“采样状态”,否则需要 X-B3-SpanId
标头。
ParentSpanId
X-B3-ParentSpanId
标头可能存在于子跨度上,而在根跨度上必须不存在。它被编码为16个低十六进制字符。例如,ParentSpanId
标头可能看起来像:X-B3-ParentSpanId:00020000000000001
Sampling State
接受采样决定编码为X-B3-Sampled:1
,拒绝编码为X-B3-Sampled:0
。缺席意味着将决定推迟到该报头的接收方。例如:X-B3-Sampled:1
。
注:在编写本规范之前,一些示踪剂传播X-B3-Sampled
为true
或false
,而不是1
或0
。虽然您不应该将X-B3-Sampled
编码为true
或false
,但宽松的实现可能会接受它们。
Debug Flag
调试编码为X-B3-Flags: 1
。可以忽略 Absent 或任何其他值。调试意味着接受决定,所以不要同时发送X-B3-Sampled
标头。
Single Header
Single Header
只有一个header 为b3
的 key 作为标记。
b3={TraceId}-{SpanId}-{SamplingState}-{ParentSpanId}
如
b3: 80f198ee56343ba864fe8b2a57d3eff7-e457b5a2e4d86bd1-d
实现场景
目前主要有两大实现场景:
- APM:主要是服务端之间传播
- RUM:用户端(web、小程序等)与服务端传播
APM
OpenTelemetry 传播器源码
OpenTelemetry 传播器源码
传播器接口:TextMapPropagator
opentelemetry-java
通过定义统一的接口TextMapPropagator
来实现各种 Propagate。
TextMapPropagator
默认提供了一个空实现noop()
。
TextMapPropagator
定义了三个接口方法:
- fields() : 规定了哪些字段作为传播器识别的对象
- inject():定义了传播器字段注入规则
- extract():定义传播器字段提取规则,返回
Context
对象
一些厂商有自己的 APM 标准,通过扩展TextMapPropagator
接口,实现对接厂商特定的传播器。
@ThreadSafe
public interface TextMapPropagator {static TextMapPropagator composite(TextMapPropagator... propagators) {return composite(Arrays.asList(propagators));}static TextMapPropagator composite(Iterable<TextMapPropagator> propagators) {List<TextMapPropagator> propagatorsList = new ArrayList<>();for (TextMapPropagator propagator : propagators) {propagatorsList.add(propagator);}if (propagatorsList.isEmpty()) {return NoopTextMapPropagator.getInstance();}if (propagatorsList.size() == 1) {return propagatorsList.get(0);}return new MultiTextMapPropagator(propagatorsList);}static TextMapPropagator noop() {return NoopTextMapPropagator.getInstance();}Collection<String> fields();<C> void inject(Context context, @Nullable C carrier, TextMapSetter<C> setter);<C> Context extract(Context context, @Nullable C carrier, TextMapGetter<C> getter);
}
OtTracePropagator
OtTracePropagator
是 OpenTelemetry 特有的传播器,识别解析ot-
开头的header,部分源码如下:
@Immutable
public final class OtTracePropagator implements TextMapPropagator {static final String TRACE_ID_HEADER = "ot-tracer-traceid";static final String SPAN_ID_HEADER = "ot-tracer-spanid";static final String SAMPLED_HEADER = "ot-tracer-sampled";static final String PREFIX_BAGGAGE_HEADER = "ot-baggage-";private static final Collection<String> FIELDS =Collections.unmodifiableList(Arrays.asList(TRACE_ID_HEADER, SPAN_ID_HEADER, SAMPLED_HEADER));....@Overridepublic Collection<String> fields() {return FIELDS;}@Overridepublic <C> void inject(Context context, @Nullable C carrier, TextMapSetter<C> setter) {if (context == null || setter == null) {return;}SpanContext spanContext = Span.fromContext(context).getSpanContext();if (!spanContext.isValid()) {return;}// Lightstep trace id MUST be 64-bits therefore OpenTelemetry trace id is truncated to 64-bits// by retaining least significant (right-most) bits.setter.set(carrier, TRACE_ID_HEADER, spanContext.getTraceId().substring(TraceId.getLength() / 2));setter.set(carrier, SPAN_ID_HEADER, spanContext.getSpanId());setter.set(carrier, SAMPLED_HEADER, String.valueOf(spanContext.isSampled()));// Baggage is only injected if there is a valid SpanContextBaggage baggage = Baggage.fromContext(context);if (!baggage.isEmpty()) {// Metadata is not supported by OpenTracingbaggage.forEach((key, baggageEntry) ->setter.set(carrier, PREFIX_BAGGAGE_HEADER + key, baggageEntry.getValue()));}}@Overridepublic <C> Context extract(Context context, @Nullable C carrier, TextMapGetter<C> getter) {if (context == null) {return Context.root();}if (getter == null) {return context;}String incomingTraceId = getter.get(carrier, TRACE_ID_HEADER);String traceId =incomingTraceId == null? TraceId.getInvalid(): StringUtils.padLeft(incomingTraceId, MAX_TRACE_ID_LENGTH);String spanId = getter.get(carrier, SPAN_ID_HEADER);String sampled = getter.get(carrier, SAMPLED_HEADER);SpanContext spanContext = buildSpanContext(traceId, spanId, sampled);if (!spanContext.isValid()) {return context;}Context extractedContext = context.with(Span.wrap(spanContext));// Baggage is only extracted if there is a valid SpanContextif (carrier != null) {BaggageBuilder baggageBuilder = Baggage.builder();for (String key : getter.keys(carrier)) {if (!key.startsWith(PREFIX_BAGGAGE_HEADER)) {continue;}String value = getter.get(carrier, key);if (value == null) {continue;}baggageBuilder.put(key.replace(OtTracePropagator.PREFIX_BAGGAGE_HEADER, ""), value);}Baggage baggage = baggageBuilder.build();if (!baggage.isEmpty()) {extractedContext = extractedContext.with(baggage);}}return extractedContext;}...
}
初始化传播器
opentelemetry-java
通过PropagatorConfiguration
对象对Propagate
进行初始化操作,源码如下:
final class PropagatorConfiguration {private static final List<String> DEFAULT_PROPAGATORS = Arrays.asList("tracecontext", "baggage");static ContextPropagators configurePropagators(ConfigProperties config,ClassLoader serviceClassLoader,BiFunction<? super TextMapPropagator, ConfigProperties, ? extends TextMapPropagator>propagatorCustomizer) {Set<TextMapPropagator> propagators = new LinkedHashSet<>();List<String> requestedPropagators = config.getList("otel.propagators", DEFAULT_PROPAGATORS);NamedSpiManager<TextMapPropagator> spiPropagatorsManager =SpiUtil.loadConfigurable(ConfigurablePropagatorProvider.class,ConfigurablePropagatorProvider::getName,ConfigurablePropagatorProvider::getPropagator,config,serviceClassLoader);if (requestedPropagators.contains("none")) {if (requestedPropagators.size() > 1) {throw new ConfigurationException("otel.propagators contains 'none' along with other propagators");}return ContextPropagators.noop();}for (String propagatorName : requestedPropagators) {propagators.add(propagatorCustomizer.apply(getPropagator(propagatorName, spiPropagatorsManager), config));}return ContextPropagators.create(TextMapPropagator.composite(propagators));}private static TextMapPropagator getPropagator(String name, NamedSpiManager<TextMapPropagator> spiPropagatorsManager) {if (name.equals("tracecontext")) {return W3CTraceContextPropagator.getInstance();}if (name.equals("baggage")) {return W3CBaggagePropagator.getInstance();}TextMapPropagator spiPropagator = spiPropagatorsManager.getByName(name);if (spiPropagator != null) {return spiPropagator;}throw new ConfigurationException("Unrecognized value for otel.propagators: "+ name+ ". Make sure the artifact including the propagator is on the classpath.");}private PropagatorConfiguration() {}
}
启动 agent 时,通过指定传播器类型来实现对应实例构造,通过方法得知,otel 支持同时指定多种类型的传播器协议,默认采用tracecontext
传播器——即w3c
标准的传播器:
List<String> requestedPropagators = config.getList("otel.propagators", DEFAULT_PROPAGATORS);
获取传播器
opentelemetry-java
通过OpenTelemetry
对象的propagating()
方法构造当前支持的传播器,且通过getPropagators()
方法来获取已有的传播器,OpenTelemetry
是一个接口类,部分代码如下:
public interface OpenTelemetry {static OpenTelemetry noop() {return DefaultOpenTelemetry.getNoop();}static OpenTelemetry propagating(ContextPropagators propagators) {return DefaultOpenTelemetry.getPropagating(propagators);}TracerProvider getTracerProvider();ContextPropagators getPropagators();...
}
每一个Instrumente
都需要通过InstrumenterBuilder
获取OpenTelemetry
对象来实现 trace、metric 相关业务逻辑。比如,启动一个 span。
如何获取OpenTelemetry
对象
通过上面的研究,我们知道如何获取传播器,但是获取传播器需要获取OpenTelemetry
对象,opentelemetry-java
提供了一个全局的对象GlobalOpenTelemetry
来获取OpenTelemetry
对象。我们来看看具体代码
public final class GlobalOpenTelemetry {
...@Nullableprivate static volatile ObfuscatedOpenTelemetry globalOpenTelemetry;public static OpenTelemetry get() {OpenTelemetry openTelemetry = globalOpenTelemetry;if (openTelemetry == null) {synchronized(mutex) {openTelemetry = globalOpenTelemetry;if (openTelemetry == null) {OpenTelemetry autoConfigured = maybeAutoConfigureAndSetGlobal();if (autoConfigured != null) {return autoConfigured;}set(OpenTelemetry.noop());return OpenTelemetry.noop();}}}return openTelemetry;}public static void set(OpenTelemetry openTelemetry) {synchronized(mutex) {if (globalOpenTelemetry != null) {throw new IllegalStateException("GlobalOpenTelemetry.set has already been called. GlobalOpenTelemetry.set must be called only once before any calls to GlobalOpenTelemetry.get. If you are using the OpenTelemetrySdk, use OpenTelemetrySdkBuilder.buildAndRegisterGlobal instead. Previous invocation set to cause of this exception.", setGlobalCaller);} else {globalOpenTelemetry = new ObfuscatedOpenTelemetry(openTelemetry);setGlobalCaller = new Throwable();}}}@Nullableprivate static OpenTelemetry maybeAutoConfigureAndSetGlobal() {Class openTelemetrySdkAutoConfiguration;try {openTelemetrySdkAutoConfiguration = Class.forName("io.opentelemetry.sdk.autoconfigure.AutoConfiguredOpenTelemetrySdk");} catch (ClassNotFoundException var7) {return null;}boolean globalAutoconfigureEnabled = Boolean.parseBoolean(ConfigUtil.getString("otel.java.global-autoconfigure.enabled", "false"));if (!globalAutoconfigureEnabled) {logger.log(Level.INFO, "AutoConfiguredOpenTelemetrySdk found on classpath but automatic configuration is disabled. To enable, run your JVM with -Dotel.java.global-autoconfigure.enabled=true");return null;} else {try {Method initialize = openTelemetrySdkAutoConfiguration.getMethod("initialize");Object autoConfiguredSdk = initialize.invoke((Object)null);Method getOpenTelemetrySdk = openTelemetrySdkAutoConfiguration.getMethod("getOpenTelemetrySdk");return new ObfuscatedOpenTelemetry((OpenTelemetry)getOpenTelemetrySdk.invoke(autoConfiguredSdk));} catch (IllegalAccessException | NoSuchMethodException var5) {throw new IllegalStateException("AutoConfiguredOpenTelemetrySdk detected on classpath but could not invoke initialize method. This is a bug in OpenTelemetry.", var5);} catch (InvocationTargetException var6) {logger.log(Level.SEVERE, "Error automatically configuring OpenTelemetry SDK. OpenTelemetry will not be enabled.", var6.getTargetException());return null;}}}...
GlobalOpenTelemetry
通过单例模式实现获取全局OpenTelemetry
对象。而OpenTelemetry
则主要是通过AutoConfiguredOpenTelemetrySdk
的 getOpenTelemetrySdk
方法初始化构建。
至此,基本上完成了opentelemetry-java
从传播器实现、构造、初始化及获取相关操作。
DataDog(DDtrace)传播器源码
DataDog(DDtrace)传播器源码
DDtrace除了支持上面表格中的传播协议之外,还支持其他传播协议,如:
- Haystack
- Haystack-Trace-ID
- Haystack-Span-ID
- Haystack-Parent-ID
- XRAY
- X-Amzn-Trace-Id
RUM
前面了解了传播器的原理、作用以及实现方式。传播器提到最多的是 header,也就说大多数都是基于 http 协议。基于 http 协议,进一步引申到 html、小程序、Android、iOS 等,从而引出另一个概念:RUM。
RUM 全称为
Real User Monitor
,即真实用户监控。
RUM 通过实现不同的传播器协议,将用户端与服务端紧密联系在一起,我们知道 APM 是后端接口及服务的性能表现,但接口用于地方很多,有的来源于 web,有的来源于小程序等等。通过引入 RUM,结合链路分析,很容易追踪到数据来源于哪一端。
当然 RUM 的作用不仅仅是这一方面,目前市面上常见的是基于 W3C(万维网联盟)定义的[navigation-timing] 标准(见下图),该标准详细定义了各种浏览器事件,通过浏览器事件的简单计算就可以算出来前端页面的首屏、白屏、DOM 加载、HTML 加载等时长,相较于测试环境的 F12 检查者模式,能有更效的收集生产环境真实用户的前端体验。
opentelemetry-js
opentelemetry-js是 OpenTelemetry 具体的实现,目前支持 nodejs 和 js,作用范围比较有限,主要围绕 OpenTelemetry 的集中传播器协议实现,产品成熟度仍需进一步提升。
opentelemetry-js
demo
观测云 RUM
是观测云推出的 RUM 产品,可以与多种 APM 技术融合,本质上是支持多种传播器协议,进而能够与各种 APM 结合使用。
支持的传播器协议有:
- ddtrace :x-datadog-parent-id,x-datadog-sampled,x-datadog-sampling-priority,x-datadog-trace-id。
- skywalking: sw8。
- jaeger: uber-trace-id。
- zipkin: X-B3-TraceId、X-B3-SpanId、X-B3-ParentSpanId、X-B3-Sampled、X-B3-Flags。
- zipkin_single_header: b3。
- w3c_traceparent: traceparent。
- opentelemetry: 该类型支持 zipkin_single_header,w3c_traceparent,zipkin、jaeger三种类型的配置方式,根据在 rum sdk 中配置的 traceType 类型 添加对应的 header。
目前支持的应用有:
- web H5
- 小程序
- Android
- iOS
- React Native
- Flutter
- UniApp
- C++
以 web 为例,展示接入方式,接入简单。
<script src="https://static.guance.com/browser-sdk/v3/dataflux-rum.js" type="text/javascript"></script>
<script>window.DATAFLUX_RUM &&window.DATAFLUX_RUM.init({applicationId: '<应用 ID>',datakitOrigin: '<DATAKIT ORIGIN>', // 协议(包括://),域名(或IP地址)[和端口号]env: 'production',version: '1.0.0',service: 'browser',sessionSampleRate: 100,sessionReplaySampleRate: 70,trackInteractions: true,traceType: 'ddtrace', // 非必填,默认为ddtrace,目前支持 ddtrace、zipkin、skywalking_v3、jaeger、zipkin_single_header、w3c_traceparent 6种类型allowedTracingOrigins: ['https://api.example.com',/https:\/\/.*\.my-api-domain\.com/], // 非必填,允许注入trace采集器所需header头部的所有请求列表。可以是请求的origin,也可以是是正则})
</script>
其中 traceType 为传播器协议。
通过 CDN 加速缓存,以同步脚本引入的方式引入 SDK,此方式可以确保能够收集到所有的错误,资源,请求,性能指标,不过可能会影响页面的加载性能。
单页应用建议将下方代码复制粘贴到 html 文件 head 标签的首行,多页应用建议将下方代码复制粘贴到公共 head 模版文件的首行。
更多更详细接入方式,参考官方文档用户访问监测
RUM 与 APM 实际应用
以某开源平台访问用户资源为例,查看实际应用场景,如下图所示:
右侧服务列表:
- browser :浏览器链路,由RUM端上报
- 其他服务为 APM 上报
RUM 通过传递特定的 header 信息,将链路信息传递给 APM,APM 正确解析相关传播协议,并以 RUM 传递的 trace为基准,创建 span信息,实现前后端串联。
browser同时可以查看当前用户的请求耗时分布(128.3 ms)
通过右上角view 按钮,可以跳转到当前页面的查看器,以此来查看分析用户行为。如下图所示
Baggage
前面已经分析了传播器一般需要携带的参数信息,便于前后端的应用串联,但实际上这只是传播器的基础用法,通常都是用于传递 trace 信息,实际上,在上面 opentelemetry-java
源码分析中,有一个频繁出现的单词baggage
,baggage
主要作用于业务参数的传递。
通常,研发人员不会直接在接口上填上用户信息,所以无法准确追踪这个接口是哪个用户触发的,借助 baggage,通过 header 进行传递,能够在服务间无限传递下去。
OpenTelemetry Baggage 用法
Header key 以ot-baggage-
开头的参数,会被 OpenTelemetry 一直传递下去。
还可以采用sdk的方式:OpenTelemetry Baggage SDK用法
DataDog Baggage 用法
需要配置启动参数dd.trace.header.baggage,设置哪些header 作为传递的参数依据。用法如下:
Environment Variable: DD_TRACE_HEADER_BAGGAGE
Default: null
Example: CASE-insensitive-Header:my-baggage-name,User-ID:userId,My-Header-And-Baggage-Name
Accepts a map of case-insensitive header keys to baggage keys and automatically applies matching request header values as baggage on traces. On propagation the reverse mapping is applied: Baggage is mapped to headers.
Available since version 1.3.0.
也可以采用 SDK 的方式:DataDog Baggage SDK 用法
相关文章:

链路传播(Propagate)机制及使用场景
服务间链路追踪传播机制是指在微服务架构中,通过记录和跟踪服务之间的请求和响应信息,来实现对服务间链路的追踪和监控。这种机制可以帮助开发人员快速定位服务间出现的问题,并进行优化和调整。 具体来说,服务间链路追踪传播机制…...
pytorch技巧总结1:学习率调整方法
pytorch技巧总结1:学习率调整方法 前言 这个系列,我会把一些我觉得有用、有趣的关于pytorch的小技巧进行总结,希望可以帮助到有需要的朋友。 免责申明 本人水平有限,若有误写、漏写,请大家温柔的批评指正。 目录…...

谈谈VPN是什么、类型、使用场景、工作原理
作者:Insist-- 个人主页:insist--个人主页 作者会持续更新网络知识和python基础知识,期待你的关注 前言 本文将讲解VPN是什么、以及它的类型、使用场景、工作原理。 目录 一、VPN是什么? 二、VPN的类型 1、站点对站点VPN 2、…...

windows 下载安装Redis,并配置开机自启动
windows 下载安装Redis,并配置开机自启动 1. 下载 地址:https://github.com/tporadowski/redis/releases Redis 支持 32 位和 64 位。这个需要根据你系统平台的实际情况选择,这里我们下载 Redis-x64-xxx.zip压缩包,之后解压 打…...

2. CSS3的新特性
2.1CSS3的现状 ●新增的CSS3特性有兼容性问题, ie9才支持 ●移动端支持优于PC端 ●不断改进中 ●应用相对广泛 ●现阶段主要学习: 新增选择器和盒子模型以及其他特性 CSS3给我们新增了选择器,可以更加便捷,更加自由的选择目标元素: 1.属性选择器 2.结构伪类选择器…...
从零开始训练神经网络
用Keras实现一个简单神经网络 Keras: Keras是由纯python编写的基于theano/tensorflow的深度学习框架。 Keras是一个高层神经网络API,支持快速实验,能够把你的idea迅速转换为结果,如果有如下需 求,可以优先选择Keras&a…...

连接区块链节点的 JavaScript 库 web3.js
文章目录 前言web3.js 介绍web3.js安装web3.js库模块介绍连接区块链节点向区块链网络发送数据查询区块链网络数据 前言 通过前面的文章我们可以知道基于区块链开发一个DApp,而DApp结合了智能合约和用户界面(客户端),那客户端是如…...
js:scroll平滑滚动页面或元素到顶部或底部的方案汇总
目录 1、CSS的scroll-behavior2、Element.scrollTop3、Element.scroll()/Window.scroll()4、Element.scrollBy()/Window.scrollBy()5、Element.scrollTo()/Window.scrollTo()6、Element.scrollIntoView()7、自定义兼容性方案8、参考文章 准备知识: scrollWidth: 是…...

【Docker】Docker的部署含服务和应用、多租环境、Linux内核的详细介绍
前言 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux或Windows操作系统的机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。 📕作者简介:热…...

C国演义 [第五章]
第五章 子集题目理解步骤树形结构递归函数递归结束的条件单层逻辑 代码 子集II题目理解步骤树形结构递归函数递归结束的条件单层逻辑 代码 子集 力扣链接 给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。…...

Proxy-Reflect使用详解
1 监听对象的操作 2 Proxy类基本使用 3 Proxy常见捕获器 4 Reflect介绍和作用 5 Reflect的基本使用 6 Reflect的receiver Proxy-监听对象属性的操作(ES5) 通过es5的defineProperty来给对象中的某个参数添加修改和获取时的响应式。 单独设置defineProperty是只能一次设置一…...

【Linux后端服务器开发】Shell外壳——命令行解释器
目录 一、Shell外壳概述 二、描述Shell外壳原理的生动例子 三、C语言模拟实现Shell外壳 一、Shell外壳概述 在狭义上 , 我们称Linux操作系统的内核为 Linux 在广义上 , Linux发行版 Linux内核 外壳程序 就比如市面上现在的redhat, centos, ubuntu等等我们耳熟能详的Linux发…...

【无公网IP】在外Windows远程连接MongoDB数据库
文章目录 前言1. 安装数据库2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射2.3 测试随机公网地址远程连接 3. 配置固定TCP端口地址3.1 保留一个固定的公网TCP端口地址3.2 配置固定公网TCP端口地址3.3 测试固定地址公网远程访问 转载自cpolar极点云文章:公网远程…...
mac python3 安装virtualenv
第一步,执行安装virtualenv pip3 install virtualenv 注意:如果出现WARNING: The script virtualenv is installed in ‘/home/local/bin’ which is not on PATH. Consider adding this directory to PATH or, if you prefer to suppress this warning,…...

网络安全(自学笔记)
如果你真的想通过自学的方式入门web安全的话,那建议你看看下面这个学习路线图,具体到每个知识点学多久,怎么学,自学时间共计半年左右,亲测有效(文末有惊喜): 1、Web安全相关概念&am…...

SPSS方差分析
参考文章 导入准备好的数据 选择分析方法 选择参数 选择对比,把组别放入因子框中,把红细胞增加数放进因变量列表 勾选“多项式”,等级取默认“线性” ,继续 接着点击“事后比较”,弹出对话框,勾选“LSD” …...

【Linux】深入理解文件系统
系列文章 收录于【Linux】文件系统 专栏 关于文件描述符与文件重定向的相关内容可以移步 文件描述符与重定向操作。 可以到 浅谈文件原理与操作 了解文件操作的系统接口。 想深入理解文件缓冲区还可以看看文件缓冲区。 目录 系列文章 磁盘 结构介绍 定位数据 抽象管理…...
12.9 专用指令
目录 状态寄存器传送指令 读CPSR 写CPSR 软中断指令 协处理器指令 协处理器数据运算指令 协处理器存储器访问指令 协处理器寄存器传送指令 伪指令 空指令 LDR 指令 伪指令 状态寄存器传送指令 专门用来读写CPSR寄存器的指令 读CPSR MRS R1,CPSR R1 CPSR 写CP…...

Jvm对象回收算法-JVM(九)
上篇文章介绍了jvm运行时候对象进入老年代的场景,以及如何避免频繁fullGC。 Jvm参数设置-JVM(八) 老年代分配担保机制 这个机制的目的是为了提升效率,在minorGC之前,会有三次判断,之后再次minorGC速度会…...

SpringCloud Alibaba微服务分布式架构组件演变
文章目录 1、SpringCloud版本对应1.1 技术选型依据1.2 cloud组件演变: 2、Eureka2.1 Eureka Server : 提供服务注册服务2.2 EurekaClient : 通过注册中心进行访问2.3 Eureka自我保护 3、Eureka、Zookeeper、Consul三个注册中心的异同点3.1 CP…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...

Yolov8 目标检测蒸馏学习记录
yolov8系列模型蒸馏基本流程,代码下载:这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中,**知识蒸馏(Knowledge Distillation)**被广泛应用,作为提升模型…...

vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...

[ACTF2020 新生赛]Include 1(php://filter伪协议)
题目 做法 启动靶机,点进去 点进去 查看URL,有 ?fileflag.php说明存在文件包含,原理是php://filter 协议 当它与包含函数结合时,php://filter流会被当作php文件执行。 用php://filter加编码,能让PHP把文件内容…...

ubuntu22.04有线网络无法连接,图标也没了
今天突然无法有线网络无法连接任何设备,并且图标都没了 错误案例 往上一顿搜索,试了很多博客都不行,比如 Ubuntu22.04右上角网络图标消失 最后解决的办法 下载网卡驱动,重新安装 操作步骤 查看自己网卡的型号 lspci | gre…...
小木的算法日记-多叉树的递归/层序遍历
🌲 从二叉树到森林:一文彻底搞懂多叉树遍历的艺术 🚀 引言 你好,未来的算法大神! 在数据结构的世界里,“树”无疑是最核心、最迷人的概念之一。我们中的大多数人都是从 二叉树 开始入门的,它…...

图解JavaScript原型:原型链及其分析 | JavaScript图解
忽略该图的细节(如内存地址值没有用二进制) 以下是对该图进一步的理解和总结 1. JS 对象概念的辨析 对象是什么:保存在堆中一块区域,同时在栈中有一块区域保存其在堆中的地址(也就是我们通常说的该变量指向谁&…...

数据结构第5章:树和二叉树完全指南(自整理详细图文笔记)
名人说:莫道桑榆晚,为霞尚满天。——刘禹锡(刘梦得,诗豪) 原创笔记:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 上一篇:《数据结构第4章 数组和广义表》…...
大数据治理的常见方式
大数据治理的常见方式 大数据治理是确保数据质量、安全性和可用性的系统性方法,以下是几种常见的治理方式: 1. 数据质量管理 核心方法: 数据校验:建立数据校验规则(格式、范围、一致性等)数据清洗&…...