Kruise Rollout 全链路灰度实践

2024-01-25 05:52

本文主要是介绍Kruise Rollout 全链路灰度实践,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

作者:旦酱、十眠

什么是全链路灰度?

在发布应用的过程中,我们通常希望用少量特定流量来验证新版本的发布是否正常,以保障整体稳定性。这个过程被称为灰度发布。关于灰度发布,我们通过逐步增加发布的范围,来验证新版本的稳定性。如果新版本出现问题,我们也能及时发现,控制影响范围,保障整体的稳定性。

图片

灰度发布一般具有以下特点:

  • 逐步增加发布的影响范围,拒绝一次性全部发布。
  • 阶段性的发布过程,可以通过金丝雀发布方式小心验证,以验证新版本的稳定性;
  • 可暂停、可回滚、可继续、可自动化状态流转,以便灵活地控制发布过程并确保稳定性;

据调研数据 70% 的线上问题都是由于变更导致,我们常说安全生产三板斧,可灰度、可观测、可回滚,也是为了控制变更带来的风险与影响面。 通过采用灰度发布的方式,我们能够更加稳健地发布新版本,避免因发布过程中出现的问题而带来的损失。

全链路灰度是微服务场景下灰度发布方案的最佳实践,通常每个微服务都会有灰度环境或分组来接受灰度流量。我们希望进入上游灰度环境的流量也能进入下游灰度的环境中,确保1个请求始终在灰度环境中传递,从而形成流量“泳道”。在“泳道”内的流量链路中,即使这个调用链路上有一些微服务应用不存在灰度环境,那么这些微服务应用在请求下游应用的时候依然能够回到下游应用的灰度环境中。

图片

全链路灰度为微服务发布保驾护航

这种方式可以根据服务的实际情况,可以对单个服务可以进行独立的发布和流量控制,也可以控制多个服务同时进行发布变更,从而保证整个系统的稳定性。同时,还可以采用自动化的部署方式,实现快速、可靠的发布过程,提高发布效率和稳定性。

Istio 全链路灰度技术解析

如何通过 Istio 实现全链路灰度能力,想必大家都很关心这个话题,今天我们就详细谈一下基于 istio 实现全链路灰度能力的几个关键技术细节。

流量标签全链路透传

在对微服务进行全链路灰度的过程中,一个最需要考虑的问题是流量中 header 透传的问题,一些微服务会仅保留特定的 header 进行透传,而去除其它 header,利用 Kruise Rollout,可以有效减少发布中对网关资源进行配置的复杂性,但却无法解决 header 透传的问题。如何保证灰度标识能够在链路中一直传递下去呢?分布式链路追踪技术对大型分布式系统中请求调用链路进行详细记录,核心思想就是通过一个全局唯一的 traceid 和每一条的 spanid 来记录请求链路所经过的节点以及请求耗时,其中 traceid 是需要整个链路传递的。借助于分布式链路追踪思想,我们也可以传递一些自定义信息,比如灰度标识。业界常见的分布式链路追踪产品都支持链路传递用户自定义的数据,其数据处理流程如下图所示:

图片

我们可以借助 Tracing Baggage 机制在全链路中传递对应染色标识,因为大部分 Tracing 框架都支持 Baggage 概念及能力,如:OpenTelemetry、Skywalking、Jaeger 等等。我们只需要在 Envoy outbound Filter 中讲指定的透传 key 如 x-mse-tag 从 Tracing 协议指定位置的 Baggage 中读出 x-mse-tag 对应的值,并塞入到 Http 的 Header 中,供 Envoy 进行路由。

流量路由

通过对服务下所有节点按照标签名和标签值不同进行分组,使得订阅该服务节点信息的服务消费端可以按需访问该服务的某个分组,即所有节点的一个子集。服务消费端可以使用服务提供者节点上的任何标签信息,根据所选标签的实际含义,消费端可以将标签路由应用到更多的业务场景中。

图片

