基于WASM的无侵入式全链路A/B Test实践

简介: 我们都知道,服务网格(ServiceMesh)可以为运行其上的微服务提供无侵入式的流量治理能力。通过配置VirtualService和DestinationRule,即可实现流量管理、超时重试、流量复制、限流、熔断等功能,而无需修改微服务代码。 本文所述的实践是根据请求Header实现全链路A/B测试。

1 背景介绍

我们都知道,服务网格(ServiceMesh)可以为运行其上的微服务提供无侵入式的流量治理能力。通过配置VirtualService和DestinationRule,即可实现流量管理、超时重试、流量复制、限流、熔断等功能,而无需修改微服务代码。

流量管理的前提是一个服务存在多个版本,我们可以按部署多版本的目的进行分类,简述如下,以方便理解余文。

  • traffic routing:根据请求信息(Header/Cookie/Query Params),将请求流量路由到指定服务(Service)的指定版本(Deployment)的端点上(Pod[])。就是我们所说的A/B测试(A/B Testing)。
  • traffic shifting:通过灰度/金丝雀(Canary)发布,将请求流量无差别地按比例路由到指定服务(Service)的各个版本(Deployment[])的端点上(Pod[])。
  • traffic switching/mirroring:通过蓝绿(Blue/Green)发布,根据请求信息按比例进行流量切换,以及进行流量复制。

本文所述的实践是根据请求Header实现全链路A/B测试。

1.1 功能简述

从Istio社区的文档,我们很容易找到关于如何根据请求Header将流量路由到一个服务的特定版本的文档和示例。但是这个示例只能在全链路的第一个服务上生效。

举例来说,一个请求要访问A-B-C三个服务,这三个服务都有en版本和fr版本。我们期待:

  • header值为user:en的请求,全链路路由为A1-B1-C1
  • header值为user:fr的请求,全链路路由为A2-B2-C2

相应的VirtualService配置如下所示:

http:
- name: A|B|C-routematch:- headers:user:exact: enroute:- destination:host: A|B|C-svcsubset: v1
- route:- destination:host: A|B|C-svcsubset: v2

我们通过实测可以发现,只有A这个服务的路由是符合我们预期的。B和C无法做到根据Header值路由到指定版本。

 

这是为什么呢?对于服务网格其上的微服务来说,这个header是凭空出现的,也就是微服务代码无感知。因此,当A服务请求B服务时,不会透传这个header;也就是说,当A请求B时,这个header已经丢失了。这时,这个匹配header进行路由的VirtualService配置已经毫无意义。

要解决这个问题,从微服务方的业务角度看,只能修改代码(枚举业务关注的全部header并透传)。但这是一种侵入式的修改,而且无法灵活地支持新出现的header。

从服务网格的基础设施角度看,任何header都是没有业务意义且要被透传的kv pair。只有做到这点,服务网格才能实现无差别地透传用户自定义的header,从而支持无侵入式全链路A/B Test功能。

那么该怎样实现呢?

1.2 社区现状

前面已经说明,在header无法透传的情况下,单纯地配置VirtualService的header匹配是无法实现这个功能的。

但是,在VirtualService中是否存在其他配置,可以实现header透传呢?如果存在,那么单纯使用VirtualService,代价是最小的。

经过各种尝试(包括精心配置header相关的set/add),我发现无法实现。原因是VirtualService对header的干预发生在inbound阶段,而透传是需要在outbound阶段干预header的。而微服务workload没有能力对凭空出现的header值进行透传,因此在路由到下一个服务时,这个header就会丢失。

 

因此,我们可以得出一个结论:无法单纯使用VirtualService实现无侵入式全链路A/B Test,进一步地说,社区提供的现有配置都无法做到直接使用就能支持这个功能。

