Bean Li 2022-06-25T08:17:11+00:00 beanli.coder@gmail.com 查看NTP的状态 2022-06-26T10:29:00+00:00 Bean Li http://bean-li.github.io/NTP 如何查看当前当前NTP状态

ntpstat

>> NODE: 20.20.20.222 <<
synchronised to local net at stratum 11
   time correct to within 10 ms
   polling server every 16 s

>> NODE: 20.20.20.223 <<
synchronised to NTP server (20.20.20.222) at stratum 12
   time correct to within 12 ms
   polling server every 16 s
   
>> NODE: 20.20.20.224 <<
synchronised to NTP server (20.20.20.222) at stratum 12
   time correct to within 11 ms
   polling server every 16 s

>> NODE: 20.20.20.226 <<
synchronised to NTP server (20.20.20.222) at stratum 12
   time correct to within 12 ms
   polling server every 16 s

>> NODE: 20.20.20.227 <<
synchronised to NTP server (20.20.20.222) at stratum 12
   time correct to within 12 ms
   polling server every 16 s

首先第一行NTP Server反应了当前机器的NTP Server IP。 第二行反应了时间的偏差。 第三行表示同步的时间频率。

root@n82-2:~# cat /etc/ntp.conf
...
server 20.20.20.222 burst iburst minpoll 4 maxpoll 4
...

为什么是每16秒查询一次? poll 的含义是how frequently to query server (in seconds), 4的含义是2的4次方,即每16秒查询一次。

除了正常的上述情况外,还有:

>> NODE: 20.20.20.222 <<
unsynchronised
   polling server every 8 s

>> NODE: 20.20.20.223 <<
unsynchronised
   polling server every 8 s

>> NODE: 20.20.20.224 <<
unsynchronised
   polling server every 8 s

上述情况出现在,刚刚重启ntpd,尚未同步的阶段。

ntpq -p

root@n82-1:/var/log# ntpq -pn
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
 20.20.20.224    20.20.20.222    12 s   13   16  376    0.142   -0.010   0.202
 20.20.20.226    20.20.20.222    12 s    1   16  377    0.114   -0.003   0.076
 20.20.20.227    20.20.20.222    12 s    1   16  377    0.150   -0.021   0.020
 20.20.20.223    20.20.20.222    12 s    4   16  377    0.136   -0.013  18.163
*127.127.1.0     .LOCL.          10 l   10   16  377    0.000    0.000   0.000
root@n82-1:/var/log#

remote和refid,表明的本机器的远端NTP Server和该远端Server的上级 NTP Server

remote and refid : remote NTP server, and its NTP server

按照我们的NTP部署,如果没有外部的NTP服务器,我们会选择 ceph-mon leader节点,作为内部集群的NTP Server。对于我们本集群而言:

root@n82-1:/var/log# ceph mon dump
dumped monmap epoch 5
epoch 5
fsid bd489dd6-57c1-4878-a279-739624997f24
last_changed 2022-06-09 15:48:42.559018
created 2022-06-09 15:47:51.033044
0: 20.20.20.222:6789/0 mon.mvdfp
1: 20.20.20.223:6789/0 mon.fciae
2: 20.20.20.224:6789/0 mon.vmlcw
3: 20.20.20.226:6789/0 mon.qcdnb
4: 20.20.20.227:6789/0 mon.abtdv

20.20.20.222节点是IP最小的ceph-mon,正常情况下,整个集群的NTP Server 20.20.20.222。

可是,为什么在20.20.20.222节点上,执行ntpq -pn指令,remote这一列,会列出来其他存储节点的IP?

这就不得不提 peer参数了。

peer 20.20.20.224 burst iburst minpoll 4 maxpoll 4

peer中出现的IP和 server 指定的IP,都出现在ntpq -pn的remote列,why?这两者有什么区别?

ntpd service requests the time from another server
ntpd service exchanges the time with a fellow peer

NTP Server 是有层级的概念的,即配置文件中的:

server 127.127.1.0 burst iburst minpoll 4 maxpoll 4
fudge 127.127.1.0 stratum 10

stratum 这个值越低,表示越权威。127.127.1.0 表示local本机作为NTP Server,层级一般定为10。 我们看一个集群内的普通节点:

root@n82-2:~# ntpq -pn
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
+20.20.20.224    20.20.20.222    12 s    8   16  376    0.163   -0.008   0.562
+20.20.20.226    20.20.20.222    12 s    7   16  377    0.172    0.046   0.074
+20.20.20.227    20.20.20.222    12 s    8   16  377    0.144    0.006   0.167
+20.20.20.222    LOCAL(0)        11 s    1   16  377    0.104   -0.018   0.122
*20.20.20.222    LOCAL(0)        11 u    6   16  377    0.090    0.014   0.584

可以看到20.20.20.222 stratum 层级为11 ,而 出现在peer中的,层级为 12 。

下面介绍下ntpq 各个字段的含义: poll: 这一行,表示周期,即查询周期,前面介绍了 minpoll 4 maxpoll 4 即16秒查询一次。 when: 这一行表示,距离上一次查询的时间。 reach:这个是个8进制的表示:

*	377 = 0b1111111, 表示最近8次查询都成功了
*   376 = 0b11111110 除了最近一次查询失败外,其他7次查询都成功了。
*   257 = 0b10101111 表示,最近的4次都成功了,以最近一次为开始算起,第五次和第七次查询失败了

dalay: network round trip time (in milliseconds) 这个是估算的和对应NTP Server(或者peer)之间的网络延迟。因为是虚拟机,所以延迟是0.1ms以上。 offset: 本机与remote NTP Server (or peer)的时间差异,我看文档已里面写的单位是ms,但是我自己判断单位是秒。 jitter: 这个是抖动的含义,比较高的抖动,表示要么是remote Server不够稳定精准,或者是网络条件太差。

  • jitter: difference of successive time values from server (high jitter could be due to an unstable clock or, more likely, poor network performance)

如何校验某个NTP Server是否可用

我们可以通过ntpdate -d指令来校验,他用来诊断,但是并不会更改本地的时间。

       -d     Enable  the  debugging  mode,  in which ntpdate will go through all the steps, but not adjust the local clock. Information useful for general debugging will also be printed.

如果NTP Server网络可达,并且可以响应我们的查询,输入如下:

root@n82-1:/home/btadmin# ntpdate -d 20.20.20.223
25 Jun 15:24:50 ntpdate[919323]: ntpdate 4.2.8p4@1.3265-o Tue Jan  7 15:08:24 UTC 2020 (1)
Looking for host 20.20.20.223 and service ntp
host found : 20.20.20.223
transmit(20.20.20.223)
receive(20.20.20.223)
transmit(20.20.20.223)
receive(20.20.20.223)
transmit(20.20.20.223)
receive(20.20.20.223)
transmit(20.20.20.223)
receive(20.20.20.223)
server 20.20.20.223, port 123
stratum 11, precision -24, leap 00, trust 000
refid [20.20.20.223], delay 0.02576, dispersion 0.00005
transmitted 4, in filter 4
reference time:    e66136bf.6e4bc565  Sat, Jun 25 2022 15:24:47.430
originate timestamp: e66136c9.1d79f7d3  Sat, Jun 25 2022 15:24:57.115
transmit timestamp:  e66136c9.1d70de0a  Sat, Jun 25 2022 15:24:57.115
filter delay:  0.02602  0.02638  0.02591  0.02576
         0.00000  0.00000  0.00000  0.00000
filter offset: -0.00006 -0.00026 0.000019 -0.00001
         0.000000 0.000000 0.000000 0.000000
delay 0.02576, dispersion 0.00005
offset -0.000011

25 Jun 15:24:57 ntpdate[919323]: adjust time server 20.20.20.223 offset -0.000011 sec
root@n82-1:/home/btadmin# echo $?
0

如果网络不可达,或者不能响应查询的请求:

root@n82-1:/home/btadmin# ntpdate -d 20.20.20.222
25 Jun 15:28:20 ntpdate[931881]: ntpdate 4.2.8p4@1.3265-o Tue Jan  7 15:08:24 UTC 2020 (1)
Looking for host 20.20.20.222 and service ntp
host found : 20.20.20.222
transmit(20.20.20.222)
transmit(20.20.20.222)
transmit(20.20.20.222)
transmit(20.20.20.222)
transmit(20.20.20.222)
20.20.20.222: Server dropped: no data
server 20.20.20.222, port 123
stratum 0, precision 0, leap 00, trust 000
refid [20.20.20.222], delay 0.00000, dispersion 64.00000
transmitted 4, in filter 4
reference time:    00000000.00000000  Thu, Feb  7 2036 14:28:16.000
originate timestamp: 00000000.00000000  Thu, Feb  7 2036 14:28:16.000
transmit timestamp:  e661379f.36a98426  Sat, Jun 25 2022 15:28:31.213
filter delay:  0.00000  0.00000  0.00000  0.00000
         0.00000  0.00000  0.00000  0.00000
filter offset: 0.000000 0.000000 0.000000 0.000000
         0.000000 0.000000 0.000000 0.000000
delay 0.00000, dispersion 64.00000
offset 0.000000

25 Jun 15:28:33 ntpdate[931881]: no server suitable for synchronization found
root@n82-1:/home/btadmin# echo $?
1

NTP和hwclock

最后一个话题就是NTP 与hardware clock了。硬件时钟和系统时钟到底啥关系,NTP会在其中发挥什么样的影响。

Linux层面有两个时钟:

  • system clock
  • hardware clock

hwclock manual中,有如下一段话:

Automatic Hardware Clock Synchronization by the Kernel
       You should be aware of another way that the Hardware Clock is kept synchronized in some systems.  The Linux kernel has a mode wherein it copies  the System  Time  to  the  Hardware Clock every 11 minutes. This mode is a compile time option, so not all kernels will have this capability.  This is a good mode to use when you are using something sophisticated like NTP to keep your System Clock synchronized. (NTP is a way to keep your System  Time synchronized either to a time server somewhere on the network or to a radio clock hooked up to your system.  See RFC 1305.)

       If the kernel is compiled with the '11 minute mode' option it will be active when the kernel's clock discipline is in a synchronized state.  When in this state, bit 6 (the bit that is set in the mask 0x0040) of the kernel's time_status variable is unset. This value is output as the 'status'  line of the adjtimex --print or ntptime commands.

       It  takes  an  outside influence, like the NTP daemon ntpd(1), to put the kernel's clock discipline into a synchronized state, and therefore turn on  '11 minute mode'.  It can be turned off by running anything that sets the System Clock the old fashioned way, including hwclock --hctosys.  However, if the NTP daemon is still running, it will turn '11 minute mode' back on again the next time it synchronizes the System Clock.

       If  your  system runs with '11 minute mode' on, it may need to use either --hctosys or --systz in a startup script, especially if the Hardware Clock is configured to use the local timescale. Unless the kernel is informed of what timescale the Hardware Clock is using, it may clobber  it  with  the wrong one. The kernel uses UTC by default.

       The  first  userspace  command  to  set  the  System  Clock  informs  the  kernel  what timescale the Hardware Clock is using.  This happens via the persistent_clock_is_local kernel variable.  If --hctosys or --systz is the first, it will set this variable according to the  adjtime  file  or  the appropriate command-line argument.  Note that when using this capability and the Hardware Clock timescale configuration is changed, then a reboot is required to notify the kernel.

大意是说,如果设置了NTP Server,内核每11分钟会调整硬件时钟,使其向系统时钟看起, 这被成为 11 miniute mode。看不看起,也是有条件的。

内核中有两个相关的配置选项:

  • CONFIG_GENERIC_CMOS_UPDATE
  • CONFIG_RTC_SYSTOHC

如此外,也要关注NTP的状态,我们可以通过timedatectl查看NTP SYNC 状态:

root@SEG-248-82:/home/btadmin# timedatectl
      Local time: Sat 2022-06-25 16:07:59 HKT
  Universal time: Sat 2022-06-25 08:07:59 UTC
        RTC time: Sat 2022-06-25 08:08:00
       Time zone: Asia/Hong_Kong (HKT, +0800)
 Network time on: yes
NTP synchronized: yes
 RTC in local TZ: no

如果ntp同步时间有异常,硬件时钟向系统时钟的同步也会受到影响。

]]>
systemd tmpfiles相关的服务 2022-03-18T10:29:00+00:00 Bean Li http://bean-li.github.io/systemd-tmpfiles 前言

前些日子在排查一个httpd session的问题,发现虚机尽管重启了,但是Firefox浏览器并不logout,机器重启后,Firefox的发送的请求,httpd后台依然会处理。

一般来讲,httpd请求会为每一个client维护一个session,session相关的信息存放位置

  • CentOS:/tmp/systemd-private-5257097ec71448b0aac566695b533a84-httpd.service-dMlTTI/sessions 这种类似的目录
CentOS 版本:
---------------
[root@node-a tmp]# tree systemd-private-5257097ec71448b0aac566695b533a84-httpd.service-dMlTTI
systemd-private-5257097ec71448b0aac566695b533a84-httpd.service-dMlTTI
└── tmp
    └── sessions
        └── 6d474c39c1606792c92f72973c0f135dc07b6682
2 directories, 1 file

注意为什么CentOS版本的session存放在一个systemd-priviate-开头的奇怪目录下。原因是写在httpd的systemd启动脚本中:

[root@node-a system]# cat httpd.service 
[Unit]
Description=The Apache HTTP Server
After=network.target remote-fs.target nss-lookup.target
Documentation=man:httpd(8)
Documentation=man:apachectl(8)

[Service]
Type=notify
EnvironmentFile=/etc/sysconfig/httpd
ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND
ExecReload=/usr/sbin/httpd $OPTIONS -k graceful
ExecStop=/bin/kill -WINCH ${MAINPID}
# We want systemd to give httpd some time to finish gracefully, but still want
# it to kill httpd after TimeoutStopSec if something went wrong during the
# graceful stop. Normally, Systemd sends SIGTERM signal right after the
# ExecStop, which would kill httpd. We are sending useless SIGCONT here to give
# httpd time to finish.
KillSignal=SIGCONT
PrivateTmp=true

[Install]
WantedBy=multi-user.target

注意上面的PrivateTmp=true,这个选项是一个systemd选项,表示该服务会有一个独立的/tmp目录作为自己的/tmp目录,对于httpd而言:

drwx------  3 root root    4096 Mar 18 13:22 systemd-private-5257097ec71448b0aac566695b533a84-httpd.service-dMlTTI
drwx------  3 root root    4096 Mar 18 12:44 systemd-private-5257097ec71448b0aac566695b533a84-ntpd.service-YDlnOF

很多服务都有类似的行为,比如上面的ntpd的service,毫不意外,ntpd的service脚本中也有:

[Unit]
Description=Network Time Service
After=syslog.target ntpdate.service sntp.service

[Service]
Type=forking
EnvironmentFile=-/etc/sysconfig/ntpd
ExecStart=/usr/sbin/ntpd -u ntp:ntp $OPTIONS
PrivateTmp=true

[Install]
WantedBy=multi-user.target

很奇怪的现象是,CentOS的session文件,有以下行为模式:

  • reboot -f时,sessoin并不会被清理 。reboot -f,然后重建集群,发现很多很奇怪的请求到来,并且被后端正常处理。
  • reboot的时候,本次的session文件会被清理,但是历史垃圾的session信息不会被清理。

systemd-tmpfiles 相关的服务

Linux操作系统,会有一些临时存放文件的区域,最典型的就应该是/tmp/目录下,该目录存放的文件,一般为临时存放区,不重要,可损失的文件,正式因为这个区域不那么严肃,所以很多进程或者人,会堆放一些文件在该目录下,如果没有任何服务负责管理,很可能会累积非常多的垃圾文件。

Linux的systemd提供了tmpfiles相关的服务:

