如何使用Journalctl查看并操作Systemd日志

内容简介

作为最具吸引力的优势,systemd拥有强大的处理与系统日志记录功能。在使用其它工具时,日志往往被分散在整套系统当中,由不同的守护进程及进程负责处理,这意味着我们很难跨越多种应用程序对其内容进行解读。

相比之下,systemd尝试提供一套集中化管理方案,从而统一打理全部内核及用户级进程的日志信息。这套系统能够收集并管理日志内容,而这也就是我们所熟知的journal。

Journal的实现归功于journald守护进程,其负责处理由内核、initrd以及服务等产生的信息。在今天的教程中,我们将探讨如何使用journalctl工具,并在其帮助下访问并操作journal内部的数据。

总体思路

Systemd journal的深层驱动力在于以集中方式管理对来自任意来源的日志信息。由于大部分引导进程都是由systemd进程处理的,因此我们有理由以标准化方式实现日志的收集与访问。其中jornald守护进程会收集全部来源的数据并将其以二进制格式加以存储,从而轻松实现动态操作。

这种作法能够实现多种收益。通过单一工具与数据交互,管理员能够以动态方式显示日志数据。另外,我们也可以轻松查看历史引导数据,或者将日志条目同其它相关服务加以结合,从而 完成通信问题调试。

将日志数据以二进制形式存储还意味着这些数据可根据需求随时以二进制输出格式显示。例如,大家可以通过标准syslog格式查看日志以实现日常管理,并在需要使用图形服务时将各条目作为JSON对象交由图形化服务处理。由于数据不会以纯文本形式被写入磁盘,因此我们无需进行任何格式转换。

大家可以将systemd journal与现有syslog方案配合使用,也可利用其替代现有syslog功能,具体取决于实际需求。尽管systemd journal足以涵盖大部分管理工作需求,但其同时也能够补充现有日志记录机制。例如,大家可以建立一套集中式syslog服务器,从而对来自多台服务器的数据进行编译;或者,我们也能够利用systemd journal将来自多项服务的日志汇总在单一系统当中。

设置系统时间

使用二进制journal的一大好处在于,它能够以UTC或者本地时间显示日志记录。在默认情况下,systemd会以本地时间显示结果。

有鉴于此,在我们开始使用journal之前,首先要确保时区得到正确设置。Systemd套件中还提供一款timedatectl工具,专门用于解决此类问题。
首先,利用list-timezones选项查看可用时区:

timedatectl list-timezones

结果将列出系统上可用的全部时区。而后选择与服务器所在地相匹配的项目,并使用set-timezone选项加以设置:

sudo timedatectl set-timezone zone

为了确保我们的设备使用正确的时间,可单独使用timedatectl命令或者添加status选项。显示结果如下:

timedatectl status

Local time: Thu 2015-02-05 14:08:06 EST
Universal time: Thu 2015-02-05 19:08:06 UTC
    RTC time: Thu 2015-02-05 19:08:06
   Time zone: America/New_York (EST, -0500)
 NTP enabled: no
NTP synchronized: no
RTC in local TZ: no
  DST active: n/a

第一行所示应为正确时间。

基础日志查看

要查看journald守护进程收集到的日志,可使用journalctl命令。

在单独使用时,系统中的每个journal条目都会被显示在单一pager中供我们浏览。条目时间越早,排列越靠前:

journalctl

