Kubernetes_KubeProxy_Service找到Pod与DNS解析Service/Pod

news2024/9/23 19:25:19

文章目录

  • 前言
  • 一、Service找到Pod(Iptables)
  • 二、Service找到Pod(IPVS)
    • 2.1 IPVS模式原理
    • 2.2 IPVS模式实践
      • 修改为 IPVS 模式 之前
      • 修改为 IPVS 模式之中
      • 修改为 IPVS 模式之后
  • 三、Service和Pod的DNS域名
  • 尾声

前言

一、Service找到Pod(Iptables)

在前面的文章中,我们已经多次使用到了 Service 这个 Kubernetes 里重要的服务对象。而 Kubernetes 之所以需要 Service,一方面是因为 Pod 的 IP 不是固定的,另一方面则是因为一组 Pod 实例之间总会有负载均衡的需求。一个最典型的 Service 定义,如下所示:

一个最典型的 Service 定义,如下所示:

apiVersion: v1
kind: Service
metadata:
  name: hostnames
spec:
  selector:
    app: hostnames
  ports:
  - name: default
    protocol: TCP
    port: 80
    targetPort: 9376

这个 Service 的例子,相信你不会陌生。其中,我使用了 selector 字段来声明这个 Service 只代理携带了 app=hostnames 标签的 Pod。并且,这个 Service 的 80 端口,代理的是 Pod 的 9376 端口。

然后,我们的应用的 Deployment,如下所示:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: hostnames
spec:
  selector:
    matchLabels:
      app: hostnames
  replicas: 3
  template:
    metadata:
      labels:
        app: hostnames
    spec:
      containers:
      - name: hostnames
        image: k8s.gcr.io/serve_hostname
        ports:
        - containerPort: 9376
          protocol: TCP

这个应用的作用,就是每次访问 9376 端口时,返回它自己的 hostname。

而被 selector 选中的 Pod,就称为 Service 的 Endpoints,你可以使用 kubectl get ep 命令看到它们,如下所示:

$ kubectl get endpoints hostnames
NAME        ENDPOINTS
hostnames   10.244.0.5:9376,10.244.0.6:9376,10.244.0.7:9376

要注意的是,只有处于 Running 状态,且 readinessProbe 检查通过的 Pod,才会出现在 Service 的 Endpoints 列表里。并且,当某一个 Pod 出现问题时,Kubernetes 会自动把它从 Service 里摘除掉。

而此时,通过该 Service 的 VIP 地址 10.0.1.175,你就可以访问到它所代理的 Pod 了:

$ kubectl get svc hostnames
NAME        TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
hostnames   ClusterIP   10.0.1.175   <none>        80/TCP    5s
 
$ curl 10.0.1.175:80
hostnames-0uton
 
$ curl 10.0.1.175:80
hostnames-yp2kp
 
$ curl 10.0.1.175:80
hostnames-bvc05

这个 VIP 地址是 Kubernetes 自动为 Service 分配的。而像上面这样,通过三次连续不断地访问 Service 的 VIP 地址和代理端口 80,它就为我们依次返回了三个 Pod 的 hostname。这也正印证了 Service 提供的是 Round Robin 方式的负载均衡。对于这种方式,我们称为:ClusterIP 模式的 Service。

你可能一直比较好奇,Kubernetes 里的 Service 究竟是如何工作的呢?

实际上,Service 是由 kube-proxy 组件,加上 iptables 来共同实现的。

举个例子,对于我们前面创建的名叫 hostnames 的 Service 来说,一旦它被提交给 Kubernetes,那么 kube-proxy 就可以通过 Service 的 Informer 感知到这样一个 Service 对象的添加。而作为对这个事件的响应,它就会在宿主机上创建这样一条 iptables 规则(你可以通过 iptables-save 看到它),如下所示:

在这里插入图片描述

-A KUBE-SERVICES -d 10.0.1.175/32 -p tcp -m comment --comment "default/hostnames: cluster IP" \
-m tcp --dport 80 -j KUBE-SVC-NWV5X2332I4OT4T3

可以看到,这条 iptables 规则的含义是:凡是目的地址是 10.0.1.175、目的端口是 80 的 IP 包,都应该跳转到另外一条名叫 KUBE-SVC-NWV5X2332I4OT4T3 的 iptables 链进行处理。

