golang使用linux共享内存及信号实现崩溃重启

golang使用linux共享内存及信号实现崩溃重启

最近项目里有用到共享内存,来实现程序崩溃自启,具体做法就是建立一个守护进程,守护进程实时监测一片共享内存,发现有程序崩溃的时候往里写的数据是某个程序崩溃前写进去的,就把程序重新拉起来

第一步:拦截程序崩溃的信号

要实现程序意外崩溃的时候往共享内存里写东西,首先就要拦截那个让它崩溃的信号,自行处理,比如数组越界,往关闭的套接字里写数据,不小心除了一个为0的数等等,上代码

func RegisterSignal() {
    //注册感兴趣的信号
    signal.Notify(SigChan,
        syscall.SIGBUS,  //总线错误
        syscall.SIGABRT, //调用abort
        //      syscall.SIGTERM, //杀死,测试用
        syscall.SIGSEGV, //访问无效内存
        syscall.SIGILL)  //栈溢出

        //忽略掉其他信号
    signal.Ignore(syscall.SIGHUP, //终端挂起
        syscall.SIGPIPE) //管道错误
}

这是一个系统启动的时候就需要调用的函数,signal.Notify函数主要添加你要拦截的信号,而Ignore函数主要是用来忽略掉一些信号,注册的信号用SigChan来进行接受,以上为几个常用的引起崩溃的信号,有自己的信号也可以进行注册,比如说你可以定义一个78的信号用于在程序中出现某步不得不结束程序的操作,然后先把该信号注册起来,对应的地方把信号发出来,程序就能捕获到

第二步:捕获到程序崩溃的信号

这一步没什么讲的,就是程序开一个chan然后等待chan里面发送数据

select {
    case sig := <-SigChan:
        fmt.Println("recived a signal:", sig)
        CoreDump()
    }

然后就调用一个自己定义的CoreDump函数进行崩溃前处理

第三步 操作共享内存

先上代码:

func CoreDump() {
    fmt.Println("core dump.....")

    fd, err := syscall.Open("/dev/shm/usdeamon", syscall.O_RDWR, 0666)
    if err != nil {
        fmt.Println("open shm file error:", err.Error())
        return
    }
    bs, err := syscall.Mmap(fd, 0, 32, syscall.PROT_WRITE|syscall.PROT_READ, syscall.MAP_SHARED)
    if err != nil {
        fmt.Println("mmap error:", err.Error())
        return
    }

    in := "iftttServer"
    inByte := []byte(in)

    copy(bs, inByte)

    os.Exit(-1)
}

1.由于golang里不带shm_open函数,所以只能使用系统带的open函数进行文件打开,关于shm_open的相关信息此处不再赘述,open函数返回了一个文件描述符供mmap函数调用
2.syscall.Mmap函数跟linux系统调用的mmap函数入参几乎一样,只不过返回值多一个err用于判断是否出错 ,这一步要注意的一点是:
mmap里面的prot字段要和open里面的mode字段想对应,大体来说就是:open的时候开了读写和prot的读写要一致,否则容易引起错误,导致mmap执行失败
3.然后就是利用返回来的Byte数组写东西了 你往[]byte里拷贝的数据都会映射到那个文件里去,读者可以自己实验一下,当程序执行了coreDump之后,手动cat一下那个对应的文件
到这里,golang往里写的部分就完成了,下一篇计划讲解守护进程创建文件和把程序启动.

### 使用 PM2 部署 Go 应用程序 尽管 PM2 主要用于 Node.js 应用的管理和部署,也可以通过一些额外配置来支持其他类型的后台服务,比如 Go 编写的服务器端应用。为了确保 Go 应用能被有效管理并保持稳定运行,在使用 PM2 进行部署时应当遵循一系列最佳实践。 #### 安装依赖项与环境准备 在目标机器上安装必要的软件包,包括但不限于 Git 和 Golang 开发工具链。如果应用程序依赖特定版本的库,则需提前准备好这些资源[^2]。 #### 构建可执行文件 编译阶段至关重要,因为这决定了最终产物的质量以及其能否顺利启动。建议采用静态链接的方式构建二进制文件,这样可以减少对外部共享库的依赖,从而降低因缺少某些动态链接库而导致的应用无法正常工作的风险。 ```bash CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app . ``` 此命令会生成名为 `app` 的 Linux 平台下兼容的独立执行档。 #### 创建生态系统配置文件 (ecosystem.config.js) 定义一个 JSON 或 JavaScript 格式的配置文件来描述待托管的服务详情。对于 Go 应用而言,重点在于设置正确的入口点(即刚才提到的那个 `.exe` 文件),还有就是工作目录、日志记录策略等方面的内容: ```javascript module.exports = { apps : [{ name: 'my-go-app', script: './app', // 假设当前路径存在上述编译得到的二进制文件 instances: 'max', // 可选参数, 表示尽可能多地创建实例数以充分利用多核CPU性能 exec_mode: "cluster",// 同样是为了优化并发处理能力而设定的工作模式 watch: false, max_memory_restart: '1G',// 当内存占用超过一定限度时自动重启进程以防崩溃 env: { NODE_ENV: "production" } }] }; ``` 值得注意的是,这里虽然指定了 `NODE_ENV` 环境变量,但这并不影响 Go 应用本身;相反,这样做主要是为了让后续可能引入的日志分析组件或其他中间件能够据此调整行为逻辑。 #### 初始化 PM2 并加载配置 一旦完成了前面几步的操作之后就可以正式启用 PM2 来接管整个流程了。先让 PM2 加载之前编辑好的配置文件,再将其保存到开机自启列表里以便于长期维护: ```bash pm2 start ecosystem.config.js --env production pm2 save pm2 startup systemd ``` 最后一条指令的作用是在不同的操作系统平台上注册 PM2 成为系统级守护进程的一部分,保证即使主机意外断电或者重新启动也能继续维持业务连续性。 #### 日常运维注意事项 定期查看由 PM2 收集起来的各种监控指标,及时响应异常情况报告。另外也要记得适时清理过期无用的日志条目以免占据过多磁盘空间。同时鼓励开发团队积极采纳 CI/CD 流程自动化方案进一步简化迭代更新过程中的重复劳动环节[^4]。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值