-- Logs begin at Tue 2015-02-03 21:48:52 UTC, end at Tue 2015-02-03 22:29:38 UTC. --
Feb 03 21:48:52 localhost.localdomain systemd-journal[243]: Runtime journal is using 6.2M (max allowed 49.
Feb 03 21:48:52 localhost.localdomain systemd-journal[243]: Runtime journal is using 6.2M (max allowed 49.
Feb 03 21:48:52 localhost.localdomain systemd-journald[139]: Received SIGTERM from PID 1 (systemd).
Feb 03 21:48:52 localhost.localdomain kernel: audit: type=1404 audit(1423000132.274:2): enforcing=1 old_en
Feb 03 21:48:52 localhost.localdomain kernel: SELinux: 2048 avtab hash slots, 104131 rules.
Feb 03 21:48:52 localhost.localdomain kernel: SELinux: 2048 avtab hash slots, 104131 rules.
Feb 03 21:48:52 localhost.localdomain kernel: input: ImExPS/2 Generic Explorer Mouse as /devices/platform/
Feb 03 21:48:52 localhost.localdomain kernel: SELinux:  8 users, 102 roles, 4976 types, 294 bools, 1 sens,
Feb 03 21:48:52 localhost.localdomain kernel: SELinux:  83 classes, 104131 rules

. . .

大家可以一页页进行翻看,不过如果系统运行时间较长,那么systemd中的日志也将成千上万,这也证明了journal数据库中可观的数据量。

其格式与标准的syslog日志非常相似。然而,其收集数据的来源较syslog要丰富得多。其中包含有来自先前引导进程、内核、initrd以及应用程序标准错误与输出的日志。这一切都可在journal中查看到。

大家可能还注意到,全部时间戳都以本地时间为准。由于已经为系统正确设置了本地时间,所以显示的时间戳也都准确无误。

如果大家希望以UTC显示时间戳,则可使用–utc标记:

journalctl --utc

按时间进行journal过滤

浏览大量数据当然有其作用,但信息量过于庞大则会让我们很难甚至根本不可能找到真正重要的内容。因此,journalctl提供了极为关键的过滤选项。

  • 显示当前引导进程下的日志

其中最常用的就是-b标记了,其将显示全部最近一次重新引导后收集到的journal条目。

journalctl -b

通过这种方式,我们能够识别并管理源自当前环境下的信息。
如果不使用这项功能,而且显示的引导数量超过一天,那么journalctl会在在系统关闭处插入说明:

. . .

-- Reboot --

. . .

这种方式能够帮助我们有效区分来自不同引导会话的信息。

  • 过往引导记录

大家通常只需要查看当前引导环境下的信息,但有时候查看过往引导记录也非常必要。Journal能够保存大量过往引导信息,从而允许journalctl轻松显示相关内容。

有些版本会在默认情况下保存过往引导信息,而有些则默认禁用这项功能。要启用此功能,可以使用以下功能以创建用于存储journal信息的目录:

sudo mkdir -p /var/log/journal

或者直接编辑journal配置文件:

sudo nano /etc/systemd/journald.conf

在[Journal]区段下将Storage=选项设定为“persistent”以启用持久记录:

/etc/systemd/journald.conf

. . .
[Journal]
Storage=persistent

当启用保存过往引导信息功能后,journalctl会提供额外命令以帮助大家将各引导记录作为独立单元操作。要查看Journald中已经记录的引导信息,可使用–list-boots选项:

journalctl --list-boots

-2 caf0524a1d394ce0bdbcff75b94444fe Tue 2015-02-03 21:48:52 UTC—Tue 2015-02-03 22:17:00 UTC
-1 13883d180dc0420db0abcb5fa26d6198 Tue 2015-02-03 22:17:03 UTC—Tue 2015-02-03 22:19:08 UTC
 0 bed718b17a73415fade0e4e7f4bea609 Tue 2015-02-03 22:19:12 UTC—Tue 2015-02-03 23:01:01 UTC

这里每次引导都将显示为一行。第一列可用于在journalctl中引用该次引导。如果大家需要更为准确的引用方式,则可在第二列中找到引导ID。末尾记录的两次时间为当次引导的开始与结束时间。

要显示这些引导中的具体信息,则可使用第一或者第二列提供的信息。

例如,要查看上次引导的journal记录,则可使用-1相对指针配合-b标记:

journalctl -b -1

另外,也可以使用引导ID:

journalctl -b caf0524a1d394ce0bdbcff75b94444fe
  • 时间窗

按照引导环境查看日志条目当然非常重要,但我们往往还需要使用与系统引导无关的时间窗作为浏览基准。这种情况在长期运行的服务器当中较为常见。

大家可以利用–since与–until选项设定时间段,二者分别负责说明给定时间之前与之后的记录。

时间值可以多种格式输出。对于绝对时间值,大家可以使用以下格式:

YYYY-MM-DD HH:MM:SS

例如,我们可以通过以下命令查看全部2015年1月10日下午5:15之后的条目:

journalctl --since "2015-01-10 17:15:00"

如果以上格式中的某些组成部分未进行填写,系统会直接进行默认填充。例如,如果日期部分未填写,则会直接显示当前日期。如果时间部分未填写,则缺省使用“00:00:00”(午夜)。第二字段亦可留空,默认值为“00”:

journalctl --since "2015-01-10" --until "2015-01-11 03:00"

另外,journal还能够理解部分相对值及命名简写。例如,大家可以使用“yesterday”、“today”、“tomorrow”或者“now”等表达。另外,我们也可以使用“-”或者“+”设定相对值,或者使用“ago”之前的表达。

获取昨天数据的命令如下:

journalctl –since yesterday

要获得早9:00到一小时前这段时间内的报告,可使用以下命令:

journalctl --since 09:00 --until "1 hour ago"

如大家所见,时间窗的过滤机制非常灵活且易用。

  • 按信息类型过滤

现在我们要探讨如何利用感兴趣的服务或者组件类型实现过滤。Systemd journal同样提供多种方式供大家选择。

  • 按单元

最常用的此类过滤方式当数按单元过滤了。我们可以使用-u选项实现这一效果。

例如,要查看系统上全部来自Nginx单元的日志,可使用以下命令:

journalctl -u nginx.service

一般来讲,我们可能需要同时按单元与时间进行信息过滤。例如,检查今天某项服务的运行状态:

journalctl -u nginx.service --since today

我们还可以充分发挥journal查看多种单元信息的优势。例如,如果我们的Nginx进程接入某个PHP-FPM单元以处理动态内容,则可将这两个单元合并并获取按时间排序的查询结果:

journalctl -u nginx.service -u php-fpm.service --since today

这种能力对于不同程序间交互及系统调试显然非常重要。

  • 按进程、用户或者群组ID

由于某些服务当中包含多个子进程,因此如果我们希望通过进程ID实现查询,也可以使用相关过滤机制。

这里需要指定_PID字段。例如,如果PID为8088,则可输入:

journalctl _PID=8088

有时候我们可能希望显示全部来自特定用户或者群组的日志条目,这就需要使用_UID或者_GID。例如,如果大家的Web服务器运行在www-data用户下,则可这样找到该用户ID:

id -u www-data

33

接下来,我们可以使用该ID返回过滤后的journal结果:

journalctl _UID=33 --since today

Systemd journal拥有多种可实现过滤功能的字段。其中一些来自被记录的进程,有些则由journald用于自系统中收集特定时间段内的日志。

之前提到的_PID属于后一种。Journal会自动记录并检索进程PID,以备日后过滤之用。大家可以查看当前全部可用journal字段:

man systemd.journal-fields

下面来看针对这些字段的过滤机制。-F选项可用于显示特定journal字段内的全部可用值。

例如,要查看systemd journal拥有条目的群组ID,可使用以下命令:

journalctl -F _GID

32
99
102
133
81
84
100
0
124
87

其将显示全部journal已经存储至群组ID字段内的值,并可用于未来的过滤需求。

  • 按组件路径

我们也可以提供路径位置以实现过滤。

如果该路径指向某个可执行文件,则journalctl会显示与该可执行文件相关的全部条目。例如,要找到与bash可执行文件相关的条目:

journalctl /usr/bin/bash

一般来讲,如果某个单元可用于该可执行文件,那么此方法会更为明确且能够提供更好的相关信息(与子进程相关的条目等)。但有时候,这种作法则无法奏效。

  • 显示内核信息

内核信息通常存在于dmesg输出结果中,journal同样可对其进行检索。要只显示此类信息,可添加-k或者–dmesg标记:

journalctl -k

默认情况下,其会显示当前引导环境下的全部内核信息。大家也可以使用常规的引导选择标记对此前的引导记录进行查询。例如,要查询五次之前引导环境的信息:

journalctl -k -b -5
  • 按优先级

管理员们可能感兴趣的另一种过滤机制为信息优先级。尽管以更为详尽的方式查看日志也很有必要,不过在理解现有信息时,低优先级日志往往会分散我们的注意力并导致理解混乱。

大家可以使用journalctl配合-p选项显示特定优先级的信息,从而过滤掉优先级较低的信息。

例如,只显示错误级别或者更高的日志条目:

journalctl -p err -b

这将只显示被标记为错误、严重、警告或者紧急级别的信息。Journal的这种实现方式与标准syslog信息在级别上是一致的。大家可以使用优先级名称或者其相关量化值。以下各数字为由最高到最低优先级:

0: emerg
1: alert
2: crit
3: err
4: warning
5: notice
6: info
7: debug

以上为可在-p选项中使用的数字或者名称。选定某一优先级会显示等级与之等同以及更高的信息。

修改journal显示内容

到这里,过滤部分已经介绍完毕。我们也可以使用多种方式对输出结果进行修改,从而调整journalctl的显示内容。

  • 截断或者扩大输出结果

我们可以缩小或者扩大输出结果,从而调整journalctl的显示方式。

在默认情况下,journalctl会在pager内显示各条目,并通过右箭头键访问其信息。

如果大家希望截断输出内容,向其中插入省略号以代表被移除的信息,则可使用–no-full选项:

journalctl --no-full

. . .

Feb 04 20:54:13 journalme sshd[937]: Failed password for root from 83.234.207.60...h2
Feb 04 20:54:13 journalme sshd[937]: Connection closed by 83.234.207.60 [preauth]
Feb 04 20:54:13 journalme sshd[937]: PAM 2 more authentication failures; logname...ot

大家也可以要求其显示全部信息,无论其是否包含不可输出的字符。具体方式为添加-a标记:

journalctl -a
  • 标准输出结果

默认情况下,journalctl会在pager内显示输出结果以便于查阅。如果大家希望利用文本操作工具对数据进行处理,则可能需要使用标准格式。在这种情况下,我们需要使用–no-pager选项:

journalclt --no-pager

这样相关结果即可根据需要被重新定向至磁盘上的文件或者处理工具当中。

  • 输出格式

如果大家需要对journal条目进行处理,则可能需要使用更易使用的格式以简化数据解析工作。幸运的是,journal能够以多种格式进行显示,只须添加-o选项加格式说明即可。

例如,我们可以将journal条目输出为JSON格式:

journalctl -b -u nginx -o json

{ "__CURSOR" : "s=13a21661cf4948289c63075db6c25c00;i=116f1;b=81b58db8fd9046ab9f847ddb82a2fa2d;m=19f0daa;t=50e33c33587ae;x=e307daadb4858635", "__REALTIME_TIMESTAMP" : "1422990364739502", "__MONOTONIC_TIMESTAMP" : "27200938", "_BOOT_ID" : "81b58db8fd9046ab9f847ddb82a2fa2d", "PRIORITY" : "6", "_UID" : "0", "_GID" : "0", "_CAP_EFFECTIVE" : "3fffffffff", "_MACHINE_ID" : "752737531a9d1a9c1e3cb52a4ab967ee", "_HOSTNAME" : "desktop", "SYSLOG_FACILITY" : "3", "CODE_FILE" : "src/core/unit.c", "CODE_LINE" : "1402", "CODE_FUNCTION" : "unit_status_log_starting_stopping_reloading", "SYSLOG_IDENTIFIER" : "systemd", "MESSAGE_ID" : "7d4958e842da4a758f6c1cdc7b36dcc5", "_TRANSPORT" : "journal", "_PID" : "1", "_COMM" : "systemd", "_EXE" : "/usr/lib/systemd/systemd", "_CMDLINE" : "/usr/lib/systemd/systemd", "_SYSTEMD_CGROUP" : "/", "UNIT" : "nginx.service", "MESSAGE" : "Starting A high performance web server and a reverse proxy server...", "_SOURCE_REALTIME_TIMESTAMP" : "1422990364737973" }

. . .

这种方式对于工具解析非常重要。大家也可以使用json-pretty格式以更好地处理数据结构:

journalctl -b -u nginx -o json-pretty

{
"__CURSOR" : "s=13a21661cf4948289c63075db6c25c00;i=116f1;b=81b58db8fd9046ab9f847ddb82a2fa2d;m=19f0daa;t=50e33c33587ae;x=e307daadb4858635",
"__REALTIME_TIMESTAMP" : "1422990364739502",
"__MONOTONIC_TIMESTAMP" : "27200938",
"_BOOT_ID" : "81b58db8fd9046ab9f847ddb82a2fa2d",
"PRIORITY" : "6",
"_UID" : "0",
"_GID" : "0",
"_CAP_EFFECTIVE" : "3fffffffff",
"_MACHINE_ID" : "752737531a9d1a9c1e3cb52a4ab967ee",
"_HOSTNAME" : "desktop",
"SYSLOG_FACILITY" : "3",
"CODE_FILE" : "src/core/unit.c",
"CODE_LINE" : "1402",
"CODE_FUNCTION" : "unit_status_log_starting_stopping_reloading",
"SYSLOG_IDENTIFIER" : "systemd",
"MESSAGE_ID" : "7d4958e842da4a758f6c1cdc7b36dcc5",
"_TRANSPORT" : "journal",
"_PID" : "1",
"_COMM" : "systemd",
"_EXE" : "/usr/lib/systemd/systemd",
"_CMDLINE" : "/usr/lib/systemd/systemd",
"_SYSTEMD_CGROUP" : "/",
"UNIT" : "nginx.service",
"MESSAGE" : "Starting A high performance web server and a reverse proxy server...",
"_SOURCE_REALTIME_TIMESTAMP" : "1422990364737973"
}

. . .

以下为可用于显示的各类格式:

cat: 只显示信息字段本身。
export: 适合传输或备份的二进制格式。
json: 标准JSON,每行一个条目。
json-pretty: JSON格式,适合人类阅读习惯。
json-sse: JSON格式,经过打包以兼容server-sent事件。
short: 默认syslog类输出格式。
short-iso: 默认格式,强调显示ISO 8601挂钟时间戳。
short-monotonic: 默认格式,提供普通时间戳。
short-precise: 默认格式,提供微秒级精度。
verbose: 显示该条目的全部可用journal字段,包括通常被内部隐藏的字段。

这些选项允许大家以最适合需求的格式显示journal条目。

活动进程监控

Journalctl命令还能够帮助管理员以类似于tail的方式监控活动或近期进程。这项功能内置于journalctl当中,允许大家在无需借助其它工具的前提下实现访问。

  • 显示近期日志

要显示特定数量的记录,大家可以使用-n选项,具体方式为tail -n。

默认情况下,其会显示最近十条记录:

journalctl -n

大家可以在-n之后指定要查看的条目数量:

journalctl -n 20
  • 追踪日志

要主动追踪当前正在编写的日志,大家可以使用-f标记。方式同样为tail -f:

journalctl -f

Journal维护

存储这么多数据当然会带来巨大压力,因此我们还需要了解如何清理部分陈旧日志以释放存储空间。

  • 了解现有磁盘使用量

大家可以利用–disk-usage标记查看journal的当前磁盘使用量:

journalctl --disk-usage

Journals take up 8.0M on disk.
  • 删除旧有日志

如果大家打算对journal记录进行清理,则可使用两种不同方式(适用于systemd 218及更高版本)。

如果使用–vacuum-size选项,则可硬性指定日志的总体体积,意味着其会不断删除旧有记录直到所占容量符合要求:

sudo journalctl --vacuum-size=1G

另一种方式则是使用–vacuum-time选项。任何早于这一时间点的条目都将被删除。

例如,去年之后的条目才能保留:

sudo journalctl --vacuum-time=1years
  • 限定Journal扩展

大家可以配置自己的服务器以限定journal所能占用的最高容量。要实现这一点,我们需要编辑/etc/systemd/journald.conf文件。

以下条目可用于限定journal体积的膨胀速度:

SystemMaxUse=: 指定journal所能使用的最高持久存储容量。
SystemKeepFree=: 指定journal在添加新条目时需要保留的剩余空间。
SystemMaxFileSize=: 控制单一journal文件大小,符合要求方可被转为持久存储。
RuntimeMaxUse=: 指定易失性存储中的最大可用磁盘容量(/run文件系统之内)。
RuntimeKeepFree=: 指定向易失性存储内写入数据时为其它应用保留的空间量(/run文件系统之内)。
RuntimeMaxFileSize=: 指定单一journal文件可占用的最大易失性存储容量(/run文件系统之内)。

通过设置上述值,大家可以控制journald对服务器空间的消耗及保留方式。

总结

到这里,systemd journal对系统及应用数据的收集与管理机制就介绍完毕了。其出色的灵活性源自将广泛的元数据自动记录至集中化日志之内。另外,journalctl命令则显著简化了journal的使用方式,从而让更多管理员得以利用它完成面向不同应用组件的分析与相关调试工作。

使用 systemd 限制系统资源的使用

简单介绍

在基于 Linux-3.x 内核版本的很多发行版都提供了 Systemd 来管理系统和服务. 同时也将 cgroup 功能加到了 slice, scope 和 service 三个单元中, 详见 sec-Default_Cgroup_Hierarchies. 基于这些特性我们可以很方便的通过 systemd 来限制服务或者进程对系统资源的使用, 这在单主机多服务的场景下会很有用. 下面则以 MySQL 服务为例介绍如何使用 systemd 限制资源的使用, 其它服务的限制和此等同.

示例使用

以 Centos7 系统为例, 从 redhat-resource-control 的文档来看, 官方建议通过 service 来实现资源的限制, 所以这里我们增加可以带端口参数(如果单台主机有多个 MySQL 实例的话)启动的 mysql 服务:

# cat /usr/lib/systemd/system/mysql@.service                                   
[Unit]
Description=MySQL Server node%i

[Service]
Type=forking
Environment="PORT_ARGS=%I"
PermissionsStartOnly=true
ExecStart=/usr/local/mysqlnode/bin/node ${PORT_ARGS} start
ExecStop=/usr/local/mysqlnode/bin/node ${PORT_ARGS} stop

[Install]
WantedBy=multi-user.target

上述服务以 fork 方式启动服务, @ 符号之后的端口号即为相应的端口参数, 启动后查看对应服务状态:

# systemctl start mysql@3327 
# systemctl status mysql@3327
● mysql@3327.service - MySQL Server node3327
   Loaded: loaded (/usr/lib/systemd/system/mysql@.service; disabled; vendor preset: disabled)
   Active: active (running) since Fri 2018-12-07 21:31:32 CST; 4s ago
  Process: 58084 ExecStart=/usr/local/mysqlnode/bin/node ${PORT_ARGS} start (code=exited, status=0/SUCCESS)
 Main PID: 58159 (mysqld_safe)
   CGroup: /system.slice/system-mysql.slice/mysql@3327.service
           ├─58159 /bin/sh /opt/Percona-Server-5.6.38-rel83.0-Linux.x86_64.ssl101//bin/mysqld_safe --defaults-file=/export/mysql/node3327/my.node.cnf
           ├─59489 /opt/Percona-Server-5.6.38-rel83.0-Linux.x86_64.ssl101/bin/mysqld --defaults-file=/export/mysql/node3327/my.node.cnf --basedir=/opt/Percona-Server-5.6.38-rel83.0-Linux.x86_64.ssl101 --datadir=/export/mysql/node3327/...
           └─59490 logger -t mysqld-3327 -p daemon.error

通过 systemd 增加 cgroup 限制,可以一次设置单项属性值, 也可以一次设置多项:

# systemctl set-property mysql@3327.service MemoryLimit=5G       # 5G 内存
# systemctl set-property mysql@3327.service CPUQuota=150%        # 150% cpu 使用率
# systemctl set-property mysql@3327.service BlockIOWeight=1000   # IO 权重

# systemctl status mysql@3327
● mysql@3327.service - MySQL Server node3327
   Loaded: loaded (/usr/lib/systemd/system/mysql@.service; disabled; vendor preset: disabled)
  Drop-In: /etc/systemd/system/mysql@3327.service.d
           └─50-MemoryLimit.conf
   Active: active (running) since Fri 2018-12-07 21:31:32 CST; 1min 18s ago
  Process: 58084 ExecStart=/usr/local/mysqlnode/bin/node ${PORT_ARGS} start (code=exited, status=0/SUCCESS)
 Main PID: 58159 (mysqld_safe)
   Memory: 1.3M (limit: 5G)            # 内存限制 5G
   CGroup: /system.slice/system-mysql.slice/mysql@3327.service
           ├─58159 /bin/sh /opt/Percona-Server-5.6.38-rel83.0-Linux.x86_64.ssl101//bin/mysqld_safe --defaults-file=/export/mysql/node3327/my.node.cnf
           ├─59489 /opt/Percona-Server-5.6.38-rel83.0-Linux.x86_64.ssl101/bin/mysqld --defaults-file=/export/mysql/node3327/my.node.cnf --basedir=/opt/Percona-Server-5.6.38-rel83.0-Linux.x86_64.ssl101 --datadir=/export/mysql/node3327/...
           └─59490 logger -t mysqld-3327 -p daemon.error

更多属性参见 man systemd.resource-control, 不过一些参数没有对应的属性, 需要手动单独设置, 比如设置单独某个服务的 memory + swap 限制, 可以使用以下命令将限制的字节数写到对应的参数文件中:

echo xxxxxx > memory.memsw.limit_in_bytes

查看 MySQL 进程 cgroup 信息, 可以看到 memory, blkid, cpuacct 三个条目对应的信息:

# cat /proc/59489/cgroup 
11:memory:/system.slice/system-mysql.slice/mysql@3327.service
10:devices:/system.slice/system-mysql.slice
9:cpuset:/
8:blkio:/system.slice/system-mysql.slice/mysql@3327.service
7:perf_event:/
6:hugetlb:/
5:freezer:/
4:cpuacct,cpu:/system.slice/system-mysql.slice
3:pids:/system.slice/system-mysql.slice
2:net_prio,net_cls:/
1:name=systemd:/system.slice/system-mysql.slice/mysql@3327.service

查看进程相关的限制值:

# cat /sys/fs/cgroup/memory/system.slice/system-mysql.slice/mysql@3327.service/memory.limit_in_bytes 
5368709120

# cat /sys/fs/cgroup/blkio/system.slice/system-mysql.slice/mysql@3327.service/blkio.weight
1000

# cat /sys/fs/cgroup/cpu/system.slice/system-mysql.slice/mysql@3327.service/cpu.cfs_quota_us 
150000

简单验证

这里仅以不同的 CPUQuota 为例说明, 如下所示可以看到, MySQL 进程在不同 CPUQuota 限制下的不同表现, benchyou 的压测结果也相差较大.

限制进程 CPUQuota 为 150% 的情况下:

# top -p 59489
   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                                           
 59489 mysql     20   0 3412052 1.468g   8784 S 149.5  2.3   7:08.22 mysqld

# benchyou --oltp-tables-count=256 --read-threads=30 --update-threads 8 --write-threads 6 --delete-threads=5 --mysql-table-engine=innodb ..
time            thds              tps     wtps    rtps    rio    rio/op   wio    wio/op    rMB     rKB/op    wMB     wKB/op   cpu/op  freeMB  cacheMB   w-rsp(ms)  r-rsp(ms)    total-number
[13s]        [r:30,w:6,u:8,d:5]  3323     304     3019    0      0.00     0      0.00      0.00    0.00      0.00    0.00     0.00    0       0         62.56      9.92         40765

time            thds              tps     wtps    rtps    rio    rio/op   wio    wio/op    rMB     rKB/op    wMB     wKB/op   cpu/op  freeMB  cacheMB   w-rsp(ms)  r-rsp(ms)    total-number
[14s]        [r:30,w:6,u:8,d:5]  3319     325     2994    0      0.00     0      0.00      0.00    0.00      0.00    0.00     0.00    0       0         57.21      9.99         44084

限制进程 CPUQuota 为 400% 情况下:

# top -p 59489
   PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                                           
 59489 mysql     20   0 3416472 1.474g   8796 S 400.0  2.4   7:47.42 mysqld 


# benchyou --oltp-tables-count=256 --read-threads=30 --update-threads 8 --write-threads 6 --delete-threads=5 --mysql-table-engine=innodb ..
time            thds              tps     wtps    rtps    rio    rio/op   wio    wio/op    rMB     rKB/op    wMB     wKB/op   cpu/op  freeMB  cacheMB   w-rsp(ms)  r-rsp(ms)    total-number
[10s]        [r:30,w:6,u:8,d:5]  10547    967     9580    0      0.00     0      0.00      0.00    0.00      0.00    0.00     0.00    0       0         19.49      3.12         96270

time            thds              tps     wtps    rtps    rio    rio/op   wio    wio/op    rMB     rKB/op    wMB     wKB/op   cpu/op  freeMB  cacheMB   w-rsp(ms)  r-rsp(ms)    total-number
[11s]        [r:30,w:6,u:8,d:5]  10829    1036    9793    0      0.00     0      0.00      0.00    0.00      0.00    0.00     0.00    0       0         18.23      3.04         107099

会话级别限制

如果没有以 service 启动, 可以按照 pid 查看会话级别的信息:

# systemctl status 303   # 303 为 mysql 进程 id
● session-31208.scope - Session 31208 of user root

session-31208.scope 即为会话级别的信息, 一个会话可能包含多个 MySQL 进程, 使用上述的 systemctl set-property session-31208.scope XXXX 即可对整个会话的进程进行相关的限制. 当然使用这种方式即是对多个进程总体使用情况的限制.

其它限制

如果要单独限制 1 个进程 id, 则需要借助 libcgroup 提供的工具, 具体的使用同 Centos6 的设置, 不过 Centos7 已经弃用了 libgcgroup-tools, 不再建议使用, 如果要对单独进程进行限制, 最好使用 service 进行启动. 另外从 systemd 提供的 ControlGroupInterface 来看, 其提供的控制选项还不够精细, 比如没有 memsw, cpuset 等设置的属性, 这种情况下如果有限制的需求, 还需要靠和以前一样的 libcgroup-tool 方式来设置, 比如以下设置, 限制 pid 为 59489 的进程仅使用 cpu 0 ~ 5, mem 可以是 cpu node0 或 node1, cgclassify 没有指定 --sticky 选项的话则 tasks 会包含指定进程的子进程信息:

# cgcreate -g  cpuset:mysql@3327.service
# cgset -r cpuset.cpus=0-5 mysql@3327.service
# cgset -r cpuset.mems=0-1 mysql@3327.service
# cgclassify -g cpuset:mysql@3327.service 59489

当然也可以使用红帽知识库的方式在启动进程的时候就限制相应的 cpuset 等选项, 详见 redhat-1445073

centos7 配置 uwsgi 系统服务(systemd)

背景生产环境中采用nginx + uwsgi + django 来部署web服务,这里需要实现uwsgi的启动和停止,简单的处理方式可以直接在命令行中启动和kill掉uwsgi服务,但为了更安全、方便的管理uwsgi服务,配置uwsgi到systemd服务中,同时实现开启自启的功能;
另,鉴于supervisor不支持python3,没采用supervisor来管理uwsgi服务;

具体配置方法如下:

step1. 创建配置文件

/etc/systemd/system/server_uwsgi.service

step2. 填入以下内容

[Unit]
Description=HTTP Interface Server
After=syslog.target

[Service]
KillSignal=SIGQUIT
ExecStart=/usr/bin/uwsgi --ini /path/uwsgi.ini
Restart=always
Type=notify
NotifyAccess=all
StandardError=syslog

[Install]
WantedBy=multi-user.target

step3. 将该服务加入到systemd中

systemctl enable /etc/systemd/system/server_uwsgi.service

然后就可以通过systemctl来控制服务的启停

systemctl stop server_uwsgi.service 关闭uwsgi服务
systemctl start server_uwsgi.service 开启uwsgi服务
systemctl restart server_uwsgi.service 重启uwsgi服务

注意事项:

如果uwsgi配置文件中配置了 daemonize=/path/uwsgi.log (uwsgi服务以守护进程运行)
会导致sytemctl启动时多次重启而导致启动失败
需改为 logto=/path/uwsgi.log

Linux CentOS 6.5 yum安装MongoDB的操作

安装mongodb-3.6.4版本

执行命令

wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel62-3.6.4.tgz

如果出现错误,则在root下更新wget,执行

yum upgrade wget

再去执行以上wget命令即可。

下载完成后,进行解压

tar -zxvf mongodb-linux-x86_64-rhel62-3.6.4.tgz

如果嫌解压后文件名称过长,可以进行重命名

mv mongodb-linux-x86_64-rhel62-3.6.4 mongodb

进入到mongodb目录下

cd mongodb

创建db和日志目录

mkdir data
mkdir -p data/db
mkdir -p data/logs

在logs目录下创建mongodb.log文件

touch mongodb.log

在data目录下创建mongodb.conf文件

cd mongodb/data
vi mongodb.conf
port=8087

dbpath=/opt/mongodb/mongodb/data/db

logpath=/opt/mongodb/mongodb/data/logs/mongodb.log

fork=true

logappend=true

启动

在mongodb目录下执行

./bin/mongod --config /opt/mongodb/mongodb/data/mongodb.conf

可以看到以下内容:

未分类

进入到mongodb进行操作

./bin/mongo

无法连接 127.0.01:27017,经过分析,是防火墙端口没有开放。

未分类

可以看到有很多警告信息,没有关系,因为接下来要创建用户,mongodb默认情况下没有用户,需要创建,授权。

> use admin
switched to db admin
> db.system.users.find();

没有任何输出,这时则创建用户,我创建的是一个超级用户

db.createUser(
... {
... user:"root",
... pwd:"554466",
... roles:[{role:"root",db:"admin"}]
... }
... )
Successfully added user: {
    "user" : "root",
    "roles" : [
        {
            "role" : "root",
            "db" : "admin"
        }
    ]

}

然后关闭mongodb,执行命令db.shutdownServer();

exit;退出mongodb客户端,重新编辑配置文件vi data/mongodb.conf

加入一行auth=true,保存退出,再次启动mongodb,此时就不会出现警告信息,进入客户端,进行用户验证。

未分类

CentOS部署部署Edusoho

关闭SELINUX

sudo vi /etc/selinux/config

将内容修改为以下信息:

# SELINUX=enforcing # 禁用该配置
# SELINUXTYPE=targeted # 禁用该配置
SELINUX=disabled # 禁用该配置

修改配置后执行以下命令使其配置生效:

setenforce 0

安装 apache 和 xsendfile 依赖

yum install httpd
rpm -ivh http://dl.fedoraproject.org/pub/epel/7/x86_64/m/mod_xsendfile-0.12-10.el7.x86_64.rpm

注意:如果安装的时候,提示与httpd版本不匹配,依赖不足,可以到http://mirrors.opencas.cn/epel 查找合适的安装源

安装PHP和相关插件

yum install -y php php-cli php-curl php-fpm php-intl php-mcrypt php-mysql php-gd php-mbstring php-xml php-dom

修改PHP配置

vim /etc/php.ini

将以下配置参数进行修改:

post_max_size = 1024M             # 672 行
memory_limit = 1024M              # 405 行
upload_max_filesize = 1024M       # 800 行

修改PHP-FPM配置

sudo vi /etc/php-fpm.d/www.conf

添加以下配置参数:

listen.owner = apache
listen.group = apache
listen.mode = 0666

设置PHP-FPM启动脚本

sudo systemctl start php-fpm    # 启动php-fpm
sudo systemctl enable php-fpm   # 开机启动php-fpm

下载安装edusoho

wget http://download.edusoho.com/edusoho-VERSION.tar.gz  (注:将VERSION替换为当前EduSoho最新版本号,可从官网www.edusoho.com查询获取)
tar zxvf edusoho-VERSION.tar.gz
cp -r edusoho /var/www
cd /var/www && sudo chown -R apache:apache ./

创建配置edusoho

sudo vi /etc/httpd/conf.d/edusoho.conf

在文件中添加以下内容:

<VirtualHost *:80>
    ServerName mooc.ttxit.com
    ServerAlias mooc.ttxit.com

    DocumentRoot /edu/edusoho/web
    <Directory /edu/edusoho/web>
        # enable the .htaccess rewrites
        AllowOverride All
        Order allow,deny
        Allow from All
    </Directory>
    ErrorLog /var/log/edusoho_error.log
    CustomLog /var/log/edusoho_access.log combined
</VirtualHost>

配置启动apache服务

sudo systemctl start httpd    # 启动apache
sudo systemctl enable httpd   # 开机启动apache

在Centos 7上使用rclone挂载OneDrive网盘

前期准备

客户端授权

在本地Windows电脑上下载rclone,下载地址:https://rclone.org/downloads/ 。然后解压出来,进入cmd,输入以下命令:

rclone authorize "onedrive"

之后会弹出窗口认证,然后复制token

Paste the following into your remote machine --->
{"access_token":"xxxx"}  #请复制{xx}整个内容(包括花括号),后面需要用到
<---End paste

安装fuse

在服务器上安装fuse,在挂载时会用到

yum install fuse

安装rclone

安装

curl https://rclone.org/install.sh | sudo bash

初始化配置

rclone config

No remotes found - make a new one
n) New remote
s) Set configuration password
q) Quit config
n/s/q> n
name> Spirit #随便填
Type of storage to configure.
Enter a string value. Press Enter for the default ("").
Choose a number from below, or type in your own value
 1 / A stackable unification remote, which can appear to merge the contents of several remotes
    "union"
 2 / Alias for a existing remote
    "alias"
 3 / Amazon Drive
    "amazon cloud drive"
 4 / Amazon S3 Compliant Storage Provider (AWS, Alibaba, Ceph, Digital Ocean, Dreamhost, IBM COS, Minio, etc)
    "s3"
 5 / Backblaze B2
    "b2"
 6 / Box
    "box"
 7 / Cache a remote
    "cache"
 8 / Dropbox
    "dropbox"
 9 / Encrypt/Decrypt a remote
    "crypt"