在 Istio 中我们可以通过 Istio Gateway、DestinationRule 和 VirtualService 配置路由和外部访问;

节点打标

如何给服务节点添加不同的标签?我们只要在业务应用描述资源 Deployment 中的 Pod 模板中为节点添加标签即可。在使用 Kubernetes Service 作为服务发现的业务系统中,服务提供者通过向 ApiServer 提交 Service 资源完成服务暴露,服务消费端监听与该 Service 资源下关联的 Endpoint 资源,从 Endpoint 资源中获取关联的业务 Pod 资源,读取上面的 Labels 数据并作为该节点的元数据信息。

图片

为什么选择 Kruise Rollout?

从上述技术细节中可以看出,实现基于 Istio 的全链路灰度操作非常复杂且成本较高。首先,需要创建灰度的 Deployment 并打上灰度的节点标识。其次,还需要配置 Istio 的流量路由 CRD,包括每一跳请求的 VirtualService 和 DestinationRule 规则,并且这些流量规则还需要与请求标识相配合。如果只是纸上谈谈技术细节,可能还能勉强理解,但如果真要实践起来,成本确实非常高。同时,如果在配置过程中出现错误,可能会导致生产流量出现问题,对业务造成重大影响。为了降低全链路灰度实践的成本,不得不提 Kruise Rollout 了。

Kruise Rollout [ 1] 是 OpenKruise 社区开源提出的一个渐进式交付框架。其设计理念是提供一组能够将流量发布与实例灰度相结合,支持金丝雀、蓝绿、A/B Testing 等多样化发布形式,以及支持基于 Prometheus Metrics 等自定义 Metrics 实现发布过程自动化,无感对接、易扩展的旁路式标准 Kubernetes 发布组件。

图片

从上图中我们可以看到 OpenKruise Rollout 能够将复杂的灰度发布过程自动化,因此通过 OpenKruise Rollout 可以大幅度降低全链路灰度的实施成本,对于使用者来说只需要配置 Kruise Rollout 的 CRD,然后直接进行应用发布,即可实现全链路灰度发布。

Kruise + Istio 全链路灰度实践

谈完技术实现的细节,下面我们就开始基于 Kruise Rollout 跟 Istio 的全链路灰度能力实践。

配置服务

首先部署两个服务 mocka 和 mockb,服务 mocka 会调用服务 mockb,⚠️服务只会保留流量中的 header my-request-id 而去除其它 header(我们也可以通过接入 OpenTelemetry 实现动态流量标签透传), 整个服务的访问可以表示为:

图片

服务的配置文件为:

apiVersion: v1
kind: Service
metadata:name: mockanamespace: e2elabels:app: mockaservice: mocka
spec:ports:- port: 8000name: httpselector:app: mocka
---
apiVersion: apps/v1
kind: Deployment
metadata:name: mocka-basenamespace: e2elabels:app: mocka
spec:replicas: 1selector:matchLabels:app: mockatemplate:metadata:labels:app: mockaversion: basespec:containers:- name: defaultimage: registry.cn-beijing.aliyuncs.com/aliacs-app-catalog/go-http-sample:1.0imagePullPolicy: Alwaysenv:- name: versionvalue: base- name: appvalue: mocka- name: upstream_urlvalue: "http://mockb:8000/"ports:- containerPort: 8000
---
apiVersion: v1
kind: Service
metadata:name: mockbnamespace: e2elabels:app: mockbservice: mockb
spec:ports:- port: 8000name: httpselector:app: mockb
---
apiVersion: apps/v1
kind: Deployment
metadata:name: mockb-basenamespace: e2elabels:app: mockb
spec:replicas: 1selector:matchLabels:app: mockbtemplate:metadata:labels:app: mockbversion: basespec:containers:- name: defaultimage: registry.cn-beijing.aliyuncs.com/aliacs-app-catalog/go-http-sample:1.0imagePullPolicy: Alwaysenv:- name: versionvalue: base- name: appvalue: mockbports:- containerPort: 8000