而我们前面已经看到,10.0.1.175 正是这个 Service 的 VIP。所以这一条规则,就为这个 Service 设置了一个固定的入口地址。并且,由于 10.0.1.175 只是一条 iptables 规则上的配置,并没有真正的网络设备,所以你 ping 这个地址,是不会有任何响应的。

那么,我们即将跳转到的 KUBE-SVC-NWV5X2332I4OT4T3 规则,又有什么作用呢?实际上,它是一组规则的集合,如下所示:

-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -m statistic \
--mode random --probability 0.33332999982 -j KUBE-SEP-WNBA2IHDGP2BOBGZ
 
-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -m statistic \
--mode random --probability 0.50000000000 -j KUBE-SEP-X3P2623AGDH6CDF3
 
-A KUBE-SVC-NWV5X2332I4OT4T3 -m comment --comment "default/hostnames:" -j KUBE-SEP-57KPRZ3JQVENLNBR

可以看到,这一组规则,实际上是一组随机模式(–mode random)的 iptables 链。

而随机转发的目的地,分别是 KUBE-SEP-WNBA2IHDGP2BOBGZ、KUBE-SEP-X3P2623AGDH6CDF3 和 KUBE-SEP-57KPRZ3JQVENLNBR。

而这三条链指向的最终目的地,其实就是这个 Service 代理的三个 Pod。所以这一组规则,就是 Service 实现负载均衡的位置。

需要注意的是,iptables 规则的匹配是从上到下逐条进行的,所以为了保证上述三条规则每条被选中的概率都相同,我们应该将它们的 probability 字段的值分别设置为 1/3(0.333…)、1/2 和 1。

这么设置的原理很简单:第一条规则被选中的概率就是 1/3;而如果第一条规则没有被选中,那么这时候就只剩下两条规则了,所以第二条规则的 probability 就必须设置为 1/2;类似地,最后一条就必须设置为 1。

你可以想一下,如果把这三条规则的 probability 字段的值都设置成 1/3,最终每条规则被选中的概率会变成多少。

通过查看上述三条链的明细,我们就很容易理解 Service 进行转发的具体原理了,如下所示:

-A KUBE-SEP-57KPRZ3JQVENLNBR -s 10.244.3.6/32 -m comment --comment "default/hostnames:" \
-j MARK --set-xmark 0x00004000/0x00004000
-A KUBE-SEP-57KPRZ3JQVENLNBR -p tcp -m comment --comment "default/hostnames:" \
-m tcp -j DNAT --to-destination 10.244.3.6:9376
 
-A KUBE-SEP-WNBA2IHDGP2BOBGZ -s 10.244.1.7/32 -m comment --comment "default/hostnames:" \
-j MARK --set-xmark 0x00004000/0x00004000
-A KUBE-SEP-WNBA2IHDGP2BOBGZ -p tcp -m comment --comment "default/hostnames:" \
-m tcp -j DNAT --to-destination 10.244.1.7:9376
 
-A KUBE-SEP-X3P2623AGDH6CDF3 -s 10.244.2.3/32 -m comment --comment "default/hostnames:" \
-j MARK --set-xmark 0x00004000/0x00004000
-A KUBE-SEP-X3P2623AGDH6CDF3 -p tcp -m comment --comment "default/hostnames:" \
-m tcp -j DNAT --to-destination 10.244.2.3:9376

可以看到,这三条链,其实是三条 DNAT 规则。但在 DNAT 规则之前,iptables 对流入的 IP 包还设置了一个“标志”(–set-xmark)。这个“标志”的作用,我会在下一篇文章再为你讲解。

而 DNAT 规则的作用,就是在 PREROUTING 检查点之前,也就是在路由之前,将流入 IP 包的目的地址和端口,改成–to-destination 所指定的新的目的地址和端口。可以看到,这个目的地址和端口,正是被代理 Pod 的 IP 地址和端口。

这样,访问 Service VIP 的 IP 包经过上述 iptables 处理之后,就已经变成了访问具体某一个后端 Pod 的 IP 包了。

