MetalLB:本地Kubernetes集群的LoadBalancer负载均衡利器
背景
在本地集群进行测试时,我们常常面临一个棘手的问题:Service Type不支持LoadBalancer,而我们只能选择使用NodePort作为替代。这种情况下,我们通常会配置Service为NodePort,并使用externalIPs将流量导入Kubernetes环境。然而,这些解决方案都存在明显的缺陷,使得在私有环境部署Kubernetes的用户在这个生态中感觉自己像是二等公民。
值得注意的是,Kubernetes默认并未提供负载均衡器的实现。在Kubernetes生态中,网络负载均衡器的实现通常依赖于各种IaaS平台,如Google Cloud Platform (GCP)、Amazon Web Services (AWS)、Azure等。因此,如果你不在这些IaaS平台上运行Kubernetes,你创建的Service中的type: LoadBalancers将一直处于Pending状态,如下所示:
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx LoadBalancer 10.93.15.64 <pending> 8080:31322/TCP,443:31105/TCP 1h
这种情况下,我们急需一个解决方案,一个可以在本地环境中实现负载均衡的解决方案。这就是我们今天要介绍的主角——MetalLB。
Metallb 通过标准路由协议能解决该问题。MetalLB 也是 CNCF 的沙箱项目,最早发布在 https://github.com/google/metallb 开发,后来迁移到 https://github.com/metallb/metallb 中。
原理
Metallb 会在 Kubernetes 内运行,监控服务对象的变化,一旦察觉有新的LoadBalancer 服务运行,并且没有可申请的负载均衡器之后,
MetalLB 通过 MetalLB hooks 为 Kubernetes 中提供网络负载均衡器的实现。简单的说,它允许你在非云供应商提供的(私有的) Kubernetes 中创建 type: LoadBalancer 的 services。
MetalLB 有两大功能:
- 地址分配:在 IaaS 平台申请 LB,会自动分配一个公网 IP,因此,MetalLB也需要管理 IP 地址的分配工作
- IP 外部声明:当 MetalLB 获取外部地址后,需要对外声明该 IP 在 k8s 中使用,并可以正常通信。
IP 声明可以使用 ARP、 NDP、或 BGP 协议,因此 MetalLB 有两种工作模式:
- BGP 工作模式,使用 BGP 协议分配地址池
- L2 工作模式,使用 ARP/NDP 协议分配地址池
Layer2模式
在2层模式下,Metallb会在Node节点中选出一台作为Leader,与服务IP相关的所有流量都会流向该节点。在该节点上, kube-proxy将接收到的流量传播到对应服务的Pod。当leader节点出现故障时,会由另一个节点接管。从这个角度来看,2层模式更像是高可用,而不是负载均衡,因为同时只能在一个节点负责接收数据。
在二层模式中会存在以下两种局限性:单节点瓶颈和故障转移慢的情况。
由于Layer 2 模式会使用单个选举出来的Leader来接收服务IP的所有流量,这就意味着服务的入口带宽被限制为单个节点的带宽,单节点的流量处理能力将成为整个集群的接收外部流量的瓶颈。
在故障转移方面,目前的机制是MetalLB通过发送2层数据包来通知各个节点,并重新选举Leader,这通常能在几秒内完成。但如果是计划外的事故导致的,此时在有故障的客户端刷新其缓存条目之前,将无法访问服务IP。
BGP模式
BGP模式是真正的负载均衡,该模式需要路由器支持BGP协议 ,群集中的每个节点会与网络路由器建议基于BGP的对等会话,并使用该会话来通告负载均衡的IP。MetalLB发布的路由彼此等效,这意味着路由器将使用所有的目标节点,并在它们之间进行负载平衡。数据包到达节点后,kube-proxy负责流量路由的最后一跳,将数据包发送到对应服务的Pod。
负载平衡的方式取决于您特定的路由器型号和配置,常见的有基于数据包哈希对每个连接进行均衡,这意味着单个TCP或UDP会话的所有数据包都将定向到群集中的单个计算机。
BGP模式也存在着自身的局限性,该模式通过对数据包头中的某些字段进行哈希处理,并将该哈希值用作后端数组的索引,将给定的数据包分配给特定的下一跳。但路由器中使用的哈希通常不稳定,因此只要后端节点数量发生变化时,现有连接就会被随机地重新哈希,这意味着大多数现有连接将被转发到另一后端,而该后端并不清楚原有的连接状态。为了减少这种麻烦,建议使用更加稳定的BGP算法,如:ECMP散列算法。
系统要求
在开始部署MetalLB之前,我们需要确定部署环境能够满足最低要求:
- 一个k8s集群,要求版本不低于1.13.0,且没有负载均衡器相关插件
- k8s集群上的CNI组件和MetalLB兼容
- 预留一段IPv4地址给MetalLB作为LoadBalance的VIP使用
- 如果使用的是MetalLB的BGP模式,还需要路由器支持BGP协议
- 如果使用的是MetalLB的Layer2模式,因为使用了memberlist算法来实现选主,因此需要确保各个k8s节点之间的7946端口可达(包括TCP和UDP协议),当然也可以根据自己的需求配置为其他端口
安装要求
准备
(根据情况而定)
如果你在 IPVS 模式下使用 kube-proxy,从 Kubernetes v1.14.2 开始,必须启用严格 ARP 模式。
注意,如果使用 kube-router 作为 service-proxy,则不需要这样做,因为它默认启用严格 ARP。
部署Layer2模式需要把k8s集群中的ipvs配置打开strictARP,开启之后k8s集群中的kube-proxy会停止响应kube-ipvs0网卡之外的其他网卡的arp请求,而由MetalLB接手处理。
strict ARP开启之后相当于把 将 arp_ignore 设置为 1 并将 arp_announce 设置为 2 启用严格的 ARP,这个原理和LVS中的DR模式对RS的配置一样,可以参考之前的文章中的解释。
可以通过编辑当前集群的 kube-proxy 配置来实现:
# 查看kube-proxy中的strictARP配置
$ kubectl get configmap -n kube-system kube-proxy -o yaml | grep strictARPstrictARP: false# 手动修改strictARP配置为true
$ kubectl edit configmap -n kube-system kube-proxy
configmap/kube-proxy edited# 使用命令直接修改并对比不同
$ kubectl get configmap kube-proxy -n kube-system -o yaml | sed -e "s/strictARP: false/strictARP: true/" | kubectl diff -f - -n kube-system# 确认无误后使用命令直接修改并生效
$ kubectl get configmap kube-proxy -n kube-system -o yaml | sed -e "s/strictARP: false/strictARP: true/" | kubectl apply -f - -n kube-system# 重启kube-proxy确保配置生效
$ kubectl rollout restart ds kube-proxy -n kube-system# 确认配置生效
$ kubectl get configmap -n kube-system kube-proxy -o yaml | grep strictARPstrictARP: true
部署MetalLB(Layer2模式)
MetalLB的部署也十分简单,官方提供了manifest文件部署(yaml部署),helm3部署和Kustomize部署三种方式,这里我们还是使用manifest文件部署。
大多数的官方教程为了简化部署的步骤,都是写着直接用kubectl命令部署一个yaml的url,这样子的好处是部署简单快捷,但是坏处就是本地自己没有存档,不方便修改等操作,因此我个人更倾向于把yaml文件下载到本地保存再进行部署
# 下载v0.12.1的两个部署文件
$ wget https://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/namespace.yaml
$ wget https://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/metallb.yaml# 如果使用frr来进行BGP路由管理,则下载这两个部署文件
$ wget https://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/namespace.yaml
$ wget https://raw.githubusercontent.com/metallb/metallb/v0.12.1/manifests/metallb-frr.yaml
下载官方提供的yaml文件之后,我们再提前准备好configmap的配置,github上面有提供一个参考文件,layer2模式需要的配置并不多,这里我们只做最基础的一些参数配置定义即可:
protocol这一项我们配置为layer2
addresses这里我们可以使用CIDR来批量配置(198.51.100.0/24),也可以指定首尾IP来配置(192.168.0.150-192.168.0.200),指定一段和k8s节点在同一个子网的IP。也可以指定宿主机的网络分配。
# config.yaml
apiVersion: v1
kind: ConfigMap
metadata:namespace: metallb-systemname: config
data:config: |address-pools:- name: defaultprotocol: layer2addresses:- 192.168.102.50-192.168.102.60
还可以指定多个网段
addresses:- 192.168.12.0/24- 192.168.144.0/20
除了自动分配IP外,Metallb 还支持在定义服务的时候,通过 spec.loadBalancerIP
指定一个静态IP 。
使用kubectl log -f [matellb-contoller-pod]能看到配置更新过程
接下来就可以开始进行部署,整体可以分为三步:
- 部署namespace
- 部署deployment和daemonset
- 配置configmap
# 创建namespace
$ kubectl apply -f namespace.yaml
namespace/metallb-system created
$ kubectl get ns
NAME STATUS AGE
default Active 8d
kube-node-lease Active 8d
kube-public Active 8d
kube-system Active 8d
metallb-system Active 8s
nginx-quic Active 8d# 部署deployment和daemonset,以及相关所需的其他资源
$ kubectl apply -f metallb.yaml
Warning: policy/v1beta1 PodSecurityPolicy is deprecated in v1.21+, unavailable in v1.25+
podsecuritypolicy.policy/controller created
podsecuritypolicy.policy/speaker created
serviceaccount/controller created
serviceaccount/speaker created
clusterrole.rbac.authorization.k8s.io/metallb-system:controller created
clusterrole.rbac.authorization.k8s.io/metallb-system:speaker created
role.rbac.authorization.k8s.io/config-watcher created
role.rbac.authorization.k8s.io/pod-lister created
role.rbac.authorization.k8s.io/controller created
clusterrolebinding.rbac.authorization.k8s.io/metallb-system:controller created
clusterrolebinding.rbac.authorization.k8s.io/metallb-system:speaker created
rolebinding.rbac.authorization.k8s.io/config-watcher created
rolebinding.rbac.authorization.k8s.io/pod-lister created
rolebinding.rbac.authorization.k8s.io/controller created
daemonset.apps/speaker created
deployment.apps/controller created# 这里主要就是部署了controller这个deployment来检查service的状态
$ kubectl get deploy -n metallb-system
NAME READY UP-TO-DATE AVAILABLE AGE
controller 1/1 1 1 86s
# speaker则是使用ds部署到每个节点上面用来协商VIP、收发ARP、NDP等数据包
$ kubectl get ds -n metallb-system
NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE
speaker 3 3 3 3 3 kubernetes.io/os=linux 64s
$ kubectl get pod -n metallb-system -o wideNAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
controller-55bbcf48c8-qst68 1/1 Running 0 2d19h 172.20.28.118 node02 <none> <none>
speaker-8wctf 1/1 Running 0 2d19h 192.168.102.41 node02 <none> <none>
speaker-txdsv 1/1 Running 0 2d19h 192.168.102.30 master01 <none> <none>
speaker-xdzrr 1/1 Running 0 2d19h 192.168.102.40 node01 <none> <none>$ kubectl apply -f configmap-layer2.yaml
configmap/config createdkubectl wait --for=condition=Ready pods --all -n metallb-system# pod/controller-57fd9c5bb-d5z9j condition met
# pod/speaker-6hz2h condition met
# pod/speaker-7pzb4 condition met
# pod/speaker-trr9v condition met
部署测试服务
# mentallb/whoami.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: whoamilabels:app: containousname: whoami
spec:replicas: 2selector:matchLabels:app: containoustask: whoamitemplate:metadata:labels:app: containoustask: whoamispec:containers:- name: containouswhoamiimage: containous/whoamiresources:ports:- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:name: whoami
spec:ports:- name: httpport: 80selector:app: containoustask: whoamitype: LoadBalancer
或者 nginx
apiVersion: apps/v1
kind: Deployment
metadata:name: nginx
spec:replicas: 3selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: nginx:1.23-alpineports:- name: httpcontainerPort: 80---
apiVersion: v1
kind: Service
metadata:name: nginx
spec:#loadBalancerIP: x.y.z.a # 指定公网IPports:- name: httpport: 80protocol: TCPtargetPort: 80selector:app: nginxtype: LoadBalancer
可见分配的 EXTERNAL-IP 为 192.168.102.52
分别在虚拟机和宿主机试试:
curl 192.168.102.52[root@bt metallb]# curl 192.168.102.52
Hostname: whoami-665585b57c-kngqc
IP: 127.0.0.1
IP: 172.20.28.123
RemoteAddr: 127.0.0.6:47635
GET / HTTP/1.1
Host: 192.168.102.52
User-Agent: curl/7.29.0
Accept: */*
X-B3-Sampled: 1
X-B3-Spanid: 0268f13fd66b2858
X-B3-Traceid: c6984aca633971850268f13fd66b2858
X-Forwarded-Proto: http
X-Request-Id: 6664e21c-b2d4-9abe-af63-6d79485cbdd8
这时如果你 ping
这个 ip 的话,会发现无法 ping 通
这个是正常的,因为它是一个虚拟IP地址,所以根本无法ping 通(此虚拟IP与物理网卡共用同一个 MAC
地址,那么这个IP是如何工作的呢?又是如何收到流量请求的呢?很值得思考)。
那如何测试这个虚拟IP是否能正常提供服务呢,其实只需要使用 telnet 命令就可以了,如
[root@bt metallb]# telnet 192.168.102.52 80
Trying 192.168.102.52...
Connected to 192.168.102.52.
Escape character is '^]'.
注意:
注意:并非所有的LoadBalancer都允许设置 loadBalancerIP。
如果LoadBalancer支持该字段,那么将根据用户设置的 loadBalancerIP 来创建负载均衡器。
如果没有设置 loadBalancerIP 字段,将会给负载均衡器指派一个临时 IP。
如果设置了 loadBalancerIP,但LoadBalancer并不支持这种特性,那么设置的 loadBalancerIP 值将会被忽略掉。
我们在创建LoadBalancer服务的时候,默认情况下k8s会帮我们自动创建一个nodeport服务,这个操作可以通过指定Service中的allocateLoadBalancerNodePorts字段来定义开关,默认情况下为true
不同的loadbalancer实现原理不同,有些是需要依赖nodeport来进行流量转发,有些则是直接转发请求到pod中。对于MetalLB而言,是通过kube-proxy将请求的流量直接转发到pod,因此我们需要关闭nodeport的话可以修改service中的spec.allocateLoadBalancerNodePorts字段,将其设置为false,那么在创建svc的时候就不会分配nodeport。
但是需要注意的是如果是对已有service进行修改,关闭nodeport(从true改为false),k8s不会自动去清除已有的ipvs规则,这需要我们自行手动删除。
我们重新定义创建一个svc
apiVersion: v1
kind: Service
metadata:name: nginx-lb-servicenamespace: nginx-quic
spec:allocateLoadBalancerNodePorts: falseexternalTrafficPolicy: ClusterinternalTrafficPolicy: Clusterselector:app: nginx-lbports:- protocol: TCPport: 80 # match for service access porttargetPort: 80 # match for pod access porttype: LoadBalancerloadBalancerIP: 10.31.8.100
此时再去查看对应的svc状态和ipvs规则会发现已经没有nodeport相关的配置
$ ipvsadm -ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags-> RemoteAddress:Port Forward Weight ActiveConn InActConn
TCP 10.8.62.180:80 rr-> 10.8.65.18:80 Masq 1 0 0-> 10.8.65.19:80 Masq 1 0 0-> 10.8.66.14:80 Masq 1 0 0-> 10.8.66.15:80 Masq 1 0 0
TCP 10.31.8.100:80 rr-> 10.8.65.18:80 Masq 1 0 0-> 10.8.65.19:80 Masq 1 0 0-> 10.8.66.14:80 Masq 1 0 0-> 10.8.66.15:80 Masq 1 0 0$ kubectl get svc -n nginx-quic
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-lb-service LoadBalancer 10.8.62.180 10.31.8.100 80/TCP 23s
如果是把已有服务的spec.allocateLoadBalancerNodePorts从true改为false,原有的nodeport不会自动删除,因此最好在初始化的时候就规划好相关参数
$ kubectl get svc -n nginx-quic nginx-lb-service -o yaml | egrep " allocateLoadBalancerNodePorts: "allocateLoadBalancerNodePorts: false
$ kubectl get svc -n nginx-quic
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-lb-service LoadBalancer 10.8.62.180 10.31.8.100 80:31405/TCP 85m
参考文档:
https://tinychen.com/20220519-k8s-06-loadbalancer-metallb
https://juejin.cn/post/6906447786112516110
相关文章:

MetalLB:本地Kubernetes集群的LoadBalancer负载均衡利器
背景 在本地集群进行测试时,我们常常面临一个棘手的问题:Service Type不支持LoadBalancer,而我们只能选择使用NodePort作为替代。这种情况下,我们通常会配置Service为NodePort,并使用externalIPs将流量导入Kubernetes…...
C++判定终端ip和目标ip是否在同一局域网内
程序如下:用于判断给定的终端 IP、子网掩码和目标 IP 是否在同一局域网内。请注意,这个程序假设 IP 地址是用整数表示的。 #include <iostream> #include <sstream> #include <vector> #include <bitset>// Function to check …...

深入解析 可空值类型
前言: 问:为什么会有可空值类型的诞生? 答:应对在某些特定场景中获取的信息可能是不完整的。 C# 1中的可空值类型 在C#1中没有对应的表示Null值的方法。当时普遍都是采用其他方式。第一种在数据缺失的情况下给其一个默认值。第…...
esp32idf使用thingscloud例程
对于不同的消息类型,API 如下: 消息类型 HTTP Method HTTP URL 设备上报属性 POST /device/v1//attributes 设备获取属性 GET /device/v1//attributes 设备上报事件 POST /device/v1//event/report 您只需要将以上的 HTTP URL 和接入点拼接即可获得最终…...

记一次应急响应练习(Linux)
记一次应急响应练习(Linux) Linux: 请提交攻击者的IP地址 答: 192.168.31.132 思路: 通过查看历史命令和开放的8080端口看到这台主机上运行的是Tomcat服务。并且在历史命令中看到了Tomcat的安装路径。那么就算是找到了日志的查看点了&#x…...

Pandas教程(四)—— 分层索引及数据联合
1.分层索引 分层索引就是在一个轴上拥有多个(两个及以上)索引级别,能以低维度形式处理高维度数据。 行索引有两层 1.1 分层索引的创建 1.1.1 方式一:直接设置 1)在创建series、dataframe或读取文件时时,行…...

小梅哥Xilinx FPGA学习笔记16——FSM(状态机)的学习
目录 一、 状态机导读 1.1 理论学习 1.2 状态机的表示 1.3 状态机编码 1.4 状态机描述方式 二 、实战演练一(来自野火) 2.1 实验目标 2.2 模块框图 2.3 状态转移图绘制 2.4 设计文件 2.5 仿真测试文件 2.6 仿真结果 三、 实战演练二&…...
vol----学习随记!!!
目录 一、代码生成1.先新建一个功能的对应的代码配置各项解释: 2.后设置配置菜单3.再点保存,生成vue页面,生成model,生成业务类4.再通过菜单设置编写系统菜单 一、代码生成 1.先新建一个功能的对应的代码配置 各项解释ÿ…...

HarmonyOS4.0系统性深入开发10卡片事件能力说明
卡片事件能力说明 ArkTS卡片中提供了postCardAction()接口用于卡片内部和提供方应用间的交互,当前支持router、message和call三种类型的事件,仅在卡片中可以调用。 接口定义:postCardAction(component: Object, action: Object): void 接口…...

openGauss学习笔记-181 openGauss 数据库运维-升级-升级流程
文章目录 openGauss学习笔记-181 openGauss 数据库运维-升级-升级流程 openGauss学习笔记-181 openGauss 数据库运维-升级-升级流程 本章介绍升级到该版本的主要升级过程。 图 1 升级流程图 说明: 本文档中描述的时间仅供参考,实际操作时间以现场情况…...

提前应对威胁
通过新的《2023-2028 年荷兰国际网络安全战略》,荷兰政府在面对国家和犯罪分子持续构成的网络威胁时展现了责任和机构。它渴望将民主、人权和规范放在首位,并寻求维护全球开放、自由和安全的互联网。该战略明确了政府在国内实施打击的意愿和能力…...

C语言与人生:数组交换和二分查找
少年们,大家好。我是博主那一脸阳光,今天和分享数组交换和二分查找。 前言:探索C语言中的数组交换操作与二分查找算法 在计算机编程领域,特别是以C语言为代表的低级编程语言中,对数据结构的理解和熟练运用是至关重要的…...

Python实现【亚马逊商品】数据采集
前言 亚马逊公司,是美国最大的一家网络电子商务公司,位于华盛顿州的西雅图 是网络上最早开始经营电子商务的公司之一,亚马逊成立于1994年 今天教大家用Python批量采集亚马逊平台商品数据(完整代码放在文末) 地址&#…...

Git使用教程 gittutorial
该教程对该文章的翻译:https://git-scm.com/docs/gittutorial 本文介绍怎用使用 Git 导入新的工程、修改文件及如何其他人同步开发。 首先, 可以使用以下指令获取文档帮助 git help log笔者注:不建议看这个文档,标准的语法介绍…...

有了向量数据库,我们还需 SQL 数据库吗?
“除了向量数据库外,我是否还需要一个普通的 SQL 数据库?” 这是我们经常被问到的一个问题。如果除了向量数据以外,用户还有其他标量数据信息,那么其业务可能需要在进行语义相似性搜索前先根据某种条件过滤数据,例如&a…...

信息网络协议基础-IPv6协议
文章目录 概述为什么引入IP服务模型IPv4的可扩展性问题解决方法***CIDR(Classless Inter-Domain Routing, 无类别域间寻路)前缀汇聚***前缀最长匹配***NAT(网络地址转换)存在的问题解决方案路由表配置***局限性IPv6协议头标IPv6地址表示前缀类型单播地址链路局部地址(Link-Loca…...

VC++ ado 实现单表CURD
继续修改前文的资产管理源码; 新建一个数据库sds;把代码中的数据库连接改为连接此库; 新建下图一个表; 把之前的资产类别管理对话框改为下图所示;对话框ID也改为下图; 资产类别管理菜单和ID改为下图; 直接修改资产类别管理对话框类不太方便,新建一个对话框类,没有关联…...

C#使用switch多路选择语句判断何为季节
目录 一、 switch语句 二、示例 三、生成 一、 switch语句 switch语句是多路选择语句,它通过一个表达式的值来使程序从多个分支中选取一个用于执行的分支。 switch表达式的值只可以是整型、字符串、枚举和布尔类型。 switch语句中多个case可以使用一个break。 在…...

可爱的魔法曲线 Lovely Magical Curves(12年开始只有5个人AC)
一起来交流编程吧!【CSDN app】:http://qm.qq.com/cgi-bin/qm/qr?_wv1027&k3svdDJTlkD76TRRShbxYCYK1zK1c8cyF&authKeyv1pxp6rS8AA4SRy7bflJl9LIwp8d5v0HOudw%2BDxHiWDRqZ1LzjeoBJH1Z1EXnl35&noverify0&group_code546881376 可爱的魔法…...

通过C++程序实现光驱的自动化刻录和读取
文章目录 ISO文件格式光盘的基本概念光盘种类特点DVDR光盘使用windows调用Linux调用Linux平台下用到的C库:读取设备驱动列表向光驱中写文件 数字存储媒体快速发展的今天,光驱的使用已经不像以前那样普及了。但是在数据备份、安装软件和操作系统、旧设备兼容等领域还…...

UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...

C++初阶-list的底层
目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试
作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...

YSYX学习记录(八)
C语言,练习0: 先创建一个文件夹,我用的是物理机: 安装build-essential 练习1: 我注释掉了 #include <stdio.h> 出现下面错误 在你的文本编辑器中打开ex1文件,随机修改或删除一部分,之后…...
pam_env.so模块配置解析
在PAM(Pluggable Authentication Modules)配置中, /etc/pam.d/su 文件相关配置含义如下: 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块,负责验证用户身份&am…...
使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装
以下是基于 vant-ui(适配 Vue2 版本 )实现截图中照片上传预览、删除功能,并封装成可复用组件的完整代码,包含样式和逻辑实现,可直接在 Vue2 项目中使用: 1. 封装的图片上传组件 ImageUploader.vue <te…...

MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...
Spring AI与Spring Modulith核心技术解析
Spring AI核心架构解析 Spring AI(https://spring.io/projects/spring-ai)作为Spring生态中的AI集成框架,其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似,但特别为多语…...

Appium下载安装配置保姆教程(图文详解)
目录 一、Appium软件介绍 1.特点 2.工作原理 3.应用场景 二、环境准备 安装 Node.js 安装 Appium 安装 JDK 安装 Android SDK 安装Python及依赖包 三、安装教程 1.Node.js安装 1.1.下载Node 1.2.安装程序 1.3.配置npm仓储和缓存 1.4. 配置环境 1.5.测试Node.j…...