服务的 header 部分处理代码如下所示:

// All URLs will be handled by this function
m.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {requestId := r.Header.Get("my-request-id")fmt.Printf("receive request: my-request-id: %s\n", requestId)response := fmt.Sprintf("-> %s(version: %s, ip: %s)", app, version, ip)if url != "" {// 新请求只发送my-request-idcontent := doReq(url, requestId)response = response + content}w.Write([]byte(response))
})

之后部署 Istio Gateway、DestinationRule 和 VirtualService 配置路由和外部访问:

apiVersion: networking.istio.io/v1beta1
kind: Gateway
metadata:name: gatewaynamespace: e2e
spec:selector:istio: ingressgatewayservers:- hosts:- "*"port:name: httpnumber: 80protocol: HTTP
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:name: dr-mockanamespace: e2e
spec:host: mockatrafficPolicy:loadBalancer:simple: ROUND_ROBINsubsets:- labels:version: basename: version-base
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:name: dr-mockbnamespace: e2e
spec:host: mockbtrafficPolicy:loadBalancer:simple: ROUND_ROBINsubsets:- labels:version: basename: version-base
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:name: vs-mockanamespace: e2e
spec:gateways:- simple-gatewayhosts:- "*"http:- route:- destination:host: mockasubset: version-base
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:name: vs-mockbnamespace: e2e
spec:hosts:- mockbhttp:- route:- destination:host: mockbsubset: version-base

部署完成后整个结构如下图所示:

图片

在本地集群中,可以通过运行如下指令获取 Gateway 入口 ip 以及 port 对服务进行访问:

kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}'
kubectl get po -l istio=ingressgateway -n istio-system -o jsonpath='{.items[0].status.hostIP}'

此时运行 curl http://GATEWAY_IP:PORT 可以得到如下结果:

-> mocka(version: base, ip: 10.244.1.36)-> mockb(version: base, ip: 10.244.1.37)

配置 Rollout 和 TrafficRouting 规则

之后部署 Rollout,分别对 mocka 和 mockb 进行控制。Rollout 以及 TrafficRouting 配置的策略如下:

  • 添加了匹配 my-request-id=canary 的 header 规则,包含指定 header 的流量会走灰度环境
  • 为发布的 pod 添加了 label istio.service.tag=gray 以及 version=canary

⚠️pod label 的添加规则是什么?

在配置中为新版本 pod 打上了两个 label,其中 istio.service.tag=gray 的目的是为了在 DestinationRule 中指定包含该 label 的 pod 作为一个 subset,lua 脚本会为 DestinationRule 自动添加该 Subset。添加 version=canary 的目的是为了覆盖原始版本中的 version=baselabel,如果不覆盖该 label, 原始 DestinationRule 也会将稳定版本的流量导入新版本 pod 中。

apiVersion: rollouts.kruise.io/v1alpha1
kind: Rollout
metadata:name: rollouts-anamespace: demoannotations:rollouts.kruise.io/rolling-style: canaryrollouts.kruise.io/trafficrouting: mocka-tr
spec:disabled: falseobjectRef:workloadRef:apiVersion: apps/v1kind: Deploymentname: mocka-basestrategy:canary:steps:- replicas: 1patchPodTemplateMetadata:labels:istio.service.tag: grayversion: canary
---
apiVersion: rollouts.kruise.io/v1alpha1
kind: TrafficRouting
metadata:name: mocka-trnamespace: demo
spec:strategy:matches:- headers:- type: Exactname: my-request-idvalue: canaryobjectRef:- service: mockacustomNetworkRefs:- apiVersion: networking.istio.io/v1alpha3kind: VirtualServicename: vs-mocka- apiVersion: networking.istio.io/v1beta1kind: DestinationRulename: dr-mocka
---
apiVersion: rollouts.kruise.io/v1alpha1
kind: Rollout
metadata:name: rollouts-bnamespace: demoannotations:rollouts.kruise.io/rolling-style: canaryrollouts.kruise.io/trafficrouting: mockb-tr
spec:disabled: falseobjectRef:workloadRef:apiVersion: apps/v1kind: Deploymentname: mockb-basestrategy:canary:steps:- replicas: 1patchPodTemplateMetadata:labels:istio.service.tag: grayversion: canary
---
apiVersion: rollouts.kruise.io/v1alpha1
kind: TrafficRouting
metadata:name: mockb-trnamespace: demo
spec:strategy:matches:- headers:- type: Exactname: my-request-idvalue: canaryobjectRef:- service: mockbcustomNetworkRefs:- apiVersion: networking.istio.io/v1alpha3kind: VirtualServicename: vs-mockb- apiVersion: networking.istio.io/v1beta1kind: DestinationRulename: dr-mockb

