高可用性服務(wù)端的設(shè)計(jì)與實(shí)現(xiàn)
本文的客戶(hù)端基于我們的GQT開(kāi)源項(xiàng)目:http://cxlh.iteye.com/blog/2021463
本人拙見(jiàn),如有不同意見(jiàn),歡迎拍磚,同時(shí)獻(xiàn)給特別有對(duì)服務(wù)端跨語(yǔ)言需求的程序猿們!
客戶(hù)端(GQT Demo V3(服務(wù)端配套版).rar)太大請(qǐng)挪步到QQ群下載(群號(hào):101189702),注明:GQT或Java,C++等;
Java工程代碼請(qǐng)挪步下載:http://cxlh.iteye.com/blog/2074307
總體設(shè)計(jì)思路:
- 高可用性:每個(gè)業(yè)務(wù)服務(wù)端都是獨(dú)立的個(gè)體,任何一個(gè)業(yè)務(wù)服務(wù)器Crash時(shí),都不會(huì)影響服務(wù),并且業(yè)務(wù)服務(wù)器可以按需增加,業(yè)務(wù)服務(wù)端使用Java代碼實(shí)現(xiàn),主要是為了考慮更好的數(shù)據(jù)庫(kù)操作,更好的事務(wù)支持,更好的社區(qū)支持以及可用更多的開(kāi)源服務(wù),提高開(kāi)發(fā)效率;
- 自動(dòng)負(fù)載均衡:當(dāng)某個(gè)接口頻繁調(diào)用,增加的響應(yīng)服務(wù)器自動(dòng)分流接口調(diào)用壓力,也就說(shuō)我們的異步的請(qǐng)求/響應(yīng)模式下,有一個(gè)Broker仲裁程序決定客戶(hù)端發(fā)來(lái)的請(qǐng)求交由哪個(gè)Java業(yè)務(wù)服務(wù)器來(lái)處理,這個(gè)Broker程序我們采用C++代碼實(shí)現(xiàn);
- 客戶(hù)端(包括桌面或移動(dòng)端)網(wǎng)關(guān):根據(jù)策略選取遠(yuǎn)程Socket服務(wù)器連接,Socket服務(wù)器與服務(wù)器之間的消息通訊通過(guò)地址尋址遠(yuǎn)程路由,以便連在不同Socket服務(wù)器上的用戶(hù)之間可以相互通訊,典型的應(yīng)用就是聊天程序;
- Sub/Pub類(lèi)消息:客戶(hù)端訂閱服務(wù)端的服務(wù),服務(wù)端有多個(gè)Pub服務(wù)器(Java編寫(xiě)),交由Socket服務(wù)器將客戶(hù)端Sub的消息Push給Client,此時(shí)Socket服務(wù)只作為Proxy用;
好了,其實(shí)這里只有2個(gè)C++核心組件(Socket服務(wù)器,Broker仲裁程序)和N個(gè)Java業(yè)務(wù)服務(wù)器(請(qǐng)求處理服務(wù)器,Pub服務(wù)器),以下介紹用法(需要一定的客戶(hù)端編程知識(shí)和一些腳本只是):
客戶(hù)端發(fā)送請(qǐng)求,異步收取,編寫(xiě)業(yè)務(wù)代碼步驟:
編寫(xiě)Java服務(wù)端,比如我們編寫(xiě)一個(gè)按關(guān)鍵字讀取股票列表等接口(依賴(lài)注入用的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); }
編寫(xiě)Java服務(wù)就這么簡(jiǎn)單:
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Properties;
import java.util.ResourceBundle;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.gqt.server.BaseReqServer;
import com.gqt.server.ReqCallBack;
public class StockServer extends BaseReqServer {
private static Logger logger = LogManager.getLogger(StockServer.class.getName());
final static Properties prop = new Properties();
static{
InputStream is = null;
try {
String c_path = StockServer.class.getResource("/").getPath();
logger.info("c_path:{}",c_path);
is = new FileInputStream(new File(c_path+"config.properties"));
prop.load(is);
} catch (Exception e) {
e.printStackTrace();
}
}
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();
}
}
編寫(xiě)客戶(hù)端C++或腳本:
gw.req("命令代碼"."命令代碼對(duì)應(yīng)的參數(shù)列表"); //回調(diào)函數(shù) gw.s_cb_gw.connect(function(trcode,msg){ log("-----------------------------------------------------------------"); log("<p>gqt server異步方式獲取數(shù)據(jù),回調(diào)信息:trcode=" + trcode + ",msg=" + msg+"</p>"); });
效果如下:
這樣做的好處:
- 桌面或移動(dòng)的客戶(hù)端再也不用編寫(xiě)繁瑣的網(wǎng)絡(luò)通信相關(guān)的程序,只需要發(fā)送請(qǐng)求/訂閱,處理響應(yīng)/訂閱數(shù)據(jù)包即可,也不用關(guān)心底層的數(shù)據(jù)分包合包,客戶(hù)端代理,網(wǎng)絡(luò)傳輸?shù)募咏饷芎蛪嚎s等;
- 客戶(hù)端開(kāi)發(fā)人員也幾乎不用和服務(wù)端程序員溝通,通過(guò)JSON解析請(qǐng)求透?jìng)鹘oJava,Java響應(yīng)的數(shù)據(jù)帶上包頭和響應(yīng)給客戶(hù)端,客戶(hù)端解析JSON即可;
- 跨語(yǔ)言的服務(wù)端雖然會(huì)損失一定的性能,但似乎這點(diǎn)ZeroMQ已做的足夠好;
Demo程序部署步驟:
- 創(chuàng)建一個(gè)MySQL Demo數(shù)據(jù)庫(kù),數(shù)據(jù)庫(kù)名:stock,utf-8編碼,導(dǎo)入output下的stock.sql;
- 配置output下的config.properties文件,指定機(jī)器IP,配置jdbc.properties,確保數(shù)據(jù)庫(kù)配置正確;
- 點(diǎn)擊runStockServer.bat,運(yùn)行stock的Java Demo服務(wù)器,可以開(kāi)任意個(gè);
- 配置gqt-server-communicator(cpp)下的config_ims.ini文件,IP地址全部換成機(jī)器IP;
- 啟動(dòng)ss_server.exe,ss_zserver.exe;
- 點(diǎn)擊客戶(hù)端GQT程序,配置config_ims.ini中的IP地址,切換到gateway的標(biāo)簽頁(yè),enjoy it!
posted @ 2014-05-30 16:15 徐靈 閱讀(1235) | 評(píng)論 (0) | 編輯 收藏