当前位置: 首页 > news >正文

南京网站设计价格/台州网站建设

南京网站设计价格,台州网站建设,郑州市建设安全管理协会网站,中国互联网协会成立于多少年在上一篇文章中,我以网桥类型的 Flannel 插件为例,为你讲解了 Kubernetes 里容器网络和 CNI 插件的主要工作原理。不过,除了这种模式之外,还有一种纯三层(Pure Layer 3)网络方案非常值得你注意。其中的典型…

在上一篇文章中,我以网桥类型的 Flannel 插件为例,为你讲解了 Kubernetes 里容器网络和 CNI 插件的主要工作原理。不过,除了这种模式之外,还有一种纯三层(Pure Layer 3)网络方案非常值得你注意。其中的典型例子,莫过于 Flannel 的 host-gw 模式和 Calico 项目了。

我们先来看一下 Flannel 的 host-gw 模式。

它的工作原理非常简单,我用一张图就可以和你说清楚。为了方便叙述,接下来我会称这张图为“host-gw 示意图”。
在这里插入图片描述

假设现在,Node 1 上的 Infra-container-1,要访问 Node 2 上的 Infra-container-2。

当你设置 Flannel 使用 host-gw 模式之后,flanneld 会在宿主机上创建这样一条规则,以 Node 1 为例:

$ ip route
...
10.244.1.0/24 via 10.168.0.3 dev eth0

这条路由规则的含义是:目的 IP 地址属于 10.244.1.0/24 网段的 IP 包,应该经过本机的 eth0 设备发出去(即:dev eth0);并且,它下一跳地址(next-hop)是 10.168.0.3(即:via 10.168.0.3)。

所谓下一跳地址就是:如果 IP 包从主机 A 发到主机 B,需要经过路由设备 X 的中转。那么 X 的 IP 地址就应该配置为主机 A 的下一跳地址。

而从 host-gw 示意图中我们可以看到,这个下一跳地址对应的,正是我们的目的宿主机 Node 2。

一旦配置了下一跳地址,那么接下来,当 IP 包从网络层进入链路层封装成帧的时候,eth0 设备就会使用下一跳地址对应的 MAC 地址,作为该数据帧的目的 MAC 地址。显然,这个 MAC 地址,正是 Node 2 的 MAC 地址。

这样,这个数据帧就会从 Node 1 通过宿主机的二层网络顺利到达 Node 2 上。

而 Node 2 的内核网络栈从二层数据帧里拿到 IP 包后,会“看到”这个 IP 包的目的 IP 地址是 10.244.1.3,即 Infra-container-2 的 IP 地址。这时候,根据 Node 2 上的路由表,该目的地址会匹配到第二条路由规则(也就是 10.244.1.0 对应的路由规则),从而进入 cni0 网桥,进而进入到 Infra-container-2 当中。

可以看到,host-gw 模式的工作原理,其实就是将每个 Flannel 子网(Flannel Subnet,比如:10.244.1.0/24)的“下一跳”,设置成了该子网对应的宿主机的 IP 地址。

也就是说,这台“主机”(Host)会充当这条容器通信路径里的“网关”(Gateway)。这也正是“host-gw”的含义。

当然,Flannel 子网和主机的信息,都是保存在 Etcd 当中的。flanneld 只需要 WACTH 这些数据的变化,然后实时更新路由表即可。

注意:在 Kubernetes v1.7 之后,类似 Flannel、Calico 的 CNI 网络插件都是可以直接连接 Kubernetes 的 APIServer 来访问 Etcd 的,无需额外部署 Etcd 给它们使用。

而在这种模式下,容器通信的过程就免除了额外的封包和解包带来的性能损耗。根据实际的测试,host-gw 的性能损失大约在 10% 左右,而其他所有基于 VXLAN“隧道”机制的网络方案,性能损失都在 20%~30% 左右。

当然,通过上面的叙述,你也应该看到,host-gw 模式能够正常工作的核心,就在于 IP 包在封装成帧发送出去的时候,会使用路由表里的“下一跳”来设置目的 MAC 地址。这样,它就会经过二层网络到达目的宿主机。

