news 2026/10/14 3:07:33

Seldon Core 2 与 Ambassador(Emissary)服务网格集成实战:REST 与 gRPC 端点配置指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Seldon Core 2 与 Ambassador(Emissary)服务网格集成实战:REST 与 gRPC 端点配置指南
  • 人工智能
  • 大模型
  • MLOps
  • LLMOps
  • 模型推理服务
  • 云原生
  • 后端

【免费下载链接】seldon-core

An MLOps framework to package, deploy, monitor and manage thousands of production machine learning models

项目地址:https://gitcode.com/gh_mirrors/se/seldon-core
点击查看免费下载

本文基于 Seldon Core 2 仓库中的docs-gb/kubernetes/service-meshes/ambassador.md文档及其配套 notebook(service-meshes/ambassador/ambassador.ipynb)编写。文章讲解如何在 Seldon Core 2 的安装命名空间中通过 Ambassador / Emissary ingress 暴露模型推理端点,包括单模型路由、REST 与 gRPC 双协议 Mapping 配置、基于权重的流量拆分尝试,以及背后"单一seldon-meshService + 请求头路由"的实现原理。读完本文,你将能够独立完成 Ambassador 与 Seldon Core 2 的接入、验证与清理全流程,并理解seldon-model请求头在模型路由中的核心作用。

一、为什么需要 Service Mesh 接入:Seldon 的单一端点模型

Seldon Core 2 的模型与 Pipeline 在安装命名空间中统一通过一个名为seldon-mesh的 Service 端点对外暴露(见 service-meshes/README.md)。所有模型、Pipeline 和实验(Experiment)都可以通过这个唯一的 Service 端点访问,区别仅在于调用方需要在推理请求上携带特定的请求头(Header)。

这一设计使得 Seldon 对服务网格的选择完全无感——无论是 Ambassador、Istio 还是 Traefik,只要网格能将流量路由到这个seldon-mesh端点,并正确转发(或注入)所需的请求头即可。仓库在service-meshes/目录下按字母序提供了三个网格的示例集成:

  • Ambassador(即本文主题,基于其 Emissary ingress 产品)
  • Istio(service-meshes/istio)
  • Traefik(service-meshes/traefik)

1.1 请求头路由:seldon-model

网格负责把请求送达seldon-mesh,但具体访问哪一个模型、Pipeline 或实验,则由请求头决定。Seldon 的 agent 组件会从请求中提取该头部并据此进行内部路由。

在 scheduler/pkg/util/constants.go 中,相关头常量定义如下:

// Headers const ( SeldonModelHeader = "seldon-model" SeldonPipelineHeader = "pipeline" SeldonInternalModelHeader = "seldon-internal-model" SeldonLoggingHeader = "Seldon-Logging" SeldonRouteHeader = "x-seldon-route" ExternalHeaderPrefix = "x-" SeldonModelHeaderSuffix = "model" SeldonPipelineHeaderSuffix = "pipeline" )

在 agent 的反向代理实现 scheduler/pkg/agent/rproxy.go 中,externalModelName = req.Header.Get(util.SeldonModelHeader),即从seldon-model头中解析出目标模型名(该头还可能携带实验标签,用于 Envoy 路由)。因此,Ambassador 的 Mapping 中通过add_request_headers为每个请求注入seldon-model: <模型名>,本质上是替调用方完成"指定目标模型"这一步,从而可以把同一个入口 URL 按模型维度分流。

二、前置准备与测试环境

本示例假定你已经按照 Emissary 的官方教程安装好了 Emissary ingress(本文仓库示例测试使用的版本为emissary-ingress-7.3.2,通过 helm 安装)。文档中给出的假设与测试条件是:

  • 前提:已按 Emissary 官方文档完成安装;
  • 测试版本:emissary-ingress-7.3.2(helm 安装);
  • 所有 Seldon 资源(Model、Mapping、Host、Listener)均部署在seldon-mesh命名空间中。

此外,示例的完整可运行版本位于仓库 service-meshes/ambassador 目录,包含:

  • ambassador.ipynb:可交互执行的 Jupyter notebook;
  • README.md:notebook 转换出的 Markdown 步骤记录;
  • config/:kustomize 组织的基础(base)与覆盖(overlay)配置;
  • static/:由config/经kustomize build生成的全量 YAML(供直接查看或应用)。

