kube-proxy的iptables工作模式分析

系列文章目录

iptables基础知识


文章目录

  • 系列文章目录
  • 前言
  • 一、kube-proxy介绍
    • 1、kube-proxy三种工作模式
    • 2、iptables中k8s相关的链
  • 二、kube-proxy的iptables模式剖析
    • 1.集群内部通过clusterIP访问到pod的流程
      • 1.1.流程分析
    • 2.从外部访问内部service clusterIP后端pod的流程
      • 2.1. 流程分析
    • 3、外部通过nodeport访问后端pod的流程
      • 3.1.当externalTrafficPolicy默认为cluster配置时且从本机访问后端pod流程
      • 3.2.当externalTrafficPolicy为Local配置时且从本机访问后端pod流程
  • 三、iptables与ipvs区别


前言

在一个k8s集群中,微服务以 Pod形式 运行在我们的集群中,这些 Pod 的副本通过Service 服务暴露,当一个外部请求到达 Service 的虚拟 IP 时,如何将请求转发到其中一个底层 Pod?这便是本篇文章的核心思想。


一、kube-proxy介绍

在这里插入图片描述

kube-proxy是k8s网络代理核心组件,部署在每个Node节点上,主要维护节点上的网络规则。它是实现service的通信与负载均衡机制的重要组件
kube-proxy负责为pod创建代理服务,通过watch机制会根据 service 和 endpoints,node资源对象的改变来实时刷新iptables或者ipvs规则
使发往 Service 的流量(通过ClusterIP和NodePort)负载均衡到正确的后端Pod。

1、kube-proxy三种工作模式

userspace(目前已经弃用)
	请求是从用户态-->内核态-->用户态,转发是在用户态进行的,效率不高且容易丢包
iptables(默认工作模式)
	相比于userspace免去了一次内核态-->用户态的切换
	1、kube-proxy通过Api-server的watch接口实时监测service和endpoint对象的变化,当有service创建时,kube-proxy在iptables中追加新的规则
    2、在该模式下,kube-proxy为service后端的每个pod创建对应的iptables规则,直接将发向cluster ip的请求重定向到一个pod ip
    3、在该模式下,kube-proxy不承担四层代理的角色,只负责创建iptables规则
    补充:
		在iptables模式下,会根据service以及endpoints对象的改变来实时刷新规则,kube-proxy使用了iptables的filter表和nat表,
		并对 iptables 的链进行了扩充,自定义了 KUBE-SERVICES、KUBE-EXTERNAL-SERVICES、KUBE-NODEPORTS、KUBE-POSTROUTING、
			KUBE-MARK-MASQ、KUBE-MARK-DROP、KUBE-FORWARD 七条链。
		另外还新增了以“KUBE-SVC-xxx”和“KUBE-SEP-xxx”开头的数个链,除了创建自定义的链以外还将自定义链插入到已有链的后面以便劫持数据包。
ipvs
	1、kube-proxy ipvs模式是基于NAT实现的,对访问k8s service的请求进行虚拟ip到pod ip的转发
	工作原理:
		当创建一个svc后,ipvs模式的kube-proxy会做以下三件事:
			1、确保kube-ipvs0网卡的存在。因为ipvs的netfilter钩子挂载input链.需要把svc的访问IP绑定在该网卡上让内核觉得虚IP就是本机IP,从而进入input链。
			2、把svc的访问ip绑定在该网卡上
			3、通过socket调用,创建ipvs的虚拟服务和真实服务,分别对应svc和endpoints
	注意事项:
		ipvs用于流量转发,无法处理kube-proxy中的其他问题,例如把包过滤、SNAT等。因此在以下四种情况下kube-proxy依赖iptables:
			1、kube-proxy配置启动参数masquerade-all=true,即集群中所有经过kube-proxy的包都做一次SNAT;
			2、kube-proxy启动参数指定集群IP地址范围;
			3、支持loadbalance类型的服务
			4、支持nodeport类型的服务

2、iptables中k8s相关的链