10 / FTP Connection
    "ftp"
11 / Google Cloud Storage (this is not Google Drive)
    "google cloud storage"
12 / Google Drive
    "drive"
13 / Hubic
    "hubic"
14 / JottaCloud
    "jottacloud"
15 / Local Disk
    "local"
16 / Mega
    "mega"
17 / Microsoft Azure Blob Storage
    "azureblob"
18 / Microsoft OneDrive
    "onedrive"
19 / OpenDrive
    "opendrive"
20 / Openstack Swift (Rackspace Cloud Files, Memset Memstore, OVH)
    "swift"
21 / Pcloud
    "pcloud"
22 / QingCloud Object Storage
    "qingstor"
23 / SSH/SFTP Connection
    "sftp"
24 / Webdav
    "webdav"
25 / Yandex Disk
    "yandex"
26 / http Connection
    "http"
Storage> 18 #选择18,Microsoft OneDrive
** See help for onedrive backend at: https://rclone.org/onedrive/ **

Microsoft App Client Id
Leave blank normally.
Enter a string value. Press Enter for the default ("").
client_id> #留空
Microsoft App Client Secret
Leave blank normally.
Enter a string value. Press Enter for the default ("").
client_secret> #留空
Edit advanced config? (y/n)
y) Yes
n) No
y/n> n
Remote config
Use auto config?
 * Say Y if not sure
 * Say N if you are working on a remote or headless machine
