12、Kubernetes中KubeProxy实现之iptables和ipvs

目录

一、概述

二、iptables 代理模式

三、iptables案例分析

四、ipvs案例分析

一、概述

iptables和ipvs其实都是依赖的一个共同的Linux内核模块:Netfilter。Netfilter是Linux 2.4.x引入的一个子系统,它作为一个通用的、抽象的框架,提供一整套的hook函数的管理机制,使得诸如数据包过滤、网络地址转换(NAT)和基于协议类型的连接跟踪成为了可能。

Netfilter的架构就是在整个网络流程的若干位置放置了一些检测点(HOOK),而在每个检测点上登记了一些处理函数进行处理。

在一个网络包进入Linux网卡后,有可能经过这上面五个Hook点,我们可以自己写Hook函数,注册到任意一个点上,而iptables和ipvs都是在这个基础上实现的。

二、iptables 代理模式

iptables模式下 kube-proxy 为每一个pod创建相对应的 iptables 规则,发送给 ClusterIP 的请求会被直接发送给后端pod之上。

在该模式下 kube-proxy 不承担负载均衡器的角色,其只会负责创建相应的转发策略,该模式的优点在于效率较高,但是不能提供灵活的LB策略,当后端Pod不可用的时候无法进行重试。

iptables是把一些特定规则以“链”的形式挂载到每个Hook点,这些链的规则是固定的,而是是比较通用的,可以通过iptables命令在用户层动态的增删,这些链必须串行的执行。执行到某条规则,如果不匹配,则继续执行下一条,如果匹配,根据规则,可能继续向下执行,也可能跳到某条规则上,也可能下面的规则都跳过。

三、iptables案例分析

apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-deployment
spec:replicas: 3selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: nginx---apiVersion: v1
kind: Service
metadata:name: nginx-basic
spec:type: ClusterIPports:- port: 80protocol: TCPname: httpselector:app: nginx                           

我们这里创建一个副本数量为3的nginx pod,并创建一个对应的service对外暴露服务,service类型为ClusterIP。

创建完成后,资源如下:

$ kubectl get pod -o wide
NAME                                READY   STATUS    RESTARTS   AGE   IP            NODE           NOMINATED NODE   READINESS GATES
nginx-deployment-748c667d99-dtr82   1/1     Running   0          38m   192.168.1.3   node01         <none>           <none>
nginx-deployment-748c667d99-jzpqf   1/1     Running   0          38m   192.168.0.7   controlplane   <none>           <none>
nginx-deployment-748c667d99-whgr5   1/1     Running   0          38m   192.168.1.4   node01         <none>           <none>$ kubectl get svc nginx-basic -o wide
NAME          TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE   SELECTOR
nginx-basic   ClusterIP   10.105.250.129   <none>        80/TCP    39m   app=nginx

可以看到,三个pod的IP分别为192.168.1.3、192.168.0.7、192.168.1.4。service的ClusterIP地址为10.105.250.129。

下面我们通过【iptables-save -t nat】命令输出iptables中nat表的信息,说明iptables如何实现转发。