[root@node-a system]# systemctl status systemd-tmpfiles-*
● systemd-tmpfiles-clean.service - Cleanup of Temporary Directories
   Loaded: loaded (/usr/lib/systemd/system/systemd-tmpfiles-clean.service; static; vendor preset: disabled)
   Active: inactive (dead) since Fri 2022-03-18 13:00:01 CST; 1h 14min ago
     Docs: man:tmpfiles.d(5)
           man:systemd-tmpfiles(8)
  Process: 12340 ExecStart=/usr/bin/systemd-tmpfiles --clean (code=exited, status=0/SUCCESS)
 Main PID: 12340 (code=exited, status=0/SUCCESS)

Mar 18 13:00:01 node-a systemd[1]: Starting Cleanup of Temporary Directories...
Mar 18 13:00:01 node-a systemd[1]: Started Cleanup of Temporary Directories.

● systemd-tmpfiles-clean.timer - Daily Cleanup of Temporary Directories
   Loaded: loaded (/usr/lib/systemd/system/systemd-tmpfiles-clean.timer; static; vendor preset: disabled)
   Active: active (waiting) since Fri 2022-03-18 12:44:40 CST; 1h 29min ago
     Docs: man:tmpfiles.d(5)
           man:systemd-tmpfiles(8)

Mar 18 12:44:40 node-a systemd[1]: Started Daily Cleanup of Temporary Directories.

● systemd-tmpfiles-setup-dev.service - Create Static Device Nodes in /dev
   Loaded: loaded (/usr/lib/systemd/system/systemd-tmpfiles-setup-dev.service; static; vendor preset: disabled)
   Active: active (exited) since Fri 2022-03-18 12:44:35 CST; 1h 29min ago
     Docs: man:tmpfiles.d(5)
           man:systemd-tmpfiles(8)
  Process: 556 ExecStart=/usr/bin/systemd-tmpfiles --prefix=/dev --create --boot (code=exited, status=0/SUCCESS)
 Main PID: 556 (code=exited, status=0/SUCCESS)
   CGroup: /system.slice/systemd-tmpfiles-setup-dev.service

Mar 18 12:44:35 node-a systemd[1]: Starting Create Static Device Nodes in /dev...
Mar 18 12:44:35 node-a systemd[1]: Started Create Static Device Nodes in /dev.

● systemd-tmpfiles-setup.service - Create Volatile Files and Directories
   Loaded: loaded (/usr/lib/systemd/system/systemd-tmpfiles-setup.service; static; vendor preset: disabled)
   Active: active (exited) since Fri 2022-03-18 12:44:38 CST; 1h 29min ago
     Docs: man:tmpfiles.d(5)
           man:systemd-tmpfiles(8)
  Process: 805 ExecStart=/usr/bin/systemd-tmpfiles --create --remove --boot --exclude-prefix=/dev (code=exited, status=0/SUCCESS)
 Main PID: 805 (code=exited, status=0/SUCCESS)
   CGroup: /system.slice/systemd-tmpfiles-setup.service

Mar 18 12:44:38 node-a systemd[1]: Starting Create Volatile Files and Directories...
Mar 18 12:44:38 node-a systemd[1]: Started Create Volatile Files and Directories.
[root@node-a system]# vim systemd-tmpfiles-clean.service 

清理工作一般分成两类:

  • 开机启动时的清理
    • systemd-tmpfiles-setup.service
    • systemd-tmpfiles-setup-dev.service
  • Linux正常运行期间的清理
    • systemd-tmpfiles-clean.timer

开机清理,这个是比较容易理解,开机的时候,可能所有服务都没有启动,上一轮机器运行阶段,可能产生了不少垃圾文件,或者没来得及清理的文件(比如异常掉电或者reboot -f),需要对具体的目录做一些清理动作。

另外一个就是长时间运行状态下,也要有服务负责清理,因为Linux服务器一般不喜欢关机,我们也有很多机器线上运行时间1000天以上,完全指望开机清理,可能势必垃圾文件堆积成山。

我们一起看下sytemd-tmpfiles-setup.service配置文件的内容:

[Unit]
Description=Create Volatile Files and Directories
Documentation=man:tmpfiles.d(5) man:systemd-tmpfiles(8)
DefaultDependencies=no
Conflicts=shutdown.target
After=systemd-readahead-collect.service systemd-readahead-replay.service local-fs.target systemd-sysusers.service
Before=sysinit.target shutdown.target
RefuseManualStop=yes

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/systemd-tmpfiles --create --remove --boot --exclude-prefix=/dev

该文件可以看到,主要是调用一个名称为/usr/bin/systemd-tmpfiles的可执行文件,传了一些参数。sytemd-tmpfiles有一些参数值得我们注意:

  • create:

    • If this option is passed, all files and directories marked with f, F, w, d, D, v, p, L, c, b, m in the configuration files are created
                 or written to. Files and directories marked with z, Z, t, T, a, and A have their ownership, access mode and security labels set.
      
  • remove

    • If this option is passed, the contents of directories marked with D or R, and files or directories themselves marked with r or R are removed.
      
  • clean

    • If this option is passed, all files and directories with an age parameter configured will be cleaned up.
      
  • boot

    • Also execute lines with an exclamation mark. (带感叹号的行, --boot才会执行)
      

boot最好理解,正常运行期间和重启刚开机是又分别的,有些目录,开机阶段可以粗暴删除,但是正常运行期间不能太粗暴,因为你可能没有办法确定,该文件或者目录是否还在被使用。因此后面配置文件会有区分的手段,剧透一下就是 action后面加感叹号,就是只有boot阶段才应该执行,正常运行期间,本条配置可以忽略。

systemd-tmpfiles 的可配置性

我们讲了很多了,但是到底如何告知systemd那些文件可以被清理,可被清理的文件又遵循什么样的策略呢?这个地方就到了配置文件部分了。

配置文件的名称必须符合 package.confpackage-part.conf格式。 当需要明确的将某部分(part)配置提取出来,以方便用户专门针对这部分进行修改的时候, 应该使用第二种命名格式。

对于不同目录下的同名配置文件,仅以优先级最高的目录中的那一个为准。具体说来就是: /etc/tmpfiles.d 的优先级最高、 /run/tmpfiles.d 的优先级居中、 /usr/lib/tmpfiles.d 的优先级最低。 软件包应该将自带的配置文件安装在 /usr/lib/tmpfiles.d 目录中, 而 /etc/tmpfiles.d 目录仅供系统管理员使用。 所有的配置文件,无论其位于哪个目录中,都统一按照文件名的字典顺序处理。 如果在多个配置文件中设置了同一个路径(文件或目录),那么仅以文件名最靠前(字典顺序)的那一个为准, 其他针对同一个路径的配置项将会作为警告信息记录到错误日志中。 如果有两行的路径互为前后缀,那么始终是先创建前缀行、再创建后缀行, 如果还需要删除,那么顺序正好相反,始终是先删除后缀行、再删除前缀行。 所有带有shell风格通配符的行,都在所有不带通配符的行之后处理。如果有多个操作符应用于同一个文件(例如 ACL, xattr, 文件属性调整),那么将始终按固定的顺序操作。除上述清空之外,对于其他情况, 文件与目录总是按照它们在配置文件中出现的顺序处理。