所以说,Flannel host-gw 模式必须要求集群宿主机之间是二层连通的。

需要注意的是,宿主机之间二层不连通的情况也是广泛存在的。比如,宿主机分布在了不同的子网(VLAN)里。但是,在一个 Kubernetes 集群里,宿主机之间必须可以通过 IP 地址进行通信,也就是说至少是三层可达的。否则的话,你的集群将不满足上一篇文章中提到的宿主机之间 IP 互通的假设(Kubernetes 网络模型)。当然,“三层可达”也可以通过为几个子网设置三层转发来实现。

而在容器生态中,要说到像 Flannel host-gw 这样的三层网络方案,我们就不得不提到这个领域里的“龙头老大”Calico 项目了。

实际上,Calico 项目提供的网络解决方案,与 Flannel 的 host-gw 模式,几乎是完全一样的。也就是说,Calico 也会在每台宿主机上,添加一个格式如下所示的路由规则:

<目的容器IP地址段> via <网关的IP地址> dev eth0

其中,网关的 IP 地址,正是目的容器所在宿主机的 IP 地址。

而正如前所述,这个三层网络方案得以正常工作的核心,是为每个容器的 IP 地址,找到它所对应的、“下一跳”的网关。

不过,不同于 Flannel 通过 Etcd 和宿主机上的 flanneld 来维护路由信息的做法,Calico 项目使用了一个“重型武器”来自动地在整个集群中分发路由信息。

这个“重型武器”,就是 BGP。

BGP 的全称是 Border Gateway Protocol,即:边界网关协议。它是一个 Linux 内核原生就支持的、专门用在大规模数据中心里维护不同的“自治系统”之间路由信息的、无中心的路由协议。

这个概念可能听起来有点儿“吓人”,但实际上,我可以用一个非常简单的例子来为你讲清楚。

在这里插入图片描述

在这个图中,我们有两个自治系统(Autonomous System,简称为 AS):AS 1 和 AS 2。而所谓的一个自治系统,指的是一个组织管辖下的所有 IP 网络和路由器的全体。你可以把它想象成一个小公司里的所有主机和路由器。在正常情况下,自治系统之间不会有任何“来往”。

但是,如果这样两个自治系统里的主机,要通过 IP 地址直接进行通信,我们就必须使用路由器把这两个自治系统连接起来。

比如,AS 1 里面的主机 10.10.0.2,要访问 AS 2 里面的主机 172.17.0.3 的话。它发出的 IP 包,就会先到达自治系统 AS 1 上的路由器 Router 1。

而在此时,Router 1 的路由表里,有这样一条规则,即:目的地址是 172.17.0.2 包,应该经过 Router 1 的 C 接口,发往网关 Router 2(即:自治系统 AS 2 上的路由器)。

所以 IP 包就会到达 Router 2 上,然后经过 Router 2 的路由表,从 B 接口出来到达目的主机 172.17.0.3。

但是反过来,如果主机 172.17.0.3 要访问 10.10.0.2,那么这个 IP 包,在到达 Router 2 之后,就不知道该去哪儿了。因为在 Router 2 的路由表里,并没有关于 AS 1 自治系统的任何路由规则。

所以这时候,网络管理员就应该给 Router 2 也添加一条路由规则,比如:目标地址是 10.10.0.2 的 IP 包,应该经过 Router 2 的 C 接口,发往网关 Router 1。

像上面这样负责把自治系统连接在一起的路由器,我们就把它形象地称为:边界网关。它跟普通路由器的不同之处在于,它的路由表里拥有其他自治系统里的主机路由信息。

上面的这部分原理,相信你理解起来应该很容易。毕竟,路由器这个设备本身的主要作用,就是连通不同的网络。

但是,你可以想象一下,假设我们现在的网络拓扑结构非常复杂,每个自治系统都有成千上万个主机、无数个路由器,甚至是由多个公司、多个网络提供商、多个自治系统组成的复合自治系统呢?