$ iptables-save -t nat
# Generated by iptables-save v1.8.4 on Mon Feb 20 01:52:41 2023
*nat
:PREROUTING ACCEPT [11:660]
:INPUT ACCEPT [11:660]
:OUTPUT ACCEPT [4706:282406]
:POSTROUTING ACCEPT [4706:282406]
:DOCKER - [0:0]
:KUBE-KUBELET-CANARY - [0:0]
:KUBE-MARK-DROP - [0:0]
:KUBE-MARK-MASQ - [0:0]
:KUBE-NODEPORTS - [0:0]
:KUBE-POSTROUTING - [0:0]
:KUBE-PROXY-CANARY - [0:0]
:KUBE-SEP-ABG426TTTCGMOND7 - [0:0]
:KUBE-SEP-BEMSLTMJA26ZCLYL - [0:0]
:KUBE-SEP-D23ODROEH5R4FSGE - [0:0]
:KUBE-SEP-G44RJ25JKAEOKO42 - [0:0]
:KUBE-SEP-GHNVWKROTCCBFQKZ - [0:0]
:KUBE-SEP-NGZXZA7GIJDM26Z3 - [0:0]
:KUBE-SEP-NH2YM7NDCNPLOCTP - [0:0]
:KUBE-SEP-UF65ZV4QBOPNRP6O - [0:0]
:KUBE-SEP-UG4OSZR4VSWZ27C5 - [0:0]
:KUBE-SEP-WQR67ZLSTPDXXME4 - [0:0]
:KUBE-SERVICES - [0:0]
:KUBE-SVC-ERIFXISQEP7F7OF4 - [0:0]
:KUBE-SVC-JD5MR3NA4I4DYORP - [0:0]
:KUBE-SVC-NPX46M4PTMTKRN6Y - [0:0]
:KUBE-SVC-TCOU7JCQXEZGVUNU - [0:0]
:KUBE-SVC-WWRFY3PZ7W3FGMQW - [0:0]
:cali-OUTPUT - [0:0]
:cali-POSTROUTING - [0:0]
:cali-PREROUTING - [0:0]
:cali-fip-dnat - [0:0]
:cali-fip-snat - [0:0]
:cali-nat-outgoing - [0:0]
-A PREROUTING -m comment --comment "cali:6gwbT8clXdHdC1b1" -j cali-PREROUTING
-A PREROUTING -m comment --comment "kubernetes service portals" -j KUBE-SERVICES
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT -m comment --comment "cali:tVnHkvAo15HuiPy0" -j cali-OUTPUT
-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
-A POSTROUTING -m comment --comment "cali:O3lYWMrLQYEMJtB5" -j cali-POSTROUTING
-A POSTROUTING -m comment --comment "kubernetes postrouting rules" -j KUBE-POSTROUTING
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A POSTROUTING -s 192.168.0.0/16 -d 192.168.0.0/16 -j RETURN
-A POSTROUTING -s 192.168.0.0/16 ! -d 224.0.0.0/4 -j MASQUERADE --random-fully
-A POSTROUTING ! -s 192.168.0.0/16 -d 192.168.0.0/24 -j RETURN
-A POSTROUTING ! -s 192.168.0.0/16 -d 192.168.0.0/16 -j MASQUERADE --random-fully
-A DOCKER -i docker0 -j RETURN
-A KUBE-MARK-DROP -j MARK --set-xmark 0x8000/0x8000
-A KUBE-MARK-MASQ -j MARK --set-xmark 0x4000/0x4000
-A KUBE-POSTROUTING -m mark ! --mark 0x4000/0x4000 -j RETURN
-A KUBE-POSTROUTING -j MARK --set-xmark 0x4000/0x0
-A KUBE-POSTROUTING -m comment --comment "kubernetes service traffic requiring SNAT" -j MASQUERADE --random-fully
-A KUBE-SEP-ABG426TTTCGMOND7 -s 192.168.1.2/32 -m comment --comment "kube-system/kube-dns:dns-tcp" -j KUBE-MARK-MASQ
-A KUBE-SEP-ABG426TTTCGMOND7 -p tcp -m comment --comment "kube-system/kube-dns:dns-tcp" -m tcp -j DNAT --to-destination 192.168.1.2:53
-A KUBE-SEP-BEMSLTMJA26ZCLYL -s 192.168.0.7/32 -m comment --comment "default/nginx-basic:http" -j KUBE-MARK-MASQ
-A KUBE-SEP-BEMSLTMJA26ZCLYL -p tcp -m comment --comment "default/nginx-basic:http" -m tcp -j DNAT --to-destination 192.168.0.7:80
-A KUBE-SEP-D23ODROEH5R4FSGE -s 172.30.1.2/32 -m comment --comment "default/kubernetes:https" -j KUBE-MARK-MASQ
-A KUBE-SEP-D23ODROEH5R4FSGE -p tcp -m comment --comment "default/kubernetes:https" -m tcp -j DNAT --to-destination 172.30.1.2:6443
-A KUBE-SEP-G44RJ25JKAEOKO42 -s 192.168.0.6/32 -m comment --comment "kube-system/kube-dns:dns-tcp" -j KUBE-MARK-MASQ
-A KUBE-SEP-G44RJ25JKAEOKO42 -p tcp -m comment --comment "kube-system/kube-dns:dns-tcp" -m tcp -j DNAT --to-destination 192.168.0.6:53
-A KUBE-SEP-GHNVWKROTCCBFQKZ -s 192.168.1.2/32 -m comment --comment "kube-system/kube-dns:dns" -j KUBE-MARK-MASQ
-A KUBE-SEP-GHNVWKROTCCBFQKZ -p udp -m comment --comment "kube-system/kube-dns:dns" -m udp -j DNAT --to-destination 192.168.1.2:53
-A KUBE-SEP-NGZXZA7GIJDM26Z3 -s 192.168.0.6/32 -m comment --comment "kube-system/kube-dns:dns" -j KUBE-MARK-MASQ
-A KUBE-SEP-NGZXZA7GIJDM26Z3 -p udp -m comment --comment "kube-system/kube-dns:dns" -m udp -j DNAT --to-destination 192.168.0.6:53
-A KUBE-SEP-NH2YM7NDCNPLOCTP -s 192.168.0.6/32 -m comment --comment "kube-system/kube-dns:metrics" -j KUBE-MARK-MASQ
-A KUBE-SEP-NH2YM7NDCNPLOCTP -p tcp -m comment --comment "kube-system/kube-dns:metrics" -m tcp -j DNAT --to-destination 192.168.0.6:9153
-A KUBE-SEP-UF65ZV4QBOPNRP6O -s 192.168.1.3/32 -m comment --comment "default/nginx-basic:http" -j KUBE-MARK-MASQ
-A KUBE-SEP-UF65ZV4QBOPNRP6O -p tcp -m comment --comment "default/nginx-basic:http" -m tcp -j DNAT --to-destination 192.168.1.3:80
-A KUBE-SEP-UG4OSZR4VSWZ27C5 -s 192.168.1.2/32 -m comment --comment "kube-system/kube-dns:metrics" -j KUBE-MARK-MASQ
-A KUBE-SEP-UG4OSZR4VSWZ27C5 -p tcp -m comment --comment "kube-system/kube-dns:metrics" -m tcp -j DNAT --to-destination 192.168.1.2:9153
-A KUBE-SEP-WQR67ZLSTPDXXME4 -s 192.168.1.4/32 -m comment --comment "default/nginx-basic:http" -j KUBE-MARK-MASQ
-A KUBE-SEP-WQR67ZLSTPDXXME4 -p tcp -m comment --comment "default/nginx-basic:http" -m tcp -j DNAT --to-destination 192.168.1.4:80
-A KUBE-SERVICES -d 10.96.0.10/32 -p tcp -m comment --comment "kube-system/kube-dns:dns-tcp cluster IP" -m tcp --dport 53 -j KUBE-SVC-ERIFXISQEP7F7OF4
-A KUBE-SERVICES -d 10.96.0.10/32 -p tcp -m comment --comment "kube-system/kube-dns:metrics cluster IP" -m tcp --dport 9153 -j KUBE-SVC-JD5MR3NA4I4DYORP
-A KUBE-SERVICES -d 10.96.0.10/32 -p udp -m comment --comment "kube-system/kube-dns:dns cluster IP" -m udp --dport 53 -j KUBE-SVC-TCOU7JCQXEZGVUNU
-A KUBE-SERVICES -d 10.105.250.129/32 -p tcp -m comment --comment "default/nginx-basic:http cluster IP" -m tcp --dport 80 -j KUBE-SVC-WWRFY3PZ7W3FGMQW
-A KUBE-SERVICES -d 10.96.0.1/32 -p tcp -m comment --comment "default/kubernetes:https cluster IP" -m tcp --dport 443 -j KUBE-SVC-NPX46M4PTMTKRN6Y
-A KUBE-SERVICES -m comment --comment "kubernetes service nodeports; NOTE: this must be the last rule in this chain" -m addrtype --dst-type LOCAL -j KUBE-NODEPORTS
-A KUBE-SVC-ERIFXISQEP7F7OF4 ! -s 192.168.0.0/16 -d 10.96.0.10/32 -p tcp -m comment --comment "kube-system/kube-dns:dns-tcp cluster IP" -m tcp --dport 53 -j KUBE-MARK-MASQ
-A KUBE-SVC-ERIFXISQEP7F7OF4 -m comment --comment "kube-system/kube-dns:dns-tcp -> 192.168.0.6:53" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-G44RJ25JKAEOKO42
-A KUBE-SVC-ERIFXISQEP7F7OF4 -m comment --comment "kube-system/kube-dns:dns-tcp -> 192.168.1.2:53" -j KUBE-SEP-ABG426TTTCGMOND7
-A KUBE-SVC-JD5MR3NA4I4DYORP ! -s 192.168.0.0/16 -d 10.96.0.10/32 -p tcp -m comment --comment "kube-system/kube-dns:metrics cluster IP" -m tcp --dport 9153 -j KUBE-MARK-MASQ
-A KUBE-SVC-JD5MR3NA4I4DYORP -m comment --comment "kube-system/kube-dns:metrics -> 192.168.0.6:9153" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-NH2YM7NDCNPLOCTP
-A KUBE-SVC-JD5MR3NA4I4DYORP -m comment --comment "kube-system/kube-dns:metrics -> 192.168.1.2:9153" -j KUBE-SEP-UG4OSZR4VSWZ27C5
-A KUBE-SVC-NPX46M4PTMTKRN6Y ! -s 192.168.0.0/16 -d 10.96.0.1/32 -p tcp -m comment --comment "default/kubernetes:https cluster IP" -m tcp --dport 443 -j KUBE-MARK-MASQ
-A KUBE-SVC-NPX46M4PTMTKRN6Y -m comment --comment "default/kubernetes:https -> 172.30.1.2:6443" -j KUBE-SEP-D23ODROEH5R4FSGE
-A KUBE-SVC-TCOU7JCQXEZGVUNU ! -s 192.168.0.0/16 -d 10.96.0.10/32 -p udp -m comment --comment "kube-system/kube-dns:dns cluster IP" -m udp --dport 53 -j KUBE-MARK-MASQ
-A KUBE-SVC-TCOU7JCQXEZGVUNU -m comment --comment "kube-system/kube-dns:dns -> 192.168.0.6:53" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-NGZXZA7GIJDM26Z3
-A KUBE-SVC-TCOU7JCQXEZGVUNU -m comment --comment "kube-system/kube-dns:dns -> 192.168.1.2:53" -j KUBE-SEP-GHNVWKROTCCBFQKZ
-A KUBE-SVC-WWRFY3PZ7W3FGMQW ! -s 192.168.0.0/16 -d 10.105.250.129/32 -p tcp -m comment --comment "default/nginx-basic:http cluster IP" -m tcp --dport 80 -j KUBE-MARK-MASQ
-A KUBE-SVC-WWRFY3PZ7W3FGMQW -m comment --comment "default/nginx-basic:http -> 192.168.0.7:80" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-BEMSLTMJA26ZCLYL
-A KUBE-SVC-WWRFY3PZ7W3FGMQW -m comment --comment "default/nginx-basic:http -> 192.168.1.3:80" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-UF65ZV4QBOPNRP6O
-A KUBE-SVC-WWRFY3PZ7W3FGMQW -m comment --comment "default/nginx-basic:http -> 192.168.1.4:80" -j KUBE-SEP-WQR67ZLSTPDXXME4
-A cali-OUTPUT -m comment --comment "cali:GBTAv2p5CwevEyJm" -j cali-fip-dnat
-A cali-POSTROUTING -m comment --comment "cali:Z-c7XtVd2Bq7s_hA" -j cali-fip-snat
-A cali-POSTROUTING -m comment --comment "cali:nYKhEzDlr11Jccal" -j cali-nat-outgoing
-A cali-PREROUTING -m comment --comment "cali:r6XmIziWUJsdOK6Z" -j cali-fip-dnat
-A cali-nat-outgoing -m comment --comment "cali:flqWnvo8yq4ULQLa" -m set --match-set cali40masq-ipam-pools src -m set ! --match-set cali40all-ipam-pools dst -j MASQUERADE --random-fully
COMMIT

