前言

最近发现mongodb总是莫名其妙的挂掉,一边查找原因,一边想着如果能自动重启就好了,于是mongodb的自动重启这件事就提上日程了。本来以为最多半小时的事,没想到还是遇到了一些奇妙的问题,为了找原因花费了不少时间。在这里记录一下,以便其他同学避免踩坑。

踩坑历程再现

操作系统:Ubuntu 18.04

建立了一个/lib/systemd/system/mongo.service文件,在文件上写上对应内容

[Unit]
Description=mongodb
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
ExecStart=/dev/usr/mongodb/bin/mongod --dbpath /dev/usr/mongodb/data
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/dev/usr/mongodb/bin/mongod --shutdown --dbpath /dev/usr/mongodb/data
PrivateTmp=true
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

关键就是

Restart=always
RestartSec=5

这两句话,能够在mongodb挂掉之后自动重启。

然后使用

systemctl daemon-reload
systemctl start mongo.service

启动mongodb服务,发现半天没有反应,只能ctrl-c结束掉,感觉不太对劲。

查了一下有数据,本来以为万事大吉,但使用journalctl -xe没有看到错误,但systemctl status mongo.sercice查了一下看输出却显示没有进入running一直是start的状态

● mongo-server.service - mongodb
   Loaded: loaded (/lib/systemd/system/mongo-server.service; enabled; vendor preset: enabled)
   Active: activating (start) since Fri 2021-02-19 14:37:13 CST; 1min 21s ago
  Process: 20076 ExecStop=/dev/usr/mongodb/bin/mongod --shutdown --dbpath /dev/usr/mongodb/data
 Main PID: 18870 (code=exited, status=0/SUCCESS); Control PID: 22030 (mongod)
    Tasks: 24 (limit: 4915)
   CGroup: /system.slice/mongo-server.service
           └─22030 /dev/usr/mongodb/bin/mongod --dbpath /dev/usr/mongodb/data

Feb 19 14:37:14 ecs-ae0d-0006 mongod[22030]: 2021-02-19T14:37:14.220+0800 I CONTROL  [initandlisten] **          Remote systems will be unab
Feb 19 14:37:14 ecs-ae0d-0006 mongod[22030]: 2021-02-19T14:37:14.220+0800 I CONTROL  [initandlisten] **          Start the server with --bin
Feb 19 14:37:14 ecs-ae0d-0006 mongod[22030]: 2021-02-19T14:37:14.220+0800 I CONTROL  [initandlisten] **          addresses it should serve r
Feb 19 14:37:14 ecs-ae0d-0006 mongod[22030]: 2021-02-19T14:37:14.220+0800 I CONTROL  [initandlisten] **          bind to all interfaces. If
Feb 19 14:37:14 ecs-ae0d-0006 mongod[22030]: 2021-02-19T14:37:14.220+0800 I CONTROL  [initandlisten] **          server with --bind_ip 127.0
Feb 19 14:37:14 ecs-ae0d-0006 mongod[22030]: 2021-02-19T14:37:14.220+0800 I CONTROL  [initandlisten]
Feb 19 14:37:14 ecs-ae0d-0006 mongod[22030]: 2021-02-19T14:37:14.222+0800 I FTDC     [initandlisten] Initializing full-time diagnostic data
Feb 19 14:37:14 ecs-ae0d-0006 mongod[22030]: 2021-02-19T14:37:14.223+0800 I NETWORK  [initandlisten] listening via socket bound to 127.0.0.1
Feb 19 14:37:14 ecs-ae0d-0006 mongod[22030]: 2021-02-19T14:37:14.223+0800 I NETWORK  [initandlisten] listening via socket bound to /tmp/mong
Feb 19 14:37:14 ecs-ae0d-0006 mongod[22030]: 2021-02-19T14:37:14.223+0800 I NETWORK  [initandlisten] waiting for connections on port 27017
~