static/目录中的全量 YAML 由 Makefile 目标自动生成(见 service-meshes/ambassador/Makefile):

static/single-model.yaml: ./config/single-model/model.yaml ./config/single-model/mappings.yaml kustomize build config/single-model > static/single-model.yaml static/traffic-split.yaml: ./config/traffic-split/models.yaml ./config/single-model/mappings.yaml kustomize build config/traffic-split > static/traffic-split.yaml

三、单模型示例:Iris 分类器接入 Ambassador

本节演示通过 Ambassador 暴露一个 Seldon Iris 分类器模型,配置内容包括:

  • 默认的 Ambassador Host 与 Listener;
  • 针对 REST 与 gRPC 两个端点的 Ambassador Mapping;
  • 对应的 SeldonModel资源。

3.1 完整 YAML 配置

以下完整配置保存在 service-meshes/ambassador/static/single-model.yaml(由config/single-model目录 kustomize 生成,源文件见 config/single-model/mappings.yaml 与 config/single-model/model.yaml):

apiVersion: getambassador.io/v3alpha1 kind: Host metadata: name: wildcard namespace: seldon-mesh spec: hostname: '*' requestPolicy: insecure: action: Route --- apiVersion: getambassador.io/v3alpha1 kind: Listener metadata: name: emissary-ingress-listener-8080 namespace: seldon-mesh spec: hostBinding: namespace: from: ALL port: 8080 protocol: HTTP securityModel: INSECURE --- apiVersion: getambassador.io/v3alpha1 kind: Mapping metadata: name: iris-grpc namespace: seldon-mesh spec: add_request_headers: seldon-model: value: iris grpc: true hostname: '*' prefix: /inference.GRPCInferenceService rewrite: "" service: seldon-mesh:80 --- apiVersion: getambassador.io/v3alpha1 kind: Mapping metadata: name: iris-http namespace: seldon-mesh spec: add_request_headers: seldon-model: value: iris hostname: '*' prefix: /v2/ rewrite: "" service: seldon-mesh:80 --- apiVersion: mlops.seldon.io/v1alpha1 kind: Model metadata: name: iris namespace: seldon-mesh spec: requirements: - sklearn storageUri: gs://seldon-models/mlserver/iris

3.2 关键参数逐项说明

资源 / 字段值说明
Host.spec.hostname*通配主机名,匹配任意 Host 头
Host.spec.requestPolicy.insecure.actionRoute允许明文(非 TLS)请求直接路由,无需重定向
Listener.spec.port/protocol8080/HTTP监听 8080 端口的 HTTP 流量
Listener.spec.securityModelINSECURE非 TLS 安全模型
Listener.spec.hostBinding.namespace.fromALL允许来自所有命名空间的 Host 绑定
Mapping.spec.prefix/inference.GRPCInferenceServicegRPC 服务前缀,对应 KServe/V2 数据面的 gRPC 服务名
Mapping.spec.prefix/v2/REST 前缀,对应 V2 Inference Protocol 的 REST 路径
Mapping.spec.grpctrue仅 gRPC Mapping 设置,标记为 gRPC 路由
Mapping.spec.serviceseldon-mesh:80上游 Service,即 Seldon 的单一网格端点及其端口
Mapping.spec.rewrite""重写为空字符串,保留原始路径交给上游处理
Mapping.spec.add_request_headers.seldon-modeliris为每个请求注入模型选择头,值为 SeldonModel资源名
Model.spec.storageUrigs://seldon-models/mlserver/iris模型存储位置(本示例为 GCS 上的 MLServer 格式 Iris 模型)
Model.spec.requirements[sklearn]声明模型运行所需的能力(capability),调度器据此匹配 Server

注意 gRPC Mapping 的prefix使用/inference.GRPCInferenceService,这与数据面 gRPC 服务GRPCInferenceService的完整方法名(<Service>/<Method>,如inference.GRPCInferenceService/ModelInfer)对应。该服务定义位于仓库 apis/mlops/v2_dataplane/v2_dataplane.proto,其中包含ModelInfer、ModelReady、ServerLive、ServerMetadata等 RPC,以及 gRPC 调用所需的全部 message 定义(ModelInferRequest、ModelInferResponse、InferTensorContents等)。

3.3 部署与验证流程

以下命令均出自 notebook(ambassador.ipynb),可在安装了 Emissary 的集群上按序执行。

(1)获取 Emissary Ingress 的外部 IP