那么,就只剩下EnvoyFilter这个更高级的配置了。这是我们一开始很不希望的结论。原因有两个:

  1. EnvoyFilter的配置太过复杂,一般用户很难在服务网格中快速学习和使用,即便我们提供示例,一旦需求稍有变化,示例对修改EnvoyFilter的参考价值甚微。
  2. 就算使用EnvoyFilter,目前Envoy内置的filter也没有直接支持这个功能的,需要借助Lua或者WebAssembly(WASM)进行开发。

1.3 实现方案

接下来进入技术选型。我用一句话来概括:

  • Lua的优点是小巧,缺点是性能不理想
  • WASM的优点是性能好,缺点是开发和分发相比Lua要困难。
  • WASM的实现主流是C++和Rust,其他语言的实现尚不成熟或者存在性能问题。本文使用的是Rust。

我们使用Rust开发一个WASM,在outbound阶段,获取用户在EnvoyFilter中定义的header并向后传递。

WASM包的分发使用Kubernetes的configmap存储,Pod通过annotation中的定义获取WASM配置并加载。(为什么使用这种分发形式,后面会讲。)

 

2 技术实现

本节所述的相关代码:

https://github.com/AliyunContainerService/rust-wasm-4-envoy/tree/master/propagate-headers-filter

2.1 使用RUST实现WASM

1 定义依赖

WASM工程的核心依赖crates只有一个,就是proxy-wasm,这是使用Rust开发WASM的基础包。此外,还有用于反序列化的包serde_json和用于打印日志的包log。Cargo.toml定义如下:

[dependencies]
proxy-wasm = "0.1.3"
serde_json = "1.0.62"
log = "0.4.14"

2 定义构建

WASM的最终构建形式是兼容c的动态链接库,Cargo.toml定义如下:

[lib]
name = "propaganda_filter"
path = "src/propagate_headers.rs"
crate-type = ["cdylib"]

3 Header透传功能

首先定义结构体如下,head_tag_name是用户自定义的header键的名称,head_tag_value是对应值的名称。

struct PropagandaHeaderFilter {config: FilterConfig,
}struct FilterConfig {head_tag_name: String,head_tag_value: String,
}

{proxy-wasm}/src/traits.rs中的trait HttpContext定义了on_http_request_headers方法。我们通过实现这个方法来完成Header透传的功能。

impl HttpContext for PropagandaHeaderFilter {fn on_http_request_headers(&mut self, _: usize) -> Action {let head_tag_key = self.config.head_tag_name.as_str();info!("::::head_tag_key={}", head_tag_key);if !head_tag_key.is_empty() {self.set_http_request_header(head_tag_key, Some(self.config.head_tag_value.as_str()));self.clear_http_route_cache();}for (name, value) in &self.get_http_request_headers() {info!("::::H[{}] -> {}: {}", self.context_id, name, value);}Action::Continue}
}

第3-6行是获取配置文件中用户自定义的header键值对,如果存在就调用set_http_request_header方法,将键值对写入当前header。

第7行是对当前proxy-wasm实现的一个workaround,如果你对此感兴趣可以阅读如下参考:

  • https://github.com/istio/istio/issues/30545#issuecomment-783518257
  • https://github.com/proxy-wasm/spec/issues/16
  • https://www.elvinefendi.com/2020/12/09/dynamic-routing-envoy-wasm.html

2.2 本地验证(基于Envoy)

1 WASM构建

使用如下命令构建WASM工程。需要强调的是wasm32-unknown-unknown这个target目前只存在于nightly中,因此在构建之前需要临时切换构建环境。

rustup override set nightly
cargo build --target=wasm32-unknown-unknown --release

构建完成后,我们在本地使用docker compose启动Envoy,对WASM功能进行验证。

2 Envoy配置

本例需要为Envoy启动提供两个文件,一个是构建好的propaganda_filter.wasm,一个是Envoy配置文件envoy-local-wasm.yaml。示意如下:

volumes:- ./config/envoy/envoy-local-wasm.yaml:/etc/envoy-local-wasm.yaml- ./target/wasm32-unknown-unknown/release/propaganda_filter.wasm:/etc/propaganda_filter.wasm