不难理解,这些 Endpoints 对应的 iptables 规则,正是 kube-proxy 通过监听 Pod 的变化事件,在宿主机上生成并维护的。

以上,就是 Service 最基本的工作原理。

此外,你可能已经听说过,Kubernetes 的 kube-proxy 还支持一种叫作 IPVS 的模式。这又是怎么一回事儿呢?

其实,通过上面的讲解,你可以看到,kube-proxy 通过 iptables 处理 Service 的过程,其实需要在宿主机上设置相当多的 iptables 规则。而且,kube-proxy 还需要在控制循环里不断地刷新这些规则来确保它们始终是正确的。

不难想到,当你的宿主机上有大量 Pod 的时候,成百上千条 iptables 规则不断地被刷新,会大量占用该宿主机的 CPU 资源,甚至会让宿主机“卡”在这个过程中。

所以说,一直以来,基于 iptables 的 Service 实现,都是制约 Kubernetes 项目承载更多量级的 Pod 的主要障碍。 而 IPVS 模式的 Service,就是解决这个问题的一个行之有效的方法。

二、Service找到Pod(IPVS)

2.1 IPVS模式原理

IPVS 模式的工作原理,其实跟 iptables 模式类似。当我们创建了前面的 Service 之后,kube-proxy 首先会在宿主机上创建一个虚拟网卡(叫作:kube-ipvs0),并为它分配 Service VIP 作为 IP 地址,如下所示:

# ip addr
  ...
  73:kube-ipvs0:<BROADCAST,NOARP>  mtu 1500 qdisc noop state DOWN qlen 1000
  link/ether  1a:ce:f5:5f:c1:4d brd ff:ff:ff:ff:ff:ff
  inet 10.0.1.175/32  scope global kube-ipvs0
  valid_lft forever  preferred_lft forever

而接下来,kube-proxy 就会通过 Linux 的 IPVS 模块,为这个 IP 地址设置三个 IPVS 虚拟主机,并设置这三个虚拟主机之间使用轮询模式 (rr) 来作为负载均衡策略。我们可以通过 ipvsadm 查看到这个设置,如下所示:

# ipvsadm -ln
 IP Virtual Server version 1.2.1 (size=4096)
  Prot LocalAddress:Port Scheduler Flags
    ->  RemoteAddress:Port           Forward  Weight ActiveConn InActConn     
  TCP  10.102.128.4:80 rr
    ->  10.244.3.6:9376    Masq    1       0          0         
    ->  10.244.1.7:9376    Masq    1       0          0
    ->  10.244.2.3:9376    Masq    1       0          0

可以看到,这三个 IPVS 虚拟主机的 IP 地址和端口,对应的正是三个被代理的 Pod。

这时候,任何发往 10.102.128.4:80 的请求,就都会被 IPVS 模块转发到某一个后端 Pod 上了。

而相比于 iptables,IPVS 在内核中的实现其实也是基于 Netfilter 的 NAT 模式,所以在转发这一层上,理论上 IPVS 并没有显著的性能提升。但是,IPVS 并不需要在宿主机上为每个 Pod 设置 iptables 规则,而是把对这些“规则”的处理放到了内核态,从而极大地降低了维护这些规则的代价。这也正印证了我在前面提到过的,“将重要操作放入内核态”是提高性能的重要手段。

不过需要注意的是,IPVS 模块只负责上述的负载均衡和代理功能。而一个完整的 Service 流程正常工作所需要的包过滤、SNAT 等操作,还是要靠 iptables 来实现。只不过,这些辅助性的 iptables 规则数量有限,也不会随着 Pod 数量的增加而增加。

所以,在大规模集群里,我非常建议你为 kube-proxy 设置–proxy-mode=ipvs 来开启这个功能。它为 Kubernetes 集群规模带来的提升,还是非常巨大的。

2.2 IPVS模式实践

修改为 IPVS 模式 之前

修改为 IPVS 模式之前
(1) addr ip 没找到 ipvs0 网卡
(2) ipvsadm -ln 没找到 svc ip 下面的 pod ip

# 执行ip addr命令,无法ipvs0网卡
ip addr

在这里插入图片描述

# yum源安装ipvsadm (yum list | grep ipvsadm)
yum install ipvsadm

