oceanbasev4.0如何设置开机自启用Systemd服务单元文件

【 使用环境 】生产环境
【 OB or 其他组件 】
【 使用版本 】oceanbase-all-in-one-4.3.0.1-100000242024032211.el7.x86_64.tar.gz
【问题描述】清晰明确描述问题
【复现路径】 oceanbase.service - oceanbase
Loaded: loaded (/etc/systemd/system/oceanbase.service; enabled; vendor preset: enabled)
Active: failed (Result: exit-code) since Sat 2024-06-15 15:40:58 CST; 3s ago
Process: 61238 ExecStart=/home/admin/oceanbase-all-in-one/obd/usr/bin/obd cluster start demo (code=exited, status=1/FAILURE)
CPU: 7.944s

6月 15 15:40:57 admin-standardpci440fxpiix1996 obd[61239]: obshell program health check ok
6月 15 15:40:57 admin-standardpci440fxpiix1996 obd[61239]: [ERROR] import connect failed
6月 15 15:40:57 admin-standardpci440fxpiix1996 obd[61239]: See OceanBase分布式数据库-海量数据 笔笔算数 .
6月 15 15:40:57 admin-standardpci440fxpiix1996 obd[61239]: Trace ID: 967cb81a-2aea-11ef-a88c-bc2411637a57
6月 15 15:40:57 admin-standardpci440fxpiix1996 obd[61239]: If you want to view detailed obd logs, please run: obd display-trace 967cb81a-2aea-1>
6月 15 15:40:57 admin-standardpci440fxpiix1996 obd[61239]:
6月 15 15:40:57 admin-standardpci440fxpiix1996 systemd[1]: oceanbase.service: Control process exited, code=exited, status=1/FAILURE
6月 15 15:40:58 admin-standardpci440fxpiix1996 systemd[1]: oceanbase.service: Failed with result ‘exit-code’.
6月 15 15:40:58 admin-standardpci440fxpiix1996 systemd[1]: Failed to start oceanbase.
6月 15 15:40:58 admin-standardpci440fxpiix1996 systemd[1]: oceanbase.service: Consumed 7.944s CPU time.

3 个赞

如果是单机版,直接rpm安装,sysctrl设置开机启动可以搞定的

3 个赞

但是我这里设置了还是不行 的

2 个赞

如果需要自启动功能可以自己写个启动脚本 比如使用service或者crontab

1 个赞

1 个赞


重启报错

1 个赞

image
重启集群时可以试着把restart换成start的方式

1 个赞

可以试一下先把启动 停止 重启,编辑成三个shell脚本,测试shell脚本成功后,service里写脚本呢

1 个赞

如果不考虑demo全家桶的功能,也不考虑是否是一个集群,建议使用rpm + systemd的方式启动,可以参考社区的快速上手

  1. 如果要自己折腾,首先可以看一下observer关于systemd的源代码,并想好以下这些问题
  2. systemd的forking模式和obd非service类型的兼容,这种情况下obd会forking多个进程,跟踪哪一个你要考虑好
  3. journalctl查看日志和如何查看obd的日志
  4. 环境变量的配置是否只有env.sh就够了
  5. systemd的reload从设计上不太等于这里的obd demo restart
1 个赞

systemctl属于后台命令,能返回到console的特别少,可以用下面的方式继续排查

  1. journalctl -u oceanbase,从这里面应该能找到trace
  2. obd display-trace XXXXX
  3. 不过看上去也可能是observer的问题,也需要查看 安装目录/log/observer.log的日志
1 个赞

你的需求想法是好的,实现方式却有点不妥。

配置 OB 的 systemd 服务

systemd 服务通常是linux 主机用来管理本机服务的,在 systemd 服务里调用 obd 命令去管理一个 OB 集群服务,这个 OB 的节点却可能是在其他服务器上。这种管理方式并不妥。