iptables-save命令,可以查看当前所有的iptables规则,涉及到k8s的比较多,基本在每个链上都有,包括一些SNAT的,就是Pod访问外部的地址的时候,需要做一下NAT转换,我们只看涉及到Service负载均衡的。

首先,PREROUTING和OUTPUT都加了一个KUBE-SERVICES规则,也就是进来的包和出去的包都要都走一下KUBE-SERVICES规则。

-A PREROUTING -m comment --comment "kubernetes service portals" -j KUBE-SERVICES-A OUTPUT -m comment --comment "kubernetes service portals" -j KUBE-SERVICES

接着,因为我们service的ClusterIP地址为10.105.250.129,所以我们从nat表中找出跟10.105.250.129有关的转发规则。

-A KUBE-SERVICES -d 10.105.250.129/32 -p tcp -m comment --comment "default/nginx-basic:http cluster IP" -m tcp --dport 80 -j KUBE-SVC-WWRFY3PZ7W3FGMQW

 可以看到,当目标地址是10.105.250.129/32并且目标端口是80的,也就是这个服务的ClusterIP,走到KUBE-SVC-WWRFY3PZ7W3FGMQW规则,这个规则其实就是Kube-Proxy。

下面我们查看KUBE-SVC-WWRFY3PZ7W3FGMQW规则:

-A KUBE-SVC-WWRFY3PZ7W3FGMQW -m comment --comment "default/nginx-basic:http -> 192.168.0.7:80" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-BEMSLTMJA26ZCLYL
-A KUBE-SVC-WWRFY3PZ7W3FGMQW -m comment --comment "default/nginx-basic:http -> 192.168.1.3:80" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-UF65ZV4QBOPNRP6O
-A KUBE-SVC-WWRFY3PZ7W3FGMQW -m comment --comment "default/nginx-basic:http -> 192.168.1.4:80" -j KUBE-SEP-WQR67ZLSTPDXXME4

可以看到,KUBE-SVC-WWRFY3PZ7W3FGMQW又对应了三条规则,分别来看下:

1)、第一条规则

-A KUBE-SVC-WWRFY3PZ7W3FGMQW -m comment --comment "default/nginx-basic:http -> 192.168.0.7:80" -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-BEMSLTMJA26ZCLYL# 这条规则对应的又会走KUBE-SEP-BEMSLTMJA26ZCLYL规则
-A KUBE-SEP-BEMSLTMJA26ZCLYL -p tcp -m comment --comment "default/nginx-basic:http" -m tcp -j DNAT --to-destination 192.168.0.7:80# 可以看到, 有33%的概率将会被转发到【192.168.0.7:80】这个pod

