云原生 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 的强大功能之一是支持动态配置,当使用动态配置时,我们不需要重新启动 Envoy…...
Linux--实用指令与方法(部分)
下文主要是一些工作中零碎的常用指令与方法 实用指令与方法(部分) linux长时间保持ssh连接 这个问题的原因是:设置检测时间太短,或者没有保持tcp长连接。 解决步骤: 步骤1:打开sshd配置文件࿰…...

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

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提升工作效率?
在日常的工作中,我们常常需要记录一些信息、重要的事情或者一些重要的想法,Markdown就是一种非常好用的记录工具。搭配思维导图可以提高我们的记录效率,让我们的记录更加结构化。 为什么使用思维导图? 思维导图可以帮助我们整理…...

睿趣科技:抖音开网店现在做还来得及吗
随着社交媒体的迅速发展,抖音作为一款短视频平台,已经在年轻人中间取得了巨大的成功。而近年来,越来越多的人开始考虑在抖音上开设网店,以迎合这一潮流。那么,抖音开网店现在还来得及吗? 首先,要明确的是&…...
C++——list的简要介绍
list的介绍 详细请看(https://cplusplus.com/reference/list/list/?kwlist) 1.list是一个可以在常数范围内在任意位置,进行插入和删除的序列式容器,并且此容器可以前后双向迭代。 2.list的底层实质是一个双向链表结构…...

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

深入学习SpringCloud Alibaba微服务架构,揭秘Nacos、Sentinel、Seata等核心技术,助力构建高效系统!
课程链接: 链接: https://pan.baidu.com/s/1hRN0R8VFcwjyCTWCEsz-8Q?pwdj6ej 提取码: j6ej 复制这段内容后打开百度网盘手机App,操作更方便哦 --来自百度网盘超级会员v4的分享 课程介绍: 📚【第01阶段】课程简介:全…...

【iMessage频發软件苹果群发技术开源原创】当 APNs 发送通知到一个离线设备时,APNs 会把通知存储起来(一定的时间内),当设备上线时再递送给设备。
推荐内容IMESSGAE相关 作者✈️IMEAE推荐内容iMessage苹果推软件 *** 点击即可查看作者要求内容信息作者✈️IMEAE推荐内容1.家庭推内容 *** 点击即可查看作者要求内容信息作者✈️IMEAE推荐内容2.相册推 *** 点击即可查看作者要求内容信息作者✈️IMEAE推荐内容3.日历推 *** …...
【数据结构】_8.二叉树OJ
目录 1. 题目1:检查两棵树是否相同 2. 题目2:判断一棵树是否为另一棵树的子树 3. 题目3:翻转二叉树 4. 题目4:判断一棵树是否为平衡二叉树 5. 题目5:判断一棵树是否为对称二叉树 6. 题目6:二叉树的层序…...

酷开系统 | 酷开科技大数据,更好的与目标消费人群建立联系
众所周知,OTT的一大优势在于强曝光,能够给消费者带来强烈的视觉冲击,强化品牌认知。但是,要想达到提升品牌认知,首先要保证OTT的流量规模,实现对目标人群的有效覆盖。得年轻消费者得“天下”,年…...

无涯教程-Perl - study函数
描述 此功能需要花费额外的时间来研究EXPR,以改善在EXPR上执行的正则表达式的性能。如果省略EXPR,则使用$_。实际的速度增益可能非常小,具体取决于您希望搜索字符串的次数。 您一次只能学习一种表达式或标量。 语法 以下是此函数的简单语法- study EXPRstudy返回值 此函数…...
dfs深度搜索入门之滑雪
P1434 [SHOI2002] 滑雪 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 本题我们主要使用了深度搜索和记忆化搜所。 首先我们可从任意一点开始滑行,这要求我们每一个点都进行一次深搜。但是如果每个点进行的话肯定会有许多个点重复被寻找最长滑雪长度,…...

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

八股文之框架篇(Spring Boot、SSM)
文章目录 Spring中的单例bean是线程安全的吗什么是AOP,项目中有没有使用到AOPSpring中的事务是如何实现的Spring中事务失效的场景有哪些Bean的生命周期Spring中的循环依赖(循环引用)SpringMVC的执行流程SpringBoot自动配置原理Spring、Spring…...

[PaddlePaddle] [学习笔记] [上] 计算机视觉(卷积、卷积核、卷积计算、padding计算、BN、缩放、平移、Dropout)
1. 计算机视觉的发展历程 计算机视觉作为一门让机器学会如何去“看”的学科,具体的说,就是让机器去识别摄像机拍摄的图片或视频中的物体,检测出物体所在的位置,并对目标物体进行跟踪,从而理解并描述出图片或视频里的场…...
【JS 贪心算法常见步骤】
贪心算法是一种解决优化问题的算法,其思想是在每一步选择中选择当前状态下最优解,从而达到全局最优解的目的。 以下是贪心算法的一些常见步骤: 将问题模型化为一个包含若干子问题的问题集合,每个子问题都有一个最优解。 对于每个…...

应用案例|基于三维机器视觉的机器人纸箱拆码垛应用解决方案
Part.1 项目背景 在现代物流和制造行业中,纸箱的拆码垛操作是一项重要且频繁的任务。传统的纸箱拆码垛工作通常由人工完成,这种方式存在劳动强度大、生产效率低以及人为操作容易导致错误等问题,严重影响物料的安全运输和质量。为了满足物流行…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

Linux --进程控制
本文从以下五个方面来初步认识进程控制: 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程,创建出来的进程就是子进程,原来的进程为父进程。…...
日常一水C
多态 言简意赅:就是一个对象面对同一事件时做出的不同反应 而之前的继承中说过,当子类和父类的函数名相同时,会隐藏父类的同名函数转而调用子类的同名函数,如果要调用父类的同名函数,那么就需要对父类进行引用&#…...
Qt 事件处理中 return 的深入解析
Qt 事件处理中 return 的深入解析 在 Qt 事件处理中,return 语句的使用是另一个关键概念,它与 event->accept()/event->ignore() 密切相关但作用不同。让我们详细分析一下它们之间的关系和工作原理。 核心区别:不同层级的事件处理 方…...
LLaMA-Factory 微调 Qwen2-VL 进行人脸情感识别(二)
在上一篇文章中,我们详细介绍了如何使用LLaMA-Factory框架对Qwen2-VL大模型进行微调,以实现人脸情感识别的功能。本篇文章将聚焦于微调完成后,如何调用这个模型进行人脸情感识别的具体代码实现,包括详细的步骤和注释。 模型调用步骤 环境准备:确保安装了必要的Python库。…...

PydanticAI快速入门示例
参考链接:https://ai.pydantic.dev/#why-use-pydanticai 示例代码 from pydantic_ai import Agent from pydantic_ai.models.openai import OpenAIModel from pydantic_ai.providers.openai import OpenAIProvider# 配置使用阿里云通义千问模型 model OpenAIMode…...