如果把 obd 命令所在主机称之为 “中控机”,OB 集群的机器不在中控机上。
试想一下,如果中控机重启了,而 OB 集群服务器自身并无异常,中控机又来一个 obd cluster start ,这不是添乱吗。即使这个命令能做到不报错,去启动一个已经启动了的集群,这个想法就是不对的。
另外一种情形,如果中控机无异常,OB 集群的一台机器重启了,那个故障机器的 observer 进程还是要自己拉起来。当然你也可以在中控机上使用 obd 命令带上参数去拉起。

我推测你的目的是想实现 OB 集群服务器如果重启了,能自动把 observer 进程拉起来。那实现方式就是应该去 OB 集群节点上配置一个 systemd 服务。

下面是参考。

[root@server061 ~]# cat /etc/systemd/system/observer.service
[Unit]
Description=observer systemd service
After=network.target

[Service]
Type=forking
User=admin
Environment="LD_LIBRARY_PATH=/home/admin/oceanbase/lib"
WorkingDirectory=/home/admin/oceanbase
ExecStart=/home/admin/oceanbase/bin/observer
ExecStartPost=/bin/sleep 1
ExecStop=/usr/bin/kill -9 $MAINPID
ExecStopPost=/bin/sleep 3

[Install]
WantedBy=multi-user.target

在使用这个脚本之前,先在 OB 机器上把 observer 进程杀掉。

kill -9 `pidof observer`
sleep 3
ps -ef|grep observer |grep -v grep

之所以 sleep 一下,是生产环境,杀一个进程,是需要点时间。
然后就可以使用 systemd 服务来管理 observer 启动。

[root@server061 ~]# systemctl start observer
[root@server061 ~]# systemctl status observer
● observer.service - observer systemd service
   Loaded: loaded (/etc/systemd/system/observer.service; enabled; vendor preset: disabled)
   Active: active (running) since Sat 2024-06-22 08:59:35 CST; 7s ago
  Process: 10587 ExecStopPost=/bin/sleep 3 (code=exited, status=0/SUCCESS)
  Process: 10584 ExecStop=/usr/bin/kill -9 $MAINPID (code=exited, status=0/SUCCESS)
  Process: 10689 ExecStartPost=/bin/sleep 1 (code=exited, status=0/SUCCESS)
  Process: 10679 ExecStart=/home/admin/oceanbase/bin/observer (code=exited, status=0/SUCCESS)
 Main PID: 10688 (observer)
    Tasks: 65
   Memory: 191.1M
   CGroup: /system.slice/observer.service
           └─10688 /home/admin/oceanbase/bin/observer

Jun 22 08:59:34 server061 systemd[1]: Starting observer systemd service...
Jun 22 08:59:35 server061 systemd[1]: Started observer systemd service.
[root@server061 ~]# ps -ef|grep observer
admin    10688     1  8 08:59 ?        00:00:01 /home/admin/oceanbase/bin/observer
root     10920  2040  0 08:59 pts/2    00:00:00 grep --color=auto observer

停止 observer 进程

[root@server061 ~]# systemctl stop observer
[root@server061 ~]# ps -ef|grep observer
root     11805  2040  0 09:00 pts/2    00:00:00 grep --color=auto observer

将这个服务设置为 自启动模式。

[root@server062 ~]# systemctl enable observer
Created symlink from /etc/systemd/system/multi-user.target.wants/observer.service to /etc/systemd/system/observer.service.
[root@server062 ~]# 

observer 启动提醒

首先 observer 的运行用户建议是 admin 而不是 root 。如果使用 obd 部署的集群,特别注意要改这个。
所以,我上面的脚本是运行在 admin 用户下的。

第二,observer 的启动命令的工作目录必须在 软件目录下。我这里是 /home/admin/oceanbase
启动方式不要求是绝对路径,不过 systemd 服务文件要求必须是绝对路径我才这么写的。
并不意味着在任意目录下运行 /home/admin/oceanbase/bin/observer 都可以启动 observer。

