Java实现Linux下双守护进程
一、简介
现在的服务器端程序很多都是基于java开发,针对于java开发的socket程序,这样的服务器端上线后出现问题需要手动重启,万一大半夜的挂了,还是特别麻烦的。
大多数的解决方法是使用其他进程来守护服务器程序,如果服务器程序挂了,通过守护进程来启动服务器程序。
万一守护进程挂了呢?使用双守护来提高稳定性,守护a负责监控服务器程序与守护b,守护b负责监控守护a,任何一方出现问题,都能快速的启动程序,提高服务器程序的稳定性。
java的运行环境不同于c等语言开发的程序,java程序跑在jvm上面。不同于c语言可以直接创建进程,java创建一个进程等同于使用java -jar xxx.jar启动一个程序。
java启动程序并没有c#类似的单实例限制,你可以启动多个,但是你不能启动多个,不能让多个守护a去守护服务器程序,万一启动了多个服务器程序怎么办?
二、技术讲解
这里的技术讲解比较粗略,具体请百度一下,这里只讲解作用。
1、jps命令。
jdk自带的命令工具,使用jps -l可以列出正在运行的java程序,显示java程序的pid与name。只对java程序有效,其实查看的是运行的jvm
2、java.nio.channels.filelock类的使用
这个是java new io中的类,使用他可以维持在读取文件的给文件加上锁,判断文件时候有锁可以判断该文件是否被其他的程序使用
3、processbuilder与process
这两个原理差不多,都是调用系统的命令运行,然后返回信息。但是硬编码会导致你的java程序失去可移植性,可以将命令独立到配置文件中。
三、设计原理
server:服务器程序
a:守护进程a
b:守护进程b
a.lock:守护进程a的文件锁
b.lock:守护进程b的文件锁
----------------------------------------------------------------------------------
step 1:首先不考虑server,只考虑a与b之间的守护
1.a判断b是否存活,没有就启动b
2.b判断a是否存活,没有就启动a
3.在运行过程中a与b互相去拿对方的文件锁,如果拿到了,证明对面挂了,则启动对方。
4.a启动的时候,获取a.lock文件的锁,如果拿到了证明没有a启动,则a运行;如果没有拿到锁,证明a已经启动了,或者是b判断的时候拿到了锁,如果是a已经启动了,不需要再次启动a,如果是b判断的时候拿到了锁,没关紧 要,反正b会再次启动a。
5.b启动的时候原理与a一致。
6.运行中如果a挂了,b判断到a已经挂了,则启动a。b同理。
step 2:加入server
1.a用于守护b和server,b用于守护a。
2.原理与step 1 一致,只是a多个一个守护serer的任务。
3.当a运行的时候,使用进程pid检测到server已经挂了,就启动server
4.如果server与a都挂了,b会启动a,然后a启动server
5.如果server与b挂了,a启动server与b
6.如果a与b都挂了,守护结束
step 3:使用shutdown结束守护,不然结束server后会自动启动
四、实现
1、guarda的实现
public class guarda {
// guarda用于维持自己的锁
private file fileguarda;
private fileoutputstream fileoutputstreamguarda;
private filechannel filechannelguarda;
private filelock filelockguarda;
// guardb用于检测b的锁
private file fileguardb;
private fileoutputstream fileoutputstreamguardb;
private filechannel filechannelguardb;
private filelock filelockguardb;
public guarda() throws exception {
fileguarda = new file(configure.guard_a_lock);
if (!fileguarda.exists()) {
fileguarda.createnewfile();
}
//获取文件锁,拿不到证明guarda已启动则退出
fileoutputstreamguarda = new fileoutputstream(fileguarda);
filechannelguarda = fileoutputstreamguarda.getchannel();
filelockguarda = filechannelguarda.trylock();
if (filelockguarda == null) {
system.exit(0);
}
fileguardb = new file(configure.guard_b_lock);
if (!fileguardb.exists()) {
fileguardb.createnewfile();
}
fileoutputstreamguardb = new fileoutputstream(fileguardb);
filechannelguardb = fileoutputstreamguardb.getchannel();
}
/**
* 检测b是否存在
*
* @return true b已经存在
*/
public boolean checkguardb() {
try {
filelockguardb = filechannelguardb.trylock();
if (filelockguardb == null) {
return true;
} else {
filelockguardb.release();
return false;
}
} catch (ioexception e) {
system.exit(0);
// never touch
return true;
}
}
}
2、guardserver的实现
public class guardserver {
private string servername;
public guardserver(string servername) {
this.servername = servername;
}
public void startserver(string cmd) throws exception {
system.out.println("start server : " + cmd);
//将命令分开
// string[] cmds = cmd.split(" ");
// processbuilder builder = new processbuilder(cmds);
//
processbuilder builder=new processbuilder(new string[]{"/bin/sh","-c",cmd});
//将服务器程序的输出定位到/dev/tty
builder.redirectoutput(new file("/dev/tty"));
builder.redirecterror(new file("/dev/tty"));
builder.start(); // throws ioexception
thread.sleep(10000);
}
/**
* 检测服务是否存在
*
* @return 返回配置的java程序的pid
* @return pid >0 返回的是 pid <=0 代表指定java程序未运行
* **/
public int checkserver() throws exception {
int pid = -1;
process process = null;
bufferedreader reader = null;
process = runtime.getruntime().exec("jps -l");
reader = new bufferedreader(new inputstreamreader(process.getinputstream()));
string line;
while ((line = reader.readline()) != null) {
string[] strings = line.split(",}");
if (strings.length < 2)
continue;
if (strings[1].contains(servername)) {
pid = integer.parseint(strings[0]);
break;
}
}
reader.close();
process.destroy();
return pid;
}
}
3、guardamain实现
public class guardamain {
public static void main(string[] args) throws exception {
guarda guarda = new guarda();
configure configure = new configure();
guardserver server = new guardserver(configure.getservername());
while (true) {
// 如果guardb未运行 运行guardb
if (!guarda.checkguardb()) {
system.out.println("start guardb.....");
runtime.getruntime().exec(configure.getstartguardb());
}
// 检测服务器存活
if (server.checkserver() <= 0) {
boolean isserverdown = true;
// trip check
for (int i = 0; i < 3; i++) {
// 如果服务是存活着
if (server.checkserver() > 0) {
isserverdown = false;
break;
}
}
if (isserverdown)
server.startserver(configure.getstartserver());
}
thread.sleep(configure.getinterval());
}
}
}
4、shutdown实现
public class shutdown {
public static void main(string[] args) throws exception {
configure configure = new configure();
system.out.println("shutdown guards..");
for (int i = 0; i < 3; i++) {
process p = runtime.getruntime().exec("jps -l");
bufferedreader reader = new bufferedreader(new inputstreamreader(p.getinputstream()));
string line;
while ((line = reader.readline()) != null) {
if (line.tolowercase().contains("guard".tolowercase())) {
string[] strings = line.split(",}");
int pid = integer.parseint(strings[0]);
runtime.getruntime().exec(configure.getkillcmd() + " " + pid);
}
}
p.waitfor();
reader.close();
p.destroy();
thread.sleep(2000);
}
system.out.println("guards is shutdown");
}
}
5、guardb与guarda类似
五、下载与使用
项目文件夹:guard_demo
下载地址:http://pan.baidu.com/s/1bn1y6bx
如果有什么疑问或者建议,请联系我