y) Yes
n) No
y/n> n  #选择n
For this to work, you will need rclone available on a machine that has a web browser available.
Execute the following on your machine:
    rclone authorize "onedrive"
Then paste the result below:
result> {"access_token":""}  #输入之前在客户端授权的内容
--------------------
Choose a number from below, or type in an existing value
 1 / OneDrive Personal or Business
    "onedrive"
 2 / Root Sharepoint site
    "sharepoint"
 3 / Type in driveID
    "driveid"
 4 / Type in SiteID
    "siteid"
 5 / Search a Sharepoint site
    "search"
Your choice> 1 #选择1
--------------------
y) Yes this is OK
e) Edit this remote
d) Delete this remote
y/e/d> y  #选择y
Current remotes:

Name                 Type
====                 ====
Spirit                 onedrive

e) Edit existing remote
n) New remote
d) Delete remote
r) Rename remote
c) Copy remote
s) Set configuration password
q) Quit config
e/n/d/r/c/s/q> q  #选择q退出

挂载

rclone mount Spirit:Wallpapers /mnt/3/ --copy-links --no-gzip-encoding --no-check-certificate --allow-other --allow-non-empty --umask 000

Spirit为初始化配置填的nameWallpapers为OneDrive里的文件夹,/mnt/3/为VPS上的本地文件夹