2)、第二条规则

-A KUBE-SVC-WWRFY3PZ7W3FGMQW -m comment --comment "default/nginx-basic:http -> 192.168.1.3:80" -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-UF65ZV4QBOPNRP6O# 这条规则对应的又会走KUBE-SEP-UF65ZV4QBOPNRP6O规则
-A KUBE-SEP-UF65ZV4QBOPNRP6O -p tcp -m comment --comment "default/nginx-basic:http" -m tcp -j DNAT --to-destination 192.168.1.3:80# 可以看到, 有50%的概率将会被转发到【192.168.1.3:80】这个pod

3)、第三条规则

-A KUBE-SVC-WWRFY3PZ7W3FGMQW -m comment --comment "default/nginx-basic:http -> 192.168.1.4:80" -j KUBE-SEP-WQR67ZLSTPDXXME4# 这条规则对应的又会走KUBE-SEP-WQR67ZLSTPDXXME4规则
-A KUBE-SEP-WQR67ZLSTPDXXME4 -p tcp -m comment --comment "default/nginx-basic:http" -m tcp -j DNAT --to-destination 192.168.1.4:80# 可以看到,这条规则没有加--probability,所以有100%的概率将会被转发到【192.168.1.4:80】这个pod

可以看到,最重要的就是KUBE-SVC-WWRFY3PZ7W3FGMQW规则,它以不同的概率走到了不同的规则,这些规则最终走到了Pod里,这就是负载均衡策略。

