联系我们
18591797788
hubin@rlctech.com
北京市海淀区中关村南大街乙12号院天作国际B座1708室
18681942657
lvyuan@rlctech.com
上海市浦东新区商城路660号乐凯大厦26c-1
18049488781
xieyi@rlctech.com
广州市越秀区东风东路华宫大厦808号1608房
029-81109312
service@rlctech.com
西安市高新区天谷七路996号西安国家数字出版基地C座501
OceanBase云平台(OCP)作为OceanBase分布式数据库的全生命周期综合运维管理平台,其核心服务以Java进程形式运行在容器环境中,这带来了进程稳定性、高可用性和自动化运维的全新需求。本文通过分析,展示OCP容器中Supervisor的进程守护机制。
OCP 云平台的本质是一个运行在容器中的Java进程,具体表现为 ocp-server-4.4.1-20260212105850.jar 这样的 jar 包执行体。
在容器环境中,该Java进程通过特定的JVM参数配置运行,以满足企业级应用对性能和稳定性的高要求。
# 登录 ocp 容器# docker exec -it ocp sh# 查看容器中的JAVA进程# ps -ef|grep -v grep|grep javaadmin 12 133 2.3 745050368 25132288 ? Sl 14:51 5:16 /usr/lib/jvm/java-17/bin/java-server -XX:+UseZGC -Xms14336m -Xmx14336m -Xss512k -XX:MetaspaceSize=1024m -XX:MaxMetaspaceSize=1024m-Xlog:gc*,gc+stats=off,safepoint=off:file=/home/admin/ocp-server/bin/../log/gc.log:time:filecount=2,filesize=50M-XX:+ExitOnOutOfMemoryError -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home/admin/ocp-server/bin/../log/-Dfile.encoding=UTF-8--add-exports=java.xml/jdk.xml.internal=ALL-UNNAMED--add-opens=java.base/java.io=ALL-UNNAMED--add-opens=java.base/java.lang.reflect=ALL-UNNAMED--add-opens=java.base/java.lang=ALL-UNNAMED--add-opens=java.base/java.math=ALL-UNNAMED--add-opens=java.base/java.net=ALL-UNNAMED--add-opens=java.base/java.nio.charset=ALL-UNNAMED--add-opens=java.base/java.nio=ALL-UNNAMED--add-opens=java.base/java.nio.file=ALL-UNNAMED--add-opens=java.base/java.security=ALL-UNNAMED--add-opens=java.base/java.text=ALL-UNNAMED--add-opens=java.base/java.time.format=ALL-UNNAMED--add-opens=java.base/java.time=ALL-UNNAMED--add-opens=java.base/java.util.concurrent.atomic=ALL-UNNAMED--add-opens=java.base/java.util.concurrent=ALL-UNNAMED--add-opens=java.base/java.util.regex=ALL-UNNAMED--add-opens=java.base/java.util.stream=ALL-UNNAMED--add-opens=java.base/java.util=ALL-UNNAMED--add-opens=java.base/sun.net.www.protocol.https=ALL-UNNAMED--add-opens=java.base/sun.net=ALL-UNNAMED--add-opens=java.base/sun.nio.cs=ALL-UNNAMED--add-opens=java.base/sun.nio.fs=ALL-UNNAMED--add-opens=java.base/sun.security.jca=ALL-UNNAMED--add-opens=java.base/sun.security.ssl=ALL-UNNAMED--add-opens=java.base/sun.security.util=ALL-UNNAMED--add-opens=java.base/jdk.internal.util=ALL-UNNAMED--add-opens=java.logging/java.util.logging=ALL-UNNAMED--add-opens=java.rmi/sun.rmi.transport=ALL-UNNAMED-Daliyun.rass.enabled=false-jar /home/admin/ocp-server/bin/../lib/ocp-server-4.4.1-20260212105850.jar --bootstrap
在传统的物理机或虚拟机部署中,系统服务通常由systemd或init系统管理。然而,在Docker容器环境中,每个容器默认只运行一个前台进程,当这个进程退出时容器也随之终止。对于OCP这样的复杂企业级应用,需要确保其核心Java服务在意外崩溃时能够自动恢复,同时还需要管理可能存在的其他辅助进程。这种需求催生了在容器内部引入进程管理工具的必要性,而Supervisor正是这一场景下的理想选择。
Supervisord 是一个用 Python 编写的进程控制系统,用于在类 Unix 系统(如 Linux)上监控和管理后台进程,确保它们守护的进程在意外退出时自动重启 。
Supervisor 是一个 C/S(客户端/服务器)架构的工具。在此架构中:
supervisord:是服务端(server)守护进程,也是整个系统的核心。它负责启动配置中指定的子进程,响应客户端的命令,监控子进程状态,并在其崩溃或退出时按策略自动重启,同时负责记录子进程的标准输出和错误输出。supervisorctl:是命令行客户端(client)工具,为用户提供了一个与 supervisord 交互的接口。通过它,用户可以查看进程状态、启动、停止、重启进程或重新加载配置文件。Supervisord 的设计宗旨在于简化多进程管理,其主要功能包括:
查看容器中 supervisord 进程信息,发现 supervisord 进程是通过 /usr/bin/supervisord -c /etc/supervisor/supervisord.conf 命令启动而来,其父进程号为 1。
# ps -ef|grep -v grep|grep -i supervisorroot 1 0 0 14:51 ? 00:00:00 /bin/bash -c chmod u+s /usr/sbin/clockdiff; setcap 'cap_net_raw+ep' /usr/sbin/clockdiff; /usr/bin/supervisord -c /etc/supervisor/supervisord.confroot 9 1 0 14:51 ? 00:00:04 /usr/bin/python2 /usr/bin/supervisord -c /etc/supervisor/supervisord.conf
在OCP的容器化部署中,Supervisor被配置为容器的1号进程(PID 1),这意味着它伴随着容器的启动而启动,并负责管理容器内的所有其他进程。通过分析OCP容器的启动命令可以发现,容器入口点是一个包含多个命令的bash脚本,其中最后一步就是启动 supervisord 服务:
# docker ps -f "name=ocp" --no-trunc --format '{{.Names}} {{.Command}}'ocp "/bin/bash -c 'chmod u+s /usr/sbin/clockdiff; setcap 'cap_net_raw+ep' /usr/sbin/clockdiff; /usr/bin/supervisord -c /etc/supervisor/supervisord.conf'"
这种设计确保了Supervisor作为容器生命周期管理器,当它退出时整个容器也会终止,从而实现了对容器内所有进程的统一管控。
# ls -l /etc/supervisor
drwxr-xr-x 2 admin admin 22 2月 12 11:21 conf.d
-rw-r--r-- 1 admin admin 1009 2月 12 11:19 supervisord.conf
# ls -l /etc/supervisor/conf.d/
-rw-r--r-- 1 admin admin 369 2月 12 11:19 ocp.conf
主配置文件(/etc/supervisor/supervisord.conf)定义了Supervisor服务本身的全局设置,包括日志文件路径、PID文件位置、日志级别等关键参数。特别值得注意的是nodaemon = true这一配置,它使supervisord以前台模式运行,这是容器环境中确保supervisord作为1号进程的必要条件。
程序配置文件(/etc/supervisor/conf.d/ocp.conf)专门定义OCP Java进程的管理规则。该配置文件包含了进程名称、启动命令、工作目录、运行用户、日志文件路径等关键信息。确保了OCP进程在意外退出时能够自动重启,这是实现高可用性的核心机制。
# cat /etc/supervisor/supervisord.conf[unix_http_server]file = /dev/supervisor.sock ; (the path to the socket file)[supervisord]logfile = /home/admin/logs/ocp_supervisord.log ; (main log file;default $CWD/supervisord.log)logfile_maxbytes = 50MB ; (max main logfile bytes b4 rotation;default 50MB)logfile_backups = 10 ; (num of main logfile rotation backups;default 10)loglevel = info ; (log level;default info; others: debug,warn,trace)pidfile = /run/supervisord.pid ; (supervisord pidfile;default supervisord.pid)nodaemon = true ; (start in foreground if true;default false)minfds = 1024 ; (min. avail startup file descriptors;default 1024)minprocs = 200 ; (min. avail process descriptors;default 200)[rpcinterface:supervisor]supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface[supervisorctl]serverurl = unix:///dev/supervisor.sock ; use a unix:// URL for a unix socket[include]
# cat /etc/supervisor/conf.d/ocp.conf[program:ocp-server]process_name = %(program_name)s_%(process_num)02d <-- 程序名称:ocp-server:ocp-server_00command = /home/admin/ocp-server/bin/ocp-server --bootstrap <-- ocp 启动命令directory = /home/admin <-- 执行命令前切换的目录user = admin <-- 启动用户numprocs = 1stopsignal=INTkillasgroup = truestdout_logfile = /home/admin/logs/ocp-server.%(process_num)s.outstderr_logfile = /home/admin/logs/ocp-server.%(process_num)s.errredirect_stderr = false
当手动终止OCP的Java进程(kill -9)后,观察发现该进程会被自动重新拉起,且进程ID发生变化。这一现象正是Supervisor的 autorestart 机制在起作用,它持续监控被管理进程的状态,一旦发现进程异常退出,便根据配置策略重新启动该进程。
# kill -9 12 <--- 杀掉ocp进程# ps -ef|grep -v grep|grep java <-- 发现ocp进程重新拉起,进程号由原来的12,变为29796admin 29796 9 99 15:02 ? 00:00:31 /usr/lib/jvm/java-17/bin/java -server -XX:+UseZGC -Xms14336m ...
进一步分析进程关系可以发现,OCP Java进程的父进程正是 supervisord 进程(PID 9),而 supervisord 的父进程是容器的1号进程(PID 1)。这种进程层级关系清晰地展示了Supervisor作为进程管理器的角色定位。
# ps -ef|grep -v grep|grep supervisorroot 1 0 0 14:51 ? 00:00:00 /bin/bash -c chmod u+s /usr/sbin/clockdiff; setcap 'cap_net_raw+ep' /usr/sbin/clockdiff; /usr/bin/supervisord -c /etc/supervisor/supervisord.confroot 9 1 0 14:51 ? 00:00:08 /usr/bin/python2 /usr/bin/supervisord -c /etc/supervisor/supervisord.conf
Supervisor提供了 supervisorctl 命令行工具,能够方便地查看和管理被监控的进程。通过supervisorctl手动停止的进程不会自动重启,这与进程意外崩溃时的自动重启行为形成对比。这种差异化的行为控制为运维操作提供了灵活性,既保证了生产环境的高可用性,又支持了必要的维护操作。
# supervisorctl statusocp-server:ocp-server_00 RUNNING pid 29796, uptime 0:22:49
# supervisorctl stop ocp-server:ocp-server_00ocp-server:ocp-server_00: stopped# supervisorctl statusocp-server:ocp-server_00 STOPPED Mar 05 03:25 PM# ps -ef|grep -v grep|grep java使用supervisorctl停止的进程,不会自动拉起。
ocp 进程启动后,监测 8080 端口,成功监听后,ocp 才能对外提供服务。
# supervisorctl start ocp-server:ocp-server_00ocp-server:ocp-server_00: started# supervisorctl statusocp-server:ocp-server_00 RUNNING pid 101997, uptime 0:00:07# ps -ef|grep -v grep|grep javaadmin 101997 9 99 15:27 ? 00:00:30 /usr/lib/jvm/java-17/bin/java -server -XX:+UseZGC -Xms14336m ...# netstat -tnlp|grep 8080tcp6 0 0 :::8080 :::* LISTEN