建网站外包/长春百度推广公司
前面我们知道了容器是通过对一个普通的linux进程进行隔离和限制实现的一种特殊视角下的进程表现。而隔离和限制的实现技术分别是"Namespace"和“Cgroups”,在这两种机制的控制下,我们需要知道容器的本质是一种特殊的进程。
我们现在有了这个认知之后,我们再来思考一个问题,容器在自己的进程视角下看到了一堆自己控制下的资源,那么他看到的文件系统又是啥样的呢?
我们很自然就想到,这其实和容器的Mount Namespace的问题,我们理解中,在容器内部,通过限制,容器进程看到的是完全独立的文件系统,这样它就能在自己的容器目录下进行操作,而不用受到宿主机或者其他容器进程的影响。也就是说他是不是实现了文件系统级别的限制。
一、限制之下文件系统的表现
实际上我们上面说的不是对的,即便你开启了Mount Namespace,容器进程看到的文件系统和宿主机的文件系统是一模一样的。
这句话的意思就是实际上文件系统层面实际上没发生任何隔离和限制,Mount Namespace修改的是容器进程对于文件系统挂载点的认知,也就是说只有挂载这个操作发生之后,进程的视图才会改变,在这之前,新创建的容器只会直接继承宿主机的各个挂载点。
换言之就是说我们需要在容器进程中先挂载对应的文件目录,然后你的Mount Namespace才有效果。
这就是Mount Namespace和其他Namespace的使用略有不同,他对于容器进程视图的改变,一定是伴随挂载操作mount才能生效。
但是在用户视角下,我们希望的是上手就操作,屏蔽后面多的这一步,我们就希望创建一个新的容器的时候,创建好了就完事了,不用我们自己去做挂载这一步。所以我们可以在容器进程启动之前重新挂载容器的整个根目录 / 即可,然后进行Mount Namespace,那么这个挂载就对其他容器和宿主机都是不可见的了。
在Linux操作系统中,有一个名为chroot的命令就可以实现这个能力,他的全称是"change root file system",翻译过来就是改变进程的根目录到你指定的位置。
二、chroot
我们来实际操作一下来使用一下这个命令。
假设我们现在有一个$HOME/test目录,也就是家目录下的test目录,我们想要把他作为一个/bin/bash进程的根目录。
1、首先,创建一个test目录和几个lib文件夹
T=$HOME/test
mkdir -p $HOME/test
mkdir -p $HOME/test/{bin,lib64,lib}
cd $T
2、然后,把 bash 命令拷贝到 test 目录对应的 bin 路径下:
# 此时就把bin下面的bash 和 ls拷贝到了家目录下的test下的bin下面,
# 后面我们进程挂载到这个test/bin下面就能直接使用bash和ls了
cp -v /bin/{bash,ls} $HOME/test/bin
3、接下来,把 bash 命令需要的所有 so 文件,也拷贝到 test 目录对应的 lib64 路径下。找到 so 文件可以用 ldd 命令:
T=$HOME/test
list="$(ldd /bin/ls | egrep -o '/lib.*\.[0-9]')"
for i in $list; do cp -v "$i" "${T}${i}"; done
4、最后,执行 chroot 命令,告诉操作系统,我们将使用 $HOME/test 目录作为 /bin/bash 进程的根目录:此时就实现了这个挂载
chroot $HOME/test /bin/bash
这时,你如果执行 “ls /”,就会看到,它返回的都是 $HOME/test 目录下面的内容,而不是宿主机的内容。更重要的是,对于被 chroot 的进程来说,它并不会感受到自己的根目录已经被“修改”成 $HOME/test 了。这种视图被修改的原理,和之前介绍的 Linux Namespace 很类似,实际上,Mount Namespace 正是基于对 chroot 的不断改良才被发明出来的,它也是 Linux 操作系统里的第一个 Namespace。
当然,为了能够让容器的这个根目录看起来更“真实”,我们一般会在这个容器的根目录下挂载一个完整操作系统的文件系统,比如 Ubuntu16.04 的 ISO。这样,在容器启动之后,我们在容器里通过执行 “ls /” 查看根目录下的内容,就是 Ubuntu 16.04 的所有目录和文件。
而这个挂载在容器根目录上、用来为容器进程提供隔离后执行环境的文件系统,就是所谓的“容器镜像”。它还有一个更为专业的名字,叫作:rootfs(根文件系统)。所以,一个最常见的 rootfs,或者说容器镜像,会包括如下所示的一些目录和文件,比如 /bin,/etc,/proc 等等:
$ ls /
bin dev etc home lib lib64 mnt opt proc root run sbin sys tmp usr var
而你进入容器之后执行的 /bin/bash,就是 /bin 目录下的可执行文件,与宿主机的 /bin/bash 完全不同。现在,你应该可以理解,对 Docker 项目来说,它最核心的原理实际上就是为待创建的用户进程:
1、启用 Linux Namespace 配置;
2、设置指定的 Cgroups 参数;
3、切换进程的根目录(Change Root)。
这样,一个完整的容器就诞生了。不过,Docker 项目在最后一步的切换上会优先使用 pivot_root 系统调用,如果系统不支持,才会使用 chroot。这两个系统调用虽然功能类似,但是也有细微的区别,这一部分小知识就交给你课后去探索了。另外,需要明确的是,rootfs 只是一个操作系统所包含的文件、配置和目录,并不包括操作系统内核。在 Linux 操作系统中,这两部分是分开存放的,操作系统只有在开机启动时才会加载指定版本的内核镜像。
三、 rootfs
上面我们引出了rootfs的概念,但是我们也得知,他就是一个文件系统,不包括内核。
所以说,rootfs 只包括了操作系统的“躯壳”,并没有包括操作系统的“灵魂”。那么,对于容器来说,这个操作系统的“灵魂”又在哪里呢?实际上,同一台机器上的所有容器,都共享宿主机操作系统的内核。这就意味着,如果你的应用程序需要配置内核参数、加载额外的内核模块,以及跟内核进行直接的交互,你就需要注意了:这些操作和依赖的对象,都是宿主机操作系统的内核,它对于该机器上的所有容器来说是一个“全局变量”,牵一发而动全身。这也是容器相比于虚拟机的主要缺陷之一:毕竟后者不仅有模拟出来的硬件机器充当沙盒,而且每个沙盒里还运行着一个完整的 Guest OS 给应用随便折腾。不过,正是由于 rootfs 的存在,容器才有了一个被反复宣传至今的重要特性:一致性。什么是容器的“一致性”呢?
有了容器之后,更准确地说,有了容器镜像(即 rootfs)之后,这个问题被非常优雅地解决了。由于 rootfs 里打包的不只是应用,而是整个操作系统的文件和目录,也就意味着,应用以及它运行所需要的所有依赖,都被封装在了一起。事实上,对于大多数开发者而言,他们对应用依赖的理解,一直局限在编程语言层面。比如 Golang 的 Godeps.json。但实际上,一个一直以来很容易被忽视的事实是,对一个应用来说,操作系统本身才是它运行所需要的最完整的“依赖库”。有了容器镜像“打包操作系统”的能力,这个最基础的依赖环境也终于变成了应用沙盒的一部分。这就赋予了容器所谓的一致性:无论在本地、云端,还是在一台任何地方的机器上,用户只需要解压打包好的容器镜像,那么这个应用运行所需要的完整的执行环境就被重现出来了。这种深入到操作系统级别的运行环境一致性,打通了应用在本地开发和远端执行环境之间难以逾越的鸿沟。
四、关于增量rootfs和Union File System
不过,这时引出另一个非常棘手的问题:难道我每开发一个应用,或者升级一下现有的应用,都要重复制作一次 rootfs 吗?
比如,我现在用 Ubuntu 操作系统的 ISO 做了一个 rootfs,然后又在里面安装了 Java 环境,用来部署我的 Java 应用。那么,我的另一个同事在发布他的 Java 应用时,显然希望能够直接使用我安装过 Java 环境的 rootfs,而不是重复这个流程。类似于实现一种共享公共镜像的操作,不用每个人做重复性的工作。
一种比较直观的解决办法是,我在制作 rootfs 的时候,每做一步“有意义”的操作,就保存一个 rootfs 出来,这样其他同事就可以按需求去用他需要的 rootfs 了。但是,这个解决办法并不具备推广性。原因在于,一旦你的同事们修改了这个 rootfs,新旧两个 rootfs 之间就没有任何关系了,因为产生了一个新的rootfs。这样做的结果就是极度的碎片化。那么,既然这些修改都基于一个旧的 rootfs,我们能不能以增量的方式去做这些修改呢?这样做的好处是,所有人都只需要维护相对于 base rootfs 修改的增量内容,而不是每次修改都制造一个“fork”。我们只保存一份基础的,每个人不同内容的自己维护一份增量就行了,这样我们只每个人维护增量的内容。
答案当然是肯定的。这也正是为何,Docker 公司在实现 Docker 镜像时并没有沿用以前制作 rootfs 的标准流程,而是做了一个小小的创新:Docker 在镜像的设计中,引入了层(layer)的概念。也就是说,用户制作镜像的每一步操作,都会生成一个层,也就是一个增量 rootfs。当然,这个想法不是凭空臆造出来的,而是用到了一种叫作联合文件系统(Union File System)的能力。Union File System 也叫 UnionFS,最主要的功能是将多个不同位置的目录联合挂载(union mount)到同一个目录下。比如,我现在有两个目录 A 和 B,它们分别有两个文件:A目录下面有a和x文件,B目录下面有b和x两个文件。
$ tree
.
├── A
│ ├── a
│ └── x
└── B├── b└── x
然后,使用联合挂载的方式,将这两个目录挂载到一个公共的目录 C 上:
$ mkdir C
$ mount -t aufs -o dirs=./A:./B none ./C
这时,再查看目录 C 的内容,就能看到目录 A 和 B 下的文件被合并到了一起:
$ tree ./C
./C
├── a
├── b
└── x
可以看到,在这个合并后的目录 C 里,有 a、b、x 三个文件,并且 x 文件只有一份。这,就是“合并”的含义。此外,如果你在目录 C 里对 a、b、x 文件做修改,这些修改也会在对应的目录 A、B 中生效。那么,在 Docker 项目中,又是如何使用这种 Union File System 的呢?
我的环境是CentOS Linux release 7.8.2003和Docker Engine - Community 20.10.14,这对组合默认使用的是 overlay2这个联合文件系统的实现。你可以通过 docker info 命令,查看到这个信息,其栏目就是docker info中的Storage Driver: overlay2。
对于 overlay2 来说,它最关键的目录结构在 /var/lib/docker 路径下的overlay2 目录:
/var/lib/docker/overlay2/<layer_id>
而这个目录的作用,我们不妨通过一个具体例子来看一下。现在,我们启动一个容器,比如:
$ docker run -d redis:latest sleep 3600
这时候,Docker 就会从 Docker Hub 上拉取一个redis镜像到本地。这个所谓的“镜像”,实际上就是一个 redis的 rootfs,它的内容是 Uredis的所有文件和目录。不过,与之前我们讲述的 rootfs 稍微不同的是,Docker 镜像使用的 rootfs,往往由多个“层”组成:
$ docker image inspect redis:latest
..."RootFS": {"Type": "layers","Layers": ["sha256:8553b91047dad45bedc292812586f1621e0a464a09a7a7c2ce6ac5f8ba2535d7","sha256:a29f3c086730b523ac2e1c55da793a9d63fc4c7167fa7196500011f4d0e5df05","sha256:bee68ae43a83b10c9f490448abb719304af02a834f3557fda199c6e408ae8cc7","sha256:df132c87bdb2ed2662fbcab6e9ecce353f6e8fe257797f442bc50bf70a78a089","sha256:c4afa995e3ec19959c6f9768d7ef6d8614717301ea4997b624de7aeaa2ff3690","sha256:47998e638469ca465758350e8f2a24675d6ae02600ac00baae447c3900ee337f"]},
可以看到,这个 redis镜像,实际上由六个层组成。这六个层就是六增量 rootfs,每一层都是redis文件与目录的一部分;而在使用镜像时,Docker 会把这些增量联合挂载在一个统一的挂载点上(等价于前面例子里的“/C”目录)。这个挂载点就是 /var/lib/docker/overlay2/,比如:
/var/lib/docker/overlay2/8cfeca51edf8dab2e19ce574dbf1fc6d845ca38880b026bafdcc514c83d94e8b
那么,前面提到的五个镜像层,又是如何被联合挂载成这样一个完整的 redis文件系统的呢?
五、三层划分
我们说容器镜像是以多层划分开的,一共分为三层,从上到下分别是:
可读写层(RW):
它是容器的 rootfs 最上面的一层,它的挂载方式为:rw,即 read write。
在没有写入文件之前,这个目录是空的。而一旦在容器里做了写操作,
你修改产生的内容就会以增量的方式出现在这个层中。可是,你有没有想到这样一个问题:
如果我现在要做的,是删除只读层里的一个文件呢?为了实现这样的删除操作,
AuFS 会在可读写层创建一个 whiteout 文件,把只读层里的文件“遮挡”起来。比如,
你要删除只读层里一个名叫 foo 的文件,那么这个删除操作实际上是在可读写层创建了一个名叫.wh.foo 的文件。
这样,当这两个层被联合挂载之后,foo 文件就会被.wh.foo 文件“遮挡”起来,“消失”了。
这个功能,就是“ro+wh”的挂载方式,即只读 +whiteout 的含义,称之为隔档。
所以,最上面这个可读写层的作用,就是专门用来存放你修改 rootfs 后产生的增量,
无论是增、删、改,都发生在这里。而当我们使用完了这个被修改过的容器之后,
还可以使用 docker commit 和 push 指令,保存这个被修改过的可读写层,并上传到 Docker Hub 上,
供其他人使用;而与此同时,原先的只读层里的内容则不会有任何变化。这,就是增量 rootfs 的好处。
说白了就是下面的基础层是不变的,假如A用户做了修改,变得只是A用户操作的部分以增量的方式写入可读写层,
这样就其他用户的基础的只读层还是不变的。只有A自己的镜像发生了可读写层的改变,
A自己维护就好了,大家共享的只读层是不变的。
问题1、而且被whiteout遮挡的文件需要清除,否则镜像就膨胀了。这个需要对镜像做压缩。网上很多方案。
问题2、如果对docker原始镜像进行修改 比如在ubuntu镜像上安装Java 那么修改的是可读写层。提交后变成只读层的最上面一层。原本已有的只读层不会变,并再此基础上新增层, 而不是整个只读层不会变,即commit后就会将读写层的内容合并到只读层的最上层。init层(RO+WH):
他的挂载方式是RO只读和WH隔档,也就是这里的修改是会产生隔档的,但是我们知道隔档是放在读写层的。
它是一个以“-init”结尾的层,夹在只读层和读写层之间。Init 层是 Docker 项目单独生成的一个内部层,
专门用来存放 /etc/hosts、/etc/resolv.conf 等信息。需要这样一层的原因是,
这些文件本来属于只读的镜像的一部分,但是用户往往需要在启动容器时写入一些指定的值比如 hostname,
所以就需要在可读写层对它们进行修改。可是,这些修改往往只对当前的容器有效,
我们并不希望执行 docker commit 时,把这些信息连同可读写层一起提交掉。
所以,Docker 做法是,在修改了这些文件之后,以一个单独的层挂载了出来。
而用户执行 docker commit 只会提交可读写层,所以是不包含这些内容的。
修改只对当前容器生效,镜像提交只有可读写层,没有这一层。换了容器这个修改就废了。
问题1、这一层中的文件的修改到底由谁以及什么时候触发的,如果是在容器启动阶段,修改的结果不是应该放到容器读写层吗?是docker引擎做的,在容器启动之前就做好这个层,和其他层一起挂载好。然后容器才会创建。只读层(RO+WH):
他的挂载方式是RO只读和WH隔档,也就是这里的修改是会产生隔档的,但是我们知道隔档是放在读写层的。
它是这个容器的 rootfs 最下面的五层,对应的正是 镜像的五层。
它们的挂载方式都是只读的(ro+wh,即 readonly+whiteout)。
可以看到,这些层,都以增量的方式分别包含了应用的一部分。
最终,这 7 个层(可读写五层,加上init和只读层)都被联合挂载到 /var/lib/docker/overlay2/mnt 目录下,表现为一个完整的应用供容器使用。
六、总结
Linux 容器文件系统的实现机制,正是我们经常提到的容器镜像,也叫作:rootfs。它只是一个操作系统的所有文件和目录,并不包含内核,最多也就几百兆。
而相比之下,传统虚拟机的镜像大多是一个磁盘的“快照”,磁盘有多大,镜像就至少有多大。通过结合使用 Mount Namespace 和 rootfs,容器就能够为进程构建出一个完善的文件系统隔离环境。当然,这个功能的实现还必须感谢 chroot 和 pivot_root 这两个系统调用切换进程根目录的能力。
而在 rootfs 的基础上,Docker 公司创新性地提出了使用多个增量 rootfs 联合挂载一个完整 rootfs 的方案,这就是容器镜像中“层”的概念。通过“分层镜像”的设计,以 Docker 镜像为核心,来自不同公司、不同团队的技术人员被紧密地联系在了一起。而且,由于容器镜像的操作是增量式的,这样每次镜像拉取、推送的内容,比原本多个完整的操作系统的大小要小得多;而共享层的存在,可以使得所有这些容器镜像需要的总空间,也比每个镜像的总和要小。这样就使得基于容器镜像的团队协作,要比基于动则几个 GB 的虚拟机磁盘镜像的协作要敏捷得多。
更重要的是,一旦这个镜像被发布,那么你在全世界的任何一个地方下载这个镜像,得到的内容都完全一致,可以完全复现这个镜像制作者当初的完整环境。这,就是容器技术“强一致性”的重要体现。
本文有些问题,因为环境切换导致不太正确,但是基本理论的学习本文主要是,实际操作下篇开始。
现在docker新版本存储驱动都是layerfs的overlay2,我看官方文档也没说明怎么切换到aufs,要想切换在启动参数里指定即可,因为我没指定,所以其实是overlay2,导致有些结果不一样。可以参考这篇文章https://blog.csdn.net/u010566813/article/details/117783220
相关文章:

橘子学K8S03之容器的理解
前面我们知道了容器是通过对一个普通的linux进程进行隔离和限制实现的一种特殊视角下的进程表现。而隔离和限制的实现技术分别是"Namespace"和“Cgroups”,在这两种机制的控制下,我们需要知道容器的本质是一种特殊的进程。 我们现在有了这个认知之后&…...

算法第十二天-矩形区域不超过K的最大数值和
矩形区域不超过K的最大数值和 题目要求 解题思路 来自[宫水三叶] 从题面来看显然是一道[二维前缀和]的题目。本题预处理前缀和的复杂度为O(m* n) 搜索所有子矩阵需要枚举[矩形左上角]和[矩形右下角],复杂度是 O ( m 2 ∗ n 2 ) O(m^2 * n^2) O(m2∗n2),…...

【js】js数组对象去重:
文章目录 一、Map()二、对象访问属性的方法三、indexOf()四、双层for循环 let arrObj [{ name: "小红", id: 1 },{ name: "小橙", id: 1 },{ name: "小黄", id: 4 },{ name: "小绿", id: 3 },{ name: "小青", id: 1 },{ na…...

python高校舆情分析系统+可视化+情感分析 舆情分析+Flask框架(源码+文档)✅
毕业设计:2023-2024年计算机专业毕业设计选题汇总(建议收藏) 毕业设计:2023-2024年最新最全计算机专业毕设选题推荐汇总 🍅感兴趣的可以先收藏起来,点赞、关注不迷路,大家在毕设选题ÿ…...

Phaser详解
Phaser是一个相对较新且功能强大的同步原语,它于Java 7中引入,用于协调并行任务的执行。与CyclicBarrier和CountDownLatch等传统的同步工具相比,Phaser提供了更灵活和更高级的功能,特别是在处理动态和可变的并行任务集合时。 1.P…...

2个nodejs进程利用redis 实现订阅发布
1.新建文件 redis_db.js use strict;const redis require(redis); const options {host: "127.0.0.1",port: 6379,password: "123456", // CONFIG SET requirepass "123456" }var array [] for(var i0; i<3; i){const client redis.crea…...

LeetCode——2397. 被列覆盖的最多行数
通过万岁!!! 题目:给你一个二维数组,然后里面是0和1,然后让你从里面选择numSelect列,使得去掉选择的列以后不存在1的行的数量最少。思路: 看到这个题目,本来以为是每一列…...

java通过HttpClient方式实现https请求的工具类(绕过证书验证)
目录 一、引入依赖包二、HttpClient方式实现的https请求工具类三、测试类 一、引入依赖包 引入相关依赖包 <!--lombok用于简化实体类开发--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><option…...

【自学笔记】01Java基础-07面向对象基础-04接口与内部类详解
记录学习Java基础中有关接口类和内部类的知识。 1 接口 interface 关键字用于定义接口类,接口类是一系列方法的声明,一般只有方法的特征没有方法的实现,因此可以被不同的类接入实现,而这些实现可以具有不同的行为(功…...

【cmu15445c++入门】(5)c++中的模板类
一、template模板类 除了模板方法【cmu15445c入门】(4)c中的模板方法 模板也可以用来实现类 二、代码 /*** file templated_classes.cpp* author Abigale Kim (abigalek)* brief Tutorial code for templated classes.*/// Includes std::cout (printing). #include <io…...

MongoDB聚合:$bucket
$bucket将输入文档按照指定的表达式和边界进行分组,每个分组为一个文档,称为“桶”,每个桶都有一个唯一的_id,其值为文件桶的下线。每个桶中至少要包含一个输入文档,也就是没有空桶。 使用 语法 {$bucket: {groupBy…...

从优化设计到智能制造:生成式AI在可持续性3D打印中的潜力和应用
可持续性是现代工业中一个紧迫的问题,包括 3D 打印领域。为了满足环保制造实践日益增长的需求,3D 打印已成为一种有前景的解决方案。然而,要使 3D 打印更具可持续性,还存在一些需要解决的挑战。生成式人工智能作为一股强大的力量&…...

vue3 响应式api中特殊的api
系列文章目录 TypeScript 从入门到进阶专栏 文章目录 系列文章目录一、shallowRef()二、triggerRef()三、customRef()四、shallowReactive()五、shallowReadonly()六、toRaw()七、markRaw()八、effectScope()九、getCurrentScope() 一、shallowRef() shallowRef()是一个新的响…...

【大厂算法面试冲刺班】day2:合并两个有序链表
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 递归 class Solution {public ListNode mergeTwoLists(ListNode l1, ListNode l2) {if (l1 null) {return l2;}else if (l2 null) {return l1;}else if (l1.val < l2.…...

【JaveWeb教程】(19) MySQL数据库开发之 MySQL数据库操作-DML 详细代码示例讲解
目录 3. 数据库操作-DML3.1 增加(insert)3.2 修改(update)3.3 删除(delete)3.4 总结 3. 数据库操作-DML DML英文全称是Data Manipulation Language(数据操作语言),用来对数据库中表的数据记录进行增、删、改操作。 添加数据(INSERT)修改数据…...

Web前端篇——ElementUI之el-scrollbar + el-backtop + el-timeline实现时间轴触底刷新和一键返回页面顶部
ElementUI之el-scrollbar el-backtop el-timeline实现时间轴触底刷新和一键返回页面顶部。 背景:ElementUI的版本(vue.global.js 3.2.36, index.css 2.4.4, index.full.js 2.4.4) 废话不多说,先看动…...

CAS-ABA问题编码实战
多线程情况下演示AtomicStampedReference解决ABA问题 package com.nanjing.gulimall.zhouyimo.test;import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicStampedReference;/*** @author zho…...

Linux 常用进阶指令
我是南城余!阿里云开发者平台专家博士证书获得者! 欢迎关注我的博客!一同成长! 一名从事运维开发的worker,记录分享学习。 专注于AI,运维开发,windows Linux 系统领域的分享! 其他…...

windows通过ssh连接Liunx服务器并实现上传下载文件
连接ssh 输入:ssh空格用户名ip地址,然后按Enter 有可能出现下图提示,输入yes 回车即可 输入 password ,注意密码是不显示的,输入完,再按回车就行了 以上是端口默认22情况下ssh连接,有些公司它…...

【K8S 存储卷】K8S的存储卷+PV/PVC
目录 一、K8S的存储卷 1、概念: 2、挂载的方式: 2.1、emptyDir: 2.2、hostPath: 2.3、NFS共享存储: 二、PV和PVC: 1、概念 2、请求方式 3、静态请求流程图: 4、PV和PVC的生命周期 5、…...

工业智能网关如何保障数据通信安全
工业智能网关是组成工业物联网的重要设备,不仅可以起到数据交换、通信、边缘计算的功能,还可以发挥数据安全保障功能,保障工业物联网稳定、可持续。本篇就为大家简单介绍一下工业智能网关增强和确保数据通信安全的几种措施: 1、软…...

基于Springboot的课程答疑系统(有报告)。Javaee项目,springboot项目。
演示视频: 基于Springboot的课程答疑系统(有报告)。Javaee项目,springboot项目。 项目介绍: 采用M(model)V(view)C(controller)三层体系结构&…...

操作系统 内存相关
0 内存 cpu和内存的关系 内存覆盖 内存的覆盖是一种在程序运行时将部分程序和数据分为固定区和覆盖区的技术。这种技术的主要目的是为了解决程序较大,无法一次性装入内存导致无法运行的问题。 具体来说,内存的覆盖技术将用户空间划分为以下两个部分&…...

【模拟IC学习笔记】 PSS和Pnoise仿真
目录 PSS Engine Beat frequency Number of harmonics Accuracy Defaults Run tranisent?的3种设置 Pnoise type noise Timeaverage sampled(jitter) Edge Crossing Edge Delay Sampled Phase sample Ratio 离散时间网络(开关电容电路)的噪声仿真方法 PSS PSS…...

IPv6邻居发现协议(NDP)---路由发现
IPv6路由发现(前缀公告) 邻居发现 邻居发现协议NDP(Neighbor Discovery Protocol)是IPv6协议体系中一个重要的基础协议。邻居发现协议替代了IPv4的ARP(Address Resolution Protocol)和ICMP路由器发现(Router Discovery),它定义了使用ICMPv6报文实现地址解析,跟踪邻…...

OpenPLC v3 代码结构
OpenPLC v3 是一个基于 C 的开源实时自动化平台,主要用于控制和自动化行业中的设备。该项目具有以下主要模块: 1. Core:核心模块,提供数据结构和算法实现。 2. Master:主设备模块,实现与从设备通信的接口。…...

安全防御之备份恢复技术
随着计算机和网络的不断普及,人们更多的通过网络来传递大量信息。在网络环境下,还有各种各样的病毒感染、系统故障、线路故障等,使得数据信息的安全无法得到保障。由于安全风险的动态性,安全不是绝对的,信息系统不可能…...

条款39:明智而审慎地使用private继承
1.前言 在之前挑款32曾讨论了C如何将public继承视为is-a关系,在那个例子中我们有个继承体系,其中class Student以public形式继承class Person,于是编译器在必要时刻将Student转换为Persons。。现在,我在以原先那个例子࿰…...

【数据库原理】(20)查询优化概述
查询优化是关系数据库系统设计和实现中的核心部分,对提高数据库性能、减少资源消耗、提升用户体验有着重要影响。虽然挑战重重,但凭借坚实的理论基础和先进的技术手段,关系数据库在查询优化方面有着广阔的发展空间。 一.查询中遇到的问题 数…...

FineBI实战项目一(18):每小时上架商品个数分析开发
点击新建组件,创建每小时上架商品个数组件。 选择线图,拖拽cnt(总数)到纵轴,拖拽hourStr到横轴。 修改横轴和纵轴的文字。 调节连线样式。 添加组件到仪表板。...