第三,这个启动方式只适合于 OB 集群已经初始化成功了,所以 observer 启动的时候没有传递命令行参数,因为会自动读取工作目录下的 etc/observer.config.bin 里的参数。

第四, observer 的启动和停止都是需要时间的,特别是生产环境。所以不能频繁的对这个服务调用 start 和 stop 。start 之前要确保进程已经退出,stop 也要留时间等进程退出。所以我在服务文件里加上了 sleep 语句。

不管从哪条路入门的 OB ,最终作为 OBDBA 都需要掌握 observer 的手动启动方法和停止方法。 OBD 只是一个运维工具,只有理解了 observer 进程的启动和停止方法,才可以放心使用 obd 自动化去管理 OB 集群。

上面我的例子中的 OB 是企业版,OCP 部署的。企业版的 OCP 管理 OB 集群的时候会在每个节点增加一个启动脚本,自动拉起 observer 和 obproxy 。社区版也可以参考,详情参考: OBServer 服务器重启后 observer 进程未能自动启动-OceanBase知识库


更多 OB 集群手动部署和启动方法可以参考: OB 4.2 集群手动部署方法 (qq.com)

3 个赞

system不建议在生产使用

建议改用OBD部署,或者OCP

企业版的 OB 重启后自动化启动脚本。

[root@server062 ~]# cat /usr/local/bin/auto_start_ob.sh 
#!/bin/bash

EXPECT_OFFSET=50
STEADY_COUNT=10
SYNC_WAIT_TIMEOUT=300 # 5min

function wait_until_startup_finished() {
  ts_echo "wait until all systemd services start..."
  while true; do
    systemd-analyze > /dev/null 
    if [ $? = 0 ]; then
      ts_echo "all systemd services has started" 
      break
    else
      sleep 1
    fi
  done
}

function ensure_clock() {
  ps -C ntpd > /dev/null 2>&1
  run_ntp=$?
  ps -C chronyd > /dev/null 2>&1
  run_chrony=$?

  if [ ${run_ntp} -eq 0 ]; then
    ts_echo "find running ntpd service, try to sync time..."
    success_count=0
    step_sync_flag=0
    for i in $(seq ${SYNC_WAIT_TIMEOUT}); do
      ntp_server=$(ntpq -np | grep -e '^*' | awk '{print $1}' | sed 's/*//g')
      if [[ "$ntp_server" != "" ]]; then
        clock_offset=$(ntpq -np | grep -e '^*' | awk '{print $9}')
        if [ $(echo ${clock_offset} ${EXPECT_OFFSET} | awk '{if($1<=$2) {print 1} else {print 0}}') == 1 ]; then
          let success_count++
          if [ ${success_count} -eq ${STEADY_COUNT} ]; then
            ts_echo "sync time success"
            break
          fi
        else
          if [ ${step_sync_flag} -eq 0 ]; then
            step_sync_flag=1
            systemctl stop ntpd
            systemctl restart ntpdate
            systemctl start ntpd  # maybe restart ntpd can also cause step-time 
          fi
          success_count=0
        fi
      else
        success_count=0
      fi
      sleep 1
    done

    if [ ${success_count} -lt ${STEADY_COUNT} ]; then
      ts_echo "can't get steady ntp server, observer will not run"
      return 1
    fi

  elif [ ${run_chrony} -eq 0 ]; then
    ts_echo "find running chronyd service, try to sync time..."
    success_count=0
    step_sync_flag=0
    for i in $(seq ${SYNC_WAIT_TIMEOUT}); do
      chrony_server=$(chronyc -n sources | grep -e '^\^\*' | awk '{print $2}')
      if [[ "$chrony_server" != "" ]]; then
        clock_offset=$(chronyc -n tracking | grep "$chrony_server" -A 3|tail -1 | awk '{print $4}')
        if [ $(echo ${clock_offset} ${EXPECT_OFFSET} | awk '{if($1 * 1000 <= $2) {print 1} else {print 0}}') == 1 ]; then
          let success_count++
          if [ ${success_count} -eq ${STEADY_COUNT} ]; then
            ts_echo "sync time success"
            break
          fi
          sleep 1
        else
          if [ ${step_sync_flag} -eq 0 ]; then
            step_sync_flag=1
            chronyc makestep
          fi
          success_count=0
        fi
      else
        success_count=0
      fi
      sleep 1
    done

    if [ ${success_count} -lt ${STEADY_COUNT} ]; then
      ts_echo "can't get steady chrony server, observer will not run"
      return 1
    fi

  else
    ts_echo "can't find running ntpd/chronyd service, observer will not run"
    return 1
  fi

}