卸载

fusermount -qzu /mnt/3/

设置开机自启

下载脚本

wget -N --no-check-certificate https://raw.githubusercontent.com/x91270/Centos/master/rcloned

修改一下内容

vim rcloned
NAME=""  #rclone name名,及配置时输入的Name
REMOTE=''  #远程文件夹,OneDrive 网盘里的挂载的一个文件夹
LOCAL=''  #挂载地址,VPS本地挂载目录

设置自启

mv rcloned /etc/init.d/rcloned
chmod +x /etc/init.d/rcloned
chkconfig rcloned on
bash /etc/init.d/rcloned start

CentOS 7安装Deluge

未分类

Deluge 支持 Linux (Debian, Fedora, OpenSUSE, Arch, Gentoo )、Win、Mac、FreeBSD 多个平台,非常稳定,而且支持单一种子限速功能。部分 PT 站会对单一种子的速度有限制,如果超速,账号可能会被警告甚至封禁。如果挂的PT站有限速要求,推荐使用Deluge。比较遗憾的是,Deluge没有官方的CentOS源。如果需要在CentOS安装,可尝试下第三方的源。

Deluge 有 GUI for the desktop,Web UI for the browser 和 Console UI for the command line 三个 interfaces,这里安装的是 Web UI for the browser,可以通过浏览器管理 Deluge。