名称含义
KUBE-SERVICES是服务数据包的入口点。它的作用是匹配 目标 IP:port 并将数据包分派到对应的 KUBE-SVC-* 链
KUBE-SVC-*充当负载均衡器,将数据包分发到 KUBE-SEP-* 链。KUBE-SEP-* 的数量等于后面的端点数量 服务。选择哪个 KUBE-SEP-* 是随机决定的
KUBE-SEP-*表示 Service EndPoint。它只是执行 DNAT,将 服务 IP:端口,以及 Pod 的端点 IP:端口
KUBE-MARK-MASQ将 Netfilter 标记添加到发往该服务的数据包中,该标记 源自集群网络之外。带有此标记的数据包将被更改 在 POSTROUTING 规则中使用源网络地址转换 (SNAT) 和 node 的 IP 地址作为其源 IP 地址
KUBE-MARK-DROP为没有目的地的数据包添加 Netfilter 标记 此时已启用 NAT。这些数据包将在 KUBE-FIREWALL 中被丢弃 链
KUBE-FW-*chain 在 service 部署时执行 LoadBalancer 类型,则 将目标 IP 与服务的负载均衡器 IP 匹配,并分配 数据包到对应的 KUBE-SVC-* 链或 KUBE-XLB-* 链的 KEY-XLB-* 链
KUBE-NODEPORTS发生在服务部署在 NodePort 和 LoadBalancer 的 LoadPort 共享 LoadPort 和 LoadBalancer 的有了它,外部源可以访问该服务 按 Node Port 的 NODE 端口。它匹配节点端口并分发 数据包到对应的 KUBE-SVC-* 链或 KUBE-XLB-* 链 的 KEY-XLB-* 链 的
KUBE-XLB-*在 externalTrafficPolicy 设置为 Local 时工作。有了这个 链式编程,如果节点没有相关端点,则数据包将被丢弃 保留

二、kube-proxy的iptables模式剖析

首先请查看顶部文章链接iptables基本知识,对出入栈、四表五链有个认知,然后再看下文
包含整改service模式的流程图
iptable工作流程图
只包含cluster IP、NodePort模式的流程图
在这里插入图片描述
流程图结合iptables示例图
在这里插入图片描述

结合上述流程图,主要分两部分对kube-proxy的iptables模式进行剖析

1.集群内部通过clusterIP访问到pod的流程

资源准备,如下图所示
在这里插入图片描述
需求: 当在集群pod1访问curl http://10.102.172.63:8088时,请求是怎么到达后端pod2的?

1.1.流程分析

确定kube-proxy的工作模式两种方式

[root@master ~]# curl http://127.0.0.1:10249/proxyMode
iptables

[root@master ~]# kubectl get configmaps -n kube-system kube-proxy -oyaml |grep mode
    mode: "" #默认为空就是iptables模式

a、进入到pod1,执行curl请求

[root@master ~]# kubectl exec -it -n xx xx-xx-6c57d9ddc6-2495v bash
bash-4.2$ curl http://10.102.172.63:8088

xshell多开一个窗口,登录到pod1宿主机,查看iptables规则
b、因为从上述iptables流程图可知,当请求从集群内部发出时,先进入的是NAT表中的OUTPUT链---->到达KUBE-SERVICE自定义链

那么在pod1宿主机中查看output链规则如下所示
[root@xmhl-std12 ~]# iptables -t nat -S |grep -i output
-P OUTPUT ACCEPT
-A OUTPUT -m comment --comment "kubernetes service portals" -j KUBE-SERVICES   #此链就是入口链
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER

c、因为是clusterIP模式,因此在KUBE-SERVICES链查找到ClusterIP-10.102.172.63,然后根据结果将其转发到KUBE-SVC-*链

判断是否发生IP伪装(masquerade all)
从下面可以看到当数据包来自内部 Pod 时,即源 IP 仍然是pod ip。因此未发生转换,则直接到kube-svc-*链
bash-4.2$ curl -s 10.102.172.63:8088 | grep client
bash-4.2$ client_address=10.244.193.194
 
#查看kube-svc-*链是否存在  
[root@master ~]# iptables -nv -t nat -L KUBE-SERVICES |grep 'zz-trace'
    0     0 KUBE-SVC-LWBZJHXSVINAPFYY  tcp  --  *      *       0.0.0.0/0            10.102.172.63        /* xos/zz-trace-analyze:web cluster IP */ tcp dpt:8088

d、访问 KUBE-SVC*链 使用随机数负载均衡,将请求转发到kube-sep-*链中