function autostart_ob() {
  if [ -e "/home/admin/oceanbase/bin/observer" ]; then
    ts_echo "find observer, try to sync time first..."
    ensure_clock
    if [ $? = 0 ]; then
      ts_echo "try to start observer..."
      su admin -c "cd /home/admin/oceanbase; ulimit -s 10240; ulimit -c unlimited; LD_LIBRARY_PATH=/home/admin/oceanbase/lib:/usr/local/lib:/usr/lib:/usr/lib64:/usr/local/lib64:$LD_LIBRARY_PATH LD_PRELOAD='' /home/admin/oceanbase/bin/observer"
      sleep 5
    else
      echo "sync time failed, will not start observer."
    fi
  else
    ts_echo "can't find observer, skip"
  fi
}

function autostart_obproxy() {
  if [ -d /opt/taobao/install ]; then
    ts_echo "start obproxy..."
    OBPROXY_ROOT_ARRAY=($(ls -t /opt/taobao/install | grep obproxy- ))
    for OBPROXY_ROOT in ${OBPROXY_ROOT_ARRAY[@]}; do
      if [ -e "/opt/taobao/install/$OBPROXY_ROOT/bin/obproxy" ]; then
        ts_echo "start obproxy in /opt/taobao/install/$OBPROXY_ROOT"
        app_name=obproxy
        app_name=$(strings /opt/taobao/install/${OBPROXY_ROOT}/.conf/obproxy_config.bin | grep app_name | cut -d'=' -f 2)
        su admin -c "cd /opt/taobao/install/$OBPROXY_ROOT && ./bin/obproxyd.sh -c start -e offline -n ${app_name}"
        sleep 3
        break
      fi
    done
  elif [ -e "/home/admin/obproxy/bin/obproxyd.sh" ]; then
    su admin -c "cd /home/admin/obproxy && ./bin/obproxyd.sh -c start"
    ts_echo "start obproxy in /home/admin/obproxy"
    sleep 3
  else
    ts_echo "can't find obproxy, skip"
  fi

}

function autostart_obagent() {
  if [ -e "/home/admin/obztools_agent/ob_agent.py" ]; then
    [ -e "/home/admin/ocp_agent/libs" ] && export PYTHONPATH=/home/admin/ocp_agent/libs
    cd /home/admin/obztools_agent

    ps -C observer > /dev/null 2>&1
    run_observer=$?
    if [[ ${run_observer} == 0 && -e "/home/admin/oceanbase/bin/observer" ]]; then 
      ts_echo "start ob-agent..."
      ./ob_agent.py start agent
      sleep 3
    fi
    
    ps -C obproxy > /dev/null 2>&1
    run_obproxy=$?
    if [[ ${run_obproxy} == 0 && -e "/opt/taobao/install/$OBPROXY_ROOT/bin/obproxy" ]]; then
      ts_echo "start proxy-agent..."
      ./ob_agent.py start proxy_agent
      sleep 3
    fi
  else
    ts_echo "can't find ob-agent, skip"
  fi
}

