服务器架构之后台进程防多开

  1. 参考

这两天在想如何防进程多开的问题,先说一下项目中是如何做的,其实项目的框架使用了公司tapp组件,进程在启动的时候传入pid文件,tapp本身就会进行进程多开的保护。

在讨论具体防进程多开的实现方式前,先说一下项目过程中遇到的问题,在一开始接触项目的时候其实并没有太注意到这块,后来发现我们自己的开发环境的进程经常会发生启动了多份,那为啥会启动多份呢?本身业务进程的监控都是通过tcm来进行管理的,tcm重启进程的时候为什么没有杀死旧进程呢?这里就是防进程多开的具体实现了。

那如果让你去设计一种防进程多开的方案,你会怎么设计呢?多进程间的协作无非就是利用进程间同步来实现。进程间的同步方式常见的有:记录锁信号量。当然进程间的通信方式也可以用来同步:管道FIFO消息队列共享内存。因为进程间的同步都可以通过进程间的通信来实现,只不过需要加上同步逻辑而已。那么为了防止进程多开,最简单的当然是使用进程同步的方式:记录锁和信号量。

linux的记录锁接口为fcntl()它不仅仅可以用来同步不同进程对同一文件的操作,还可以通过对同一文件加记录锁来同步不同进程对某一共享资源的访问。记录锁相对信号量的一个优势是当一个进程终止时,它所建立的记录锁将全部释放。fcntl接口的使用这里不做介绍,可以看我之前的一篇文章,下面是其在防进程多开中的实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
int32_t process_open_protect(const std::string & pid_file)
{
int32_t pid_file_fd = open(pid_file.c_str(), O_WRONLY|O_CREAT|O_TRUNC, 0600);
if(pid_file_fd < 0)
{
std::cout<<"can not open "<<pid_file<<" error:"<<strerror(errno)<<std::endl;
return -1;
}

struct flock lock;
lock.l_type = F_WRLCK; // 写锁
lock.l_whence = SEEK_SET; // 锁的位置在文件开始处
lock.l_start = lock.l_len = 0; // 锁的位置从文件开始处偏移0,长度0,来达到对整个文件上锁

// 非阻塞加锁
int32_t ret = fcntl(pid_file_fd, F_SETLK, &lock);
if(ret < 0)
{
std::cout<<"fcntl failed, error:"<<strerror(errno)<<std::endl;
return -2;
}

// 将进程pid写入PID文件
char str[16];
sprintf(str, "%d", getpid());
uint32_t len = strlen(str);
if(write(pid_file_fd, str, len) != len)
{
std::cout<<"write failed, error:"<<strerror(errno)<<std::endl;
return -3;
}

return 0;
}

当进程启动时候通过上面的初始化逻辑,对传入的pid文件进行加文件锁。当再次启动同一个进程并传入相同的pid文件时,会加锁失败,阻止进程的启动。当进程结束时,会自动释放其所加的文件锁。这就很好的解决了进程多开的问题。

这里有一个问题需要思考的是,如果防多开的进程运行的过程中,pid文件被删除了,怎么办?这在项目运营的过程中真的发生了。我们知道被进程打开的文件被删除时,不会真正的删除,外部的删除操作只是把文件名和inode的映射从目录项中删除了,文件和inode节点的数据也都在(如何通过inode来查看文件的数据?)。针对这个问题,如何才能原地恢复被删的pid文件,保证能够正常防多开呢?如果有知道的同学可以分享一下~!

参考

防多开

https://blog.csdn.net/wangfengwf/article/details/75948792

https://www.jianshu.com/p/c60ff400ddec

inode级别恢复被删的打开文件

https://superuser.com/questions/283102/how-to-recover-deleted-file-if-it-is-still-opened-by-some-process

http://dag.wiee.rs/blog/undeleting-an-open-file-by-inode

https://serverfault.com/questions/168909/relinking-a-deleted-file

https://support.hpe.com/hpsc/doc/public/display?docId=emr_na-c00833030

http://sundayhut.is-programmer.com/tag/debugfs