问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

运维实战:Windows服务挂掉怎么办?Bat脚本实现自动重启方案

创作时间:
作者:
@小白创作中心

运维实战:Windows服务挂掉怎么办?Bat脚本实现自动重启方案

引用
1
来源
1.
https://developer.aliyun.com/article/1527191

在日常运维工作中,Windows服务器的服务可能会意外停止,例如数据库、Tomcat、Redis等关键服务。为了解决这一问题,本文将介绍如何通过Bat脚本实现异常Windows服务的自动重启。通过这种方式,运维人员可以避免在服务挂掉时紧急处理问题,从而提高工作效率和系统稳定性。

一、新建Bat脚本文件

这里以mysql服务为例,演示如何设置每小时监控一次,如果服务挂掉就自动重启。你可以根据实际需求调整监控频率。

rem 设置已管理员运行cmd命令
@echo off
>nul 2>&1 "%SYSTEMROOT%\system32\cacls.exe" "%SYSTEMROOT%\system32\config\system"
if '%errorlevel%' NEQ '0' (
goto UACPrompt
) else ( goto gotAdmin )
:UACPrompt
echo Set UAC = CreateObject^("Shell.Application"^) > "%temp%\getadmin.vbs"
echo UAC.ShellExecute "%~s0", "", "", "runas", 1 >> "%temp%\getadmin.vbs"
"%temp%\getadmin.vbs"
exit /B
:gotAdmin
if exist "%temp%\getadmin.vbs" ( del "%temp%\getadmin.vbs" )
rem 定义循环间隔时间和监测的服务,这里设置为1小时
set secs=3600
rem 这里以mysql服务为案例
set srvname="mysql"

echo.
echo ========================================
echo ==         查询计算机服务的状态,     ==
echo ==     每间隔%secs%秒种进行一次查询,     ==
echo ==     发现服务其停止,立即启动。     ==
echo ========================================
echo.
echo 此脚本监测的服务是:%srvname%
echo.

if %srvname%. == . goto end

:chkit
set svrst=0
rem 使用for 循环遍历当前系统上正在运行的服务列表。判断运行的服务列表里面是否存在 %srvname% ,匹配成功,则将 svrst 的值设置为 1。
for /F "tokens=1* delims= " %%a in ('net start') do (
    if /I "%%a %%b" == %srvname% (        
        set svrst=1       
    )
)
rem 查询服务状态
echo 服务状态为:%svrst%
if %svrst% == 0 (
    net start %srvname%    
    echo 服务 %srvname% 正常启动成功了。
) 
rem 下面的命令用于延时,否则可能会导致cpu单个核心满载。
ping -n %secs% 127.0.0.1 > nul
goto chkit

:end

注意:需要把Bat脚本文件设置为ANSI编码,否则会出现控制台中文乱码的情况。

关于脚本本身的含义,可以直接查看脚本中的注释。此外,脚本中还包含了自动以管理员身份运行的功能,这部分代码可以通用,适用于其他运维脚本。

二、运行效果

将mysql服务停止后执行Bat脚本,可以看到服务被自动重启的效果。

三、封装为服务的方式运行

建议将Bat脚本打包为Windows服务运行,以避免直接使用cmd窗口运行时被意外关闭的风险。以下是三种实现方式:

3.1 NSSM

使用nssm(Non-Sucking Service Manager)工具将.bat脚本转换为服务。具体操作可以参考官网文档。

官网:http://www.nssm.cc/usage

3.2 Windows服务程序

通过编写C# Windows服务程序来调用批处理文件。以下是一个示例:

using System;
using System.Diagnostics;
using System.ServiceProcess;

public partial class BatchService : ServiceBase
{
    public BatchService()
    {
        InitializeComponent();
    }

    protected override void OnStart(string[] args)
    {
        ExecuteBatchFile();
    }

    private void ExecuteBatchFile()
    {
        try
        {
            // 替换为你的批处理文件路径
            string batFilePath = @"Bat脚本路径";
            Process.Start(new ProcessStartInfo("cmd.exe", $"/c {batFilePath}") { CreateNoWindow = true });
        }
        catch (Exception ex)
        {
            EventLog.WriteEntry("BatchService", $"Error executing batch file: {ex.Message}", EventLogEntryType.Error);
        }
    }
    // 其他服务方法如OnStop等...
}

将该项目编译成.exe可执行文件,然后通过命令行工具sc或安装util(在.NET Framework中可用)将这个.exe注册为系统服务。

sc create YourServiceName binPath= "C:\\path\\to\\your\\compiled_service.exe" start= auto DisplayName= "Your Service Display Name"

3.3 开源的Java工具winsw

使用winsw可以将任何可执行文件包装成Windows服务。你需要编写一个XML配置文件来指定批处理文件的位置和其他参数,然后用winsw.exe和配置文件一起创建服务。

下载地址:https://github.com/kohsuke/winsw/releases

<service>
  <id>your-service-name</id>
  <name>Your Service Display Name</name>
  <description>Description of your service</description>
  <executable>C:\\Windows\\System32\\cmd.exe</executable>
  <arguments>/c bat脚本完整路径</arguments>
</service>

将winsw.exe重命名为带有.exe扩展名的服务名称,如your-service-name.exe,这样它就能读取同目录下的your_service.xml配置文件。

使用命令行工具sc注册服务:

sc create YourServiceName binPath= "C:\\path\\to\\your_service\\your-service-name.exe" start= auto DisplayName= "服务名称"

注意:这种方法还是间接地将批处理文件作为服务运行,而不是直接将批处理文件注册为服务。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号