[root@node-a system]# cd /usr/lib/tmpfiles.d/
[root@node-a tmpfiles.d]# ll
total 132
-rw-r--r--. 1 root root   29 Mar 16 04:33 ceph-common.conf
-rw-r--r--. 1 root root   35 Apr  1  2020 cryptsetup.conf
-rw-r--r--. 1 root root   26 Mar 16 05:02 ctdb.conf
-rw-r--r--. 1 root root   67 Dec 11 08:32 elasticsearch.conf
-rw-r--r--. 1 root root  464 Nov 17  2020 etc.conf
-rw-r--r--. 1 root root   77 Nov 16  2020 httpd.conf
-rw-r--r--. 1 root root   39 Nov 17  2020 initscripts.conf
-rw-r--r--. 1 root root   75 Dec 15  2020 iscsi.conf
-rw-r--r--. 1 root root 1181 Nov 17  2020 legacy.conf
-rw-r--r--. 1 root root   34 Apr  1  2020 libselinux.conf
-r--r--r--. 1 root root   61 Dec 16  2020 lvm2.conf
-rw-r--r--. 1 root root   34 Oct  1  2020 mdadm.conf
-rw-r--r--. 1 root root   35 Jan 22  2021 net-snmp.conf
-rw-r--r--. 1 root root   27 Sep 30  2020 nscd.conf
-rw-r--r--. 1 root root  104 Sep 30  2020 nss-pam-ldapd.conf
-rw-r--r--. 1 root root   85 Oct  1  2020 openldap.conf
-rw-r--r--. 1 root root  110 Apr  1  2020 pam.conf
-rw-r--r--. 1 root root   15 Apr 10  2017 proftpd.conf
-rw-r--r--. 1 root root   16 Nov 17  2020 python.conf
-rw-r--r--. 1 root root   42 Nov 17  2020 resource-agents.conf
-rw-r--r--. 1 root root   87 Apr  1  2020 rpcbind.conf
-rw-r--r--. 1 root root   22 Oct  1  2020 rpm.conf
-rw-r--r--. 1 root root   60 Mar 16 05:02 samba.conf
-rw-r--r--. 1 root root  228 Nov 17  2020 sap.conf
-rw-r--r--. 1 root root   72 Oct  1  2020 screen.conf
-rw-r--r--. 1 root root  137 Nov 17  2020 selinux-policy.conf
-rw-r--r--. 1 root root  305 Jan 27  2021 sudo.conf
-rw-r--r--. 1 root root 1662 Nov 17  2020 systemd.conf
-rw-r--r--. 1 root root  496 Nov 17  2020 systemd-nologin.conf
-rw-r--r--. 1 root root  638 Nov 17  2020 tmp.conf
-rw-r--r--. 1 root root   56 Mar 22  2019 tuned.conf
-rw-r--r--. 1 root root  563 Nov 17  2020 var.conf
-rw-r--r--. 1 root root  623 Nov 17  2020 x11.conf
[root@node-a tmpfiles.d]# 
[root@node-a tmpfiles.d]# cd /etc/tmpfiles.d/
[root@node-a tmpfiles.d]# ll
total 0
[root@node-a tmpfiles.d]# 

主要的配置文件都被存放在/etc/tmpfiles.d和 /usr/lib/tmpfiles.d/下。其中/usr/lib/tmpfiles.d下可以看到有形形色色的配置文件。Ubuntu版本的产品比较神器,可以自动清理/tmp/sessions下的文件,甚至整个/tmp/sessions都被删除,我们看下配置文件:

root@CVM01:/usr/lib/tmpfiles.d# cat tmp.conf 
D /tmp 1777 root root -
#q /var/tmp 1777 root root 30d

# Exclude namespace mountpoints created with PrivateTmp=yes
x /tmp/systemd-private-%b-*
X /tmp/systemd-private-%b-*/tmp
x /var/tmp/systemd-private-%b-*
X /var/tmp/systemd-private-%b-*/tmp

这里除了我们比较熟悉的路径意外,有写D x X之类的奇奇怪怪的字母,这些何意?

systemd-tmpfiles 配置语法

tmpfiles.d 配置文件定义了一套临时文件管理机制: 创建 文件、目录、管道、设备节点, 调整访问模式、所有者、属性、限额、内容, 删除过期文件。 主要用于管理易变的临时文件与目录,例如 /run, /tmp, /var/tmp, /sys, /proc, 以及 /var 下面的某些目录

配置文件的格式是每行对应一个路径,包含如下字段: 类型, 路径, 权限, 属主, 属组, 寿命, 参数

#Type Path        Mode User Group Age Argument
d     /run/user   0755 root root  10d -
L     /tmp/foobar -    -    -     -   /dev/null

字段值可以用引号界定,并可以包含C风格的转义字符

然后就到了奇奇怪怪的字母部分了,因为它支持的Type太多了,我就一一罗列的,否则也记不住,我重点介绍常用的,如果需要了解细节的,可以阅读 金步国的文章

  • d 创建指定的目录并赋于指定的User/Group与权限。如果指定的目录已经存在,那么仅调整User/Group与权限。 如果指定了”寿命”字段,那么该目录中的内容将遵守基于时间的清理策略。
  • D 与 d 类似, 但是如果使用了 --remove 选项,那么将会清空目录中的所有内容。

注意此处, 我们看下Ubuntu的tmp.conf配置文件里面的一行:

D /tmp 1777 root root -

这一行毁天灭地,如果有印象的话,systemd-tmpfiles-setup.service执行的是:

ExecStart=/usr/bin/systemd-tmpfiles --create --remove --boot --exclude-prefix=/dev

这会将/tmp/下的所有东西一扫而空。但是Ubuntu版本有些人会说,没有,启动之后/tmp/目录下还有文件。这些文件是重启之后创建出来的。因此我们就明白了为什么Ubuntu下,/tmp/sessions会被清理,因为实时上不仅它会被清理,整个/tmp/都会被清理。

  • x 根据”寿命”字段清理过期文件时, 忽略指定的路径及该路径下的所有内容。 可以在”路径”字段中使用shell风格的通配符。 注意, 这个保护措施对 rR 无效。
  • R 在根据”寿命”字段清理过期文件时, 仅忽略指定的路径自身而不包括该路径下的其他内容。 可以在”路径”字段中使用shell风格的通配符。 注意, 这个保护措施对 rR 无效。

这两个是额外的保护,即按照时间线来清理的时候,免死金牌,不被清理。但是这个保护措施对后面提到的r和R无效

  • r 若指定的文件或目录存在, 则删除它。 不可用于非空目录。 可以在”路径”字段中使用shell风格的通配符。 不追踪软连接。
  • R 若指定的文件或目录存在,则递归的删除它。 可用于非空目录。 可以在”路径”字段中使用shell风格的通配符。 不追踪软连接。

这两个删除指令,R可递归,r不可。支持通配符。我们欣赏下Ubuntu 20.04版本里的systemd-tmp.conf

# Exclude namespace mountpoints created with PrivateTmp=yes
x /tmp/systemd-private-%b-*
X /tmp/systemd-private-%b-*/tmp
x /var/tmp/systemd-private-%b-*
X /var/tmp/systemd-private-%b-*/tmp

# Remove top-level private temporary directories on each boot
R! /tmp/systemd-private-*
R! /var/tmp/systemd-private-*

上面赦免不用说了,正常清理过程中,不要按照时间清理/tmp/systemd-private/打头的文件。但是后面R!表示机器重启期间,要将上述文件彻底删除,防止留下垃圾。

使用了感叹号(!)标记的行,仅可在系统启动过程中执行, 而不能用于运行中的系统(会破坏系统的正常运行)。 未使用感叹号(!)标记的行, 可以在任意时间安全的执行(例如升级软件包的时候)。 systemd-tmpfiles 仅在明确使用了 --boot 选项的时候 才会执行使用了感叹号(!)标记的行。

分析CentOS版本的行为

# Clear tmp directories separately, to make them easier to override
v /tmp 1777 root root 10d
v /var/tmp 1777 root root 30d

# Exclude namespace mountpoints created with PrivateTmp=yes
x /tmp/systemd-private-%b-*
X /tmp/systemd-private-%b-*/tmp
x /var/tmp/systemd-private-%b-*
X /var/tmp/systemd-private-%b-*/tmp

啥也不说了。根本就不清理 /tmp/system-private-文件。

如何调试systemd-tmpfiles

env SYSTEMD_LOG_LEVEL=debug systemd-tmpfiles --clean

这种方式比较详细,会把中间的判断过程也打印出来,如果清理行为不理解的话,可以用这个方法,看下为什么行为和自己理解的不一样。