开始灰度发布

修改 mocka 和 mockb 中的环境变量为 version=canary 开始发布。Kruise Rollout 将自动获取网关资源并进行修改,此时查看 VirtualService 和 DestinationRule 可以得到,VirtualService 定义了路由规则将带有 my-request-id=canary 的 header 的流量路由至 canary 版本。DestinationRule 添加了对于包含 label istio.service.tag=gray 新的 Subset。

apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:annotations:kubectl.kubernetes.io/last-applied-configuration: |{"apiVersion":"networking.istio.io/v1beta1","kind":"VirtualService","metadata":{"annotations":{},"name":"vs-mocka","namespace":"demo"},"spec":{"gateways":["simple-gateway"],"hosts":["*"],"http":[{"route":[{"destination":{"host":"mocka","subset":"version-base"}}]}]}}rollouts.kruise.io/origin-spec-configuration: '{"spec":{"gateways":["simple-gateway"],"hosts":["*"],"http":[{"route":[{"destination":{"host":"mocka","subset":"version-base"}}]}]},"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"networking.istio.io/v1beta1\",\"kind\":\"VirtualService\",\"metadata\":{\"annotations\":{},\"name\":\"vs-mocka\",\"namespace\":\"demo\"},\"spec\":{\"gateways\":[\"simple-gateway\"],\"hosts\":[\"*\"],\"http\":[{\"route\":[{\"destination\":{\"host\":\"mocka\",\"subset\":\"version-base\"}}]}]}}\n"}}'creationTimestamp: "2023-09-12T07:49:15Z"generation: 40name: vs-mockanamespace: demoresourceVersion: "98670"uid: c7da3a99-789c-4f1e-93a4-caaee41cbe06
spec:gateways:- simple-gatewayhosts:- '*'http:# -- lua脚本自动添加的规则- match:- headers:my-request-id:exact: canaryroute:- destination:host: mockasubset: canary# --- route:- destination:host: mockasubset: version-base
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:annotations:kubectl.kubernetes.io/last-applied-configuration: |{"apiVersion":"networking.istio.io/v1beta1","kind":"VirtualService","metadata":{"annotations":{},"name":"vs-mockb","namespace":"demo"},"spec":{"hosts":["mockb"],"http":[{"route":[{"destination":{"host":"mockb","subset":"version-base"}}]}]}}rollouts.kruise.io/origin-spec-configuration: '{"spec":{"hosts":["mockb"],"http":[{"route":[{"destination":{"host":"mockb","subset":"version-base"}}]}]},"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"networking.istio.io/v1beta1\",\"kind\":\"VirtualService\",\"metadata\":{\"annotations\":{},\"name\":\"vs-mockb\",\"namespace\":\"demo\"},\"spec\":{\"hosts\":[\"mockb\"],\"http\":[{\"route\":[{\"destination\":{\"host\":\"mockb\",\"subset\":\"version-base\"}}]}]}}\n"}}'creationTimestamp: "2023-09-12T07:49:16Z"generation: 40name: vs-mockbnamespace: demoresourceVersion: "98677"uid: 7c96ee2b-96ce-48e4-ba6d-cf94171ed854
spec:hosts:- mockbhttp:# -- lua脚本自动添加的规则- match:- headers:my-request-id:exact: canaryroute:- destination:host: mockbsubset: canary# -- - route:- destination:host: mockbsubset: version-base
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:annotations:kubectl.kubernetes.io/last-applied-configuration: |{"apiVersion":"networking.istio.io/v1beta1","kind":"DestinationRule","metadata":{"annotations":{},"name":"dr-mocka","namespace":"demo"},"spec":{"host":"mocka","subsets":[{"labels":{"version":"base"},"name":"version-base"}],"trafficPolicy":{"loadBalancer":{"simple":"ROUND_ROBIN"}}}}rollouts.kruise.io/origin-spec-configuration: '{"spec":{"host":"mocka","subsets":[{"labels":{"version":"base"},"name":"version-base"}],"trafficPolicy":{"loadBalancer":{"simple":"ROUND_ROBIN"}}},"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"networking.istio.io/v1beta1\",\"kind\":\"DestinationRule\",\"metadata\":{\"annotations\":{},\"name\":\"dr-mocka\",\"namespace\":\"demo\"},\"spec\":{\"host\":\"mocka\",\"subsets\":[{\"labels\":{\"version\":\"base\"},\"name\":\"version-base\"}],\"trafficPolicy\":{\"loadBalancer\":{\"simple\":\"ROUND_ROBIN\"}}}}\n"}}'creationTimestamp: "2023-09-12T07:49:15Z"generation: 12name: dr-mockanamespace: demoresourceVersion: "98672"uid: a6f49044-e889-473c-b188-edbdb8ee347f
spec:host: mockasubsets:- labels:version: basename: version-base# -- lua脚本自动添加的规则- labels:istio.service.tag: grayname: canary# --trafficPolicy:loadBalancer:simple: ROUND_ROBIN
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:annotations:kubectl.kubernetes.io/last-applied-configuration: |{"apiVersion":"networking.istio.io/v1beta1","kind":"DestinationRule","metadata":{"annotations":{},"name":"dr-mockb","namespace":"demo"},"spec":{"host":"mockb","subsets":[{"labels":{"version":"base"},"name":"version-base"}],"trafficPolicy":{"loadBalancer":{"simple":"ROUND_ROBIN"}}}}rollouts.kruise.io/origin-spec-configuration: '{"spec":{"host":"mockb","subsets":[{"labels":{"version":"base"},"name":"version-base"}],"trafficPolicy":{"loadBalancer":{"simple":"ROUND_ROBIN"}}},"annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"networking.istio.io/v1beta1\",\"kind\":\"DestinationRule\",\"metadata\":{\"annotations\":{},\"name\":\"dr-mockb\",\"namespace\":\"demo\"},\"spec\":{\"host\":\"mockb\",\"subsets\":[{\"labels\":{\"version\":\"base\"},\"name\":\"version-base\"}],\"trafficPolicy\":{\"loadBalancer\":{\"simple\":\"ROUND_ROBIN\"}}}}\n"}}'creationTimestamp: "2023-09-12T07:49:15Z"generation: 12name: dr-mockbnamespace: demoresourceVersion: "98678"uid: 4bd0f6c5-efa1-4558-9e31-6f7615c21f9a
spec:host: mockbsubsets:- labels:version: basename: version-base# -- lua脚本自动添加的规则- labels:istio.service.tag: grayname: canary# --trafficPolicy:loadBalancer:simple: ROUND_ROBIN