这时候,如果还要依靠人工来对边界网关的路由表进行配置和维护,那是绝对不现实的。

而这种情况下,BGP 大显身手的时刻就到了。

在使用了 BGP 之后,你可以认为,在每个边界网关上都会运行着一个小程序,它们会将各自的路由表信息,通过 TCP 传输给其他的边界网关。而其他边界网关上的这个小程序,则会对收到的这些数据进行分析,然后将需要的信息添加到自己的路由表里。

这样,图 2 中 Router 2 的路由表里,就会自动出现 10.10.0.2 和 10.10.0.3 对应的路由规则了。

所以说,所谓 BGP,就是在大规模网络中实现节点路由信息共享的一种协议。

而 BGP 的这个能力,正好可以取代 Flannel 维护主机上路由表的功能。而且,BGP 这种原生就是为大规模网络环境而实现的协议,其可靠性和可扩展性,远非 Flannel 自己的方案可比。

需要注意的是,BGP 协议实际上是最复杂的一种路由协议。我在这里的讲述和所举的例子,仅是为了能够帮助你建立对 BGP 的感性认识,并不代表 BGP 真正的实现方式。

接下来,我们还是回到 Calico 项目上来。

在了解了 BGP 之后,Calico 项目的架构就非常容易理解了。它由三个部分组成:

● Calico 的 CNI 插件。这是 Calico 与 Kubernetes 对接的部分。我已经在上一篇文章中,和你详细分享了 CNI 插件的工作原理,这里就不再赘述了。
● Felix。它是一个 DaemonSet,负责在宿主机上插入路由规则(即:写入 Linux 内核的 FIB 转发信息库),以及维护 Calico 所需的网络设备等工作。
● BIRD。它就是 BGP 的客户端,专门负责在集群里分发路由规则信息。

除了对路由信息的维护方式之外,Calico 项目与 Flannel 的 host-gw 模式的另一个不同之处,就是它不会在宿主机上创建任何网桥设备。这时候,Calico 的工作方式,可以用一幅示意图来描述,如下所示(在接下来的讲述中,我会统一用“BGP 示意图”来指代它):
在这里插入图片描述

其中的绿色实线标出的路径,就是一个 IP 包从 Node 1 上的 Container 1,到达 Node 2 上的 Container 4 的完整路径。

可以看到,Calico 的 CNI 插件会为每个容器设置一个 Veth Pair 设备,然后把其中的一端放置在宿主机上(它的名字以 cali 前缀开头)。

此外,由于 Calico 没有使用 CNI 的网桥模式,Calico 的 CNI 插件还需要在宿主机上为每个容器的 Veth Pair 设备配置一条路由规则,用于接收传入的 IP 包。比如,宿主机 Node 2 上的 Container 4 对应的路由规则,如下所示:

10.233.2.3 dev cali5863f3 scope link

即:发往 10.233.2.3 的 IP 包,应该进入 cali5863f3 设备。

基于上述原因,Calico 项目在宿主机上设置的路由规则,肯定要比 Flannel 项目多得多。不过,Flannel host-gw 模式使用 CNI 网桥的主要原因,其实是为了跟 VXLAN 模式保持一致。否则的话,Flannel 就需要维护两套 CNI 插件了。

有了这样的 Veth Pair 设备之后,容器发出的 IP 包就会经过 Veth Pair 设备出现在宿主机上。然后,宿主机网络栈就会根据路由规则的下一跳 IP 地址,把它们转发给正确的网关。接下来的流程就跟 Flannel host-gw 模式完全一致了。

其中,这里最核心的“下一跳”路由规则,就是由 Calico 的 Felix 进程负责维护的。这些路由规则信息,则是通过 BGP Client 也就是 BIRD 组件,使用 BGP 协议传输而来的。

而这些通过 BGP 协议传输的消息,你可以简单地理解为如下格式:

[BGP消息]
我是宿主机192.168.1.3
10.233.2.0/24网段的容器都在我这里
这些容器的下一跳地址是我