Envoy支持动态配置,本地测试采用静态配置:

static_resources:listeners:- address:socket_address:address: 0.0.0.0port_value: 80filter_chains:- filters:- name: envoy.filters.network.http_connection_manager
...http_filters:- name: envoy.filters.http.wasmtyped_config:"@type": type.googleapis.com/udpa.type.v1.TypedStructtype_url: type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasmvalue:config:name: "header_filter"root_id: "propaganda_filter"configuration:"@type": "type.googleapis.com/google.protobuf.StringValue"value: |{"head_tag_name": "custom-version","head_tag_value": "hello1-v1"}vm_config:runtime: "envoy.wasm.runtime.v8"vm_id: "header_filter_vm"code:local:filename: "/etc/propaganda_filter.wasm"allow_precompiled: true
...

Envoy的配置重点关注如下3点:

  • 15行 我们在http_filters中定义了一个名称为header_filter的type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm
  • 32行 本地文件路径为/etc/propaganda_filter.wasm
  • 20-26行 相关配置的类型是type.googleapis.com/google.protobuf.StringValue,值的内容是{"head_tag_name": "custom-version","head_tag_value": "hello1-v1"}。这里自定义的Header键名为custom-version,值为hello1-v1。

3 本地验证

执行如下命令启动docker compose:

docker-compose up --build

请求本地服务:

curl -H "version-tag":"v1" "localhost:18000"

此时Envoy的日志应有如下输出:

proxy_1        | [2021-02-25 06:30:09.217][33][info][wasm] [external/envoy/source/extensions/common/wasm/context.cc:1152] wasm log: ::::create_http_context head_tag_name=custom-version,head_tag_value=hello1-v1
proxy_1        | [2021-02-25 06:30:09.217][33][info][wasm] [external/envoy/source/extensions/common/wasm/context.cc:1152] wasm log: ::::head_tag_key=custom-version
...
proxy_1        | [2021-02-25 06:30:09.217][33][info][wasm] [external/envoy/source/extensions/common/wasm/context.cc:1152] wasm log: ::::H[2] -> custom-version: hello1-v1

2.3 WASM的分发方式

WASM的分发是指将WASM包存储于一个分布式仓库中,供指定的Pod拉取的过程。

1 Configmap + Envoy的Local方式

虽然这种方式不是WASM分发的终态,但是因为它较为容易理解且适合简单的场景,本例最终选择了这个方案作为示例讲解。虽然configmap的本职工作不是存WASM的,但是configmap和Envoy的local模式都很成熟,两者结合恰能满足当前需求。

阿里云服务网格ASM产品已经提供了这种类似的方式,具体可以参考 为Envoy编写WASM Filter并部署到ASM中。

要把WASM包塞到配置中,首要考虑的是包的尺寸。我们使用wasm-gc进行包裁剪,示意如下:

ls -hl target/wasm32-unknown-unknown/release/propaganda_filter.wasm
wasm-gc ./target/wasm32-unknown-unknown/release/propaganda_filter.wasm ./target/wasm32-unknown-unknown/release/propaganda-header-filter.wasm
ls -hl target/wasm32-unknown-unknown/release/propaganda-header-filter.wasm

执行结果如下,可以看到裁剪前后,包的尺寸对比:

-rwxr-xr-x  2 han  staff   1.7M Feb 25 15:38 target/wasm32-unknown-unknown/release/propaganda_filter.wasm
-rw-r--r--  1 han  staff   136K Feb 25 15:38 target/wasm32-unknown-unknown/release/propaganda-header-filter.wasm

创建configmap:

wasm_image=target/wasm32-unknown-unknown/release/propaganda-header-filter.wasm
kubectl -n $NS create configmap -n $NS propaganda-header --from-file=$wasm_image

为指定Deployment打Patch:

patch_annotations=$(cat config/annotations/patch-annotations.yaml)
kubectl -n $NS patch deployment "hello$i-deploy-v$j" -p "$patch_annotations"

patch-annotations.yaml如下:

spec:template:metadata:annotations:sidecar.istio.io/userVolume: '[{"name":"wasmfilters-dir","configMap": {"name":"propaganda-header"}}]'sidecar.istio.io/userVolumeMount: '[{"mountPath":"/var/local/lib/wasm-filters","name":"wasmfilters-dir"}]'

2 Envoy的Remote方式

Envoy同时支持local和remote形式的资源定义。对比如下:

vm_config:runtime: "envoy.wasm.runtime.v8"vm_id: "header_filter_vm"code:local:filename: "/etc/propaganda_filter.wasm"
vm_config:runtime: "envoy.wasm.runtime.v8"code:remote:http_uri:uri: "http://*.*.*.216:8000/propaganda_filter.wasm"cluster: web_servicetimeout:seconds: 60sha256: "da2e22*"

remote方式是最接近原始Enovy的,因此这种方式本来是本例的首选。但是实测过程中发现在包的hash校验上存在问题,详见下方参考。并且,Envoy社区的大牛周礼赞反馈我说remote不是Envoy支持WASM分发的未来方向。因此,本例最终放弃这种方式。

  • https://stackoverflow.com/questions/65871312/how-to-set-the-sha256-hex-in-envoy-wasm-remote-config
  • https://envoyproxy.slack.com/archives/C78M4KW76/p1611496672017500

3 ORAS + Local方式

ORAS是OCI Artifacts项目的参考实现,可显著简化OCI注册表中任意内容的存储。

使用ORAS客户端或者API/SDK的方式将具有允许的媒体类型的Wasm模块推送到注册库(一个OCI兼容的注册库)中,然后通过控制器将Wasm Filter部署到指定工作负载对应的Pod中,以Local的方式进行挂载。

阿里云服务网格ASM产品中提供了对WebAssembly(WASM)技术的支持,服务网格使用人员可以把扩展的WASM Filter通过ASM部署到数据面集群中相应的Envoy代理中。通过ASMFilterDeployment Controller组件, 可以支持动态加载插件、简单易用、以及支持热更新等能力。具体来说,ASM产品提供了一个新的CRD ASMFilterDeployment以及相关的controller组件。这个controller组件会监听ASMFilterDeployment资源对象的情况,会做2个方面的事情:

  • 创建出用于控制面的Istio EnvoyFilter Custom Resource,并推送到对应的asm控制面istiod中
  • 从OCI注册库中拉取对应的wasm filter镜像,并挂载到对应的workload pod中

具体可以参考:基于Wasm和ORAS简化扩展服务网格功能。

后续的实践分享将会使用这种方式进行WASM的分发,敬请期待。

类似地,业界其他友商也在推进这种方式,特别是Solo.io提供了一整套WASM的开发框架wasme,基于该框架可以开发-构建-分发WASM包(OCI image)并部署到Webassembly Hub。这个方案的优点很明显,完整地支持了WASM的开发到上线的生命周期。但这个方案的缺点也非常明显,wasme的自包含导致了很难将其拆分,并扩展到solo体系之外。

阿里云服务网格ASM团队正在与包括solo在内的业界相关团队交流如何共同推进Wasm filter的OCI规范以及相应的生命周期管理,以帮助客户可以轻松扩展Envoy的功能并将其在服务网格中的应用推向了新的高度。

2.4 集群验证(基于Istio)

1 实验示例

WASM分发到Kubernetes的configmap后,我们可以进行集群验证了。示例(源代码)包含3个Service:hello1-hello2-hello3,每个服务包含2个版本:v1/en和v2/fr。

每个Service配置了VirtualService和DestinationRule用来定义匹配Header并路由到指定版本。

apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:name: hello2-vs
spec:hosts:- hello2-svchttp:- name: hello2-v2-routematch:- headers:route-v:exact: hello2v2route:- destination:host: hello2-svcsubset: hello2v2- route:- destination:host: hello2-svcsubset: hello2v1
----
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:name: hello2-dr
spec:host: hello2-svcsubsets:- name: hello2v1labels:version: v1- name: hello2v2labels:version: v2

Envoyfilter示意如下:

apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:name: hello1v2-propaganda-filter
spec:workloadSelector:labels:app: hello1-deploy-v2version: v2configPatches:- applyTo: HTTP_FILTERmatch:context: SIDECAR_OUTBOUNDproxy:proxyVersion: "^1\\.8\\.*"listener:filterChain:filter:name: envoy.filters.network.http_connection_managersubFilter:name: envoy.filters.http.routerpatch:operation: INSERT_BEFOREvalue:name: envoy.filters.http.wasmtyped_config:"@type": type.googleapis.com/udpa.type.v1.TypedStructtype_url: type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasmvalue:config:name: propaganda_filterroot_id: propaganda_filter_rootconfiguration:'@type': type.googleapis.com/google.protobuf.StringValuevalue: |{"head_tag_name": "route-v","head_tag_value": "hello2v2"}vm_config:runtime: envoy.wasm.runtime.v8vm_id: propaganda_filter_vmcode:local:filename: /var/local/lib/wasm-filters/propaganda-header-filter.wasmallow_precompiled: true

2 验证方法

携带header的请求curl -H "version:v1" "http://$
ingressGatewayIp:8001/hello/xxx"通过istio-ingressgateway进入,全链路按header值,进入服务的指定版本。这里,由于header中指定了version为v2,那么全链路将
为hello1 v2-hello2 v2-hello3 v2。效果如下图所示。

 

验证过程和结果示意如下。

for i in {1..5}; docurl -s -H "route-v:v2" "http://$ingressGatewayIp:$PORT/hello/eric" >>resultecho >>result
done
check=$(grep -o "Bonjour eric" result | wc -l)
if [[ "$check" -eq "15" ]]; thenecho "pass"
elseecho "fail"exit 1
fi

result:

Bonjour eric@hello1:172.17.68.205<Bonjour eric@hello2:172.17.68.206<Bonjour eric@hello3:172.17.68.182
Bonjour eric@hello1:172.17.68.205<Bonjour eric@hello2:172.17.68.206<Bonjour eric@hello3:172.17.68.182
Bonjour eric@hello1:172.17.68.205<Bonjour eric@hello2:172.17.68.206<Bonjour eric@hello3:172.17.68.182
Bonjour eric@hello1:172.17.68.205<Bonjour eric@hello2:172.17.68.206<Bonjour eric@hello3:172.17.68.182
Bonjour eric@hello1:172.17.68.205<Bonjour eric@hello2:172.17.68.206<Bonjour eric@hello3:172.17.68.182

我们看到,输出信息Bonjour eric来自各个服务的fr版本,说明功能验证通过。

3 性能分析

新增EnvoyFilter+WASM后,功能验证通过,但这会带来多少延迟开销呢?这是服务网格的提供者和使用者都非常关心的问题。本节将对如下两个关注点进行验证。

  • 增加EnvoyFilter+WASM后的增量延迟开销情况
  • WASM版本和Lua版本的开销对比

3.1 Lua实现

Lua的实现可以直接写到EnvoyFilter中,无需独立的工程。示例如下:

patch:operation: INSERT_BEFOREvalue:name: envoy.luatyped_config:"@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.LuainlineCode: |function envoy_on_request(handle)handle:logInfo("[propagate header] route-v:hello3v2")handle:headers():add("route-v", "hello3v2")end

3.2 压测方法

1 部署

  • 分别在3个namespace上部署相同的Deployment/Service/VirtualService/DestinationRule
  • 在hello-abtest-lua中部署基于Lua的EnvoyFilter
  • 在hello-abtest-wasm中部署基于WASM的EnvoyFilter
