架构方面学习笔记(2)-计算机系统
记录看书的一些心得
2022.01.11 add 计算机系统之如何提高 CPU 运行速度
2022.01.19 add 如何提高数组遍历的效率?
2022.03.24 add oom killer
2022.05.30 add 进程间通信
文章目录
操作系统内核
概念作用:
应用连接硬件设备的桥梁,应用程序只需要和内核交互,无需关心硬件细节。
具体作用:
- 进程调度
- 内存管理
- 硬件通信能力
- 提供系统调用,当应用程序需要运行更高的权限的任务时,内核就是应用程序和操作系统之间的接口。
用户态和内核态的区别:
- 用户态:程序使用用户空间(专门给用户程序使用的空间)
- 内核态:程序使用内核空间(只有内核程序可以访问,可以控制 CPU、内存、硬盘等硬件)
缓存
如何写出让 CPU 跑得更快的代码
实际上转化成「如何写出缓存命中率高的代码」
- 针对数据缓存:遍历数据时按照内存布局的顺序操作,因为 CPU cache 是根据 CPU cache line 批量操作数据的
- 针对指令缓存:有规律的写条件分支语句,让 CPU 的分支预测期发挥作用。(TODO 待深入了解)
如何提高数组遍历的效率?
以 js 为例,有很多可以遍历数组的方式如:for loop, for of, for in, forEach
var arr = [1,2,3,4,5]
for(var i=0,len=arr.length;i<len;i++){
console.log(arr[i])
}
无疑,使用临时变量,将长度缓存起来,避免重复获取数组长度,这种方法基本上是所有循环遍历方法中性能最高的一种
其他方式不再赘述
如何保证多核机器的「缓存一致性」?
前置知识:内存的写入和读取,都是经过 CPU 缓存,也就是说将新的内容写入内存之前其实是先写入到缓存中。那么在写入数据又读取的过程中如何保证多核 CPU 缓存的一致性?①写传播 ②事务串行化
基础: 总线嗅探(Bus snooping)即当某个 CPU 核心更新了 cache 中的数据,则将该事件通知到其他核心。
升级:因为基础版实现方式只要在某个 CPU 核心更新了内容就要通知其他核心,这种方式加重了总线负载,但是其不能保证「事务串行化」即在不同核心中能看到相同的数据更新顺序,因此有了MESI 协议,其在 modified 和 exclusive 的状态下不会向其他核心发送广播。
CPU 缓存常遇到的几个问题
CPU Cache 从内存读取数据的单位是 CPU Line,一般 64 位 CPU 的 CPU Line 的大小是 64 个字节。
伪分享:当多个线程同时读写同一个 Cache Line 的不同变量时,会导致 CPU cache 失效,这种现象即为 False Sharing
- 解决方法: 避免将经常需要修改的数据出现在同一个 Cache Line 中
CPU 选择线程
CPU 通常遵循 CFS(Completely Fair Scheduling) 即完全公平调度来选择当前要执行的线程。
内存管理
概念区分:
在多进程环境下,为了使每个进程之间的内存地址不受影响、相互隔离,于是操作系统为每个进程独立分配一套虚拟地址空间。
- 虚拟内存:程序中所使用的内存地址即为虚拟内存地址
- 每个进程都有自己的虚拟地址空间
- 32 位环境下,虚拟地址空间共有 4GB
- 物理内存:实际存在硬盘中的空间地址
虚拟内存的作用
- 第一,虚拟内存可以使得进程对运行内存超过物理内存大小,因为程序运行符合局部性原理,CPU 访问内存会有很明显的重复访问的倾向性,对于那些没有被经常使用到的内存,我们可以把它换出到物理内存之外,比如硬盘上的 swap 区域,即交换空间
- 第二,由于每个进程都有自己的页表,所以每个进程的虚拟内存空间就是相互独立的。进程也没有办法访问其他进程的页表,所以这些页表是私有的,这就解决了多进程之间地址冲突的问题
- 第三,页表里的页表项中除了物理地址之外,还有一些标记属性的比特,比如控制一个页的读写权限,标记该页是否存在等。在内存访问方面,操作系统提供了更好的安全性
tips:
- 通常我们所说的程序占用多少内存指的是物理内存而不是虚拟内存,或者说驻留内存,即通过 top 指令看到的 RES 值,
- VIRT 则是虚拟内存占用的意思
- SHR 是共享内存,不同进程共享使用的物理内存空间,因为其实我们写的程序会依赖于很多外部的动态库(.so),比如 libc.so、libd.so等等。这些动态库在内存中仅仅会保存/映射一份,如果某个进程运行时需要这个动态库,那么动态加载器会将这块内存映到对应进程的虚拟内存空间中。
top -p pid
#
操作系统如何管理虚拟内存和物理内存之间的关系?
-
内存分段
- Linux 系统中有一块从硬盘划分出来的 Swap 空间用于内存和硬盘的交换,来解决内存分段带来的内存碎片问题
-
内存分页
- 针对内存碎片的 Swap 空间反而导致内存交换效率过低,为了解决这个问题,那就是在进行内存交换的时候让需要交换写入或从磁盘装载的数据更少一点,这就是内存分页。
- 把整个虚拟和物理内存空间切成一段段固定尺寸的大小就是分页,在 Linux 下每一页大小约为
4k
- 分页机制下:加载程序时,不需要一次性将程序加载到物理内存中,而是只有在程序运行中,需要用到对应虚拟内存页里面的指令和数据时,在加载到物理内存中。
服务器常说的 4C8G 是什么概念?
4C 指的是 CPU 的核数,8G 指的是 RAM 的数量
-
CPU 内核数量是决定其性能的关键因素:每个 CPU 内核本质上是一个独立的处理单元,可以独立于其他内核执行指令。这意味着服务器拥有的内核越多,它的处理能力就越强。这对于需要大量 CPU 能力的应用程序尤其重要,例如数据库、虚拟化和高性能计算。
-
RAM 数量:RAM 数量决定了在任何给定时间它可以在内存中存储多少数据。RAM 用于临时存储 CPU 正在访问的数据。服务器拥有的 RAM 越多,它可以在内存中存储的数据就越多,这有助于提高性能。这对于需要大量内存的应用程序尤其重要,例如 Web 服务器、文件服务器和数据库服务器。
通常:4 核 8 g 服务器适合中小型企业的预算。8 核 16 g 服务器适合大型企业和高性能计算的应用涉及到的数据和业务。
如何选择:
- 个人博客、小型网站从 1核1G、1核2G 都是可以的;
2、如果是每天访问量过万的网站、业务,请选择 2 核 4 G 或 2 核 8 G 起步。这样访问时不会卡顿,很流畅;
3、十万以上的网站、业务请选择 4 核 8 G 起步。
进程
并发
并发这两个字会很容易让人产生错觉是并行,实则不是,进程并发也是因为在比较短的时间内 CPU 运行了多个进程,从而造成了并行的错觉。
OOM: out of memory 内存溢出,是指应用进程中存在无法回收的内存或使用的内存过多,其它或当前应用进程申请分配内存时系统会优先强制退出当前进程以减轻系统负担。
表现:异常退出当前应用进程(前台闪退或后台系统强制退出当前进程)
OOM killer: Linux 内核有个机制叫OOM killer(Out Of Memory killer),该机制会监控那些占用内存过大,尤其是瞬间占用内存很快的进程,然后防止内存耗尽而自动把该进程杀掉。
进程被 kill -9 了,有一定概率是 OOM 导致的,具体需要排查日志。
进程间通信
实现进程间通信的必要性:
由于每个进程的用户空间独立,不能互相访问,因此需要借助内核空间实现进程间的通信,因为所有进程共享内核空间。
同一主机上实现进程间通信:
- 管道
- 特点:进程写入的数据都是缓存在内核中,另一个进程读取数据也是从内核中获取
- 缺点:效率低,不适合进程间频繁的数据交换
- 消息队列
- 缺点 1:消息队列不适合比较大数据量的传输
- 缺点 2:消息队列通信过程中,存在用户态与内核态之间的数据拷贝开销
- 共享内存
- 缺点:存在进程间的竞争
- 信号量
- 特点:信号量其实是一个整型的计数器,主要用于实现进程间的互斥与同步,而不是用于缓存进程间通信的数据,可以说是规避共享内存缺点的一种方式。
- 信号
- 特点:是异常情况下的工作模式,用「信号」来通知进程
- 特点:进程间通信机制的唯一异步通信机制
Ctrl+C 产生 SIGINT
信号,表示终止该进程
# 查看所有信号
kill -l
注: SIGKILL
和 SIGSTOP
是进程无法忽略和捕捉的。
不同主机上进程间通信:
- socket
僵尸进程与孤儿进程
僵尸进程
任何进程退出后系统都会保留它的状态信息(进程号、退出状态、运行时间等)直到父进程来收集掉状态信息,如果子进程已死但父进程又不收尸那么子进程就会变成僵尸进程。
ps aux | grep Z
危害
系统能够分配的 pid 数量是有限的,能够存储进程状态信息的资源同样是有限的,如果短时间产生大量僵尸进程,这会造成系统资源的浪费甚至导致系统无法创建新的进程。
清理僵尸进程
最快的方式是 kill 父进程,这样僵尸进程将变成孤儿进程进而被 init 进程管理和回收
避免僵尸进程
TODO 实践
- 子进程死后,会发送 SIGCHLD 信号给父进程,只要父进程收到此信号后执行 wait/waitpid 函数为子进程收尸即可,子进程就会顺利从僵死状态变为彻底消失。
- 子进程死后,会发送 SIGCHLD 信号给父进程,只要父进程收到此信号后执行 wait/waitpid 函数为子进程收尸即可,子进程就会顺利从僵死状态变为彻底消失。
- 由于父进程死后,子进程以及僵死进程会成为孤儿进程,从而会被过继给 init 进程,init 进程就会负责清理僵死进程。
- 在建立子进程时,使用 2 次 fork,让所建立的子进程成为父进程的孙子进程,而实际中的子进程则随即推出,和第三条相同,由于孙子进程的父进程已经退出,所以在孙子进程会被自动过继给守护进程,由守护进程负责为该进程回收资源。
孤儿进程
当一个父进程退出,而他有若干子进程仍然在执行,那么,这些子进程就变成了孤儿进程。它们会自动被共同的祖先 – init 进程收养,从而自动完成它们的状态收集工作。孤儿进程没有什么实质的危害
线程
线程池
概念:
线程池(英语:thread pool):一种线程使用模式。
作用:
- 保证计算机内核的充分利用, 线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。
- 防止过分调度,因为线程过多会带来调度开销,进而影响缓存局部性和整体性能。
进程和线程对比
关联:
进程包含一个或多个线程。
相同点:
- 进程和线程都有就绪、运行、阻塞三种基本状态,同时具有三种状态之间的转换关系
不同点:
- 进程是资源(内存、打开的文件等)分配的单位,线程是 CPU 调度的单位
- 进程拥有一个完整的资源平台,而线程只独享必须的一些资源比如寄存器和栈,像地址空间、文件等资源是多个线程间共享的
- 线程相比较于进程能够减少时间、空间开销
线程间通信
同一个进程下的线程之间共享进程的资源,只要是共享变量就可以做到线程间通信,比如全局变量所以对于线程间关注的不是通信方式而是关注多线程竞争共享资源的问题。
多线程是异步吗?
多线程和异步的关系并不能完全画等号,可以理解成多线程是实现异步编程的一种方式。
异步模型有两个关键特点:1. 不阻塞 2. 回调。
多线程则是并发(单核计算机实则为并发)或并行(多核计算机有可能是并行)执行线程。
注意点:
-
对于具有大量 I/O 操作和不同计算的大规模应用程序,使用异步来实现,比如多线程有利于充分利用计算资源,并且能够照顾到非阻塞函数。这也是所有操作系统所采用的线程模型。
-
多线程的使用(滥用)会给系统带来上下文切换的额外负担,并且线程间的共享变量可能造成死锁。因此在使用多线程时需要处理资源竞争、死锁、共享资源等问题。
公有云、私有云和混合云的区别
Alibaba Cloud 公有云、私有云和混合云有什么区别?
- 公有云:无需购买或安装物理服务器,没有服务器运营和维护成本
- 私有云:具有极高级别的云计算解决方案,可以有企业或组织内部的 IT 团队在该组织的防火墙后面进行内部操作,可以视为一种企业云
- 混合云:顾名思义是以上两种“云”的混合版,它通过安全连接(如VPN连接或租用线路)组合一个或多个公有云和私有云环境,从而允许在不同云环境之间共享数据和应用程序。
操作系统和架构
reference:
计算机要想工作,就需要操作系统及其执行的程序和 CPU 以及其他硬件如内存、存储器和网卡交互;
什么是架构:CPU 发挥着操作系统和硬件之间调解的作用,CPU 有一组预定义的操作和计算,称为指令集或 ISA(指令集架构)常见的有 x86 和 ARM 架构。
Linux 操作系统派系
派系 | 阶段 | 代表 |
---|---|---|
deb系 | 桌面版系统 | 比较有代表的是 Ubuntu、Debian、Mint、Kali等 |
rpm系 | 服务器版系统 | 主要指 Redhat、CentOS、Fedora、OpenSUSE等 |
圣教系 | “从零开始”的系统 | 主要指 Arch、Gentoo等 |
阿卡林系 | 追求自由 | 有Slackware |
通常 debian 系的包管理工具是 dpkg, deb 包通常是二进制包;
redhat 以及 centos 系的包管理工具则是 rpm, rpm 包有源码包 .src.rpm 和二进制包(源码编译后则为二进制文件)
而实际操作中不能使用 uname -a 判断是不是 debian 系统来使用 dpkg,可以通过which dpkg
来检查系统是否支持使用 dpkg 的命令然后执行 dpkg 操作或者 rpm 操作。
高可用和高可靠
Reliability 和 Availability 分别对应可靠性和可用性, 这两个概念既有区别也有联系:
- Reliability 定义为一个服务连续无故障运行的时间,无故障运行的时间越长,可靠性就越高。
- Availiability 定义为在足够长的时间里,比如一年的时间里,一个服务可用的时间,服务可用时间越长越好。一般用可服务时间除于总时间算出一个百分比,用百分比作为度量。比如一个服务如果有5个9的可用性,指的就是一年里 99.999% 时间里服务都是可用的。
有两个极端的例子可以很好的说明这两个概念的区别:
- 假想一个服务,可靠性很高,平均来说可以稳定运行10年,但是一旦服务中断,要用一年的时间来恢复,那么它的可用性只有90%。
- 假想另一个服务,可靠性很差,运行10秒就会宕机,但是恢复服务只需要1ms, 那么它的可用性是99.99%
从这两个极端的例子可以看出,提高可用性有两条路:
- 一是提高可靠性,当然影响可靠性的原因有很多,包括硬件,软件,网络,运维等。但是有人做过统计,软件的 bug 是影响可靠性的最主要的因素。并且提高软件质量相较于使用更可靠的硬件也算成本较低的方式了,
- 二是减少恢复时间,一旦出现宕机,如果能在秒级恢复,那对业务影响是很小的。
磁盘与文件系统
磁盘管理的三大步:
-
磁盘分区:
- 提升数据的安全性(一个分区的数据损坏不会影响其他分区的数据)
- 支持安装多个操作系统
- 更好的组织数据
- 节约寻找文件的时间
# 查看分区表 fdisk -l # 查看具体盘的分区表 fdisk -l /dev/sda
-
格式化分区
- 为每种操作系统所设定的文件属性/权限并不相同, 为了存放这些文件所需的数据,因此就需要将分区槽进行格式化,以成为操作系统能够利用的文件系统格式(filesystem)
-
磁盘挂载
- 将一个存储设备挂到一个已存在的目录上,访问这个目录就是访问该存储设备。
- 文件系统挂载时有覆盖(/遮盖)关系,如果你所要挂载的挂载点(/目录)下面有文件或已挂载的文件系统,那么新挂载的文件系统会遮盖其下面的内容(因此根目录已经是挂载点了,/data00 若被挂载为其他新盘,那么 /data00 下的数据就会被新盘数据给覆盖掉)
一些问题:
Q:假设有一个磁盘分区,磁盘上有数据,怎么让 linux 系统访问这些数据呢?
- 在这块磁盘分区上创建 linux 支持的文件系统
Q:假设磁盘分区有 linux 支持的文件系统,linux 该如何读取它呢?
- 把磁盘挂载在某个目录下,linux 系统就能够进入磁盘分区
因此磁盘分区,文件系统,挂载点之间的关系是:
文件系统和磁盘分区存在一一对应的关系,磁盘分区之后的格式化操作就是创建文件系统,挂载点是进入文件系统或者说磁盘分区的入口。
# list block 查看磁盘分区情况
lsblk -p
- 该机器有两块磁盘,vda vdb
- vda 有一个分区 vda1
# disk free 查看文件系统信息
df -h
/usr/bin 下面的都是系统预装的可执行程序,会随着系统升级而改变。
/usr/local/bin 目录是给用户放置自己的可执行程序的地方,推荐放在这里,不会被系统升级而覆盖同名文件。
tips: usr unix system resource
通常可以通过 ll /usr/local/bin 看到当前机器上的可执行程序
Linux 下的中断
什么是中断
由硬件或软件发送的一种称为 interrupt request IRQ 中断请求的信号。一旦 CPU 接收了中断请求,CPU 就会暂时停止执行正在运行的程序,并且调用一个称为中断处理器或中断服务程序(interrupt service routine)的特定程序。
信息存储位置
在linux的机器上,/proc/interrupts
这个文件(基本都是硬中断)包含有关于哪些中断正在使用和每个处理器各被中断了多少次的信息。
# cat /proc/interrupts
CPU0 CPU1 CPU2 CPU3
0: 3710374484 0 0 0 IO-APIC-edge timer
1: 20 0 0 0 IO-APIC-edge i8042
6: 5 0 0 0 IO-APIC-edge floppy
7: 0 0 0 0 IO-APIC-edge parport0
8: 0 0 0 0 IO-APIC-edge rtc
9: 0 0 0 0 IO-APIC-level acpi
12: 240 0 0 0 IO-APIC-edge i8042
14: 11200026 0 0 0 IO-APIC-edge ide0
51: 61281329 0 0 0 IO-APIC-level ioc0
59: 1 0 0 0 IO-APIC-level vmci
67: 19386473 0 0 0 IO-APIC-level eth0
75: 94595340 0 0 0 IO-APIC-level eth1
NMI: 0 0 0 0
LOC: 3737150067 3737142382 3737145101 3737144204
ERR: 0
MIS: 0
中断分类
日志
日志轮转
什么是日志轮转
日志轮转也叫日志的切割,即对日志文件大小的控制
怎么做日志轮转
linux 中 logrotate 负责对系统日志轮转,通过定时任务每天执行一次,主流 linux 发行版本上都默认装有 logrotate 包。
# 主配置文件
/etc/logrotate.conf
日志文件
linux 下系统日志主要存放在 /var/log 目录下,
- /var/log/messages:这个文件包含了系统各种服务的日志信息,可以通过 tail 命令来实时检查日志的变化,如
tail -f /var/log/messages
- /var/log/syslog:这个文件主要是记录系统的运行信息,比如内存映像文件的反转、系统守护进程的信息等等。
- /var/log/auth.log:这个日志记录的是用户登录和身份验证信息,可以查看谁登录了系统,以及登录操作是否成功等等。
- /var/log/dmesg:这个文件记录的是系统启动时的信息,比如硬件检测、驱动加载等等。
- /var/log/kern.log:这个文件记录了内核的信息,包括内核错误、警告信息以及调试信息等等。
- /var/log/cron.log:这个文件记录了定时任务的执行情况,可以查看定时任务是否执行成功等等。
- /var/log/lastlog:这个文件记录了所有用户最后一次登录的时间和信息。
- /var/log/secure 系统登录日志
- /var/log/cron 定时任务日志
- /var/log/maillog 邮件日志
- /var/log/boot.log 系统启动日志
通常如果想查看系统日志中的某些报错内容,可以通过 cat /var/log/* | grep “key words” 进行查找
cat /var/log/* | grep -i "out of memory"
linux crond
是什么
crond 是 linux 拿来定期执行命令或指定程序任务的一种服务。
linux 下的任务调度主要有两类:系统任务调度和用户任务调度
系统任务调度:系统周期性所要执行的工作,比如写缓存数据到硬盘、日志清理等。在 /etc 目录下有一个crontab文件,这个就是系统任务调度的配置文件。less /etc/crontab
用户任务调度:用户定期要执行的工作,比如用户数据备份、定时邮件提醒等。用户可以使用 crontab 工具来定制自己的计划任务。所有用户定义的crontab 文件都被保存在 /var/spool/cron
目录中。其文件名与用户名一致。
网络相关
# tcp 连接数
sudo netstat -nta|grep ESTABLISHED|wc -l
sudo lsof -i TCP | grep ESTABLISHED
# udp 连接数
sudo netstat -nua|grep ESTABLISHED|wc -l
# udp 连接查看
sudo lsof -i udp
文件系统
文件句柄
文件句柄(file handle)是 windows 系统的叫法
文件描述符(file descriptor)是 Linux 系统的叫法,两者概念一致
概念
本质是一个索引值:当打开一个文件时,内核向进程返回一个文件描述符用来标识该文件吗,并在后续的 read write 操作中都会用到,完成任务后再通过调用系统函数来关闭该文件。
# 获取 telegraf 进程信息
ps aux | grep telegraf
# 直接获取 pid
pgrep telegraf
# 获取指定 pid 的资源限制
vim /proc/${pid}/limits
# 或者直接看某个资源限制比如:open file
prlimit --nofile --pid ${pid}
lsof -p $pid
资源软限制:用户可更改,超过软限制则会导致 too many open files
报错
资源硬限制:superuser 可更改
注:
每建立一个 TCP 连接即占用一个文件操作符,即 socket 占用 fd,socket 本质是一个接口是介于用户进程与TCP/IP 协议之间的中间人,完成 TCP/IP 协议的书写。
在实际使用中,systemctl status telegraf 处于运行之中,但不打日志也不上报数据,首先应该排查过往日志,发现有大量 too many open files,这就是根因,导致日志输出和压缩受限,同时和 influxdb 建立连接也需要 fd,导致数据无法上报。
inotify
inotify 即 inode notify 是一个 linux 内核子系统,可以监控文件系统的变更并将这些变更报告给应用。它可以被用来实现自动更新文件、重载配置文件、日志变更、备份、同步以及上传等能力。
关于 inotify 资源耗尽
通常 inotify 资源耗尽后会报这个错:tail: inotify cannot be used, reverting to polling: Too many open files,通常可以快速通过修改资源限制的方式解决,但需要排查是否存在应用 inotify 资源泄露的问题。
# 快速解决方式:修改 inotify 资源限制
vim /etc/sysctl.conf
fs.inotify.max_user_instances=1048576
fs.inotify.max_user_watches=1048576
sysctl -p
其他:在实际使用过程中,当 inotify 使用过多时会导致程序占用内存量增大,具体情况需要再观察
systemd
systemd 可以管理所有系统资源。
概念
systemd 是 linux 操作系统一系列系统组件的软件套件,它提供了 pid=1 的进程作为系统和服务管理器来启动系统其他部分,旨在统一不同 linux 发行版本间的服务配置和行为。
systemctl 是 systemd 的控制命令来管理系统和服务。
特点
- 使用 cgroup 跟踪和管理进程的生命周期
在 Systemd 之间的主流应用管理服务都是使用 进程树 来跟踪应用的继承关系的,而进程的父子关系很容易通过 两次 fork 的方法脱离。使用 pid 跟踪进程的话就会遇到这种问题,而 Systemd 则提供通过 CGroup 跟踪进程关系,引补了这个缺漏。通过 CGroup 不仅能够实现服务之间访问隔离,限制特定应用程序对系统资源的访问配额,还能更精确地管理服务的生命周期。
注:control groups 是Linux内核提供的一种可以限制单个进程或者多个进程所使用资源的机制,可以对 cpu,内存等资源实现精细化的控制,目前越来越火的轻量级容器 Docker 就使用了 cgroups 提供的资源限制能力来完成cpu,内存等部分的资源控制。
service
只有那些由 systemd 启动的服务进程比如 systemctl 启动才受 system unit 管理单元的监控和管理
Systemd Service 是 systemd 提供的用于管理服务启动、停止和相关操作的功能,它极大的简化了服务管理的配置过程,用户只需要在 .service 配置文件中配置几项指令即可。
- 配置文件存放位置:
/usr/lib/systemd/system
目录,也可能在/etc/systemd/system
目录。找到配置文件以后,使用文本编辑器打开即可。或使用systemctl status telegraf.service
的时候会提示 service 文件目录
Restart
Auto-restart a crashed service in systemd
当在 service 中配置了 Restart=on-failure
时服务若崩溃会根据 RestartSec
的 interval 来重启服务,而配置成 on-abort
时则会仅仅在进程因未捕捉的信号退出时才重启,This means a signal other than SIGHUP, SIGINT, SIGTERM or SIGPIPE
查看 systemctl status yourdaemon
可以看到 Active 中有 activating (auto-restart) 字样,interval 后会自动重启。
exit code
具体可以参考https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#Process%20Exit%20Codes
如果是 code=exited status=0/success
则是手动 stop 掉的,其他信号需要关注日志。
cgroup
是什么
Cgroup 即 control group 是一个 linux 内核机制,提供了对一组进程的资源(如 cpu 内存)限制。
什么应用
对 CPU、内存等资源实现精细化的控制,docker 以及 k8s 中的 pod 就是用了 cgroups 提供的资源限制能力完成对 CPU、内存等部分的资源控制
比如在一个既部署了前端 web 服务,也部署了后端计算模块的八核服务器上,可以使用 cgroups 限制 web server 仅可以使用其中的六个核,把剩下的两个核留给后端计算模块。
bash
你明白 shell、bash 和 zsh 等词的真正含义吗?
shell:
- 一种应用程序,提供图形化界面,用户可以通过这个界面访问操作系统服务,可以是命令行(狭义)也可以是 GUI(广义)
- 一种程序设计语言、命令语言,可以写 shell script 即 shell 脚本
bash VS sh VS zsh VS cmd:
- bash
- 一种特定的 shell 类型
- 大多数 linux 系统默认的 shell 就是 bash
- sh
- sh 就是开启了 POSIX 标准的 bash,sh 脚本发生错误后不再向下执行,bash 脚本则会一直向下执行
- zsh 能基本完美兼容 bash 的命令,并且支持自动补全等能力
- windows 下的 shell 就是 cmd,最新的 Microsoft shell 是 powershell
# 执行一个 shell 脚本
bash a.sh
# -c 后的内容会被当做命令来执行
bash -c "command"
$PATH
在 macOS(以及其他 Unix 和 Linux 系统)中,$PATH
是一个环境变量,它定义了系统查找可执行程序的路径列表。
作用
- 查找可执行文件:当你在终端中输入一个命令(如
ls
,echo
,python
等),shell 会根据$PATH
变量中定义的目录顺序,逐一查找该命令对应的可执行文件。 - 命令简化:通过包含常用可执行程序的目录在
$PATH
中,可以免去输入命令的完整路径的麻烦。
# 你可以在终端中输入以下命令来查看当前的 `$PATH` 环境变量:
echo $PATH
# 将新的路径添加到现有的 `$PATH` 环境变量中,并使其在当前会话和所有子进程中可用
export PATH