不难发现,Calico 项目实际上将集群里的所有节点,都当作是边界路由器来处理,它们一起组成了一个全连通的网络,互相之间通过 BGP 协议交换路由规则。这些节点,我们称为 BGP Peer。

需要注意的是,Calico 维护的网络在默认配置下,是一个被称为“Node-to-Node Mesh”的模式。这时候,每台宿主机上的 BGP Client 都需要跟其他所有节点的 BGP Client 进行通信以便交换路由信息。但是,随着节点数量 N 的增加,这些连接的数量就会以 N²的规模快速增长,从而给集群本身的网络带来巨大的压力。

所以,Node-to-Node Mesh 模式一般推荐用在少于 100 个节点的集群里。而在更大规模的集群中,你需要用到的是一个叫作 Route Reflector 的模式。

在这种模式下,Calico 会指定一个或者几个专门的节点,来负责跟所有节点建立 BGP 连接从而学习到全局的路由规则。而其他节点,只需要跟这几个专门的节点交换路由信息,就可以获得整个集群的路由规则信息了。

这些专门的节点,就是所谓的 Route Reflector 节点,它们实际上扮演了“中间代理”的角色,从而把 BGP 连接的规模控制在 N 的数量级上。

此外,我在前面提到过,Flannel host-gw 模式最主要的限制,就是要求集群宿主机之间是二层连通的。而这个限制对于 Calico 来说,也同样存在。

举个例子,假如我们有两台处于不同子网的宿主机 Node 1 和 Node 2,对应的 IP 地址分别是 192.168.1.2 和 192.168.2.2。需要注意的是,这两台机器通过路由器实现了三层转发,所以这两个 IP 地址之间是可以相互通信的。

而我们现在的需求,还是 Container 1 要访问 Container 4。

按照我们前面的讲述,Calico 会尝试在 Node 1 上添加如下所示的一条路由规则:

10.233.2.0/16 via 192.168.2.2 eth0

但是,这时候问题就来了。

上面这条规则里的下一跳地址是 192.168.2.2,可是它对应的 Node 2 跟 Node 1 却根本不在一个子网里,没办法通过二层网络把 IP 包发送到下一跳地址。

在这种情况下,你就需要为 Calico 打开 IPIP 模式。

我把这个模式下容器通信的原理,总结成了一张图片,如下所示(接下来我会称之为:IPIP 示意图):

在这里插入图片描述

在 Calico 的 IPIP 模式下,Felix 进程在 Node 1 上添加的路由规则,会稍微不同,如下所示:

10.233.2.0/24 via 192.168.2.2 tunl0

可以看到,尽管这条规则的下一跳地址仍然是 Node 2 的 IP 地址,但这一次,要负责将 IP 包发出去的设备,变成了 tunl0。注意,是 T-U-N-L-0,而不是 Flannel UDP 模式使用的 T-U-N-0(tun0),这两种设备的功能是完全不一样的。

Calico 使用的这个 tunl0 设备,是一个 IP 隧道(IP tunnel)设备。

在上面的例子中,IP 包进入 IP 隧道设备之后,就会被 Linux 内核的 IPIP 驱动接管。IPIP 驱动会将这个 IP 包直接封装在一个宿主机网络的 IP 包中,如下所示:

在这里插入图片描述

其中,经过封装后的新的 IP 包的目的地址(图 5 中的 Outer IP Header 部分),正是原 IP 包的下一跳地址,即 Node 2 的 IP 地址:192.168.2.2。

而原 IP 包本身,则会被直接封装成新 IP 包的 Payload。

这样,原先从容器到 Node 2 的 IP 包,就被伪装成了一个从 Node 1 到 Node 2 的 IP 包。

由于宿主机之间已经使用路由器配置了三层转发,也就是设置了宿主机之间的“下一跳”。所以这个 IP 包在离开 Node 1 之后,就可以经过路由器,最终“跳”到 Node 2 上。

这时,Node 2 的网络内核栈会使用 IPIP 驱动进行解包,从而拿到原始的 IP 包。然后,原始 IP 包就会经过路由规则和 Veth Pair 设备到达目的容器内部。