[root@node-a tmpfiles.d]# env SYSTEMD_LOG_LEVEL=debug systemd-tmpfiles --clean
Reading config file "/usr/lib/tmpfiles.d/ceph-common.conf".
Reading config file "/usr/lib/tmpfiles.d/cryptsetup.conf".
Reading config file "/usr/lib/tmpfiles.d/ctdb.conf".
Reading config file "/usr/lib/tmpfiles.d/elasticsearch.conf".
Reading config file "/usr/lib/tmpfiles.d/etc.conf".
Reading config file "/usr/lib/tmpfiles.d/httpd.conf".
Reading config file "/usr/lib/tmpfiles.d/initscripts.conf".
Reading config file "/usr/lib/tmpfiles.d/iscsi.conf".
Reading config file "/run/tmpfiles.d/kmod.conf".
Ignoring entry c! "/dev/fuse" because --boot is not specified.
Ignoring entry c! "/dev/cuse" because --boot is not specified.
Ignoring entry c! "/dev/btrfs-control" because --boot is not specified.
Ignoring entry c! "/dev/loop-control" because --boot is not specified.
Ignoring entry c! "/dev/net/tun" because --boot is not specified.
Ignoring entry c! "/dev/ppp" because --boot is not specified.
Ignoring entry c! "/dev/uinput" because --boot is not specified.
Ignoring entry c! "/dev/mapper/control" because --boot is not specified.
Ignoring entry c! "/dev/uhid" because --boot is not specified.
Ignoring entry c! "/dev/vfio/vfio" because --boot is not specified.
Ignoring entry c! "/dev/vhci" because --boot is not specified.
Ignoring entry c! "/dev/vhost-net" because --boot is not specified.
....

如果带上参数 –boot 和–remove,模拟的基本就是开机启动时的清理逻辑:

env SYSTEMD_LOG_LEVEL=debug systemd-tmpfiles --clean

参考文献:

]]>
RAID 卡温度及风扇转速调节 2022-03-06T10:29:00+00:00 Bean Li http://bean-li.github.io/raid-temperature-and-fan 前言

本文讨论RAID卡温度以及潜在的影响。

查看RAID卡的温度

root@scanode1s:~# storcli64 /c0 show all |grep -i temp
Support Temperature = Yes
Temperature Sensor for ROC = Present
Temperature Sensor for Controller = Absent
ROC temperature(Degree Celsius) = 54
Model  State   Temp Mode MfgDate    Next Learn
root@scanode1s:~#

其中ROC temperature 即是我们需要关心的温度。一般来讲,该温度的合理值55摄氏度附近。目前空调状态不太好的机房,可能也会涨到60~80摄氏度。

如果R OC Temperature温度超过105摄氏度,从RAID卡的角度,你就会看到如下类似的日志:

WARNING:Controller temperature threshold exceeded. This may indicate inadequate system cooling, switch to low performace mode.

这种比较可怕,可能会出现大面积掉盘的情况。我们曾遇到客户,冬季客户主动把机房的空调关掉了,结果很快就有盘从RAID组中离线,RAID变成Degrade的情况。

因此,对于一个服务器而言,实时监控RAID卡的散热情况,也是非常重要的。

影响RAID温度的要素

RAID卡温度的要素,无非有如下几个要素

  • 机房温度
  • 风扇转速
  • 磁盘业务压力
  • RAID组内的一致性检查等带来磁盘I/O的行为

注意,计算机房温度高,风扇有问题等问题存在,但是如果没有任何磁盘I/O基本上也不会导致RAID温度过好。我们遇到的多次RAID卡温度过高,都是糟糕的散热条件,遇到了较高的业务压力,又碰上了一致性检查,多个条件一起作用,终于RAID卡温度飙高不下。

如果发现机房的散热条件不好,或者机器老化等要素,可以针对性地调整一致性检查的速度和模式

  • 调整一致性检查的模式从ModeConc改成ModeSeq,串型模式
  • 调整CCRate从默认的30,调整成15
  • 一致性检查的时间,可以调整成夜间12点这种业务和温度比较低的时间。

风扇转速

我们以超微主板为例,风扇有相关的运行模式 Fan Mode:

  • Standard Speed
  • Full Speed
  • Optimal Speed
  • HeavyIO Speed

风扇按照控制区域来分,分成两类:

  • CPU or system Fans,一般被标记成 FAN0 FAN1 FAN2 ,命名方式为FAN+数字,这部分为Zone 0

  • Peripheral zone Fans, 一般被命名为FANA FANB FANC,明明方式为FAN+字母,这部分为Zone 1

  • image-20220306121313707

上面提到的四种模式:

  • Standard: BMC 同时控制两个zone, with CPU Zone base CPU temp(target speed 50%),and Peripheral zone based on PCH temp (with target speed 50%)
  • Optimal: BMC Control of the CPU zone (target speed 30%),with Peripheral zone fixed at low speed (fixed ~30%)
  • Full: all Fans running at 100%
  • HeavyIO : BMC control both CPU zone (target speed 50%) and Peripheral zone fixed at 75%

如果像存储服务器这种,Optimal肯定是不合适了,Full的话也不太合适,因为太吵,可选的就是两个,Standard和HeavyIO。如果保守起见,可以选择Heavy IO,防止散热不好的情况下,RA ID卡温度过高。

如何调整风扇转速和模式

调整风扇模式

我们以全速模式为例,如何讲风扇调整为全速模式:

ipmitool 0x30 0x45 0x01 0x01

注意倒数第二个0x01表示的是Zone:

  • 0x00 表示的是zone 0, 即负责CPU zone的风扇
  • 0x01 表示的是zone 1

最后一个0x01 表示的是模式:

  • standard :0
  • Full: 1
  • Optimal: 2
  • HeavyIO:4

我们故意做个测试,来看下将风扇模式调整成Full的效果:

image-20220306122718856

调整成Full模式之后,很快的时间内温度就下降下来了。

调整转速

Full模式虽然开心,效果明显,但是很明显噪音很大。所以100%的风扇转速虽然爽,但是忍受不了噪音。那如何处理?

ipmitool raw 0x30 0x70 0x66 0x01 0x<z> 0x<n>

z的合法值为0 和1 ,其中0表示Zone 0, 1 表示Zone 1.

n的合法值是从0x00 到0x64 ,即从0%到100%。

比如说我们觉得Full模式的100%太吵,Heavy IO模式的75%效果虽然不错,但是也太吵,我们可以将Zone1的百分比调整成60%。

 ipmitool raw 0x30 0x70 0x66 0x01 0x1 0x3C 

总结

下面总结是对于存储服务器而言的,并非针对所有应用场景

  • RAID卡的温度要实时监测,确保运行稳定
  • 风扇模式有4种,Full和Optimal都不可取,Standard和Heavy IO可以选择
  • 对于转速不满意的,可以通过ipmitool 指令调节转速,使其在合理范围内调节。
]]>
查看Bucket相关的metadata 2021-12-26T10:29:00+00:00 Bean Li http://bean-li.github.io/bucket-info 前言

本文介绍,如何查看bucket相关的元数据信息。

