当前位置: 首页 > news >正文

云原生 envoy xDS 动态配置 java控制平面开发 支持restful grpc实现 EDS 动态endpoint配置

envoy xDS 动态配置 java控制平面开发 支持restful grpc 动态endpoint配置

大纲

  • 基础概念
  • Envoy 动态配置API
  • 配置方式
  • 动静结合的配置方式
  • 纯动态配置方式
  • 实战

基础概念

Envoy 的强大功能之一是支持动态配置,当使用动态配置时,我们不需要重新启动 Envoy 进程就可以生效。Envoy 通过从磁盘文件或网络接口读取配置,动态地重新加载配置。动态配置使用所谓的发现服务 API,指向配置的特定部分。这些 API 也被统称为xDS 即 (xxx discovery service)

注意:
Envoy的发现API开发模式是,按照Envoy指定的接口名称,请求参数,响应值,自己开发,即需要满足Envoy的规范

Envoy动态配置支持文件方式,grpc接口和, restful接口,其中 grpc接口/REST接口 的配置提供者(自己开发的项目)也被称为控制平面

实现方式:

  • 文件方式: 监听文件的变化动态修改
  • grpc接口: 使用的tcp长连接
  • REST接口: 使用的http轮询的方式实现

Envoy 动态配置API

API类型

Envoy 内部有多个发现服务 API (xDS):

  • 监听器发现服务(LDS listener discovery service) 使用 LDS,Envoy 可以在运行时发现监听器,包括所有的过滤器栈、HTTP 过滤器和对 RDS 的引用。(即动态配置 listener 类似nginx配置虚拟主机)
  • 扩展配置发现服务(ECDS) 使用 ECDS,Envoy 可以独立于监听器获取扩展配置(例如,HTTP 过滤器配置)。
  • 路由发现服务(RDS route discovery service) 使用 RDS,Envoy 可以在运行时发现 HTTP 连接管理器过滤器的整个路由配置。与 EDS 和 CDS 相结合,我们可以实现复杂的路由拓扑结构。(即动态配置路由)
  • 虚拟主机发现服务(VHDS) 使用 VHDS 允许 Envoy 从路由配置中单独请求虚拟主机。当路由配置中有大量的虚拟主机时,就可以使用这个功能。
  • 宽泛路由发现服务(SRDS) 使用 SRDS,可以把路由表分解成多个部分。当有大的路由表时,就可以使用这个 API。
  • 集群发现服务(CDS cluster discovery service ) 使用 CDS,Envoy 可以发现上游集群。Envoy 将通过排空和重新连接所有现有的连接池来优雅地添加、更新或删除集群。Envoy 在初始化时不必知道所有的集群,因为我们可以在以后使用 CDS 配置它们。(即动态配置集群)
  • 端点发现服务(EDS endpoint discovery service) 使用 EDS,Envoy 可以发现上游集群的成员。 (即动态配置后端服务类似nginx upstream)
  • 秘密发现服务(SDS) 使用 SDS,Envoy 可以为其监听器发现秘密(证书和私钥,TLS 会话密钥),并为对等的证书验证逻辑进行配置。
  • 运行时发现服务(RTDS) 使用 RTDS,Envoy 可以动态地发现运行时层。

API 版本

Envoy 的 API 有 v2 v3 目前主流版本是 v3

官方文档 https://www.envoyproxy.io/docs/envoy/latest/configuration/overview/xds_api

xDS API 可以使用restful接口和grpc接口开发,只要满足指定的接口名称和DiscoveryRequest,DiscoveryResponse参数和响应对象即可

例如以下就是一个EDS的接口
/v3/discovery:endpoints (即自己写的controller的mapping是/v3/discovery:endpoints)
@RequestMapping("/v3/discovery:endpoints")

配置方式

动静结合的配置方式

静态配置与动态配置结合

例如

