空山雪林通用模塊工作室

           

          2010年9月9日

          高可用性服務端的設計與實現

          本文的客戶端基于我們的GQT開源項目:http://cxlh.iteye.com/blog/2021463

           

          本人拙見,如有不同意見,歡迎拍磚,同時獻給特別有對服務端跨語言需求的程序猿們!

          客戶端(GQT Demo V3(服務端配套版).rar)太大請挪步到QQ群下載(群號:101189702),注明:GQT或Java,C++等;

          Java工程代碼請挪步下載:http://cxlh.iteye.com/blog/2074307 


          總體設計思路: 

           

          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服務器),以下介紹用法(需要一定的客戶端編程知識和一些腳本只是):

          客戶端發送請求,異步收取,編寫業務代碼步驟:

           

          編寫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); }

          編寫Java服務就這么簡單:

          package com.gqt.demo;

          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();
              }
          }

          編寫客戶端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!


           

          posted @ 2014-05-30 16:15 徐靈 閱讀(1235) | 評論 (0)編輯 收藏

          也談基于Web的含工作流項目的一般開發流程

          該項目包含的通用模塊代碼等我有時間一并剝離貢獻出來(基于WebSocket的通知引擎,工作流整合模塊,自定義表單(詳見這里),基于RBAC權限設計),最近太忙了,Web項目有一段時間沒碰,有點生疏的感覺,主要在忙GQT項目,一套基于桌面開發的框架,詳見這里,寫代碼寫的有點手酸的感覺。

           

          基于Web的含工作流的項目看起來并不如想象的那么簡單,主要需求:

          1. 靈活定制工作流,并跟蹤流程進度;
          2. 每個Order含有歷史軌跡記錄,可在歷史中查看;
          3. 工作流的Action靈活,認領任務不一定非要先提取表單,因為很多節點都只有幾個動作,直接按鈕操作即可;
          4. 待辦事宜列表在不刷新頁面情況下也能變動;

          項目要求:

          1. 操作簡單高效;
          2. 權限細節到按鈕級別;
          3. 并發數少,不超過3000個在線用戶;

          主要可能使用到技術:

          1. 工作流引擎,我這里選用Activiti5,很靈活好用;
          2. 權限使用Spring Security,基于標簽式管理權限很方便;
          3. 通知引擎使用WebSocket,基于Flash實時通信,基于socket.io;
          4. 權限粒度基于經典的RBAC;
          5. 總體框架Spring MVC+Mybatis;

          實現的WebSocket的總體思路:

          1. WebSocket Server獨立于Web項目,Web Server與WebSocket Server之間的局域網通信基于簡單的Socket通信,這樣這個組件可以完全解耦和通用;
          2. 當Web項目要Push消息到Client時,通過Web Server的Socket Client向WebSocket Server的Socker Server發送消息,然后WebSocket Server收到消息后解碼,廣播到所有瀏覽器;

          我們實現的事件通知非常簡單,設定全局變量并讓瀏覽器偵聽:

          var G_WebSocket=false; 
          var EVENT_ORDER_CHANGE_STATUS = "orderChange";
          var EVENT_ORDER_CHANGE_AMOUNT = "amountChange";
          var EVENT_ORDER_CHANGE_REFUND = "refundChange";
          WebSocket.init = function(callbackFunc){
          socket = io.connect(connUrl, connOptions);
          socket.on('connect', function() {
          G_WebSocket=true;
          callbackFunc("connect",null);
          });
          socket.on('disconnect', function() {
          G_WebSocket=false;
          callbackFunc("disconnect",null);
          });
          socket.on('clientQuit', function(obj){
          G_WebSocket=false;
          callbackFunc("clientQuit",obj);
          });
          socket.on('broadcast', function(obj) {
          callbackFunc("broadcast",obj);
          });
          };

           

          在需要偵聽WebSocket接受Web Server推送消息的地方加上一個函數即可:

          	WebSocket.init(function(command,jsonObj){ 		
          if(command=="broadcast"){
          if(jsonObj.e == EVENT_ORDER_CHANGE_STATUS){
          //TODO:write your code here
          }else if(jsonObj.e == EVENT_ORDER_CHANGE_AMOUNT){
          //TODO:write your code here
          }else if(jsonObj.e == EVENT_ORDER_CHANGE_REFUND){
          //TODO:write your code here
          }
          }
          });

           這樣的結構要擴展推送服務很簡單,比如按頻道推送等,都可以很容易的擴展。

          再看看看工作流,我們實現了activiti通用的申請提交任務流程和自定義表單功能,提取跟蹤流程圖功能等,這樣你要設計一個新流程也變得非常簡單,只需要在eclipse里劃上工作流圖,在后臺發布,然后通過SpringMVC的RestAPI啟動實例流程,申領完成任務等,如下圖:



           流程走到了分支的兩個節點上,這樣對后續新增的工作流提供了極大的遍歷。

          最后說說Spring Security,基于RBAC的權限體系搭建好后(可以用在任何管理系統中),要在頁面中訪問一個資源,首先判斷一下是否有權限,如下HTML:

          <sec:authorize ifAllGranted="r_pd"> 
          <a href="#">resource access here</a>
          </sec:authorize>

           

          <sec:authorize url="/XXX/XXX/XXX.html"> 	
          <a href="XXX/XXX/XXX.html'">
          <span>XXX功能</span>
          </a>
          </sec:authorize>

            

          前臺由于項目比較小,沒有用到js的MVC框架,如backbone等,這里就不再記錄了。

           

           

          posted @ 2014-03-20 12:48 徐靈 閱讀(1677) | 評論 (6)編輯 收藏

          Openfire 3.7.0提供的優秀開源在線客服系統

          Openfire 3.7.0開始官方為我們提供了一套優秀的在線客服系統,你可以按如下步驟安裝使用這套在線客服系統:
          1. 安裝和部署Openfire 3.7.0
          2. 安裝fastpath插件
          3. 從openfire的svn上下載webchat源碼,webchat導入到eclipse中的工程如下圖:
           
          這套系統為我們提供了嵌入到客戶端代碼的源碼,客戶端只需要簡單的嵌入如下代碼,即可顯示在線客服圖標:<html>
          <head>
          <title>Fastpath Web Chat</title>
          <script language="JavaScript" type="text/javascript" src="http://www.faqee.com:7080/webchat2/jivelive.jsp"></script>
          </head>
          <body>
          <script>
                showChatButton('demo@workgroup.nb.faqee.com');
           
          </script>
          </body>
          </html>
          但點擊在線客服圖標時,如下圖:

          客服端使用Spark接受來自訪客的請求的,點擊Accept,如下圖:


          我們為您提供了9個客服賬號,請用Spark登陸,嵌入的訪客代碼見博客,有興趣的朋友可以測試一下:)
          服務器填入:nb.faqee.com
          客服賬號:vms01/vms01,vms02/vms02,……,vms09/vms09
          訪客嵌入代碼測試地址:
          http://code.faqee.com/interface/fastpath.jsp

          posted @ 2011-03-09 12:51 徐靈 閱讀(8206) | 評論 (12)編輯 收藏

          Flash開發開源工具推薦—FlashDevelop

          偶玩的版本是3.3.1,簡單而華麗的外表,界面截圖如下:


          ?

          安裝FD,你首先需要安裝:

          1. JDK 1.6以上版本
          2. .Net運行環境
          繼而你就可以一路Next完成安裝了……

          安裝完成后,你必須去adobe官方網站下載開源的Flex SDK,我這邊下載的版本是:flex_sdk_3.5.0.12683_mpl

          下載完成后,解壓到某個目錄下即可,如:F:\flex_sdk_3.5.0.12683_mpl

          然后在FD中設置Flex SDK,如下圖:



          ?
          我們這邊以Open Flash Chart為例,導入項目工程,點擊運行,如下圖:



          ?
          你可以設置斷點,運行表達式,使用起來非常方便,強烈推薦給大家使用!


          已有 1 人發表留言,猛擊->>這里<<-參與討論


          JavaEye推薦



          posted @ 2010-10-12 08:43 徐靈 閱讀(257) | 評論 (0)編輯 收藏

          國慶度假小記

          10月5,6日去寧波附近的度假村旅游了一下,一家3人出發了,由于兒子還比較小,怕他累著,所以這次就去了九龍湖開元名都大酒店度假村,5星級的酒店,住了一晚,有點小貴,協議價后也得880元一晚,不過是無敵湖景房,超大陽臺,陽臺上就可以看到整個九龍湖,甚是壯觀,兒子玩的開心的不得了,在酒店的花園里滑滑板車,5日早上出發,6日中午回來,在回來的路上,順便小逛了一下慈城古鎮,到寧波吃了點飯,到家就該兒子的睡覺時間了……這個國慶節3日就簡單的陪兒子在東錢湖上座了下船,他很喜歡坐船的……其實時間都在不知不覺中度過,國慶長假結束了……

          ?

          PS:附上酒店小圖一張,以之紀念……

          ?





          已有 0 人發表留言,猛擊->>這里<<-參與討論


          JavaEye推薦



          posted @ 2010-10-07 20:29 徐靈 閱讀(130) | 評論 (0)編輯 收藏

          利用Spring 3實現Rest配置與開發

          最近項目要用到Rest,選擇了Spring 3,關于Rest的介紹:

          ?

          ?

          ?REST關鍵原則
          REST定義了應該如何正確地使用(這和大多數人的實際使用方式有很大不同)Web標準,例如HTTP和URI。如果你在設計應用程序時能堅持REST原則,那就預示著你將會得到一個使用了優質Web架構(這將讓你受益)的系統。總之,五條關鍵原則列舉如下:

          1. 為所有“事物”定義ID
          2. 將所有事物鏈接在一起
          3. 使用標準方法
          4. 資源多重表述
          5. 無狀態通信

          ?

          Spring 3.0開始將全面支持Rest,而且配置實現起來也相當簡單,利用Spring MVC在web.xml定義片段:

          ?

          ?

          	<servlet>  
                  <servlet-name>mydemo</servlet-name>  
                  <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
                  <load-on-startup>1</load-on-startup>  
              </servlet>  
                
              <servlet-mapping>  
                  <servlet-name>mydemo</servlet-name>  
                  <url-pattern>/</url-pattern>  
              </servlet-mapping> 

          ?

          繼而在Web-INF目錄下增加mydemo-servlet.xml,內容如下:

          ?

          ?

          <?xml version="1.0" encoding="UTF-8"?>
          <beans xmlns="http://www.springframework.org/schema/beans"
          	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          	xmlns:p="http://www.springframework.org/schema/p"
          	xmlns:context="http://www.springframework.org/schema/context"
          	xsi:schemaLocation="http://www.springframework.org/schema/beans
          		http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
          		http://www.springframework.org/schema/context
          		http://www.springframework.org/schema/context/spring-context-3.0.xsd">
          	
          	<!-- Auto scan, declare the location path -->  
          	<context:component-scan base-package="com.mydemo.springmvc.rest" />  
          
          	<!-- Using annontation -->  
          	<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" /> 
          	
          	<!-- Resolve the view, declare the prefix and suffix -->  
          	<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"  
          		p:prefix="/view/" p:suffix=".jsp" p:viewClass="org.springframework.web.servlet.view.JstlView" />  
          	 
          	<bean id="multipartResolver"  
          		class="org.springframework.web.multipart.commons.CommonsMultipartResolver"  
          		p:defaultEncoding="utf-8" /> 
          </beans>

          ?

          這里我們定義了JSP文件的標簽庫用jstl,并啟動了注解功能,并自動掃描com.mydemo.springmvc.rest下的controller,接著我們就可以在com.mydemo.springmvc.rest包下編寫controller代碼

          并可以使用注解功能,如類似的代碼如下:

          ?

          ?

          @Controller
          public class MyDemoController {
          	private CommonDAO commonDAO;
          	@Autowired
          	public void setCommonDAO(CommonDAO commonDAO) {
          		this.commonDAO = commonDAO;
          	}
          
          	private MyDemoController (){}
          	
          	@RequestMapping(value="/home", method=RequestMethod.GET)
          	public String welcome(){
          		return "/home";
          	}
          }
          ?

          然后就可以在view目錄下通過增加home.jsp來實現顯示層代碼的編寫工作,所有的步驟就以上這些,接下去你就可以通過類似:http://localhost:8080/mydemo/home,來訪問了(這里Controller通過注解的方式注入DAO以便進行數據庫的訪問)



          已有 0 人發表留言,猛擊->>這里<<-參與討論


          JavaEye推薦



          posted @ 2010-09-28 13:19 徐靈 閱讀(577) | 評論 (0)編輯 收藏

          上海出差整整一周

          最近一周都在上海出差,終于還是決定到新公司發展,希望能在新的環境有另一番作為吧

          ?

          本周主要在上海探討產品架構,以及針對需求的概要設計,將公司的新產品有概念轉化為產品,雖然新公司是個剛起步的公

          ?

          司,但作為產品還是相當有市場潛力的,而且目前國內做同類產品的相對很少,希望能做出點成績,也作為而立之年的小小

          ?

          考驗,加油……



          已有 0 人發表留言,猛擊->>這里<<-參與討論


          JavaEye推薦



          posted @ 2010-09-16 08:46 徐靈 閱讀(130) | 評論 (0)編輯 收藏

          愛要大聲說出來……

          今天看到首頁博客上看到“喜歡一個人的理由”博文,深有感觸,特別是干我們這行的,往往都比較內向,也從來不向心儀的女孩表白占了多數,讀工科的總是木訥些,當初的我也一樣。


          我也是其中一員,曾經心儀的高中女生,自我讀大學后,我也跟她保持的書信來往,記得第一次寫信地址還是通過校友錄知道的,很快我們成為了“筆友”,相對來說,我和寫那篇博文的作者差不多,自身條件并不怎么優越,170的身高,還要打個99折,她算是個“全優女生”,成績好,長相也不錯,所以我始終沒有表白,也是怕最后連“筆友”也沒得做,一直維持著大學結束,她讀醫的,所以比我多讀一年,工作后,“筆友”變成了“話友”,短信IP電話時時騷擾,在大學期間,我還為她和我的經歷虛構寫成了一篇偵探小說,但我比寫博客的作者幸運的是,我在最后的時刻還是表白了,她沒馬上答復我,一周后,她成為了我的女友,2年后,她成為了我的妻子……


          愛要大聲說出來,要不然就會連最后的希望都沒有……男女單純的友誼能維持多久呢……我想都是用來忽悠的吧,所以應該抓住每一次機會,愛要大聲說出來……



          已有 5 人發表留言,猛擊->>這里<<-參與討論


          JavaEye推薦



          posted @ 2010-09-09 11:13 徐靈 閱讀(221) | 評論 (1)編輯 收藏

          導航

          友情鏈接

          最新評論

          主站蜘蛛池模板: 临澧县| 朝阳市| 阿拉善右旗| 英山县| 德安县| 西乌| 青岛市| 古丈县| 嘉荫县| 安阳市| 江津市| 巨鹿县| 大庆市| 孝义市| 三河市| 绥棱县| 裕民县| 库车县| 北辰区| 丹巴县| 瑞安市| 黎城县| 河北区| 镇坪县| 锦屏县| 玉溪市| 通化市| 清水县| 天台县| 定日县| 崇仁县| 铜梁县| 石景山区| 云林县| 双流县| 小金县| 河东区| 邢台市| 临安市| 安达市| 永修县|