hello-abtest        基准环境
hello-abtest-lua    增加EnvoyFilter+LUA的环境
hello-abtest-wasm   增加EnvoyFilter+WASM的环境

2 工具

本例使用hey作为压测工具。hey前身是boom,用来代替ab(Apache Bench)。使用相同的压测参数分别对三个环境进行压测。示意如下:

# 并发work数量
export NUM=2000
# 每秒请求数量
export QPS=2000
# 压测执行时常
export Duration=10shey -c $NUM -q $QPS -z $Duration -H "route-v:v2" http://$ingressGatewayIp:$PORT/hello/eric > $SIDECAR_WASM_RESULT

请关注hey压测结果文件,结果最后不能出现socket: too many open files,否则影响结果。可以使用ulimit -n $MAX_OPENFILE_NUM命令配置,然后再调整压测参数,以确保结果的准确性。

3.3 报告

我们从三份结果报告中选取4个关键指标,如下图所示:

 

 

基准

WASM

LUA

1000并发1000QPS持续10秒钟

 

 

 

平均延迟

0.6317 secs

0.6395 secs

0.7012 secs

延迟99%分布

0.9167 secs

0.9352 secs

1.1355 secs

QPS

1541

1519

1390

Total

16281

16109

1390

2000并发2000QPS持续10秒钟

 

 

 

平均延迟

1.2078 secs

1.3290 secs

1.4593 secs

延迟99%分布

1.8621 secs

1.8354 secs

2.2116 secs

QPS

1564

1421

1290

Total

17622

16009

14662

3.4 结论

  1. 相对于基准版本,增加EnvoyFilter的两个版本,平均延迟多出几十个到几百个毫秒,增加耗时比为
  • wasm 1.2% (0.6395-0.6317)/0.6317和1% (1.3290-1.2078)/1.2078
  • lua 11%(0.7012-0.6317)/0.6317和20% (1.4593-1.2078)/1.2078
  1. WASM版本的性能明显优于LUA版本

注:相比LUA版本,WASM的实现是一套代码多份配置。因此WASM的执行过程还比LUA多出一个获取配置变量的过程。

4 展望

4.1 如何使用

本文从技术实现角度,讲述了如何实现并验证一个透传用户自定义Header的WASM,从而支持无侵入式全链路A/B Test这个需求。

但是,作为服务网格的使用者,如果按照本文一步步去实现,是非常繁琐且容易出错的。

阿里云服务网格ASM团队正在推出一种ASM插件目录的机制,用户只需在插件目录中选择插件,并为插件提供自定义的Header等极少数量的kv配置,即可自动生成和部署相关的EnvoyFilter+WASM+VirtualService+DestinationRule。

4.2 如何扩展

本例只展示了基于Header的匹配路由功能,如果我们希望根据Query Params进行匹配和路由该如何扩展呢?

这是ASM插件目录正在密切关注的话题,最终插件目录将提供最佳实践。

以上。

作者:六翁

原文链接

本文为阿里云原创内容,未经允许不得转载

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

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

相关文章

网易游戏基于 Flink 的流式 ETL 建设

简介&#xff1a; 网易游戏流式 ETL 建设实践及调优经验分享&#xff5e; 网易游戏资深开发工程师林小铂为大家带来网易游戏基于 Flink 的流式 ETL 建设的介绍。内容包括&#xff1a; 专用 ETLEntryX 通用 ETL调优实践未来规划 一. 业务背景 网易游戏 ETL 服务概况 网易游戏的…

potplayer 多个进程_创建守护进程的步骤

什么是守护进程&#xff1f;答&#xff1a;守护进程是后台运行的、系统启动是就存在的、不予任何终端关联的&#xff0c;用于处理一些系统级别任务的特殊进程。实现思路&#xff1a;实现一个守护进程&#xff0c;其实就是将普通进程按照上述特性改造为守护进程的过程。需要注意…

mysql 走索引 很慢_MySQL优化:为什么SQL走索引还那么慢?