#注意事项
	假如这个KUBE-SVC-LWBZJHXSVINAPFYY链里面定义了3条规则
	第一条规则有0.33333333349的概率匹配,也就是1/3的概率命中,
	第一条没命中的话第二条规则有1/2的概率命中,也就是2/3 * 1/2 = 1/3,
	第二条没命中的话就去第3条了。
	很明显,这里是在做负载均衡,那我们可以确认这3条规则后面的target就是这个service代理的3个pod相关的规则了

[root@master ~]# iptables -nv -t nat -L KUBE-SVC-LWBZJHXSVINAPFYY
Chain KUBE-SVC-LWBZJHXSVINAPFYY (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 KUBE-SEP-SU7QRQC2MJZZVHTR  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* xos/zz-trace-analyze:web */

e、每个 KUBE-SEP-* 链分别代表一个 Pod 或终端节点

重点
它包括两个操作:
	1) 从 Pod 转义的数据包是使用主机的 docker0 IP 进行源 NAT 处理的。 
	2) 进入 Pod 的数据包使用 Pod 的 IP 进行 DNAT 处理,然后路由到后端 Pod

查询如下所示: 从结果可以清晰的看到 pod1请求pod2的svc后,进入到pod2的数据包使用 Pod 的 IP 进行了 DNAT 处理,直接到达了pod2的目标pod