static_resources:listeners:- name: my_listeneraddress:socket_address: protocol: TCPaddress: 0.0.0.0port_value: 15200filter_chains:- filters:- name: envoy.filters.network.http_connection_managertyped_config:"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManagerstat_prefix: my-http-filterhttp_filters:- name: envoy.filters.http.routerstat_prefix: my_listener_httpcodec_type: AUTOroute_config:name: local_routevirtual_hosts:- name: local_servicedomains: ["*"]routes:- match:  prefix: "/" route:  cluster: user-service clusters:- name: user-servicetype: EDS #这里就是使用动态配置的方式实现endpoint的动态发现connect_timeout: 0.5seds_cluster_config: eds_config:resource_api_version: V3api_config_source:api_type: RESTtransport_api_version: V3cluster_names: [edscluster]refresh_delay: 10s - name: edsclustertype: STATICconnect_timeout: 0.5shosts:  - socket_address: address: 192.168.0.218port_value: 7590 

纯动态配置方式

使用dynamic_resources 配置动态内容

例如

dynamic_resources:ads_config:api_type: GRPCtransport_api_version: V3grpc_services:- envoy_grpc:cluster_name: xds_clustercds_config:resource_api_version: V3api_config_source:api_type: GRPCtransport_api_version: V3grpc_services:- envoy_grpc:cluster_name: xds_clusterlds_config:resource_api_version: V3api_config_source:api_type: GRPCtransport_api_version: V3grpc_services:- envoy_grpc:cluster_name: xds_cluster

当envoy没有读取到配置时会一直使用默认的配置,所以如果控制平面宕机后还是会保持配置

每个 xDS API 都有给定的资源类型:

v2版本

LDS :  envoy.api.v2.Listener
RDS : envoy.api.v2.RouteConfiguration
CDS : envoy.api.v2.Cluster
EDS :envoy.api.v2.ClusterLoadAssignment (EDS就是配置 endpoint)

v3版本

envoy.config.listener.v3.Listener
envoy.config.route.v3.RouteConfiguration,
envoy.config.route.v3.ScopedRouteConfiguration,
envoy.config.route.v3.VirtualHost
envoy.config.cluster.v3.Cluster
envoy.config.endpoint.v3.ClusterLoadAssignment  (EDS endpoint 返回的resources 对象类型)
envoy.extensions.transport_sockets.tls.v3.Secret
envoy.service.runtime.v3.Runtime

即接口返回DiscoveryResponse 内部的resources 是以上类型

实战

本次测试 envoy的版本为v1.16.0 使用docker镜像部署

在这里插入图片描述

基于envoy xDS api v3版本 java restful实现

step1 配置 envoy.yaml

配置文件如下

node:cluster: myclusterid: test-id# 这是一段静态配置
static_resources:listeners:- name: my_listeneraddress:socket_address: protocol: TCPaddress: 0.0.0.0port_value: 15200 #配置一个静态的listener 监听来自任意IP的请求15200端口的http请求filter_chains:- filters:- name: envoy.filters.network.http_connection_manager #注意指定filterstyped_config:"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManagerstat_prefix: my-http-filterhttp_filters:- name: envoy.filters.http.routerstat_prefix: my_listener_httpcodec_type: AUTOroute_config:name: local_routevirtual_hosts:- name: local_servicedomains: ["*"]  #任意域名的请求routes:- match:  prefix: "/"   # 任意url的请求route:  cluster: user-service  # 路由到user-service 集群# 配置集群    clusters:- name: user-servicetype: EDS  #模式指定为EDS  connect_timeout: 0.5s # 配置连接超时时间eds_cluster_config: eds_config:resource_api_version: V3 #指定使用V3版本接口api_config_source:api_type: REST  #使用restful的方式transport_api_version: V3   #指定使用V3版本接口cluster_names: [edscluster]refresh_delay: 10s  # 配置刷新频率# 这里配置的是envoy EDS接口的提供服务即控制平面       - name: edsclustertype: STATICconnect_timeout: 0.5s # 配置连接超时时间# envoy会去请求 192.168.0.218:7590/v3/discovery:endpoints 这个接口 获取endpoint配置信息# 代码见 my-docker-demo-envoy-plane/DataPlaneEndpointControllerV3.javahosts:  - socket_address: address: 192.168.0.218port_value: 7590  