root@CVM01:~# radosgw-admin metadata get bucket:bkt_test
{
    "key": "bucket:bkt_test",
    "ver": {
        "tag": "_avOPFvyGt4fut9GiJPsIXeK",
        "ver": 1
    },
    "mtime": "2021-04-22 07:22:12.706675Z",
    "data": {
        "bucket": {
            "name": "bkt_test",
            "marker": "7240a9f2-42ea-4f3d-b534-ad4d867ab9cb.372941258.1",
            "bucket_id": "7240a9f2-42ea-4f3d-b534-ad4d867ab9cb.372941258.1",
            "tenant": "",
            "explicit_placement": {
                "data_pool": "",
                "data_extra_pool": "",
                "index_pool": ""
            }
        },
        "owner": "s3user1",
        "creation_time": "2021-04-22 07:22:12.559921Z",
        "linked": "true",
        "has_bucket_info": "false"
    }
}
root@CVM01:~# radosgw-admin metadata get bucket.instance:bkt_test:7240a9f2-42ea-4f3d-b534-ad4d867ab9cb.372941258.1
{
    "key": "bucket.instance:bkt_test:7240a9f2-42ea-4f3d-b534-ad4d867ab9cb.372941258.1",
    "ver": {
        "tag": "_CPltbMF1_HktM5SUnn1zwPn",
        "ver": 4
    },
    "mtime": "2021-04-22 07:58:32.656184Z",
    "data": {
        "bucket_info": {
            "bucket": {
                "name": "bkt_test",
                "marker": "7240a9f2-42ea-4f3d-b534-ad4d867ab9cb.372941258.1",
                "bucket_id": "7240a9f2-42ea-4f3d-b534-ad4d867ab9cb.372941258.1",
                "tenant": "",
                "explicit_placement": {
                    "data_pool": "",
                    "data_extra_pool": "",
                    "index_pool": ""
                }
            },
            "creation_time": "2021-04-22 07:22:12.559921Z",
            "owner": "s3user1",
            "flags": 6,
            "zonegroup": "0a4d68f0-0a16-4e0c-a88b-d0b708ce75f1",
            "placement_rule": "default-placement",
            "has_instance_obj": "true",
            "quota": {
                "enabled": false,
                "check_on_raw": false,
                "max_size": -1,
                "max_size_kb": 0,
                "max_objects": -1
            },
            "num_shards": 128,
            "bi_shard_hash_type": 0,
            "requester_pays": "false",
            "has_website": "false",
            "swift_versioning": "false",
            "swift_ver_location": "",
            "index_type": 0,
            "mdsearch_config": [],
            "reshard_status": 0,
            "new_bucket_instance_id": "",
            "worm": {
                "enable": false
            }
        },
        "attrs": [
            {
                "key": "user.rgw.acl",
                "val": "AgKNAAAAAwIWAAAABwAAAHMzdXNlcjEHAAAAczN1c2VyMQQDawAAAAEBAAAABwAAAHMzdXNlcjEPAAAAAQAAAAcAAABzM3VzZXIxBQM6AAAAAgIEAAAAAAAAAAcAAABzM3VzZXIxAAAAAAAAAAACAgQAAAAPAAAABwAAAHMzdXNlcjEAAAAAAAAAAAAAAAAAAAAA"
            },
            {
                "key": "user.rgw.idtag",
                "val": ""
            },
            {
                "key": "user.rgw.lc",
                "val": "AQGJAAAAAQAAAAcAAABkZWZhdWx0BgF0AAAABwAAAGRlZmF1bHQAAAAABwAAAEVuYWJsZWQDAggAAAAAAAAAAAAAAAMCCQAAAAEAAAA1AAAAAAMCCAAAAAAAAAAAAAAAAAEBBAAAAAAAAAABAQwAAAAAAAAAAAAAAAAAAAABAQwAAAAAAAAAAAAAAAAAAAA="
            }
        ]
    }
}

如何修改bucket index shards

root@CVM01:~# radosgw-admin zonegroup get >  tmp.conf
{
    "id": "0a4d68f0-0a16-4e0c-a88b-d0b708ce75f1",
    "name": "default",
    "api_name": "",
    "is_master": "true",
    "endpoints": [],
    "hostnames": [],
    "hostnames_s3website": [],
    "master_zone": "7240a9f2-42ea-4f3d-b534-ad4d867ab9cb",
    "zones": [
        {
            "id": "7240a9f2-42ea-4f3d-b534-ad4d867ab9cb",
            "name": "default",
            "endpoints": [],
            "log_meta": "false",
            "log_data": "false",
            "bucket_index_max_shards": 0,
            "read_only": "false",
            "tier_type": "",
            "sync_from_all": "true",
            "sync_from": []
        }
    ],
    "placement_targets": [
        {
            "name": "default-placement",
            "tags": []
        }
    ],
    "default_placement": "default-placement",
    "realm_id": ""
}

修改 bucket_index_max_shards = 64 之后,然后执行:

radosgw-admin region set < tmp.conf
]]>
IFF_UP 与 IFF_RUNNING 2021-10-23T10:29:00+00:00 Bean Li http://bean-li.github.io/if-is-up 前言

近期,发现判断网卡是否Ready的程序出了一些问题,有些网卡明明没有插线,依然会被判定为active的网卡。我去跟踪了下代码:

# struct ifreq { // FOR SIOCGIFFLAGS:
#   char ifrn_name[IFNAMSIZ]
#   short ifru_flags
# };
my $STRUCT_IFREQ_SIOCGIFFLAGS = 'Z' . IFNAMSIZ . 's1';
sub get_active_network_interfaces {
    # Use the interface name list from /proc/net/dev
    open my $fh, '<', '/proc/net/dev'
	or die "failed to open /proc/net/dev: $!\n";
    # And filter by IFF_UP flag fetched via a PF_INET6 socket ioctl:
    my $sock;
    socket($sock, PF_INET6, SOCK_DGRAM, &IPPROTO_IP)
    or socket($sock, PF_INET, SOCK_DGRAM, &IPPROTO_IP)
    or return [];

    my $ifaces = [];
    while(defined(my $line = <$fh>)) {
	next if $line !~ /^\s*([^:\s]+):/;
	my $ifname = $1;
	my $ifreq = pack($STRUCT_IFREQ_SIOCGIFFLAGS, $ifname, 0);
	if (!defined(ioctl($sock, SIOCGIFFLAGS, $ifreq))) {
	    warn "failed to get interface flags for: $ifname\n";
	    next;
	}
	my ($name, $flags) = unpack($STRUCT_IFREQ_SIOCGIFFLAGS, $ifreq);
	push @$ifaces, $ifname if ($flags & IFF_UP);
    }
    close $fh;
    close $sock;
    return $ifaces;
}

发现源码使用通过调用 ioctl SIOCGIFFLAGS 来判定网卡是否已经ready。

关于SIOCGIFFLAGS

Linux ioctl支持一下两个标志位:

  • SIOCGIFFLAGS: 获取设备的活动标志位
  • SIOCSIFFLAGS: 修改设备的活动标志位
       SIOCGIFFLAGS, SIOCSIFFLAGS
              Get or set the active flag word of the device.  ifr_flags contains a bit mask of the following values:

                                           Device flags
              IFF_UP            Interface is running.
              IFF_BROADCAST     Valid broadcast address set.
              IFF_DEBUG         Internal debugging flag.
              IFF_LOOPBACK      Interface is a loopback interface.

              IFF_POINTOPOINT   Interface is a point-to-point link.
              IFF_RUNNING       Resources allocated.
              IFF_NOARP         No arp protocol, L2 destination address not set.
              IFF_PROMISC       Interface is in promiscuous mode.
              IFF_NOTRAILERS    Avoid use of trailers.
              IFF_ALLMULTI      Receive all multicast packets.
              IFF_MASTER        Master of a load balancing bundle.
              IFF_SLAVE         Slave of a load balancing bundle.
              IFF_MULTICAST     Supports multicast
              IFF_PORTSEL       Is able to select media type via ifmap.
              IFF_AUTOMEDIA     Auto media selection active.
              IFF_DYNAMIC       The addresses are lost when the interface goes down.
              IFF_LOWER_UP      Driver signals L1 up (since Linux 2.6.17)
              IFF_DORMANT       Driver signals dormant (since Linux 2.6.17)
              IFF_ECHO          Echo sent packets (since Linux 2.6.25)本次我们重点介绍IFF_UP和 IFF_RUNNING。

IFF_UP: 这个标志位表示的是从管理上讲,这个网口是UP的,是Ready的,但是并不代表连接状态。即网卡已经准备好了,但是并不意味着网线已插。

IFF_RUNNING: 这个标志位表示operational state,如果置位的话,表示CONNECTED的。

验证

做个简单验证:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <string.h>

#define BUFSIZE 1024

int main(int argc, char *argv[])
{
	struct ifreq ifr;
	int sfd ;

	memset(&ifr, '\0' , sizeof(struct ifreq));
	strcpy(ifr.ifr_name, argv[1]);
	sfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);

	int ret = ioctl(sfd, SIOCGIFFLAGS, (char *)&ifr);
	if(ret !=0)
	{
		printf("failed to exec ioctl");
		goto out;
	}

	printf("%10s IFF_UP: %d\n", argv[1], !!(ifr.ifr_flags & IFF_UP));
	printf("%10s IFF_RUNNING: %d \n",argv[1], !!(ifr.ifr_flags & IFF_RUNNING));

out:
	close(sfd);
	exit(ret);
}

我的笔记本的网口情况如下:

manu-latitude3510 CODE/C » cat /proc/net/dev
Inter-|   Receive                                                |  Transmit
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
    lo: 1503282   11818    0    0    0     0          0         0  1503282   11818    0    0    0     0       0          0
  eno1:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0
wlp1s0: 14947732561 40405691    0 822774    0     0          0         0 650855154 3591298    0    0    0     0       0          0
manu-latitude3510 CODE/C »

其中eno1 是有线,并未插线,wlp1s0是无线,已经连接的状态。

manu-latitude3510 CODE/C » ./nettool eno1                                                                                                                
      eno1 IFF_UP: 1
      eno1 IFF_RUNNING: 0
manu-latitude3510 CODE/C » ./nettool wlp1s0
    wlp1s0 IFF_UP: 1
    wlp1s0 IFF_RUNNING: 1
manu-latitude3510 CODE/C » ./nettool lo
        lo IFF_UP: 1
        lo IFF_RUNNING: 1
manu-latitude3510 CODE/C
]]>
上图不说话:关闭服务器节能模式 2021-03-07T10:29:00+00:00 Bean Li http://bean-li.github.io/powerleader-efficiency-mode

powerleader_2

powerleader_3

powerleader_4

powerleader_5

powerleader_6

powerleader_7

]]>
使用SystemTap给I/O设备注入延迟 2021-03-07T10:29:00+00:00 Bean Li http://bean-li.github.io/SystemTap-Inject-Latency 前言

当我们的IO密集型的应用怀疑设备的IO抖动,比如说某个磁盘的性能衰退,导致性能问题。这种故障一般需要有故障的硬盘才能测试。但是如何使用正常的硬盘模拟出块设备有较大的延迟呢?

阿里的褚霸有一篇文章《巧用Systemtap注入延迟模拟IO设备抖动》,使用SystemTap来模拟故障的设备。

global inject, ka_cnt

probe procfs("cnt").read {
  $value = sprintf("%d\n", ka_cnt);
}
probe procfs("inject").write {
  inject= $value;
  printf("inject count %d, ka %s", ka_cnt, inject);
}

probe vfs.read.return,
      vfs.write.return {
  if ($return &&
      devname == @1 &&
      inject == "on\n")
  {
    ka_cnt++;
    udelay($2);
  }
}

probe begin{
  println("ik module begin:)");
}

$ stap -V
Systemtap translator/driver (version 2.1/0.152, commit release-2.0-385-gab733d5)
Copyright (C) 2005-2013 Red Hat, Inc. and others
This is free software; see the source for copying conditions.
enabled features: LIBSQLITE3 NSS BOOST_SHARED_PTR TR1_UNORDERED_MAP NLS

$ sudo stap -p4 -DMAXSKIPPED=9999 -m ik -g inject_ka.stp sda6 300
ik.ko

但是霸爷的中心在vfs层注入延迟,如果我们关心块设备层,希望能够模拟出来块设备层的较高延迟,那么怎么做呢?

不啰嗦,直接进入主题。

在块设备层注入延迟

global cnt = 0 ;
probe module("sd_mod").function("sd_init_command") !,
      kernel.function("sd_init_command")
{
    device = kernel_string(@choose_defined($cmd, $SCpnt)->request->rq_disk->disk_name)
    if(device == @1)
    {
        mdelay($2);
        if(cnt % 100 == 0)
        { 
             printf("%s inject delay %4d times %7d\n", device,$2, cnt)
        }
        cnt++ ;
    }
    #printf("device %s sd_init_command\n", device);
}

probe begin{
  println("inject_scsi_delay module begin");
}

上述文件命名为inject_ka.stp,那么通过如下指令,可以给sdb设备注入10ms的延迟:

stap -p4 -DMAXSKIPPED=99999999 -m ik -g inject_ka.stp sdb 10
staprun ik.ko

或者执行:

stap -g -DMAXSKIPPED=99999999 inject_ka.stp sdb 10

我们可以通过iostat查看效果:

image-20210305224928219

参考文献

https://sourceware.org/systemtap/examples/io/iostat-scsi.stp

https://sourceware.org/systemtap/examples/io/iostat-scsi.txt

]]>
从osdmap中获取crush相关的信息 2021-02-27T10:29:00+00:00 Bean Li http://bean-li.github.io/osdmap-crush 前言

开发功能过程中,有遇到crushmap被改坏的情况:

2021-02-26 16:58:13.362710 mon.lmuoc mon.0 10.10.10.119:6789/0 2658547 : cluster [DBG] osdmap e1033: 10 total, 10 up, 10 in
2021-02-26 16:58:14.418809 mon.lmuoc mon.0 10.10.10.119:6789/0 2658853 : cluster [DBG] osdmap e1034: 10 total, 10 up, 10 in
2021-02-26 16:58:06.359967 mgr.lmuoc client.4097 10.10.10.119:0/854553116 16170 : cluster [DBG] pgmap v6705: 7168 pgs: 7168 active+clean; 87.2GiB data, 180GiB used, 36.0TiB / 36.2TiB avail; 12.3KiB/s rd, 505B/s wr, 15op/s; 10.5MiB/s, 2objects/s recovering
2021-02-26 16:58:08.388416 mgr.lmuoc client.4097 10.10.10.119:0/854553116 16174 : cluster [DBG] pgmap v6706: 7168 pgs: 7168 active+clean; 87.2GiB data, 180GiB used, 36.0TiB / 36.2TiB avail; 16.7KiB/s rd, 589B/s wr, 21op/s; 4.60MiB/s, 1objects/s recovering
2021-02-26 16:58:10.411606 mgr.lmuoc client.4097 10.10.10.119:0/854553116 16175 : cluster [DBG] pgmap v6707: 7168 pgs: 7168 active+clean; 87.2GiB data, 180GiB used, 36.0TiB / 36.2TiB avail; 15.6KiB/s rd, 589B/s wr, 18op/s; 4.60MiB/s, 1objects/s recovering
2021-02-26 16:58:12.440488 mgr.lmuoc client.4097 10.10.10.119:0/854553116 16179 : cluster [DBG] pgmap v6708: 7168 pgs: 7168 active+clean; 87.2GiB data, 180GiB used, 36.0TiB / 36.2TiB avail; 9.45KiB/s rd, 336B/s wr, 12op/s; 4.60MiB/s, 1objects/s recovering
2021-02-26 16:58:14.454427 mgr.lmuoc client.4097 10.10.10.119:0/854553116 16181 : cluster [DBG] pgmap v6711: 7168 pgs: 17 peering, 7151 active+clean; 87.2GiB data, 180GiB used, 36.0TiB / 36.2TiB avail; 19.7KiB/s rd, 505B/s wr, 24op/s
2021-02-26 16:58:15.399887 mon.lmuoc mon.0 10.10.10.119:6789/0 2659056 : cluster [WRN] Health check failed: Reduced data availability: 2 pgs inactive, 17 pgs peering (PG_AVAILABILITY)
2021-02-26 16:58:21.342312 mon.lmuoc mon.0 10.10.10.119:6789/0 2660571 : cluster [INF] Health check cleared: PG_AVAILABILITY (was: Reduced data availability: 3 pgs inactive, 18 pgs peering)
2021-02-26 16:58:21.342357 mon.lmuoc mon.0 10.10.10.119:6789/0 2660572 : cluster [INF] Cluster is now healthy
2021-02-26 16:58:23.065699 mon.lmuoc mon.0 10.10.10.119:6789/0 2660963 : cluster [DBG] osdmap e1035: 10 total, 10 up, 10 in
2021-02-26 16:58:24.139954 mon.lmuoc mon.0 10.10.10.119:6789/0 2661276 : cluster [DBG] osdmap e1036: 10 total, 10 up, 10 in

在修改crush过程中,只有4个版本的osdmap变化,如何从osdmap中提取出crush,以及判断crush是从那个版本开始被改坏的呢?

获取指定版本的osdmap

ceph osd getmap 1034 -o osdmap.1034

从osdmap获得crush

osdmaptool osdmap.1034 --export-crush crush.1034
crushtool -d crush.1034 -o crush.1034.txt

