摘要: 首先先介紹一款知名的網站壓力測試工具:webbench.Webbench能測試處在相同硬件上,不同服務的性能以及不同硬件上同一個服務的運行狀況。webbench的標準測試可以向我們展示服務器的兩項內容:每分鐘相應請求數和每秒鐘傳輸數據量。webbench不但能具有便準靜態頁面的測試能力,還能對動態頁面(ASP,PHP,JAVA,CGI)進 行測試的能力。還有就是他支持對含有SSL的安全網站例如電子...  閱讀全文
          posted @ 2015-03-17 09:59 小馬歌 閱讀(319) | 評論 (0)編輯 收藏
           
          from: http://nll.im/post/tomcat-apr.html

          操作系統:Centos6.3
          Tomcat:7.0.42
          JDK:1.6.0_45
          配置:8G,4核.

          最近tomcat負載比較高,默認的配置和bio的處理方式已經無力支撐.據說APR能提升50%~60%的性能,所以嘗試下APR優化.
          APR介紹:

          Tomcat可以使用APR來提供超強的可伸縮性和性能,更好地集成本地服務器技術。  APR(Apache Portable Runtime)是一個高可移植庫,它是Apache HTTP Server 2.x的核心。  APR有很多用途,包括訪問高級IO功能(例如sendfile,epoll和OpenSSL),OS級別功能(隨機數生成,系統狀態等等),本地進程管理(共享內存,NT管道和UNIX sockets)。這些功能可以使Tomcat作為一個通常的前臺WEB服務器,能更好地和其它本地web技術集成,總體上讓Java更有效率作為一個高性能web服務器平臺而不是簡單作為后臺容器。  在產品環境中,特別是直接使用Tomcat做WEB服務器的時候,應該使用Tomcat Native來提高其性能。

          1. 服務器安裝GCC

          客戶服務器連不上外網,服務器也沒有gcc,所以先使用代理連接外網,修改/etc/yum.conf,加入代理配置:

          proxy=http://10.103.0.46:808

          如果需要驗證加入用戶名密碼:

          proxy_username=代理服務器用戶名 proxy_password=代理服務器密碼 

          yum使用163的Centos源:參考http://mirrors.163.com/.help/centos.html
          先備份

          mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 

          然后下載CentOS6 放入到/etc/yum.repos.d/(操作前請做好相應備份)

          運行以下命令生成緩存:

          yum clean all yum makecache 

          然后安裝gcc:

          yum -y install gcc 

          2. 安裝APR

          http://apr.apache.org/download.cgi下載apr,apr-util,apr-iconv. 因為服務器沒有配置全局的http代理,只是yum代理,所以下載之后傳到服務器即可.

          傳輸完安裝apr:

          tar zxvf apr-1.5.1.tar.gz cd apr-1.5.1 ./configure --prefix=/usr/local/apr make make install 

          安裝apr-iconv:

          tar zxvf apr-iconv-1.2.1.tar.gz cd apr-iconv-1.2.1 ./configure --prefix=/usr/local/apr-iconv --with-apr=/usr/local/apr make make install 

          安裝apr-util:

          tar zxvf apr-util-1.5.3.tar.gz cd apr-util-1.5.3 ./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr --with-apr-iconv=/usr/local/apr-iconv/bin/apriconv make   make install 

          安裝tomcat-native:首先到tomcat/bin目錄下,找到對應的tar文件.

          tar zxvf tomcat-native.tar.gz cd tomcat-native-1.1.27-src/jni/native/ ./configure --with-apr=/usr/local/apr --with-java-home=/usr/lib/jdk1.6.0_45 make make install 

          安裝完成之后 會出現如下提示信息

          Libraries have been installed in: /usr/local/apr/lib 

          添加環境變量: vi /etc/profile在文件末尾處添加下面的變量

          export LD_LIBRARY_PATH=/usr/local/apr/lib 

          然后執行下面命令,使環境變量即時生效

          source /etc/profile 

          以下為完整安裝腳本:

          #setup apr tar zxvf apr-1.5.1.tar.gz cd apr-1.5.1 ./configure --prefix=/usr/local/apr make && make install cd ../ #setup apr-iconv tar zxvf apr-iconv-1.2.1.tar.gz cd apr-iconv-1.2.1/ ./configure --prefix=/usr/local/apr-iconv --with-apr=/usr/local/apr make && make install cd ../ #setup apr-util tar zxvf apr-util-1.5.3.tar.gz cd apr-util-1.5.3 ./configure --prefix=/usr/local/apr-util --with-apr=/usr/local/apr --with-apr-iconv=/usr/local/apr-iconv/bin/apriconv make && make install #setup tomcat-native cd /app/apache-tomcat-7.0.42/bin tar zxvf tomcat-native.tar.gz cd tomcat-native-1.1.27-src/jni/native ./configure --with-apr=/usr/local/apr --with-java-home=/usr/lib/jdk1.6.0_45 make && make install cd / #LD_LIBRARY_PATH echo -e 'export LD_LIBRARY_PATH=/usr/local/apr/lib' >> /etc/profile export LD_LIBRARY_PATH=/usr/local/apr/lib source /etc/profile 

          3. 配置Tomcat

          修改tomcat配置conf/server.xml:

          <!--The connectors can use a shared executor, you can define one or more named thread pools-->     <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"         maxThreads="800" minSpareThreads="400"/>        <!-- A "Connector" represents an endpoint by which requests are received          and responses are returned. Documentation at :          Java HTTP Connector: /docs/config/http.html (blocking & non-blocking)          Java AJP  Connector: /docs/config/ajp.html          APR (HTTP/AJP) Connector: /docs/apr.html          Define a non-SSL HTTP/1.1 Connector on port 8080     -->     <Connector port="80" executor="tomcatThreadPool" protocol="org.apache.coyote.http11.Http11AprProtocol"                connectionTimeout="20000"                redirectPort="8443" enableLookups="false" acceptCount="1000"/> 

          修改為Http11AprProtocol 協議.

          之后啟動tomcat即可.

          遇到問題:

          SEVERE: Failed to initialize the SSLEngine. org.apache.tomcat.jni.Error: 70023: This function has not been implemented on this platform 

          請關閉SSL偵聽,除非你有使用SSL,修改conf/server.xml

          <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="off" /> 

          壓測結果:

          webbench -c 4000 -t 30 http://10.103.10.140/workbench/index.jsp Webbench - Simple Web Benchmark 1.5 Copyright (c) Radim Kolar 1997-2004, GPL Open Source Software.  Benchmarking: GET http://10.103.10.140/workbench/index.jsp 4000 clients, running 30 sec.  Speed=484340 pages/min, 2441573 bytes/sec. Requests: 242170 susceed, 0 failed. 

          參考:

          http://www.chepoo.com/tomcat-performance-three-times-is-not-a-dream.html

          http://rhomobi.com/topics/36

          https://gitsea.com/2013/07/02/tomcat-%E5%B9%B6%E5%8F%91%E4%BC%98%E5%8C%96/

          http://pengranxiang.iteye.com/blog/1128905

          http://tomcat.apache.org/tomcat-7.0-doc/apr.html#Linux

          http://www.cnblogs.com/wanghaosoft/archive/2013/02/04/2892099.html

          posted @ 2015-03-16 18:59 小馬歌 閱讀(346) | 評論 (0)編輯 收藏
           

          本文轉載自xum2008的博客,主要介紹13款現有的開源搜索引擎,你可以將它們用在你的項目中以實現檢索功能。 


          1.  Lucene 

          Lucene的開發語言是Java,也是Java家族中最為出名的一個開源搜索引擎,在Java世界中已經是標準的全文檢索程序,它提供了完整的查詢引擎和索引引擎,沒有中文分詞引擎,需要自己去實現,因此用Lucene去做一個搜素引擎需要自己去架構.另外它不支持實時搜索,但linkedin和twitter有分別對Lucene改進的實時搜素. 其中Lucene有一個C++移植版本叫CLucene,CLucene因為使用C++編寫,所以理論上要比lucene快. 

          官方主頁:http://lucene.apache.org/ 

          CLucene官方主頁:http://sourceforge.net/projects/clucene/ 

          2.  Sphinx 

          Sphinx是一個用C++語言寫的開源搜索引擎,也是現在比較主流的搜索引擎之一,在建立索引的事件方面比Lucene快50%,但是索引文件比Lucene要大一倍,因此Sphinx在索引的建立方面是空間換取事件的策略,在檢索速度上,和lucene相差不大,但檢索精準度方面Lucene要優于Sphinx,另外在加入中文分詞引擎難度方面,Lucene要優于Sphinx.其中Sphinx支持實時搜索,使用起來比較簡單方便. 

          官方主頁:http://sphinxsearch.com/about/sphinx/ 

          3.  Xapian 

          Xapian是一個用C++編寫的全文檢索程序,它的api和檢索原理和lucene在很多方面都很相似,算是填補了lucene在C++中的一個空缺. 

          官方主頁:http://xapian.org/ 

          4.  Nutch 

          Nutch是一個用java實現的開源的web搜索引擎,包括爬蟲crawler,索引引擎,查詢引擎. 其中Nutch是基于Lucene的,Lucene為Nutch提供了文本索引和搜索的API. 

          對于應該使用Lucene還是使用Nutch,應該是如果你不需要抓取數據的話,應該使用Lucene,最常見的應用是:你有數據源,需要為這些數據提供一個搜索頁面,在這種情況下,最好的方式是直接從數據庫中取出數據,并用Lucene API建立索引. 

          官方主頁:http://nutch.apache.org/ 

          5.  DataparkSearch 

          DataparkSearch是一個用C語言實現的開源的搜索引擎. 其中網頁排序是采用神經網絡模型.  其中支持HTTP,HTTPS,FTP,NNTP等下載網頁.包括索引引擎,檢索引擎和中文分詞引擎(這個也是唯一的一個開源的搜索引擎里有中文分詞引擎).能個性化定制搜索結果,擁有完整的日志記錄. 

          官方主頁:http://www.dataparksearch.org/ 

          6.  Zettair 

          Zettair是根據Justin Zobel的研究成果為基礎的全文檢索實驗系統.它是用C語言實現的. 其中Justin Zobel在全文檢索領域很有名氣,是業界第一個系統提出倒排序索引差分壓縮算法的人,倒排列表的壓縮大大提高了檢索和加載的性能,同時空間膨脹率也縮小到相當優秀的水平. 由于Zettair是源于學術界,代碼是由RMIT University的搜索引擎組織寫的,因此它的代碼簡潔精煉,算法高效,是學習倒排索引經典算法的非常好的實例. 其中支持linux,windows,mac os等系統. 

          官方主頁:http://www.seg.rmit.edu.au/zettair/about.html 

          7.  Indri 

          Indri是一個用C語言和C++語言寫的全文檢索引擎系統,是由University of Massachusetts和Carnegie Mellon University合作推出的一個開源項目. 特點是跨平臺,API接口支持Java,PHP,C++. 

          官方主頁:http://www.lemurproject.org/indri/ 

          8.  Terrier 

          Terrier是由School of Computing Science,Universityof Glasgow用java開發的一個全文檢索系統. 

          官方主頁:http://terrier.org/ 

          9.  Galago 

          Galago是一個用java語言寫的關于文本搜索的工具集. 其中包括索引引擎和查詢引擎,還包括一個叫TupleFlow的分布式計算框架(和google的MapReduce很像).這個檢索系統支持很多Indri查詢語言. 

          官方主頁:http://www.galagosearch.org/ 

          10.  Zebra 

          Zebra是一個用C語言實現的檢索程序,特點是對大數據的支持,支持EMAIL,XML,MARC等格式的數據. 

          官方主頁:https://www.indexdata.com/zebra 

          11.  Solr 

          Solr是一個用java開發的獨立的企業級搜索應用服務器,它提供了類似于Web-service的API接口,它是基于Lucene的全文檢索服務器,也算是Lucene的一個變種,很多一線互聯網公司都在使用Solr,也算是一種成熟的解決方案. 

          官方主頁:http://lucene.apache.org/solr/ 

          12.  Elasticsearch 

          Elasticsearch是一個采用java語言開發的,基于Lucene構造的開源,分布式的搜索引擎. 設計用于云計算中,能夠達到實時搜索,穩定可靠. Elasticsearch的數據模型是JSON. 

          官方主頁:http://www.elasticsearch.org/ 

          13.  Whoosh 

          Whoosh是一個用純python寫的開源搜索引擎. 

          官方主頁:https://bitbucket.org/mchaput/whoosh/wiki/Home  

          1. 增加一個,SolrCloud是基于Solr和Zookeeper的分布式搜索方案,是正在開發中的Solr4.0的核心組件之一,它的主要思想是使用Zookeeper作為集群的配置信息中心。它有幾個特色功能:1)集中式的配置信息 2)自動容錯 3)近實時搜索 4)查詢時自動負載均衡
          posted @ 2015-03-16 18:37 小馬歌 閱讀(383) | 評論 (0)編輯 收藏
           
          from:http://songwie.com/articlelist/21

          mysql數據庫切分

          前言

          通過MySQLReplication功能所實現的擴展總是會受到數據庫大小的限制,一旦數據庫過于龐大,尤其是當寫入過于頻繁,很難由一臺主機支撐的時候,我們還是會面臨到擴展瓶頸。這時候,我們就必須許找其他技術手段來解決這個瓶頸,那就是我們這一章所要介紹惡的數據切分技術。

           

          何謂數據切分

          可能很多讀者朋友在網上或者雜志上面都已經多次見到關于數據切分的相關文章了,只不過在有些文章中稱之為數據的Sharding。其實不管是稱之為數據的Sharding還是數據的切分,其概念都是一樣的。簡單來說,就是指通過某種特定的條件,將我們存放在同一個數據庫中的數據分散存放到多個數據庫(主機)上面,以達到分散單臺設備負載的效果。數據的切分同時還可以提高系統的總體可用性,因為單臺設備Crash之后,只有總體數據的某部分不可用,而不是所有的數據。

          數據的切分(Sharding)根據其切分規則的類型,可以分為兩種切分模式。一種是按照不同的表(或者Schema)來切分到不同的數據庫(主機)之上,這種切可以稱之為數據的垂直(縱向)切分;另外一種則是根據表中的數據的邏輯關系,將同一個表中的數據按照某種條件拆分到多臺數據庫(主機)上面,這種切分稱之為數據的水平(橫向)切分。

          垂直切分的最大特點就是規則簡單,實施也更為方便,尤其適合各業務之間的耦合度非常低,相互影響很小,業務邏輯非常清晰的系統。在這種系統中,可以很容易做到將不同業務模塊所使用的表分拆到不同的數據庫中。根據不同的表來進行拆分,對應用程序的影響也更小,拆分規則也會比較簡單清晰。

          水平切分于垂直切分相比,相對來說稍微復雜一些。因為要將同一個表中的不同數據拆分到不同的數據庫中,對于應用程序來說,拆分規則本身就較根據表名來拆分更為復雜,后期的數據維護也會更為復雜一些。

          當我們某個(或者某些)表的數據量和訪問量特別的大,通過垂直切分將其放在獨立的設備上后仍然無法滿足性能要求,這時候我們就必須將垂直切分和水平切分相結合,先垂直切分,然后再水平切分,才能解決這種超大型表的性能問題。

          下面我們就針對垂直、水平以及組合切分這三種數據切分方式的架構實現及切分后數據的整合進行相應的分析。

           

          數據的垂直切分

          我們先來看一下,數據的垂直切分到底是如何一個切分法的。數據的垂直切分,也可以稱之為縱向切分。將數據庫想象成為由很多個一大塊一大塊的“數據塊”(表)組成,我們垂直的將這些“數據塊”切開,然后將他們分散到多臺數據庫主機上面。這樣的切分方法就是一個垂直(縱向)的數據切分。

          一個架構設計較好的應用系統,其總體功能肯定是由很多個功能模塊所組成的,而每一個功能模塊所需要的數據對應到數據庫中就是一個或者多個表。而在架構設計中,各個功能模塊相互之間的交互點越統一越少,系統的耦合度就越低,系統各個模塊的維護性以及擴展性也就越好。這樣的系統,實現數據的垂直切分也就越容易。

          當我們的功能模塊越清晰,耦合度越低,數據垂直切分的規則定義也就越容易。完全可以根據功能模塊來進行數據的切分,不同功能模塊的數據存放于不同的數據庫主機中,可以很容易就避免掉跨數據庫的Join存在,同時系統架構也非常的清晰。

          當然,很難有系統能夠做到所有功能模塊所使用的表完全獨立,完全不需要訪問對方的表或者需要兩個模塊的表進行Join操作。這種情況下,我們就必須根據實際的應用場景進行評估權衡。決定是遷就應用程序將需要Join的表的相關某快都存放在同一個數據庫中,還是讓應用程序做更多的事情,也就是程序完全通過模塊接口取得不同數據庫中的數據,然后在程序中完成Join操作。

          一般來說,如果是一個負載相對不是很大的系統,而且表關聯又非常的頻繁,那可能數據庫讓步,將幾個相關模塊合并在一起減少應用程序的工作的方案可以減少較多的工作量,是一個可行的方案。

          當然,通過數據庫的讓步,讓多個模塊集中共用數據源,實際上也是簡介的默許了各模塊架構耦合度增大的發展,可能會讓以后的架構越來越惡化。尤其是當發展到一定階段之后,發現數據庫實在無法承擔這些表所帶來的壓力,不得不面臨再次切分的時候,所帶來的架構改造成本可能會遠遠大于最初的時候。

          所以,在數據庫進行垂直切分的時候,如何切分,切分到什么樣的程度,是一個比較考驗人的難題。只能在實際的應用場景中通過平衡各方面的成本和收益,才能分析出一個真正適合自己的拆分方案。

          比如在本書所使用示例系統的example數據庫,我們簡單的分析一下,然后再設計一個簡單的切分規則,進行一次垂直垂直拆分。

          系統功能可以基本分為四個功能模塊:用戶,群組消息,相冊以及事件,分別對應為如下這些表:

          1. 用戶模塊表:user,user_profile,user_group,user_photo_album

          2. 群組討論表:groups,group_message,group_message_content,top_message

          3. 相冊相關表:photo,photo_album,photo_album_relation,photo_comment

          4. 事件信息表:event

          初略一看,沒有哪一個模塊可以脫離其他模塊獨立存在,模塊與模塊之間都存在著關系,莫非無法切分?

          當然不是,我們再稍微深入分析一下,可以發現,雖然各個模塊所使用的表之間都有關聯,但是關聯關系還算比較清晰,也比較簡單。

          ◆群組討論模塊和用戶模塊之間主要存在通過用戶或者是群組關系來進行關聯。一般關聯的時候都會是通過用戶的id或者nick_name以及group的id來進行關聯,通過模塊之間的接口實現不會帶來太多麻煩;

          ◆相冊模塊僅僅與用戶模塊存在通過用戶的關聯。這兩個模塊之間的關聯基本就有通過用戶id關聯的內容,簡單清晰,接口明確;

          ◆ 事件模塊與各個模塊可能都有關聯,但是都只關注其各個模塊中對象的ID信息,同樣可以做到很容易分拆。

          所以,我們第一步可以將數據庫按照功能模塊相關的表進行一次垂直拆分,每個模塊所涉及的表單獨到一個數據庫中,模塊與模塊之間的表關聯都在應用系統端通過藉口來處理。如下圖所示:

          通過這樣的垂直切分之后,之前只能通過一個數據庫來提供的服務,就被分拆成四個數據庫來提供服務,服務能力自然是增加幾倍了。

          垂直切分的優點

          ◆ 數據庫的拆分簡單明了,拆分規則明確;

          ◆ 應用程序模塊清晰明確,整合容易;

          ◆ 數據維護方便易行,容易定位;

          垂直切分的缺點

          ◆ 部分表關聯無法在數據庫級別完成,需要在程序中完成;

          ◆ 對于訪問極其頻繁且數據量超大的表仍然存在性能平靜,不一定能滿足要求;

          ◆ 事務處理相對更為復雜;

          ◆ 切分達到一定程度之后,擴展性會遇到限制;

          ◆ 過讀切分可能會帶來系統過渡復雜而難以維護。

          針對于垂直切分可能遇到數據切分及事務問題,在數據庫層面實在是很難找到一個較好的處理方案。實際應用案例中,數據庫的垂直切分大多是與應用系統的模塊相對應,同一個模塊的數據源存放于同一個數據庫中,可以解決模塊內部的數據關聯問題。而模塊與模塊之間,則通過應用程序以服務接口方式來相互提供所需要的數據。雖然這樣做在數據庫的總體操作次數方面確實會有所增加,但是在系統整體擴展性以及架構模塊化方面,都是有益的。可能在某些操作的單次響應時間會稍有增加,但是系統的整體性能很可能反而會有一定的提升。而擴展瓶頸問題,就只能依靠下一節將要介紹的數據水平切分架構來解決了。

           

          數據的水平切分

          上面一節分析介紹了數據的垂直切分,這一節再分析一下數據的水平切分。數據的垂直切分基本上可以簡單的理解為按照表按照模塊來切分數據,而水平切分就不再是按照表或者是功能模塊來切分了。一般來說,簡單的水平切分主要是將某個訪問極其平凡的表再按照某個字段的某種規則來分散到多個表之中,每個表中包含一部分數據。

          簡單來說,我們可以將數據的水平切分理解為是按照數據行的切分,就是將表中的某些行切分到一個數據庫,而另外的某些行又切分到其他的數據庫中。當然,為了能夠比較容易的判定各行數據被切分到哪個數據庫中了,切分總是都需要按照某種特定的規則來進行的。如根據某個數字類型字段基于特定數目取模,某個時間類型字段的范圍,或者是某個字符類型字段的hash值。如果整個系統中大部分核心表都可以通過某個字段來進行關聯,那這個字段自然是一個進行水平分區的上上之選了,當然,非常特殊無法使用就只能另選其他了。

          一般來說,像現在互聯網非常火爆的Web2.0類型的網站,基本上大部分數據都能夠通過會員用戶信息關聯上,可能很多核心表都非常適合通過會員ID來進行數據的水平切分。而像論壇社區討論系統,就更容易切分了,非常容易按照論壇編號來進行數據的水平切分。切分之后基本上不會出現各個庫之間的交互。

          如我們的示例系統,所有數據都是和用戶關聯的,那么我們就可以根據用戶來進行水平拆分,將不同用戶的數據切分到不同的數據庫中。當然,唯一有點區別的是用戶模塊中的groups表和用戶沒有直接關系,所以groups不能根據用戶來進行水平拆分。對于這種特殊情況下的表,我們完全可以獨立出來,單獨放在一個獨立的數據庫中。其實這個做法可以說是利用了前面一節所介紹的“數據的垂直切分”方法,我將在下一節中更為詳細的介紹這種垂直切分與水平切分同時使用的聯合切分方法。

          所以,對于我們的示例數據庫來說,大部分的表都可以根據用戶ID來進行水平的切分。不同用戶相關的數據進行切分之后存放在不同的數據庫中。如將所有用戶ID通過2取模然后分別存放于兩個不同的數據庫中。每個和用戶ID關聯上的表都可以這樣切分。這樣,基本上每個用戶相關的數據,都在同一個數據庫中,即使是需要關聯,也可以非常簡單的關聯上。

          我們可以通過下圖來更為直觀的展示水平切分相關信息:水平切分的優點

          ◆ 表關聯基本能夠在數據庫端全部完成;

          ◆ 不會存在某些超大型數據量和高負載的表遇到瓶頸的問題;

          ◆ 應用程序端整體架構改動相對較少;

          ◆ 事務處理相對簡單;

          ◆ 只要切分規則能夠定義好,基本上較難遇到擴展性限制;

          水平切分的缺點

          ◆ 切分規則相對更為復雜,很難抽象出一個能夠滿足整個數據庫的切分規則;

          ◆ 后期數據的維護難度有所增加,人為手工定位數據更困難;

          ◆ 應用系統各模塊耦合度較高,可能會對后面數據的遷移拆分造成一定的困難。

           

          垂直與水平切分的聯合使用

          上面兩節內容中,我們分別,了解了“垂直”和“水平”這兩種切分方式的實現以及切分之后的架構信息,同時也分析了兩種架構各自的優缺點。但是在實際的應用場景中,除了那些負載并不是太大,業務邏輯也相對較簡單的系統可以通過上面兩種切分方法之一來解決擴展性問題之外,恐怕其他大部分業務邏輯稍微復雜一點,系統負載大一些的系統,都無法通過上面任何一種數據的切分方法來實現較好的擴展性,而需要將上述兩種切分方法結合使用,不同的場景使用不同的切分方法。

          在這一節中,我將結合垂直切分和水平切分各自的優缺點,進一步完善我們的整體架構,讓系統的擴展性進一步提高。

          一般來說,我們數據庫中的所有表很難通過某一個(或少數幾個)字段全部關聯起來,所以很難簡單的僅僅通過數據的水平切分來解決所有問題。而垂直切分也只能解決部分問題,對于那些負載非常高的系統,即使僅僅只是單個表都無法通過單臺數據庫主機來承擔其負載。我們必須結合“垂直”和“水平”兩種切分方式同時使用,充分利用兩者的優點,避開其缺點。

          每一個應用系統的負載都是一步一步增長上來的,在開始遇到性能瓶頸的時候,大多數架構師和DBA都會選擇先進行數據的垂直拆分,因為這樣的成本最先,最符合這個時期所追求的最大投入產出比。然而,隨著業務的不斷擴張,系統負載的持續增長,在系統穩定一段時期之后,經過了垂直拆分之后的數據庫集群可能又再一次不堪重負,遇到了性能瓶頸。

          這時候我們該如何抉擇?是再次進一步細分模塊呢,還是尋求其他的辦法來解決?如果我們再一次像最開始那樣繼續細分模塊,進行數據的垂直切分,那我們可能在不久的將來,又會遇到現在所面對的同樣的問題。而且隨著模塊的不斷的細化,應用系統的架構也會越來越復雜,整個系統很可能會出現失控的局面。

          這時候我們就必須要通過數據的水平切分的優勢,來解決這里所遇到的問題。而且,我們完全不必要在使用數據水平切分的時候,推倒之前進行數據垂直切分的成果,而是在其基礎上利用水平切分的優勢來避開垂直切分的弊端,解決系統復雜性不斷擴大的問題。而水平拆分的弊端(規則難以統一)也已經被之前的垂直切分解決掉了,讓水平拆分可以進行的得心應手。

          對于我們的示例數據庫,假設在最開始,我們進行了數據的垂直切分,然而隨著業務的不斷增長,數據庫系統遇到了瓶頸,我們選擇重構數據庫集群的架構。如何重構?考慮到之前已經做好了數據的垂直切分,而且模塊結構清晰明確。而業務增長的勢頭越來越猛,即使現在進一步再次拆分模塊,也堅持不了太久。我們選擇了在垂直切分的基礎上再進行水平拆分。

          在經歷過垂直拆分后的各個數據庫集群中的每一個都只有一個功能模塊,而每個功能模塊中的所有表基本上都會與某個字段進行關聯。如用戶模塊全部都可以通過用戶ID進行切分,群組討論模塊則都通過群組ID來切分,相冊模塊則根據相冊ID來進切分,最后的事件通知信息表考慮到數據的時限性(僅僅只會訪問最近某個事件段的信息),則考慮按時間來切分。

          下圖展示了切分后的整個架構:

          實際上,在很多大型的應用系統中,垂直切分和水平切這兩種數據的切分方法基本上都是并存的,而且經常在不斷的交替進行,以不斷的增加系統的擴展能力。我們在應對不同的應用場景的時候,也需要充分考慮到這兩種切分方法各自的局限,以及各自的優勢,在不同的時期(負載壓力)使用不同的結合方式。

          聯合切分的優點

          ◆ 可以充分利用垂直切分和水平切分各自的優勢而避免各自的缺陷;

          ◆ 讓系統擴展性得到最大化提升;

          聯合切分的缺點

          ◆ 數據庫系統架構比較復雜,維護難度更大;

          ◆ 應用程序架構也相對更復雜;

           

          數據切分及整合方案

          通過前面的章節,我們已經很清楚了通過數據庫的數據切分可以極大的提高系統的擴展性。但是,數據庫中的數據在經過垂直和(或)水平切分被存放在不同的數據庫主機之后,應用系統面臨的最大問題就是如何來讓這些數據源得到較好的整合,可能這也是很多讀者朋友非常關心的一個問題。這一節我們主要針對的內容就是分析可以使用的各種可以幫助我們實現數據切分以及數據整合的整體解決方案。

          數據的整合很難依靠數據庫本身來達到這個效果,雖然MySQL存在Federated存儲引擎,可以解決部分類似的問題,但是在實際應用場景中卻很難較好的運用。那我們該如何來整合這些分散在各個MySQL主機上面的數據源呢?

          總的來說,存在兩種解決思路:

          1. 在每個應用程序模塊中配置管理自己需要的一個(或者多個)數據源,直接訪問各個數據庫,在模塊內完成數據的整合;

          2. 通過中間代理層來統一管理所有的數據源,后端數據庫集群對前端應用程序透明;

          可能90%以上的人在面對上面這兩種解決思路的時候都會傾向于選擇第二種,尤其是系統不斷變得龐大復雜的時候。確實,這是一個非常正確的選擇,雖然短期內需要付出的成本可能會相對更大一些,但是對整個系統的擴展性來說,是非常有幫助的。

          所以,對于第一種解決思路我這里就不準備過多的分析,下面我重點分析一下在第二種解決思路中的一些解決方案。

          ★ 自行開發中間代理層

          在決定選擇通過數據庫的中間代理層來解決數據源整合的架構方向之后,有不少公司(或者企業)選擇了通過自行開發符合自身應用特定場景的代理層應用程序。

          通過自行開發中間代理層可以最大程度的應對自身應用的特定,最大化的定制很多個性化需求,在面對變化的時候也可以靈活的應對。這應該說是自行開發代理層最大的優勢了。

          當然,選擇自行開發,享受讓個性化定制最大化的樂趣的同時,自然也需要投入更多的成本來進行前期研發以及后期的持續升級改進工作,而且本身的技術門檻可能也比簡單的Web應用要更高一些。所以,在決定選擇自行開發之前,還是需要進行比較全面的評估為好。

          由于自行開發更多時候考慮的是如何更好的適應自身應用系統,應對自身的業務場景,所以這里也不好分析太多。后面我們主要分析一下當前比較流行的幾種數據源整合解決方案。

          ★利用MySQLProxy實現數據切分及整合

          MySQLProxy是MySQL官方提供的一個數據庫代理層產品,和MySQLServer一樣,同樣是一個基于GPL開源協議的開源產品。可用來監視、分析或者傳輸他們之間的通訊信息。他的靈活性允許你最大限度的使用它,目前具備的功能主要有連接路由,Query分析,Query過濾和修改,負載均衡,以及基本的HA機制等。

          實際上,MySQLProxy本身并不具有上述所有的這些功能,而是提供了實現上述功能的基礎。要實現這些功能,還需要通過我們自行編寫LUA腳本來實現。

          MySQLProxy實際上是在客戶端請求與MySQLServer之間建立了一個連接池。所有客戶端請求都是發向MySQLProxy,然后經由MySQLProxy進行相應的分析,判斷出是讀操作還是寫操作,分發至對應的MySQLServer上。對于多節點Slave集群,也可以起做到負載均衡的效果。以下是MySQLProxy的基本架構圖:

          通過上面的架構簡圖,我們可以很清晰的看出MySQLProxy在實際應用中所處的位置,以及能做的基本事情。關于MySQLProxy更為詳細的實施細則在MySQL官方文檔中有非常詳細的介紹和示例,感興趣的讀者朋友可以直接從MySQL官方網站免費下載或者在線閱讀,我這里就不累述浪費紙張了。

          ★利用Amoeba實現數據切分及整合

          Amoeba是一個基于Java開發的,專注于解決分布式數據庫數據源整合Proxy程序的開源框架,基于GPL3開源協議。目前,Amoeba已經具有Query路由,Query過濾,讀寫分離,負載均衡以及HA機制等相關內容。

          Amoeba 主要解決的以下幾個問題:

          1. 數據切分后復雜數據源整合;

          2. 提供數據切分規則并降低數據切分規則給數據庫帶來的影響;

          3. 降低數據庫與客戶端的連接數;

          4. 讀寫分離路由;

          我們可以看出,Amoeba所做的事情,正好就是我們通過數據切分來提升數據庫的擴展性所需要的。

          Amoeba并不是一個代理層的Proxy程序,而是一個開發數據庫代理層Proxy程序的開發框架,目前基于Amoeba所開發的Proxy程序有AmoebaForMySQL和AmoebaForAladin兩個。

          AmoebaForMySQL主要是專門針對MySQL數據庫的解決方案,前端應用程序請求的協議以及后端連接的數據源數據庫都必須是MySQL。對于客戶端的任何應用程序來說,AmoebaForMySQL和一個MySQL數據庫沒有什么區別,任何使用MySQL協議的客戶端請求,都可以被AmoebaForMySQL解析并進行相應的處理。下如可以告訴我們AmoebaForMySQL的架構信息(出自Amoeba開發者博客):

          AmoebaForAladin則是一個適用更為廣泛,功能更為強大的Proxy程序。他可以同時連接不同數據庫的數據源為前端應用程序提供服務,但是僅僅接受符合MySQL協議的客戶端應用程序請求。也就是說,只要前端應用程序通過MySQL協議連接上來之后,AmoebaForAladin會自動分析Query語句,根據Query語句中所請求的數據來自動識別出該所Query的數據源是在什么類型數據庫的哪一個物理主機上面。下圖展示了AmoebaForAladin的架構細節(出自Amoeba開發者博客):

          咋一看,兩者好像完全一樣嘛。細看之后,才會發現兩者主要的區別僅在于通過MySQLProtocalAdapter處理之后,根據分析結果判斷出數據源數據庫,然后選擇特定的JDBC驅動和相應協議連接后端數據庫。

          其實通過上面兩個架構圖大家可能也已經發現了Amoeba的特點了,他僅僅只是一個開發框架,我們除了選擇他已經提供的ForMySQL和ForAladin這兩款產品之外,還可以基于自身的需求進行相應的二次開發,得到更適應我們自己應用特點的Proxy程序。

          當對于使用MySQL數據庫來說,不論是AmoebaForMySQL還是AmoebaForAladin都可以很好的使用。當然,考慮到任何一個系統越是復雜,其性能肯定就會有一定的損失,維護成本自然也會相對更高一些。所以,對于僅僅需要使用MySQL數據庫的時候,我還是建議使用AmoebaForMySQL。

          AmoebaForMySQL的使用非常簡單,所有的配置文件都是標準的XML文件,總共有四個配置文件。分別為:

          ◆amoeba.xml:主配置文件,配置所有數據源以及Amoeba自身的參數設置;

          ◆rule.xml:配置所有Query路由規則的信息;

          ◆functionMap.xml:配置用于解析Query中的函數所對應的Java實現類;

          ◆ rullFunctionMap.xml:配置路由規則中需要使用到的特定函數的實現類;

          如果您的規則不是太復雜,基本上僅需要使用到上面四個配置文件中的前面兩個就可完成所有工作。Proxy程序常用的功能如讀寫分離,負載均衡等配置都在amoeba.xml中進行。此外,Amoeba已經支持了實現數據的垂直切分和水平切分的自動路由,路由規則可以在rule.xml進行設置。

          目前Amoeba少有欠缺的主要就是其在線管理功能以及對事務的支持了,曾經在與相關開發者的溝通過程中提出過相關的建議,希望能夠提供一個可以進行在線維護管理的命令行管理工具,方便在線維護使用,得到的反饋是管理專門的管理模塊已經納入開發日程了。另外在事務支持方面暫時還是Amoeba無法做到的,即使客戶端應用在提交給Amoeba的請求是包含事務信息的,Amoeba也會忽略事務相關信息。當然,在經過不斷完善之后,我相信事務支持肯定是Amoeba重點考慮增加的feature。

          關于Amoeba更為詳細的使用方法讀者朋友可以通過Amoeba開發者博客(http://amoeba.sf.net)上面提供的使用手冊獲取,這里就不再細述了。

          ★利用HiveDB實現數據切分及整合

          和前面的MySQLProxy以及Amoeba一樣,HiveDB同樣是一個基于Java針對MySQL數據庫的提供數據切分及整合的開源框架,只是目前的HiveDB僅僅支持數據的水平切分。主要解決大數據量下數據庫的擴展性及數據的高性能訪問問題,同時支持數據的冗余及基本的HA機制。

          HiveDB的實現機制與MySQLProxy和Amoeba有一定的差異,他并不是借助MySQL的Replication功能來實現數據的冗余,而是自行實現了數據冗余機制,而其底層主要是基于HibernateShards來實現的數據切分工作。

          在HiveDB中,通過用戶自定義的各種Partitionkeys(其實就是制定數據切分規則),將數據分散到多個MySQLServer中。在訪問的時候,在運行Query請求的時候,會自動分析過濾條件,并行從多個MySQLServer中讀取數據,并合并結果集返回給客戶端應用程序。

          單純從功能方面來講,HiveDB可能并不如MySQLProxy和Amoeba那樣強大,但是其數據切分的思路與前面二者并無本質差異。此外,HiveDB并不僅僅只是一個開源愛好者所共享的內容,而是存在商業公司支持的開源項目。

          下面是HiveDB官方網站上面一章圖片,描述了HiveDB如何來組織數據的基本信息,雖然不能詳細的表現出太多架構方面的信息,但是也基本可以展示出其在數據切分方面獨特的一面了。

          ★ mycat 數據整合:具體http://www.songwie.com/articlelist/11

          ★ 其他實現數據切分及整合的解決方案

          除了上面介紹的幾個數據切分及整合的整體解決方案之外,還存在很多其他同樣提供了數據切分與整合的解決方案。如基于MySQLProxy的基礎上做了進一步擴展的HSCALE,通過Rails構建的SpockProxy,以及基于Pathon的Pyshards等等。

          不管大家選擇使用哪一種解決方案,總體設計思路基本上都不應該會有任何變化,那就是通過數據的垂直和水平切分,增強數據庫的整體服務能力,讓應用系統的整體擴展能力盡可能的提升,擴展方式盡可能的便捷。

          只要我們通過中間層Proxy應用程序較好的解決了數據切分和數據源整合問題,那么數據庫的線性擴展能力將很容易做到像我們的應用程序一樣方便,只需要通過添加廉價的PCServer服務器,即可線性增加數據庫集群的整體服務能力,讓數據庫不再輕易成為應用系統的性能瓶頸。

           


          數據切分與整合可能存在的問題

          這里,大家應該對數據切分與整合的實施有了一定的認識了,或許很多讀者朋友都已經根據各種解決方案各自特性的優劣基本選定了適合于自己應用場景的方案,后面的工作主要就是實施準備了。

          在實施數據切分方案之前,有些可能存在的問題我們還是需要做一些分析的。一般來說,我們可能遇到的問題主要會有以下幾點:

          ◆ 引入分布式事務的問題;

          ◆跨節點Join的問題;

          ◆ 跨節點合并排序分頁問題;

           

          1. 引入分布式事務的問題

          一旦數據進行切分被分別存放在多個MySQLServer中之后,不管我們的切分規則設計的多么的完美(實際上并不存在完美的切分規則),都可能造成之前的某些事務所涉及到的數據已經不在同一個MySQLServer中了。

          在這樣的場景下,如果我們的應用程序仍然按照老的解決方案,那么勢必需要引入分布式事務來解決。而在MySQL各個版本中,只有從MySQL5.0開始以后的各個版本才開始對分布式事務提供支持,而且目前僅有Innodb提供分布式事務支持。不僅如此,即使我們剛好使用了支持分布式事務的MySQL版本,同時也是使用的Innodb存儲引擎,分布式事務本身對于系統資源的消耗就是很大的,性能本身也并不是太高。而且引入分布式事務本身在異常處理方面就會帶來較多比較難控制的因素。

          怎么辦?其實我們可以可以通過一個變通的方法來解決這種問題,首先需要考慮的一件事情就是:是否數據庫是唯一一個能夠解決事務的地方呢?其實并不是這樣的,我們完全可以結合數據庫以及應用程序兩者來共同解決。各個數據庫解決自己身上的事務,然后通過應用程序來控制多個數據庫上面的事務。

          也就是說,只要我們愿意,完全可以將一個跨多個數據庫的分布式事務分拆成多個僅處于單個數據庫上面的小事務,并通過應用程序來總控各個小事務。當然,這樣作的要求就是我們的俄應用程序必須要有足夠的健壯性,當然也會給應用程序帶來一些技術難度。

           

          2.跨節點Join的問題

          上面介紹了可能引入分布式事務的問題,現在我們再看看需要跨節點Join的問題。數據切分之后,可能會造成有些老的Join語句無法繼續使用,因為Join使用的數據源可能被切分到多個MySQLServer中了。

          怎么辦?這個問題從MySQL數據庫角度來看,如果非得在數據庫端來直接解決的話,恐怕只能通過MySQL一種特殊的存儲引擎Federated來解決了。Federated存儲引擎是MySQL解決類似于Oracle的DBLink之類問題的解決方案。和OracleDBLink的主要區別在于Federated會保存一份遠端表結構的定義信息在本地。咋一看,Federated確實是解決跨節點Join非常好的解決方案。但是我們還應該清楚一點,那就似乎如果遠端的表結構發生了變更,本地的表定義信息是不會跟著發生相應變化的。如果在更新遠端表結構的時候并沒有更新本地的Federated表定義信息,就很可能造成Query運行出錯,無法得到正確的結果。

          對待這類問題,我還是推薦通過應用程序來進行處理,先在驅動表所在的MySQLServer中取出相應的驅動結果集,然后根據驅動結果集再到被驅動表所在的MySQLServer中取出相應的數據。可能很多讀者朋友會認為這樣做對性能會產生一定的影響,是的,確實是會對性能有一定的負面影響,但是除了此法,基本上沒有太多其他更好的解決辦法了。而且,由于數據庫通過較好的擴展之后,每臺MySQLServer的負載就可以得到較好的控制,單純針對單條Query來說,其響應時間可能比不切分之前要提高一些,所以性能方面所帶來的負面影響也并不是太大。更何況,類似于這種需要跨節點Join的需求也并不是太多,相對于總體性能而言,可能也只是很小一部分而已。所以為了整體性能的考慮,偶爾犧牲那么一點點,其實是值得的,畢竟系統優化本身就是存在很多取舍和平衡的過程。

           

          3. 跨節點合并排序分頁問題

          一旦進行了數據的水平切分之后,可能就并不僅僅只有跨節點Join無法正常運行,有些排序分頁的Query語句的數據源可能也會被切分到多個節點,這樣造成的直接后果就是這些排序分頁Query無法繼續正常運行。其實這和跨節點Join是一個道理,數據源存在于多個節點上,要通過一個Query來解決,就和跨節點Join是一樣的操作。同樣Federated也可以部分解決,當然存在的風險也一樣。

          還是同樣的問題,怎么辦?我同樣仍然繼續建議通過應用程序來解決。

          如何解決?解決的思路大體上和跨節點Join的解決類似,但是有一點和跨節點Join不太一樣,Join很多時候都有一個驅動與被驅動的關系,所以Join本身涉及到的多個表之間的數據讀取一般都會存在一個順序關系。但是排序分頁就不太一樣了,排序分頁的數據源基本上可以說是一個表(或者一個結果集),本身并不存在一個順序關系,所以在從多個數據源取數據的過程是完全可以并行的。這樣,排序分頁數據的取數效率我們可以做的比跨庫Join更高,所以帶來的性能損失相對的要更小,在有些情況下可能比在原來未進行數據切分的數據庫中效率更高了。當然,不論是跨節點Join還是跨節點排序分頁,都會使我們的應用服務器消耗更多的資源,尤其是內存資源,因為我們在讀取訪問以及合并結果集的這個過程需要比原來處理更多的數據。

          分析到這里,可能很多讀者朋友會發現,上面所有的這些問題,我給出的建議基本上都是通過應用程序來解決。大家可能心里開始犯嘀咕了,是不是因為我是DBA,所以就很多事情都扔給應用架構師和開發人員了?

          其實完全不是這樣,首先應用程序由于其特殊性,可以非常容易做到很好的擴展性,但是數據庫就不一樣,必須借助很多其他的方式才能做到擴展,而且在這個擴展過程中,很難避免帶來有些原來在集中式數據庫中可以解決但被切分開成一個數據庫集群之后就成為一個難題的情況。要想讓系統整體得到最大限度的擴展,我們只能讓應用程序做更多的事情,來解決數據庫集群無法較好解決的問題。

           

          小結

          通過數據切分技術將一個大的MySQLServer切分成多個小的MySQLServer,既解決了寫入性能瓶頸問題,同時也再一次提升了整個數據庫集群的擴展性。不論是通過垂直切分,還是水平切分,都能夠讓系統遇到瓶頸的可能性更小。尤其是當我們使用垂直和水平相結合的切分方法之后,理論上將不會再遇到擴展瓶頸了。

          posted @ 2015-03-16 18:27 小馬歌 閱讀(4307) | 評論 (0)編輯 收藏
           
               摘要: from:http://wuhuajun.iteye.com/blog/1905578Thrift Java Servers ComparedThis article talks only about Java servers. See this page if you are interested in C++ servers.本文僅討論Java版的Thrift server...  閱讀全文
          posted @ 2015-03-12 17:25 小馬歌 閱讀(417) | 評論 (0)編輯 收藏
           

          1、添加依賴 jar

          <dependency>   <groupId>org.apache.thrift</groupId>   <artifactId>libthrift</artifactId>   <version>0.8.0</version> </dependency> <dependency>   <groupId>org.slf4j</groupId>   <artifactId>slf4j-log4j12</artifactId>   <version>1.6.1</version> </dependency> 

          2、編寫IDL文件 Hello.thrift

          namespace java service.demo
          service Hello {
              string helloString(1:string para)
              i32 helloInt(1:i32 para)
              bool helloBoolean(1:bool para)
              void helloVoid()
              string helloNull()
          }


          3、生成代碼

          thrift -o <output directory> -gen java Hello.thrift
          生成代碼縮略圖:



          4、編寫實現類、實現Hello.Iface:

          縮略圖:



          5、編寫服務端,發布(阻塞式IO + 多線程處理)服務。

          1. /** 
          2.      * 阻塞式、多線程處理 
          3.      *  
          4.      * @param args 
          5.      */  
          6.     @SuppressWarnings({ "unchecked", "rawtypes" })  
          7.     public static void main(String[] args) {  
          8.         try {  
          9.             //設置傳輸通道,普通通道  
          10.             TServerTransport serverTransport = new TServerSocket(7911);  
          11.               
          12.             //使用高密度二進制協議  
          13.             TProtocolFactory proFactory = new TCompactProtocol.Factory();  
          14.               
          15.             //設置處理器HelloImpl  
          16.             TProcessor processor = new Hello.Processor(new HelloImpl());  
          17.               
          18.             //創建服務器  
          19.             TServer server = new TThreadPoolServer(  
          20.                     new Args(serverTransport)  
          21.                     .protocolFactory(proFactory)  
          22.                     .processor(processor)  
          23.                 );  
          24.               
          25.             System.out.println("Start server on port 7911...");  
          26.             server.serve();  
          27.         } catch (Exception e) {  
          28.             e.printStackTrace();  
          29.         }  
          30.     }  



          6、編寫客戶端,調用(阻塞式IO + 多線程處理)服務:

          1. public static void main(String[] args) throws Exception {  
          2.         // 設置傳輸通道 - 普通IO流通道  
          3.         TTransport transport = new TSocket("localhost", 7911);  
          4.         transport.open();  
          5.           
          6.         //使用高密度二進制協議  
          7.         TProtocol protocol = new TCompactProtocol(transport);  
          8.           
          9.         //創建Client  
          10.         Hello.Client client = new Hello.Client(protocol);  
          11.           
          12.         long start = System.currentTimeMillis();  
          13.         for(int i=0; i<10000; i++){  
          14.             client.helloBoolean(false);  
          15.             client.helloInt(111);  
          16.             client.helloNull();  
          17.             client.helloString("dongjian");  
          18.             client.helloVoid();  
          19.         }  
          20.         System.out.println("耗時:" + (System.currentTimeMillis() - start));  
          21.           
          22.         //關閉資源  
          23.         transport.close();  
          24.     }  



          現在已完成整個開發過程,超級無敵簡單。

          其中服務端使用的協議需要與客戶端保持一致

          -------------------------------------------------------------------------------------------------------------------


          上面展示了普通且常用的服務端和客戶端,下面請看非阻塞IO,即java中的NIO:


          基于非阻塞IO(NIO)的服務端

          1. public static void main(String[] args) {  
          2.         try {  
          3.             //傳輸通道 - 非阻塞方式  
          4.             TNonblockingServerTransport serverTransport = new TNonblockingServerSocket(7911);  
          5.               
          6.             //異步IO,需要使用TFramedTransport,它將分塊緩存讀取。  
          7.             TTransportFactory transportFactory = new TFramedTransport.Factory();  
          8.               
          9.             //使用高密度二進制協議  
          10.             TProtocolFactory proFactory = new TCompactProtocol.Factory();  
          11.               
          12.             //設置處理器 HelloImpl  
          13.             TProcessor processor = new Hello.Processor(new HelloImpl());  
          14.               
          15.             //創建服務器  
          16.             TServer server = new TThreadedSelectorServer(  
          17.                     new Args(serverTransport)  
          18.                     .protocolFactory(proFactory)  
          19.                     .transportFactory(transportFactory)  
          20.                     .processor(processor)  
          21.                 );  
          22.               
          23.             System.out.println("Start server on port 7911...");  
          24.             server.serve();  
          25.         } catch (Exception e) {  
          26.             e.printStackTrace();  
          27.         }  
          28.     }  



          調用非阻塞IO(NIO)服務的客戶端

          1. public static void main(String[] args) throws Exception {  
          2.         //設置傳輸通道,對于非阻塞服務,需要使用TFramedTransport,它將數據分塊發送  
          3.         TTransport transport = new TFramedTransport(new TSocket("localhost", 7911));  
          4.         transport.open();  
          5.           
          6.         //使用高密度二進制協議  
          7.         TProtocol protocol = new TCompactProtocol(transport);  
          8.           
          9.         //創建Client  
          10.         Hello.Client client = new Hello.Client(protocol);  
          11.           
          12.         long start = System.currentTimeMillis();  
          13.         for(int i=0; i<10000; i++){  
          14.             client.helloBoolean(false);  
          15.             client.helloInt(111);  
          16.             client.helloNull();  
          17.             client.helloString("360buy");  
          18.             client.helloVoid();  
          19.         }  
          20.         System.out.println("耗時:" + (System.currentTimeMillis() - start));  
          21.           
          22.         //關閉資源  
          23.         transport.close();  
          24.     }  



          -----------------------------------------------------------------------------------------------------------------------------------

          客戶端異步調用

          1. /** 調用[非阻塞IO]服務,異步 */  
          2.     public static void main(String[] args) {  
          3.         try {  
          4.             //異步調用管理器  
          5.             TAsyncClientManager clientManager = new TAsyncClientManager();  
          6.             //設置傳輸通道,調用非阻塞IO。  
          7.             final TNonblockingTransport transport = new TNonblockingSocket("localhost", 7911);    
          8.             //設置協議  
          9.             TProtocolFactory protocol = new TCompactProtocol.Factory();    
          10.             //創建Client  
          11.             final Hello.AsyncClient client = new Hello.AsyncClient(protocol, clientManager, transport);  
          12.             // 調用服務   
          13.             System.out.println("開始:" + System.currentTimeMillis());  
          14.             client.helloBoolean(false, new AsyncMethodCallback<Hello.AsyncClient.helloBoolean_call>() {  
          15.                 public void onError(Exception exception) {  
          16.                     System.out.println("錯誤1: " + System.currentTimeMillis());  
          17.                 }  
          18.                 public void onComplete(helloBoolean_call response) {  
          19.                     System.out.println("完成1: " + System.currentTimeMillis());  
          20.                     try {  
          21.                         client.helloBoolean(false, new AsyncMethodCallback<Hello.AsyncClient.helloBoolean_call>() {  
          22.                             public void onError(Exception exception) {  
          23.                                 System.out.println("錯誤2: " + System.currentTimeMillis());  
          24.                             }  
          25.                               
          26.                             public void onComplete(helloBoolean_call response) {  
          27.                                 System.out.println("完成2: " + System.currentTimeMillis());  
          28.                                 transport.close();  
          29.                             }  
          30.                         });  
          31.                     } catch (TException e) {  
          32.                         e.printStackTrace();  
          33.                     }  
          34.                 }  
          35.             });  
          36.             System.out.println("結束:" + System.currentTimeMillis());  
          37.             Thread.sleep(5000);  
          38.         } catch (Exception e) {  
          39.             e.printStackTrace();  
          40.         }  
          41.     }  


          -----------------------------------------------------------------------------------------------------------------------------------

          使用SSL的服務端:



          調用基于SSL服務端的客戶端:


          posted @ 2015-03-12 17:20 小馬歌 閱讀(540) | 評論 (0)編輯 收藏
           
               摘要: 作為Java程序員來說,最痛苦的事情莫過于可以選擇的范圍太廣,可以讀的書太多,往往容易無所適從。我想就我自己讀過的技術書籍中挑選出來一些,按照學習的先后順序,推薦給大家,特別是那些想不斷提高自己技術水平的Java程序員們。 一、Java編程入門類  對于沒有Java編程經驗的程序員要入門,隨便讀什么入門書籍都一樣,這個階段需要你快速的掌握Java基礎語法和基本用法,宗...  閱讀全文
          posted @ 2015-03-11 13:47 小馬歌 閱讀(313) | 評論 (0)編輯 收藏
           

          from: http://wapapp.baidu.com/tianhuimin/item/6e144c362eced2ff96f88d42

          1 概述1.1 研發背景

          支撐互聯網應用的各種服務通常都是用復雜大規模分布式集群來實現的。而這些互聯網應用又構建在不同的軟件模塊集上,這些軟件模塊,有可能是由不同的團隊開 發、可能使用不同的編程語言來實現、有可能布在了幾千臺服務器,橫跨多個不同的數據中心。因此,就需要一些可以幫助理解系統行為、用于分析性能問題的工 具。

          hydra分布式跟蹤系統就為了解決以上這些問題而設計的。

          1.2 理論依據

          Google的論文《Dapper, a Large-Scale Distributed Systems Tracing Infrastructure》是我們設計開發的指導思想(原文和譯文地址 https://github.com/bigbully/Dapper-translation)。Google針對自己的分布式跟蹤系統Dapper 在生產環境下運行兩年多時間積累的經驗,在論文中重點提到了分布式跟蹤系統對業務系統的零侵入這個先天優勢,并總結了大量的應用場景,還提及它的不足之 處。我們通過對這篇論文的深入研究,并參考了Twitter同樣依據這篇論文的scala實現Zipkin,結合我們自身的現有架構,我們認為分布式跟蹤 系統在我們內部是非常適合的,而且也是急需的。

          1.3 功能概述

          hydra目前的功能并不復雜,他可以接入一些基礎組件,然后實現在基礎組件上收集在組建上產生的行為的時間消耗,并且提供跟蹤查詢頁面,對跟蹤到的數據進行查詢和展示。

          我們會在之后的功能介紹中對hydra現有功能進行說明。

          2 領域模型

          分布式跟蹤的領域模型其實已經很成熟,早在1997年IBM就把ARM2.0(Application Response Measurement)作為一個公開的標準提供給了Open Group,無奈當時SOA的架構還未成熟,對業務的跟蹤還需要直接嵌入到業務代碼中,致使跟蹤系統無法順利推廣。

          如今互聯網領域大多數后臺服務都已經完成了SOA化,所以對業務的跟蹤可以直接簡化為對服務調用框架的跟蹤,所以越來越多的跟蹤系統也涌現出來。 在hydra系統中,我們使用的領域模型參考了Google的Dapper和Twitter的Zipkin(http://twitter.github.io/zipkin/)。

          2.1 hydra中的跟蹤數據模型

          參考Dapper和Zipkin的設計,hydra也提煉出了自己的領域模型,如圖所示:

          Hydra - 京東開源的基于Dubbo的調用分布跟蹤系統
          • Trace:一次服務調用追蹤鏈路。

          • Span:追蹤服務調基本結構,多span形成樹形結構組合成一次Trace追蹤記錄。

          • Annotation:在span中的標注點,記錄整個span時間段內發生的事件。

          • BinaryAnnotation:屬于Annotation一種類型和普通Annotation區別,這鍵值對形式標注在span中發生的事件,和一些其他相關的信息。

          Annotation在整個跟蹤數據模型中最靈活的,靈活運用annotation基本能表達你所想到的跟蹤場景。在hydra中(參考了zipkin)定義4種不同value的annotation用來表達記錄span 4個最基本的事件。通過這4個annotation能計算出鏈路中業務消耗和網絡消耗時間。

          2.2 dubbo服務調用框架的模型

          公司內部,尤其是我們部門有很多業務系統使用dubbo作為服務調用框,所以我們的分布式跟蹤系統第一個接入組件就是dubbo。 另一個原因也是因為我們團隊對dubbo有著非常深入的理解,加之dubbo本身的架構本身十分適合擴展,作為服務調用框架而言,跟蹤的效果會非常明顯, 比如Twitter的Zipkin也是植入到內部的Finagle服務調用框架上來進行跟蹤的。

          由于現階段hydra主要接入了dubbo服務調用框架,所以在這必須了解dubbo的幾個模型,如下圖所示:

          Hydra - 京東開源的基于Dubbo的調用分布跟蹤系統
          • Application:一類業務類型的服務,下面可能包含多個接口服務,可能出現多種類型業務跟蹤鏈路。

          • InterfaceService:接口服務,一個服務接口提供多種業務處理方法。

          • Method:接口服務中具體處理業務的方法。

          2.3 Hydra中跟蹤模型和dubbo模型之間關系Hydra - 京東開源的基于Dubbo的調用分布跟蹤系統

          如圖所示的應用場景對A服務的調用。A服務在被調用的過程中會繼續調用服務B和服務C,而服務C被調用之后又會繼續調用服務D和服 務E。在我們的領域模型中,服務A被調用到調用完成的過程,就是一次trace。而每一個服務被調用并返回的過程(一去一回的箭頭)為一個span。可以 看到這個示例中包含5個span,client-A,A-B,A-C,C-D,C-E。span本身以樹形結構展開,A-C是C-D和C-E的父 span,而client-A是整個樹形結構的root span。之后要提到的一個概念就是annotation,annotation代表在服務調用過程中發生的一些我們感興趣的事情,如圖所示C-E上標出 來的那四個點,就是四個annotation,來記錄事件時間戳,分別是C服務的cs(client send),E服務的ss(server receive),E服務的ss(server send), C服務的cr(client receive)。如果有一些自定義的annotation我們會把它作為BinaryAnnotation,其實就是一個k-v對,記錄任何跟蹤系統想 記錄的信息,比如服務調用中的異常信息,重要的業務信息等等。

          3 功能介紹

          當前hydra1.0版的功能主要分為兩個部分,跟蹤查詢和跟蹤展示。

          如圖所示為查詢頁面:

          Hydra - 京東開源的基于Dubbo的調用分布跟蹤系統

          在hydra針對業務提出兩個相關的概念:應用和服務。不同的業務的所屬不同的應用(相當于dubbo中的Application),服務(相當于dubbo中的interface)掛在應用之下。

          在hydra的查詢界面中首先要選擇想要關注的應用名,然后通過自動完成的方式輸入應用下的服務。選擇服務的開始時間和需要查看的跟蹤次數。另外hydra需要確定返回數據的總量,防止查詢出大數據量導致頁面失去響應。

          另外我們提供對額外的篩選條件:調用響應時間、是否發生異常。調用響應時間指的是這一次服務調用從調用開始到調用結束的時間,是否發生異常則包括一次服務調用中所有歷經的服務拋出的異常都會捕獲到。

          對于查詢之后的數據,hydra提供在前臺進行排序的功能。

          對于每一次跟蹤,我們可以進一步展示他的服務調用層級與響應時間的時序圖。如下圖所示:

          Hydra - 京東開源的基于Dubbo的調用分布跟蹤系統

          我們參考Dapper中論述的場景,在時序圖中用綠色代表服務調用時間,淺藍色代表網絡耗時,另外如果服務調用拋出異常被 hydra捕捉到的話,會用紅色表示。鼠標移動到時序圖中的每一個對象上,會Tip展現詳細信息,包括服務名、方法名、調用時長、Endpoint、異常 信息等。

          左側的樹形結構圖可以收起和展開,同時右側的時序圖產生聯動,利于調整關注點在不同的服務上。

          4 整體架構4.1 完整版Hydra - 京東開源的基于Dubbo的調用分布跟蹤系統

          對于分布式跟蹤系統而言,必須對接入的基礎組件進行改造,我們對dubbo的改造很簡單,只是在過濾器鏈上增加一個過濾器,我們將其封裝成一個hydra-dubbo的jar包,由dubbo直接依賴。

          所有跟蹤所需的通用性的API我們封裝在hydra-client中,遍于接入各種組件。 hydra-manager用來完成每個服務的注冊、采樣率的調成、發送seed生成全局唯一的traceId等通用性的功能。所有hydra-manager數據統一用mysql進行存儲。

          我們使用hydra-collector和hydra-collector-service進行跟蹤數據的異步存儲,中間使用metaQ進行緩沖。

          hydra-manager和hydra-collector使用dobbo提供服務。

          4.2 精簡版

          考慮到數據量不大的情況,以及部署的復雜度。我們提供了兩種更簡便的架構

          • 如果考慮到數據量沒有那么大,可以不使用hbase,用mysql代替,即精簡版1。因為畢竟hadoop集群和hbase集群的部署和維護工作量很大。

          • 如果并發量也不是很大的話,可以不使用消息中間件,也就是精簡版2,如圖所示。在hydra-collector端直接進行數據落地,當然仍然是異步的。

          Hydra - 京東開源的基于Dubbo的調用分布跟蹤系統

          在使用mysql進行存儲的時候我們并未進行分庫分表,因為考慮到存儲的是監控數據,時效性較高,而長期的監控數據的保留意義并不大。所以我們在主表上有明確的時間戳字段,使用者可以自行決定何時對保存的歷史數據進行遷移。

          5 Quick Start5.1 部署簡介

          Hydra分布式跟蹤系統可以跟蹤環境的數據量大小選擇上文所述的三種部署方式

          • 高并發,大數據量:hydra-client | Queue | hbase

          • 高并發,小數據量:hydra-client | Queue | mysql

          • 低并發,小數據量:hydra-client | mysql

          因為是quick start,這里只介紹低并發和小數據量的情況。不過這里會詳細介紹如何通過配置文件的修改來切換這三種部署方式。

          5.2 硬件要求
          • 1或多臺業務系統集群機

          • 1套zookeeper單點或集群機

          • 1臺機器部署Hydra-manager

          • 1或多臺機器部署Hydra-Collector

          • 1臺機器部署Hydra-web

          • 1臺數據庫服務器

          5.3 軟件要求
          • Dubbo:Hydra是基于alibaba的dubbo框架基準上做的服務跟蹤系統,理論上原有的Dubbo框架服務群中所有應用不需要額外的配置,皆可以平滑的接入Hydra系統。

          • Zookeeper:各個服務點依賴于zookeeper來讀取Hydra-manager和Hydra-collector獲取數據交互路由點,來完成跟蹤數據的推送和跟蹤的控制。

          • Mysql:跟蹤數據的持久化存儲。

          • Tomcat:前端web應用容器

          5.4 源碼獲取

          可以暫時使用master,后續版本會歸并到dubbo管理端

          5.5 項目構建打包

          maven項目不用多說。mvn clean install。不過不得不說的是,hydra項目中包含一些涉及數據庫讀寫的單元測試(mysql,hbase),配置文件分別在:

          • modules/hydra-manager-db/src/test/resources/mysql.properties

          • modules/hydra-store/hydra-mysql/src/test/resources/mysql.properties

          • modules/hydra-store/hydra-hbase/src/test/resources/hbase-site.xml

          • modules/hydra-store/hydra-hbase/src/test/resources/hydra-hbase-test.xml

          mysql需要創建測試用數據庫和測試用表,hbase需要創建測試用表

          • docs/table-hbase/initTable
            (hbase建表時可以根據hbase集群的具體情況調整域分區,涉及到table-mysql中對TB_PARA_SERVICE_ID_GEN初始化數據的設計)

          • docs/table-mysql

          當然對于不需要使用hbase的同學也可以自行移除modules/hydar-store/hydra-hbase。

          當然用maven構建跳過測試也是可以的。使用mvn clean install -Dmaven.test.skip=true

          需要打包的子項目會通過maven:assemblly插件打成tar.gz包在各自的target目錄下。

          5.6 安裝部署5.6.1 Hydra-client

          hydra-client中包含hydra與dubbo的集成,以及hydra跟蹤收集的相關功能。如果需要進行dubbo服務的跟蹤,只需要把這個jar包放在dubbo服務的classpath下,就會自動開啟跟蹤功能!

          5.6.2 Hydra-manager
          1. 部署:scp -r target/*.tar.gz username@ip:dirname

          2. 配置:cd basedir/conf (需要修改配置)

          3. 啟動:cd basedir/bin
            sh manager.sh start

          4. 停止:cd basedir/bin
            sh manager.sh stop

          5. 輸入:cd basedir/log
            tail -f manager.log

          5.6.3 Hydra-collector
          1. 部署:scp -r target/*.tar.gz username@ip:dirname

          2. 配置:cd basedir/conf (需要修改配置)

          3. 啟動:cd basedir/bin
            sh collector-mysql.sh start 
            (這里注意一下,如果在hydra-collector中需要發送到Queue中,則需要啟動collector.sh,jar包會加載不同的配置文件。)

          4. 停止:cd basedir/bin
            sh collector-mysql.sh stop

          5. 輸入:cd basedir/log
            tail -f *.log

          5.6.4 Hydra-web
          1. 需要在web.xml中修改引入的配置文件為hydra-mysql.xml,注掉hydra-hbase.xml

          2. 部署:scp -r target/*.war username@ip:$TOMCAT_WEBAPPS

          6 模擬場景6.1 場景描述

          我們模擬了兩個測試場景,均是基于dubbo服務調用

          場景exp1:

          A --> B --> C         

          即服務A調用服務B,服務B調用服務C。測試用例在modules/hydra-example/hydra-exmple-exp1/。熟悉dubbo的同學一定不會陌生。

          場景exp2:

          A --> B --> C1 --> E                     --> C2 --> D1 --> C1 --> E                            --> D2         

          場景2很復雜,基本涵蓋了對同步調用跟蹤的大多數可能遇到的場景。測試用例在modules/hydra-example/hydra-exmple-exp2/。

          6.2 模擬場景dubbo服務的部署

          Hydra默認使用了hydra-exmple中的兩個應用場景來做,你可以在hydra-test/hydra-test-integration打包中獲得應用場景。

          獲得tar.gz包或者zip包后,將服務分布式部署到不同的機器上,以模擬應用場景,一下介紹場景一的部署方法,場景二的部署方法類似。

          hydra-test-intergration 分為windows版和linux版(默認),見如下打包方法。

          • 打包:linux: mvn package -Pruntime-env-linux
            window: mvn package -Pruntime-env-windows

          • 部署: scp -r target/*.tar.gz username@ip:dirname

          • 配置: cd basedir/conf
            修改 *exp1.properties

          • 啟動: cd basedir/bin
            cd exp1
            sh startA.sh
            cd ..
            sh startTrigger-exp1.sh start

          • 停止: cd basedir/bin
            sh startTrigger-exp1.sh stop
            All.sh stop

          • 輸出: cd basedir/log
            tail -f *.log

          6.3 部署舉例

          以下演示安裝樣例:

          1. 部署zookeeper單點或集群環境,以保證獲得最佳SOA,zookeeper的部署請參照官方文檔。

          2. 部署實驗場景exp1,只需要部署hydra-test-integration模塊打包的tar.gz包,拷貝三份分布式部署。

          3. 部署一個觸發器Trigger,以激活服務的調用。

          4. 部署一個Manager,以管理各個跟蹤點的跟蹤上下文。

          5. 部署一個或者多個Collector消費機集群,以搜集來自Hydra-client推送過來的跟蹤數據。

          6. 部署一個web應用,已提供給前端展現應用系統服務上下文。

          exp1場景說明:

          有三個服務應用A、B、C和一個觸發RPC調用的應用Trigger,服務調用關系為A-B-C, 每隔500s觸發一個調用,持續時間為1天。

          部署地址舉例:

          角色ipportZK192.168.200.110-1122181~A192.168.200.11020990B192.168.200.11120991C192.168.200.11220992Trigger192.168.200.113-Manager192.168.228.8120890Collector192.168.228.81-8220889Web192.168.228.818080MySql-DB192.168.228.8133067 測試相關7.1 測試說明

          本測試針對Hydra-Client模塊進行功能測試和壓力測試,以便在Hydra開發的過程中及時發現重要bug和幫助優化Hydra系統性能。

          本測試目前只針對Hydra-client的測試,重點關注業務系統接入Hydra和不接入Hydra前后性能影響,以保證Hydra系統接入端的低侵入性和穩定性。

          針對Hydra-Client的測試,在部署上,只用部署應用場景(帶Hydra_client)和Benchmark觸發點,然后在應用Benchmark和應用場景上埋點分析Hydra性能。


          資料來源:http://www.open-open.com/lib/view/open1370253915148.html

          posted @ 2015-03-09 16:06 小馬歌 閱讀(5056) | 評論 (0)編輯 收藏
           
               摘要: from:http://www.jb51.net/article/48304.htm本教程將Java8的新特新逐一列出,并將使用簡單的代碼示例來指導你如何使用默認接口方法,lambda表達式,方法引用以及多重Annotation,之后你將會學到最新的API上的改進,比如流,函數式接口,Map以及全新的日期API“Java is still not dead—and peop...  閱讀全文
          posted @ 2015-03-09 14:52 小馬歌 閱讀(400) | 評論 (1)編輯 收藏
           
          posted @ 2015-03-06 17:03 小馬歌 閱讀(227) | 評論 (0)編輯 收藏
          僅列出標題
          共95頁: First 上一頁 12 13 14 15 16 17 18 19 20 下一頁 Last 
           
          主站蜘蛛池模板: 南漳县| 同江市| 土默特右旗| 新建县| 晴隆县| 江川县| 临高县| 仁布县| 莱芜市| 安宁市| 炎陵县| 新和县| 阳城县| 从江县| 宝鸡市| 皋兰县| 望都县| 盘山县| 长汀县| 广昌县| 沈丘县| 仁化县| 新余市| 通榆县| 石首市| 通河县| 虎林市| 于田县| 宾阳县| 电白县| 清水河县| 突泉县| 绵阳市| 哈尔滨市| 运城市| 贵州省| 高碑店市| 信丰县| 布尔津县| 临安市| 凭祥市|