启动 envoy 镜像

docker run  -p 5201:5201 -p 15200:15200  -v /ops/envoy:/etc/envoy  envoyproxy/envoy:v1.16.0 

envoy 启动后可以看到开始调用 EDS接口,由于还没启动服务此时会报错

在这里插入图片描述

step2 java 程序开发

EDS接口使用java springboot 开发

注意点如下:

  • 1 接口必须是 /v3/discovery:endpoints
  • 2 动态配置需要是一个json 字符串 并且满足endpoint需要的格式
  • 3 返回值必须是一个DiscoveryResponse service.discovery.v3.DiscoveryResponse

DiscoveryResponse 格式如下

{"version_info": ...,"resources": [],"type_url": ...,"nonce": ...,"control_plane": {...}
}

整体的返回值json字符串如下

{"versionInfo": "1.0.0","resources": [{"@type": "type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment","clusterName": "user-service","endpoints": [{"lbEndpoints": [ {"endpoint": {"address": {"socketAddress": {"address": "10.244.1.203","portValue": 5588}}}}]}]}]
}

如果自己拼接json字符串感觉比较麻烦,可以使用envoy-api包

<dependency><groupId>io.envoyproxy.controlplane</groupId><artifactId>api</artifactId><version>1.0.39</version></dependency>

这个包,里面有xDS中的各种资源对象 以及grpc接口

也可以使用官方提供的 java控制面板项目 打包编译后得到api包,里面也有xDS中的各种资源对象

在这里插入图片描述

java 代码如下

  @RequestMapping(value="/v3/discovery:endpoints" , produces = {"application/json;charset=UTF-8"})public String discovery(HttpServletRequest req) throws Exception {			//json 字符串拼接//String json = staticJson();/*** 构建返回EDS 配置json 字符串*/String json = useBean();return json;}/*** @return*/private String useBean() throws Exception {/*** 以下资源类出自* * <dependency><groupId>io.envoyproxy.controlplane</groupId><artifactId>api</artifactId><version>1.0.39</version></dependency>* *///配置上游服务(类似nginx upstream)SocketAddress sa1 = SocketAddress.newBuilder().setAddress("10.244.0.190").setPortValue(5588).build();SocketAddress sa2 = SocketAddress.newBuilder().setAddress("10.244.1.203").setPortValue(5588).build();Address address1 = Address.newBuilder().setSocketAddress(sa1).build();Address address2 = Address.newBuilder().setSocketAddress(sa2).build();Endpoint end1 = Endpoint.newBuilder().setAddress(address1).build();Endpoint end2 = Endpoint.newBuilder().setAddress(address2).build();LbEndpoint lb1 = LbEndpoint.newBuilder().setEndpoint(end1).build();LbEndpoint lb2 = LbEndpoint.newBuilder().setEndpoint(end2).build();LocalityLbEndpoints llb = LocalityLbEndpoints.newBuilder().addLbEndpoints(lb1).addLbEndpoints(lb2).build();ClusterLoadAssignment cla = ClusterLoadAssignment.newBuilder().setClusterName("user-service").addEndpoints(llb).build();DiscoveryResponse dr = DiscoveryResponse.newBuilder().setVersionInfo("1.0.0").addResources(Any.pack(cla)).build();JsonFormat.TypeRegistry typeRegistry = JsonFormat.TypeRegistry.newBuilder().add(ClusterLoadAssignment.getDescriptor()).build();JsonFormat.Printer printer = JsonFormat.printer().usingTypeRegistry(typeRegistry);return printer.print(dr);
}