获得crush之后,可以比较两个版本之间,crush的变化:

image-20210228101105633

我们发现,我们关心的metadata的权重,在1035这个osdmap epoch被篡改了。

从osdmap获得某个Pool的PG分布

osdmaptool osdmap.1034  --test-map-pgs-dump --pool 10

其输出大约为:

。。。
10.3f6	[6,3]	6
10.3f7	[0,8]	0
10.3f8	[5,4]	5
10.3f9	[6,0]	6
10.3fa	[9,0]	9
10.3fb	[6,4]	6
10.3fc	[6,0]	6
10.3fd	[6,2]	6
10.3fe	[5,0]	5
10.3ff	[5,3]	5
#osd	count	first	primary	c wt	wt
osd.0	212	102	102	3.60291	1
osd.1	181	83	83	3.60291	1
osd.2	203	97	97	3.60291	1
osd.3	233	112	112	3.60291	1
osd.4	195	103	103	3.60291	1
osd.5	202	97	97	3.63974	1
osd.6	224	124	124	3.63974	1
osd.7	201	99	99	3.63974	1
osd.8	212	99	99	3.63974	1
osd.9	185	108	108	3.63974	1
 in 10
 avg 204 stddev 15.3428 (0.0752096x) (expected 13.5765 0.0665512x))
 min osd.1 181
 max osd.3 233
size 0	0
size 1	0
size 2	1024
size 3	0

我们可以看到PG在OSD上的分布是否均匀,以及各个PG各自分布在那个OSD上。

]]>
kdump 安装 2021-02-21T10:29:00+00:00 Bean Li http://bean-li.github.io/kdump 前言

有时候需要分配内核crash,我们需要kdump工具,本文介绍Ubuntu 下的相关工具的安装。

kdump功能主要分为3部分:

1)kdump使能阶段:安装kdump,然后重启系统生效,系统会预留一段内存作为第二内核和日志存储用;kdump启动会使用kexec命令加载第二内核完毕,等待触发panic启动;

2)系统panic,进入第二内核,内核将出错信息保存在/proc/vmcore提供给用户;

3)日志转储完毕,重启系统,/var/crash分析日志;

安装

Ubuntu下,需要安装linux-crashdump:

apt-get install linux-crashdump

安装完成之后,重启之前:

kdump-before-reboot

重启之后:


root@CVM01:/etc/sysctl.d# kdump-config show
DUMP_MODE:        kdump
USE_KDUMP:        1
KDUMP_SYSCTL:     kernel.panic_on_oops=1
KDUMP_COREDIR:    /var/crash
crashkernel addr: 0x2a000000
   /var/lib/kdump/vmlinuz: symbolic link to /boot/vmlinuz-4.14.148-server
kdump initrd:
   /var/lib/kdump/initrd.img: symbolic link to /var/lib/kdump/initrd.img-4.14.148-server
current state:    ready to kdump

kexec command:
  /sbin/kexec -p --command-line="BOOT_IMAGE=/boot/vmlinuz-4.14.148-server root=UUID=ba73a2b3-f5a0-4035-8689-3494a5aeab16 ro video=VGA-1:800x600 quiet i915.modeset=0 nomodeset net.ifnames=1 biosdevname=0  systemd.unit=kdump-tools-dump.service irqpoll nousb ata_piix.prefer_ms_hyperv=0" --initrd=/var/lib/kdump/initrd.img /var/lib/kdump/vmlinuz

通过service –status-all可以看到新加入的kdump相关的服务:

root@CVM01:/etc/sysctl.d# service --status-all
 [ + ]  kdump-tools
 [ + ]  kexec
 [ + ]  kexec-load

如果配置要修改,可以通过如下两种方式来进行:

  1. dpkg-reconfigure kexec-tools 和dpkg-reconfigure kdump-tools
  2. 修改/etc/default/kexec配置文件

参考文献:

Kernel Crash Dump

如何在Ubuntu18.04下安装和配置kdump

]]>
systemd修改服务的资源使用 2021-01-30T10:29:00+00:00 Bean Li http://bean-li.github.io/systemd-limit 前言

有些时候,我们需要修改某些进程或者某个服务的资源,比如:

  • 允许进程打开的最大文件数
  • 修改线程的默认栈大小

Linux提供了ulimit 指令来查看和修改默认资源限制:

root@subhealth1:/lib/systemd# ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 379704
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 4096
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 379704
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

对于systmed来讲,如果修改配置文件,限定或者修改资源的使用呢?

systemd和ulimit的映射

systemd基本上可以修改所有资源的限制,它和ulimit的映射关系如下:

Directive        ulimit equivalent     Unit
LimitCPU=        ulimit -t             Seconds      
LimitFSIZE=      ulimit -f             Bytes
LimitDATA=       ulimit -d             Bytes
LimitSTACK=      ulimit -s             Bytes
LimitCORE=       ulimit -c             Bytes
LimitRSS=        ulimit -m             Bytes
LimitNOFILE=     ulimit -n             Number of File Descriptors 
LimitAS=         ulimit -v             Bytes
LimitNPROC=      ulimit -u             Number of Processes 
LimitMEMLOCK=    ulimit -l             Bytes
LimitLOCKS=      ulimit -x             Number of Locks 
LimitSIGPENDING= ulimit -i             Number of Queued Signals 
LimitMSGQUEUE=   ulimit -q             Bytes
LimitNICE=       ulimit -e             Nice Level 
LimitRTPRIO=     ulimit -r             Realtime Priority  
LimitRTTIME=     No equivalent

我们以OSD为例:

[Unit]
Description=Ceph object storage daemon osd.%i
After=network-online.target local-fs.target time-sync.target ceph-mon.target
Wants=network-online.target local-fs.target time-sync.target
PartOf=ceph-osd.target

[Service]
LimitNOFILE=1048576
LimitNPROC=1048576
EnvironmentFile=-/etc/default/ceph
Environment=CLUSTER=ceph
ExecStart=/usr/bin/ceph-osd -f --cluster ${CLUSTER} --id %i --setuser root --setgroup root
ExecStartPre=/usr/lib/ceph/ceph-osd-prestart.sh --cluster ${CLUSTER} --id %i
ExecReload=/bin/kill -HUP $MAINPID
ProtectHome=true
ProtectSystem=full
PrivateTmp=true
TasksMax=infinity
Restart=on-failure
StartLimitInterval=30min
StartLimitBurst=30
RestartSec=20s

[Install]
WantedBy=ceph-osd.target

注意,Linux默认允许打开的文件数非常有限,而ceph-osd可能需要打开更多的文件,所以通过

LimitNOFILE=1048576

将允许该进程打开的文件数放大到了1M。

如果我们需要修改默认stacksize,那么,我们需要增加如下行:

LimitSTACK=2097152

我们将ceph-osd的栈大小从默认的8M改成了2M。

修改完毕之后需要执行:

systemctl daemon-reload

然后重启相关的服务,即可生效。

检查修改是否生效

如果我们修改了相关的资源限制,如何查看是否生效呢?

cat /proc/[PID]/limits

我们以一个测试环境为例:

root@CVM01:/lib/systemd/system# pidof ceph-osd
978185 928119
root@CVM01:/lib/systemd/system# cat /proc/928119/limits
Limit                     Soft Limit           Hard Limit           Units
Max cpu time              unlimited            unlimited            seconds
Max file size             unlimited            unlimited            bytes
Max data size             unlimited            unlimited            bytes
Max stack size            2097152              2097152              bytes
Max core file size        0                    unlimited            bytes
Max resident set          unlimited            unlimited            bytes
Max processes             1048576              1048576              processes
Max open files            1048576              1048576              files
Max locked memory         65536                65536                bytes
Max address space         unlimited            unlimited            bytes
Max file locks            unlimited            unlimited            locks
Max pending signals       257494               257494               signals
Max msgqueue size         819200               819200               bytes
Max nice priority         0                    0
Max realtime priority     0                    0
Max realtime timeout      unlimited            unlimited            us
root@CVM01:/lib/systemd/system#

我们可以看到我们修改的stacksize已经生效了,从默认的8M降低为2M。

]]>