# 执行ipvsadm -ln命令,无法看到任何svc转到Pod
ipvsadm -ln

在这里插入图片描述

在这里插入图片描述

修改为 IPVS 模式之中

kubectl edit configmap kube-proxy -n kube-system
kubectl delete pod pod-name -n kube-system
kubectl get pod -n kube-system -w

在这里插入图片描述

在这里插入图片描述

修改为 IPVS 模式之后

修改为 IPVS 模式之后
(1) addr ip 找到了 ipvs0 网卡
(2) ipvsadm -ln 找到了 svc ip 下面的 pod ip

ipvsadm -ln 找到了 svc ip 下面的 pod ip,等效于 kubectl get svc + kubectl get endpoints, svc 可以看到 svc ip , endpoints可以看到这个svc ip 下面有哪些 pod ip, 因为这个 ipvsadm -ln 就是 svc 和 endpoint 的底层原理

ipaddr 

ipvsadm -ln
kubectl get svc -o wide -A
kubectl get endpoints -o wide -A
kubectl get endpoints xxx -o yaml  -A 或者 kubectl describe endpoints xxx  -A

在这里插入图片描述

在这里插入图片描述

三、Service和Pod的DNS域名

此外,我在前面的文章中还介绍过 Service 与 DNS 的关系。在 Kubernetes 中,Service 和 Pod 都会被分配对应的 DNS A 记录(从域名解析 IP 的记录)。

  1. 对于 ClusterIP 模式的 Service 来说(比如我们上面的例子),它的 A 记录的格式是:…svc.cluster.local。当你访问这条 A 记录的时候,它解析到的就是该 Service 的 VIP 地址。
  2. 对于 ClusterIP 模式的 Service 来说,它代理的 Pod 被自动分配的 A 记录的格式是:…pod.cluster.local。这条记录指向 Pod 的 IP 地址。
  3. 对于指定了 clusterIP=None 的 Headless Service 来说,它的 A 记录的格式也是:…svc.cluster.local。但是,当你访问这条 A 记录的时候,它返回的是所有被代理的 Pod 的 IP 地址的集合。当然,如果你的客户端没办法解析这个集合的话,它可能会只会拿到第一个 Pod 的 IP 地址。
  4. 对 Headless Service 来说,它代理的 Pod 被自动分配的 A 记录的格式是:…svc.cluster.local。这条记录也指向 Pod 的 IP 地址。

但如果你为 Pod 指定了 Headless Service,并且 Pod 本身声明了 hostname 和 subdomain 字段,那么这时候 Pod 的 A 记录就会变成:<pod 的 hostname>…svc.cluster.local,比如:

apiVersion: v1
kind: Service
metadata:
  name: default-subdomain
spec:
  selector:
    name: busybox
  clusterIP: None
  ports:
  - name: foo
    port: 1234
    targetPort: 1234
---
apiVersion: v1
kind: Pod
metadata:
  name: busybox1
  labels:
    name: busybox
spec:
  hostname: busybox-1
  subdomain: default-subdomain
  containers:
  - image: busybox
    command:
      - sleep
      - "3600"
    name: busybox

在上面这个 Service 和 Pod 被创建之后,你就可以通过 busybox-1.default-subdomain.default.svc.cluster.local 解析到这个 Pod 的 IP 地址了。

需要注意的是,在 Kubernetes 里,/etc/hosts 文件是单独挂载的,这也是为什么 kubelet 能够对 hostname 进行修改并且 Pod 重建后依然有效的原因。这跟 Docker 的 Init 层是一个原理。

在这里插入图片描述

尾声

在这篇文章里,我为你详细讲解了 Service 的工作原理。实际上,Service 找到 Pod 的 KubeProxy 两种模式,以及 Kubernetes 里的 DNS 插件,都是在帮助你解决同样一个问题,即:如何找到我的某一个容器?

这个问题在平台级项目中,往往就被称作服务发现,即:当我的一个服务(Pod)的 IP 地址是不固定的且没办法提前获知时,我该如何通过一个固定的方式访问到这个 Pod 呢?

而我在这里讲解的、ClusterIP 模式的 Service 为你提供的,就是一个 Pod 的稳定的 IP 地址,即 VIP (Virtual IP 虚拟IP)。并且,这里 Pod 和 Service 的关系是可以通过 Label 确定的。

