分类 Linux 下的文章

[IPM] (http://ipm-hpc.sourceforge.net/)(Integrated Performance Monitoring)是用于MPI性能评测的一套软件库,声称可以收集MPI函数运行时间、通信拓扑、通信量统计、能耗统计等等功能。

https://stackoverflow.com/questions/43002936/what-are-the-differences-between-the-mpi-functions-and-pmpi-functions

这个问题解决了我在阅读IPM源码的时候发现的MPI_开头和PMPI_开头的函数的区别和关系的疑惑,同时也解决了我对于IPM运行原理的疑惑。

主要原理就是通过使用加了debug逻辑的IPM库代替原始MPI函数,达到既不影响原有程序执行,又能收集性能数据的目的。

达成目的的方法有两种,一是经典的显示链接,在编译时就指定要使用IPM版的MPI函数实现;二是利用动态库的骚操作,利用系统环境变量“劫持”运行时程序要调用的MPI实现,通过LD_PRELOAD的优先级实现。

起因在于之前使用全键盘进行Linux操作的时候,无意间碰到了Page Up按键,开启了奇妙体验。把一条命令打到一半,然后按Page Up/Page Down就可以匹配历史记录,实在是太舒服了。

然而在使用Ubuntu的时候,突然发现就没有这个功能了,StackOverflow一查,才发现原来是需要手动配置的。

修改/etc/inputrc或者~/.inputrc,这么修改一下,就能把这个功能和Page Up/Page Down按键绑定:

$if mode=emacs

"\e[5~": history-search-backward
"\e[6~": history-search-forward

$endif

https://stackoverflow.com/questions/46667659/kubernetes-cannot-access-nodeport-from-other-machines

本来第一次配置集群的时候,是可以在局域网内访问的,之后关机重启,遇到DiskPressure这个Taint“污点(标记)”的时候,重新配置了一次集群(即kubeadm resetkubeadm init),然后以为是服务没跑起来,测试以后发现只能在本机访问了。

nmap扫了一遍端口,目标端口显示的不是closed,而是filtered,然后也隐隐猜测和防火墙有关,万万没想到,原因正是出在iptables上。而后了解到,firewalldiptables是两个不同的Linux防火墙工具,有着各自独立的规则。因而在配置Kubernetes时禁用了firewalld之后,iptables还是在工作的。而NodePort的访问,需要进行流量转发。

简单粗暴的解决方式(非生产环境):

iptables -A FORWARD -j ACCEPT

不过这个地方我有点没想明白:kube-proxy可以将Pod内的端口映射到主机端口的监听上,而在Linux中,默认的端口监听是监听在所有可用的interface网络接口上的,监听特定的网络接口是需要编程显式声明的,理论上不会需要进行不同网络接口间的流量转发。

这一次历时接近一天的CentOS 8扩容翻车和修复事件,终于让我对之前一直觉得深奥而不愿接触的Linux LVM(Logical Volume Management,逻辑卷管理)分区管理机制有了基本而全面的认识,算是又填上了Linux基本操作在存储管理方面的一个大坑。

LVM采用了一种三层的整体结构,自底向上依次是Physival Volume物理卷Volume Group(物理)卷组Logical Volume逻辑卷。其中物理卷对应传统意义上,在诸如Windows上磁盘管理,或者Linux上GParted中为分区分配的物理空间;卷组和RAID 0十分相似,即在逻辑地址空间中将某些指定的物理卷“融合”起来,形成逻辑意义上的“磁盘”;逻辑卷则和物理卷相似,只不过其是在一个卷组内进行分区空间的指派,最后一个分区对应的就是一个逻辑卷,对逻辑卷进行分区格式化,初始化文件系统就可以使用(当然,前提是系统支持且识别这种LVM分区布局)。

用一个十分有意思的方法来解释就是,物理硬盘加上LVM,会形成一个“螺旋上升”的结构:

物理磁盘(硬盘)->物理分区(物理卷)->逻辑磁盘(卷组)->逻辑分区(逻辑卷)

这决定了建立一个可用的LVM逻辑卷,需要依次进行物理卷、卷组和逻辑卷的创建三个步骤。

可以看到,即使加了LVM,仍然没有逃脱磁盘需要先分区后使用的本质。但是LVM的一个优势在于,上层系统所使用的是“逻辑卷”,而不是“物理卷”,也就是说,此时的上层系统不知道底层的物理数据分布的同时,还可以正常使用(当然,Linux内核是知道数据的物理分布的,毕竟LVM需要在此处实现)。这意味着,LVM可以实现跨磁盘的分区创建和管理;也可以实现分区本身在磁介质上的非连续存储。对于个人用户来说,可能算不上有意义的功能;但是对于企业用户来说,对于可能大到一块磁盘都装不下的单文件来说,这是一种解决方案。换个角度来说,LVM方案能做到的不仅仅是实现一种无RAID情况下超大文件存储的可能,还可以起到简化mount操作的作用。将一组完成同一业务功能的磁盘建立为LVM逻辑卷,可以极大地简化分区挂载/卸在脚本的复杂度,并且增加指令的可读性。

在Linux的LVM实现中,划分了三个指令簇,分别对应LVM三个层次的操作,如下表所示。

功能 PV管理命令 VG管理命令 LV管理命令
s 摘要 pvs vgs lvs
scan 扫描 pvscan vgscan lvscan
create 创建 pvcreate vgcreate lvcreate
display 显示 pvdisplay vgdisplay lvdisplay
remove 移除 pvremove vgremove lvremove
extend 扩展 - vgextend lvextend
reduce 压缩 - vgreduce lvreduce

在某些场景下(比如dracut中),这些指令不会单独存在,需要添加lvm前缀,将指令作为参数使用,如lvm pvscan

在对LVM有了初步的认识之后,进行这次修改的流程介绍:删除LVM卷组内的swap分区,将多出来的空间分配给同一卷组内的系统根分区root

步骤依次如下:

  1. 删除cl卷组中的swap分区:由于swap分区本身就属于缓存的性质,无需进行数据的保存。

    lvremove /dev/cl/swap
  2. 建议先保存数据)扩容根分区:
    有两种方式可以选择,区别在于手动或者自动对于文件系统的大小调整。在本示例中,删除swap分区释放的空间为2GiB。
    手动:
    lvresize -L +2G /dev/cl/root
    xfs_growfs /dev/cl/root

    自动:

    lvresize --resizefs -L +2G /dev/cl/root

