进程启动顺序问题

背景:

Java进程A使用lpop从Redis中的队列弹出消息,并对消息进行处理。

Java进程B使用rpush向Redis队列中压入消息。

现象:服务器重启后,进程B向Redis队列中压入消息后,进程A并不会取出消息并处理。此问题,仅在服务器重启后发生。

分析:

1.通过命令行redis-cli登入Redis,查看队列,发现队列中确实成功压入了消息,排除进程B的问题。

2.查看进程A日志,在进程B压入消息后,日志中并没有错误打印。

3.为了尽快恢复程序运行,尝试重启A进程,发现,重启后进程A变得完全正常。

4.因为能够确认,进程B向Redis压入消息,是成功的,只是进程A无法从队列中取出消息,那么可以肯定,进程A与Redis之间肯定是出了问题。

5.怀疑进程A与Redis连接是有问题的,查看之前的日志,找到进程A启动时的日志,发现启动后日志中打印了不少获取Redis连接失败的错误。

6.问题只出现在服务器重启后,那即是说:服务器开机后,进程A自动启动,但是Redis连接池初始化却是失败的。

7.怀疑进程A启动时,Redis服务还没有启动,即启动顺序出现了问题。

8.查看Redis启动日志,使用命令systemctl status redis,发现redis启动成功并准备好接收连接的时间,确实是在进程A启动之后。这里有一个点:redis连接池,并不能向c3p0数据库连接池一样,支持自动重连机制,即连接池初始化失败了,以后就再也不能恢复了。

9.查看进程A的系统服务配置,使用命令vim /usr/lib/systemd/system/xxx_a.service,如下图:

在图中可以看到,我们通过Requires配置了,进程A是依赖于redis的,但好像仅是这样配置,还不能使进程A在redis之后启动,这是为何?

去查找资料,发现有如下解释:

AfterBefore字段只涉及启动顺序,不涉及依赖关系。

Wants字段与Requires字段只涉及依赖关系,与启动顺序无关,默认情况下是同时启动的。

通过如上解释可知,必须要使用After或Before才可以控制启动顺序。

所以,在进程A的service配置文件中添加After配置,结果如下图:

10.重启服务器验证,问题解决。

猜你喜欢

转载自www.cnblogs.com/sybblogs/p/9296387.html