我们把这个负载均衡用图画出来,大体就是如下:

上述我们演示的是ClusterIP类型的Service,我们可以尝试修改为NodePort类型,实际上,在iptables规则里,最终也是会转发到KUBE-SVC-WWRFY3PZ7W3FGMQW规则,综上,不管是ClusterIP,还是NodePort,都走到了同一个规则上。

四、ipvs案例分析

IPVS模式工作在内核态,在同步代理规则时具有更好的性能,同时提高网络吞吐量为大型集群提供了更好的可扩展性,同时提供了大量的负责均衡算法。

还是通过一个例子说明ipvs怎么转发的,首先我们需要修改kube-proxy的代理模式为ipvs,我们可以通过修改configmap来实现:

$ kubectl edit configmap kube-proxy -n kube-system
configmap/kube-proxy edited

将mode修改为ipvs即可,如下图:

image.png

apiVersion: apps/v1
kind: Deployment
metadata:name: nginx-deployment
spec:replicas: 3selector:matchLabels:app: nginxtemplate:metadata:labels:app: nginxspec:containers:- name: nginximage: nginx---apiVersion: v1
kind: Service
metadata:name: nginx-basic
spec:type: ClusterIPports:- port: 80protocol: TCPname: httpselector:app: nginx                           

创建对应的pod和service:

$ vim ipvs.yaml
controlplane $ kubectl create -f ipvs.yaml
deployment.apps/nginx-deployment created
service/nginx-basic created$ kubectl get pods -o wide
NAME                                READY   STATUS    RESTARTS   AGE   IP            NODE           NOMINATED NODE   READINESS GATES
nginx-deployment-748c667d99-fpsh6   1/1     Running   0          12s   192.168.1.3   node01         <none>           <none>
nginx-deployment-748c667d99-hsnzw   1/1     Running   0          12s   192.168.0.7   controlplane   <none>           <none>
nginx-deployment-748c667d99-sb9b2   1/1     Running   0          12s   192.168.1.4   node01         <none>           <none>$ kubectl get svc -o wide
NAME          TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE   SELECTOR
nginx-basic   ClusterIP   10.96.115.68   <none>        80/TCP    36s   app=nginx

我们通过【ipvsadm -L】命令查看ipvs转发规则:

$  ipvsadm -Ln
IP Virtual Server version 1.2.1 (size=4096)
Prot LocalAddress:Port Scheduler Flags-> RemoteAddress:Port           Forward Weight ActiveConn InActConn
...省略...    
TCP  10.96.115.68:80 rr-> 192.168.0.7:80               Masq    1      0          0         -> 192.168.1.3:80               Masq    1      0          0         -> 192.168.1.4:80               Masq    1      0          0         
...省略...

可以看到,到ClusterIP:Port的流量,都被以rr(round robin)的策略转发到3个后端pod上。

五、iptables vs ipvs

●1、iptables更通用,主要是应用在防火墙上,也能应用于路由转发等功能,ipvs更聚焦,它只能做负载均衡,不能实现其它的例如防火墙上。
●2、iptables在处理规则时,是按“链”逐条匹配,如果规则过多,性能会变差,它匹配规则的复杂度是O(n),而ipvs处理规则时,在专门的模块内处理,查找规则的复杂度是O(1)。
●3、iptables虽然可以实现负载均衡,但是它的策略比较简单,只能以概率转发,而ipvs可以实现多种策略。

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

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