以上,就是 Calico 项目主要的工作原理了。

不难看到,当 Calico 使用 IPIP 模式的时候,集群的网络性能会因为额外的封包和解包工作而下降。在实际测试中,Calico IPIP 模式与 Flannel VXLAN 模式的性能大致相当。所以,在实际使用时,如非硬性需求,我建议你将所有宿主机节点放在一个子网里,避免使用 IPIP。

不过,通过上面对 Calico 工作原理的讲述,你应该能发现这样一个事实:

如果 Calico 项目能够让宿主机之间的路由设备(也就是网关),也通过 BGP 协议“学习”到 Calico 网络里的路由规则,那么从容器发出的 IP 包,不就可以通过这些设备路由到目的宿主机了么?

比如,只要在上面“IPIP 示意图”中的 Node 1 上,添加如下所示的一条路由规则:

10.233.2.0/24 via 192.168.1.1 eth0

然后,在 Router 1 上(192.168.1.1),添加如下所示的一条路由规则:

10.233.2.0/24 via 192.168.2.1 eth0

那么 Container 1 发出的 IP 包,就可以通过两次“下一跳”,到达 Router 2(192.168.2.1)了。以此类推,我们可以继续在 Router 2 上添加“下一条”路由,最终把 IP 包转发到 Node 2 上。

遗憾的是,上述流程虽然简单明了,但是在 Kubernetes 被广泛使用的公有云场景里,却完全不可行。

这里的原因在于:公有云环境下,宿主机之间的网关,肯定不会允许用户进行干预和设置。

当然,在大多数公有云环境下,宿主机(公有云提供的虚拟机)本身往往就是二层连通的,所以这个需求也不强烈。

不过,在私有部署的环境下,宿主机属于不同子网(VLAN)反而是更加常见的部署状态。这时候,想办法将宿主机网关也加入到 BGP Mesh 里从而避免使用 IPIP,就成了一个非常迫切的需求。

而在 Calico 项目中,它已经为你提供了两种将宿主机网关设置成 BGP Peer 的解决方案。

第一种方案,就是所有宿主机都跟宿主机网关建立 BGP Peer 关系。

这种方案下,Node 1 和 Node 2 就需要主动跟宿主机网关 Router 1 和 Router 2 建立 BGP 连接。从而将类似于 10.233.2.0/24 这样的路由信息同步到网关上去。

需要注意的是,这种方式下,Calico 要求宿主机网关必须支持一种叫作 Dynamic Neighbors 的 BGP 配置方式。这是因为,在常规的路由器 BGP 配置里,运维人员必须明确给出所有 BGP Peer 的 IP 地址。考虑到 Kubernetes 集群可能会有成百上千个宿主机,而且还会动态地添加和删除节点,这时候再手动管理路由器的 BGP 配置就非常麻烦了。而 Dynamic Neighbors 则允许你给路由器配置一个网段,然后路由器就会自动跟该网段里的主机建立起 BGP Peer 关系。

不过,相比之下,我更愿意推荐第二种方案。

这种方案,是使用一个或多个独立组件负责搜集整个集群里的所有路由信息,然后通过 BGP 协议同步给网关。而我们前面提到,在大规模集群中,Calico 本身就推荐使用 Route Reflector 节点的方式进行组网。所以,这里负责跟宿主机网关进行沟通的独立组件,直接由 Route Reflector 兼任即可。

更重要的是,这种情况下网关的 BGP Peer 个数是有限并且固定的。所以我们就可以直接把这些独立组件配置成路由器的 BGP Peer,而无需 Dynamic Neighbors 的支持。

当然,这些独立组件的工作原理也很简单:它们只需要 WATCH Etcd 里的宿主机和对应网段的变化信息,然后把这些信息通过 BGP 协议分发给网关即可。

总结

在本篇文章中,我为你详细讲述了 Fannel host-gw 模式和 Calico 这两种纯三层网络方案的工作原理。

需要注意的是,在大规模集群里,三层网络方案在宿主机上的路由规则可能会非常多,这会导致错误排查变得困难。此外,在系统故障的时候,路由规则出现重叠冲突的概率也会变大。