背景2019-01-11 9:00-10:00 一个 MySQL 数据库把 CPU 打满了。硬件配置&#xff1a;256G 内存&#xff0c;48 core分析过程接手这个问题时现场已经不在了&#xff0c;信息有限&#xff0c;所以我们先从监控系统中查看一下当时的状态。从 PMM 监控来看&#xff0c;这个 MySQL 实…

华为徐直军:以持续创新加快数字化发展

【中国 深圳】2021年9月23日&#xff0c;华为全联接大会以线上形式举行&#xff0c;今年的全联接大会以“深耕数字化”为主题&#xff0c;汇聚了业界思想领袖&#xff0c;商业精英&#xff0c;技术大咖&#xff0c;生态伙伴等&#xff0c;探讨如何深入业务场景&#xff0c;把数…

大型 Web 应用插件化架构探索

简介&#xff1a; 随着 Web 技术的逐渐成熟&#xff0c;越来越多的应用架构趋向于复杂&#xff0c;例如阿里云等巨型控制台项目&#xff0c;每个产品下都有各自的团队来负责维护和迭代。不论是维护还是发布以及管控成本都随着业务体量的增长而逐渐不可控。在这个背景下微前端应…

高精地图技术专栏 | 基于空间连续性的异常3D点云修复技术

简介&#xff1a; 我们需要通过激光的内部机制和数据处理算法&#xff0c;将这些噪声恢复到它本来的位置。本文会从MTA问题产生的原理、激光应对MTA的内部机制、数据处理算法三方面来介绍高精资料处理是如何解决这个问题的。 1.背景 1.1 高精资料采集 高精采集车是集成了测绘…

pytorch 图像分割的交并比_「通知」《深度学习之图像识别》再版工作启动,欢迎指导和提建议...

不知不觉有三第一本书也上市超过1年半了&#xff0c;第一次写作略显稚嫩&#xff0c;许多细节处理不当&#xff0c;比如没有在印刷前核对公式&#xff0c;被删掉了参考文献影响读者阅读体验等。现在本书正式启动再版工作&#xff0c;注意不是重印&#xff0c;是再版。重印只是修…

mysql实例怎么复制_Mysql实例MySQL数据库复制概论

《Mysql实例MySQL数据库复制概论》要点&#xff1a;本文介绍了Mysql实例MySQL数据库复制概论&#xff0c;希望对您有用。如果有疑问&#xff0c;可以联系我们。导读&#xff1a;每当我们讨论一项(新的)领域技术的时候,最好的方式通常是首先抛出一些问题,这些问题大致分为三类&a…

app inventor离线版_百度要哭了!今日头条出了搜索引擎了,还做了APP

今天小编为大家送上几条新闻了&#xff1a;1 微软给Edge浏览器添加离线小游戏谷歌浏览器在不联网的情况下&#xff0c;会有一个小恐龙跳一跳的游戏&#xff0c;而最近换上chromium内核的edge&#xff0c;也添加了自己的离线小游戏。这是一款冲浪游戏&#xff0c;非常类似于微软…

打车业务下单高并发解决方案

简介&#xff1a; 打车业务下单高并发解决方案前言 在技术领域有一条准则&#xff0c;即不存在银弹技术。在实际工作中&#xff0c;通常无法通过几项简单的技术组合就解决实际业务中各种场景下的复杂问题。虽然追求架构的简单简洁也是架构师的目标之一。但必须认识到架构的简单…

Serverless 时代 DevOps 的最佳打开方式

简介&#xff1a; 传统软件开发过程中&#xff0c;开发和运维是极其分裂的两个环节&#xff0c;运维人员不关心代码是怎样运作的&#xff0c;开发人员也不知道代码是如何运行的。 作者 | 许成铭&#xff08;竞霄&#xff09; 来源 | 阿里巴巴云原生公众号 DevOps 简析 传统软…

