使用rinetd做端口转发

Linux中的iptables非常强大,但是用起来稍显复杂。如果只做端口转发,使用rinetd是一个非常不错的选择。

官方网站为:http://www.boutell.com/rinetd/

安装很简单:

wget  http://www.boutell.com/rinetd/http/rinetd.tar.gz
tar fxz rinetd.tar.gz   
cd rinetd 
make  
make install

修改配置文件:vim /etc/rinetd.conf ,例如

0.0.0.0    1234    dest_ip    dest_port

其中0.0.0.0为本机要监听的IP,0.0.0.0表示所有IP都可以访问该转发服务。
1234为监听端口,dest_ip为转发目标的IP,dest_port为转发目标的端口。

使用同一个jetty启动多个不同的服务

在部署Java Web工程时,往往会在同一台服务器上同时部署多个不同的服务,如果每个服务都拷贝一份Jetty,会显得比较麻烦和冗余,如果将多个工程都放到同一个Jetty中,那么最多只有一个工程能有root context,其余的工程都得加个子context去访问,显得不够友好。通过一些sh脚本,可以实现使用一份Jetty来启动多个不同的服务。

创建一个工程目录,例如oms,在这其中新建一个bin目录,把相关shell脚本放在这里面。新建一个env.sh,内容如下:

#!/usr/bin/env bash

if [ -z "$APP_NAME" ] ; then
  export APP_NAME=oms
  cd ..
  export NODE_PATH=$(pwd)
  export app_conf=$NODE_PATH/conf
  cd -
fi

export JETTY_RUN=$NODE_PATH/bin
export JETTY_PID=$NODE_PATH/.jetty.pid
export JETTY_ARGS=jetty.port=8080
export JETTY_LOGS=$NODE_PATH/logs


JAVA_MEM_OPTS=" -server -XX:+UseParNewGC -XX:+DisableExplicitGC -XX:+UseConcMarkSweepGC -XX:+CMSParallelRemarkEnabled -XX:-CMSParallelRemarkEnabled -XX:CMSInitiatingOccupancyFraction=70 -XX:Sof
tRefLRUPolicyMSPerMB=0 -XX:+UseFastAccessorMethods -XX:+UseCMSInitiatingOccupancyOnly -XX:-HeapDumpOnOutOfMemoryError "

JAVA_OPTS_EXT=" -Djava.awt.headless=true -Djava.net.preferIPv4Stack=true -Dapplication.codeset=UTF-8 -Dfile.encoding=UTF-8  "

JAVA_DEBUG=" -Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8088 "


export JAVA_OPTIONS="$JAVA_MEM_OPTS $JAVA_OPTS_EXT "
#export JAVA_OPTIONS="$JAVA_OPTIONS $JAVA_DEBUG "

其中,APP_NAME 为该服务war包的名称。jetty.port为jetty服务要启动的端口,其他的为一些常规的java参数设置

再在该目录下新建一个shell脚本jetty.sh,内容如下:

#!/usr/bin/env bash

DIR=`dirname $0`
source $DIR/env.sh

if [ -z "$JETTY_HOME" ] ; then
    echo "Please set JETTY_HOME"
    exit
fi

if [ ! -e ../conf/webapps ] ; then
    mkdir -p ../conf/webapps
fi

if [ ! -e ../logs ] ; then
    mkdir -p ../logs
fi

if [ ! -e ../conf/webapps/$APP_NAME.xml ] ; then
    conf=../conf/webapps/$APP_NAME.xml
    echo '<?xml version="1.0"  encoding="ISO-8859-1"?>' >> $conf
    echo '<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">' >> $conf
    echo '<Configure class="org.eclipse.jetty.webapp.WebAppContext">' >> $conf
    echo '  <Set name="contextPath">/</Set>' >> $conf
    echo '  <Set name="war">'"$NODE_PATH/war/$APP_NAME.war</Set>" >> $conf
    echo '  <Set name="tempDirectory">'"$NODE_PATH/war/${APP_NAME}_exploded</Set>" >> $conf
    echo '  <Set name="extractWAR">true</Set>' >> $conf
    echo '  <Set name="copyWebDir">false</Set>' >> $conf
    echo '  <Set name="defaultsDescriptor"><SystemProperty name="jetty.home" default="."/>/etc/webdefault.xml</Set>'  >> $conf
    echo '</Configure>' >> $conf
fi

rm -rf $JETTY_HOME/webapps

ln  -s $NODE_PATH/conf/webapps $JETTY_HOME/webapps

$JETTY_HOME/bin/jetty.sh $1

设置好JETTY_HOME,然后执行jetty.sh start,便可以自动创建相关需要的xml,并启动jetty。这里假设war包放在工程目录的war目录下,并且名字为APP_NAME.war。

由于jetty自己的启动脚本中将JAVA_OPTIONS变成了数组,数组变量在shell脚本之间是不能传递的,而jetty restart调用了自身shell来进行重启操作,因此在我们自己写的env.sh中设置的JAVA_OPTIONS在jetty restart时就失效了,参数不能传递过去。为了解决该问题,需要修改jetty自己的启动脚本jetty.sh,vim $JETTY_HOME/bin/jetty.sh,在最上方加上这段代码:

if [ -f $NODE_PATH/bin/env.sh ];then
    source $NODE_PATH/bin/env.sh
fi

在shell脚本里面重新加载env.sh

Nginx根据Http头字段来分发请求

有两套客户端,共用了同一个接口服务,通过Http方式交互,现在需要将两套客户端对应的接口服务分离。由于请求的uri完全一致,调用的接口也完全一致,只有Http头里面有一个字段,用来区分是来自哪个客户端的请求。于是考虑根据这个Http头字段来进行请求分发,不同的客户端对应到不同的服务端。

写了个简单的配置示例(nginx.conf),证实该方案是可行的:

location / {
        	if ($http_t = "163"){
        		proxy_pass   http://163.com;
        	}
        	if ($http_t = "baidu"){
        		proxy_pass   http://baidu.com;
        	}
        	
            root   html;
            index  index.html index.htm;
        }

其中$http_为nginx配置文件中获取Http头字段的默认前缀,例如Http头中有个字段为t,那么$http_t就为该字段对应的值。当该值为163的时候,直接跳转到163网站,当该值为baidu的时候,直接跳转到百度网站。

处理完该事情后,对Http JSON接口协议的制定也有了一些新的认识,对于全局性的字段,建议放到Http头中进行传递,因为不需要解析包体就可以对该请求做一些简单分析和处理。对于接口相关性的字段,可以放在JSON包体中进行传递。