基于上述原因,如果是在公有云上,由于宿主机网络本身比较“直白”,我一般会推荐更加简单的 Flannel host-gw 模式。

但不难看到,在私有部署环境里,Calico 项目才能够覆盖更多的场景,并为你提供更加可靠的组网方案和架构思路。

相关文章:

【云原生】解读Kubernetes三层网络方案

在上一篇文章中&#xff0c;我以网桥类型的 Flannel 插件为例&#xff0c;为你讲解了 Kubernetes 里容器网络和 CNI 插件的主要工作原理。不过&#xff0c;除了这种模式之外&#xff0c;还有一种纯三层&#xff08;Pure Layer 3&#xff09;网络方案非常值得你注意。其中的典型…...

elasticsearch8.3.2搭建部署

Elasticsearch8.3.2搭建部署详细步骤 0.过往文章 ES-6文章&#xff1a; Elasticsearch6.6.0部署、原理和使用介绍: https://blog.csdn.net/wt334502157/article/details/119515730 ES-7文章&#xff1a; Elasticsearch7.6.1部署、原理和使用介绍: https://blog.csdn.net/wt…...

MySQL_InnoDB引擎

InnoDB引擎 逻辑存储结构 表空间&#xff08;ibd文件&#xff09;&#xff0c;一个mysql实例可以对应多个表空间&#xff0c;用于存储记录、索引等数据。 段&#xff0c;分为数据段&#xff08;Leaf node segment&#xff09;、索引段(Non-leaf node segment)、回滚段(Rollba…...

json-server使用

文章目录json-server使用简介安装json-server启动json-server操作创建数据库查询数据增加数据删除数据修改数据putpatch配置静态资源静态资源首页资源json-server使用 简介 github地址 安装json-server npm install -g json-server启动json-server json-server --watch db…...

实现mint操作(参考pancake)

区块链发展越来越好&#xff0c;nft已经火了很久&#xff0c;今天写一下如何用js、web3js、调用合约&#xff0c;实现mint nft。简单的调用&#xff1a;//引入一些依赖 &#xff08;根据需要&#xff0c;有一些是其他功能的&#xff09; import useActiveWeb3React from ./web3…...

Linux进程信号

目录 一、认识信号 1.1 生活角度的信号 1.2 技术角度的信号 1.3 信号的发送与记录 1.4 常见信号处理方式 二、产生信号 2.1 通过终端按键产生信号(核心转储) 2.2 通过系统函数向进程发送信号 2.2.1 kill()函数 2.2.2 raise()函数 2.2.3 abort()函数 2.3 因软件条件…...

1.7 Web学生管理系统

1.定义通讯协议基于前面介绍过的 FLask Web 网站 与 urlib 的访问网站的方法&#xff0c;设计一个综合应用实例。它是一个基于 Web 的学生记录管理程序。学生的记录包括 id(学号) 、name(姓名) 、grade(成绩)&#xff0c;服务器的作用是建立与维护一个Sqllite 的学生数据库 stu…...

前端教学视频分享(视频内容与市场时刻保持紧密相连,火热更新中。。。)

⚠️获取公众号 本次要想大家推荐一下本人的公众号&#xff0c;在微信中搜索公众号 李帅豪在对话框中输入前端视频四个字即可立即获取所有视频&#xff0c;不收费无广告&#xff01;&#xff01;&#xff01; 本公众号收集了近两年来前端最新最优秀的学习视频&#xff0c;涵盖…...

Docker-consul的容器服务更新与发现

一.Consul概述1.1 什么是服务注册与发现服务注册与发现是微服务架构中不可或缺的重要组件。起初服务都是单节点的&#xff0c;不保障高可用性&#xff0c;也不考虑服务的压力承载&#xff0c;服务之间调用单纯的通过接口访问。直到后来出现了多个节点的分布式架构&#xff0c;起…...

Java笔记-线程中断

