异构语言高可用性服务端的设计与实现

本文的客户端基于我们的GQT开源项目:http://cxlh.iteye.com/blog/2021463

本人拙见,如有不同意见,欢迎拍砖,同时献给特别有对服务端跨语言需求的程序猿们!

客户端(GQT Demo V3(服务端配套版).rar)太大请挪步到QQ群下载(群号:101189702),注明:GQT或Java,C++等,Java服务端源码在附件中下载;

总体设计思路: 

  1. 高可用性:每个业务服务端都是独立的个体,任何一个业务服务器Crash时,都不会影响服务,并且业务服务器可以按需增加,业务服务端使用Java代码实现,主要是为了考虑更好的数据库操作,更好的事务支持,更好的社区支持以及可用更多的开源服务,提高开发效率;
  2. 自动负载均衡:当某个接口频繁调用,增加的响应服务器自动分流接口调用压力,也就说我们的异步的请求/响应模式下,有一个Broker仲裁程序决定客户端发来的请求交由哪个Java业务服务器来处理,这个Broker程序我们采用C++代码实现;
  3. 客户端(包括桌面或移动端)网关:根据策略选取远程Socket服务器连接,Socket服务器与服务器之间的消息通讯通过地址寻址远程路由,以便连在不同Socket服务器上的用户之间可以相互通讯,典型的应用就是聊天程序;
  4. Sub/Pub类消息:客户端订阅服务端的服务,服务端有多个Pub服务器(Java编写),交由Socket服务器将客户端Sub的消息Push给Client,此时Socket服务只作为Proxy用;

  好了,其实这里只有2个C++核心组件(Socket服务器,Broker仲裁程序)和N个Java业务服务器(请求处理服务器,Pub服务器),以下介绍用法:

客户端发送请求,异步收取,编写业务代码步骤:

编写业务请求的服务端非常简单,看起来就这么几句:

public class StockServer extends BaseReqServer {
	private static Logger logger = LogManager.getLogger(StockServer.class.getName());
	public StockServer(String ip, String port, ReqCallBack callback) {
		super(ip, port, callback);
	}
	public static void main(String[] args) {
		logger.info("=============StockServer========");
		new Thread(){
			@Override
			public void run() {
				ReqCallBack callback = new StockCallBack();
				String ip = prop.getProperty("gqt-reqserver-ip");
				String port = prop.getProperty("gqt-reqserver-port");
				final StockServer ss = new StockServer(ip,port,callback);
				ss.startServer();
			}
		}.start();
    }
}

  处理请求Java代码:

public class StockCallBack extends ReqCallBackAbstract{
	
	final SpringInstance si = SpringInstance.getInstance();
	final private StockService stockService = (StockService)si.getService("stockService");

	@Override
	public void solve(JSONObject json,String c, String args) {
		try{
			String[] commandArray = StrUtil.split(c, ".");
			if(commandArray.length == 2){
				String objStr = commandArray[0];
				String objFunc = commandArray[1];
				//Map<String,Object> argMap = (Map<String,Object>)JSON.parse(args);
				if(objStr.equals("stock")){
					Map<String,Object> argMap = new HashMap<String, Object>();
					if(objFunc.equals("listStockByKeyword")){
						argMap.put("kw", args);
					}else if(objFunc.equals("listByDate")){
						argMap.put("date", args);
					}
					Object ret = invokeMethodRequest(stockService, objFunc, argMap);
					JSONObject jsonBODY = json.getJSONObject("body");
					jsonBODY.put("ret",ret.toString());
				}
			}
		}catch(Exception ex){
			ex.printStackTrace();
		}
	}

}

 Java代码跟数据库打交道:

编写Java服务端,比如我们编写一个按关键字读取股票列表等接口(依赖注入用的Spring):
@Repository
@CacheNamespace(implementation = org.mybatis.caches.ehcache.EhcacheCache.class, readWrite = true)
public interface StockDao {
	@Select("select SYMBOL,SHORT_NAME from `master`")
	public List<Map> listStock();
	
	@Select("select SYMBOL,SHORT_NAME from `master` where SHORT_NAME like '%${k}%' or SPELL_NAME like '%${k}%' or SYMBOL like '%${k}%' limit 0,10")
	public List<Map> listStockByKeyword(Map<String,String> map);
	
	@Select("select SYMBOL,SHORT_NAME from `master` where exch_id=8")
	public List<Map> listAllSh(Map<String,String> map);
	
	@Select("select SYMBOL,SHORT_NAME from `master` where trade_date=#dt#")
	public List<Map> listStockByDate(Map<String,String> map);
}

编写客户端C++或脚本:

gw.req("命令代码"."命令代码对应的参数列表");
//回调函数
gw.s_cb_gw.connect(function(trcode,msg){
	log("-----------------------------------------------------------------");
	log("<p>gqt server异步方式获取数据,回调信息:trcode=" + trcode + ",msg=" + msg+"</p>");
});

效果如下:

 

 

这样做的好处:

  1. 桌面或移动的客户端再也不用编写繁琐的网络通信相关的程序,只需要发送请求/订阅,处理响应/订阅数据包即可,也不用关心底层的数据分包合包,客户端代理,网络传输的加解密和压缩等;
  2. 客户端开发人员也几乎不用和服务端程序员沟通,通过JSON解析请求透传给Java,Java响应的数据带上包头和响应给客户端,客户端解析JSON即可;
  3. 跨语言的服务端虽然会损失一定的性能,但似乎这点ZeroMQ已做的足够好;

Demo程序部署步骤:

  1. 创建一个MySQL Demo数据库,数据库名:stock,utf-8编码,导入output下的stock.sql;
  2. 配置output下的config.properties文件,指定机器IP,配置jdbc.properties,确保数据库配置正确;
  3. 点击runStockServer.bat,运行stock的Java Demo服务器,可以开任意个;
  4. 配置gqt-server-communicator(cpp)下的config_ims.ini文件,IP地址全部换成机器IP;
  5. 启动ss_server.exe,ss_zserver.exe;
  6. 点击客户端GQT程序,配置config_ims.ini中的IP地址,切换到gateway的标签页,enjoy it!

猜你喜欢

转载自cxlh.iteye.com/blog/2074307