Delgue 在 NUX 源中,因而安装需要添加 NUX。部分依赖包需要 EPEL 源,如果没有安装 EPEL 源,也需要添加。

# 安装 EPEL 源
yum -y install epel-release
# 安装 NUX 源
yum -y install wget
wget http://li.nux.ro/download/nux/dextop/el7/x86_64/nux-dextop-release-0-5.el7.nux.noarch.rpm
rpm -ivh nux-dextop-release-0-5.el7.nux.noarch.rpm

添加源后,接着安装 Deluge:

yum -y install deluge-web

运行

systemctl start deluge-web

访问 http://ip 地址:8112 即可访问 Web 界面。如果开启了防火墙,需要开放 8112 端口:

firewall-cmd --permanent --zone=public --add-port=8112/tcp
firewall-cmd --reload

开机自启动

systemctl enable deluge-web

附带 http://ip 地址:8112,deluge的web页面:

未分类

Ubuntu安装deluge教程可以参考官方:https://dev.deluge-torrent.org/wiki/Installing/Linux/Ubuntu

CentOS 7 安装 PHP 7.2

本文将介绍如何在 CentOS 7 服务器上使用 yum 命令安装 PHP7.2,内容提炼自外文网站,点击查看原文

安装 PHP7.2

安装 EPEL 软件包:

$ sudo yum install epel-release

安装 remi 源:

$ sudo yum install http://rpms.remirepo.net/enterprise/remi-release-7.rpm

安装 yum 扩展包:

$ sudo yum install yum-utils

启用 remi 仓库:

$ sudo yum-config-manager --enable remi-php72
$ sudo yum update

安装 PHP7.2

$ sudo yum install php72

安装 php-fpm 和一些其他模块

$ sudo yum install php72-php-fpm php72-php-gd php72-php-json php72-php-mbstring php72-php-mysqlnd php72-php-xml php72-php-xmlrpc php72-php-opcache

输入 php72 -v 查看安装结果

php-fpm 服务

设置开机自启

$ sudo systemctl enable php72-php-fpm.service

常用 php-fpm 命令

# 开启服务
$ sudo systemctl start php72-php-fpm.service

# 停止服务
$ sudo systemctl stop php72-php-fpm.service

# 查看状态
$ sudo systemctl status php72-php-fpm.service

通过 egrep 查询 nginx 服务器的用户和用户组:

$ egrep '^(user|group)' /etc/nginx/nginx.conf

结果示例:

user nginx;

编辑 /etc/opt/remi/php72/php-fpm.d/www.conf,修改执行 php-fpm 的权限:

$ sudo vi /etc/opt/remi/php72/php-fpm.d/www.conf

设置用户和用户组为 nginx:

user = nginx
group = nginx

保存并关闭文件,重启 php-fpm 服务:

$ sudo systemctl restart php72-php-fpm.service

路径整理

# php 安装路径
/etc/opt/remi/php72

# nginx 配置文件
/etc/nginx/nginx.conf

# nginx 默认项目路径
/usr/share/nginx/html

CentOS简单操作命令及node.js的安装方法

本文实例讲述了CentOS简单操作命令及node.js的安装方法。分享给大家供大家参考,具体如下:

查看centos内核的版本:

uname -a

uname -r

查看linux版本:

cat /etc/issue

查看系统是64位还是32位:

getconf LONG_BIT

安装node.js

因为node.js需要Python2.6以上

Note: Python 2.6 or 2.7 is required to build from source tarballs.

查看Python版本

python -V

安装依赖

yum -y install gcc make gcc-c++ openssl-devel wget

下载node.js源码及安装

wget http://nodejs.org/dist/v0.12.0/node-v0.12.0.tar.gz

tar -zxf node-v0.12.0.tar.gz

cd node-v0.12.0

./configure && make && make install