而 Headless Service 为你提供的,则是一个 Pod 的稳定的 DNS 名字,并且,这个名字是可以通过 Pod 名字和 Service 名字拼接出来的。

在实际的场景里,你应该根据自己的具体需求进行合理选择。

值得注意的知识点:

  1. iptables模式中: 规则的匹配是从上到下逐条进行的,所以为了保证上述三条规则每条被选中的概率都相同,我们应该将它们的 probability 字段的值分别设置为 1/3(0.333…)、1/2 和 1。
  2. iptables模式中: 使用 iptables-save 命令查看 iptables 规则
  3. ipvs模式中: 修改为 ipvs 模式的时候,修改configmap,然后重启 Pod
  4. ipvs模式中: iptables模式和ipvs模式性能一样的,只是ipvs模式不需要规则随Pod增加而增加

参考:Service找到Pod与DNS解析Service/Pod

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

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

相关文章

【动态规划算法】第十题:174.地下城游戏

&#x1f496;作者&#xff1a;小树苗渴望变成参天大树&#x1f388; &#x1f389;作者宣言&#xff1a;认真写好每一篇博客&#x1f4a4; &#x1f38a;作者gitee:gitee✨ &#x1f49e;作者专栏&#xff1a;C语言,数据结构初阶,Linux,C 动态规划算法&#x1f384; 如 果 你…

Java中如何定义一个线程工厂?

线程工厂官方文档&#xff1a; 在Java中&#xff0c;可以通过实现ThreadFactory接口来定义一个线程工厂。线程工厂用于创建新的线程对象&#xff0c;并可以自定义线程的属性、命名规则等。 下面是一个简单的示例代码&#xff0c;展示如何定义一个线程工厂&#xff1a; import…

路径规划算法:基于学校优化优化的路径规划算法- 附代码

路径规划算法&#xff1a;基于学校优化优化的路径规划算法- 附代码 文章目录 路径规划算法&#xff1a;基于学校优化优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要&#xff1a;本文主要介绍利用智能优化…

抖音账号矩阵系统|源码|开源代码独立部署难度-开发者分享

抖音账号矩阵系统&#xff0c;短视频账号矩阵系统源码&#xff0c; 短视频矩阵是一种常见的视频编码标准&#xff0c;它通过将视频分成多个小块并对每个小块进行压缩来实现高效的视频传输。短视频多账号矩阵系统&#xff0c;通过多账号一键授权管理的方式&#xff0c;为运营人员…

学生信息管理系统——C语言版

C语言版学生信息管理系统 一&#xff0c;开发环境 操作系统&#xff1a;windows10, windows11, linux, mac等。开发工具&#xff1a;Qt, vscode, visual studio等开发语言&#xff1a;c语言 二&#xff0c;功能需求 用户界面: 提供一个简洁的文本界面&#xff0c;用户可以通…

EA编写的十大注意事项:避免常见的错误和陷阱

EA编写是一项复杂而有挑战性的任务&#xff0c;需要投资者具备一定的编程技能及丰富的交易经验。下面我将分享EA编写过程中的十大注意事项&#xff0c;以及如何避免常见的错误和陷阱。 设定明确的目标和策略 在编写EA之前&#xff0c;一定要明确交易目标和策略。这包括交易工具…

从OVF矢量场文件中获取磁斯格明子的位置和半径的粗略方法(trace skyrmion)

文章目录 前言一、使用oommf的avf2odt命令行程序获取斯格明子中心位置的示例二、当磁体系的单个xy平面层仅有一个斯格明子的情况1.读取所有磁化文件中的指定磁化分量2.筛选出每一个xy平面层中位于磁化分量阈值范围内的单元格3.计算组成磁结构的所有单元格的平均坐标和平均距离 …

今年想考CISP,速看这篇

关键词&#xff1a;CISP考试&#xff0c;CISP认证&#xff0c;CISP报名条件&#xff0c;CISP培训&#xff0c;CISP考试费用&#xff0c;CISP考试大纲 注册信息安全专业人员&#xff08;Certified Information Security Professional&#xff0c;简称“CISP"&#xff09;&…