相关文章

手机自动直播系统源码交付与代理加盟注意事项解析!

随着直播行业的不断发展&#xff0c;手机自动直播已经成为了人们生活中不可或缺的一部分。手机无人直播软件成了香饽饽&#xff0c;各类手机实景直播APP大批量涌现。因为创业和技术门槛低&#xff0c;市场需求高&#xff0c;所以成了最火热创业赛道。那么如果是不懂技术的人群&…

由Long类型引发的生产事故

事情原由 今天测试忽然在群里发了一个看似非常简单的线上问题&#xff0c;具体是&#xff1a;在后台通过订单编号(orderId)修改订单信息时&#xff0c;修改不成功 &#xff0c;修改前后的订单数据完全没有发生变化。第一眼看到这个问题的时候&#xff0c;我心想后台实现逻辑并不…

CSS 语法

CSS 实例 CSS 规则由两个主要的部分构成&#xff1a;选择器&#xff0c;以及一条或多条声明: 选择器通常是您需要改变样式的 HTML 元素。 每条声明由一个属性和一个值组成。 属性&#xff08;property&#xff09;是您希望设置的样式属性&#xff08;style attribute&#x…

IDEA 配置 Maven(解决依赖下载缓慢)

IDEA 配置 Maven&#xff08;解决依赖下载缓慢&#xff09; 这一篇主要介绍 Maven 的基本用法。等我之后学习到框架知识时&#xff0c;会完善此部分内容。 一、Maven 简介 Maven 是专门用于管理和构建 Java 项目的工具&#xff0c;Apache Maven 是一个项目管理和构建工具&#…

lenovo联想台式机 拯救者 刃7000-28ICBR(90KX)原装出厂Windows10系统镜像

LENOVO联想拯救者(90KX)原厂WIN10系统 下载链接&#xff1a;https://pan.baidu.com/s/1beocPJSmnFbY4Y_ZQM2djA?pwd4d1n 系统自带所有驱动、出厂主题壁纸LOGO、Office办公软件、联想电脑管家等预装程序 所需要工具&#xff1a;16G或以上的U盘 文件格式&#xff1a;ISO 文件大…

QT、C++实现地图导航系统(mapSystem)

文章目录 地图导航系统项目应用背景技术栈选择数据处理算法实现界面实现源码展示成果展示源码下载 &#xff08;免费&#xff09; 地图导航系统 项目应用背景 电子地图导航系统的主要目的是为用户提供精确、实时的导航和位置信息&#xff0c;以帮助他们在城市或地区内轻松找到…

Golang 中的调试技巧

掌握有效的策略和工具&#xff0c;实现顺畅的开发 调试是每位开发人员都必须掌握的关键技能。它是识别、隔离和解决代码库中问题的过程。在 Golang 的世界中&#xff0c;掌握有效的调试技巧可以显著提升您的开发工作流程&#xff0c;并帮助您创建更可靠和健壮的应用程序。在本…

【面试经典150 | 矩阵】矩阵置零

文章目录 写在前面Tag题目来源题目解读解题思路方法一&#xff1a; O ( m n ) O(mn) O(mn) 空间复杂度方法二&#xff1a; O ( m n ) O(mn) O(mn) 空间复杂度方法三&#xff1a;仅使用2个额外变量的常量空间复杂度 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算…

【Docker】Docker的应用包含Sandbox、PaaS、Open Solution以及IT运维概念的详细讲解

前言 Docker 是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux或Windows操作系统的机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。 &#x1f4d5;作者简介&#xff1a;热…

简单的考试系统

开发一个简单的考试系统&#xff0c;在HTML页面中建立一个表单&#xff0c;通过post方法传递参数。题目类型包括单选题、多选题和填空题&#xff0c;要求程序给出考试成绩。 <!DOCTYPE html> <html> <head><title>question.html</title><met…

C#餐饮收银系统

