我们有一个在 Linux 服务器上运行的用 C++ 编写的进程,它从输入文件读取查询,对其运行一些计算/算法并将结果写回命令行。它是多线程的,因此它可以一次接收多个查询,并且对于每个查询,它会生成一个新线程并在同一线程中写入结果。由于高可用性的要求,脚本会自动重新启动进程,以防发生不可预见的崩溃。
#include <pthread.h>
#include <iostream>
#include <cstdlib>
void* func1(void* arg)
{
Validate();
Calculate();
WriteResults();
}
int main(int argc,char *argv[])
{
//set signal handlers to handle SIGTERM, SIGKILL etc
int rc;
pthread_t ptid;
//read config
//...
//...
//listen for queries in a while loop
while(1)
{
//read a query from an input file
//validate it
rc = pthread_create(&ptid,(pthread_attr_t*)NULL, &func1, (void*)Ptr);
if(rc == 0)
pthread_detach(ptid);
}
}
最坏的情况是进程冻结或进入挂起状态而没有崩溃并且无法再接受请求。我们决定在发生此类情况时让该进程自行终止。 从高层开始,我们决定在程序启动后立即生成一个线程,该线程将继续检查映射中的活动查询及其最后活动时间。如果不活动超过某个预先配置的时间,则终止该过程。
#include <pthread.h>
#include <iostream>
#include <cstdlib>
#include <map>
std::map<int id, QueryStruct> activeQueries;
void* func1(void* arg)
{
Validate();
Calculate();
WriteResults();
}
void* func2(void* arg)
{
while (true)
{
//sleep for 300 seconds
//check activeQueries in the system and their last activity time
//if query inactive for more than pre-configured time, terminate the process.
}
}
int main(int argc,char *argv[])
{
//set signal handlers to handle SIGTERM, SIGKILL etc
int rc;
pthread_t ptid, ptid2;
//read config
//...
//spawn a new thread which activates every 300 seconds (pre-configured time)
pthread_create(&ptid2, NULL, &func2, NULL);
//listen for queries in a while loop
while(1)
{
//read a query from an input file
//validate it
rc = pthread_create(&ptid,(pthread_attr_t*)NULL, &func1, (void*)Ptr);
if(rc == 0)
pthread_detach(ptid);
}
}
是否有更标准或更好的方法来实现相同的目标? 在实施同样的过程时我需要注意哪些复杂问题?
我们决定在发生此类情况时让进程自行终止。
我在你的计划中发现的最大问题是,多种崩溃会扰乱 C/C++ 运行时的状态。
这包括诸如
malloc
或 free
的能力、辅助线程的内存状态等。
将某些代码与其他行为不良的代码隔离的标准方法是将其放入单独的进程中。 这给了它自己的内存空间等。您可以使用各种形式的进程间通信来回通信 - 命名管道、磁盘上的文件、套接字等。
如果你这样做,那么你的程序的失败几乎可以完全与你的看门狗隔离。
我可能会分三部分来做。
第一部分是工人。 它应该定期提供“进展证明”——证明它正在以可接受的速度开展工作。 这个证明应该相当有力——例如,新任务正在完成(而不是“我们有一个整数,每次工作时代码都会递增”,没有上限值)——以防止无限循环看起来像无限进度。
一个进程内线程,用于监视“进度证明”并将其转发给看门狗进程。 它唯一的工作是找到进度证明并向看门狗发送报告。
该任务还可以检查看门狗是否存在;如果没有,它就会启动它。 (这是为了稍微防止看门狗崩溃)。
我会在崩溃后清理持久状态作为主程序的一部分,以保持看门狗简单。 它通过一些 IPC 进行侦听,注意到进度证明丢失,然后重新启动工作进程。