于是开始各种尝试和查询资料,直到将type这个参数删除,终于一切正常了。

再次使用systemctl status mongo.sercice

● mongo-server.service - mongodb
   Loaded: loaded (/lib/systemd/system/mongo-server.service; enabled; vendor preset: enabled)
   Active: active (running) since Fri 2021-02-19 14:41:32 CST; 4s ago
  Process: 22548 ExecStart=/dev/usr/mongodb/bin/mongod --dbpath /dev/usr/mongodb/data --fork --logpath /var/log/mongodb/mongod.log (code=exi
 Main PID: 22557 (mongod)
    Tasks: 24 (limit: 4915)
   CGroup: /system.slice/mongo-server.service
           └─22557 /dev/usr/mongodb/bin/mongod --dbpath /dev/usr/mongodb/data --fork --logpath /var/log/mongodb/mongod.log

Feb 19 14:41:31 ecs-ae0d-0006 systemd[1]: Starting mongodb...
Feb 19 14:41:31 ecs-ae0d-0006 mongod[22548]: about to fork child process, waiting until server is ready for connections.
Feb 19 14:41:31 ecs-ae0d-0006 mongod[22548]: forked process: 22557
Feb 19 14:41:32 ecs-ae0d-0006 mongod[22548]: child process started successfully, parent exiting
Feb 19 14:41:32 ecs-ae0d-0006 systemd[1]: Started mongodb.

找到了type这突破口就简单多了,顺藤摸瓜查了一下type参数的作用和用法,一切真相大白。

正确的配置方式

forking

[Unit]
Description=mongodb
After=network.target remote-fs.target nss-lookup.target

[Service]
Type=forking
ExecStart=/dev/usr/mongodb/bin/mongod --dbpath /dev/usr/mongodb/data --fork --logpath /var/log/mongodb/mongod.log
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/dev/usr/mongodb/bin/mongod --shutdown --dbpath /dev/usr/mongodb/data
PrivateTmp=true
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

simple或不填

[Unit]
Description=mongodb
After=network.target remote-fs.target nss-lookup.target

[Service]
#Type=forking
ExecStart=/dev/usr/mongodb/bin/mongod --dbpath /dev/usr/mongodb/data
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/dev/usr/mongodb/bin/mongod --shutdown --dbpath /dev/usr/mongodb/data
PrivateTmp=true
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

原因分析

这个Type参数的问题看似诡异,甚至好像是bug,其实隐藏着对于systemctl理解不清的问题。

这个Type参数作用是用来标志systemctl是否要跟踪处理服务进程是否启动成功,如果是forking则是需要跟踪对应的MAINPID是否存在,只有检测到MAINPID存在才能确定这个服务启动成功。这就需要保证被启动的那个服务能够按照标准协议来把pid写入对应文件或是进行对应处理。如果是simple或是不填,则systemctl认为这是一般的应用程序,只要启动就能保证成功,而不会去检查对应的服务是否真的执行成功。

这也就解释了两个现象:

  1. 要想把type设置成forking,需要在mongodb的启动选项上使用–fork,又由于有fork则必须带上–logpath
  2. 为什么设置成forking之后要等一会才能运行完sytemctl start指令,因为它要检查是否成功,而simple则一闪而过。

另附type的取值

  • Type:定义启动时的进程行为。它有以下几种值。

  • Type=simple:默认值,执行ExecStart指定的命令,启动主进程

  • Type=forking:以 fork 方式从父进程创建子进程,创建后父进程会立即退出

  • Type=oneshot:一次性进程,Systemd 会等当前服务退出,再继续往下执行

  • Type=dbus:当前服务通过D-Bus启动

  • Type=notify:当前服务启动完毕,会通知Systemd,再继续往下执行

  • Type=idle:若有其他任务执行完毕,当前服务才会运行

参考链接

  1. http://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-commands.html
  2. https://bbs.archlinux.org/viewtopic.php?id=191669
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