如何处理Long类型精度丢失问题?

如何处理Long类型精度丢失问题?_拒绝画大饼的博客-CSDN博客 解决问题&#xff1a;long型数据精度丢失_long精度丢失_YOLO小蜗的博客-CSDN博客 原因分析 通过观察控制台输出的SQL发现页面传递过来的员工id的值和数据库中的id值不一致&#xff0c;这是怎么回事呢&#xff1f; 在…

Node中的模块引擎EJS模块渲染

1.导入 const ejsrequire("ejs") 2.声明数组 const group["张三","李四","王二","麻子"] 3.EJS实现 let resultejs.render(<ul> <% group.forEach(item>{ %> <li><%item%></li> <% }) …

ionic实现滑动的三种方式

ionic实现滑动的三种方式 在移动端受屏幕大小所限&#xff0c;展示内容很多的时候&#xff0c;就要使部分区域进行滑动。本文展示项目中所有到的几种方式&#xff0c;大家可以看自己的需求选择合适的滑动方式。实现滑动的基本原理&#xff0c;有两个容器A、B,假如A在外层&#…

[element-ui] el-descriptions站位,换行用法

使用element-ui组件el-descriptions element-ui组件el-descriptions官方文档 需要将el-descriptions-item换行用法&#xff1a;使用span &#xff08;1&#xff09;span 代表占位&#xff0c;当span 的值大于 column的值&#xff0c;就会自动换一行 &#xff08;2&#xff0…

通过正则表达式删除包含某个字符串的一整行

正则表达式为&#xff1a;^.*YourString.*\R 以下为NotePad编辑器的操作步骤&#xff1a; 1、CtrlH打开文本编辑器的替换功能 2、将上面的正则表达式复制到"查找目标"文本框 3、"替换为"文本框置为空 4、勾选“正则表达式” 5、点击替换或者全部替换

数据结构-ArrayList

目录 线性表 顺序表 ArrayList ArrayList的使用 ArrayList的构造方法 ArrayList的常用方法 ArrayList的遍历 实现简单的ArrayList 洗牌算法 删除公共字符串问题 杨辉三角 线性表 线性表是n个具有相同特性的数据元素的有限序列.线性表是一种在实际中广泛使用的数据结…

【标准】国家标准GB7713-87(科学论文编写格式)

目 录 1 引言 2 定义 2.1 科学技术报告 2.2 学位论文 2.3 学术论文 3 编写要求 4 编写格式 5 前置部分 5.1 封面 5.2 封二 5.3 题名页 5.4 变异本 5.5 题名 5.6 序或前言 5.7 摘要 5.8 关键词 5.9 目次页 6 主体部分 6.1 格式 6.2 序号 6.3 引言(或绪论)…

如何在没有软件的情况下将 PDF 转换为 PPT(100% 免费)

演示文稿由文字、图片、音频、动画等元素组成&#xff0c;通常用于会议、课堂或演讲中&#xff0c;展示演讲者想要表达的主要内容。如果您遇到重要文档以 PDF 格式存储&#xff0c;但现在需要转换为 PPT 格式的情况&#xff0c;请不要担心。我们本指南的目标是帮助用户将 PDF 转…

BeanFactory和ApplicationContext的入门、关系和继承

BeanFactory快速入门 ApplicationContext快速入门 BeanFactory与ApplicationContext的关系 1)BeanFactory是Spring的早期接口&#xff0c;称为Spring的Bean工厂。ApplicationContext是后期更高级接口&#xff0c;称之为Spring 容器; 2)ApplicationContext在BeanFactory基础上…

路径规划算法:基于瞬态优化的路径规划算法- 附代码

路径规划算法&#xff1a;基于瞬态优化的路径规划算法- 附代码 文章目录 路径规划算法&#xff1a;基于瞬态优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要&#xff1a;本文主要介绍利用智能优化算法瞬态…

充电桩系统的阿里云服务器的配置如何?

两台ecs. 微信公众号 微信小程序 微信商户 Redis mysql netty mqtt 更多信息私信我

【Leetcode】203. 移除链表元素

给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 # Definition for singly-linked list. # class ListNode(object): # def __init__(self, val0, nextNone): # self.val va…