基于 envoy xDS api v3版本 java grpc实现

grpc的关键

  • 1 使用envoy api包 实现对应的grpc 服务
  • 2 返回值需要指定typeUrl
  • 3 配置文件需要加入 http2_protocol_options 指定使用http2

没使用http2_protocol_options 配置会出现如下异常

io.grpc.netty.shaded.io.netty.handler.codec.http2.Http2Exception: Unexpected HTTP/1.x request: POST /envoy.service.endpoint.v3.EndpointDiscoveryService/StreamEndpoints at io.grpc.netty.shaded.io.netty.handler.codec.http2.Http2Exception.connectionError(Http2Exception.java:109) ~[grpc-netty-shaded-1.48.1.jar:1.48.1]at io.grpc.netty.shaded.io.netty.handler.codec.http2.Http2ConnectionHandler$PrefaceDecoder.readClientPrefaceString(Http2ConnectionHandler.java:302) ~[grpc-netty-shaded-1.48.1.jar:1.48.1]at io.grpc.netty.shaded.io.netty.handler.codec.http2.Http2ConnectionHandler$PrefaceDecoder.decode(Http2ConnectionHandler.java:239) ~[grpc-netty-shaded-1.48.1.jar:1.48.1]at io.grpc.netty.shaded.io.netty.handler.codec.http2.Http2ConnectionHandler.decode(Http2ConnectionHandler.java:438) [grpc-netty-shaded-1.48.1.jar:1.48.1]

在这里插入图片描述

返回值未指定typeUrl

023-08-16 06:14:49.608][8][warning][config] [source/common/config/grpc_mux_impl.cc:155] Ignoring the message for type URL  as it has no current subscribers.

在这里插入图片描述

关键配置 envoy.yaml 如下

# 指定集群名称
# 动态配置需要指定节点集群名称        
node:cluster: myclusterid: test-id# 这是一段静态配置
static_resources:listeners:- name: my_listeneraddress:socket_address: protocol: TCPaddress: 0.0.0.0port_value: 15200 #配置一个静态的listener 监听来自任意IP的请求15200端口的http请求filter_chains:- filters:- name: envoy.filters.network.http_connection_manager #注意指定filterstyped_config:"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManagerstat_prefix: my-http-filterhttp_filters:- name: envoy.filters.http.routerstat_prefix: my_listener_httpcodec_type: AUTOroute_config:name: local_routevirtual_hosts:- name: local_servicedomains: ["*"]  #任意域名的请求routes:- match:  prefix: "/"   # 任意url的请求route:  cluster: user-service  # 路由到user-service 集群# 配置集群    clusters:- name: user-servicetype: EDS  #模式指定为EDS  connect_timeout: 0.5s # 配置连接超时时间eds_cluster_config: eds_config:resource_api_version: V3 #指定使用V3版本接口api_config_source:api_type: GRPC  #使用grpc的方式transport_api_version: V3   #指定使用V3版本接口# 指定grpc_services 对应的集群# 这里将使用下面定义的集群grpc_services: - envoy_grpc: cluster_name: edscluster# 这里配置的是envoy EDS接口的提供服务即控制平面       - name: edsclustertype: STATICconnect_timeout: 0.5s # 配置连接超时时间# 这里是一个关键,必须指定http2_protocol_options 即使用http2http2_protocol_options: {}hosts:  - socket_address: address: 192.168.0.218port_value: 7899  

关键java代码