线程的中断 1.应用场景&#xff1a; 假设从网络下载一个100M的文件&#xff0c;如果网速很慢&#xff0c;用户等得不耐烦&#xff0c;就可能在下载过程中点“取消”&#xff0c;这时&#xff0c;程序就需要中断下载线程的执行。 2.常用中断线程的方法&#xff1a; 1.使用标…...

js中的自调用表达式

自调用表达式 由函数表达式创建的函数可以自调用&#xff0c;称之为自调用表达式。 语法 由函数表达式创建函数: const myFn function () {let a 100console.log(a);return a } myFn() //调用后执行&#xff0c;输出100表达式后面紧跟 ( ) 则会自动调用: const myFn fu…...

Python操作的5个坏习惯,你中了几个呢?

很多文章都有介绍怎么写好 Python&#xff0c;我今天呢相反&#xff0c;说说写代码时的几个坏习惯。有的习惯会让 Bug 变得隐蔽难以追踪&#xff0c;当然&#xff0c;也有的并没有错误&#xff0c;只是个人觉得不够完美。 注意&#xff1a;示例代码在 Python 3.6 环境下编写 …...

C++并发与多线程编程(3)---线程间共享数据

主要内容&#xff1a;共享数据带来的问题使用互斥量保护数据数据保护的替代方案共享数据带来的问题当涉及到共享数据时&#xff0c;问题可能是因为共享数据修改所导致。如果共享数据是只读的&#xff0c;那么只读操作不会影响到数据&#xff0c;更不会涉及对数据的修改&#xf…...

洞察:2022年医疗行业数据安全回顾及2023年展望

过去的2022年&#xff0c;统筹安全与发展&#xff0c;在医疗信息化发展道路中&#xff0c;数据安全不可或缺。这一年&#xff0c;实施五年多的《网络安全法》迎来首次修改&#xff0c;《数据安全法》、《个人信息保护法》实施一周年&#xff0c;配套的《数据出境安全评估办法》…...

多传感器融合定位十五-多传感器时空标定(综述)

多传感器融合定位十五-多传感器时空标定1. 多传感器标定简介1.1 标定内容及方法1.2 讲解思路2. 内参标定2.1 雷达内参标定2.2 IMU内参标定2.3 编码器内参标定2.4 相机内参标定3. 外参标定3.1 雷达和相机外参标定3.2 多雷达外参标定3.3 手眼标定3.4 融合中标定3.5 总结4. 时间标…...

开发微服务电商项目演示(三)

一&#xff0c;nginx动静分离第1步&#xff1a;通过SwitchHosts新增二级域名&#xff1a;images.zmall.com第2步&#xff1a;将本次项目的易买网所有静态资源js/css/images复制到nginx中的html目录下第3步&#xff1a;在nginx的核心配置文件nginx.conf中新增二级域名images.zma…...

C/C++排序算法(二) —— 选择排序和堆排序

文章目录前言1. 直接选择排序&#x1f351; 基本思想&#x1f351; 具体步骤&#x1f351; 具体步骤&#x1f351; 动图演示&#x1f351; 代码实现&#x1f351; 代码升级&#x1f351; 特性总结2. 堆排序&#x1f351; 向下调整算法&#x1f351; 任意树调整为堆的思想&#…...

爬虫笔记之——selenium安装与使用(1)

爬虫笔记之——selenium安装与使用&#xff08;1&#xff09;一、安装环境1、下载Chrome浏览器驱动&#xff08;1&#xff09;查看Chrome版本&#xff08;2&#xff09;下载相匹配的Chrome驱动程序地址&#xff1a;https://chromedriver.storage.googleapis.com/index.html2、学…...

STC15单片机软串口的使用

STC15软串口的使用&#x1f4d6;在没有使用定时器资源的情况下&#xff0c;根据波特率位传输时间&#xff0c;利用STC-ISP工具自动计算出位延时函数。 ✨在官方所提供的库函数中位传输时间函数,仅适用于使用波特率为&#xff1a;9600的串口数据传输&#xff1a; void BitTime(…...

Ansible的脚本------playbook剧本