function autostart_ocp_agent() {
  if [ -e "/home/admin/ocp_agent/bin/ocp_agentctl" ]; then
    ts_echo "start ocp-agent 3.2+"
    /home/admin/ocp_agent/bin/ocp_agentctl start
  elif [ -e "/home/admin/ocp_agent/ocp_agent_ctl.py" ]; then
    ts_echo "start ocp-agent 2.5+"
    cd /home/admin/ocp_agent && python ocp_agent_ctl.py start ocp_agent ob_monitor
  elif [ -e "/home/admin/ocp_agent/ocp_agentd.py" ]; then
    ts_echo "start ocp-agent 2.4"
    export PYTHONPATH=/home/admin/ocp_agent/libs && cd /home/admin/ocp_agent && ./ocp_agentd.py start base
  else
      ts_echo "can't find ocp-agent, skip"
  fi
}


function ts_echo() {
    local timestamp=`date "+%Y-%m-%d %H:%M:%S.%6N"`
    echo -e "[$timestamp]  [$1]"
}

wait_until_startup_finished
autostart_obproxy
autostart_ob
autostart_ocp_agent
autostart_obagent

上面这个脚本会启动 observer、obproxy和 obagent、ocp_agent 。后面这两个 agent 跟 OCP 功能有关。社区版需要验证一下 agent 相关逻辑是否适用。可以自己修改或删除这部分。前面部分 社区版的 observer 和obproxy 路径会不一样,可以相应调整。

将脚本加到 主机文件 rc.local 中。

[root@server062 ~]# cat /etc/rc.local |grep auto
/usr/local/bin/auto_start_ob.sh >> /var/log/ob.autostart.log 2>&1 &

大部分操作系统下加入到 rc.local 中就会自动调用,这个跟主机的服务有关。

[root@server062 ~]# systemctl status rc-local
● rc-local.service - /etc/rc.d/rc.local Compatibility
   Loaded: loaded (/usr/lib/systemd/system/rc-local.service; static; vendor preset: disabled)
   Active: active (exited) since Thu 2024-06-27 08:39:15 CST; 2 days ago
  Process: 1178 ExecStart=/etc/rc.d/rc.local start (code=exited, status=0/SUCCESS)
    Tasks: 0
   Memory: 0B

Jun 27 08:37:07 server062 rc.local[1178]: iscsiadm: cannot make connection to 10.0.0.205: No route to host
Jun 27 08:37:10 server062 rc.local[1178]: iscsiadm: cannot make connection to 10.0.0.205: No route to host
Jun 27 08:37:10 server062 rc.local[1178]: iscsiadm: connection login retries (reopen_max) 5 exceeded
Jun 27 08:37:10 server062 rc.local[1178]: iscsiadm: Could not perform SendTargets discovery: encountered connection failure
Jun 27 08:39:15 server062 rc.local[1178]: iscsiadm: Could not login to [iface: default, target: iqn.2000-01.com.synology:DS918.default-target.392e48dbfa5, portal: 10.0.0.205,3260].
Jun 27 08:39:15 server062 rc.local[1178]: iscsiadm: initiator reported error (8 - connection timed out)
Jun 27 08:39:15 server062 rc.local[1178]: iscsiadm: Could not log into all portals
Jun 27 08:39:15 server062 rc.local[1178]: Logging in to [iface: default, target: iqn.2000-01.com.synology:DS918.default-target.392e48dbfa5, portal: 10.0.0.205,3260] (multiple)
Jun 27 08:39:15 server062 rc.local[1178]: mount: special device /dev/sdd does not exist
Jun 27 08:39:15 server062 systemd[1]: Started /etc/rc.d/rc.local Compatibility.

麒麟系统有些版本这个服务可能会启动失败。导致不会自动启动,需要相应解决。

1 个赞

宕机后自启动终究还是有需求的 :rofl:之前给OB官方也提过,反馈说如果systemd自启动可能有数据同步状态之类问题,后面出了obshell工具,可以用obshell来管理observer的自启动