public class EndpointDiscoveryServiceGrpcImpl extends EndpointDiscoveryServiceGrpc.EndpointDiscoveryServiceImplBase {/*** 这个接口是客户端模式* */@Overridepublic io.grpc.stub.StreamObserver<io.envoyproxy.envoy.service.discovery.v3.DiscoveryRequest> streamEndpoints(io.grpc.stub.StreamObserver<io.envoyproxy.envoy.service.discovery.v3.DiscoveryResponse> responseObserver) {System.out.println("run grpc ...");/*** 创建StreamObserver<DiscoveryRequest>对象*/StreamObserver<DiscoveryRequest> so = new StreamObserver<DiscoveryRequest>() {@Overridepublic void onNext(DiscoveryRequest request) {//接收客户端每一次发送的数据,返回给客户端//showRequest(request);SocketAddress sa1 = SocketAddress.newBuilder().setAddress("10.244.0.214").setPortValue(5588).build();SocketAddress sa2 = SocketAddress.newBuilder().setAddress("10.244.0.201").setPortValue(5588).build();Address address1 = Address.newBuilder().setSocketAddress(sa1).build();Address address2 = Address.newBuilder().setSocketAddress(sa2).build();Endpoint end1 = Endpoint.newBuilder().setAddress(address1).build();Endpoint end2 = Endpoint.newBuilder().setAddress(address2).build();LbEndpoint lb1 = LbEndpoint.newBuilder().setEndpoint(end1).build();LbEndpoint lb2 = LbEndpoint.newBuilder().setEndpoint(end2).build();LocalityLbEndpoints llb = LocalityLbEndpoints.newBuilder().addLbEndpoints(lb1).addLbEndpoints(lb2).build();ClusterLoadAssignment cla = ClusterLoadAssignment.newBuilder()/*** 这里配置的ClusterName 应该是路由对应的cluster name 而不是 node中的cluster* route: { cluster: user-service }*/.setClusterName("user-service") .addEndpoints(llb).build();final DiscoveryResponse dr = DiscoveryResponse.newBuilder().setVersionInfo("1.0.0")							.setTypeUrl("type.googleapis.com/envoy.config.endpoint.v3.ClusterLoadAssignment").addResources(Any.pack(cla)).build();/*** 客户端模式这里不会去关闭StreamObserver* 即不会调用 responseObserver.onCompleted();方法*/responseObserver.onNext(dr);System.out.println("send DiscoveryResponse ");}@Overridepublic void onError(Throwable t) {System.out.println("onError");t.printStackTrace();}@Overridepublic void onCompleted() {//当客户端数据发送完毕后调用此方法,返回客户端SocketAddress sa1 = SocketAddress.newBuilder().setAddress("10.244.0.214").setPortValue(5588).build();SocketAddress sa2 = SocketAddress.newBuilder().setAddress("10.244.0.201").setPortValue(5588).build();Address address1 = Address.newBuilder().setSocketAddress(sa1).build();Address address2 = Address.newBuilder().setSocketAddress(sa2).build();Endpoint end1 = Endpoint.newBuilder().setAddress(address1).build();Endpoint end2 = Endpoint.newBuilder().setAddress(address2).build();LbEndpoint lb1 = LbEndpoint.newBuilder().setEndpoint(end1).build();LbEndpoint lb2 = LbEndpoint.newBuilder().setEndpoint(end2).build();LocalityLbEndpoints llb = LocalityLbEndpoints.newBuilder().addLbEndpoints(lb1).addLbEndpoints(lb2).build();ClusterLoadAssignment cla = ClusterLoadAssignment.newBuilder().setClusterName("user-service").addEndpoints(llb).build();final DiscoveryResponse dr = DiscoveryResponse.newBuilder().setVersionInfo("1.0.0").addResources(Any.pack(cla)).build();System.out.println("onCompleted");responseObserver.onNext(dr);responseObserver.onCompleted();}};return so;

相关文章:

云原生 envoy xDS 动态配置 java控制平面开发 支持restful grpc实现 EDS 动态endpoint配置

envoy xDS 动态配置 java控制平面开发 支持restful grpc 动态endpoint配置 大纲 基础概念Envoy 动态配置API配置方式动静结合的配置方式纯动态配置方式实战 基础概念 Envoy 的强大功能之一是支持动态配置&#xff0c;当使用动态配置时&#xff0c;我们不需要重新启动 Envoy…...

Linux--实用指令与方法(部分)

下文主要是一些工作中零碎的常用指令与方法 实用指令与方法&#xff08;部分&#xff09; linux长时间保持ssh连接 这个问题的原因是&#xff1a;设置检测时间太短&#xff0c;或者没有保持tcp长连接。 解决步骤&#xff1a; 步骤1&#xff1a;打开sshd配置文件&#xff0…...

常见期权策略类型有哪些?

这几天在做一个期权策略类型的整理分类&#xff0c;怎么解释期权策略&#xff0c;期权策略是现代金融市场中运用非常广泛、变化非常丰富、结构非常精妙的金融衍生产品&#xff1b;同时也是一种更为复杂也更为灵活的投资工具&#xff0c;下文介绍常见期权策略类型有哪些&#xf…...

tomcat服务七层搭建动态页面查看

一个服务器多实例复制完成 配置tomcat多实例的环境变量 vim /etc/profile.d/tomcat.sh配置tomcat1和tomcat2的环境变量 进入tomcat1修改配置 测试通信端口是否正常 连接正常 toncat 2 配置修改 修改这三个 端口配置修改完成 修改tomcat1 shudown 分别把启动文件指向tomcat1…...

sql A表(含有部分B表字段) 向B表插入A表数据

今天遇到一个数据库插入问题 向表中插入 生产状态 为 2 的数据 但生产状态为改为12 的所有数据 查看网上的评论 参考 insert into b (a,b,c) select ‘1’,‘2’,c from a where a1 这样就可以a,b字段是插入指定某个值,而C字段则用表a的c字段. 最后解决了。忽然想起原来也有这…...

如何用思维导图+Markdown提升工作效率?

在日常的工作中&#xff0c;我们常常需要记录一些信息、重要的事情或者一些重要的想法&#xff0c;Markdown就是一种非常好用的记录工具。搭配思维导图可以提高我们的记录效率&#xff0c;让我们的记录更加结构化。 为什么使用思维导图&#xff1f; 思维导图可以帮助我们整理…...

睿趣科技:抖音开网店现在做还来得及吗

随着社交媒体的迅速发展&#xff0c;抖音作为一款短视频平台&#xff0c;已经在年轻人中间取得了巨大的成功。而近年来&#xff0c;越来越多的人开始考虑在抖音上开设网店&#xff0c;以迎合这一潮流。那么&#xff0c;抖音开网店现在还来得及吗? 首先&#xff0c;要明确的是&…...

C++——list的简要介绍

list的介绍 详细请看&#xff08;https://cplusplus.com/reference/list/list/?kwlist&#xff09; 1.list是一个可以在常数范围内在任意位置&#xff0c;进行插入和删除的序列式容器&#xff0c;并且此容器可以前后双向迭代。 2.list的底层实质是一个双向链表结构&#xf…...

Java自学网站推荐,专业教学快速提升

Java自学书籍推荐&#xff0c;很多同学在找小编要一些比较适合初学者的学习书籍&#xff0c;Java自学书籍可以帮助您学习和掌握Java编程语言。以下是一些常见的Java自学书籍&#xff0c;它们涵盖了Java的基础知识、编程技巧和应用开发等方面&#xff1a; 1."Java核心技术&…...

深入学习SpringCloud Alibaba微服务架构,揭秘Nacos、Sentinel、Seata等核心技术,助力构建高效系统!

课程链接&#xff1a; 链接: https://pan.baidu.com/s/1hRN0R8VFcwjyCTWCEsz-8Q?pwdj6ej 提取码: j6ej 复制这段内容后打开百度网盘手机App&#xff0c;操作更方便哦 --来自百度网盘超级会员v4的分享 课程介绍&#xff1a; &#x1f4da;【第01阶段】课程简介&#xff1a;全…...

【iMessage频發软件苹果群发技术开源原创】当 APNs 发送通知到一个离线设备时,APNs 会把通知存储起来(一定的时间内),当设备上线时再递送给设备。

推荐内容IMESSGAE相关 作者✈️IMEAE推荐内容iMessage苹果推软件 *** 点击即可查看作者要求内容信息作者✈️IMEAE推荐内容1.家庭推内容 *** 点击即可查看作者要求内容信息作者✈️IMEAE推荐内容2.相册推 *** 点击即可查看作者要求内容信息作者✈️IMEAE推荐内容3.日历推 *** …...

【数据结构】_8.二叉树OJ

目录 1. 题目1&#xff1a;检查两棵树是否相同 2. 题目2&#xff1a;判断一棵树是否为另一棵树的子树 3. 题目3&#xff1a;翻转二叉树 4. 题目4&#xff1a;判断一棵树是否为平衡二叉树 5. 题目5&#xff1a;判断一棵树是否为对称二叉树 6. 题目6&#xff1a;二叉树的层序…...

酷开系统 | 酷开科技大数据,更好的与目标消费人群建立联系

众所周知&#xff0c;OTT的一大优势在于强曝光&#xff0c;能够给消费者带来强烈的视觉冲击&#xff0c;强化品牌认知。但是&#xff0c;要想达到提升品牌认知&#xff0c;首先要保证OTT的流量规模&#xff0c;实现对目标人群的有效覆盖。得年轻消费者得“天下”&#xff0c;年…...

无涯教程-Perl - study函数

描述 此功能需要花费额外的时间来研究EXPR,以改善在EXPR上执行的正则表达式的性能。如果省略EXPR,则使用$_。实际的速度增益可能非常小,具体取决于您希望搜索字符串的次数。 您一次只能学习一种表达式或标量。 语法 以下是此函数的简单语法- study EXPRstudy返回值 此函数…...

dfs深度搜索入门之滑雪

P1434 [SHOI2002] 滑雪 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 本题我们主要使用了深度搜索和记忆化搜所。 首先我们可从任意一点开始滑行&#xff0c;这要求我们每一个点都进行一次深搜。但是如果每个点进行的话肯定会有许多个点重复被寻找最长滑雪长度&#xff0c;…...

Python程序设计——元组、集合和字典

可以使用元组存储一个固定的元素列表&#xff0c;使用集合存储和快速访问不重复的元素、使用字典存储键值对并使用这些关键字来快速访问元素。 一、元组 元组跟列表类似&#xff0c;但是元组中的元素是固定的;也就是说&#xff0c;一旦一个元组被创建,就无法对元组中的元素进行…...

八股文之框架篇(Spring Boot、SSM)

文章目录 Spring中的单例bean是线程安全的吗什么是AOP&#xff0c;项目中有没有使用到AOPSpring中的事务是如何实现的Spring中事务失效的场景有哪些Bean的生命周期Spring中的循环依赖&#xff08;循环引用&#xff09;SpringMVC的执行流程SpringBoot自动配置原理Spring、Spring…...

[PaddlePaddle] [学习笔记] [上] 计算机视觉(卷积、卷积核、卷积计算、padding计算、BN、缩放、平移、Dropout)

1. 计算机视觉的发展历程 计算机视觉作为一门让机器学会如何去“看”的学科&#xff0c;具体的说&#xff0c;就是让机器去识别摄像机拍摄的图片或视频中的物体&#xff0c;检测出物体所在的位置&#xff0c;并对目标物体进行跟踪&#xff0c;从而理解并描述出图片或视频里的场…...

【JS 贪心算法常见步骤】

贪心算法是一种解决优化问题的算法&#xff0c;其思想是在每一步选择中选择当前状态下最优解&#xff0c;从而达到全局最优解的目的。 以下是贪心算法的一些常见步骤&#xff1a; 将问题模型化为一个包含若干子问题的问题集合&#xff0c;每个子问题都有一个最优解。 对于每个…...

应用案例|基于三维机器视觉的机器人纸箱拆码垛应用解决方案

Part.1 项目背景 在现代物流和制造行业中&#xff0c;纸箱的拆码垛操作是一项重要且频繁的任务。传统的纸箱拆码垛工作通常由人工完成&#xff0c;这种方式存在劳动强度大、生产效率低以及人为操作容易导致错误等问题&#xff0c;严重影响物料的安全运输和质量。为了满足物流行…...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八

现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet&#xff0c;点击确认后如下提示 最终上报fail 解决方法 内核升级导致&#xff0c;需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

MySQL 8.0 OCP 英文题库解析(十三)

Oracle 为庆祝 MySQL 30 周年&#xff0c;截止到 2025.07.31 之前。所有人均可以免费考取原价245美元的MySQL OCP 认证。 从今天开始&#xff0c;将英文题库免费公布出来&#xff0c;并进行解析&#xff0c;帮助大家在一个月之内轻松通过OCP认证。 本期公布试题111~120 试题1…...

python报错No module named ‘tensorflow.keras‘

是由于不同版本的tensorflow下的keras所在的路径不同&#xff0c;结合所安装的tensorflow的目录结构修改from语句即可。 原语句&#xff1a; from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后&#xff1a; from tensorflow.python.keras.lay…...

系统掌握PyTorch:图解张量、Autograd、DataLoader、nn.Module与实战模型

本文较长&#xff0c;建议点赞收藏&#xff0c;以免遗失。更多AI大模型应用开发学习视频及资料&#xff0c;尽在聚客AI学院。 本文通过代码驱动的方式&#xff0c;系统讲解PyTorch核心概念和实战技巧&#xff0c;涵盖张量操作、自动微分、数据加载、模型构建和训练全流程&#…...

用鸿蒙HarmonyOS5实现中国象棋小游戏的过程

下面是一个基于鸿蒙OS (HarmonyOS) 的中国象棋小游戏的实现代码。这个实现使用Java语言和鸿蒙的Ability框架。 1. 项目结构 /src/main/java/com/example/chinesechess/├── MainAbilitySlice.java // 主界面逻辑├── ChessView.java // 游戏视图和逻辑├──…...

Python网页自动化Selenium中文文档

1. 安装 1.1. 安装 Selenium Python bindings 提供了一个简单的API&#xff0c;让你使用Selenium WebDriver来编写功能/校验测试。 通过Selenium Python的API&#xff0c;你可以非常直观的使用Selenium WebDriver的所有功能。 Selenium Python bindings 使用非常简洁方便的A…...

深入浅出WebGL:在浏览器中解锁3D世界的魔法钥匙

WebGL&#xff1a;在浏览器中解锁3D世界的魔法钥匙 引言&#xff1a;网页的边界正在消失 在数字化浪潮的推动下&#xff0c;网页早已不再是静态信息的展示窗口。如今&#xff0c;我们可以在浏览器中体验逼真的3D游戏、交互式数据可视化、虚拟实验室&#xff0c;甚至沉浸式的V…...

Java并发编程实战 Day 11:并发设计模式

【Java并发编程实战 Day 11】并发设计模式 开篇 这是"Java并发编程实战"系列的第11天&#xff0c;今天我们聚焦于并发设计模式。并发设计模式是解决多线程环境下常见问题的经典解决方案&#xff0c;它们不仅提供了优雅的设计思路&#xff0c;还能显著提升系统的性能…...

2.2.2 ASPICE的需求分析

ASPICE的需求分析是汽车软件开发过程中至关重要的一环&#xff0c;它涉及到对需求进行详细分析、验证和确认&#xff0c;以确保软件产品能够满足客户和用户的需求。在ASPICE中&#xff0c;需求分析的关键步骤包括&#xff1a; 需求细化&#xff1a;将从需求收集阶段获得的高层需…...