2020 q5l使用手册电子版_关于2020下半年自考本科毕业生论文预答辩题目查询的通知...

一、对象&#xff1a;2020下半年获论文预答辩资格毕业生(名单见附件1)二、查询方法&#xff1a;请登录以下网址&#xff1a; 输入个人准考证和姓名&#xff0c;查询论文预答辩题目。三、相关要求1. 请将《自学考试本科毕业论文预答辩记录表》(见附件2)中个人相关信息以及预答辩…

现实版“奇异博士”?原来是这款神秘的“数学黑盒”

简介&#xff1a; 现实版“奇异博士”&#xff1f;原来是这款神秘的“数学黑盒”供稿团队&#xff1a;阿里云市场部在漫威电影《复联3》中&#xff0c;奇异博士预测到未来有1400多万种可能&#xff0c;而胜利却只有一种&#xff0c;这唯一的最优解成为他们战斗的希望。只可惜&a…

如何在Spring生态中玩转RocketMQ?

简介&#xff1a; RocketMQ作为业务消息的首选&#xff0c;在消息和流处理领域被广泛应用。而微服务生态Spring框架也是业务开发中最受欢迎的框架&#xff0c;两者的完美契合使得RocketMQ成为Spring Messaging实现中最受欢迎的消息实现。本文展示了5种在Spring生态中文玩转Rock…

enum 有什么好处_林卡尔|先买地板后装修的三大好处

【中华地板网】现在很多装饰公司和设计师&#xff0c; 提倡的装修新模式——“先定地板后装修”。 后装修并不是买完地板后再开工&#xff0c; 而是在开工之前&#xff0c; 先把地板风格、颜色、尺寸、价位定下&#xff0c; 然后让设计师根据地板进行其他设计。 那么这样做究竟…

华为推出业界首个分布式云原生产品:华为云UCS,持续创新,深耕数字化

华为面向ICT产业的全球年度旗舰活动——华为全联接2021拉开序幕。华为轮值董事长徐直军进行了“以持续创新加快数字化发展”的大会主题演讲。 本次大会围绕“深耕数字化”主题&#xff0c;探讨如何深入业务场景&#xff0c;把数字技术与行业知识深度结合&#xff0c;解决核心业…

Flink 必知必会经典课程四:Fault-tolerance in Flink

简介&#xff1a; 本文由 Apache Flink PMC , 阿里巴巴高级技术专家李钰分享&#xff0c;主要从有状态的流计算、全局一致性快照 、Flink的容错机制、Flink的状态管理 四个方面介绍 Flink 的容错机制原理。 作者 | 李钰 分享人&#xff1a;本文由 Apache Flink PMC , 阿里巴巴…

用云原生的思维践行云原生,华为云深耕数字化,一切皆服务

[中国&#xff0c;深圳&#xff0c;2021年9月23日] 华为全联接2021于9月23日开幕。华为轮值董事长徐直军进行了“以持续创新加快数字化发展”的主题演讲&#xff0c;发布业界首个分布式云原生产品——华为云UCS&#xff0c;即 “无处不在的云原生服务”。华为高级副总裁、华为云…

白苹果了怎么办_苹果手机出现白苹果、死机、不断重启怎么办?

小伙伴们的苹果设备是否出现过白苹果、不断重启、更新失败、卡机死机、进入了恢复模式等情况呢?小编自己的iPhoneXR就遇到过&#xff0c;不知道怎么操作的就进入了恢复模式&#xff0c;有时候手机卡机需要强制重启&#xff0c;遇到问题就想去外面的修理店解决一下&#xff0c;…

Knative 多容器支持介绍

简介&#xff1a; 微服务和容器化带来了将应用程序分解成可重复使用的小型单元的诉求&#xff0c;这些单元通常作为单独的进程运行&#xff0c;或者在单独的容器运行。 Kubernetes的Pod模型允许用户创建一个部署单元&#xff0c;该单元可以打包多个容器作为应用程序的单个实例。…