本文结合网上资料整理。
Dubbo部分
Dubbo 是阿里巴巴开源一个RPC框架,核心思想是通过注册中心,实现provider和consumer之间的接口交互。可以通过多个provider实现分布式,consumer在使用时不必关心提供方。
这几天在调整dubbo provider的发布方式。之前项目使用了war的方式提供服务,这在provider过多时,需要引入许多container并带来维护成本,而且容器本身也占用系统内存。官方的demo是采用jar的方式调用,但要注意的是,如果直接在main线程注册provider而不block住,注册完马上就会注销。
网上有人采用System.in.read(); 方式来block,代码片段如下:
public class Main {
public static void main(String[] args){
// load spring、dubbo configuration
try {
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
}
但是放到centos上执行不顺利,改用了线程sleep的方式。代码片段如下:
public static void main(String[] args) throws IOException {
logger.info(" **** main start ****");
MyThread myThread = new MyThread();
Thread thread = new Thread(myThread, "xxx");
thread.start();
logger.info(" **** main end ****");
}
@Override
public void run() {
//load spring、dubbo configurations
context.start();
do {
try {
Thread.sleep(3600000);
} catch (InterruptedException e) {
logger.error("",e);
}
} while (true);
}
如果有业务需要,可以增加interrupt方式来终止线程。
Assembly部分
maven提供了maven-assembly-plugin,适用于打包。在assembly基础上配套了profie,更适用于企业多环境的部署问题。
比如一个qa profile,配置assembly文件位置
<profile>
<id>qa</id>
<properties>
<assembly.ddescriptor>build/assembly/qa/assembly.xml</assembly.ddescriptor>
</properties>
</profile>
插件使用时即可根据profile读取正确的配置文件
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<configuration>
<descriptors>
<descriptor>${assembly.ddescriptor}</descriptor>
</descriptors>
</configuration>
<executions>
<!-- 当执行mvn package时才会打包 -->
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
assembly.xml 如下,指定一些配置文件的路径。
<assembly>
<id>bin</id>
<formats>
<!-- zip,tar,tar.gz,tar.bz2,jar,dir,war -->
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<!-- 依赖包的输出路径 -->
<dependencySet>
<useProjectArtifact>true</useProjectArtifact>
<outputDirectory>lib</outputDirectory>
</dependencySet>
</dependencySets>
<!-- 需要打包的文件集 -->
<fileSets>
<fileSet>
<directory>env/qa/conf</directory>
<outputDirectory>/conf</outputDirectory>
<includes>
<include>**/*.xml</include>
</includes>
</fileSet>
<fileSet>
<directory>env/qa/conf</directory>
<outputDirectory>/conf</outputDirectory>
<includes>
<include>**/*.properties</include>
</includes>
<filtered>true</filtered>
</fileSet>
<fileSet>
<directory>build/scripts</directory>
<outputDirectory>/bin</outputDirectory>
<includes>
<include>**</include>
</includes>
</fileSet>
</fileSets>
</assembly>
提供start.sh、stop.sh脚本
#!/bin/bash
export JAVA_HOME=xxx
export PATH=$PATH:/xxx/bin
cd `dirname $0`
BIN_DIR=`pwd`
cd ..
DEPLOY_DIR=`pwd`
CONF_DIR=$DEPLOY_DIR/conf
JAVA_MAIN_CLASS="xxx"
PIDS=`ps -f | grep java | grep "$CONF_DIR" |awk '{print $2}'`
if [ -n "$PIDS" ]; then
echo "ERROR: The $DEPLOY_DIR already started!"
echo "PID: $PIDS"
exit 1
fi
LOGS_DIR=$DEPLOY_DIR/logs
if [ ! -d $LOGS_DIR ]; then
mkdir $LOGS_DIR
fi
STDOUT_FILE=$LOGS_DIR/stdout.log
LIB_DIR=$DEPLOY_DIR/lib
LIB_JARS=`ls $LIB_DIR|grep .jar|awk '{print "'$LIB_DIR'/"$0}'|tr "\n" ":"`
JAVA_OPTS=" -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true "
JAVA_DEBUG_OPTS=""
if [ "$1" = "debug" ]; then
JAVA_DEBUG_OPTS=" -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n "
fi
JAVA_JMX_OPTS=""
if [ "$1" = "jmx" ]; then
JAVA_JMX_OPTS=" -Dcom.sun.management.jmxremote.port=1099 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false "
fi
JAVA_MEM_OPTS=""
BITS=`java -version 2>&1 | grep -i 64-bit`
if [ -n "$BITS" ]; then
JAVA_MEM_OPTS=" -server -Xmx2g -Xms2g -Xmn256m -XX:PermSize=128m -Xss256k -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:+UseCMSCompactAtFullCollection -XX:LargePageSizeInBytes=128m -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=70 "
else
JAVA_MEM_OPTS=" -server -Xms1g -Xmx1g -XX:PermSize=128m -XX:SurvivorRatio=2 -XX:+UseParallelGC "
fi
echo -e "Starting the $DEPLOY_DIR ...\c"
nohup java $JAVA_OPTS $JAVA_MEM_OPTS $JAVA_DEBUG_OPTS $JAVA_JMX_OPTS -Djava.ext.dirs=$LIB_DIR:$CONF_DIR $JAVA_MAIN_CLASS > $STDOUT_FILE 2>&1 &
COUNT=0
while [ $COUNT -lt 1 ]; do
echo -e ".\c"
sleep 1
COUNT=`ps -f | grep java | grep "$DEPLOY_DIR" | awk '{print $2}' | wc -l`
if [ $COUNT -gt 0 ]; then
break
fi
done
echo "OK!"
PIDS=`ps -f | grep java | grep "$DEPLOY_DIR" | awk '{print $2}'`
echo "PID: $PIDS"
echo "STDOUT: $STDOUT_FILE"
#!/bin/bash
cd `dirname $0`
BIN_DIR=`pwd`
cd ..
DEPLOY_DIR=`pwd`
CONF_DIR=$DEPLOY_DIR/conf
PIDS=`ps -ef | grep java | grep "$DEPLOY_DIR" |awk '{print $2}'`
if [ -z "$PIDS" ]; then
echo "ERROR: The $DEPLOY_DIR does not started!"
exit 1
fi
if [ "$1" != "skip" ]; then
$BIN_DIR/dump.sh
fi
echo -e "Stopping the $DEPLOY_DIR ...\c"
for PID in $PIDS ; do
kill $PID > /dev/null 2>&1
done
COUNT=0
while [ $COUNT -lt 1 ]; do
echo -e ".\c"
sleep 1
COUNT=1
for PID in $PIDS ; do
PID_EXIST=`ps -f -p $PID | grep java`
if [ -n "$PID_EXIST" ]; then
COUNT=0
break
fi
done
done
echo "OK!"
echo "PID: $PIDS"
dubbo服务管理部分
以上部分从使用上已经可以正常提供dubbo服务,但是为了方便管理,可以增加后台控制。这里采用java的process来操作shell脚本。
String sudo = "chmod 777 " + script;
String cmd = "/bin/sh " + script;
Process process = null;
try {
logger.info("execute command:{}",sudo);
process = Runtime.getRuntime().exec(sudo);
process.waitFor();
logger.info("execute command:{}",cmd);
Runtime.getRuntime().exec(cmd);
} catch (Exception e) {
logger.error("{}",e);
}finally {
process.destroy();
}
chmod是考虑到权限问题。在使用java progress操作时,需要注意提供环境变量支持,如上面脚本的JAVA_HOME。
管理系统代码可以参考:Dubbo-center
********** 2015-12-23
增加windows下bat脚本
@echo off & setlocal enabledelayedexpansion
echo begin
f:
set DEPLOY_DIR=f:\root
set LIB_JARS=""
set MAIN_CLASS=com.cherong.service.pay.init.Init
cd %DEPLOY_DIR%\lib
for %%i in (*) do set LIB_JARS=!LIB_JARS!;..\lib\%%i
cd ..\bin
if ""%1"" == ""debug"" goto debug
if ""%1"" == ""jmx"" goto jmx
echo begin java java -Xms64m -Xmx1024m -XX:MaxPermSize=64M -classpath ..\conf;%LIB_JARS% %MAIN_CLASS%
java -Xms64m -Xmx1024m -XX:MaxPermSize=64M -classpath ..\conf;%LIB_JARS% %MAIN_CLASS%
goto end
:debug
java -Xms64m -Xmx1024m -XX:MaxPermSize=64M -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,address=8000,server=y,suspend=n -classpath ..\conf;%LIB_JARS% %MAIN_CLASS%
goto end
:jmx
java -Xms64m -Xmx1024m -XX:MaxPermSize=64M -Dcom.sun.management.jmxremote.port=1099 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -classpath ..\conf;%LIB_JARS% %MAIN_CLASS%
:end
pause
请注意windows下cmd的路径切换,比如脚本中的 f: ,否则无法正常执行。
windows下停止暂时采用JAVA实现,暂未解决脚本占用问题
package com.chinesedreamer.dubbocenter.executor.service;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.chinesedreamer.dubbocenter.pid.Pid;
public class WindowsStopProcess {
private static Logger logger = LoggerFactory.getLogger(WindowsStopProcess.class);
private static String TASK_LIST = "taskList";
private static String TASK_KILL = "TSKILL ";
private static String PID_PATH = "wmic process where processid=<pid> get commandline"; //获取pid路径
public static void stopProcess(String path) {
Process process = null;
List<String> pids = new ArrayList<String>();
try {
process = Runtime.getRuntime().exec(TASK_LIST);
Scanner in = new Scanner(process.getInputStream(),"GBK");
while (in.hasNextLine()) {
String line = in.nextLine();
if (line.startsWith("java")) {
pids.add(line);
}
}
in.close();
List<Pid> getPidObjs = getPidObjs(pids);
for (Pid pid : getPidObjs) {
process = Runtime.getRuntime().exec(PID_PATH.replace("<pid>", pid.getPid()));
in = new Scanner(process.getInputStream(),"GBK");
while (in.hasNextLine()) {
String commandPath = in.nextLine();
logger.info("process path: {}" , commandPath);
if (commandPath.trim().endsWith(path)) {
logger.info("kill pid#{}",pid.getPid());
Runtime.getRuntime().exec(TASK_KILL + pid.getPid());
break;
}
}
}
} catch (IOException e) {
logger.error("{}",e);
}
}
private static List<Pid> getPidObjs(List<String> pids) {
List<Pid> pidOjbs = new ArrayList<Pid>();
List<String> pidObj = new ArrayList<String>();
for (String pid : pids) {
String[] pidProperties = pid.split(" ");
pidObj.clear();
for (String pidProperty : pidProperties) {
if (StringUtils.isNotEmpty(pidProperty)) {
pidObj.add(pidProperty);
}
}
pidOjbs.add(generatePid(pidObj));
}
return pidOjbs;
}
private static Pid generatePid(List<String> pidObj) {
Pid pid = new Pid();
pid.setServiceName(pidObj.get(0));
pid.setPid(pidObj.get(1));
pid.setSessionName(pidObj.get(2));
pid.setSessionNumber(pidObj.get(3));
pid.setMemory(pidObj.get(4));
return pid;
}
}