[root@master ~]# iptables -nv -t nat -L KUBE-SEP-SU7QRQC2MJZZVHTR
Chain KUBE-SEP-SU7QRQC2MJZZVHTR (1 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 KUBE-MARK-MASQ  all  --  *      *       10.244.8.182         0.0.0.0/0            /* xos/zz-trace-analyze:web */
    0     0 DNAT       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* xityos/zz-trace-analyze:web */ tcp to:10.244.8.182:18080

f、之后nat表的OUTPUT链中的规则结束,进入filter的OUTPUT链

[root@master ~]# iptables -t filter -S |grep OUTPUT
-P OUTPUT ACCEPT
-A OUTPUT -m conntrack --ctstate NEW -m comment --comment "kubernetes service portals" -j KUBE-SERVICES
-A OUTPUT -j KUBE-FIREWALL  #即nat表的OUTPUT链完成后进入到filter表中的OUTPUT链

g、可以看到所有新建的连接(ctstate NEW)都会匹配第一条规则KUBE-SERVICES,而当查看filter表中的KUBE-SERVICES链时,会发现这是一条空链。所以重点看第二条规则KUBE-FIREWALL

[root@master ~]# iptables -nv -t filter -L KUBE-FIREWALL
Chain KUBE-FIREWALL (2 references)
 pkts bytes target     prot opt in     out     source               destination         
    0     0 DROP       all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes firewall for dropping marked packets */ mark match 0x8000/0x8000
    0     0 DROP       all  --  *      *      !127.0.0.0/8          127.0.0.0/8          /* block incoming localnet connections */ ! ctstate RELATED,ESTABLISHED,DNAT

可以看到,所有被标记了0x8000/0x8000的数据包都会被直接DROP掉,而我们的数据包一路走过来没有被标记,所以不会被DROP。
这样一来filter的OUTPUT规则也走完了,终于进入了下一个阶段 -- POSTROUTRING链

h、POSTROUTING链涉及到2个表:mangle和nat,mangle表一般不使用,所以只需要关注nat表的POSTROUTING规则

[root@master ~]# iptables -nv -t nat -L |grep POSTROUTING
Chain POSTROUTING (policy ACCEPT 26679 packets, 2287K bytes)
  11M  982M KUBE-POSTROUTING  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes postrouting rules */
Chain KUBE-POSTROUTING (1 references)

i、先进入target,KUBE-POSTROUTING

[root@master ~]# iptables -nv -t nat -L KUBE-POSTROUTING
Chain KUBE-POSTROUTING (1 references)
 pkts bytes target     prot opt in     out     source               destination         
27635 2364K RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0            mark match ! 0x4000/0x4000
   47  2820 MARK       all  --  *      *       0.0.0.0/0            0.0.0.0/0            MARK xor 0x4000
   47  2820 MASQUERADE  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes service traffic requiring SNAT */

此时会发现这条规则会把所有标记了0x4000/0x4000的数据包全部MASQUERADE SNAT,由于我们的数据包没有被标记过,所以不匹配这条规则。
当数据包匹配到MASQUERADE的话,当前表的剩余规则将不再匹配。

至此,集群内部通过clusterIP访问到pod的链路流程剖析完成,整理一下整个过程

数据包经历的链路:
	数据包 --> nat的OUTPUT
			 --> nat的KUBE-SERVICES 
			 	--> nat的KUBE-SVC-LWBZJHXSVINAPFYY
					--> nat的KUBE-SEP-SU7QRQC2MJZZVHTR(多选1,随机负载均衡,被DNAT)
						--> filter的OUTPUT 
							--> filter的KUBE-SERVICES 
								-->filter的KUBE-FIREWALL 
									--> nat的POSTROUTING 
										--> nat的KUBE-POSTROUTING 
											--> 没有被NAT
语言描述:
	0、当集群内部通过clusterIP访问到pod时,会发生以下过程
	1、对于进入 NAT表的OUTPUT 链的都转到 KUBE-SERVICES 链进行处理
	2、在 KUBE-SERVICES 链,对于访问 clusterIP 为 10.102.172.63 的转发到 KUBE-SVC-LWBZJHXSVINAPFYY
	3、访问 KUBE-SVC-LWBZJHXSVINAPFYY 的使用随机数负载均衡,并转发到 KUBE-SEP-SU7QRQC2MJZZVHTR上
	4、KUBE-SEP-SU7QRQC2MJZZVHTR对应 endpoint 中的 pod 10.244.8.182,设置 mark 标记,进行 DNAT 并转发到具体的 pod 上
	5、当nat表中的output链完成后,会进入filter表中OUTPUT链中的KUBE-FIREWALL自定义链,可以看到,
		所有被标记了0x8000/0x8000的数据包都会被直接DROP掉,反之则不会被drop
	6、最后进入到NAT表中的POSTROUTING链,此时会发现这条规则会把所有标记了0x4000/0x4000的数据包全部MASQUERADE SNAT,
		由于我们的数据包没有被标记过,所以不匹配这条规则。当数据包匹配到MASQUERADE的话,当前表的剩余规则将不再匹配
	7、至此,剖析结束

2.从外部访问内部service clusterIP后端pod的流程

2.1. 流程分析

需求: 从外部机器中访问http://10.102.172.63:8088 这个clusterip svc的后端pod
a、因为从上述iptables流程图可知,当请求从外部发出时,先进入的是NAT表中的PREROUTING链---->到达KUBE-SERVICE自定义链

[root@master ~]# iptables -t nat -S |grep PREROUTING
-P PREROUTING ACCEPT
-A PREROUTING -m comment --comment "kubernetes service portals" -j KUBE-SERVICES
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER

b、因为是clusterIP模式,因此在KUBE-SERVICES链查找到ClusterIP-10.102.172.63,然后根据结果将其转发到KUBE-SVC-*链

判断是否发生IP伪装(masquerade all)
从下面我们可以看到,当从外部(而不是从 pod)访问服务时,源 IP 替换为 nodeIP;
cactus@master01:~$ curl --interface 外部地址  -s 10.102.172.63:8088 | grep client
client_address=10.244.1.0 
[root@master ~]# conntrack -L -d 10.102.172.63
tcp      6 56 TIME_WAIT src=10.8.21.231 dst=10.102.172.63 sport=56688 dport=8088 src=10.244.8.182 dst=10.244.1.0 sport=18080 dport=50534 [ASSURED] mark=0 use=1

#查看kube-svc-*链是否存在
[root@xmhl-std24 ~]# iptables -nvL  -t nat |egrep -i 'kube-mark-masq'  |grep zz-trace
    0     0 KUBE-MARK-MASQ  all  --  *      *       10.244.8.182         0.0.0.0/0            /* cityos/zz-trace-analyze:web */
    
[root@master ~]# iptables -nv -t nat -L KUBE-SERVICES |grep 'zz-trace'
    0     0 KUBE-SVC-LWBZJHXSVINAPFYY  tcp  --  *      *       0.0.0.0/0            10.102.172.63        /* xos/zz-trace-analyze:web cluster IP */ tcp dpt:8088

接下来的分析步骤和集群内部通过clusterIP访问到pod的流程中c-i过程一致,在此不做过多描述
至此,集群内部通过clusterIP访问到pod的链路流程剖析完成,整理一下整个过程

数据包经历的链路:
	数据包 --> nat的PREROUTING
			 --> nat的KUBE-SERVICES 
			 	--> nat的KUBE-SVC-LWBZJHXSVINAPFYY
					--> nat的KUBE-SEP-SU7QRQC2MJZZVHTR(多选1,随机负载均衡,被DNAT)
						--> filter的OUTPUT 
							--> filter的KUBE-SERVICES 
								-->filter的KUBE-FIREWALL 
									--> nat的POSTROUTING 
										--> nat的KUBE-POSTROUTING 
											--> 没有被NAT
语言描述:
	0、当集群内部通过clusterIP访问到pod时,会发生以下过程
	1、对于进入 NAT表的PREROUTING 链的都转到 KUBE-SERVICES 链进行处理
	2、在 KUBE-SERVICES 链,对于访问 clusterIP 为 10.102.172.63 的转发到 KUBE-SVC-LWBZJHXSVINAPFYY
	3、访问 KUBE-SVC-LWBZJHXSVINAPFYY 的使用随机数负载均衡,并转发到 KUBE-SEP-SU7QRQC2MJZZVHTR上
	4、KUBE-SEP-SU7QRQC2MJZZVHTR对应 endpoint 中的 pod 10.244.8.182,设置 mark 标记,进行 DNAT 并转发到具体的 pod 上
	5、当nat表中的output链完成后,会进入filter表中OUTPUT链中的KUBE-FIREWALL自定义链,可以看到,
		所有被标记了0x8000/0x8000的数据包都会被直接DROP掉,反之则不会被drop
	6、最后进入到NAT表中的POSTROUTING链,此时会发现这条规则会把所有标记了0x4000/0x4000的数据包全部MASQUERADE SNAT,
		由于我们的数据包没有被标记过,所以不匹配这条规则。当数据包匹配到MASQUERADE的话,当前表的剩余规则将不再匹配
	7、至此,剖析结束

3、外部通过nodeport访问后端pod的流程

将根据上述图1分析两种类型的 NodePort 服务:
	1、默认服务 (externalTrafficPolicy: Cluster)
	2、externalTrafficPolicy:local

在这里插入图片描述

3.1.当externalTrafficPolicy默认为cluster配置时且从本机访问后端pod流程

a、从本机访问首先进入NAT表的OUTPUT链,然后进入到kube-nodeports链
所有访问端口 64438的数据包,首先要进行 SNAT 处理,然后才能进行kube-svc-*链进行负载均衡

[root@master ~]# iptables -t nat -S |grep OUTPUT
-P OUTPUT ACCEPT
-A OUTPUT -m comment --comment "kubernetes service portals" -j KUBE-SERVICES
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER

[root@master ~]# iptables -nv -t nat -L KUBE-NODEPORTS |grep 'xx-flow'
    0     0 KUBE-MARK-MASQ  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* xos/xx-flow:debug-port */ tcp dpt:64438
    0     0 KUBE-SVC-UFDICDG36KRBVVWD  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            /* xos/xx-flow:debug-port */ tcp dpt:64438

b、可以看到数据包先会命中第一条规则KUBE-MARK-MASQ,然后是第二条规则到达

[root@master ~]# iptables -t nat -L KUBE-MARK-MASQ
Chain KUBE-MARK-MASQ (165 references)
target     prot opt source               destination         
MARK       all  --  anywhere             anywhere             MARK or 0x4000

在这里数据包会被标记上0x4000标记,然后回到KUBE-NODEPORTS链中继续匹配下一条规则,下一条规则就是KUBE-SVC-UFDICDG36KRBVVWD

[root@master ~]# iptables -t nat -L KUBE-SVC-BCUGWLTE6RKBKCZT
Chain KUBE-SVC-BCUGWLTE6RKBKCZT (2 references)
target     prot opt source               destination         
KUBE-SEP-2SQRA2EPJ5ESOFTW  all  --  anywhere             anywhere             /* xos/xx-flow:web */ statistic mode random probability 0.50000000000
KUBE-SEP-QUKANZ2W6FTD6P23  all  --  anywhere             anywhere             /* xos/xx-flow:web */

c、接下来一路到nat的POSTROUTING为止都与ClusterIP模式相同,但在接下来的nat的KUBE-POSTROUTING阶段,由于我们的数据包在KUBE-MARK-MASQ被打上了0x4000标记,在这里会命中这条规则,从而被MASQUERADE(SNAT)

[root@xmhl-std11 ~]# iptables -nv -t nat -L KUBE-POSTROUTING
Chain KUBE-POSTROUTING (1 references)
 pkts bytes target     prot opt in     out     source               destination         
41065 3455K RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0            mark match ! 0x4000/0x4000
   22  1320 MARK       all  --  *      *       0.0.0.0/0            0.0.0.0/0            MARK xor 0x4000
   22  1320 MASQUERADE  all  --  *      *       0.0.0.0/0            0.0.0.0/0            /* kubernetes service traffic requiring SNAT */

至此,当externalTrafficPolicy默认为cluster配置时且从本机访问后端pod流程剖析完成

数据包经历的链路:
数据包 --> nat的OUTPUT 
		--> nat的KUBE-SERVICES 
			--> nat的KUBE-NODEPORTS 
				--> nat的KUBE-MARK-MASQ (被标记) 
					--> nat的KUBE-SVC-GKN7Y2BSGW4NJTYL
						--> nat的KUBE-SEP-ISPQE3VESBAFO225(3选1,被DNAT)
							--> filter的OUTPUT 
								--> filter的KUBE-SERVICES 
									-->filter的KUBE-FIREWALL 
										--> nat的POSTROUTING 
											--> nat的KUBE-POSTROUTING 
												--> 被SNAT

3.2.当externalTrafficPolicy为Local配置时且从本机访问后端pod流程

三、iptables与ipvs区别

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

学习ASP.NET Core的身份认证(基于Session的身份认证3)

开源博客项目Blog中提供了另一种访问控制方式,其基于自定义类及函数的特性类控制访问权限。本文学习并测试开源博客项目Blog的访问控制方式,测试程序中直接复用开源博客项目Blog中的相关类及接口定义,并在其上调整判断逻辑。   首先是接口A…

HTML前端开发-- Flex布局详解及实战

引言 Flex布局,全称为Flexible Box Layout,是一种现代CSS布局技术,它提供了一种更有效的方式来设计响应式布局和复杂页面布局。本文将详细介绍Flex布局的基本概念、属性以及实战应用。 一、基本概念 Flex布局的核心是Flex容器(…

ESG研究报告白皮书与ESG治理报告合集(2020-2023年)

一.资料范围:(1)ESG白皮书及指南;(2)ESG研究报告,(3)ESG治理报告分析(4)上市公司ESG报告(知名企业) 二、资料用途:可以分析研究企业E…

C/C++每日一练:合并K个有序链表

本篇博客将探讨如何 “合并K个有序链表” 这一经典问题。本文将从题目要求、解题思路、过程解析和相关知识点逐步展开,同时提供详细注释的代码示例。 链表(Linked List) 链表是一种线性数据结构,由一系列节点(Node&…

计算机网络复习1——导言和概论

网络简史 1946年,美国物理学家莫奇利任总设计师研制成功世界上第一台电子管计算机ENIAC(这标志着人类自学会使用工具的漫长岁月中,终于拥有了可以替代人类脑力劳动的“工具”) 1969年9月2日,以雷克雷洛克为首的约20名…

详解桥接模式

引言 在开发过程中,可能会遇到系统设计有多种维度变化的情况,比如我们想画一幅五彩斑斓的画,需要用到12个颜色,但是需要粗细不同的线条(粗、中、细),如果用蜡笔,就需要粗中细三种蜡笔…

MySQL笔记-启动时log报错Table ‘mysql.user‘ doesn‘t exist

安装好mysql后,正常使用(使用的是rpm版安装的) service mysqld start | stop | restart 不会出现这个问题。 我遇到的情况是在凝思操作系统上,已经存在了一个mysql。网上查找了一些资料,卸载,后可能卸载…

【SpringBoot+Vue】x-admin管理系统跟做

技术栈 前端技术说明Vue前端框架Vuex全局状态管理框架ElementUI前端UI框架Axios前端HTTP框架vue-element-admin项目脚手架 后端技术说明SpringBoot容器MVC框架MyBatisORM框架MyBatis-plusMyBatis增强工具Redis非关系型数据库 数据库准备 SET NAMES utf8mb4; SET FOREIGN_KE…

AI智算-正式上架GPU资源监控概览 Grafana Dashboard

下载链接 https://grafana.com/grafana/dashboards/22424-ai-gpu-20241127/

异步处理优化:多线程线程池与消息队列的选择与应用

目录 一、异步处理方式引入 (一)异步业务识别 (二)明确异步处理方式 二、多线程线程池(Thread Pool) (一)工作原理 (二)直面优缺点和适用场景 1.需要快…

用到动态库的程序运行过程

当我们写好了一段代码然后编译运行后会生成可执行文件,该文件会存在磁盘的当前目录下,而当我们开始运行这段程序时,操作系统(加载器)需要将其从磁盘加载进内存然后执行相关操作,而对于用到动态库的程序&…

Windows使用多个JDK的方法

原文网址:Windows使用多个JDK的方法-CSDN博客 简介 本文介绍Windows如何使用多个JDK。 原先已经有了JDK8,现在想用JDK21。但有的项目依然是JDK8,所以两个JDK需要共存。 解决方案 第一步:改环境变量 右键此电脑> 属性>…

RDIFramework.NET CS敏捷开发框架 SOA服务三种访问(直连、WCF、WebAPI)方式

1、介绍 在软件开发领域,尤其是企业级应用开发中,灵活性、开放性、可扩展性往往是项目成功的关键因素。对于C/S项目,如何高效地与后端数据库进行交互,以及如何提供多样化的服务访问方式,是开发者需要深入考虑的问题。…

《数字图像处理基础》学习07-图像几何变换之最近邻插值法放大图像

目录 一,概念 二,题目及matlab实现 1,解题思路 2,matlab实现 1)matlab思路 2)完整代码 三,放大图像及matlab实现 一,概念 通过上一篇,我已经学习了使用最邻近插…

LWIP和FATFS 实现 FTP 服务端

目录 一、前言 二、LWIP 和 FTP 简介 1.LWIP 2.FTP 三、实现 FTP 服务端的主要步骤 1.初始化 LWIP 2.创建 FTP 服务器任务 3.处理客户端连接 4.实现 FTP 命令处理 5.文件系统操作 6.错误处理和日志记录 四、示例代码 1.创建FTP任务 2. FTP任务代码 3.处理交互数据…

PyCharm中Python项目打包并运行到服务器的简明指南

目录 一、准备工作 二、创建并设置Python项目 创建新项目 配置项目依赖 安装PyInstaller 三、打包项目 打包为可执行文件 另一种打包方式(使用setup.py) 四、配置服务器环境 五、上传可执行文件到服务器 六、在服务器上运行项目 配置SSH解释器 配置部署 上传代…

PHP 方头像转为圆图

业务需要把创建海报上的用户头像由方形转为圆形,前端的样式设置不能用。 故采用GD的函数来对方图进行裁剪处理为圆图。 目录 裁剪函数 本地图片 远程图片 效果 参考文章 总结 裁剪函数 从网上找的一个裁剪图片的函数。 代码如下: /* * 将图片切…

Java--数组的定义与使用

1.数组的基本概念 1.1为什么用数组 在程序设计中,每一个数据总是对应一个变量.当数据量越大,就需要更多的变量来存储.我们将相同类型的数据存储到一个集合中,就可以更方便我们对数据进行访问,同时可以减少不断定义变量.这个集合就叫做数组 1.2数组的定义 数组是一种基本的数…

手机实时提取SIM卡打电话的信令声音-蓝牙电话如何适配eSIM卡的手机

手机实时提取SIM卡打电话的信令声音 --蓝牙电话如何适配eSIM卡的手机 一、前言 蓝牙电话的海外战略中,由于海外智能手机市场中政策的差异性,对内置eSIM卡的手机进行支持是非常合理的需求。Android系列手机中,无论是更换通信运营商&#xf…

《操作系统 - 清华大学》6 -4:局部页面置换算法:时钟页面置换算法 (Clock)

文章目录 1.时钟置换算法的工作原理2.时钟置换算法的具体实现过程3. 时钟置换算法示例 1.时钟置换算法的工作原理 需要考虑有没有新的办法,既能有 LRU 算法这种效果,产生缺页次数比较少,同时实现的效率比较简洁和方便,有点类似于…