此时运行 curl http://GATEWAY_IP:PORT 可以得到如下结果,所有流量均通过 base 版本服务。

-> mocka(version: base, ip: 10.244.1.36)-> mockb(version: base, ip: 10.244.1.37)

此时运行 curl -H http://GATEWAY_IP:PORT -Hmy-request-id:canary 可以得到如下结果,所有流量均通过 canary 版本服务。

-> mocka(version: canary, ip: 10.244.1.41)-> mockb(version: canary, ip: 10.244.1.42)

此时整个服务的流量可以表示为下图,包含 headermy-request-id=canary 的流量全部走灰度环境,其它流量全部走基线环境:

图片

(可选)利用 EnvoyFilter 进行流量染色

我们可以通过编写 EnvoyFilter 进一步简化流量染色的步骤,在之前的例子中,在请求的时候包含了可以透传的 header my-request-id,如果想要实现更加通用的 header 请求规则,例如包含 agent=pc 的流量全部走灰度环境,其它则走基线环境,则可以通过 EnvoyFilter 在入口网关进行染色。以下定义了一个 EnvoyFilter,该 EnvoyFilter 定义了一个 Lua 脚本,会对包含 agent=pc 的流量染色,为其添加 my-request-id=canary,而其它流量则添加 my-request-id=base。


apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:name: http-request-labelling-according-sourcenamespace: istio-system
spec:workloadSelector:labels:app: istio-ingressgatewayconfigPatches:- applyTo: HTTP_FILTERmatch:context: GATEWAYlistener:filterChain:filter:name: "envoy.filters.network.http_connection_manager"subFilter:name: "envoy.filters.http.router"patch:operation: INSERT_BEFOREvalue:name: envoy.luatyped_config:"@type": "type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua"inlineCode: |function envoy_on_request(request_handle)local header = "agent"headers = request_handle:headers()version = headers:get(header)if (version ~= nil) thenif (version == "pc") thenheaders:add("my-request-id","canary")elseheaders:add("my-request-id","base")endelseheaders:add("my-request-id","base")endend

保持其它配置不变,此时运行 curl http://GATEWAY_IP:PORT 可以得到如下结果,所有流量均通过 base 版本服务。

-> mocka(version: base, ip: 10.244.1.36)-> mockb(version: base, ip: 10.244.1.37)

此时运行 curl -H http://GATEWAY_IP:PORT -Hagent:pc 可以得到如下结果,EnvoyFilter 自动为该流量添加 headermy-request-id=canary,因此所有流量均通过新版本服务。

-> mocka(version: canary, ip: 10.244.1.41)-> mockb(version: canary, ip: 10.244.1.42)

完整的全链路灰度方案

Kruise Rollout 除了支持开源的 Istio 实现全链路灰度外,还支持与 MSE 实现完整的全链路灰度方案,我们可以通过如下操作文档 [ 2] 快速实现体系化的全链路灰度能力。

图片MSE 全链路灰度可以有效地控制流量在前端、网关、后端各个微服务等组件中闭环,不仅仅是 RPC/Http 的流量,对于异步调用比如 MQ 流量也支持符合全链路“泳道”调用的规则。通过 Kruise Rollout 跟 MSE 可以帮助我们更加便捷地实现微服务全链路灰度发布,提高微服务场景下发布的效率和稳定性。

加入 OpenKruise 社区

最后,非常欢迎你通过 Github/Slack/钉钉/微信 等方式加入我们来参与 OpenKruise 开源社区。

  • 加入社区 Slack channel (English)
  • 加入社区钉钉群:搜索群号 23330762 (Chinese)
  • 加入社区微信群(新):添加用户 openkruise 并让机器人拉你入群 (Chinese)

相关链接:

[1] Kruise Rollout

https://openkruise.io/rollouts/introduction

[2] 操作文档

https://help.aliyun.com/zh/mse/user-guide/implement-mse-based-end-to-end-canary-release-by-using-kruise-rollouts?spm=a2c4g.11186623.0.0.1d5a79dezV82UH

这篇关于Kruise Rollout 全链路灰度实践的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/642274

相关文章

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

Prometheus与Grafana在DevOps中的应用与最佳实践