一、引言 餐饮收银系统是一种用于管理餐馆、咖啡厅、快餐店等餐饮业务的计算机化工具。它旨在简化点餐、结账、库存管理等任务&#xff0c;提高运营效率&#xff0c;增强客户体验&#xff0c;同时提供准确的财务记录。C# 餐饮收银系统是一种使用C#编程语言开发的餐饮业务管理软…

SG Former论文学习笔记

超越SWin和CSWin Transformer的新模型 代码地址&#xff1a;https://github.com/OliverRensu/SG-Former 论文地址&#xff1a;https://arxiv.org/pdf/2308.12216.pdf ViT在各种视觉任务中虽然成功&#xff0c;但它的计算成本随着Token序列长度的增加呈二次增长&#xff0c;这在…

Gurobi设置初始可行解

目录 1. 决策变量的Start属性直接设置变量的初始值 1.1 Start&#xff1a;MIP变量的起始值&#xff08;初值&#xff09;double类型&#xff0c;可更改 1.2 StartNodeLimit&#xff1a;限制了在完善一组输入部分变量的初始解时&#xff0c;MIP所探索的分支定界的节点的数量 …

【1】c++设计模式——>UML类图的画法

UML介绍 UML:unified modeling language 统一建模语言 面向对象设计主要就是使用UML类图&#xff0c;类图用于描述系统中所包含的类以及他们之间的相互关系&#xff0c;帮助人们简化对系统的理解&#xff0c;他是系统分析和设计阶段的重要产物&#xff0c;也是系统编码和测试的…

Python无废话-办公自动化Excel写入操作

Python 办公自动化-Excel写入 创建并保存Excel文件 import openpyxl workbookopenpyxl.Workbook() #创建空Excel文件 sheetworkbook.active #获取活动的工作表 sheet.title“测试“ #修改sheet工作表名称为测试 workbook.save(“data\input\Test.xlsx”) #保存Excel文件 …

SDK Vitis记录

文章目录 SDK记录SDK中报错“undefined reference to sqrt”的解决方法通过XML文件导入工程的include路径方法说明 其他设置编译选项设置某些文件/文件夹不编译单独设置文件的编译选项 向存储区中导入/导出数据通过GUI操作使用命令行操作 产生C代码的MAP文件在Xilinx SDK 工程的…

Flutter项目安装到Android手机一直显示在assembledebug

问题 Flutter项目安装到Android手机一直显示在assembledebug 原因 网络不好&#xff0c;gradle依赖下载不下来 解决方案 修改如下的文件 gradle-wrapper.properties 使用腾讯提供的gradle镜像下载 distributionUrlhttps://mirrors.cloud.tencent.com/gradle/gradle-7.5…

Mac安装Ecplise产品报错:dose not contain the JNI_CreateJavaVM symbol

1. 絮絮叨叨 工作中需要借助Ecplise Memory Analyzer (MAT)分析dump文件&#xff0c;直接下载、安装、运行MAT报错 询问同事后&#xff0c;同事说可以先安装Ecplise&#xff0c;再以插件的形式安装MAT下载、安装好Eclipse&#xff0c;点击运行仍然报错&#xff0c;且错误信息一…

【算法训练-二分查找 三】【特殊二分】寻找峰值

废话不多说&#xff0c;喊一句号子鼓励自己&#xff1a;程序员永不失业&#xff0c;程序员走向架构&#xff01;本篇Blog的主题是【数组的二分查找】&#xff0c;使用【数组】这个基本的数据结构来实现&#xff0c;这个高频题的站点是&#xff1a;CodeTop&#xff0c;筛选条件为…

AcWing算法提高课-5.6.1同余方程

宣传一下 算法提高课整理 CSDN个人主页&#xff1a;更好的阅读体验 原题链接 题目描述 求关于 x x x 的同余方程 a x ≡ 1 ( m o d b ) ax ≡ 1 \pmod b ax≡1(modb) 的最小正整数解。 输入格式 输入只有一行&#xff0c;包含两个正整数 a , b a,b a,b&#xff0c;用一…