INGRESS_IP=!kubectl get svc emissary-ingress -n emissary -o jsonpath='{.status.loadBalancer.ingress[0].ip}' INGRESS_IP=INGRESS_IP[0] import os os.environ['INGRESS_IP'] = INGRESS_IP INGRESS_IP

预期输出类似:

'172.21.255.1'

(2)预览将要应用的配置

kustomize build config/single-model

输出即为 3.1 节展示的完整 YAML(Host、Listener、两个 Mapping、一个 Model)。

(3)应用配置

kustomize build config/single-model | kubectl apply --validate=false -f -

预期输出:

host.getambassador.io/wildcard created listener.getambassador.io/emissary-ingress-listener-8080 created mapping.getambassador.io/iris-grpc created mapping.getambassador.io/iris-http created model.mlops.seldon.io/iris created

这里使用--validate=false是因为getambassador.io/v3alpha1与mlops.seldon.io/v1alpha1属于 CRD 资源,跳过 schema 校验以避免版本差异导致的校验失败。

(4)等待模型就绪

kubectl wait --for condition=ready --timeout=300s model --all -n seldon-mesh

预期输出:

model.mlops.seldon.io/iris condition met

(5)通过 REST 端点发起推理

使用 curl 调用 V2 数据面 REST 推理接口(路径POST /v2/models/<模型名>/infer):

curl -v http://${INGRESS_IP}/v2/models/iris/infer -H "Content-Type: application/json"\ -d '{"inputs": [{"name": "predict", "shape": [1, 4], "datatype": "FP32", "data": [[1, 2, 3, 4]]}]}'

完整响应示例:

* Trying 172.21.255.1... * Connected to 172.21.255.1 (172.21.255.1) port 80 (#0) > POST /v2/models/iris/infer HTTP/1.1 > Host: 172.21.255.1 > User-Agent: curl/7.47.0 > Accept: */* > Content-Type: application/json > Content-Length: 94 > * upload completely sent off: 94 out of 94 bytes < HTTP/1.1 200 OK < content-length: 196 < content-type: application/json < date: Sat, 16 Apr 2022 15:45:43 GMT < server: envoy < x-envoy-upstream-service-time: 792 < seldon-route: iris_1 < * Connection #0 to host 172.21.255.1 left intact {"model_name":"iris_1","model_version":"1","id":"72ac79f5-b355-4be3-b8c5-2ebedaa39f60","parameters":null,"outputs":[{"name":"predict","shape":[1],"datatype":"INT64","parameters":null,"data":[2]}]}

需要注意几点:

  • 响应头server: envoy表明请求确实经由 Emissary(基于 Envoy)转发;
  • 响应头seldon-route: iris_1是 Seldon 返回的"粘性会话"路由头(常量x-seldon-route见 scheduler/pkg/util/constants.go),用于标识本次实际执行的模型实例;
  • 返回 JSON 中的model_name为iris_1,这是模型iris当前被调度到的具体实例标识。

(6)通过 gRPC 端点发起推理

使用 grpcurl 调用ModelInfer,需要引用仓库中的 proto 定义文件apis/mlops/v2_dataplane/v2_dataplane.proto:

grpcurl -d '{"model_name":"iris","inputs":[{"name":"input","contents":{"fp32_contents":[1,2,3,4]},"datatype":"FP32","shape":[1,4]}]}' \ -plaintext \ -import-path ../../apis \ -proto ../../apis/mlops/v2_dataplane/v2_dataplane.proto \ ${INGRESS_IP}:80 inference.GRPCInferenceService/ModelInfer

说明:命令中的-import-path ../../apis与-proto ../../apis/mlops/v2_dataplane/v2_dataplane.proto是相对于 notebook 所在目录(service-meshes/ambassador/)的路径;若在其他目录执行,请相应改为从仓库根目录出发的 apis/mlops/v2_dataplane/v2_dataplane.proto。gRPC 请求体采用InferTensorContents的fp32_contents字段携带张量数据(该 message 定义在 proto 文件第 308 行附近)。

预期响应:

{ "modelName": "iris_1", "modelVersion": "1", "outputs": [ { "name": "predict", "datatype": "INT64", "shape": [ "1" ], "contents": { "int64Contents": [ "2" ] } } ] }

(7)清理资源

kustomize build config/single-model | kubectl delete -f -

预期输出:

host.getambassador.io "wildcard" deleted listener.getambassador.io "emissary-ingress-listener-8080" deleted mapping.getambassador.io "iris-grpc" deleted mapping.getambassador.io "iris-http" deleted model.mlops.seldon.io "iris" deleted

四、流量拆分示例:两个模型之间的权重路由

Seldon 原生提供了服务网格无关的Experiment资源来做流量拆分,但如果希望把流量控制交给 Ambassador 层,示例也给出了在两个模型iris1/iris2之间按权重拆分的配置(完整文件见 service-meshes/ambassador/static/traffic-split.yaml,源文件见 config/traffic-split/mappings.yaml 与 config/traffic-split/models.yaml)。

⚠️重要提醒(来自官方文档):流量拆分目前因 Emissary 的已知问题(issue #4062)无法正常工作。官方推荐使用 Seldon 的Experiment资源进行流量拆分,而非依赖 Ambassador 的权重路由。本节配置保留在此仅作为参考示例。

4.1 完整 YAML 配置

apiVersion: getambassador.io/v3alpha1 kind: Host metadata: name: wildcard namespace: seldon-mesh spec: hostname: '*' requestPolicy: insecure: action: Route --- apiVersion: getambassador.io/v3alpha1 kind: Listener metadata: name: emissary-ingress-listener-8080 namespace: seldon-mesh spec: hostBinding: namespace: from: ALL port: 8080 protocol: HTTP securityModel: INSECURE --- apiVersion: getambassador.io/v3alpha1 kind: Mapping metadata: name: iris1-grpc namespace: seldon-mesh spec: add_request_headers: seldon-model: value: iris1 grpc: true hostname: '*' prefix: /inference.GRPCInferenceService rewrite: "" service: seldon-mesh:80 --- apiVersion: getambassador.io/v3alpha1 kind: Mapping metadata: name: iris1-http namespace: seldon-mesh spec: add_request_headers: seldon-model: value: iris1 add_response_headers: seldon_model: value: iris1 hostname: '*' prefix: /v2 rewrite: "" service: seldon-mesh:80 --- apiVersion: getambassador.io/v3alpha1 kind: Mapping metadata: name: iris2-grpc namespace: seldon-mesh spec: add_request_headers: seldon-model: value: iris2 grpc: true hostname: '*' prefix: /inference.GRPCInferenceService rewrite: "" service: seldon-mesh:80 weight: 50 --- apiVersion: getambassador.io/v3alpha1 kind: Mapping metadata: name: iris2-http namespace: seldon-mesh spec: add_request_headers: seldon-model: value: iris2 add_response_headers: seldon_model: value: iris2 hostname: '*' prefix: /v2 rewrite: "" service: seldon-mesh:80 weight: 50 --- apiVersion: mlops.seldon.io/v1alpha1 kind: Model metadata: name: iris1 namespace: seldon-mesh spec: requirements: - sklearn storageUri: gs://seldon-models/mlserver/iris --- apiVersion: mlops.seldon.io/v1alpha1 kind: Model metadata: name: iris2 namespace: seldon-mesh spec: requirements: - sklearn storageUri: gs://seldon-models/mlserver/iris

4.2 与单模型示例的差异要点

  • 定义了两个Model资源(iris1、iris2),使用相同的模型存储gs://seldon-models/mlserver/iris,可分别加载为两个模型实例;
  • iris1的 HTTP Mapping 前缀为/v2,而单模型示例中为/v2/——注意尾部斜杠的细微差别,前缀匹配语义因此不同;
  • iris2的 gRPC 与 HTTP Mapping 都设置了weight: 50,而iris1未显式设置weight(默认为 0),意图是按 50/50 拆分流量;
  • 两个 HTTP Mapping 额外配置了add_response_headers.seldon_model,用于在响应中回传实际服务模型名,便于观察分流结果。

4.3 部署与验证流程

(1)预览并应用配置

kustomize build config/traffic-split kustomize build config/traffic-split | kubectl apply -f -

预期输出:

host.getambassador.io/wildcard created listener.getambassador.io/emissary-ingress-listener-8080 created mapping.getambassador.io/iris1-grpc created mapping.getambassador.io/iris1-http created mapping.getambassador.io/iris2-grpc created mapping.getambassador.io/iris2-http created model.mlops.seldon.io/iris1 created model.mlops.seldon.io/iris2 created

(2)等待模型就绪

kubectl wait --for condition=ready --timeout=300s model --all -n seldon-mesh

预期输出:

model.mlops.seldon.io/iris1 condition met model.mlops.seldon.io/iris2 condition met

(3)REST 推理(注意路径仍使用iris)

curl -v http://${INGRESS_IP}/v2/models/iris/infer -H "Content-Type: application/json" \ -d '{"inputs": [{"name": "predict", "shape": [1, 4], "datatype": "FP32", "data": [[1, 2, 3, 4]]}]}'

预期响应:

* Trying 172.21.255.1... * Connected to 172.21.255.1 (172.21.255.1) port 80 (#0) > POST /v2/models/iris/infer HTTP/1.1 > Host: 172.21.255.1 > User-Agent: curl/7.47.0 > Accept: */* > Content-Type: application/json > Content-Length: 94 > * upload completely sent off: 94 out of 94 bytes < HTTP/1.1 200 OK < content-length: 197 < content-type: application/json < date: Sat, 16 Apr 2022 15:46:17 GMT < server: envoy < x-envoy-upstream-service-time: 920 < seldon-route: iris2_1 < seldon_model: iris2 < * Connection #0 to host 172.21.255.1 left intact {"model_name":"iris2_1","model_version":"1","id":"ed521c32-cd85-4cb8-90eb-7c896803f271","parameters":null,"outputs":[{"name":"predict","shape":[1],"datatype":"INT64","parameters":null,"data":[2]}]}

从响应可以看出,本次请求经 Ambassador 路由后命中iris2(seldon-route: iris2_1、响应头seldon_model: iris2、返回 JSON 中model_name为iris2_1)。注意 curl 的请求 URL 中模型名是iris,实际路由到哪个模型由 Mapping 注入的seldon-model头决定,这也是"单一入口 + 头部路由"设计的直观体现。

(4)gRPC 推理

grpcurl -d '{"model_name":"iris1","inputs":[{"name":"input","contents":{"fp32_contents":[1,2,3,4]},"datatype":"FP32","shape":[1,4]}]}' \ -plaintext \ -import-path ../../apis \ -proto ../../apis/mlops/v2_dataplane/v2_dataplane.proto \ ${INGRESS_IP}:80 inference.GRPCInferenceService/ModelInfer

预期响应(同样命中了iris2实例):

{ "modelName": "iris2_1", "modelVersion": "1", "outputs": [ { "name": "predict", "datatype": "INT64", "shape": [ "1" ], "contents": { "int64Contents": [ "2" ] } } ] }

(5)清理资源

kustomize build config/traffic-split | kubectl delete -f -

预期输出:

host.getambassador.io "wildcard" deleted listener.getambassador.io "emissary-ingress-listener-8080" deleted mapping.getambassador.io "iris1-grpc" deleted mapping.getambassador.io "iris1-http" deleted mapping.getambassador.io "iris2-grpc" deleted mapping.getambassador.io "iris2-http" deleted model.mlops.seldon.io "iris1" deleted model.mlops.seldon.io "iris2" deleted

五、源码视角:流量如何在 Ambassador 与 Seldon 之间衔接

5.1 kustomize 组织方式

service-meshes/ambassador/config/采用 kustomize 的 base/overlay 结构:

  • config/listener/是公共 base,包含 Host 与 Listener(host.yaml、listener.yaml);
  • config/single-model/以 base 为基础,叠加单个模型的Model与两个 Mapping(kustomization.yaml);
  • config/traffic-split/以 base 为基础,叠加两个模型的Model与四个 Mapping(kustomization.yaml)。

两个 overlay 的kustomization.yaml都通过bases: - ../listener复用 Host/Listener,并通过namespace: seldon-mesh统一设置命名空间。这样,网格层的公共配置只需维护一份。

5.2seldon-model头如何驱动路由

  • Ambassador 侧:Mapping 通过add_request_headers.seldon-model注入模型名(Ambassador/Emissary 会在转发时把配置头附加到请求上)。
  • Seldon 侧:seldon-mesh服务背后的 agent 反向代理(scheduler/pkg/agent/rproxy.go)读取seldon-model头确定目标模型,并将内部模型名放入seldon-internal-model头继续向下游转发;gRPC 路径同理(见 scheduler/pkg/agent/rproxy_grpc.go)。
  • 实验(Experiment)场景:seldon-model头还可以携带实验标签,供网格层 Envoy 依据实验规则做流量路由,这正是 scheduler/pkg/util/constants.go 中注释所体现的设计意图。

5.3 数据面协议:REST 与 gRPC 的同一套契约

Ambassador 的 REST Mapping(/v2/)与 gRPC Mapping(/inference.GRPCInferenceService)其实指向同一个 Seldon 数据面协议——KServe V2 / Triton Inference Protocol。协议的服务与 message 定义统一在 apis/mlops/v2_dataplane/v2_dataplane.proto:

  • service GRPCInferenceService提供ServerLive、ServerReady、ModelReady、ServerMetadata、ModelMetadata、ModelInfer、ModelStreamInfer以及控制面相关的RepositoryIndex/RepositoryModelLoad/RepositoryModelUnload;
  • REST 的/v2/models/<model>/infer与 gRPC 的ModelInfer语义一一对应,这也是为什么 curl 与 grpcurl 的请求体可以如此相似(name/shape/datatype/data或contents)。

六、常见问题与注意事项

  1. 流量拆分目前不可用:Ambassador 方式的weight拆分受 Emissary 已知问题(issue #4062)影响,当前无法正常工作。官方建议改用 Seldon 的Experiment资源做网格无关的流量拆分,相关示例可参考 docs-gb/kubernetes/resources/experiment.md。
  2. 前缀斜杠的差异:单模型示例 REST 前缀为/v2/(带尾部斜杠),流量拆分示例为/v2(不带尾部斜杠),两者匹配语义不同,复制配置时注意区分。
  3. --validate=false的必要性:mlops.seldon.io/v1alpha1等 CRD 资源在部分 kubectl 版本下会触发 schema 校验错误,示例中的kubectl apply --validate=false正是为规避此问题。
  4. 外部访问地址:示例通过 LoadBalancer 类型的emissary-ingressService 获取入口 IP,端口 80 对应 Listener 的 8080 端口映射。实际集群中也可能使用 NodePort 或 Ingress Controller 的其它暴露方式,需按环境调整INGRESS_IP。
  5. gRPC 客户端工具:验证 gRPC 端点需要 grpcurl,并须提供 proto 文件;请直接使用仓库内 apis/mlops/v2_dataplane/v2_dataplane.proto,避免自行维护一份可能失配的协议定义。
  • 人工智能
  • 大模型
  • MLOps
  • LLMOps
  • 模型推理服务
  • 云原生
  • 后端

【免费下载链接】seldon-core

An MLOps framework to package, deploy, monitor and manage thousands of production machine learning models

项目地址:https://gitcode.com/gh_mirrors/se/seldon-core
点击查看免费下载

相关推荐

上一篇:如何3D打印Sesame机器人:STL下载、PLA切片参数与支撑设置完整教程
下一篇:HyperFrames Bold Poster 帧设计系统实战:用 FRAME.md 搭建印刷感海报视频帧

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 3:07:05

基于Springboot医院病历管理系统【附源码+文档】

&#x1f495;&#x1f495;作者&#xff1a; 米罗学长 &#x1f495;&#x1f495;个人简介&#xff1a;混迹java圈十余年&#xff0c;精通Java、小程序、数据库等。 &#x1f495;&#x1f495;各类成品Java毕设 。ssm&#xff0c;springboot&#xff0c;vue等项目&#xff0…

作者头像 李华
网站建设 2026/10/14 3:06:42

SpringBoot+Vue构建智能冷链物流系统实战

1. 冷链物流系统概述&#xff1a;当技术遇上生鲜供应链去年夏天帮朋友调试他们生鲜电商的仓储系统时&#xff0c;亲眼目睹了因为温控数据延迟上报导致的一车精品牛排报废——这个价值12万的教训让我深刻意识到&#xff0c;一套可靠的冷链管理系统对现代物流意味着什么。今天我们…

作者头像 李华
网站建设 2026/10/14 3:06:38

SM3算法的各种密码分析方法全面盘点

SM3算法的各种密码分析方法全面盘点对SM3算法的密码分析&#xff0c;目前主要分为针对算法数学结构的分析和针对具体实现的物理攻击两大类。虽然SM3在设计上增强了安全性&#xff0c;但对其实施缩减轮数攻击和侧信道攻击的研究一直在持续。以下是当前主要的密码分析方法盘点&am…

作者头像 李华
网站建设 2026/10/14 3:06:30

C++对象存储SDK集成实战:从编译到分片上传的避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华