Prometheus 与 Grafana 在 DevOps 中的应用与最佳实践 随着 DevOps 文化和实践的普及,监控和可视化工具已成为 DevOps 工具链中不可或缺的部分。Prometheus 和 Grafana 是其中最受欢迎的开源监控解决方案之一,它们的结合能够为系统和应用程序提供全面的监控、告警和可视化展示。本篇文章将详细探讨 Prometheus 和 Grafana 在 DevO

springboot整合swagger2之最佳实践

来源:https://blog.lqdev.cn/2018/07/21/springboot/chapter-ten/ Swagger是一款RESTful接口的文档在线自动生成、功能测试功能框架。 一个规范和完整的框架,用于生成、描述、调用和可视化RESTful风格的Web服务,加上swagger-ui,可以有很好的呈现。 SpringBoot集成 pom <!--swagge

vue2实践:el-table实现由用户自己控制行数的动态表格

需求 项目中需要提供一个动态表单,如图: 当我点击添加时,便添加一行;点击右边的删除时,便删除这一行。 至少要有一行数据,但是没有上限。 思路 这种每一行的数据固定,但是不定行数的,很容易想到使用el-table来实现,它可以循环读取:data所绑定的数组,来生成行数据,不同的是: 1、table里面的每一个cell,需要放置一个input来支持用户编辑。 2、最后一列放置两个b

【HarmonyOS】-TaskPool和Worker的对比实践

ArkTS提供了TaskPool与Worker两种多线程并发方案,下面我们将从其工作原理、使用效果对比两种方案的差异,进而选择适用于ArkTS图片编辑场景的并发方案。 TaskPool与Worker工作原理 TaskPool与Worker两种多线程并发能力均是基于 Actor并发模型实现的。Worker主、子线程通过收发消息进行通信;TaskPool基于Worker做了更多场景化的功能封装,例

vue2实践:第一个非正规的自定义组件-动态表单对话框

前言 vue一个很重要的概念就是组件,作为一个没有经历过前几代前端开发的我来说,不太能理解它所带来的“进步”,但是,将它与后端c++、java类比,我感觉,组件就像是这些语言中的类和对象的概念,通过封装好的组件(类),可以通过挂载的方式,非常方便的调用其提供的功能,而不必重新写一遍实现逻辑。 我们常用的element UI就是由饿了么所提供的组件库,但是在项目开发中,我们可能还需要额外地定义一

《C++中的移动构造函数与移动赋值运算符:解锁高效编程的最佳实践》

在 C++的编程世界中,移动构造函数和移动赋值运算符是提升程序性能和效率的重要工具。理解并正确运用它们,可以让我们的代码更加高效、简洁和优雅。 一、引言 随着现代软件系统的日益复杂和对性能要求的不断提高,C++程序员需要不断探索新的技术和方法来优化代码。移动构造函数和移动赋值运算符的出现,为解决资源管理和性能优化问题提供了有力的手段。它们允许我们在不进行不必要的复制操作的情况下,高效地转移资源

Vue3+elementplus实现图片上传下载(最强实践)

图片上传子组件: 实现照片的上传,预览,以及转成以逗号隔开的图片地址,即时监听,并发送消息到父组件。 <!-- ImageUploader.vue --> <template><div><el-upload class="avatar-uploader" :http-request="customUpload" :before-upload="beforeUpload":show-fil

Banana Pi BPI-F3 进迭时空RISC-V架构下,AI融合算力及其软件栈实践

RISC-V架构下,AI融合算力及其软件栈实践 面对未来大模型(LLM)、AIGC等智能化浪潮的挑战,进迭时空在RISC-V方向全面布局,通过精心设计的RISC-V DSA架构以及软硬一体的优化策略,将全力为未来打造高效且易用的AI算力解决方案。目前,进迭时空已经取得了显著的进展,成功推出了第一个版本的智算核(带AI融合算力的智算CPU)以及配套的AI软件栈。 软件栈简介 AI算法部署旨