需要注意的一点是,xfs只支持分区扩容(ext4支持分区压缩)。如果想要分区压缩的话,只能手动备份数据,重建分区再恢复数据。

这个操作平凡无奇,网上也能找到不少教程,重点是完成操作准备重启开机的时候,问题来了:

[ OK ] Reached target initrd root device.

一看到这个,就知道大事不妙,一定是磁盘配置出了问题。果不其然,等待数分钟后,dracut开头的命令行带着日志文件出现在了我的屏幕上。

仔细阅读日志文件,发现其中提到了“swap分区找不到”的相关消息,而swap分区又是我手动操作进行的删除操作,看来是有哪里的配置残留没有清理干净。折腾了半天dracut重建之后,发现无济于事,后来突然想起来可能与内核参数有关,遂修改/etc/sysconfig/grub文件,将其中与swap分区有关的参数全部删除,重新生成配置文件后,重启。

然后与预期一样的是,系统启动过程恢复了正常。其中有一点很奇怪的地方是,可能是由于我手动重建initramfs镜像的原因,并无法使用升级后的内核启动,而只能使用与安装盘版本一致的初始内核启动成功。于是出现了偷懒的新内核修复方法:

dnf reinstall kernel*-4.18.0-193.14.2.el8_2 

后面的版本信息根据自己的需要进行更改,上方示例中的版本信息是文章撰写时的最新内核信息,可能随着时间推移发生改变。

参考:https://www.cnblogs.com/diantong/p/10554831.html

今天在看acmeair的bash脚本的时候,发现里面有这么一行指令:

sed "s#IMAGE_NAME#${IMAGENAME}#g" ${YAML_FILE} > temp.yaml

当时想了一下,感觉那里不对劲:根据网上的教程来看的话,seds命令的用法不是类似于's/regexp/repl/g'这种格式吗?

然后仔细一想,既然能发布出来的代码,又是来自可信平台(IBM Cloud),肯定是有其原因的,或者说,至少是可以运行的。然后就动手尝试了一下:

echo '1 2' | sed -e 's/ / ^ /g'     #1
echo '1 2' | sed -e 's# # ^ #g'     #2
echo '1 2' | sed -e 's@ @ ^ @g'     #3
echo '1 2' | sed -e 's\ \ ^ \g'     #4
echo '1 2' | sed -e 's啊 啊 ^ 啊g'   #5

首先显而易见的,1是肯定可行的,可以将1 2这个字符串替换为1 ^ 2。意料之外的是,2-4全部可行,都能够正确地完成替换工作。5属于脑洞大开的想法。在发现前面1-4都能够使用任意单字符作为分隔符的话,那么中文字符可以完成相同的功能吗?

答案是否定的。sed给出了如下的错误信息:

sed: -e 表达式 #1, 字符 2: delimiter character is not a single-byte character↵
sed: -e expression #1, char 13: unknown option to `s'

其中第一行是在中文环境下的报错信息,第二行是英文环境。可以看到,在常见的环境下,都是不支持将多字节字符作为分隔符的。毕竟在计算机行业中,非英文语言体系的字符基本都可以视作“异端”,往往不能享受到英文字符的“优待”,需要使用一个以上字节进行信息的储存,所以对于只能使用单字节字符作为分隔符的sed来说自然会产生错误。

(思考题:那为何可以使用sed替换中文文本?) (答案是,只要sed将脚本序列和输入的数据流都视为单字节字符流,就可以使用字符序列替换的方法完成任务了)

实际上,在咕果上,能找到和sed分隔符相关的资料少之又少;有人在Unix论坛上发问了,虽然问题最终由作者自己看书解决,但是他并未分享自己看的是哪本书;StackOverflow上还有老哥说这就是注释,根本不能用的,等等。

直到后来看到了这个:https://backreference.org/2010/02/20/using-different-delimiters-in-sed/

博主说了这么一句:

It's a not-so-known fact that sed can use any character as separator for the "s" command.

真是not-so-known,网络上都没什么热门资料阐述这一点的= =

于是问题最终解决:

sed "s#IMAGE_NAME#${IMAGENAME}#g" ${YAML_FILE} > temp.yaml

等价于

sed "s/IMAGE_NAME/${IMAGENAME}/g" ${YAML_FILE} > temp.yaml

顺便给出上面使用的样例的升级版:(工作必备,除了你没人看得懂,专家职称、升职加薪预定

echo '1 2' | sed -e 's \  \ ^\  g'

附录:对于非ssed指令,仍然可以通过\*...*的方式,使用任意自定义的字符作为正则表达式的分隔符。