一、剧本的前置知识点1、主机清单ansible默认的主机清单是/etc/ansible/hosts文件主机清单可以手动设置&#xff0c;也可以通过Dynamic Inventory动态生成一般主机名使用FQDNvi /etc/ansible/hosts [webserver] #使用方括号设置组名 www1.example.org #定…...

实验5-计算中值及分治技术

目录 1.寻找中位数(利用快速排序来寻找中位数) 2.分治方法求数组的和 3.合并排序...

dbeaver从excel导入数据笔记

场景 有excel的数据&#xff0c;需要做到数据库里。 方案一&#xff1a; 开发代码来实现。缺点是需要开发成本。 方案二&#xff1a; 数据库导入工具导入。不用开发&#xff0c;相对快速一些。 这里说下数据库工具导入。 操作过程 1、拿到excel数据文件&#xff0c;根据标题…...

PyTorch学习笔记:nn.MarginRankingLoss——排序损失

PyTorch学习笔记&#xff1a;nn.MarginRankingLoss——排序损失 torch.nn.MarginRankingLoss(margin0.0, size_averageNone, reduceNone, reductionmean)功能&#xff1a;创建一个排序损失函数&#xff0c;用于衡量输入x1x_1x1​与x2x_2x2​之间的排序损失(Ranking Loss)&…...

【JavaScript】34_Date对象 ,日期的格式化

8、Date Date 在JS中所有的和时间相关的数据都由Date对象来表示 对象的方法&#xff1a; getFullYear() 获取4位年份 getMonth() 返当前日期的月份&#xff08;0-11&#xff09; getDate() 返回当前是几日 getDay() 返回当前日期是周几&#xff08;0-6&#xff09; 0表示周日…...

计算机视觉 对比学习13篇经典论文、解读、代码

为了快速对 机器视觉中的对比学习有一个快速了解&#xff0c;或者后续复习&#xff0c;此处收录了 13篇经典论文、一些讲解地较好的博客和相应的Github代码&#xff0c;用不同颜色标记。 ​ 对比学习 13篇经典论文 论文代码和博客http://​www.webhub123.com/#/home/detail?p…...

MySQL 选择数据库

在你连接到 MySQL 数据库后&#xff0c;可能有多个可以操作的数据库&#xff0c;所以你需要选择你要操作的数据库。 在 MySQL 中就有很多系统自带的数据库&#xff0c;那么在操作数据库之前就必须要确定是哪一个数据库。 在 MySQL 中&#xff0c;USE 语句用来完成一个数据库到…...

雅思经验(9)

写作&#xff1a;关于趋势的上升和下降在小作文中&#xff0c;真的是非常常见的&#xff0c;所以还是要积累一下。下面给出了很多词&#xff0c;但是在雅思写作中并不是词越丰富&#xff0c;分数就越高的。雅思写作强调的是准确性&#xff1a;在合适的地方用合适的词和句法。不…...

java面试题(二十)中间件redis

1.1 Redis可以用来做什么&#xff1f; 参考答案 Redis最常用来做缓存&#xff0c;是实现分布式缓存的首先中间件&#xff1b;Redis可以作为数据库&#xff0c;实现诸如点赞、关注、排行等对性能要求极高的互联网需求&#xff1b;Redis可以作为计算工具&#xff0c;能用很小的…...

JavaWEB必知必会-Servlet

目录 Servlet简介Servlet快速入门Servlet配置详解ServletContext 1 Servlet简介 Servlet 运行在服务端的Java小程序&#xff0c;是sun公司提供一套规范&#xff08;接口&#xff09;&#xff0c;用来处理客户端请求、响应给浏览器的动态资源。但servlet的实质就是java代码&a…...

oralce查找返回不同的值,寻找不同的表(原创)

查找返回不同的值&#xff0c;寻找不同的表 select case a_id when 1 then (select b_id|| ||b_desc from b where b.b_ida.a_id) else (select e_id || ||e_desc from e where e.e_ida.a_id) end from a; 以上方法的缺陷是单表&#xff0c;判断。今天来了个挑战&#…...